miracle2k
miracle2k

Reputation: 32087

Making a virtual package available via sys.modules

Say I have a package "mylibrary".

I want to make "mylibrary.config" available for import, either as a dynamically created module, or a module imported from an entirely different place that would then basically be "mounted" inside the "mylibrary" namespace.

I.e., I do:

import sys, types
sys.modules['mylibrary.config'] = types.ModuleType('config')

Given that setup:

>>> import mylibrary.config    # -> works

>>> from mylibrary import config
<type 'exceptions.ImportError'>: cannot import name config

Even stranger:

>>> import mylibrary.config as X
<type 'exceptions.ImportError'>: cannot import name config

So it seems that using the direct import works, the other forms do not. Is it possible to make those work as well?

Upvotes: 11

Views: 2235

Answers (3)

fuzzyman
fuzzyman

Reputation: 8381

As well as the following:

import sys, types
config = types.ModuleType('config')
sys.modules['mylibrary.config'] = config

You also need to do:

import mylibrary
mylibrary.config = config

Upvotes: 2

rob
rob

Reputation: 37664

You can try something like this:

class VirtualModule(object):
  def __init__(self, modname, subModules):
    try:
      import sys
      self._mod = __import__(modname)
      sys.modules[modname] = self
      __import__(modname)
      self._modname = modname
      self._subModules = subModules
    except ImportError, err:
      pass  # please signal error in some useful way :-)
  def __repr__(self):
    return "Virtual module for " + self._modname
  def __getattr__(self, attrname):
    if attrname in self._subModules.keys():
      import sys
      __import__(self._subModules[attrname])
      return sys.modules[self._subModules[attrname]]
    else:
      return self._mod.__dict__[attrname]


VirtualModule('mylibrary', {'config': 'actual_module_for_config'})

import mylibrary
mylibrary.config
mylibrary.some_function

Upvotes: 1

Martin v. L&#246;wis
Martin v. L&#246;wis

Reputation: 127527

You need to monkey-patch the module not only into sys.modules, but also into its parent module:

>>> import sys,types,xml
>>> xml.config = sys.modules['xml.config'] = types.ModuleType('xml.config')
>>> import xml.config
>>> from xml import config
>>> from xml import config as x
>>> x
<module 'xml.config' (built-in)>

Upvotes: 14

Related Questions