Merge lp:~openerp-dev/openerp-command/trunk-entry-points-cto into lp:openerp-command

Proposed by Samus CTO (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openerp-command/trunk-entry-points-cto
Merge into: lp:openerp-command
Diff against target: 1406 lines (+518/-472)
30 files modified
README (+1/-1)
openerpcommand/__init__.py (+95/-52)
openerpcommand/addons/bench_sale_mrp/data.yml (+1/-1)
openerpcommand/benchmark/__init__.py (+111/-0)
openerpcommand/benchmark/dummy.py (+18/-0)
openerpcommand/benchmark/fields_view_get.py (+20/-0)
openerpcommand/benchmark/login.py (+13/-0)
openerpcommand/benchmark/read.py (+20/-0)
openerpcommand/benchmark/sale_mrp.py (+14/-18)
openerpcommand/benchmarks.py (+0/-166)
openerpcommand/call.py (+11/-20)
openerpcommand/client.py (+0/-137)
openerpcommand/common.py (+49/-14)
openerpcommand/conf.py (+5/-10)
openerpcommand/consume_cpu.py (+16/-0)
openerpcommand/consume_memory.py (+16/-0)
openerpcommand/consume_nothing.py (+11/-0)
openerpcommand/drop.py (+2/-6)
openerpcommand/initialize.py (+10/-8)
openerpcommand/leak_memory.py (+11/-0)
openerpcommand/model.py (+2/-5)
openerpcommand/module.py (+4/-5)
openerpcommand/open.py (+29/-0)
openerpcommand/read.py (+1/-4)
openerpcommand/run_tests.py (+4/-6)
openerpcommand/scaffold.py (+1/-5)
openerpcommand/show.py (+23/-0)
openerpcommand/uninstall.py (+4/-7)
openerpcommand/update.py (+1/-3)
setup.py (+25/-4)
To merge this branch: bzr merge lp:~openerp-dev/openerp-command/trunk-entry-points-cto
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+135720@code.launchpad.net
To post a comment you must log in.
187. By Samus CTO (OpenERP)

[IMP] Missing calls to expand_path for addons paths

Unmerged revisions

187. By Samus CTO (OpenERP)

[IMP] Missing calls to expand_path for addons paths

186. By Samus CTO (OpenERP)

[IMP] Modules now use entry points and OE populate automatically

185. By Samus CTO (OpenERP)

[FIX] Agrolait's id has changed in default server demo data

184. By Samus CTO (OpenERP)

Updated TODO

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2012-10-31 10:52:02 +0000
3+++ README 2012-11-27 15:42:19 +0000
4@@ -4,6 +4,6 @@
5 ----
6
7 - Make sure to have proper return code for success/failure.
8-- `oe --help` is a mess (it seems argparse doesn't try to do something sensible).
9 - Have a flag for `run-tests` to drop in the debugger (to be combined with
10 unittest2 fail-fast mode?).
11+- Make sure oe can do everything openerp-server can do
12
13=== modified file 'openerpcommand/__init__.py'
14--- openerpcommand/__init__.py 2012-11-05 11:27:01 +0000
15+++ openerpcommand/__init__.py 2012-11-27 15:42:19 +0000
16@@ -1,61 +1,104 @@
17+"""
18+OpenERP Command provides a set of command-line tools around the OpenERP
19+framework: openobject-server. All the tools are sub-commands of a single
20+oe executable.
21+"""
22+import pkg_resources
23+import sys
24+import os
25 import argparse
26-import textwrap
27-
28-from .call import Call
29-from .client import Open, Show, ConsumeNothing, ConsumeMemory, LeakMemory, ConsumeCPU
30-from .benchmarks import Bench, BenchRead, BenchFieldsViewGet, BenchDummy, BenchLogin
31-from .bench_sale_mrp import BenchSaleMrp
32-from . import common
33-
34-from . import conf # Not really server-side (in the `for` below).
35-from . import drop
36-from . import initialize
37-from . import model
38-from . import module
39-from . import read
40-from . import run_tests
41-from . import scaffold
42-from . import uninstall
43-from . import update
44-
45-command_list_server = (conf, drop, initialize, model, module, read, run_tests,
46- scaffold, uninstall, update, )
47-
48-command_list_client = (Call, Open, Show, ConsumeNothing, ConsumeMemory,
49- LeakMemory, ConsumeCPU, Bench, BenchRead,
50- BenchFieldsViewGet, BenchDummy, BenchLogin,
51- BenchSaleMrp, )
52+
53+command_list = []
54+base_group = '%s.subcommands' % __name__
55+toplevel_mark = '==toplevel=='
56+
57+for group, entry_points in pkg_resources.get_entry_map(pkg_resources.get_distribution('openerp-command')).items():
58+ if group.startswith(base_group):
59+ container = group[len(base_group)+1:] or None
60+ for name, entry_point in entry_points.items():
61+ try:
62+ init_parser = entry_point.load()
63+ pkg = sys.modules[init_parser.__module__.rsplit('.', 1)[0]]
64+ description = unicode(sys.modules[init_parser.__module__].__doc__).strip()
65+ command_list.append( (name.replace('_', '-'), container, description, init_parser, pkg) )
66+ except ImportError, e:
67+ sys.stderr.write("Invalid entry point: %s" % e.message + os.linesep)
68
69 def main_parser():
70+
71+ def format_command(name, description):
72+ text = [name]
73+ if description:
74+ text.extend([
75+ ":", os.linesep,
76+ " " + description.strip().replace("\n", "\n "),
77+ ])
78+ return "".join(text)
79+
80 parser = argparse.ArgumentParser(
81 usage=argparse.SUPPRESS,
82- description=textwrap.fill(textwrap.dedent("""\
83- OpenERP Command provides a set of command-line tools around
84- the OpenERP framework: openobject-server. All the tools are
85- sub-commands of a single oe executable.""")),
86+ description=__doc__,
87 epilog="""Use <command> --help to get information about the command.""",
88 formatter_class=argparse.RawDescriptionHelpFormatter,
89 )
90- description = []
91- for x in command_list_server:
92- description.append(x.__name__[len(__package__)+1:])
93- if x.__doc__:
94- description.extend([
95- ":\n",
96- textwrap.fill(str(x.__doc__).strip(),
97- subsequent_indent=' ',
98- initial_indent=' '),
99- ])
100- description.append("\n\n")
101- subparsers = parser.add_subparsers(
102- title="Available commands",
103- help=argparse.SUPPRESS,
104- description="".join(description[:-1]),
105- )
106- # Server-side commands.
107- for x in command_list_server:
108- x.add_parser(subparsers)
109- # Client-side commands. TODO one per .py file.
110- for x in command_list_client:
111- x(subparsers)
112+ command_list.sort(key=lambda x:(x[1], x[0]))
113+ container_help = {}
114+ for name, container, description, _, pkg in command_list:
115+ # Update parent subparser help_text
116+ container = container or toplevel_mark
117+ if container in container_help or container is toplevel_mark:
118+ help_text = container_help.setdefault(container, [])
119+ else:
120+ parent_container = container.rsplit('.', 1)[0] if '.' in container else toplevel_mark
121+ container_name = container.rsplit('.', 1)[1] if '.' in container else container
122+ parent_text = container_help.setdefault(parent_container, [])
123+ parent_text.extend([format_command(container_name, pkg.__doc__), os.linesep * 2])
124+ # Make subcommand help
125+ help_text = container_help.setdefault(container or toplevel_mark, [])
126+ help_text.extend([format_command(name, description), os.linesep * 2])
127+ subparsers = {toplevel_mark : parser.add_subparsers(
128+ title="Available commands",
129+ help=argparse.SUPPRESS,
130+ description="".join(container_help[toplevel_mark][:-1])),
131+ }
132+ for _, container, _, _, pkg in command_list:
133+ if container is not None and container not in subparsers:
134+ path, name = container.rsplit('.', 1) if '.' in container else (toplevel_mark, container)
135+ parent_subparser = subparsers[path]
136+ parent_parser = parent_subparser.add_parser(name, description=pkg.__doc__,
137+ formatter_class=argparse.RawDescriptionHelpFormatter)
138+ subparsers[container] = parent_parser.add_subparsers(
139+ title="Available commands",
140+ help=argparse.SUPPRESS,
141+ description="".join(container_help[container][:-1]),
142+ )
143+ for name, container, description, init_parser, _ in command_list:
144+ subparser = subparsers[container or toplevel_mark]
145+ command_parser = subparser.add_parser(name, description=description)
146+ init_parser(command_parser)
147 return parser
148+
149+def make_entry_points(path='.'):
150+ import pkgutil
151+ import pprint
152+ res = {}
153+ for importer, fullname, is_pkg in pkgutil.walk_packages(path):
154+ try:
155+ module_path = fullname.split('.')
156+ prefix, name = module_path[0], module_path[-1]
157+ if not prefix == __name__:
158+ continue
159+ module_container = ".".join(['openerpcommand','subcommands']+module_path[1:-1])
160+ if is_pkg:
161+ # Needed to display importation errors
162+ __import__(fullname, globals(), locals(), [], -1)
163+ else:
164+ module = __import__(fullname, globals(), locals(), [name.split('.')[-1]], -1)
165+ entry_point_string = "%s = %s:init_parser" % (name, fullname)
166+ if not hasattr(module, 'init_parser'):
167+ print "#", entry_point_string
168+ else:
169+ res.setdefault(module_container, []).append( entry_point_string )
170+ except ValueError:
171+ pass
172+ pprint.pprint(res, indent=4)
173
174=== modified file 'openerpcommand/addons/bench_sale_mrp/data.yml'
175--- openerpcommand/addons/bench_sale_mrp/data.yml 2012-02-06 14:54:54 +0000
176+++ openerpcommand/addons/bench_sale_mrp/data.yml 2012-11-27 15:42:19 +0000
177@@ -18,7 +18,7 @@
178 seller_delay: '1'
179 seller_ids:
180 - delay: 1
181- name: base.res_partner_agrolait
182+ name: base.res_partner_2
183 min_qty: 2.0
184 qty: 5.0
185 standard_price: 189.0
186
187=== added directory 'openerpcommand/benchmark'
188=== added file 'openerpcommand/benchmark/__init__.py'
189--- openerpcommand/benchmark/__init__.py 1970-01-01 00:00:00 +0000
190+++ openerpcommand/benchmark/__init__.py 2012-11-27 15:42:19 +0000
191@@ -0,0 +1,111 @@
192+"""
193+Base class for benchmark
194+"""
195+import sys
196+import hashlib
197+import multiprocessing
198+import time
199+
200+from openerpcommand.common import Client
201+
202+class Benchmark(Client):
203+ """
204+ Base class for concurrent benchmarks. The measure_once() method must be
205+ overriden.
206+
207+ Each sub-benchmark will be run in its own process then a report is done
208+ with all the results (shared with the main process using a
209+ `multiprocessing.Array`).
210+ """
211+
212+ def __init__(self, parser):
213+ super(Benchmark, self).__init__(parser)
214+ self.parser.add_argument('-n', '--samples', metavar='SAMPLES',
215+ default=100, help='number of measurements to take.')
216+ # TODO if -n <samples>s is given (instead of -n <samples>), run the
217+ # benchmark for <samples> seconds and return the number of iterations.
218+ self.parser.add_argument('-o', '--output', metavar='FILE',
219+ required=True, help='path to save the generated report.')
220+ self.parser.add_argument('--append', action='store_true',
221+ default=False, help='append the report to an existing file.')
222+ self.parser.add_argument('-j', '--jobs', metavar='JOBS',
223+ default=1, help='number of concurrent workers')
224+ self.parser.add_argument('--seed', metavar='SEED',
225+ default=0, help='a value to ensure different runs can create unique data.')
226+ self.worker = -1
227+
228+ def work(self, iarr=None):
229+ if iarr:
230+ # If an array is given, it means we are a worker process...
231+ self.work_slave(iarr)
232+ else:
233+ # ... else we are the main process and we will spawn workers,
234+ # passing them an array.
235+ self.work_master()
236+
237+ def work_master(self):
238+ N = int(self.args.samples)
239+ self.arrs = [(i, multiprocessing.Array('f', range(N)))
240+ for i in xrange(int(self.args.jobs))]
241+ ps = [multiprocessing.Process(target=self.run, args=(arr,))
242+ for arr in self.arrs]
243+ [p.start() for p in ps]
244+ [p.join() for p in ps]
245+
246+ self.report_html()
247+
248+ def work_slave(self, iarr):
249+ j, arr = iarr
250+ self.worker = j
251+ N = int(self.args.samples)
252+ total_t0 = time.time()
253+ for i in xrange(N):
254+ t0 = time.time()
255+ self.measure_once(i)
256+ t1 = time.time()
257+ arr[i] = t1 - t0
258+ print >> sys.stdout, '\r%s' % ('|' * (i * 60 / N)),
259+ print >> sys.stdout, '%s %s%%' % \
260+ (' ' * (60 - (i * 60 / N)), int(float(i+1)/N*100)),
261+ sys.stdout.flush()
262+ total_t1 = time.time()
263+ print '\nDone in %ss.' % (total_t1 - total_t0)
264+
265+ def report_html(self):
266+ series = []
267+ for arr in self.arrs:
268+ serie = """{
269+ data: %s,
270+ points: { show: true }
271+ }""" % ([[x, i] for i, x in enumerate(arr)],)
272+ series.append(serie)
273+ chart_id = hashlib.md5(" ".join(sys.argv)).hexdigest()
274+ HEADER = """<!doctype html>
275+<title>Benchmarks</title>
276+<meta charset=utf-8>
277+<script type="text/javascript" src="js/jquery.min.js"></script>
278+<script type="text/javascript" src="js/jquery.flot.js"></script>
279+"""
280+
281+ CONTENT = """<h1>%s</h1>
282+%s
283+<div id='chart_%s' style='width:400px;height:300px;'>...</div>
284+<script type="text/javascript">
285+$.plot($("#chart_%s"), [%s],
286+ {yaxis: { ticks: false }});
287+</script>""" % (self.bench_name, ' '.join(sys.argv), chart_id, chart_id,
288+ ','.join(series))
289+ if self.args.append:
290+ with open(self.args.output, 'a') as f:
291+ f.write(CONTENT,)
292+ else:
293+ with open(self.args.output, 'w') as f:
294+ f.write(HEADER + CONTENT,)
295+
296+ def measure_once(self, i):
297+ """
298+ The `measure_once` method is called --jobs times. A `i` argument is
299+ supplied to allow to create unique values for each execution (e.g. to
300+ supply fresh identifiers to a `create` method.
301+ """
302+ pass
303
304=== added file 'openerpcommand/benchmark/dummy.py'
305--- openerpcommand/benchmark/dummy.py 1970-01-01 00:00:00 +0000
306+++ openerpcommand/benchmark/dummy.py 2012-11-27 15:42:19 +0000
307@@ -0,0 +1,18 @@
308+"""
309+Dummy (call test.limits.model.consume_nothing()).
310+"""
311+from openerpcommand.benchmark import Benchmark
312+
313+class Dummy(Benchmark):
314+ bench_name = 'test.limits.model.consume_nothing()'
315+
316+ def __init__(self, parser):
317+ super(Dummy, self).__init__(parser)
318+ self.parser.add_argument('-a', '--args', metavar='ARGS',
319+ default='', help='some arguments to serialize')
320+
321+ def measure_once(self, i):
322+ self.execute('test.limits.model', 'consume_nothing')
323+
324+def init_parser(parser):
325+ Dummy(parser)
326
327=== added file 'openerpcommand/benchmark/fields_view_get.py'
328--- openerpcommand/benchmark/fields_view_get.py 1970-01-01 00:00:00 +0000
329+++ openerpcommand/benchmark/fields_view_get.py 2012-11-27 15:42:19 +0000
330@@ -0,0 +1,20 @@
331+"""
332+Read a record's fields and view architecture repeatedly.
333+"""
334+from openerpcommand.benchmark import Benchmark
335+
336+class FieldsViewGet(Benchmark):
337+ bench_name = 'res.users.fields_view_get(1)'
338+
339+ def __init__(self, parser):
340+ super(FieldsViewGet, self).__init__(parser)
341+ self.parser.add_argument('-m', '--model', metavar='MODEL',
342+ required=True, help='the model')
343+ self.parser.add_argument('-i', '--id', metavar='RECORDID',
344+ required=True, help='the record id')
345+
346+ def measure_once(self, i):
347+ self.execute(self.args.model, 'fields_view_get', self.args.id)
348+
349+def init_parser(parser):
350+ FieldsViewGet(parser)
351
352=== added file 'openerpcommand/benchmark/login.py'
353--- openerpcommand/benchmark/login.py 1970-01-01 00:00:00 +0000
354+++ openerpcommand/benchmark/login.py 2012-11-27 15:42:19 +0000
355@@ -0,0 +1,13 @@
356+"""
357+Login (update res_users.date).
358+"""
359+from openerpcommand.benchmark import Benchmark
360+
361+class Login(Benchmark):
362+ bench_name = 'res.users.login(1)'
363+
364+ def measure_once(self, i):
365+ self.common_proxy.login(self.database, self.user, self.password)
366+
367+def init_parser(parser):
368+ Login(parser)
369
370=== added file 'openerpcommand/benchmark/read.py'
371--- openerpcommand/benchmark/read.py 1970-01-01 00:00:00 +0000
372+++ openerpcommand/benchmark/read.py 2012-11-27 15:42:19 +0000
373@@ -0,0 +1,20 @@
374+"""
375+Define a base class for client-side benchmarking.
376+"""
377+from openerpcommand.benchmark import Benchmark
378+
379+class Read(Benchmark):
380+ bench_name = 'res.users.read(1)'
381+
382+ def __init__(self, parser):
383+ super(Read, self).__init__(parser)
384+ self.parser.add_argument('-m', '--model', metavar='MODEL',
385+ required=True, help='the model')
386+ self.parser.add_argument('-i', '--id', metavar='RECORDID',
387+ required=True, help='the record id')
388+
389+ def measure_once(self, i):
390+ self.execute(self.args.model, 'read', [self.args.id], [])
391+
392+def init_parser(parser):
393+ Read(parser)
394
395=== renamed file 'openerpcommand/bench_sale_mrp.py' => 'openerpcommand/benchmark/sale_mrp.py'
396--- openerpcommand/bench_sale_mrp.py 2012-02-06 14:54:54 +0000
397+++ openerpcommand/benchmark/sale_mrp.py 2012-11-27 15:42:19 +0000
398@@ -1,23 +1,17 @@
399-"""
400-Benchmark based on the `sale_mrp` addons (in `sale_mrp/test/sale_mrp.yml`).
401-"""
402+"""\
403+Similar to `sale_mrp/test/sale_mrp.yml`.
404
405+This benchmarks the OpenERP server `sale_mrp` module by creating and
406+confirming a sale order. As it creates data in the server, it is necessary
407+to ensure unique names for the newly created data. You can use the --seed
408+argument to give a lower bound to those names. (The number of generated
409+names is JOBS * SAMPLES.)
410+"""
411 import time
412
413-from .benchmarks import Bench
414-
415-class BenchSaleMrp(Bench):
416- """\
417- Similar to `sale_mrp/test/sale_mrp.yml`.
418-
419- This benchmarks the OpenERP server `sale_mrp` module by creating and
420- confirming a sale order. As it creates data in the server, it is necessary
421- to ensure unique names for the newly created data. You can use the --seed
422- argument to give a lower bound to those names. (The number of generated
423- names is --jobs * --samples.)
424- """
425-
426- command_name = 'bench-sale-mrp'
427+from openerpcommand.benchmark import Benchmark
428+
429+class SaleMrp(Benchmark):
430 bench_name = '`sale_mrp/test/sale_mrp.yml`'
431
432 def measure_once(self, i):
433@@ -33,7 +27,7 @@
434 res_partner_4 = self.execute('ir.model.data', 'get_object_reference', 'base', 'res_partner_4')[1]
435 res_partner_address_7 = self.execute('ir.model.data', 'get_object_reference', 'base', 'res_partner_address_7')[1]
436 list0 = self.execute('ir.model.data', 'get_object_reference', 'product', 'list0')[1]
437- shop = self.execute('ir.model.data', 'get_object_reference', 'sale', 'shop')[1]
438+ shop = self.execute('ir.model.data', 'get_object_reference', 'sale', 'sale_shop_1')[1]
439
440 # Create a sale order for the product `Slider Mobile`.
441 data = {
442@@ -66,3 +60,5 @@
443 # Confirm the sale order.
444 self.object_proxy.exec_workflow(self.database, self.uid, self.password, 'sale.order', 'order_confirm', sale_order_id, {})
445
446+def init_parser(parser):
447+ SaleMrp(parser)
448
449=== removed file 'openerpcommand/benchmarks.py'
450--- openerpcommand/benchmarks.py 2012-07-23 09:51:09 +0000
451+++ openerpcommand/benchmarks.py 1970-01-01 00:00:00 +0000
452@@ -1,166 +0,0 @@
453-"""
454-Define a base class for client-side benchmarking.
455-"""
456-import hashlib
457-import multiprocessing
458-import sys
459-import time
460-
461-from .client import Client
462-
463-class Bench(Client):
464- """
465- Base class for concurrent benchmarks. The measure_once() method must be
466- overriden.
467-
468- Each sub-benchmark will be run in its own process then a report is done
469- with all the results (shared with the main process using a
470- `multiprocessing.Array`).
471- """
472-
473- def __init__(self, subparsers=None):
474- super(Bench, self).__init__(subparsers)
475- self.parser.add_argument('-n', '--samples', metavar='INT',
476- default=100, help='number of measurements to take')
477- # TODO if -n <int>s is given (instead of -n <int>), run the
478- # benchmark for <int> seconds and return the number of iterations.
479- self.parser.add_argument('-o', '--output', metavar='PATH',
480- required=True, help='path to save the generated report')
481- self.parser.add_argument('--append', action='store_true',
482- default=False, help='append the report to an existing file')
483- self.parser.add_argument('-j', '--jobs', metavar='JOBS',
484- default=1, help='number of concurrent workers')
485- self.parser.add_argument('--seed', metavar='SEED',
486- default=0, help='a value to ensure different runs can create unique data')
487- self.worker = -1
488-
489- def work(self, iarr=None):
490- if iarr:
491- # If an array is given, it means we are a worker process...
492- self.work_slave(iarr)
493- else:
494- # ... else we are the main process and we will spawn workers,
495- # passing them an array.
496- self.work_master()
497-
498- def work_master(self):
499- N = int(self.args.samples)
500- self.arrs = [(i, multiprocessing.Array('f', range(N)))
501- for i in xrange(int(self.args.jobs))]
502- ps = [multiprocessing.Process(target=self.run, args=(arr,))
503- for arr in self.arrs]
504- [p.start() for p in ps]
505- [p.join() for p in ps]
506-
507- self.report_html()
508-
509- def work_slave(self, iarr):
510- j, arr = iarr
511- self.worker = j
512- N = int(self.args.samples)
513- total_t0 = time.time()
514- for i in xrange(N):
515- t0 = time.time()
516- self.measure_once(i)
517- t1 = time.time()
518- arr[i] = t1 - t0
519- print >> sys.stdout, '\r%s' % ('|' * (i * 60 / N)),
520- print >> sys.stdout, '%s %s%%' % \
521- (' ' * (60 - (i * 60 / N)), int(float(i+1)/N*100)),
522- sys.stdout.flush()
523- total_t1 = time.time()
524- print '\nDone in %ss.' % (total_t1 - total_t0)
525-
526- def report_html(self):
527- series = []
528- for arr in self.arrs:
529- serie = """{
530- data: %s,
531- points: { show: true }
532- }""" % ([[x, i] for i, x in enumerate(arr)],)
533- series.append(serie)
534- chart_id = hashlib.md5(" ".join(sys.argv)).hexdigest()
535- HEADER = """<!doctype html>
536-<title>Benchmarks</title>
537-<meta charset=utf-8>
538-<script type="text/javascript" src="js/jquery.min.js"></script>
539-<script type="text/javascript" src="js/jquery.flot.js"></script>
540-"""
541-
542- CONTENT = """<h1>%s</h1>
543-%s
544-<div id='chart_%s' style='width:400px;height:300px;'>...</div>
545-<script type="text/javascript">
546-$.plot($("#chart_%s"), [%s],
547- {yaxis: { ticks: false }});
548-</script>""" % (self.bench_name, ' '.join(sys.argv), chart_id, chart_id,
549- ','.join(series))
550- if self.args.append:
551- with open(self.args.output, 'a') as f:
552- f.write(CONTENT,)
553- else:
554- with open(self.args.output, 'w') as f:
555- f.write(HEADER + CONTENT,)
556-
557- def measure_once(self, i):
558- """
559- The `measure_once` method is called --jobs times. A `i` argument is
560- supplied to allow to create unique values for each execution (e.g. to
561- supply fresh identifiers to a `create` method.
562- """
563- pass
564-
565-class BenchRead(Bench):
566- """Read a record repeatedly."""
567-
568- command_name = 'bench-read'
569- bench_name = 'res.users.read(1)'
570-
571- def __init__(self, subparsers=None):
572- super(BenchRead, self).__init__(subparsers)
573- self.parser.add_argument('-m', '--model', metavar='MODEL',
574- required=True, help='the model')
575- self.parser.add_argument('-i', '--id', metavar='RECORDID',
576- required=True, help='the record id')
577-
578- def measure_once(self, i):
579- self.execute(self.args.model, 'read', [self.args.id], [])
580-
581-class BenchFieldsViewGet(Bench):
582- """Read a record's fields and view architecture repeatedly."""
583-
584- command_name = 'bench-view'
585- bench_name = 'res.users.fields_view_get(1)'
586-
587- def __init__(self, subparsers=None):
588- super(BenchFieldsViewGet, self).__init__(subparsers)
589- self.parser.add_argument('-m', '--model', metavar='MODEL',
590- required=True, help='the model')
591- self.parser.add_argument('-i', '--id', metavar='RECORDID',
592- required=True, help='the record id')
593-
594- def measure_once(self, i):
595- self.execute(self.args.model, 'fields_view_get', self.args.id)
596-
597-class BenchDummy(Bench):
598- """Dummy (call test.limits.model.consume_nothing())."""
599-
600- command_name = 'bench-dummy'
601- bench_name = 'test.limits.model.consume_nothing()'
602-
603- def __init__(self, subparsers=None):
604- super(BenchDummy, self).__init__(subparsers)
605- self.parser.add_argument('-a', '--args', metavar='ARGS',
606- default='', help='some arguments to serialize')
607-
608- def measure_once(self, i):
609- self.execute('test.limits.model', 'consume_nothing')
610-
611-class BenchLogin(Bench):
612- """Login (update res_users.date)."""
613-
614- command_name = 'bench-login'
615- bench_name = 'res.users.login(1)'
616-
617- def measure_once(self, i):
618- self.common_proxy.login(self.database, self.user, self.password)
619
620=== modified file 'openerpcommand/call.py'
621--- openerpcommand/call.py 2012-02-10 16:19:48 +0000
622+++ openerpcommand/call.py 2012-11-27 15:42:19 +0000
623@@ -1,29 +1,18 @@
624 """
625 Call an arbitrary model's method.
626+
627+Example:
628+ > oe call res.users.read '[1, 3]' '[]' -u 1 -p admin
629 """
630 import ast
631-import os
632 import pprint
633 import sys
634-import time
635-import xmlrpclib
636-
637-import client
638-
639-class Call(client.Client):
640- """\
641- Call an arbitrary model's method.
642-
643- Example:
644- > oe call res.users.read '[1, 3]' '[]' -u 1 -p admin
645- """
646- # TODO The above docstring is completely borked in the
647- # --help message.
648-
649- command_name = 'call'
650-
651- def __init__(self, subparsers=None):
652- super(Call, self).__init__(subparsers)
653+
654+from openerpcommand.common import Client
655+
656+class Call(Client):
657+ def __init__(self, parser):
658+ super(Call, self).__init__(parser)
659 self.parser.add_argument('call', metavar='MODEL.METHOD',
660 help='the model and the method to call, using the '
661 '<model>.<method> format.')
662@@ -42,3 +31,5 @@
663 x = self.execute(model, method, *args)
664 pprint.pprint(x, indent=4)
665
666+def init_parser(parser):
667+ Call(parser)
668
669=== removed file 'openerpcommand/client.py'
670--- openerpcommand/client.py 2012-01-20 15:41:17 +0000
671+++ openerpcommand/client.py 1970-01-01 00:00:00 +0000
672@@ -1,137 +0,0 @@
673-"""
674-Define a few common arguments for client-side command-line tools.
675-"""
676-import os
677-import sys
678-import time
679-import xmlrpclib
680-
681-import common
682-
683-class Client(common.Command):
684- """
685- Base class for XML-RPC command-line clients. It must be inherited and the
686- work() method overriden.
687- """
688-
689- def __init__(self, subparsers=None):
690- super(Client, self).__init__(subparsers)
691- required_or_default = common.required_or_default
692- self.parser.add_argument('-H', '--host', metavar='HOST',
693- **required_or_default('HOST', 'the server host'))
694- self.parser.add_argument('-P', '--port', metavar='PORT',
695- **required_or_default('PORT', 'the server port'))
696-
697- def execute(self, *args):
698- return self.object_proxy.execute(self.database, self.uid, self.password, *args)
699-
700- def initialize(self):
701- self.host = self.args.host
702- self.port = int(self.args.port)
703- self.database = self.args.database
704- self.user = self.args.user
705- self.password = self.args.password
706-
707- self.url = 'http://%s:%d/xmlrpc/' % (self.host, self.port)
708- self.common_proxy = xmlrpclib.ServerProxy(self.url + 'common')
709- self.object_proxy = xmlrpclib.ServerProxy(self.url + 'object')
710-
711- try:
712- self.uid = int(self.user)
713- except ValueError, e:
714- self.uid = self.common_proxy.login(self.database, self.user, self.password)
715-
716- def run(self, *args):
717- self.initialize()
718- self.work(*args)
719-
720- def work(self, *args):
721- pass
722-
723-class Open(Client):
724- """Get the web client's URL to view a specific model."""
725-
726- command_name = 'open'
727-
728- def __init__(self, subparsers=None):
729- super(Open, self).__init__(subparsers)
730- self.parser.add_argument('-m', '--model', metavar='MODEL',
731- required=True, help='the view type')
732- self.parser.add_argument('-v', '--view-mode', metavar='VIEWMODE',
733- default='tree', help='the view mode')
734-
735- def work(self):
736- ids = self.execute('ir.actions.act_window', 'search', [
737- ('res_model', '=', self.args.model),
738- ('view_mode', 'like', self.args.view_mode),
739- ])
740- xs = self.execute('ir.actions.act_window', 'read', ids, [])
741- for x in xs:
742- print x['id'], x['name']
743- d = {}
744- d['host'] = self.host
745- d['port'] = self.port
746- d['action_id'] = x['id']
747- print " http://%(host)s:%(port)s/web/webclient/home#action_id=%(action_id)s" % d
748-
749-class Show(Client):
750- """Display a record."""
751-
752- command_name = 'show'
753-
754- def __init__(self, subparsers=None):
755- super(Show, self).__init__(subparsers)
756- self.parser.add_argument('-m', '--model', metavar='MODEL',
757- required=True, help='the model')
758- self.parser.add_argument('-i', '--id', metavar='RECORDID',
759- required=True, help='the record id')
760-
761- def work(self):
762- xs = self.execute(self.args.model, 'read', [self.args.id], [])
763- if xs:
764- x = xs[0]
765- print x['name']
766- else:
767- print "Record not found."
768-
769-class ConsumeNothing(Client):
770- """Call test.limits.model.consume_nothing()."""
771-
772- command_name = 'consume-nothing'
773-
774- def work(self):
775- xs = self.execute('test.limits.model', 'consume_nothing')
776-
777-class ConsumeMemory(Client):
778- """Call test.limits.model.consume_memory()."""
779-
780- command_name = 'consume-memory'
781-
782- def __init__(self, subparsers=None):
783- super(ConsumeMemory, self).__init__(subparsers)
784- self.parser.add_argument('--size', metavar='SIZE',
785- required=True, help='size of the list to allocate')
786-
787- def work(self):
788- xs = self.execute('test.limits.model', 'consume_memory', int(self.args.size))
789-
790-class LeakMemory(ConsumeMemory):
791- """Call test.limits.model.leak_memory()."""
792-
793- command_name = 'leak-memory'
794-
795- def work(self):
796- xs = self.execute('test.limits.model', 'leak_memory', int(self.args.size))
797-
798-class ConsumeCPU(Client):
799- """Call test.limits.model.consume_cpu_time()."""
800-
801- command_name = 'consume-cpu'
802-
803- def __init__(self, subparsers=None):
804- super(ConsumeCPU, self).__init__(subparsers)
805- self.parser.add_argument('--seconds', metavar='INT',
806- required=True, help='how much CPU time to consume')
807-
808- def work(self):
809- xs = self.execute('test.limits.model', 'consume_cpu_time', int(self.args.seconds))
810
811=== modified file 'openerpcommand/common.py'
812--- openerpcommand/common.py 2012-10-30 15:11:48 +0000
813+++ openerpcommand/common.py 2012-11-27 15:42:19 +0000
814@@ -1,9 +1,9 @@
815 """
816-Define a few common arguments for server-side command-line tools.
817+Define a few common arguments for server-side (Command) and client-side (Client) command-line tools.
818 """
819-import argparse
820 import os
821 import sys
822+import xmlrpclib
823
824 def add_addons_argument(parser):
825 """
826@@ -37,28 +37,24 @@
827 a mandatory argument.
828 """
829 if os.environ.get('OPENERP_' + name.upper()):
830- d = {'default': os.environ['OPENERP_' + name.upper()]}
831+ d = {'default': os.environ['OPENERP_' + name.upper()]}
832 else:
833- d = {'required': True}
834+ d = {'required': True}
835 d['help'] = h + '. The environment variable OPENERP_' + \
836- name.upper() + ' can be used instead.'
837+ name.upper() + ' can be used instead.'
838 return d
839
840+def expand_path(path):
841+ return os.path.expanduser(os.path.expandvars(path))
842+
843 class Command(object):
844 """
845 Base class to create command-line tools. It must be inherited and the
846 run() method overriden.
847 """
848
849- command_name = 'stand-alone'
850-
851- def __init__(self, subparsers=None):
852- if subparsers:
853- self.parser = parser = subparsers.add_parser(self.command_name,
854- description=self.__class__.__doc__)
855- else:
856- self.parser = parser = argparse.ArgumentParser(
857- description=self.__class__.__doc__)
858+ def __init__(self, parser):
859+ self.parser = parser
860
861 parser.add_argument('-d', '--database', metavar='DATABASE',
862 **required_or_default('DATABASE', 'the database to connect to'))
863@@ -86,3 +82,42 @@
864 command = cls()
865 args = command.parser.parse_args()
866 args.run(args)
867+
868+class Client(Command):
869+ """
870+ Base class for XML-RPC command-line clients. It must be inherited and the
871+ work() method overriden.
872+ """
873+
874+ def __init__(self, parser):
875+ super(Client, self).__init__(parser)
876+ self.parser.add_argument('-H', '--host', metavar='HOST',
877+ **required_or_default('HOST', 'the server host'))
878+ self.parser.add_argument('-P', '--port', metavar='PORT',
879+ **required_or_default('PORT', 'the server port'))
880+
881+ def execute(self, *args):
882+ return self.object_proxy.execute(self.database, self.uid, self.password, *args)
883+
884+ def initialize(self):
885+ self.host = self.args.host
886+ self.port = int(self.args.port)
887+ self.database = self.args.database
888+ self.user = self.args.user
889+ self.password = self.args.password
890+
891+ self.url = 'http://%s:%d/xmlrpc/' % (self.host, self.port)
892+ self.common_proxy = xmlrpclib.ServerProxy(self.url + 'common')
893+ self.object_proxy = xmlrpclib.ServerProxy(self.url + 'object')
894+
895+ try:
896+ self.uid = int(self.user)
897+ except ValueError, e:
898+ self.uid = self.common_proxy.login(self.database, self.user, self.password)
899+
900+ def run(self, *args):
901+ self.initialize()
902+ self.work(*args)
903+
904+ def work(self, *args):
905+ pass
906
907=== modified file 'openerpcommand/conf.py'
908--- openerpcommand/conf.py 2012-10-31 11:26:36 +0000
909+++ openerpcommand/conf.py 2012-11-27 15:42:19 +0000
910@@ -1,13 +1,11 @@
911 """
912 Display the currently used configuration. The configuration for any
913-sub-command is normally given by options. But some options can be specified
914-using environment variables. This sub-command shows those variables.
915-A `set` sub-command should be provided when the configuration is in a real
916-configuration file instead of environment variables.
917+sub-command is normally given by options. But some options can be
918+specified using environment variables. This sub-command shows those
919+variables. A `set` sub-command should be provided when the configuration
920+is in a real configuration file instead of environment variables.
921 """
922 import os
923-import sys
924-import textwrap
925
926 def run(args):
927 for x in ('database', 'addons', 'host', 'port'):
928@@ -18,8 +16,5 @@
929 print '%s: <not set>' % (x, )
930 os.environ['OPENERP_DATABASE'] = 'yeah'
931
932-def add_parser(subparsers):
933- parser = subparsers.add_parser('conf',
934- description='Display the currently used configuration.')
935-
936+def init_parser(parser):
937 parser.set_defaults(run=run)
938
939=== added file 'openerpcommand/consume_cpu.py'
940--- openerpcommand/consume_cpu.py 1970-01-01 00:00:00 +0000
941+++ openerpcommand/consume_cpu.py 2012-11-27 15:42:19 +0000
942@@ -0,0 +1,16 @@
943+"""
944+Call test.limits.model.consume_cpu_time().
945+"""
946+from openerpcommand.common import Client
947+
948+class ConsumeCPU(Client):
949+ def __init__(self, parser):
950+ super(ConsumeCPU, self).__init__(parser)
951+ self.parser.add_argument('--seconds', metavar='INT',
952+ required=True, help='how much CPU time to consume')
953+
954+ def work(self):
955+ xs = self.execute('test.limits.model', 'consume_cpu_time', int(self.args.seconds))
956+
957+def init_parser(parser):
958+ ConsumeCPU(parser)
959
960=== added file 'openerpcommand/consume_memory.py'
961--- openerpcommand/consume_memory.py 1970-01-01 00:00:00 +0000
962+++ openerpcommand/consume_memory.py 2012-11-27 15:42:19 +0000
963@@ -0,0 +1,16 @@
964+"""
965+Call test.limits.model.consume_memory().
966+"""
967+from openerpcommand.common import Client
968+
969+class ConsumeMemory(Client):
970+ def __init__(self, parser):
971+ super(ConsumeMemory, self).__init__(parser)
972+ self.parser.add_argument('--size', metavar='SIZE',
973+ required=True, help='size of the list to allocate')
974+
975+ def work(self):
976+ xs = self.execute('test.limits.model', 'consume_memory', int(self.args.size))
977+
978+def init_parser(parser):
979+ ConsumeMemory(parser)
980
981=== added file 'openerpcommand/consume_nothing.py'
982--- openerpcommand/consume_nothing.py 1970-01-01 00:00:00 +0000
983+++ openerpcommand/consume_nothing.py 2012-11-27 15:42:19 +0000
984@@ -0,0 +1,11 @@
985+"""
986+Call test.limits.model.consume_nothing().
987+"""
988+from openerpcommand.common import Client
989+
990+class ConsumeNothing(Client):
991+ def work(self):
992+ xs = self.execute('test.limits.model', 'consume_nothing')
993+
994+def init_parser(parser):
995+ ConsumeNothing(parser)
996
997=== modified file 'openerpcommand/drop.py'
998--- openerpcommand/drop.py 2012-08-23 09:25:05 +0000
999+++ openerpcommand/drop.py 2012-11-27 15:42:19 +0000
1000@@ -1,8 +1,7 @@
1001 """
1002 Drop a database.
1003 """
1004-
1005-import common
1006+from openerpcommand import common
1007
1008 # TODO turn template1 in a parameter
1009 # This should be exposed from openerp (currently in
1010@@ -36,10 +35,7 @@
1011 assert args.database
1012 drop_database(args.database)
1013
1014-def add_parser(subparsers):
1015- parser = subparsers.add_parser('drop',
1016- description='Drop a database.')
1017+def init_parser(parser):
1018 parser.add_argument('-d', '--database', metavar='DATABASE',
1019 **common.required_or_default('DATABASE', 'the database to create'))
1020-
1021 parser.set_defaults(run=run)
1022
1023=== modified file 'openerpcommand/initialize.py'
1024--- openerpcommand/initialize.py 2012-11-05 17:34:39 +0000
1025+++ openerpcommand/initialize.py 2012-11-27 15:42:19 +0000
1026@@ -1,10 +1,9 @@
1027 """
1028 Install OpenERP on a new (by default) database.
1029+Create and initialize a new OpenERP database.
1030 """
1031-import os
1032 import sys
1033-
1034-import common
1035+from openerpcommand import common
1036
1037 def install_openerp(database_name, create_database_flag, module_names):
1038 import openerp
1039@@ -47,6 +46,10 @@
1040
1041 config = openerp.tools.config
1042
1043+ if args.drop:
1044+ import drop
1045+ drop.drop_database(args.database)
1046+
1047 if args.tests:
1048 config['log_handler'] = [':TEST']
1049 config['test_enable'] = True
1050@@ -57,7 +60,7 @@
1051 config['without_demo'] = True
1052
1053 if args.addons:
1054- args.addons = args.addons.split(':')
1055+ args.addons = map(common.expand_path, args.addons.split(':'))
1056 else:
1057 args.addons = []
1058 config['addons_path'] = ','.join(args.addons)
1059@@ -77,11 +80,11 @@
1060 if hasattr(registry, '_assertion_report'):
1061 sys.exit(1 if registry._assertion_report.failures else 0)
1062
1063-def add_parser(subparsers):
1064- parser = subparsers.add_parser('initialize',
1065- description='Create and initialize a new OpenERP database.')
1066+def init_parser(parser):
1067 parser.add_argument('-d', '--database', metavar='DATABASE',
1068 **common.required_or_default('DATABASE', 'the database to create'))
1069+ parser.add_argument('--drop', action='store_true',
1070+ default=False, help="Drop the database if exists")
1071 common.add_addons_argument(parser)
1072 parser.add_argument('--module', metavar='MODULE', action='append',
1073 help='specify a module to install'
1074@@ -98,5 +101,4 @@
1075 ' (use the `run-tests` command to choose specific'
1076 ' tests to run against an existing database).'
1077 ' Demo data are installed.')
1078-
1079 parser.set_defaults(run=run)
1080
1081=== added file 'openerpcommand/leak_memory.py'
1082--- openerpcommand/leak_memory.py 1970-01-01 00:00:00 +0000
1083+++ openerpcommand/leak_memory.py 2012-11-27 15:42:19 +0000
1084@@ -0,0 +1,11 @@
1085+"""
1086+Call test.limits.model.leak_memory().
1087+"""
1088+from .consume_memory import ConsumeMemory
1089+
1090+class LeakMemory(ConsumeMemory):
1091+ def work(self):
1092+ xs = self.execute('test.limits.model', 'leak_memory', int(self.args.size))
1093+
1094+def init_parser(parser):
1095+ LeakMemory(parser)
1096
1097=== modified file 'openerpcommand/model.py'
1098--- openerpcommand/model.py 2012-02-14 15:05:03 +0000
1099+++ openerpcommand/model.py 2012-11-27 15:42:19 +0000
1100@@ -1,7 +1,6 @@
1101 """
1102-Display information about a given model.
1103+Display information about a given model for an existing database.
1104 """
1105-import os
1106 import sys
1107 import textwrap
1108
1109@@ -46,9 +45,7 @@
1110 if args.verbose and v.help:
1111 print textwrap.fill(v.help, initial_indent=' ', subsequent_indent=' ')
1112
1113-def add_parser(subparsers):
1114- parser = subparsers.add_parser('model',
1115- description='Display information about a given model for an existing database.')
1116+def init_parser(parser):
1117 parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
1118 help='the database to connect to')
1119 parser.add_argument('-m', '--model', metavar='MODEL', required=True,
1120
1121=== modified file 'openerpcommand/module.py'
1122--- openerpcommand/module.py 2012-08-23 09:25:05 +0000
1123+++ openerpcommand/module.py 2012-11-27 15:42:19 +0000
1124@@ -1,11 +1,12 @@
1125 """
1126 Show module information for a given database or from the file-system.
1127+Display modules known from a given database or on file-system.
1128 """
1129 import os
1130 import sys
1131 import textwrap
1132
1133-from . import common
1134+from openerpcommand import common
1135
1136 # TODO provide a --rpc flag to use XML-RPC (with a specific username) instead
1137 # of server-side library.
1138@@ -16,7 +17,7 @@
1139 config = openerp.tools.config
1140 config['log_handler'] = [':CRITICAL']
1141 if args.addons:
1142- args.addons = args.addons.split(':')
1143+ args.addons = map(common.expand_path, args.addons.split(':'))
1144 else:
1145 args.addons = []
1146 config['addons_path'] = ','.join(args.addons)
1147@@ -50,9 +51,7 @@
1148 else:
1149 print "No module found (database `%s`)." % (args.database,)
1150
1151-def add_parser(subparsers):
1152- parser = subparsers.add_parser('module',
1153- description='Display modules known from a given database or on file-system.')
1154+def init_parser(parser):
1155 parser.add_argument('-d', '--database', metavar='DATABASE',
1156 **common.required_or_default('DATABASE', 'the database to modify'))
1157 common.add_addons_argument(parser)
1158
1159=== added file 'openerpcommand/open.py'
1160--- openerpcommand/open.py 1970-01-01 00:00:00 +0000
1161+++ openerpcommand/open.py 2012-11-27 15:42:19 +0000
1162@@ -0,0 +1,29 @@
1163+"""
1164+Get the web client's URL to view a specific model.
1165+"""
1166+from openerpcommand.common import Client
1167+
1168+class Open(Client):
1169+ def __init__(self, parser):
1170+ super(Open, self).__init__(parser)
1171+ self.parser.add_argument('-m', '--model', metavar='MODEL',
1172+ required=True, help='the view type')
1173+ self.parser.add_argument('-v', '--view-mode', metavar='VIEWMODE',
1174+ default='tree', help='the view mode')
1175+
1176+ def work(self):
1177+ ids = self.execute('ir.actions.act_window', 'search', [
1178+ ('res_model', '=', self.args.model),
1179+ ('view_mode', 'like', self.args.view_mode),
1180+ ])
1181+ xs = self.execute('ir.actions.act_window', 'read', ids, [])
1182+ for x in xs:
1183+ print x['id'], x['name']
1184+ d = {}
1185+ d['host'] = self.host
1186+ d['port'] = self.port
1187+ d['action_id'] = x['id']
1188+ print " http://%(host)s:%(port)s/web/webclient/home#action_id=%(action_id)s" % d
1189+
1190+def init_parser(parser):
1191+ Open(parser)
1192
1193=== modified file 'openerpcommand/read.py'
1194--- openerpcommand/read.py 2012-11-05 17:34:39 +0000
1195+++ openerpcommand/read.py 2012-11-27 15:42:19 +0000
1196@@ -41,9 +41,7 @@
1197 else:
1198 print "Record not found."
1199
1200-def add_parser(subparsers):
1201- parser = subparsers.add_parser('read',
1202- description='Display a record.')
1203+def init_parser(parser):
1204 parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
1205 help='the database to connect to')
1206 parser.add_argument('-m', '--model', metavar='MODEL', required=True,
1207@@ -56,5 +54,4 @@
1208 help='display less information')
1209 parser.add_argument('-f', '--field', metavar='FIELD',
1210 help='display information only for this particular field')
1211-
1212 parser.set_defaults(run=run)
1213
1214=== modified file 'openerpcommand/run_tests.py'
1215--- openerpcommand/run_tests.py 2012-11-19 13:23:37 +0000
1216+++ openerpcommand/run_tests.py 2012-11-27 15:42:19 +0000
1217@@ -1,12 +1,13 @@
1218 """
1219 Execute the unittest2 tests available in OpenERP addons.
1220+Run the OpenERP server and/or addons tests.
1221 """
1222
1223 import os
1224 import sys
1225 import types
1226
1227-import common
1228+from openerpcommand import common
1229
1230 def get_test_modules(module, submodule, explode):
1231 """
1232@@ -102,7 +103,7 @@
1233 config['db_name'] = args.database
1234 config['addons_path'] = args.addons.replace(':',',')
1235 if args.addons:
1236- args.addons = args.addons.split(':')
1237+ args.addons = map(common.expand_path, args.addons.split(':'))
1238 else:
1239 args.addons = []
1240 if args.sanity_checks and args.fast_suite:
1241@@ -169,9 +170,7 @@
1242 for test_module in test_modules:
1243 print ' ', test_module.__name__
1244
1245-def add_parser(subparsers):
1246- parser = subparsers.add_parser('run-tests',
1247- description='Run the OpenERP server and/or addons tests.')
1248+def init_parser(parser):
1249 parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
1250 help='the database to test. Depending on the test suites, the '
1251 'database must already exist or not.')
1252@@ -192,5 +191,4 @@
1253 help='run only the sanity check tests')
1254 parser.add_argument('--dry-run', action='store_true',
1255 help='do not run the tests')
1256-
1257 parser.set_defaults(run=run)
1258
1259=== modified file 'openerpcommand/scaffold.py'
1260--- openerpcommand/scaffold.py 2012-02-01 22:38:52 +0000
1261+++ openerpcommand/scaffold.py 2012-11-27 15:42:19 +0000
1262@@ -1,7 +1,6 @@
1263 """
1264 Generate an OpenERP module skeleton.
1265 """
1266-
1267 import os
1268 import sys
1269
1270@@ -22,12 +21,9 @@
1271 with open(os.path.join(module, 'models', '__init__.py'), 'w') as h:
1272 h.write(MODELS_PY % (module,))
1273
1274-def add_parser(subparsers):
1275- parser = subparsers.add_parser('scaffold',
1276- description='Generate an OpenERP module skeleton.')
1277+def init_parser(parser):
1278 parser.add_argument('module', metavar='MODULE',
1279 help='the name of the generated module')
1280-
1281 parser.set_defaults(run=run)
1282
1283 MANIFEST = """\
1284
1285=== added file 'openerpcommand/show.py'
1286--- openerpcommand/show.py 1970-01-01 00:00:00 +0000
1287+++ openerpcommand/show.py 2012-11-27 15:42:19 +0000
1288@@ -0,0 +1,23 @@
1289+"""
1290+Display a record.
1291+"""
1292+from openerpcommand.common import Client
1293+
1294+class Show(Client):
1295+ def __init__(self, parser):
1296+ super(Show, self).__init__(parser)
1297+ self.parser.add_argument('-m', '--model', metavar='MODEL',
1298+ required=True, help='the model')
1299+ self.parser.add_argument('-i', '--id', metavar='RECORDID',
1300+ required=True, help='the record id')
1301+
1302+ def work(self):
1303+ xs = self.execute(self.args.model, 'read', [self.args.id], [])
1304+ if xs:
1305+ x = xs[0]
1306+ print x['name']
1307+ else:
1308+ print "Record not found."
1309+
1310+def init_parser(parser):
1311+ Show(parser)
1312
1313=== modified file 'openerpcommand/uninstall.py'
1314--- openerpcommand/uninstall.py 2012-08-22 17:20:15 +0000
1315+++ openerpcommand/uninstall.py 2012-11-27 15:42:19 +0000
1316@@ -1,10 +1,10 @@
1317 """
1318-Install OpenERP on a new (by default) database.
1319+Uninstall some modules from an OpenERP database.
1320 """
1321 import os
1322 import sys
1323
1324-import common
1325+from openerpcommand import common
1326
1327 # TODO turn template1 in a parameter
1328 # This should be exposed from openerp (currently in
1329@@ -30,7 +30,7 @@
1330 config = openerp.tools.config
1331 config['log_handler'] = [':CRITICAL']
1332 if args.addons:
1333- args.addons = args.addons.split(':')
1334+ args.addons = map(common.expand_path, args.addons.split(':'))
1335 else:
1336 args.addons = []
1337 config['addons_path'] = ','.join(args.addons)
1338@@ -54,14 +54,11 @@
1339 finally:
1340 cr.close()
1341
1342-def add_parser(subparsers):
1343- parser = subparsers.add_parser('uninstall',
1344- description='Uninstall some modules from an OpenERP database.')
1345+def init_parser(parser):
1346 parser.add_argument('-d', '--database', metavar='DATABASE',
1347 **common.required_or_default('DATABASE', 'the database to modify'))
1348 common.add_addons_argument(parser)
1349 parser.add_argument('--module', metavar='MODULE', action='append',
1350 help='specify a module to uninstall'
1351 ' (this option can be repeated)')
1352-
1353 parser.set_defaults(run=run)
1354
1355=== modified file 'openerpcommand/update.py'
1356--- openerpcommand/update.py 2012-02-14 15:05:03 +0000
1357+++ openerpcommand/update.py 2012-11-27 15:42:19 +0000
1358@@ -10,9 +10,7 @@
1359 openerp.modules.registry.RegistryManager.get(
1360 args.database, update_module=True, pooljobs=False)
1361
1362-def add_parser(subparsers):
1363- parser = subparsers.add_parser('update',
1364- description='Update an existing OpenERP database.')
1365+def init_parser(parser):
1366 parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
1367 help='the database to update')
1368
1369
1370=== modified file 'setup.py' (properties changed: -x to +x)
1371--- setup.py 2012-01-31 17:55:23 +0000
1372+++ setup.py 2012-11-27 15:42:19 +0000
1373@@ -31,8 +31,29 @@
1374 zip_safe = False,
1375 packages = find_packages(),
1376 include_package_data = True,
1377- entry_points="""
1378- [console_scripts]
1379- oe=openerpcommand.main:run
1380- """,
1381+ entry_points={
1382+ 'console_scripts' : ['oe = openerpcommand.main:run'],
1383+ 'openerpcommand.subcommands': [ 'call = openerpcommand.call:init_parser',
1384+ 'conf = openerpcommand.conf:init_parser',
1385+ 'consume_cpu = openerpcommand.consume_cpu:init_parser',
1386+ 'consume_memory = openerpcommand.consume_memory:init_parser',
1387+ 'consume_nothing = openerpcommand.consume_nothing:init_parser',
1388+ 'drop = openerpcommand.drop:init_parser',
1389+ 'initialize = openerpcommand.initialize:init_parser',
1390+ 'leak_memory = openerpcommand.leak_memory:init_parser',
1391+ 'model = openerpcommand.model:init_parser',
1392+ 'module = openerpcommand.module:init_parser',
1393+ 'open = openerpcommand.open:init_parser',
1394+ 'read = openerpcommand.read:init_parser',
1395+ 'run_tests = openerpcommand.run_tests:init_parser',
1396+ 'scaffold = openerpcommand.scaffold:init_parser',
1397+ 'show = openerpcommand.show:init_parser',
1398+ 'uninstall = openerpcommand.uninstall:init_parser',
1399+ 'update = openerpcommand.update:init_parser'],
1400+ 'openerpcommand.subcommands.benchmark': [ 'dummy = openerpcommand.benchmark.dummy:init_parser',
1401+ 'fields_view_get = openerpcommand.benchmark.fields_view_get:init_parser',
1402+ 'login = openerpcommand.benchmark.login:init_parser',
1403+ 'read = openerpcommand.benchmark.read:init_parser',
1404+ 'sale_mrp = openerpcommand.benchmark.sale_mrp:init_parser'],
1405+ },
1406 )

Subscribers

People subscribed via source and target branches