Merge remote-tracking branch 'upstream/master' into mm

Conflicts:
	src/_pytest/main.py
	src/_pytest/mark/structures.py
	src/_pytest/python.py
	testing/test_main.py
	testing/test_parseopt.py
This commit is contained in:
Bruno Oliveira 2020-02-11 10:32:18 -03:00 committed by Bruno Oliveira
commit 78baa7b575
31 changed files with 161 additions and 138 deletions

View File

@ -7,6 +7,7 @@ Here is a quick checklist that should be present in PRs.
- [ ] Target the `features` branch for new features, improvements, and removals/deprecations.
- [ ] Include documentation when adding new features.
- [ ] Include new tests or update existing tests when applicable.
- [X] Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:

View File

@ -1,6 +1,6 @@
language: python
dist: xenial
python: '3.7'
dist: trusty
python: '3.5.1'
cache: false
env:
@ -16,36 +16,11 @@ install:
jobs:
include:
# OSX tests - first (in test stage), since they are the slower ones.
# Coverage for:
# - osx
# - verbose=1
- os: osx
osx_image: xcode10.1
language: generic
env: TOXENV=py37-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=-v
before_install:
- which python3
- python3 -V
- ln -sfn "$(which python3)" /usr/local/bin/python
- python -V
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
# Full run of latest supported version, without xdist.
# Coverage for:
# - pytester's LsofFdLeakChecker
# - TestArgComplete (linux only)
# - numpy
# - old attrs
# - verbose=0
# - test_sys_breakpoint_interception (via pexpect).
- env: TOXENV=py37-lsof-numpy-oldattrs-pexpect-twisted PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
python: '3.7'
# Coverage for Python 3.5.{0,1} specific code, mostly typing related.
- env: TOXENV=py35 PYTEST_COVERAGE=1 PYTEST_ADDOPTS="-k test_raises_cyclic_reference"
python: '3.5.1'
dist: trusty
before_install:
# Work around https://github.com/jaraco/zipp/issues/40.
- python -m pip install -U pip 'setuptools>=34.4.0' virtualenv
before_script:
- |

View File

@ -0,0 +1 @@
Assertion rewriting hooks are (re)stored for the current item, which fixes them being still used after e.g. pytester's :func:`testdir.runpytest <_pytest.pytester.Testdir.runpytest>` etc.

View File

@ -0,0 +1 @@
:func:`pytest.exit() <_pytest.outcomes.exit>` is handled when emitted from the :func:`pytest_sessionfinish <_pytest.hookspec.pytest_sessionfinish>` hook. This includes quitting from a debugger.

View File

@ -162,7 +162,7 @@ html_logo = "img/pytest1.png"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = "img/pytest1favi.ico"
html_favicon = "img/favicon.png"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,

BIN
doc/en/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -901,8 +901,8 @@ Can be either a ``str`` or ``Sequence[str]``.
pytest_plugins = ("myapp.testsupport.tools", "myapp.testsupport.regression")
pytest_mark
~~~~~~~~~~~
pytestmark
~~~~~~~~~~
**Tutorial**: :ref:`scoped-marking`

View File

@ -72,6 +72,8 @@ class Code:
""" return a path object pointing to source code (or a str in case
of OSError / non-existing file).
"""
if not self.raw.co_filename:
return ""
try:
p = py.path.local(self.raw.co_filename)
# maybe don't try this checking

View File

