Tryton - Issues

 

Message32352

Author jcavallo
Recipients ced, pokoli, reviewbot
Date 2017-03-08.11:26:27
Content
Following cedric's suggestion, here is my design proposal.

Rather than patching the "last" class in the pool, I would like to inject the
new class right after the class it wants to replace.

Here is an example. Assuming we want to patch the ModelSQL class with a custom
OverridenModelSQL class on ir.ui.menu, the current mro (with an override in the
"my_module" module) looks like :

 <class 'trytond.pool.ir.ui.menu'>,
 <class 'trytond.modules.my_module.ir.ir.ui.menu'>,
 <class 'trytond.ir.ui.menu.ir.ui.menu'>,                    # <-- base class
 <class 'trytond.model.order.SequenceOrderedMixin'>,
 <class 'trytond.model.modelsql.ModelSQL'>,                  # <-- source
 <class 'trytond.model.modelstorage.ModelStorage'>,
 <class 'trytond.model.modelview.ModelView'>,
 <class 'trytond.model.model.Model'>,
 <class 'trytond.error.WarningErrorMixin'>,
 <class 'trytond.url.URLMixin'>,
 <class 'trytond.pool.PoolBase'>,
 <type 'object'>

With the current implementation, we would have (if I understand properly) :

 <class 'trytond.pool.ir.ui.menu'>,                          # <-- new type
 <class 'trytond.modules.my_mixin_module.my_file.OverridenModelSQL>,  # <-- target
 <class 'trytond.pool.ir.ui.menu'>,
 <class 'trytond.modules.my_module.ir.ir.ui.menu'>,
 <class 'trytond.ir.ui.menu.ir.ui.menu'>,                    # <-- base class
 <class 'trytond.model.order.SequenceOrderedMixin'>,
 <class 'trytond.model.modelsql.ModelSQL'>,                  # <-- source
 <class 'trytond.model.modelstorage.ModelStorage'>,
 <class 'trytond.model.modelview.ModelView'>,
 <class 'trytond.model.model.Model'>,
 <class 'trytond.error.WarningErrorMixin'>,
 <class 'trytond.url.URLMixin'>,
 <class 'trytond.pool.PoolBase'>,
 <type 'object'>

What I think should be better :

 <class 'trytond.pool.ir.ui.menu'>,
 <class 'trytond.modules.my_module.ir.ir.ui.menu'>,
 <class 'trytond.ir.ui.menu.ir.ui.menu'>,                    # <-- base class
 <class 'trytond.modules.my_mixin_module.my_file.OverridenModelSQL>,  # <-- target
 <class 'trytond.model.order.SequenceOrderedMixin'>,
 <class 'trytond.model.modelsql.ModelSQL'>,                  # <-- source
 <class 'trytond.model.modelstorage.ModelStorage'>,
 <class 'trytond.model.modelview.ModelView'>,
 <class 'trytond.model.model.Model'>,
 <class 'trytond.error.WarningErrorMixin'>,
 <class 'trytond.url.URLMixin'>,
 <class 'trytond.pool.PoolBase'>,
 <type 'object'>

I quickly made up something that would work, but I don't think it is
clean enough to be integrated as is :

    source = ModelSQL
    target = OverridenModelSQL

    def patch_model(klass):
        if issubclass(klass, target) or not issubclass(klass, source):
            return
        for mro_class in reversed(klass.__mro__):
            if mro_class == source:
                continue
            if source not in mro_class.__bases__:
                continue
            mro_class.__bases__ = tuple(
                x if x != source else target
                for x in mro_class.__bases__)

I tried calling the patch_model method on all classes in the pool at the
end of the pool.init method, and it behaved as expected. But I do not
know if manually updating the __bases__ attribute is acceptable.

Here we directly modify the base class inheritances, so it may be a
problem for multiple databases management. We could probably go around this
by creating another 'trytond.pool.ir.ui.menu' class and make it inherit
of both the original base class and the OverridenModelSQL class.
History
Date User Action Args
2017-03-08 11:26:28jcavallosetmessageid: <1488968788.26.0.776145858156.issue4735@tryton.org>
2017-03-08 11:26:28jcavallosetrecipients: + ced, pokoli, reviewbot
2017-03-08 11:26:28jcavallolinkissue4735 messages
2017-03-08 11:26:27jcavallocreate

Showing 10 items. Show all history (warning: this could be VERY long)