MapperExtension along Inherited mapper not properly work

Issue #490 resolved
Former user created an issue

See attached testcase. This test work properly if you also declare the extension on the child mapper

user_mapper =  mapper(User, users, extension = ext)
admin_mapper = mapper(Admin, admins, inherits=user_mapper, extension=ext)

but in this case, the before_insert method is called twice.

Comments (6)

  1. Mike Bayer repo owner

    at the moment this behavior is by design. im not sure if a MapperExtension should be assumed to apply to all the child objects as well....if you look at all the methods it implements, you can see that not all of those might be desired across a whole inheritance hierarchy. im thinking id rather have the MapperExtension express if it wants to be "inherited", maybe by subclassing InheritedMapperExtension instead. what do you think ?

  2. Former user Account Deleted

    Yes, why not. An other way may be that a MapperExtension by default apply to all the child objects. Since 'b' inherit of 'a', everything applied to 'a' must be applied to 'b' unless that 'b' override inherited properties of a.

    class AExtension(MapperExtension):
        def before_insert(self, mapper, connection, instance):
            instance.attribute = 'value'
            return EXT_PASS
    
        def populate_instance(self, mapper, selectcontext, row, instance, identitykey, isnew):
            instant.other_attribute = 'other_value'
            return EXT_PASS
    
    ext = AExtension()
    
    a_mapper =  mapper(A, a, extension = ext)
    b_mapper = mapper(B, b, inherits=a_mapper)
    
    class A (object) : pass
    class B (A) : pass
    

    for me, by default in that case, b_mapper must inherit the extension from a_mapper If I want to override some methods from the by default inherited mapper I can write

    class BExtension(AExtension):
        def before_insert(self, mapper, connection, instance):
            return EXT_PASS
    
    b_mapper = mapper(B, b, inherits=a_mapper, extension=BExtension)
    

    In this case, I've override the default inherited mapper by a mapper that only redefine unwanted methods. What do you think?

  3. Mike Bayer repo owner
    • changed milestone to 0.4.0

    i propose some kind of property or method on MapperExtension, lets say __inheritable__=True, which will indicate the extension should propigate to inheriting mappers.

    just for my own notes, the steps would be along the lines of:

    * compile_extensions() moves after compile_inheritance()
    * compile_extensions() needs to go through inherited mappers extensions (but ensuring that none are the same extension which it already has..) and add those in to its own ExtensionCarrier
    * ExtensionCarrier gets a "mapper" argument so it knows what mapper it was created against
    * ExtensionCarrier gets a method like "get_chain(somemapper)" which will return a chained MapperExtension (maybe another ExtensionCarrier object) for the given mapper, which has calculated "somemapper" against its own "mapper" and if they dont match, only returns mappers that are inheritable.  this would be called at the top of `_instances` right now where it figures out the per-query extension.  these chains would be cached in a dictionary based on the mapper since they need to be returned lightning fast.
    
  4. Log in to comment