Improve ImportError verbosity for configuration files.

Fixes bug: 1408008

Change-Id: Iac73b6b0017794de9dea4180d043c18d3fb6d942
This commit is contained in:
Ryan Petrello
2015-01-06 11:16:45 -05:00
parent 97306eda45
commit 868ab86e76
2 changed files with 38 additions and 1 deletions

View File

@@ -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)

View File

@@ -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')