Merge pull request #6870 from fermezz/backport-invocation-args
This commit is contained in:
commit
ded772b288
1
AUTHORS
1
AUTHORS
|
@ -92,6 +92,7 @@ Evan Kepner
|
|||
Fabien Zarifian
|
||||
Fabio Zadrozny
|
||||
Feng Ma
|
||||
Fernando Mezzabotta Rey
|
||||
Florian Bruhin
|
||||
Floris Bruynooghe
|
||||
Gabriel Reis
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
New ``Config.invocation_args`` attribute containing the unchanged arguments passed to ``pytest.main()``.
|
|
@ -17,9 +17,9 @@ are available on PyPI.
|
|||
|
||||
While pytest ``5.0`` will be the new mainstream and development version, until **January 2020**
|
||||
the pytest core team plans to make bug-fix releases of the pytest ``4.6`` series by
|
||||
back-porting patches to the ``4.6-maintenance`` branch that affect Python 2 users.
|
||||
back-porting patches to the ``4.6.x`` branch that affect Python 2 users.
|
||||
|
||||
**After 2020**, the core team will no longer actively backport patches, but the ``4.6-maintenance``
|
||||
**After 2020**, the core team will no longer actively backport patches, but the ``4.6.x``
|
||||
branch will continue to exist so the community itself can contribute patches. The core team will
|
||||
be happy to accept those patches and make new ``4.6`` releases **until mid-2020**.
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import sys
|
|||
import types
|
||||
import warnings
|
||||
|
||||
import attr
|
||||
import py
|
||||
import six
|
||||
from packaging.version import Version
|
||||
|
@ -35,6 +36,7 @@ from _pytest.compat import lru_cache
|
|||
from _pytest.compat import safe_str
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.outcomes import Skipped
|
||||
from _pytest.pathlib import Path
|
||||
from _pytest.warning_types import PytestConfigWarning
|
||||
|
||||
hookimpl = HookimplMarker("pytest")
|
||||
|
@ -154,10 +156,15 @@ builtin_plugins = set(default_plugins)
|
|||
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
|
||||
pluginmanager = PytestPluginManager()
|
||||
config = Config(pluginmanager)
|
||||
config = Config(
|
||||
pluginmanager,
|
||||
invocation_params=Config.InvocationParams(
|
||||
args=args, plugins=plugins, dir=Path().resolve()
|
||||
),
|
||||
)
|
||||
|
||||
if args is not None:
|
||||
# Handle any "-p no:plugin" args.
|
||||
|
@ -190,7 +197,7 @@ def _prepareconfig(args=None, plugins=None):
|
|||
msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})"
|
||||
raise TypeError(msg.format(args, type(args)))
|
||||
|
||||
config = get_config(args)
|
||||
config = get_config(args, plugins)
|
||||
pluginmanager = config.pluginmanager
|
||||
try:
|
||||
if plugins:
|
||||
|
@ -686,13 +693,52 @@ def _iter_rewritable_modules(package_files):
|
|||
|
||||
|
||||
class Config(object):
|
||||
""" 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 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(object):
|
||||
"""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, *args):
|
||||
from .argparsing import Parser, FILE_OR_DIR
|
||||
|
||||
if invocation_params is None:
|
||||
invocation_params = self.InvocationParams(
|
||||
args=(), plugins=None, dir=Path().resolve()
|
||||
)
|
||||
|
||||
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.invocation_params = invocation_params
|
||||
|
||||
_a = FILE_OR_DIR
|
||||
self._parser = Parser(
|
||||
|
@ -709,9 +755,13 @@ class Config(object):
|
|||
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))
|
||||
|
||||
@property
|
||||
def invocation_dir(self):
|
||||
"""Backward compatibility"""
|
||||
return py.path.local(str(self.invocation_params.dir))
|
||||
|
||||
def add_cleanup(self, func):
|
||||
""" Add a function to be called when the config object gets out of
|
||||
use (usually coninciding with pytest_unconfigure)."""
|
||||
|
|
|
@ -19,6 +19,7 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED
|
|||
from _pytest.main import EXIT_OK
|
||||
from _pytest.main import EXIT_TESTSFAILED
|
||||
from _pytest.main import EXIT_USAGEERROR
|
||||
from _pytest.pathlib import Path
|
||||
|
||||
|
||||
class TestParseIni(object):
|
||||
|
@ -1222,6 +1223,29 @@ def test_config_does_not_load_blocked_plugin_from_args(testdir):
|
|||
assert result.ret == EXIT_USAGEERROR
|
||||
|
||||
|
||||
def test_invocation_args(testdir):
|
||||
"""Ensure that Config.invocation_* arguments are correctly defined"""
|
||||
|
||||
class DummyPlugin(object):
|
||||
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(
|
||||
"plugin",
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue