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