scan(package, ignore=None, handle_error=None)¶
Scan a package by importing it.
A framework can provide registration decorators: a decorator that when used on a class or a function causes it to be registered with the framework. Metaclasses can also be used for this effect. As a consequence of this, registration only takes place when the module is actually imported. You can do this import explicitly in your code. It can however also be convenient to import everything in a package all at once automatically. This is what
This function was extracted and refactored from the
Venusianlibrary which also provides infrastructure for finding such decorators.
- package – A reference to a Python package or module object.
- ignore –
Ignore certain modules or packages during a scan. It should be a sequence containing strings and/or callables that are used to match against the dotted name of a module encountered during a scan. The sequence can contain any of these three types of objects:
- A string representing a dotted name. For example, if you want
to ignore the
my.packagepackage and any of its submodules during the scan, pass
- A string representing a relative dotted name, a string
starting with a dot. The relative module or package is
relative to the
packagebeing scanned, so this does not match deeper relative packages.
For example, if the
packageyou’ve passed is imported as
my.package, and you pass
my.package.mymodulemymodule and any of its submodules are omitted during scan processing. But
my.package.sub.mymoduleis not ignored as
mymoduleis nested in
- A callable that accepts a dotted name indicating a module or a
package as its single positional argument and returns
False. For example, if you want to skip all packages and modules with a full dotted path that ends with the word “tests”, you can use
ignore=[re.compile('tests$').search]. If the callable returns
True(or anything else truthy), the object is ignored, if it returns
False(or anything else falsy) the object is not ignored.
You can mix and match the three types of strings in the list. For example, if the package being scanned is
ignore=['my.package', '.someothermodule', re.compile('tests$').search]would cause
my.package(and all its submodules and subobjects) to be ignored,
my.someothermoduleto be ignored, and any modules, packages, or global objects found during the scan that have a full dotted name that ends with the word
teststo be ignored.
Packages and modules matched by any ignore in the list are not imported, and their top-level (registration) code is not run as a result.
You can also pass in a string or callable by itself as a single non-list argument.
- A string representing a dotted name. For example, if you want to ignore the
- handle_error –
A callback function that is called when an exception is raised during the importing process. By default
scanpropagates all errors that happen during the import process, including
ImportError. If you use a custom
handle_errorcallback, you can change this behavior by not reraising the error.
Here’s an example
handle_errorcallback that ignores
ImportErrorbut not any other errors:
def handle_error(name, e): if not isinstance(e, ImportError): raise e
The first argument passed to
handle_erroris the module or package dotted name that could not be imported due to an exception. The second argument is the exception object. If
handle_errordoes not re-raise the error, the error is suppressed.