Merge lp:~openerp-dev/openobject-server/trunk-methport-thu into lp:openobject-server
- trunk-methport-thu
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 4839 |
Proposed branch: | lp:~openerp-dev/openobject-server/trunk-methport-thu |
Merge into: | lp:openobject-server |
Diff against target: |
552 lines (+172/-53) 20 files modified
doc/03_module_dev.rst (+1/-0) doc/changelog.rst (+3/-0) doc/report-declaration.rst (+23/-0) openerp/addons/base/ir/ir_actions.py (+40/-18) openerp/addons/base/ir/ir_actions.xml (+1/-0) openerp/conf/deprecation.py (+18/-0) openerp/import_xml.rng (+1/-0) openerp/modules/graph.py (+0/-2) openerp/modules/migration.py (+0/-2) openerp/modules/registry.py (+0/-1) openerp/netsvc.py (+21/-5) openerp/osv/orm.py (+9/-0) openerp/report/__init__.py (+9/-0) openerp/report/interface.py (+13/-7) openerp/report/print_xml.py (+1/-1) openerp/report/report_sxw.py (+13/-2) openerp/service/report.py (+3/-5) openerp/tools/convert.py (+2/-3) openerp/tools/test_reports.py (+5/-5) openerp/tools/yaml_import.py (+9/-2) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-server/trunk-methport-thu |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+149591@code.launchpad.net |
Commit message
Description of the change
- [X] Write doc.
- [X] Write changelog.
- [ ] Deprecate report registration with Python. I can't really do it: some reports are instanciated before nestv.init_
Some old-style records are declared by instanciating a custom sub-class of report_rml. It the capability needed to register third-party reports ? If so, an additional attribute can be used to specify the class to instanciate.
Vo Minh Thu (thu) wrote : | # |
- 4813. By Vo Minh Thu
-
[IMP] netsvc: slightly more explicit warning when using LocalService().
- 4814. By Vo Minh Thu
-
[MERGE] merged trunk.
- 4815. By Vo Minh Thu
-
[REF] ir.actions.
report. xml: register_all do not make sense any more: auto=True reports are looked up in the database for each rendering, so they do
no have to be in the report registry any longer.
auto=False reports will register themselves but at this point
they can be updated to use the new `parser` XML attribute. - 4816. By Vo Minh Thu
-
[REF] ir.actions.
report. xml: renamed ids to res_ids because those are not the self model IDs. - 4817. By Vo Minh Thu
-
[FIX] reports: now that _register_all() has been removed, LocalService() must be modified to do the lookup in the database too.
- 4818. By Vo Minh Thu
-
[IMP] netsvc: LocalService deprecation now guarded via openerp.
conf.deprecatio n. - 4819. By Vo Minh Thu
-
[IMP] report: registration deprecation now guarded via openerp.
conf.deprecatio n. - 4820. By Vo Minh Thu
-
[IMP] conf.deprecation: comment.
- 4821. By Vo Minh Thu
-
[IMP] orm: added a print_report() method.
- 4822. By Vo Minh Thu
-
[DOC] changelog updated to mention the new print_report().
- 4823. By Vo Minh Thu
-
[IMP] yaml_import: add openerp in the evaluation context.
Xavier (Open ERP) (xmo-deactivatedaccount) wrote : | # |
* Imports in functions? I guess the openerp imports are because of recursive blowups, but why do os or operator need to be in functions and not at the module toplevel (openerp/
* the conditional nesting in that function is odd as well, why not:
if 'report.' + name in openerp.
return openerp.
cr.
r = cr.dictfetchone()
if not r:
raise Exception, "Required report does not exist: %s" % r
if r['report_rml'] or r['report_
if r['parser']:
kwargs = { 'parser': operator.
else:
kwargs = {}
return report_
elif r['report_xsl']:
return report_
raise Exception, "Unhandled report type: %s" % r
* typo in LocalService docstring (fucntion)
* openerp/
Xavier (Open ERP) (xmo-deactivatedaccount) wrote : | # |
also, in yaml_import `code_context.
- 4824. By Vo Minh Thu
-
[REF] yaml_import: removed nested import openerp.
- 4825. By Vo Minh Thu
-
[REF] removed nested import openerp.
- 4826. By Vo Minh Thu
-
[DOC] netsvc: typo in docstring.
- 4827. By Vo Minh Thu
-
[REF] trolls.convert: missed an opportunity to reuse a beautiful association list.
Preview Diff
1 | === modified file 'doc/03_module_dev.rst' |
2 | --- doc/03_module_dev.rst 2012-11-19 14:39:12 +0000 |
3 | +++ doc/03_module_dev.rst 2013-03-27 15:55:25 +0000 |
4 | @@ -13,3 +13,4 @@ |
5 | 03_module_dev_04 |
6 | 03_module_dev_05 |
7 | 03_module_dev_06 |
8 | + report-declaration |
9 | |
10 | === modified file 'doc/changelog.rst' |
11 | --- doc/changelog.rst 2013-02-21 12:18:25 +0000 |
12 | +++ doc/changelog.rst 2013-03-27 15:55:25 +0000 |
13 | @@ -6,6 +6,9 @@ |
14 | `trunk` |
15 | ------- |
16 | |
17 | +- Almost removed ``LocalService()``. For reports, |
18 | + ``openerp.osv.orm.Model.print_report()`` can be used. For workflows, see |
19 | + :ref:`orm-workflows`. |
20 | - Removed support for the ``NET-RPC`` protocol. |
21 | - Added the :ref:`Long polling <longpolling-worker>` worker type. |
22 | - Added :ref:`orm-workflows` to the ORM. |
23 | |
24 | === added file 'doc/report-declaration.rst' |
25 | --- doc/report-declaration.rst 1970-01-01 00:00:00 +0000 |
26 | +++ doc/report-declaration.rst 2013-03-27 15:55:25 +0000 |
27 | @@ -0,0 +1,23 @@ |
28 | +.. _report-declaration: |
29 | + |
30 | +Report declaration |
31 | +================== |
32 | + |
33 | +.. versionadded:: 7.1 |
34 | + |
35 | +Before version 7.1, report declaration could be done in two different ways: |
36 | +either via a ``<report>`` tag in XML, or via such a tag and a class |
37 | +instanciation in a Python module. Instanciating a class in a Python module was |
38 | +necessary when a custom parser was used. |
39 | + |
40 | +In version 7.1, the recommended way to register a report is to use only the |
41 | +``<report>`` XML tag. The tag can now support an additional ``parser`` |
42 | +attribute. The value for that attibute must be a fully-qualified class name, |
43 | +without the leading ``openerp.addons.`` namespace. |
44 | + |
45 | +.. note:: |
46 | + The rational to deprecate the manual class instanciation is to make all |
47 | + reports visible in the database, have a unique way to declare reports |
48 | + instead of two, and remove the need to maintain a registry of reports in |
49 | + memory. |
50 | + |
51 | |
52 | === modified file 'openerp/addons/base/ir/ir_actions.py' |
53 | --- openerp/addons/base/ir/ir_actions.py 2013-03-19 14:27:01 +0000 |
54 | +++ openerp/addons/base/ir/ir_actions.py 2013-03-27 15:55:25 +0000 |
55 | @@ -20,11 +20,13 @@ |
56 | ############################################################################## |
57 | |
58 | import logging |
59 | +import operator |
60 | import os |
61 | import re |
62 | from socket import gethostname |
63 | import time |
64 | |
65 | +import openerp |
66 | from openerp import SUPERUSER_ID |
67 | from openerp import netsvc, tools |
68 | from openerp.osv import fields, osv |
69 | @@ -85,26 +87,45 @@ |
70 | res[report.id] = False |
71 | return res |
72 | |
73 | - def register_all(self, cr): |
74 | - """Report registration handler that may be overridden by subclasses to |
75 | - add their own kinds of report services. |
76 | - Loads all reports with no manual loaders (auto==True) and |
77 | - registers the appropriate services to implement them. |
78 | + def _lookup_report(self, cr, name): |
79 | + """ |
80 | + Look up a report definition. |
81 | """ |
82 | opj = os.path.join |
83 | - cr.execute("SELECT * FROM ir_act_report_xml WHERE auto=%s ORDER BY id", (True,)) |
84 | - result = cr.dictfetchall() |
85 | - reports = openerp.report.interface.report_int._reports |
86 | - for r in result: |
87 | - if reports.has_key('report.'+r['report_name']): |
88 | - continue |
89 | - if r['report_rml'] or r['report_rml_content_data']: |
90 | - report_sxw('report.'+r['report_name'], r['model'], |
91 | - opj('addons',r['report_rml'] or '/'), header=r['header']) |
92 | - if r['report_xsl']: |
93 | - report_rml('report.'+r['report_name'], r['model'], |
94 | - opj('addons',r['report_xml']), |
95 | - r['report_xsl'] and opj('addons',r['report_xsl'])) |
96 | + |
97 | + # First lookup in the deprecated place, because if the report definition |
98 | + # has not been updated, it is more likely the correct definition is there. |
99 | + # Only reports with custom parser sepcified in Python are still there. |
100 | + if 'report.' + name in openerp.report.interface.report_int._reports: |
101 | + new_report = openerp.report.interface.report_int._reports['report.' + name] |
102 | + else: |
103 | + cr.execute("SELECT * FROM ir_act_report_xml WHERE report_name=%s", (name,)) |
104 | + r = cr.dictfetchone() |
105 | + if r: |
106 | + if r['report_rml'] or r['report_rml_content_data']: |
107 | + if r['parser']: |
108 | + kwargs = { 'parser': operator.attrgetter(r['parser'])(openerp.addons) } |
109 | + else: |
110 | + kwargs = {} |
111 | + new_report = report_sxw('report.'+r['report_name'], r['model'], |
112 | + opj('addons',r['report_rml'] or '/'), header=r['header'], register=False, **kwargs) |
113 | + elif r['report_xsl']: |
114 | + new_report = report_rml('report.'+r['report_name'], r['model'], |
115 | + opj('addons',r['report_xml']), |
116 | + r['report_xsl'] and opj('addons',r['report_xsl']), register=False) |
117 | + else: |
118 | + raise Exception, "Unhandled report type: %s" % r |
119 | + else: |
120 | + raise Exception, "Required report does not exist: %s" % r |
121 | + |
122 | + return new_report |
123 | + |
124 | + def render_report(self, cr, uid, res_ids, name, data, context=None): |
125 | + """ |
126 | + Look up a report definition and render the report for the provided IDs. |
127 | + """ |
128 | + new_report = self._lookup_report(cr, name) |
129 | + return new_report.create(cr, uid, res_ids, data, context) |
130 | |
131 | _name = 'ir.actions.report.xml' |
132 | _inherit = 'ir.actions.actions' |
133 | @@ -140,6 +161,7 @@ |
134 | 'report_sxw_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='SXW Content',), |
135 | 'report_rml_content': fields.function(_report_content, fnct_inv=_report_content_inv, type='binary', string='RML Content'), |
136 | |
137 | + 'parser': fields.char('Parser Class'), |
138 | } |
139 | _defaults = { |
140 | 'type': 'ir.actions.report.xml', |
141 | |
142 | === modified file 'openerp/addons/base/ir/ir_actions.xml' |
143 | --- openerp/addons/base/ir/ir_actions.xml 2012-12-05 16:00:15 +0000 |
144 | +++ openerp/addons/base/ir/ir_actions.xml 2013-03-27 15:55:25 +0000 |
145 | @@ -82,6 +82,7 @@ |
146 | <group string="Miscellaneous"> |
147 | <field name="multi"/> |
148 | <field name="auto"/> |
149 | + <field name="parser"/> |
150 | </group> |
151 | </group> |
152 | </page> |
153 | |
154 | === modified file 'openerp/conf/deprecation.py' |
155 | --- openerp/conf/deprecation.py 2013-02-09 06:02:46 +0000 |
156 | +++ openerp/conf/deprecation.py 2013-03-27 15:55:25 +0000 |
157 | @@ -26,6 +26,8 @@ |
158 | track of those specific measures by providing variables that can be unset |
159 | by the user to check if her code is future proof. |
160 | |
161 | +In a perfect world, all these variables are set to False, the corresponding |
162 | +code removed, and thus these variables made unnecessary. |
163 | """ |
164 | |
165 | # If True, the Python modules inside the openerp namespace are made available |
166 | @@ -35,4 +37,20 @@ |
167 | # Change to False around 2013.02. |
168 | open_openerp_namespace = False |
169 | |
170 | +# If True, openerp.netsvc.LocalService() can be used to lookup reports or to |
171 | +# access openerp.workflow. |
172 | +# Introduced around 2013.03. |
173 | +# Among the related code: |
174 | +# - The openerp.netsvc.LocalService() function. |
175 | +# - The openerp.report.interface.report_int._reports dictionary. |
176 | +# - The register attribute in openerp.report.interface.report_int (and in its |
177 | +# - auto column in ir.actions.report.xml. |
178 | +# inheriting classes). |
179 | +allow_local_service = True |
180 | + |
181 | +# Applies for the register attribute in openerp.report.interface.report_int. |
182 | +# See comments for allow_local_service above. |
183 | +# Introduced around 2013.03. |
184 | +allow_report_int_registration = True |
185 | + |
186 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
187 | |
188 | === modified file 'openerp/import_xml.rng' |
189 | --- openerp/import_xml.rng 2013-02-12 15:23:28 +0000 |
190 | +++ openerp/import_xml.rng 2013-03-27 15:55:25 +0000 |
191 | @@ -107,6 +107,7 @@ |
192 | <rng:optional><rng:attribute name="sxw"/></rng:optional> |
193 | <rng:optional><rng:attribute name="xml"/></rng:optional> |
194 | <rng:optional><rng:attribute name="xsl"/></rng:optional> |
195 | + <rng:optional><rng:attribute name="parser"/></rng:optional> |
196 | <rng:optional> <rng:attribute name="auto" /> </rng:optional> |
197 | <rng:optional> <rng:attribute name="header" /> </rng:optional> |
198 | <rng:optional> <rng:attribute name="webkit_header" /> </rng:optional> |
199 | |
200 | === modified file 'openerp/modules/graph.py' |
201 | --- openerp/modules/graph.py 2012-11-29 14:07:45 +0000 |
202 | +++ openerp/modules/graph.py 2013-03-27 15:55:25 +0000 |
203 | @@ -36,8 +36,6 @@ |
204 | import openerp.pooler as pooler |
205 | from openerp.tools.translate import _ |
206 | |
207 | -import openerp.netsvc as netsvc |
208 | - |
209 | import zipfile |
210 | import openerp.release as release |
211 | |
212 | |
213 | === modified file 'openerp/modules/migration.py' |
214 | --- openerp/modules/migration.py 2012-01-24 12:42:52 +0000 |
215 | +++ openerp/modules/migration.py 2013-03-27 15:55:25 +0000 |
216 | @@ -36,8 +36,6 @@ |
217 | import openerp.pooler as pooler |
218 | from openerp.tools.translate import _ |
219 | |
220 | -import openerp.netsvc as netsvc |
221 | - |
222 | import zipfile |
223 | import openerp.release as release |
224 | |
225 | |
226 | === modified file 'openerp/modules/registry.py' |
227 | --- openerp/modules/registry.py 2013-02-12 08:53:11 +0000 |
228 | +++ openerp/modules/registry.py 2013-03-27 15:55:25 +0000 |
229 | @@ -225,7 +225,6 @@ |
230 | try: |
231 | Registry.setup_multi_process_signaling(cr) |
232 | registry.do_parent_store(cr) |
233 | - registry.get('ir.actions.report.xml').register_all(cr) |
234 | cr.commit() |
235 | finally: |
236 | cr.close() |
237 | |
238 | === modified file 'openerp/netsvc.py' |
239 | --- openerp/netsvc.py 2013-03-19 16:37:08 +0000 |
240 | +++ openerp/netsvc.py 2013-03-27 15:55:25 +0000 |
241 | @@ -21,11 +21,9 @@ |
242 | ############################################################################## |
243 | |
244 | |
245 | -import errno |
246 | import logging |
247 | import logging.handlers |
248 | import os |
249 | -import platform |
250 | import release |
251 | import sys |
252 | import threading |
253 | @@ -46,12 +44,30 @@ |
254 | _logger = logging.getLogger(__name__) |
255 | |
256 | def LocalService(name): |
257 | - # Special case for addons support, will be removed in a few days when addons |
258 | - # are updated to directly use openerp.osv.osv.service. |
259 | + """ |
260 | + The openerp.netsvc.LocalService() function is deprecated. It still works |
261 | + in two cases: workflows and reports. For workflows, instead of using |
262 | + LocalService('workflow'), openerp.workflow should be used (better yet, |
263 | + methods on openerp.osv.orm.Model should be used). For reports, |
264 | + openerp.report.render_report() should be used (methods on the Model should |
265 | + be provided too in the future). |
266 | + """ |
267 | + assert openerp.conf.deprecation.allow_local_service |
268 | + _logger.warning("LocalService() is deprecated since march 2013 (it was called with '%s')." % name) |
269 | + |
270 | if name == 'workflow': |
271 | return openerp.workflow |
272 | |
273 | - return openerp.report.interface.report_int._reports[name] |
274 | + if name.startswith('report.'): |
275 | + report = openerp.report.interface.report_int._reports.get(name) |
276 | + if report: |
277 | + return report |
278 | + else: |
279 | + dbname = getattr(threading.currentThread(), 'dbname', None) |
280 | + if dbname: |
281 | + registry = openerp.modules.registry.RegistryManager.get(dbname) |
282 | + with registry.cursor() as cr: |
283 | + return registry['ir.actions.report.xml']._lookup_report(cr, name[len('report.'):]) |
284 | |
285 | BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10) |
286 | #The background is set with 40 plus the number of the color, and the foreground with 30 |
287 | |
288 | === modified file 'openerp/osv/orm.py' |
289 | --- openerp/osv/orm.py 2013-03-21 13:32:02 +0000 |
290 | +++ openerp/osv/orm.py 2013-03-27 15:55:25 +0000 |
291 | @@ -5155,6 +5155,15 @@ |
292 | get_xml_id = get_external_id |
293 | _get_xml_ids = _get_external_ids |
294 | |
295 | + def print_report(self, cr, uid, ids, name, data, context=None): |
296 | + """ |
297 | + Render the report `name` for the given IDs. The report must be defined |
298 | + for this model, not another. |
299 | + """ |
300 | + report = self.pool['ir.actions.report.xml']._lookup_report(cr, name) |
301 | + assert self._name == report.table |
302 | + return report.create(cr, uid, ids, data, context) |
303 | + |
304 | # Transience |
305 | def is_transient(self): |
306 | """ Return whether the model is transient. |
307 | |
308 | === modified file 'openerp/report/__init__.py' |
309 | --- openerp/report/__init__.py 2013-02-12 14:24:10 +0000 |
310 | +++ openerp/report/__init__.py 2013-03-27 15:55:25 +0000 |
311 | @@ -19,6 +19,8 @@ |
312 | # |
313 | ############################################################################## |
314 | |
315 | +import openerp |
316 | + |
317 | import interface |
318 | import print_xml |
319 | import print_fnc |
320 | @@ -30,6 +32,13 @@ |
321 | |
322 | import printscreen |
323 | |
324 | +def render_report(cr, uid, ids, name, data, context=None): |
325 | + """ |
326 | + Helper to call ``ir.actions.report.xml.render_report()``. |
327 | + """ |
328 | + registry = openerp.modules.registry.RegistryManager.get(cr.dbname) |
329 | + return registry['ir.actions.report.xml'].render_report(cr, uid, ids, name, data, context) |
330 | + |
331 | |
332 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
333 | |
334 | |
335 | === modified file 'openerp/report/interface.py' |
336 | --- openerp/report/interface.py 2013-02-01 11:22:32 +0000 |
337 | +++ openerp/report/interface.py 2013-03-27 15:55:25 +0000 |
338 | @@ -25,6 +25,7 @@ |
339 | from lxml import etree |
340 | import openerp.pooler as pooler |
341 | |
342 | +import openerp |
343 | import openerp.tools as tools |
344 | import openerp.modules |
345 | import print_xml |
346 | @@ -43,11 +44,16 @@ |
347 | |
348 | _reports = {} |
349 | |
350 | - def __init__(self, name): |
351 | - if not name.startswith('report.'): |
352 | - raise Exception('ConceptionError, bad report name, should start with "report."') |
353 | - assert name not in self._reports, 'The report "%s" already exists!' % name |
354 | - self._reports[name] = self |
355 | + def __init__(self, name, register=True): |
356 | + if register: |
357 | + assert openerp.conf.deprecation.allow_report_int_registration |
358 | + assert name.startswith('report.'), 'Report names should start with "report.".' |
359 | + assert name not in self._reports, 'The report "%s" already exists.' % name |
360 | + self._reports[name] = self |
361 | + else: |
362 | + # The report is instanciated at each use site, which is ok. |
363 | + pass |
364 | + |
365 | self.__name = name |
366 | |
367 | self.name = name |
368 | @@ -65,8 +71,8 @@ |
369 | XML -> DATAS -> RML -> PDF -> HTML |
370 | using a XSL:RML transformation |
371 | """ |
372 | - def __init__(self, name, table, tmpl, xsl): |
373 | - super(report_rml, self).__init__(name) |
374 | + def __init__(self, name, table, tmpl, xsl, register=True): |
375 | + super(report_rml, self).__init__(name, register=register) |
376 | self.table = table |
377 | self.internal_header=False |
378 | self.tmpl = tmpl |
379 | |
380 | === modified file 'openerp/report/print_xml.py' |
381 | --- openerp/report/print_xml.py 2012-02-08 17:04:56 +0000 |
382 | +++ openerp/report/print_xml.py 2013-03-27 15:55:25 +0000 |
383 | @@ -264,7 +264,7 @@ |
384 | def parse_tree(self, ids, model, context=None): |
385 | if not context: |
386 | context={} |
387 | - browser = self.pool.get(model).browse(self.cr, self.uid, ids, context) |
388 | + browser = self.pool[model].browse(self.cr, self.uid, ids, context) |
389 | self.parse_node(self.dom, self.doc, browser) |
390 | |
391 | def parse_string(self, xml, ids, model, context=None): |
392 | |
393 | === modified file 'openerp/report/report_sxw.py' |
394 | --- openerp/report/report_sxw.py 2013-02-08 13:57:04 +0000 |
395 | +++ openerp/report/report_sxw.py 2013-03-27 15:55:25 +0000 |
396 | @@ -388,8 +388,19 @@ |
397 | self.setCompany(objects[0].company_id) |
398 | |
399 | class report_sxw(report_rml, preprocess.report): |
400 | - def __init__(self, name, table, rml=False, parser=rml_parse, header='external', store=False): |
401 | - report_rml.__init__(self, name, table, rml, '') |
402 | + """ |
403 | + The register=True kwarg has been added to help remove the |
404 | + openerp.netsvc.LocalService() indirection and the related |
405 | + openerp.report.interface.report_int._reports dictionary: |
406 | + report_sxw registered in XML with auto=False are also registered in Python. |
407 | + In that case, they are registered in the above dictionary. Since |
408 | + registration is automatically done upon instanciation, and that |
409 | + instanciation is needed before rendering, a way was needed to |
410 | + instanciate-without-register a report. In the future, no report |
411 | + should be registered in the above dictionary and it will be dropped. |
412 | + """ |
413 | + def __init__(self, name, table, rml=False, parser=rml_parse, header='external', store=False, register=True): |
414 | + report_rml.__init__(self, name, table, rml, '', register=register) |
415 | self.name = name |
416 | self.parser = parser |
417 | self.header = header |
418 | |
419 | === modified file 'openerp/service/report.py' |
420 | --- openerp/service/report.py 2013-02-14 15:35:11 +0000 |
421 | +++ openerp/service/report.py 2013-03-27 15:55:25 +0000 |
422 | @@ -5,8 +5,8 @@ |
423 | import sys |
424 | import threading |
425 | |
426 | -import openerp.netsvc |
427 | import openerp.pooler |
428 | +import openerp.report |
429 | from openerp import tools |
430 | |
431 | import security |
432 | @@ -51,8 +51,7 @@ |
433 | |
434 | cr = openerp.pooler.get_db(db).cursor() |
435 | try: |
436 | - obj = openerp.netsvc.LocalService('report.'+object) |
437 | - (result, format) = obj.create(cr, uid, ids, datas, context) |
438 | + result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) |
439 | if not result: |
440 | tb = sys.exc_info() |
441 | self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb) |
442 | @@ -90,8 +89,7 @@ |
443 | def go(id, uid, ids, datas, context): |
444 | cr = openerp.pooler.get_db(db).cursor() |
445 | try: |
446 | - obj = openerp.netsvc.LocalService('report.'+object) |
447 | - (result, format) = obj.create(cr, uid, ids, datas, context) |
448 | + result, format = openerp.report.render_report(cr, uid, ids, object, datas, context) |
449 | if not result: |
450 | tb = sys.exc_info() |
451 | self_reports[id]['exception'] = openerp.exceptions.DeferredException('RML is not available at specified location or not enough data to print!', tb) |
452 | |
453 | === modified file 'openerp/tools/convert.py' |
454 | --- openerp/tools/convert.py 2013-03-27 15:54:24 +0000 |
455 | +++ openerp/tools/convert.py 2013-03-27 15:55:25 +0000 |
456 | @@ -294,7 +294,8 @@ |
457 | res[dest] = rec.get(f,'').encode('utf8') |
458 | assert res[dest], "Attribute %s of report is empty !" % (f,) |
459 | for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'), |
460 | - ('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage')): |
461 | + ('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage'), |
462 | + ('report_type', 'report_type'), ('parser', 'parser')): |
463 | if rec.get(field): |
464 | res[dest] = rec.get(field).encode('utf8') |
465 | if rec.get('auto'): |
466 | @@ -304,8 +305,6 @@ |
467 | res['report_sxw_content'] = sxw_content |
468 | if rec.get('header'): |
469 | res['header'] = eval(rec.get('header','False')) |
470 | - if rec.get('report_type'): |
471 | - res['report_type'] = rec.get('report_type') |
472 | |
473 | res['multi'] = rec.get('multi') and eval(rec.get('multi','False')) |
474 | |
475 | |
476 | === modified file 'openerp/tools/test_reports.py' |
477 | --- openerp/tools/test_reports.py 2012-11-30 15:29:37 +0000 |
478 | +++ openerp/tools/test_reports.py 2013-03-27 15:55:25 +0000 |
479 | @@ -25,7 +25,7 @@ |
480 | through the code of yaml tests. |
481 | """ |
482 | |
483 | -import openerp.netsvc as netsvc |
484 | +import openerp.report |
485 | import openerp.tools as tools |
486 | import logging |
487 | import openerp.pooler as pooler |
488 | @@ -49,8 +49,8 @@ |
489 | rname_s = rname[7:] |
490 | else: |
491 | rname_s = rname |
492 | - _logger.log(netsvc.logging.TEST, " - Trying %s.create(%r)", rname, ids) |
493 | - res = netsvc.LocalService(rname).create(cr, uid, ids, data, context) |
494 | + _logger.log(logging.TEST, " - Trying %s.create(%r)", rname, ids) |
495 | + res = openerp.report.render_report(cr, uid, ids, rname_s, data, context) |
496 | if not isinstance(res, tuple): |
497 | raise RuntimeError("Result of %s.create() should be a (data,format) tuple, now it is a %s" % \ |
498 | (rname, type(res))) |
499 | @@ -92,7 +92,7 @@ |
500 | _logger.warning("Report %s produced a \"%s\" chunk, cannot examine it", rname, res_format) |
501 | return False |
502 | |
503 | - _logger.log(netsvc.logging.TEST, " + Report %s produced correctly.", rname) |
504 | + _logger.log(logging.TEST, " + Report %s produced correctly.", rname) |
505 | return True |
506 | |
507 | def try_report_action(cr, uid, action_id, active_model=None, active_ids=None, |
508 | @@ -126,7 +126,7 @@ |
509 | pool = pooler.get_pool(cr.dbname) |
510 | |
511 | def log_test(msg, *args): |
512 | - _logger.log(netsvc.logging.TEST, " - " + msg, *args) |
513 | + _logger.log(logging.TEST, " - " + msg, *args) |
514 | |
515 | datas = {} |
516 | if active_model: |
517 | |
518 | === modified file 'openerp/tools/yaml_import.py' |
519 | --- openerp/tools/yaml_import.py 2012-12-01 11:35:24 +0000 |
520 | +++ openerp/tools/yaml_import.py 2013-03-27 15:55:25 +0000 |
521 | @@ -5,6 +5,7 @@ |
522 | from datetime import datetime, timedelta |
523 | import logging |
524 | |
525 | +import openerp |
526 | import openerp.pooler as pooler |
527 | import openerp.sql_db as sql_db |
528 | import misc |
529 | @@ -281,7 +282,6 @@ |
530 | return record_dict |
531 | |
532 | def process_record(self, node): |
533 | - import openerp.osv as osv |
534 | record, fields = node.items()[0] |
535 | model = self.get_model(record.model) |
536 | |
537 | @@ -543,7 +543,14 @@ |
538 | python, statements = node.items()[0] |
539 | model = self.get_model(python.model) |
540 | statements = statements.replace("\r\n", "\n") |
541 | - code_context = { 'model': model, 'cr': self.cr, 'uid': self.uid, 'log': self._log, 'context': self.context } |
542 | + code_context = { |
543 | + 'model': model, |
544 | + 'cr': self.cr, |
545 | + 'uid': self.uid, |
546 | + 'log': self._log, |
547 | + 'context': self.context, |
548 | + 'openerp': openerp, |
549 | + } |
550 | code_context.update({'self': model}) # remove me when no !python block test uses 'self' anymore |
551 | try: |
552 | code_obj = compile(statements, self.filename, 'exec') |
This will make report registration more uniform, and report rendering be possible through the ORM (and thus the model service, instead of the report service).
To register a report, always use the database, i.e. a <report> tag within an XML file. The custom parser, if any, will be specified in the database. Previously specify a custom parser, the report was declared in Python.
Each model will expose a render_report() method, which will take the report name (as many report can be defined on a single model) in argument.