[Python-Dev] PEP: Post import hooks
Phillip J. Eby
pje at telecommunity.com
Thu Jan 10 05:29:41 CET 2008
At 03:20 AM 1/10/2008 +0100, Christian Heimes wrote:
>PyObject* PyImport_NotifyModuleLoaded(PyObject *module)
> Notify the post import system that a module was requested. Returns the
> module or NULL if an error has occured.
The big problem here is that the interaction with laziness is
actually pretty complex, when it comes to re-entrancy and
initialization order. A package can actually import a submodule, and
not yet be finished importing, for example. So you can actually have
child hooks executing before parent hooks in this case.
The "Importing" package prevents this by not registering child hooks
until a parent is actually imported, thus guaranteeing a sane hook
execution order. Relative order for hooks targeting the same module
is maintained, but parent module hooks are guaranteed to execute
before child hooks, even if the child finishes importing before the parent.
This would be a bit trickier to implement with your C API, since
"Importing" does this by registering a lot of lambdas.
But, now that I've reviewed my own code and pieced back together the
rationale for it doing things in this seemingly-odd way, it makes sense.
There's also one twist that I haven't sorted out yet: "Importing"
guarantees that a parent module 'foo' will have a 'bar' attribute for
the 'foo.bar' module, if 'foo.bar' is lazy. It does this by
registering a callback, ideally *before* any other callback is
registered for 'foo' or 'foo.bar' that would look at 'foo.bar'. I
don't see how to maintain this condition in a world where import
callbacks can be registered independently.
Bleah. All of the above isn't really a good explanation of the
problem. Let me try to simplify it:
* Lazy importing needs to guarantee that foo.bar =
sys.modules['foo.bar'], when callbacks for 'foo.bar' execute (in case
they refer to foo.bar)
* To do this, it registers a callback that sets foo.bar =
sys.modules['foo.bar'], and does not actually register any foo.bar
callbacks until 'foo' is really imported (and thus foo.bar gets set
by that callback)
In the case of the PEP, it's harder for me to figure out what
happens, because you might not have any lazy modules around, and the
foo.bar issue would then not come up. You also have the possibility
of a problem where a lazy import callback occurs in 3rd party code,
while callbacks are occurring from the import machinery. (Which
means that the notification API should probably set the hooks entry
to None while it's running, so that if it's called from inside a
hook, it will not double-run the hooks, and new hooks registered
while hooks are running will get run immediately as they are
encountered, instead of getting added to the list.)
More information about the Python-Dev
mailing list