Introduce Config.invocation_params (#5564)
Introduce Config.invocation_params
This commit is contained in:
commit
602cd5e21f
|
@ -0,0 +1 @@
|
||||||
|
New ``Config.invocation_args`` attribute containing the unchanged arguments passed to ``pytest.main()``.
|
|
@ -8,7 +8,9 @@ import sys
|
||||||
import types
|
import types
|
||||||
import warnings
|
import warnings
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import attr
|
||||||
import py
|
import py
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
from pluggy import HookimplMarker
|
from pluggy import HookimplMarker
|
||||||
|
@ -148,10 +150,15 @@ builtin_plugins = set(default_plugins)
|
||||||
builtin_plugins.add("pytester")
|
builtin_plugins.add("pytester")
|
||||||
|
|
||||||
|
|
||||||
def get_config(args=None):
|
def get_config(args=None, plugins=None):
|
||||||
# subsequent calls to main will create a fresh instance
|
# subsequent calls to main will create a fresh instance
|
||||||
pluginmanager = PytestPluginManager()
|
pluginmanager = PytestPluginManager()
|
||||||
config = Config(pluginmanager)
|
config = Config(
|
||||||
|
pluginmanager,
|
||||||
|
invocation_params=Config.InvocationParams(
|
||||||
|
args=args, plugins=plugins, dir=Path().resolve()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if args is not None:
|
if args is not None:
|
||||||
# Handle any "-p no:plugin" args.
|
# Handle any "-p no:plugin" args.
|
||||||
|
@ -184,7 +191,7 @@ def _prepareconfig(args=None, plugins=None):
|
||||||
msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})"
|
msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})"
|
||||||
raise TypeError(msg.format(args, type(args)))
|
raise TypeError(msg.format(args, type(args)))
|
||||||
|
|
||||||
config = get_config(args)
|
config = get_config(args, plugins)
|
||||||
pluginmanager = config.pluginmanager
|
pluginmanager = config.pluginmanager
|
||||||
try:
|
try:
|
||||||
if plugins:
|
if plugins:
|
||||||
|
@ -613,20 +620,57 @@ def _iter_rewritable_modules(package_files):
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
""" access to configuration values, pluginmanager and plugin hooks. """
|
"""
|
||||||
|
Access to configuration values, pluginmanager and plugin hooks.
|
||||||
|
|
||||||
def __init__(self, pluginmanager):
|
:ivar PytestPluginManager pluginmanager: the plugin manager handles plugin registration and hook invocation.
|
||||||
#: access to command line option as attributes.
|
|
||||||
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
|
:ivar argparse.Namespace option: access to command line option as attributes.
|
||||||
self.option = argparse.Namespace()
|
|
||||||
|
:ivar InvocationParams invocation_params:
|
||||||
|
|
||||||
|
Object containing the parameters regarding the ``pytest.main``
|
||||||
|
invocation.
|
||||||
|
|
||||||
|
Contains the followinig read-only attributes:
|
||||||
|
|
||||||
|
* ``args``: list of command-line arguments as passed to ``pytest.main()``.
|
||||||
|
* ``plugins``: list of extra plugins, might be None
|
||||||
|
* ``dir``: directory where ``pytest.main()`` was invoked from.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@attr.s(frozen=True)
|
||||||
|
class InvocationParams:
|
||||||
|
"""Holds parameters passed during ``pytest.main()``
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Currently the environment variable PYTEST_ADDOPTS is also handled by
|
||||||
|
pytest implicitly, not being part of the invocation.
|
||||||
|
|
||||||
|
Plugins accessing ``InvocationParams`` must be aware of that.
|
||||||
|
"""
|
||||||
|
|
||||||
|
args = attr.ib()
|
||||||
|
plugins = attr.ib()
|
||||||
|
dir = attr.ib()
|
||||||
|
|
||||||
|
def __init__(self, pluginmanager, *, invocation_params=None):
|
||||||
from .argparsing import Parser, FILE_OR_DIR
|
from .argparsing import Parser, FILE_OR_DIR
|
||||||
|
|
||||||
|
if invocation_params is None:
|
||||||
|
invocation_params = self.InvocationParams(
|
||||||
|
args=(), plugins=None, dir=Path().resolve()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.option = argparse.Namespace()
|
||||||
|
self.invocation_params = invocation_params
|
||||||
|
|
||||||
_a = FILE_OR_DIR
|
_a = FILE_OR_DIR
|
||||||
self._parser = Parser(
|
self._parser = Parser(
|
||||||
usage="%(prog)s [options] [{}] [{}] [...]".format(_a, _a),
|
usage="%(prog)s [options] [{}] [{}] [...]".format(_a, _a),
|
||||||
processopt=self._processopt,
|
processopt=self._processopt,
|
||||||
)
|
)
|
||||||
#: a pluginmanager instance
|
|
||||||
self.pluginmanager = pluginmanager
|
self.pluginmanager = pluginmanager
|
||||||
self.trace = self.pluginmanager.trace.root.get("config")
|
self.trace = self.pluginmanager.trace.root.get("config")
|
||||||
self.hook = self.pluginmanager.hook
|
self.hook = self.pluginmanager.hook
|
||||||
|
@ -636,9 +680,13 @@ class Config:
|
||||||
self._cleanup = []
|
self._cleanup = []
|
||||||
self.pluginmanager.register(self, "pytestconfig")
|
self.pluginmanager.register(self, "pytestconfig")
|
||||||
self._configured = False
|
self._configured = False
|
||||||
self.invocation_dir = py.path.local()
|
|
||||||
self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))
|
self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def invocation_dir(self):
|
||||||
|
"""Backward compatibility"""
|
||||||
|
return py.path.local(str(self.invocation_params.dir))
|
||||||
|
|
||||||
def add_cleanup(self, func):
|
def add_cleanup(self, func):
|
||||||
""" Add a function to be called when the config object gets out of
|
""" Add a function to be called when the config object gets out of
|
||||||
use (usually coninciding with pytest_unconfigure)."""
|
use (usually coninciding with pytest_unconfigure)."""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1199,6 +1200,29 @@ def test_config_does_not_load_blocked_plugin_from_args(testdir):
|
||||||
assert result.ret == ExitCode.USAGE_ERROR
|
assert result.ret == ExitCode.USAGE_ERROR
|
||||||
|
|
||||||
|
|
||||||
|
def test_invocation_args(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_params.args == [p, "-v"]
|
||||||
|
assert config.invocation_params.dir == Path(str(testdir.tmpdir))
|
||||||
|
|
||||||
|
plugins = config.invocation_params.plugins
|
||||||
|
assert len(plugins) == 2
|
||||||
|
assert plugins[0] is plugin
|
||||||
|
assert type(plugins[1]).__name__ == "Collect" # installed by testdir.inline_run()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"plugin",
|
"plugin",
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue