How to make "import x" return a subclass of .ModuleType types?

Can a Python import statement return a subclass of types.ModuleType with import hooks? I would like to override __getattribute__ to display a warning at runtime when the code outside the specific module link names is not in __all__ .

I know how to replace sys.modules['foo'] after importing it. I want the tool modules to match the pattern when importing, so that the import code can trigger a warning.

Python frowns at the idea of โ€‹โ€‹making things public and private. This idea is not to prevent users of your module from entering text from somemodule import sys ; instead it is a documentation tool. This tool should make it much easier to document your module API by including the correct __all__ in it. This should help you avoid accidentally specifying sys as somemodule.sys instead of just import sys .

+7
source share
3 answers

Since I missed the point of your question before you edited it, I thought I would delete it again (leaving my original answer for posterity).

Here is an alternative that also does not require import capture. It can be easily used modulo: a module that includes this code will have the special behavior __getattribute__() , while other modules will behave as usual.

 class StrictModule(types.ModuleType): def __getattribute__(self, key): if key is "__dict__": # fake __dict__ with only visible attributes return dict((k, v) for k, v in globals().iteritems() if k.startswith("__") or k in __all__) if (key.startswith("__") or key in __all__) and key in globals(): return globals()[key] else: raise AttributeError("'module' object has no attribute '%s'" % key) def __setattr__(self, key, value): globals()[key] = value sys.modules[__name__] = StrictModule(__name__) 

Remember that this โ€œlimitationโ€ is easily circumvented by simply calling the regular module type __getattribute__() (or, something else, the type object ). I get the impression that you are trying to provide some kind of "private member" restriction for your modules. There almost never made any sense.

+5
source

You don't even need an import hook. Just put the link to the object in the sys.modules Python module sys.modules under the name you want, and any future import statement in the Python session (even in other modules) imports the link to this object.

 import types, sys class MyModuleType(types.ModuleType): pass sys.modules["foo"] = MyModuleType("foo") import foo print type(foo) # MyModuleType 

Python doesn't even care if the objects in sys.modules are really modules or some other type of object. You could pull an int there, and not a single f *** would be specified.

 sys.modules["answer"] = 42 import answer 
+3
source

You can adapt this ActiveState recipe , perhaps something like this:

 # safemodule.py import sys import types import warnings class EncapsulationWarning(RuntimeWarning): pass class ModuleWrapper(types.ModuleType): def __init__(self, context): self.context = context super(ModuleWrapper, self).__init__( context.__name__, context.__doc__) def __getattribute__(self, key): context = object.__getattribute__(self, 'context') if hasattr(context, '__all__') and key not in context.__all__: warnings.warn('%s not in %s.__all__' % (key, context.__name__), EncapsulationWarning, 2) return context.__getattribute__(key) if 'old_import' not in globals(): old_import = __import__ def safe_import(*args, **kwargs): m = old_import(*args, **kwargs) return ModuleWrapper(m) __builtins__['__import__'] = safe_import 

Then use it as follows:

 C:\temp>python ActivePython 2.5.2.2 (ActiveState Software Inc.) based on Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import safemodule >>> import sys >>> type(sys) <class 'safemodule.ModuleWrapper'> >>> 

You can, of course, adapt this to wrap only some modules, etc.

+3
source

All Articles