2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/202e6aee5890/ Changeset: 202e6aee5890 Branch: issue486 User: hpk42 Date: 2014-04-02 20:42:41 Summary: fix issue486: better reporting and handling of early conftest loading failures Affected #: 4 files
diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r 202e6aee58906bf7fc5313d8567bb0451497394f CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -48,6 +48,9 @@ - fix issue493: don't run tests in doc directory with ``python setup.py test`` (use tox -e doctesting for that) +- fix issue486: better reporting and handling of early conftest loading failures + + 2.5.2 ----------------------------------- diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r 202e6aee58906bf7fc5313d8567bb0451497394f _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -7,6 +7,13 @@ from _pytest.core import PluginManager # pytest startup +# +class ConftestImportFailure(Exception): + def __init__(self, path, excinfo): + Exception.__init__(self, path, excinfo) + self.path = path + self.excinfo = excinfo + def main(args=None, plugins=None): """ return exit code, after performing an in-process test run. @@ -16,8 +23,17 @@ :arg plugins: list of plugin objects to be auto-registered during initialization. """ - config = _prepareconfig(args, plugins) - return config.hook.pytest_cmdline_main(config=config) + try: + config = _prepareconfig(args, plugins) + except ConftestImportFailure: + e = sys.exc_info()[1] + tw = py.io.TerminalWriter(sys.stderr) + for line in py.std.traceback.format_exception(*e.excinfo): + tw.line(line.rstrip(), red=True) + tw.line("ERROR: could not load %s\n" % (e.path), red=True) + return 4 + else: + return config.hook.pytest_cmdline_main(config=config) class cmdline: # compatibility namespace main = staticmethod(main) @@ -86,8 +102,7 @@ config.addinivalue_line("markers", "trylast: mark a hook implementation function such that the " "plugin machinery will try to call it last/as late as possible.") - while self._warnings: - warning = self._warnings.pop(0) + for warning in self._warnings: config.warn(code="I1", message=warning) @@ -496,7 +511,8 @@ continue conftestpath = parent.join("conftest.py") if conftestpath.check(file=1): - clist.append(self.importconftest(conftestpath)) + mod = self.importconftest(conftestpath) + clist.append(mod) self._path2confmods[path] = clist return clist @@ -522,7 +538,11 @@ pkgpath = conftestpath.pypkgpath() if pkgpath is None: _ensure_removed_sysmodule(conftestpath.purebasename) - self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport() + try: + mod = conftestpath.pyimport() + except Exception: + raise ConftestImportFailure(conftestpath, sys.exc_info()) + self._conftestpath2mod[conftestpath] = mod dirpath = conftestpath.dirpath() if dirpath in self._path2confmods: for path, mods in self._path2confmods.items(): @@ -682,9 +702,19 @@ self.pluginmanager.consider_preparse(args) self.pluginmanager.consider_setuptools_entrypoints() self.pluginmanager.consider_env() - self.known_args_namespace = self._parser.parse_known_args(args) - self.hook.pytest_load_initial_conftests(early_config=self, - args=args, parser=self._parser) + self.known_args_namespace = ns = self._parser.parse_known_args(args) + try: + self.hook.pytest_load_initial_conftests(early_config=self, + args=args, parser=self._parser) + except ConftestImportFailure: + e = sys.exc_info()[1] + if ns.help or ns.version: + # we don't want to prevent --help/--version to work + # so just let is pass and print a warning at the end + self.pluginmanager._warnings.append( + "could not load initial conftests (%s)\n" % e.path) + else: + raise def _checkversion(self): import pytest diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r 202e6aee58906bf7fc5313d8567bb0451497394f _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -86,17 +86,9 @@ tw.line("(shown according to specified file_or_dir or current dir " "if not specified)") for warning in config.pluginmanager._warnings: - tw.line("warning: %s" % (warning,)) + tw.line("warning: %s" % (warning,), red=True) return - tw.line("conftest.py options:") - tw.line() - conftestitems = sorted(config._parser._conftestdict.items()) - for name, help in conftest_options + conftestitems: - line = " %-15s %s" %(name, help) - tw.line(line[:tw.fullwidth]) - tw.line() - #tw.sep( "=") conftest_options = [ ('pytest_plugins', 'list of plugin names to load'), diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r 202e6aee58906bf7fc5313d8567bb0451497394f testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -124,6 +124,18 @@ "*ERROR: not found:*%s" %(p2.basename,) ]) + def test_issue486_better_reporting_on_conftest_load_failure(self, testdir): + testdir.makepyfile("") + testdir.makeconftest("import qwerty") + result = testdir.runpytest("--help") + result.stdout.fnmatch_lines(""" + *--version* + *warning*conftest.py* + """) + result = testdir.runpytest() + result.stderr.fnmatch_lines(""" + *ERROR*could not load*conftest.py* + """) def test_early_skip(self, testdir): https://bitbucket.org/hpk42/pytest/commits/e5b0bd42a006/ Changeset: e5b0bd42a006 User: bubenkoff Date: 2014-04-03 00:19:05 Summary: Merged in hpk42/pytest-hpk/issue486 (pull request #147) fix issue486: better reporting and handling of early conftest loading failures Affected #: 4 files diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r e5b0bd42a00632fec91a70fb8c61edcd7d38e898 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -48,6 +48,9 @@ - fix issue493: don't run tests in doc directory with ``python setup.py test`` (use tox -e doctesting for that) +- fix issue486: better reporting and handling of early conftest loading failures + + 2.5.2 ----------------------------------- diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r e5b0bd42a00632fec91a70fb8c61edcd7d38e898 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -7,6 +7,13 @@ from _pytest.core import PluginManager # pytest startup +# +class ConftestImportFailure(Exception): + def __init__(self, path, excinfo): + Exception.__init__(self, path, excinfo) + self.path = path + self.excinfo = excinfo + def main(args=None, plugins=None): """ return exit code, after performing an in-process test run. @@ -16,8 +23,17 @@ :arg plugins: list of plugin objects to be auto-registered during initialization. """ - config = _prepareconfig(args, plugins) - return config.hook.pytest_cmdline_main(config=config) + try: + config = _prepareconfig(args, plugins) + except ConftestImportFailure: + e = sys.exc_info()[1] + tw = py.io.TerminalWriter(sys.stderr) + for line in py.std.traceback.format_exception(*e.excinfo): + tw.line(line.rstrip(), red=True) + tw.line("ERROR: could not load %s\n" % (e.path), red=True) + return 4 + else: + return config.hook.pytest_cmdline_main(config=config) class cmdline: # compatibility namespace main = staticmethod(main) @@ -86,8 +102,7 @@ config.addinivalue_line("markers", "trylast: mark a hook implementation function such that the " "plugin machinery will try to call it last/as late as possible.") - while self._warnings: - warning = self._warnings.pop(0) + for warning in self._warnings: config.warn(code="I1", message=warning) @@ -496,7 +511,8 @@ continue conftestpath = parent.join("conftest.py") if conftestpath.check(file=1): - clist.append(self.importconftest(conftestpath)) + mod = self.importconftest(conftestpath) + clist.append(mod) self._path2confmods[path] = clist return clist @@ -522,7 +538,11 @@ pkgpath = conftestpath.pypkgpath() if pkgpath is None: _ensure_removed_sysmodule(conftestpath.purebasename) - self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport() + try: + mod = conftestpath.pyimport() + except Exception: + raise ConftestImportFailure(conftestpath, sys.exc_info()) + self._conftestpath2mod[conftestpath] = mod dirpath = conftestpath.dirpath() if dirpath in self._path2confmods: for path, mods in self._path2confmods.items(): @@ -682,9 +702,19 @@ self.pluginmanager.consider_preparse(args) self.pluginmanager.consider_setuptools_entrypoints() self.pluginmanager.consider_env() - self.known_args_namespace = self._parser.parse_known_args(args) - self.hook.pytest_load_initial_conftests(early_config=self, - args=args, parser=self._parser) + self.known_args_namespace = ns = self._parser.parse_known_args(args) + try: + self.hook.pytest_load_initial_conftests(early_config=self, + args=args, parser=self._parser) + except ConftestImportFailure: + e = sys.exc_info()[1] + if ns.help or ns.version: + # we don't want to prevent --help/--version to work + # so just let is pass and print a warning at the end + self.pluginmanager._warnings.append( + "could not load initial conftests (%s)\n" % e.path) + else: + raise def _checkversion(self): import pytest diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r e5b0bd42a00632fec91a70fb8c61edcd7d38e898 _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -86,17 +86,9 @@ tw.line("(shown according to specified file_or_dir or current dir " "if not specified)") for warning in config.pluginmanager._warnings: - tw.line("warning: %s" % (warning,)) + tw.line("warning: %s" % (warning,), red=True) return - tw.line("conftest.py options:") - tw.line() - conftestitems = sorted(config._parser._conftestdict.items()) - for name, help in conftest_options + conftestitems: - line = " %-15s %s" %(name, help) - tw.line(line[:tw.fullwidth]) - tw.line() - #tw.sep( "=") conftest_options = [ ('pytest_plugins', 'list of plugin names to load'), diff -r ceafafc62657ed15b0486e8838f20b06abc0880d -r e5b0bd42a00632fec91a70fb8c61edcd7d38e898 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -124,6 +124,18 @@ "*ERROR: not found:*%s" %(p2.basename,) ]) + def test_issue486_better_reporting_on_conftest_load_failure(self, testdir): + testdir.makepyfile("") + testdir.makeconftest("import qwerty") + result = testdir.runpytest("--help") + result.stdout.fnmatch_lines(""" + *--version* + *warning*conftest.py* + """) + result = testdir.runpytest() + result.stderr.fnmatch_lines(""" + *ERROR*could not load*conftest.py* + """) def test_early_skip(self, testdir): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org https://mail.python.org/mailman/listinfo/pytest-commit