diff options
author | Ryan Petrello <lists@ryanpetrello.com> | 2015-01-06 11:16:45 -0500 |
---|---|---|
committer | Ryan Petrello <lists@ryanpetrello.com> | 2015-01-06 13:47:29 -0500 |
commit | 868ab86e7666eea619c5371fe2b32f88d442c9a1 (patch) | |
tree | 5fc93ff9180f59a71d73312fbf030b4b7729b448 /pecan | |
parent | 97306eda458f7f54d3eac7df0bda4165ea9fd1e7 (diff) | |
download | pecan-868ab86e7666eea619c5371fe2b32f88d442c9a1.tar.gz |
Improve ImportError verbosity for configuration files.
Fixes bug: 1408008
Change-Id: Iac73b6b0017794de9dea4180d043c18d3fb6d942
Diffstat (limited to 'pecan')
-rw-r--r-- | pecan/configuration.py | 23 | ||||
-rw-r--r-- | pecan/tests/test_conf.py | 16 |
2 files changed, 38 insertions, 1 deletions
diff --git a/pecan/configuration.py b/pecan/configuration.py index b4109a8..42a9b50 100644 --- a/pecan/configuration.py +++ b/pecan/configuration.py @@ -4,6 +4,11 @@ import os import six +if six.PY3: + from importlib.machinery import SourceFileLoader +else: + import imp + IDENTIFIER = re.compile(r'[a-z_](\w)*$', re.IGNORECASE) @@ -152,8 +157,24 @@ def conf_from_file(filepath): if not os.path.isfile(abspath): raise RuntimeError('`%s` is not a file.' % abspath) + # First, make sure the code will actually compile (and has no SyntaxErrors) with open(abspath, 'rb') as f: - exec(compile(f.read(), abspath, 'exec'), globals(), conf_dict) + compiled = compile(f.read(), abspath, 'exec') + + # Next, attempt to actually import the file as a module. + # This provides more verbose import-related error reporting than exec() + absname, _ = os.path.splitext(abspath) + basepath, module_name = absname.rsplit(os.sep, 1) + if six.PY3: + SourceFileLoader(module_name, abspath).load_module(module_name) + else: + imp.load_module( + module_name, + *imp.find_module(module_name, [basepath]) + ) + + # If we were able to import as a module, actually exec the compiled code + exec(compiled, globals(), conf_dict) conf_dict['__file__'] = abspath return conf_from_dict(conf_dict) diff --git a/pecan/tests/test_conf.py b/pecan/tests/test_conf.py index c273b6f..e682885 100644 --- a/pecan/tests/test_conf.py +++ b/pecan/tests/test_conf.py @@ -144,6 +144,22 @@ class TestConf(PecanTestCase): f.name ) + def test_config_with_non_package_relative_import(self): + from pecan import configuration + with tempfile.NamedTemporaryFile('wb', suffix='.py') as f: + f.write(b_('\n'.join(['from . import variables']))) + f.flush() + configuration.Config({}) + + try: + configuration.conf_from_file(f.name) + except (ValueError, SystemError) as e: + assert 'relative import' in str(e) + else: + raise AssertionError( + "A relative import-related error should have been raised" + ) + def test_config_with_bad_import(self): from pecan import configuration path = ('bad', 'importerror.py') |