(original) (raw)



On Tue, May 22, 2012 at 9:58 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:

If you wanted to do this without changing the sys.meta_path hook API,

you'd have to pass an object to find_module() that did the dynamic

lookup of the value in obj.__iter__. Something like:



� �class _LazyPath:

� � � �def __init__(self, modname, attribute):

� � � � � �self.modname = modname

� � � � � �self.attribute = attribute

� � � �def __iter__(self):

� � � � � �return iter(getattr(sys.module[self.modname], self.attribute))



A potentially cleaner alternative to consider is tweaking the

find_loader API spec so that it gets used at the meta path level as

well as at the path hooks level and is handed a *callable* that

dynamically retrieves the path rather than a direct reference to the

path itself.



The full signature of find_loader would then become:



� �def find_loader(fullname, get_path=None):

� � � �# fullname as for find_module

� � � �# When get_path is None, it means the finder is being called

as a path hook and

� � � �# should use the specific path entry passed to __init__

� � � �# In this case, namespace package portions are returned as

(None, portions)

� � � �# Otherwise, the finder is being called as a meta_path hook

and get_path() will return the relevant path

� � � �# Any namespace packages are then returned as (loader, portions)



There are two major consequences of this latter approach:

- the PEP 302 find_module API would now be a purely legacy interface

for both the meta_path and path_hooks, used only if find_loader is not

defined

- it becomes trivial to tell whether a particular name references a

package or not *without* needing to load it first: find_loader()

returns a non-empty iterable for the list of portions



That second consequence is rather appealing: it means you'd be able to

implement an almost complete walk of a package hierarchy *without*

having to import anything (although you would miss old-style namespace

packages and any other packages that alter their own __path__ in

__init__, so you may still want to load packages to make sure you

found everything. You could definitively answer the "is this a package

or not?" question without running any code, though).



The first consequence is also appealing, since the find_module() name

is more than a little misleading. The "find_module" name strongly

suggests that the method is expected to return a module object, and

that's just wrong - �you actually find a loader, then you use that to

load the module.

While I see no problem with cleaning up the interface, I'm kind of lost as to the point of making a get_path callable, vs. just using the iterable interface you sketched.� Python has iterables, so why add a call to get the iterable, when iter() or a straight "for" loop will do effectively the same thing?