diff options
author | Marc Abramowitz <marc@marc-abramowitz.com> | 2016-03-07 18:52:36 -0800 |
---|---|---|
committer | Marc Abramowitz <marc@marc-abramowitz.com> | 2016-03-07 18:52:36 -0800 |
commit | cc83e06efff71b81ca5a3ac6df65775971181295 (patch) | |
tree | d52fa3f1a93730f263c2c5ac8266de8e5fb12abf /paste/util/import_string.py | |
download | paste-git-tox_coverage.tar.gz |
tox.ini: Measure test coveragetox_coverage
Diffstat (limited to 'paste/util/import_string.py')
-rw-r--r-- | paste/util/import_string.py | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/paste/util/import_string.py b/paste/util/import_string.py new file mode 100644 index 0000000..a10db18 --- /dev/null +++ b/paste/util/import_string.py @@ -0,0 +1,95 @@ +# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) +# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php + +""" +'imports' a string -- converts a string to a Python object, importing +any necessary modules and evaluating the expression. Everything +before the : in an import expression is the module path; everything +after is an expression to be evaluated in the namespace of that +module. + +Alternately, if no : is present, then import the modules and get the +attributes as necessary. Arbitrary expressions are not allowed in +that case. +""" + +def eval_import(s): + """ + Import a module, or import an object from a module. + + A module name like ``foo.bar:baz()`` can be used, where + ``foo.bar`` is the module, and ``baz()`` is an expression + evaluated in the context of that module. Note this is not safe on + arbitrary strings because of the eval. + """ + if ':' not in s: + return simple_import(s) + module_name, expr = s.split(':', 1) + module = import_module(module_name) + obj = eval(expr, module.__dict__) + return obj + +def simple_import(s): + """ + Import a module, or import an object from a module. + + A name like ``foo.bar.baz`` can be a module ``foo.bar.baz`` or a + module ``foo.bar`` with an object ``baz`` in it, or a module + ``foo`` with an object ``bar`` with an attribute ``baz``. + """ + parts = s.split('.') + module = import_module(parts[0]) + name = parts[0] + parts = parts[1:] + last_import_error = None + while parts: + name += '.' + parts[0] + try: + module = import_module(name) + parts = parts[1:] + except ImportError as e: + last_import_error = e + break + obj = module + while parts: + try: + obj = getattr(module, parts[0]) + except AttributeError: + raise ImportError( + "Cannot find %s in module %r (stopped importing modules with error %s)" % (parts[0], module, last_import_error)) + parts = parts[1:] + return obj + +def import_module(s): + """ + Import a module. + """ + mod = __import__(s) + parts = s.split('.') + for part in parts[1:]: + mod = getattr(mod, part) + return mod + +def try_import_module(module_name): + """ + Imports a module, but catches import errors. Only catches errors + when that module doesn't exist; if that module itself has an + import error it will still get raised. Returns None if the module + doesn't exist. + """ + try: + return import_module(module_name) + except ImportError as e: + if not getattr(e, 'args', None): + raise + desc = e.args[0] + if not desc.startswith('No module named '): + raise + desc = desc[len('No module named '):] + # If you import foo.bar.baz, the bad import could be any + # of foo.bar.baz, bar.baz, or baz; we'll test them all: + parts = module_name.split('.') + for i in range(len(parts)): + if desc == '.'.join(parts[i:]): + return None + raise |