From 3e669a262a880acdc8a69cad0761e4f1925abe21 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 5 Jul 2019 19:38:16 -0300 Subject: [PATCH] Introduce Config.invocation_args and Config.invocation_plugins These attributes can be used to access the unchanged arguments passed to pytest.main(). The intention is to use these attributes to initialize workers in the same manner as the master node is initialized in pytest-xdist. --- changelog/5564.feature.rst | 3 +++ src/_pytest/config/__init__.py | 26 ++++++++++++++++++++------ testing/test_config.py | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 changelog/5564.feature.rst diff --git a/changelog/5564.feature.rst b/changelog/5564.feature.rst new file mode 100644 index 000000000..afc9f3323 --- /dev/null +++ b/changelog/5564.feature.rst @@ -0,0 +1,3 @@ +New ``Config.invocation_args`` and ``Config.invocation_plugins`` attributes. + +These attributes can be used by plugins to access the unchanged arguments passed to ``pytest.main()``. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index c9310bcb5..688a126d4 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -70,6 +70,8 @@ def main(args=None, plugins=None): tw.line(line.rstrip(), red=True) return 4 else: + config.invocation_args = args + config.invocation_plugins = plugins try: return config.hook.pytest_cmdline_main(config=config) finally: @@ -608,20 +610,33 @@ def _iter_rewritable_modules(package_files): class Config: - """ access to configuration values, pluginmanager and plugin hooks. """ + """ + Access to configuration values, pluginmanager and plugin hooks. + + :ivar PytestPluginManager pluginmanager: the plugin manager handles plugin registration and hook invocation. + + :ivar argparse.Namespace option: access to command line option as attributes. + + :ivar invocation_args: list of command-line arguments as passed to pytest.main() + + :ivar invocation_plugins: list of extra plugins passed to pytest.main(), might be None + + :ivar py.path.local invocation_dir: directory where pytest.main() was invoked from + """ def __init__(self, pluginmanager): - #: access to command line option as attributes. - #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead - self.option = argparse.Namespace() from .argparsing import Parser, FILE_OR_DIR + self.option = argparse.Namespace() + self.invocation_args = None + self.invocation_plugins = None + self.invocation_dir = py.path.local() + _a = FILE_OR_DIR self._parser = Parser( usage="%(prog)s [options] [{}] [{}] [...]".format(_a, _a), processopt=self._processopt, ) - #: a pluginmanager instance self.pluginmanager = pluginmanager self.trace = self.pluginmanager.trace.root.get("config") self.hook = self.pluginmanager.hook @@ -631,7 +646,6 @@ class Config: self._cleanup = [] self.pluginmanager.register(self, "pytestconfig") self._configured = False - self.invocation_dir = py.path.local() self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) def add_cleanup(self, func): diff --git a/testing/test_config.py b/testing/test_config.py index eb7f95271..7ec3c9087 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1198,6 +1198,28 @@ def test_config_does_not_load_blocked_plugin_from_args(testdir): assert result.ret == ExitCode.USAGE_ERROR +def test_invocation_arguments(testdir): + """Ensure that Config.invocation_* arguments are correctly defined""" + + class DummyPlugin: + pass + + p = testdir.makepyfile("def test(): pass") + plugin = DummyPlugin() + rec = testdir.inline_run(p, "-v", plugins=[plugin]) + calls = rec.getcalls("pytest_runtest_protocol") + assert len(calls) == 1 + call = calls[0] + config = call.item.config + + assert config.invocation_args == [p, "-v"] + + plugins = config.invocation_plugins + assert len(plugins) == 2 + assert plugins[0] is plugin + assert type(plugins[1]).__name__ == "Collect" # installed by testdir.inline_run() + + @pytest.mark.parametrize( "plugin", [