diff --git a/CHANGELOG b/CHANGELOG index ce69cd0031..95617995eb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Register mixins to generic Report class * Cache in memory the report template instances * Support Genshi's MsgDirective in report * Support PYSON comparison of date and datetime diff --git a/trytond/pool.py b/trytond/pool.py index 5ddfedf605..913096ed8a 100644 --- a/trytond/pool.py +++ b/trytond/pool.py @@ -54,6 +54,7 @@ class Pool(object): _pool = {} test = False _instances = {} + _modules = None def __new__(cls, database_name=None): if database_name is None: @@ -155,6 +156,7 @@ class Pool(object): return logger.info('init pool for "%s"', self.database_name) self._pool.setdefault(self.database_name, {}) + self._modules = [] # Clean the _pool before loading modules for type in self.classes.keys(): self._pool[self.database_name][type] = {} @@ -164,6 +166,7 @@ class Pool(object): activatedeps=activatedeps) except Exception: del self._pool[self.database_name] + self._modules = None raise if restart: self.init() @@ -186,10 +189,12 @@ class Pool(object): if type == 'report': from trytond.report import Report # Keyword argument 'type' conflicts with builtin function - cls = builtins.type(str(name), (Report,), {}) + cls = builtins.type(name, (Report,), {'__slots__': ()}) cls.__setup__() + cls.__post_setup__() self.add(cls, type) - return cls + self.setup_mixin(self._modules, type='report', name=name) + return self.get(name, type=type) raise def add(self, cls, type='model'): @@ -229,6 +234,7 @@ class Pool(object): assert issubclass(cls, PoolBase), cls self.add(cls, type=type_) classes[type_].append(cls) + self._modules.append(module) return classes def setup(self, classes=None): @@ -244,18 +250,25 @@ class Pool(object): for cls in lst: cls.__post_setup__() - def setup_mixin(self, modules): + def setup_mixin(self, modules, type=None, name=None): logger.info('setup mixin for "%s"', self.database_name) + if type is not None: + types = [type] + else: + types = self.classes.keys() for module in modules: if module not in self.classes_mixin: continue - for type_ in self.classes.keys(): - for _, cls in self.iterobject(type=type_): + for type_ in types: + for kname, cls in self.iterobject(type=type_): + if name is not None and kname != name: + continue for parent, mixin in self.classes_mixin[module]: if (not issubclass(cls, parent) or issubclass(cls, mixin)): continue - cls = type(cls.__name__, (mixin, cls), {}) + cls = builtins.type( + cls.__name__, (mixin, cls), {'__slots__': ()}) self.add(cls, type=type_) diff --git a/trytond/tests/mixin.py b/trytond/tests/mixin.py index 11d9e7bd59..e498f45441 100644 --- a/trytond/tests/mixin.py +++ b/trytond/tests/mixin.py @@ -2,6 +2,7 @@ # this repository contains the full copyright notices and license terms. from trytond.model import DeactivableMixin, ModelSQL, ModelView from trytond.pool import Pool +from trytond.report import Report class TestMixin: @@ -16,6 +17,10 @@ class NotMixin: pass +class ReportMixin: + pass + + class DeactivableModelView(DeactivableMixin, ModelView): 'Deactivable ModelView' __name__ = 'test.deactivable.modelview' @@ -34,3 +39,4 @@ def register(module): Pool.register_mixin(TestMixin, ModelView, module=module) Pool.register_mixin(TestSecondMixin, ModelView, module=module) Pool.register_mixin(NotMixin, ModelView, module='__wrong__') + Pool.register_mixin(ReportMixin, Report, module=module) diff --git a/trytond/tests/test_mixins.py b/trytond/tests/test_mixins.py index eaf891e6bd..eb4adeca10 100644 --- a/trytond/tests/test_mixins.py +++ b/trytond/tests/test_mixins.py @@ -11,7 +11,7 @@ from trytond.model import ModelView from trytond.pool import Pool from trytond.url import http_host, HOSTNAME -from .mixin import TestMixin, TestSecondMixin, NotMixin +from .mixin import TestMixin, TestSecondMixin, NotMixin, ReportMixin class UrlTestCase(unittest.TestCase): @@ -103,6 +103,14 @@ class MixinTestCase(unittest.TestCase): for _, model in Pool().iterobject(): self.assertFalse(issubclass(model, NotMixin)) + @with_transaction() + def test_report_mixin(self): + "Test mixin applies on default report" + pool = Pool() + Report = pool.get('test.report.mixin', type='report') + + self.assertTrue(issubclass(Report, ReportMixin)) + class DeactivableMixinTestCase(unittest.TestCase): "Test DeactivableMixin"