[Python-ideas] Module aliases and/or "real names"

Ron Adam rrr at ronadam.com
Wed Jan 12 11:31:12 CET 2011



On 12/29/2010 03:52 PM, Nick Coghlan wrote:
> Disclaimer: this is a currently half-baked idea that needs some
> discussion here if it is going to turn into something a bit more
> coherent :)
>
> On and off, I've been pondering the problem of the way implementation
> details (like the real file structures of the multiprocessing and
> unittest packages, or whether or not an interpreter use the pure
> Python or the C accelerated version of various modules) leak out into
> the world via the __module__ attribute on various components. This
> mostly comes up when discussing pickle compatibility between 2.x and
> 3.x, but in can show up in various guises whenever you start relying
> on dynamic introspection.
>
> As, I see it, there are 3 basic ways of dealing with the problem:
>
> 1. Allow objects to lie about their source module
>    This is likely a terrible idea, since a function's global namespace
> reference would disagree with its module reference. I suspect much
> weirdness would result.
>
> 2. A pickle-specific module alias registry, since that is where the
> problem comes up most often
>    A possible approach, but not necessarily a good one (since it isn't
> really a pickle-specific problem).
>
> 3. An inspect-based module alias registry
>    That is, an additional query API (get_canonical_module_name?) in the
> inspect module that translates from the implementation detail module
> name to the "preferred" module name. The implementation could be as
> simple as a "__canonical__" attribute in the module namespace.
>
> I actually quite like option 3, with various things (such as pydoc)
> updated to show *both* names when they're different. That way people
> will know where to find official documentation for objects from
> pseudo-packages and acceleration modules (i.e. under the canonical
> name), without hiding where the actual implementation came from.
>
> Pickle *generation* could then be updated to only send canonical
> module names during normal operation, reducing the exposure of
> implementation details like pseudo-packages and acceleration modules.
>
> Whether or not runpy should set __canonical__ on the main module would
> be an open question (probably not, *unless* runpy was also updated to
> add the main module to sys.modules under its real name as well
> __main__).


This makes more sense now that we've discussed it a bit.


Here's a rough sketch of a context manager that temporarily overrides the 
__module__ attribute.

This works well for simple introspection.  For example, you can use it to 
call inspect functions without changing them.

But pickling is recursive, so this probably wouldn't work very well for that.

Cheers,
    Ron


#-------------------------------

from contextlib import contextmanager

class cls:
    def method(self): pass
c = cls()
InstanceMethod = type(c.method)


def _getter(self, value):
     if value == "__module__" and hasattr(self, "__alt_module__"):
         return object.__getattribute__(self, "__alt_module__")
     return object.__getattribute__(self, value)


@contextmanager
def alt_module_getter(obj):
     obj.__class__.__getattribute__ = InstanceMethod(_getter, obj)
     try:
         yield obj
     finally:
         del obj.__class__.__getattribute__



def get_module_name(obj):
     return obj.__module__


# gets __alt__module__ if it exists, else gets __module__

with alt_module_getter(obj) as obj:
      module_name = get_module_name(obj)





More information about the Python-ideas mailing list