5 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/0572f79c5f9c/ Changeset: 0572f79c5f9c User: hpk42 Date: 2013-09-28 09:52:41 Summary: move FILE_OR_DIR constant out Affected #: 2 files
diff -r 9b4dae68a5a41d75bbe4c48b1b5d45806e522717 -r 0572f79c5f9c786d1c643352d639c8f7112a8edd _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -93,7 +93,7 @@ a = option.attrs() arggroup.add_argument(*n, **a) # bash like autocompletion for dirs (appending '/') - optparser.add_argument(Config._file_or_dir, nargs='*' + optparser.add_argument(FILE_OR_DIR, nargs='*' ).completer=filescompleter try_argcomplete(self.optparser) return self.optparser.parse_args([str(x) for x in args]) @@ -102,7 +102,7 @@ parsedoption = self.parse(args) for name, value in parsedoption.__dict__.items(): setattr(option, name, value) - return getattr(parsedoption, Config._file_or_dir) + return getattr(parsedoption, FILE_OR_DIR) def addini(self, name, help, type=None, default=None): """ register an ini-file option. @@ -323,22 +323,9 @@ if arg and arg[0] == '-': msg = py.std.argparse._('unrecognized arguments: %s') self.error(msg % ' '.join(argv)) - getattr(args, Config._file_or_dir).extend(argv) + getattr(args, FILE_OR_DIR).extend(argv) return args -# #pylib 2013-07-31 -# (12:05:53) anthon: hynek: can you get me a list of preferred py.test -# long-options with '-' inserted at the right places? -# (12:08:29) hynek: anthon, hpk: generally I'd love the following, decide -# yourself which you agree and which not: -# (12:10:51) hynek: --exit-on-first --full-trace --junit-xml --junit-prefix -# --result-log --collect-only --conf-cut-dir --trace-config -# --no-magic -# (12:18:21) hpk: hynek,anthon: makes sense to me. -# (13:40:30) hpk: hynek: let's not change names, rather only deal with -# hyphens for now -# (13:40:50) hynek: then --exit-first *shrug* - class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter): """shorten help for long options that differ only in extra hyphens @@ -504,15 +491,15 @@ def __repr__(self): return "<CmdOptions %r>" %(self.__dict__,) +FILE_OR_DIR = 'file_or_dir' class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ - _file_or_dir = 'file_or_dir' def __init__(self, pluginmanager=None): #: access to command line option as attributes. #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead self.option = CmdOptions() - _a = self._file_or_dir + _a = FILE_OR_DIR self._parser = Parser( usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a), processopt=self._processopt, diff -r 9b4dae68a5a41d75bbe4c48b1b5d45806e522717 -r 0572f79c5f9c786d1c643352d639c8f7112a8edd testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -95,11 +95,11 @@ parser.addoption("--hello", dest="hello", action="store") args = parser.parse(['--hello', 'world']) assert args.hello == "world" - assert not getattr(args, parseopt.Config._file_or_dir) + assert not getattr(args, parseopt.FILE_OR_DIR) def test_parse2(self, parser): args = parser.parse([py.path.local()]) - assert getattr(args, parseopt.Config._file_or_dir)[0] == py.path.local() + assert getattr(args, parseopt.FILE_OR_DIR)[0] == py.path.local() def test_parse_will_set_default(self, parser): parser.addoption("--hello", dest="hello", default="x", action="store") @@ -128,13 +128,13 @@ parser.addoption("-R", action='store_true') parser.addoption("-S", action='store_false') args = parser.parse(['-R', '4', '2', '-S']) - assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2'] + assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] args = parser.parse(['-R', '-S', '4', '2', '-R']) - assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2'] + assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] assert args.R == True assert args.S == False args = parser.parse(['-R', '4', '-S', '2']) - assert getattr(args, parseopt.Config._file_or_dir) == ['4', '2'] + assert getattr(args, parseopt.FILE_OR_DIR) == ['4', '2'] assert args.R == True assert args.S == False https://bitbucket.org/hpk42/pytest/commits/db80055e00dd/ Changeset: db80055e00dd User: hpk42 Date: 2013-09-28 22:22:53 Summary: simplify Config constructor Affected #: 4 files diff -r 0572f79c5f9c786d1c643352d639c8f7112a8edd -r db80055e00dd94a6f5daf266ccee1deee0aac291 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -495,7 +495,7 @@ class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ - def __init__(self, pluginmanager=None): + def __init__(self, pluginmanager): #: access to command line option as attributes. #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead self.option = CmdOptions() @@ -505,7 +505,7 @@ processopt=self._processopt, ) #: a pluginmanager instance - self.pluginmanager = pluginmanager or PluginManager(load=True) + self.pluginmanager = pluginmanager self.trace = self.pluginmanager.trace.root.get("config") self._conftest = Conftest(onimport=self._onimportconftest) self.hook = self.pluginmanager.hook @@ -516,7 +516,7 @@ @classmethod def fromdictargs(cls, option_dict, args): """ constructor useable for subprocesses. """ - config = cls() + config = cls(PluginManager(load=True)) # XXX slightly crude way to initialize capturing import _pytest.capture _pytest.capture.pytest_cmdline_parse(config.pluginmanager, args) diff -r 0572f79c5f9c786d1c643352d639c8f7112a8edd -r db80055e00dd94a6f5daf266ccee1deee0aac291 testing/test_config.py --- a/testing/test_config.py +++ b/testing/test_config.py @@ -82,7 +82,7 @@ class TestConfigAPI: def test_config_trace(self, testdir): - config = testdir.Config() + config = testdir.parseconfig() l = [] config.trace.root.setwriter(l.append) config.trace("hello") diff -r 0572f79c5f9c786d1c643352d639c8f7112a8edd -r db80055e00dd94a6f5daf266ccee1deee0aac291 testing/test_core.py --- a/testing/test_core.py +++ b/testing/test_core.py @@ -319,7 +319,7 @@ def pytest_myhook(xyz): return xyz + 1 """) - config = testdir.Config() + config = testdir.Config(PluginManager(load=True)) config._conftest.importconftest(conf) print(config.pluginmanager.getplugins()) res = config.hook.pytest_myhook(xyz=10) diff -r 0572f79c5f9c786d1c643352d639c8f7112a8edd -r db80055e00dd94a6f5daf266ccee1deee0aac291 testing/test_tmpdir.py --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -36,7 +36,7 @@ class TestTempdirHandler: def test_mktemp(self, testdir): - config = testdir.Config() + config = testdir.parseconfig() config.option.basetemp = testdir.mkdir("hello") t = TempdirHandler(config) tmp = t.mktemp("world") https://bitbucket.org/hpk42/pytest/commits/1e3fe8b9de1a/ Changeset: 1e3fe8b9de1a User: hpk42 Date: 2013-09-28 22:22:55 Summary: refine fromdictargs to avoid an uncessary re-setup of the pluginmanager Affected #: 2 files diff -r db80055e00dd94a6f5daf266ccee1deee0aac291 -r 1e3fe8b9de1ab56da5e4d02e60f82cc6cf8740c3 _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -516,7 +516,9 @@ @classmethod def fromdictargs(cls, option_dict, args): """ constructor useable for subprocesses. """ - config = cls(PluginManager(load=True)) + from _pytest.core import get_plugin_manager + pluginmanager = get_plugin_manager() + config = cls(pluginmanager) # XXX slightly crude way to initialize capturing import _pytest.capture _pytest.capture.pytest_cmdline_parse(config.pluginmanager, args) diff -r db80055e00dd94a6f5daf266ccee1deee0aac291 -r 1e3fe8b9de1ab56da5e4d02e60f82cc6cf8740c3 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -460,8 +460,15 @@ _preinit = [] def _preloadplugins(): + assert not _preinit _preinit.append(PluginManager(load=True)) +def get_plugin_manager(): + if _preinit: + return _preinit.pop(0) + else: # subsequent calls to main will create a fresh instance + return PluginManager(load=True) + def _prepareconfig(args=None, plugins=None): if args is None: args = sys.argv[1:] @@ -471,16 +478,12 @@ if not isinstance(args, str): raise ValueError("not a string or argument list: %r" % (args,)) args = py.std.shlex.split(args) - if _preinit: - _pluginmanager = _preinit.pop(0) - else: # subsequent calls to main will create a fresh instance - _pluginmanager = PluginManager(load=True) - hook = _pluginmanager.hook + pluginmanager = get_plugin_manager() if plugins: for plugin in plugins: - _pluginmanager.register(plugin) - return hook.pytest_cmdline_parse( - pluginmanager=_pluginmanager, args=args) + pluginmanager.register(plugin) + return pluginmanager.hook.pytest_cmdline_parse( + pluginmanager=pluginmanager, args=args) def main(args=None, plugins=None): """ return exit code, after performing an in-process test run. https://bitbucket.org/hpk42/pytest/commits/967c8ec78e69/ Changeset: 967c8ec78e69 User: hpk42 Date: 2013-09-28 22:22:57 Summary: remove very likely unused pytest_plugin_unregister hook (pytest itself and all plugins i know don't use it) Affected #: 3 files diff -r 1e3fe8b9de1ab56da5e4d02e60f82cc6cf8740c3 -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,9 @@ unittest-style) will not be called if the corresponding setup method failed, see issue322 below. +- the pytest_plugin_unregister hook wasn't ever properly called + and there is no known implementation of the hook - so it got removed. + new features: - experimentally allow fixture functions to "yield" instead of "return" diff -r 1e3fe8b9de1ab56da5e4d02e60f82cc6cf8740c3 -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -114,7 +114,6 @@ if plugin is None: plugin = self.getplugin(name=name) self._plugins.remove(plugin) - self.hook.pytest_plugin_unregistered(plugin=plugin) for name, value in list(self._name2plugin.items()): if value == plugin: del self._name2plugin[name] diff -r 1e3fe8b9de1ab56da5e4d02e60f82cc6cf8740c3 -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 _pytest/hookspec.py --- a/_pytest/hookspec.py +++ b/_pytest/hookspec.py @@ -236,10 +236,7 @@ # ------------------------------------------------------------------------- def pytest_plugin_registered(plugin, manager): - """ a new py lib plugin got registered. """ - -def pytest_plugin_unregistered(plugin): - """ a py lib plugin got unregistered. """ + """ a new pytest plugin got registered. """ def pytest_internalerror(excrepr, excinfo): """ called for internal errors. """ https://bitbucket.org/hpk42/pytest/commits/64445644395f/ Changeset: 64445644395f User: hpk42 Date: 2013-09-28 22:23:00 Summary: introduce pluginmanager.ensure_teardown() which allows Affected #: 7 files diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -22,6 +22,13 @@ method = "sys" capman = CaptureManager(method) pluginmanager.register(capman, "capturemanager") + # make sure that capturemanager is properly reset at final shutdown + def teardown(): + try: + capman.reset_capturings() + except ValueError: + pass + pluginmanager.add_shutdown(teardown) def addouterr(rep, outerr): for secname, content in zip(["out", "err"], outerr): @@ -82,6 +89,7 @@ for name, cap in self._method2capture.items(): cap.reset() + def resumecapture_item(self, item): method = self._getmethod(item.config, item.fspath) if not hasattr(item, 'outerr'): diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 _pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -80,6 +80,7 @@ self._hints = [] self.trace = TagTracer().get("pluginmanage") self._plugin_distinfo = [] + self._shutdown = [] if os.environ.get('PYTEST_DEBUG'): err = sys.stderr encoding = getattr(err, 'encoding', 'utf8') @@ -118,6 +119,17 @@ if value == plugin: del self._name2plugin[name] + def add_shutdown(self, func): + self._shutdown.append(func) + + def ensure_shutdown(self): + while self._shutdown: + func = self._shutdown.pop() + func() + self._plugins = [] + self._name2plugin.clear() + self._listattrcache.clear() + def isregistered(self, plugin, name=None): if self.getplugin(name) is not None: return True @@ -286,7 +298,7 @@ config = self._config del self._config config.hook.pytest_unconfigure(config=config) - config.pluginmanager.unregister(self) + config.pluginmanager.ensure_shutdown() def notify_exception(self, excinfo, option=None): if option and option.fulltrace: diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -106,6 +106,7 @@ exitstatus=session.exitstatus) if initstate >= 1: config.pluginmanager.do_unconfigure(config) + config.pluginmanager.ensure_shutdown() return session.exitstatus def pytest_cmdline_main(config): diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 _pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -83,7 +83,8 @@ def finish_recording(self): for recorder in self._recorders.values(): - self._pluginmanager.unregister(recorder) + if self._pluginmanager.isregistered(recorder): + self._pluginmanager.unregister(recorder) self._recorders.clear() def _makecallparser(self, method): @@ -361,7 +362,7 @@ if not plugins: plugins = [] plugins.append(Collect()) - ret = self.pytestmain(list(args), plugins=plugins) + ret = pytest.main(list(args), plugins=plugins) reprec = rec[0] reprec.ret = ret assert len(rec) == 1 @@ -376,14 +377,15 @@ args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp')) import _pytest.core config = _pytest.core._prepareconfig(args, self.plugins) - # the in-process pytest invocation needs to avoid leaking FDs - # so we register a "reset_capturings" callmon the capturing manager - # and make sure it gets called - config._cleanup.append( - config.pluginmanager.getplugin("capturemanager").reset_capturings) - import _pytest.config - self.request.addfinalizer( - lambda: _pytest.config.pytest_unconfigure(config)) + # we don't know what the test will do with this half-setup config + # object and thus we make sure it gets unconfigured properly in any + # case (otherwise capturing could still be active, for example) + def ensure_unconfigure(): + if hasattr(config.pluginmanager, "_config"): + config.pluginmanager.do_unconfigure(config) + config.pluginmanager.ensure_shutdown() + + self.request.addfinalizer(ensure_unconfigure) return config def parseconfigure(self, *args): @@ -428,17 +430,6 @@ return py.std.subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw) - def pytestmain(self, *args, **kwargs): - class ResetCapturing: - @pytest.mark.trylast - def pytest_unconfigure(self, config): - capman = config.pluginmanager.getplugin("capturemanager") - capman.reset_capturings() - plugins = kwargs.setdefault("plugins", []) - rc = ResetCapturing() - plugins.append(rc) - return pytest.main(*args, **kwargs) - def run(self, *cmdargs): return self._run(*cmdargs) diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -391,15 +391,15 @@ def test_equivalence_pytest_pytest(self): assert pytest.main == py.test.cmdline.main - def test_invoke_with_string(self, testdir, capsys): - retcode = testdir.pytestmain("-h") + def test_invoke_with_string(self, capsys): + retcode = pytest.main("-h") assert not retcode out, err = capsys.readouterr() assert "--help" in out pytest.raises(ValueError, lambda: pytest.main(0)) - def test_invoke_with_path(self, testdir, capsys): - retcode = testdir.pytestmain(testdir.tmpdir) + def test_invoke_with_path(self, tmpdir, capsys): + retcode = pytest.main(tmpdir) assert not retcode out, err = capsys.readouterr() @@ -408,7 +408,7 @@ def pytest_addoption(self, parser): parser.addoption("--myopt") - testdir.pytestmain(["-h"], plugins=[MyPlugin()]) + pytest.main(["-h"], plugins=[MyPlugin()]) out, err = capsys.readouterr() assert "--myopt" in out diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 testing/test_collection.py --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -123,7 +123,7 @@ def pytest_collect_file(self, path, parent): wascalled.append(path) testdir.makefile(".abc", "xyz") - testdir.pytestmain([testdir.tmpdir], plugins=[Plugin()]) + pytest.main([testdir.tmpdir], plugins=[Plugin()]) assert len(wascalled) == 1 assert wascalled[0].ext == '.abc' @@ -134,7 +134,7 @@ wascalled.append(path.basename) testdir.mkdir("hello") testdir.mkdir("world") - testdir.pytestmain(testdir.tmpdir, plugins=[Plugin()]) + pytest.main(testdir.tmpdir, plugins=[Plugin()]) assert "hello" in wascalled assert "world" in wascalled diff -r 967c8ec78e6945a30090d98ffc607ba6935b3fc3 -r 64445644395fd57f600e0027d78692971ccd44d2 testing/test_doctest.py --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -4,7 +4,7 @@ import pdb xfail_if_pdbpp_installed = pytest.mark.xfail(hasattr(pdb, "__author__"), - reason="doctest/pdbpp problem: https://bitbucket.org/antocuni/pdb/issue/24/doctests-fail-when-pdbpp-is-installed") + reason="doctest/pdbpp problem: https://bitbucket.org/antocuni/pdb/issue/24/doctests-fail-when-pdbpp-is-installed", run=False) class TestDoctests: 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