@ -8,6 +8,7 @@ import warnings
from bisect import bisect_right
from types import CodeType
from types import FrameType
from typing import Any
from typing import Iterator
from typing import List
from typing import Optional
@ -17,6 +18,7 @@ from typing import Union
import py
from _pytest.compat import get_real_func
from _pytest.compat import overload
from _pytest.compat import TYPE_CHECKING
@ -277,7 +279,7 @@ def compile_( # noqa: F811
return s.compile(filename, mode, flags, _genframe=_genframe)
def getfslineno(obj) -> Tuple[Optional[Union["Literal['']", py.path.local]], int]:
def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]:
""" Return source location (path, lineno) for the given object.
If the source cannot be determined return ("", -1).
@ -285,6 +287,13 @@ def getfslineno(obj) -> Tuple[Optional[Union["Literal['']", py.path.local]], int
"""
from .code import Code
# xxx let decorators etc specify a sane ordering
# NOTE: this used to be done in _pytest.compat.getfslineno, initially added
# in 6ec13a2b9. It ("place_as") appears to be something very custom.
obj = get_real_func(obj)
if hasattr(obj, "place_as"):
obj = obj.place_as
try:
code = Code(obj)
except TypeError:
@ -293,18 +302,16 @@ def getfslineno(obj) -> Tuple[Optional[Union["Literal['']", py.path.local]], int
except TypeError:
return "", -1
fspath = fn and py.path.local(fn) or None
fspath = fn and py.path.local(fn) or ""
lineno = -1
if fspath:
try:
_, lineno = findsource(obj)
except IOError:
pass
return fspath, lineno
else:
fspath = code.path
lineno = code.firstlineno
assert isinstance(lineno, int)
return fspath, lineno
return code.path, code.firstlineno
#

View File

@ -8,6 +8,7 @@ from _pytest.assertion import rewrite
from _pytest.assertion import truncate
from _pytest.assertion import util
from _pytest.compat import TYPE_CHECKING
from _pytest.config import hookimpl
if TYPE_CHECKING:
from _pytest.main import Session
@ -105,7 +106,8 @@ def pytest_collection(session: "Session") -> None:
assertstate.hook.set_session(session)
def pytest_runtest_setup(item):
@hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_protocol(item):
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks
The newinterpret and rewrite modules will use util._reprcompare if
@ -143,6 +145,7 @@ def pytest_runtest_setup(item):
return res
return None
saved_assert_hooks = util._reprcompare, util._assertion_pass
util._reprcompare = callbinrepr
if item.ihook.pytest_assertion_pass.get_hookimpls():
@ -154,10 +157,9 @@ def pytest_runtest_setup(item):
util._assertion_pass = call_assertion_pass_hook
yield
def pytest_runtest_teardown(item):
util._reprcompare = None
util._assertion_pass = None
util._reprcompare, util._assertion_pass = saved_assert_hooks
def pytest_sessionfinish(session):

View File

@ -23,7 +23,6 @@ from typing import Union
import attr
import py
import _pytest
from _pytest._io.saferepr import saferepr
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
@ -308,16 +307,6 @@ def get_real_method(obj, holder):
return obj
def getfslineno(obj) -> Tuple[Union[str, py.path.local], int]:
# xxx let decorators etc specify a sane ordering
obj = get_real_func(obj)
if hasattr(obj, "place_as"):
obj = obj.place_as
fslineno = _pytest._code.getfslineno(obj)
assert isinstance(fslineno[1], int), obj
return fslineno
def getimfunc(func):
try:
return func.__func__

View File

@ -28,7 +28,6 @@ from pluggy import HookspecMarker
from pluggy import PluginManager
import _pytest._code
import _pytest.assertion
import _pytest.deprecated
import _pytest.hookspec # the extension point definitions
from .exceptions import PrintHelp
@ -284,6 +283,8 @@ class PytestPluginManager(PluginManager):
"""
def __init__(self):
import _pytest.assertion
super().__init__("pytest")
# The objects are module objects, only used generically.
self._conftest_plugins = set() # type: Set[object]
@ -917,6 +918,8 @@ class Config:
ns, unknown_args = self._parser.parse_known_and_unknown_args(args)
mode = getattr(ns, "assertmode", "plain")
if mode == "rewrite":
import _pytest.assertion
try:
hook = _pytest.assertion.install_importhook(self)
except SystemError:

View File

@ -15,12 +15,12 @@ import py
import _pytest
from _pytest._code.code import FormattedExcinfo
from _pytest._code.code import TerminalRepr
from _pytest._code.source import getfslineno
from _pytest._io import TerminalWriter
from _pytest.compat import _format_args
from _pytest.compat import _PytestWrapper
from _pytest.compat import get_real_func
from _pytest.compat import get_real_method
from _pytest.compat import getfslineno
from _pytest.compat import getfuncargnames
from _pytest.compat import getimfunc
from _pytest.compat import getlocation

View File

@ -10,6 +10,7 @@ from typing import List
from typing import Mapping
import pytest
from _pytest import nodes
from _pytest.compat import nullcontext
from _pytest.config import _strtobool
from _pytest.config import create_terminal_writer
@ -326,13 +327,13 @@ class LogCaptureFixture:
logger.setLevel(level)
@property
def handler(self):
def handler(self) -> LogCaptureHandler:
"""
:rtype: LogCaptureHandler
"""
return self._item.catch_log_handler
return self._item.catch_log_handler # type: ignore[no-any-return] # noqa: F723
def get_records(self, when):
def get_records(self, when: str) -> List[logging.LogRecord]:
"""
Get the logging records for one of the possible test phases.
@ -346,7 +347,7 @@ class LogCaptureFixture:
"""
handler = self._item.catch_log_handlers.get(when)
if handler:
return handler.records
return handler.records # type: ignore[no-any-return] # noqa: F723
else:
return []
@ -619,7 +620,9 @@ class LoggingPlugin:
yield
@contextmanager
def _runtest_for_main(self, item, when):
def _runtest_for_main(
self, item: nodes.Item, when: str
) -> Generator[None, None, None]:
"""Implements the internals of pytest_runtest_xxx() hook."""
with catching_logs(
LogCaptureHandler(), formatter=self.formatter, level=self.log_level
@ -632,15 +635,15 @@ class LoggingPlugin:
return
if not hasattr(item, "catch_log_handlers"):
item.catch_log_handlers = {}
item.catch_log_handlers[when] = log_handler
item.catch_log_handler = log_handler
item.catch_log_handlers = {} # type: ignore[attr-defined] # noqa: F821
item.catch_log_handlers[when] = log_handler # type: ignore[attr-defined] # noqa: F821
item.catch_log_handler = log_handler # type: ignore[attr-defined] # noqa: F821
try:
yield # run test
finally:
if when == "teardown":
del item.catch_log_handler
del item.catch_log_handlers
del item.catch_log_handler # type: ignore[attr-defined] # noqa: F821
del item.catch_log_handlers # type: ignore[attr-defined] # noqa: F821
if self.print_logs:
# Add a captured log section to the report.

View File

@ -4,6 +4,7 @@ import functools
import importlib
import os
import sys
from typing import Callable
from typing import Dict
from typing import FrozenSet
from typing import List
@ -24,7 +25,7 @@ from _pytest.config import ExitCode
from _pytest.config import hookimpl
from _pytest.config import UsageError
from _pytest.fixtures import FixtureManager
from _pytest.outcomes import exit
from _pytest.outcomes import Exit
from _pytest.reports import CollectReport
from _pytest.runner import collect_one_node
from _pytest.runner import SetupState
@ -175,7 +176,9 @@ def pytest_addoption(parser):
)
def wrap_session(config, doit):
def wrap_session(
config: Config, doit: Callable[[Config, "Session"], Optional[Union[int, ExitCode]]]
) -> Union[int, ExitCode]:
"""Skeleton command line program"""
session = Session.from_config(config)
session.exitstatus = ExitCode.OK
@ -192,10 +195,10 @@ def wrap_session(config, doit):
raise
except Failed:
session.exitstatus = ExitCode.TESTS_FAILED
except (KeyboardInterrupt, exit.Exception):
except (KeyboardInterrupt, Exit):
excinfo = _pytest._code.ExceptionInfo.from_current()
exitstatus = ExitCode.INTERRUPTED
if isinstance(excinfo.value, exit.Exception):
exitstatus = ExitCode.INTERRUPTED # type: Union[int, ExitCode]
if isinstance(excinfo.value, Exit):
if excinfo.value.returncode is not None:
exitstatus = excinfo.value.returncode
if initstate < 2:
@ -209,7 +212,7 @@ def wrap_session(config, doit):
excinfo = _pytest._code.ExceptionInfo.from_current()
try:
config.notify_exception(excinfo, config.option)
except exit.Exception as exc:
except Exit as exc:
if exc.returncode is not None:
session.exitstatus = exc.returncode
sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc))
@ -218,12 +221,18 @@ def wrap_session(config, doit):
sys.stderr.write("mainloop: caught unexpected SystemExit!\n")
finally:
excinfo = None # Explicitly break reference cycle.
# Explicitly break reference cycle.
excinfo = None # type: ignore
session.startdir.chdir()
if initstate >= 2:
config.hook.pytest_sessionfinish(
session=session, exitstatus=session.exitstatus
)
try:
config.hook.pytest_sessionfinish(
session=session, exitstatus=session.exitstatus
)
except Exit as exc:
if exc.returncode is not None:
session.exitstatus = exc.returncode
sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc))
config._ensure_unconfigure()
return session.exitstatus
@ -363,6 +372,7 @@ class Session(nodes.FSCollector):
_setupstate = None # type: SetupState
# Set on the session by fixtures.pytest_sessionstart.
_fixturemanager = None # type: FixtureManager
exitstatus = None # type: Union[int, ExitCode]
def __init__(self, config: Config) -> None:
nodes.FSCollector.__init__(

View File

@ -2,14 +2,16 @@ import inspect
import warnings
from collections import namedtuple
from collections.abc import MutableMapping
from typing import Iterable
from typing import List
from typing import Optional
from typing import Set
from typing import Union
import attr
from .._code.source import getfslineno
from ..compat import ascii_escaped
from ..compat import getfslineno
from ..compat import NOTSET
from _pytest.outcomes import fail
from _pytest.warning_types import PytestUnknownMarkWarning
@ -270,7 +272,7 @@ def get_unpacked_marks(obj):
return normalize_mark_list(mark_list)
def normalize_mark_list(mark_list):
def normalize_mark_list(mark_list: Iterable[Union[Mark, MarkDecorator]]) -> List[Mark]:
"""
normalizes marker decorating helpers to mark objects

View File

@ -15,8 +15,8 @@ import _pytest._code
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprExceptionInfo
from _pytest._code.source import getfslineno
from _pytest.compat import cached_property
from _pytest.compat import getfslineno
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.config import PytestPluginManager
@ -361,7 +361,9 @@ class Node(metaclass=NodeMeta):
return self._repr_failure_py(excinfo, style)
def get_fslocation_from_item(item):
def get_fslocation_from_item(
item: "Item",
) -> Tuple[Union[str, py.path.local], Optional[int]]:
"""Tries to extract the actual location from an item, depending on available attributes:
* "fslocation": a pair (path, lineno)
@ -370,9 +372,10 @@ def get_fslocation_from_item(item):
:rtype: a tuple of (str|LocalPath, int) with filename and line number.
"""
result = getattr(item, "location", None)
if result is not None:
return result[:2]
try:
return item.location[:2]
except AttributeError:
pass
obj = getattr(item, "obj", None)
if obj is not None:
return getfslineno(obj)

View File

@ -610,14 +610,14 @@ class Testdir:
"""
self.tmpdir.chdir()
def _makefile(self, ext, args, kwargs, encoding="utf-8"):
items = list(kwargs.items())
def _makefile(self, ext, lines, files, encoding="utf-8"):
items = list(files.items())
def to_text(s):
return s.decode(encoding) if isinstance(s, bytes) else str(s)
if args:
source = "\n".join(to_text(x) for x in args)
if lines:
source = "\n".join(to_text(x) for x in lines)
basename = self.request.function.__name__
items.insert(0, (basename, source))

View File

@ -9,6 +9,7 @@ from collections import Counter
from collections import defaultdict
from collections.abc import Sequence
from functools import partial
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
@ -21,10 +22,10 @@ from _pytest import fixtures
from _pytest import nodes
from _pytest._code import filter_traceback
from _pytest._code.code import ExceptionInfo
from _pytest._code.source import getfslineno
from _pytest.compat import ascii_escaped
from _pytest.compat import get_default_arg_names
from _pytest.compat import get_real_func
from _pytest.compat import getfslineno
from _pytest.compat import getimfunc
from _pytest.compat import getlocation
from _pytest.compat import is_generator
@ -37,6 +38,7 @@ from _pytest.compat import STRING_TYPES
from _pytest.config import hookimpl
from _pytest.deprecated import FUNCARGNAMES
from _pytest.mark import MARK_GEN
from _pytest.mark import ParameterSet
from _pytest.mark.structures import get_unpacked_marks
from _pytest.mark.structures import Mark
from _pytest.mark.structures import normalize_mark_list
@ -392,7 +394,7 @@ class PyCollector(PyobjMixin, nodes.Collector):
fm = self.session._fixturemanager
definition = FunctionDefinition.from_parent(self, name=name, callobj=funcobj)
fixtureinfo = fm.getfixtureinfo(definition, funcobj, cls)
fixtureinfo = definition._fixtureinfo
metafunc = Metafunc(
definition, fixtureinfo, self.config, cls=cls, module=module
@ -931,7 +933,6 @@ class Metafunc:
to set a dynamic scope using test context or configuration.
"""
from _pytest.fixtures import scope2index
from _pytest.mark import ParameterSet
argnames, parameters = ParameterSet._for_parametrize(
argnames,
@ -992,7 +993,9 @@ class Metafunc:
newcalls.append(newcallspec)
self._calls = newcalls
def _resolve_arg_ids(self, argnames, ids, parameters, item):
def _resolve_arg_ids(
self, argnames: List[str], ids, parameters: List[ParameterSet], item: nodes.Item
):
"""Resolves the actual ids for the given argnames, based on the ``ids`` parameter given
to ``parametrize``.
@ -1045,7 +1048,7 @@ class Metafunc:
)
return new_ids
def _resolve_arg_value_types(self, argnames, indirect):
def _resolve_arg_value_types(self, argnames: List[str], indirect) -> Dict[str, str]:
"""Resolves if each parametrized argument must be considered a parameter to a fixture or a "funcarg"
to the function, based on the ``indirect`` parameter of the parametrized() call.

View File

@ -104,6 +104,8 @@ class TestGeneralUsage:
@pytest.mark.parametrize("load_cov_early", [True, False])
def test_early_load_setuptools_name(self, testdir, monkeypatch, load_cov_early):
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
testdir.makepyfile(mytestplugin1_module="")
testdir.makepyfile(mytestplugin2_module="")
testdir.makepyfile(mycov_module="")

View File

@ -524,6 +524,14 @@ def test_getfslineno() -> None:
B.__name__ = "B2"
assert getfslineno(B)[1] == -1
co = compile("...", "", "eval")
assert co.co_filename == ""
if hasattr(sys, "pypy_version_info"):
assert getfslineno(co) == ("", -1)
else:
assert getfslineno(co) == ("", 0)
def test_code_of_object_instance_with_call() -> None:
class A:

View File

@ -1,6 +1,7 @@
import sys
import pytest
from _pytest.pytester import Testdir
if sys.gettrace():
@ -118,3 +119,9 @@ def dummy_yaml_custom_test(testdir):
"""
)
testdir.makefile(".yaml", test1="")
@pytest.fixture
def testdir(testdir: Testdir) -> Testdir:
testdir.monkeypatch.setenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "1")
return testdir

View File

@ -72,10 +72,19 @@ class TestImportHookInstallation:
result = testdir.runpytest_subprocess()
result.stdout.fnmatch_lines(
[
"E * AssertionError: ([[][]], [[][]], [[]<TestReport *>[]])*",
"E * assert"
" {'failed': 1, 'passed': 0, 'skipped': 0} =="
" {'failed': 0, 'passed': 1, 'skipped': 0}",
"> r.assertoutcome(passed=1)",
"E AssertionError: ([[][]], [[][]], [[]<TestReport *>[]])*",
"E assert {'failed': 1,... 'skipped': 0} == {'failed': 0,... 'skipped': 0}",
"E Omitting 1 identical items, use -vv to show",
"E Differing items:",
"E Use -v to get the full diff",
]
)
# XXX: unstable output.
result.stdout.fnmatch_lines_random(
[
"E {'failed': 1} != {'failed': 0}",
"E {'passed': 0} != {'passed': 1}",
]
)

View File

@ -3,6 +3,7 @@ from _pytest.config import ExitCode
def test_version(testdir, pytestconfig):
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
result = testdir.runpytest("--version")
assert result.ret == 0
# p = py.path.local(py.__file__).dirpath()

View File

@ -1300,6 +1300,7 @@ def test_runs_twice(testdir, run_and_parse):
def test_runs_twice_xdist(testdir, run_and_parse):
pytest.importorskip("xdist")
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
f = testdir.makepyfile(
"""
def test_pass():

View File

@ -1,5 +1,8 @@
from typing import Optional
import pytest
from _pytest.config import ExitCode
from _pytest.pytester import Testdir
@pytest.mark.parametrize(
@ -50,3 +53,25 @@ def test_wrap_session_notify_exception(ret_exc, testdir):
assert result.stderr.lines == ["mainloop: caught unexpected SystemExit!"]
else:
assert result.stderr.lines == ["Exit: exiting after {}...".format(exc.__name__)]
@pytest.mark.parametrize("returncode", (None, 42))
def test_wrap_session_exit_sessionfinish(
returncode: Optional[int], testdir: Testdir
) -> None:
testdir.makeconftest(
"""
import pytest
def pytest_sessionfinish():
pytest.exit(msg="exit_pytest_sessionfinish", returncode={returncode})
""".format(
returncode=returncode
)
)
result = testdir.runpytest()
if returncode:
assert result.ret == returncode
else:
assert result.ret == ExitCode.NO_TESTS_COLLECTED
assert result.stdout.lines[-1] == "collected 0 items"
assert result.stderr.lines == ["Exit: exit_pytest_sessionfinish"]

View File

@ -1,3 +1,9 @@
"""
Test importing of all internal packages and modules.
This ensures all internal packages can be imported without needing the pytest
namespace being set, which is critical for the initialization of xdist.
"""
import pkgutil
import subprocess
import sys

View File

@ -1,40 +0,0 @@
import subprocess
import sys
import py
import _pytest
import pytest
pytestmark = pytest.mark.slow
MODSET = [
x
for x in py.path.local(_pytest.__file__).dirpath().visit("*.py")
if x.purebasename != "__init__"
]
@pytest.mark.parametrize("modfile", MODSET, ids=lambda x: x.purebasename)
def test_fileimport(modfile):
# this test ensures all internal packages can import
# without needing the pytest namespace being set
# this is critical for the initialization of xdist
p = subprocess.Popen(
[
sys.executable,
"-c",
"import sys, py; py.path.local(sys.argv[1]).pyimport()",
modfile.strpath,
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
(out, err) = p.communicate()
assert p.returncode == 0, "importing %s failed (exitcode %d): out=%r, err=%r" % (
modfile,
p.returncode,
out,
err,
)

View File

@ -1,7 +1,7 @@
import argparse
import distutils.spawn
import os
import shlex
import shutil
import sys
import py
@ -288,7 +288,7 @@ class TestParser:
def test_argcomplete(testdir, monkeypatch) -> None:
if not distutils.spawn.find_executable("bash"):
if not shutil.which("bash"):
pytest.skip("bash not available")
script = str(testdir.tmpdir.join("test_argcomplete"))

View File

@ -606,6 +606,7 @@ class TestTerminalFunctional:
assert result.ret == 0
def test_header_trailer_info(self, testdir, request):
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
testdir.makepyfile(
"""
def test_passes():
@ -736,6 +737,7 @@ class TestTerminalFunctional:
if not pytestconfig.pluginmanager.get_plugin("xdist"):
pytest.skip("xdist plugin not installed")
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
result = testdir.runpytest(
verbose_testfile, "-v", "-n 1", "-Walways::pytest.PytestWarning"
)