This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author brett.cannon
Recipients benjamin.peterson, brett.cannon, pitrou
Date 2013-06-21.17:51:13
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <CAP1=2W5+D75f6-t9xv-h-PJuYWUYjCmvHtXxRpo6QEeRwsba_g@mail.gmail.com>
In-reply-to <321168303.104948717.1371827476523.JavaMail.root@zimbra10-e2.priv.proxad.net>
Content
On Fri, Jun 21, 2013 at 11:11 AM, Antoine Pitrou <report@bugs.python.org>wrote:

>
> Antoine Pitrou added the comment:
>
> > I'm attracted to the idea of making a loader lazy by simply doing
> > something
> > like ``class LazySourceFileLoader(LazyMixin, SourceFileLoader):
> > ...``.
>
> But then you have to make a specific Lazy subclass for each delegated
> loader implementation. With a proxy class you would simply proxy each
> loader instance:
>
> existing_loader = SourceFileLoader(...)
> lazy_loader = LazyLoader(existing_loader)
> ...

But the point I tried to make earlier is that approach doesn't work
directly when you are creating the loader instances dynamically within a
finder. E.g. FileFinder (
http://docs.python.org/3/library/importlib.html#importlib.machinery.FileFinder)
instantiates the loader for you.

Now you could tweak things to make this work, but it isn't quite as
straightforward as you suggest because of this need to have a callable for
finders to use to create new loaders:

class LazyProxy(importlib.abc.Loader):

  def __init__(self, loader):
    self.loader = loader

  def __call__(self, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    return self

  def load_module(self, fullname):
    # XXX ignoring sys.modules details, e.g. if module already existed.
    lazy_module = LazyModule(fullname, proxy=self, name=fullname)
    sys.modules[fullname] = lazy_module
    return lazy_module

class LazyModule(types.ModuleType):

    def __init__(*args, proxy, name, **kwargs):
      self.__proxy = proxy
      self.__name = name
      super().__init__(*args, **kwargs)

    def __getattribute__(self, attr):
      self.__class__ = Module
      state = self.__dict__.copy()
      loader = self.__proxy.loader(*self.proxy.args, **self.proxy.kwargs)
      # XXX ignoring sys.modules details, e.g. removing module on load
failure.
      loader.load_module(self.__name)
      self.__dict__.update(state)
      return getattr(module, attr)

That's all totally untested (not even verified to compile) but I think that
would do what you are suggesting.
History
Date User Action Args
2013-06-21 17:51:14brett.cannonsetrecipients: + brett.cannon, pitrou, benjamin.peterson
2013-06-21 17:51:13brett.cannonlinkissue18275 messages
2013-06-21 17:51:13brett.cannoncreate