Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make 'import x' return a subclass of types.ModuleType?

Tags:

python

Can Python's import statement return a subclass of types.ModuleType using import hooks? I would like to override __getattribute__ to display a runtime warning when code outside a certain module reference names that aren't in __all__.

I know how to replace sys.modules['foo'] after it's been imported. What I want is to instrument modules that match a pattern as they are imported so the importing code has an opportunity to trigger the warning.

Python frowns on the idea of making things public and private. This idea isn't about preventing your module's users from typing from somemodule import sys; instead, it is a documentation tool. This kind of instrumentation should make it much easier to document your module's API by including a correct __all__. It should help you avoid accidentally referencing sys as somemodule.sys instead of simply import sys.

like image 915
joeforker Avatar asked May 12 '11 19:05

joeforker


People also ask

What does Importlib Import_module return?

This means all semantics of the function are derived from importlib. __import__() . The most important difference between these two functions is that import_module() returns the specified package or module (e.g. pkg. mod ), while __import__() returns the top-level package or module (e.g. pkg ).

What does from X import * mean in Python?

In Python, import * means you are importing all the classes and functions from a library. E.g from maths import * will import all the classes and functions in the maths library.

What is Moduletype in Python?

The types module contains type objects for all object types defined by the standard interpreter, as Example 1-86 demonstrates. All objects of the same type share a single type object. You can use is to test if an object has a given type.

What is __ loader __ in Python?

__loader__ is an attribute that is set on an imported module by its loader. Accessing it should return the loader object itself. In Python versions before 3.3, __loader__ was not set by the built-in import machinery. Instead, this attribute was only available on modules that were imported using a custom loader.


1 Answers

Since I missed the point of your question before you edited it, I thought I'd take another whack (while leaving my original answer for posterity).

Here's an alternative that also doesn't need the import hook. It can easily be used on a module-by-module basis: a module that includes this code will have the special __getattribute__() behavior, 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__)

Keep in mind this "restriction" is easy to get around by simply calling the regular module type's __getattribute__() (or for that matter, the object type's). I get the impression that you are trying to provide some kind of "private member" restriction for your modules. There's almost never any point to this.

like image 161
kindall Avatar answered Sep 20 '22 13:09

kindall