Question: Show deprecation warning if junitfamily is not set Show a deprecation warning if the user has not configured ()

default="total",     )  # choices=['total', 'call'])     parser.addini(        "junit_family",        "Emit XML for schema: one of legacy|xunit1|xunit2",        default="xunit1",        "junit_family", "Emit XML for schema: one of legacy|xunit1|xunit2", default=None     )


Question: Show deprecation warning if junitfamily is not set Show a deprecation warning if the user has not configured ()

xmlpath = config.option.xmlpath     # prevent opening xmllog on slave nodes (xdist)     if xmlpath and not hasattr(config, "slaveinput"):        junit_family = config.getini("junit_family")        if not junit_family:            _issue_warning_captured(deprecated.JUNIT_XML_DEFAULT_FAMILY, config.hook, 2)            junit_family = "xunit1"         config._xml = LogXML(             xmlpath,             config.option.junitprefix,             config.getini("junit_suite_name"),             config.getini("junit_logging"),             config.getini("junit_duration_report"),            config.getini("junit_family"),            junit_family,             config.getini("junit_log_passing_tests"),         )         config.pluginmanager.register(config._xml)


Question: Regression in 5.2.3: pytest tries to collect random files This was caught by our build server this morning. It seems that pytest 5.2.3 tries to import any file under the current directory. (We have some package that is only used on windows and cannot be imported on linux.) Here is a minimal example using tox that reproduces the problem (I'm running on Debian 10 with Python 3.7.3):

@property     def obj(self):         """Underlying Python object."""        self._mount_obj_if_needed()        return self._obj    @obj.setter    def obj(self, value):        self._obj = value    def _mount_obj_if_needed(self):         obj = getattr(self, "_obj", None)         if obj is None:             self._obj = obj = self._getobj()             # XXX evil hack             # used to avoid Instance collector marker duplication             if self._ALLOW_MARKERS:                self.own_markers.extend(get_unpacked_marks(obj))                self.own_markers.extend(get_unpacked_marks(self.obj))        return obj    @obj.setter    def obj(self, value):        self._obj = value      def _getobj(self):         """Gets the underlying Python object. May be overwritten by subclasses."""


Question: Regression in 5.2.3: pytest tries to collect random files This was caught by our build server this morning. It seems that pytest 5.2.3 tries to import any file under the current directory. (We have some package that is only used on windows and cannot be imported on linux.) Here is a minimal example using tox that reproduces the problem (I'm running on Debian 10 with Python 3.7.3):

class Module(nodes.File, PyCollector):     """ Collector for test classes and functions. """ <del>    def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):        if fspath.basename == "__init__.py":            self._ALLOW_MARKERS = False        nodes.FSCollector.__init__(            self, fspath, parent=parent, config=config, session=session, nodeid=nodeid        )</del>     def _getobj(self):         return self._importtestmodule()


Question: Regression in 5.2.3: pytest tries to collect random files This was caught by our build server this morning. It seems that pytest 5.2.3 tries to import any file under the current directory. (We have some package that is only used on windows and cannot be imported on linux.) Here is a minimal example using tox that reproduces the problem (I'm running on Debian 10 with Python 3.7.3):

return path in self.session._initialpaths      def collect(self):<del>        self._mount_obj_if_needed()</del>         this_path = self.fspath.dirpath()         init_module = this_path.join("__init__.py")         if init_module.check(file=1) and path_matches_patterns(


Question: '.[' replaced with '[' in the headline shown of the test report The replaced with in the headline shown with long report output. The same problem also causing the vscode-python test discovery error. I trace back the source code. The headline comes from line 148. comes from line 437 The headline comes from line 306 This line of code causes the problem. We should replace it with . After changing this, run , pass all the tests and resolve this issue. But I can't find this line of code for what purpose.

break             parts.append(name)         parts.reverse()        s = ".".join(parts)        return s.replace(".[", "[")        return ".".join(parts)      def reportinfo(self):         # XXX caching?


Question: --setup-plan and --setup-only seem to claim different things I have the following example: When running with , I get the following output (indicating extra teardown of fixture1 and 2): When running with , the SETUP and TEARDOWN markers occur where my actual setup and teardown code executes: --setup-plan and --setup-only seem to claim different things I have the following example: When running with , I get the following output (indicating extra teardown of fixture1 and 2): When running with , the SETUP and TEARDOWN markers occur where my actual setup and teardown code executes:

def pytest_fixture_setup(fixturedef, request):     # Will return a dummy fixture if the setuponly option is provided.     if request.config.option.setupplan:        fixturedef.cached_result = (None, None, None)        my_cache_key = fixturedef.cache_key(request)        fixturedef.cached_result = (None, my_cache_key, None)         return fixturedef.cached_result


Question: Calls to () in skipif causes all logging calls to be duplicated to stderr Using pytest 5.2.2 / 5.3.0, when a function called from a uses a logging function, the captured log calls are duplicated to stderr. Minimal working example: Results in the following. Notice "Schmift" is printed both to "Captured stderr call" and "Captured log call". Removing the logging call from results in the expected behaviour, "Schmift" is not duplicated to stderr:

with catching_logs(self.log_file_handler, level=self.log_file_level):                     yield             else:                yield                # Add a dummy handler to ensure logging.root.handlers is not empty.                # If it were empty, then a `logging.warning()` call (and similar) during collection                # would trigger a `logging.basicConfig()` call, which would add a `StreamHandler`                # handler, which would cause all subsequent logs which reach the root to be also                # printed to stdout, which we don't want (issue #6240).                with catching_logs(logging.NullHandler()):                    yield      @contextmanager     def _runtest_for(self, item, when):


Question: disallow absolute and non-normalized paths for mktemp followup to this is an potential issue and attack vector, absolute paths are no tmpdir and escaping paths aren't either, just normalizing would also break the world so we should only ever accept normalized relative paths for it

given_basetemp=config.option.basetemp, trace=config.trace.get("tmpdir")         )     def _ensure_relative_to_basetemp(self, basename: str):        basename = os.path.normpath(basename)        if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp():            raise ValueError(                "{} is not a normalized and relative path".format(basename)            )        return basename     def mktemp(self, basename: str, numbered: bool = True) -> Path:        """makes a temporary directory managed by the factory"""        """Creates a new temporary directory managed by the factory.        :param basename:            Directory base name, must be a relative path.        :param numbered:            If True, ensure the directory is unique by adding a number            prefix greater than any existing one: ``basename="foo"`` and ``numbered=True``            means that this function will create directories named ``"foo-0"``,            ``"foo-1"``, ``"foo-2"`` and so on.        :return:            The path to the new directory.        """        basename = self._ensure_relative_to_basetemp(basename)         if not numbered:             p = self.getbasetemp().joinpath(basename)             p.mkdir()


Question: disallow absolute and non-normalized paths for mktemp followup to this is an potential issue and attack vector, absolute paths are no tmpdir and escaping paths aren't either, just normalizing would also break the world so we should only ever accept normalized relative paths for it

_tmppath_factory = attr.ib(type=TempPathFactory)     def mktemp(self, basename: str, numbered: bool = True):        """Create a subdirectory of the base temporary directory and return it.        If ``numbered``, ensure the directory is unique by adding a number        prefix greater than any existing one.    def mktemp(self, basename: str, numbered: bool = True) -> py.path.local:        """        Same as :meth:`TempPathFactory.mkdir`, but returns a ``py.path.local`` object.         """         return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve())


Question: Module re-write doesn't work with non dist-info based installations More context behind this issue is available at: TL;DR: The function doesn't detect modules that can be rewritten, if they are installed by a method which doesn't adopt the dist-info format. An easy way to reproduce the problem is to: in one environment and in another and compare the output for: Because of this problem, rpm maintainers are unable to run the tests for pytest-mock, since they rely on which creates egg-info directories.

def _iter_rewritable_modules(package_files):    """    Given an iterable of file names in a source distribution, return the "names" that should    be marked for assertion rewrite (for example the package "pytest_mock/__init__.py" should    be added as "pytest_mock" in the assertion rewrite mechanism.    This function has to deal with dist-info based distributions and egg based distributions    (which are still very much in use for "editable" installs).    Here are the file names as seen in a dist-info based distribution:        pytest_mock/__init__.py        pytest_mock/_version.py        pytest_mock/plugin.py        pytest_mock.egg-info/PKG-INFO    Here are the file names as seen in an egg based distribution:        src/pytest_mock/__init__.py        src/pytest_mock/_version.py        src/pytest_mock/plugin.py        src/pytest_mock.egg-info/PKG-INFO        LICENSE        setup.py    We have to take in account those two distribution flavors in order to determine which    names should be considered for assertion rewriting.    More information:        https://github.com/pytest-dev/pytest-mock/issues/167    """    package_files = list(package_files)    seen_some = False     for fn in package_files:         is_simple_module = "/" not in fn and fn.endswith(".py")         is_package = fn.count("/") == 1 and fn.endswith("__init__.py")         if is_simple_module:             module_name, _ = os.path.splitext(fn)            yield module_name            # we ignore "setup.py" at the root of the distribution            if module_name != "setup":                seen_some = True                yield module_name         elif is_package:             package_name = os.path.dirname(fn)            seen_some = True             yield package_name     if not seen_some:        # at this point we did not find any packages or modules suitable for assertion        # rewriting, so we try again by stripping the first path component (to account for        # "src" based source trees for example)        # this approach lets us have the common case continue to be fast, as egg-distributions        # are rarer        new_package_files = []        for fn in package_files:            parts = fn.split("/")            new_fn = "/".join(parts[1:])            if new_fn:                new_package_files.append(new_fn)        if new_package_files:            for _module in _iter_rewritable_modules(new_package_files):                yield _module  class Config(object):     """ access to configuration values, pluginmanager and plugin hooks.  """


Question: Improve deprecation docs for Node.fromparent In the "Node Construction changed to Node.fromparent" section in the deprecation docs, we definitely need to add: [x] An example of the warning that users will see (so they can find the session on google). [x] The warning should point to the deprecation docs. [x] Show a "before -after" example. [x] ensure fromparent will not support config/session

NODE_USE_FROM_PARENT = UnformattedWarning(     PytestDeprecationWarning,    "direct construction of {name} has been deprecated, please use {name}.from_parent",    "Direct construction of {name} has been deprecated, please use {name}.from_parent.\n"    "See "    "https://docs.pytest.org/en/latest/deprecations.html#node-construction-changed-to-node-from-parent"    " for more details.", )  JUNIT_XML_DEFAULT_FAMILY = PytestDeprecationWarning(


Question: Expressions match against folder structure above pytest root Say I have a test file If I want to match only , this works as expected However if I want to execute only using similar means: both tests are collected because is in the parent path even though it might not have anything to do with the test environment. Is this expected behaviour?

import pytest          for item in item.listchain():            if not isinstance(item, pytest.Instance):            if not isinstance(item, (pytest.Instance, pytest.Session)):                 mapped_names.add(item.name)          # Add the names added as extra keywords to current or parent itemsdiff --git a/src/_pytest/python.py b/src/_pytest/python.py-- a/src/_pytest/python.py++ b/src/_pytest/python.py


Question: Expressions match against folder structure above pytest root Say I have a test file If I want to match only , this works as expected However if I want to execute only using similar means: both tests are collected because is in the parent path even though it might not have anything to do with the test environment. Is this expected behaviour?

nodes.FSCollector.__init__(             self, fspath, parent=parent, config=config, session=session, nodeid=nodeid         )        self.name = fspath.dirname        self.name = os.path.basename(str(fspath.dirname))      def setup(self):         # not using fixtures to call setup_module here because autouse fixtures


Question: -k mishandles numbers Using . It seems that pytest cannot handle keyword selection with numbers, like . Considering the following tests: Selecting with works: But selecting with doesn't, as I get all tests: If I make it a string though, using , then it works again: I see there are some notes about selecting based on keywords here but it was not clear if it applied to this case: So, is this a bug? Thanks!

r"""Evaluate match expressions, as used by `-k` and `-m`.The grammar is:expression: expr? EOFexpr:       and_expr ('or' and_expr)*and_expr:   not_expr ('and' not_expr)*not_expr:   'not' not_expr | '(' expr ')' | identident:      (\w|:|\+|-|\.|\[|\])+The semantics are:- Empty expression evaluates to False.- ident evaluates to True of False according to a provided matcher function.- or/and/not evaluate according to the usual boolean semantics."""import enumimport refrom typing import Callablefrom typing import Iteratorfrom typing import Optionalfrom typing import Sequenceimport attrfrom _pytest.compat import TYPE_CHECKINGif TYPE_CHECKING:    from typing import NoReturn__all__ = [    "evaluate",    "ParseError",]class TokenType(enum.Enum):    LPAREN = "left parenthesis"    RPAREN = "right parenthesis"    OR = "or"    AND = "and"    NOT = "not"    IDENT = "identifier"    EOF = "end of input"@attr.s(frozen=True, slots=True)class Token:    type = attr.ib(type=TokenType)    value = attr.ib(type=str)    pos = attr.ib(type=int)class ParseError(Exception):    """The expression contains invalid syntax.    :param column: The column in the line where the error occurred (1-based).    :param message: A description of the error.    """    def __init__(self, column: int, message: str) -> None:        self.column = column        self.message = message    def __str__(self) -> str:        return "at column {}: {}".format(self.column, self.message)class Scanner:    __slots__ = ("tokens", "current")    def __init__(self, input: str) -> None:        self.tokens = self.lex(input)        self.current = next(self.tokens)    def lex(self, input: str) -> Iterator[Token]:        pos = 0        while pos < len(input):            if input[pos] in (" ", "\t"):                pos += 1            elif input[pos] == "(":                yield Token(TokenType.LPAREN, "(", pos)                pos += 1            elif input[pos] == ")":                yield Token(TokenType.RPAREN, ")", pos)                pos += 1            else:                match = re.match(r"(:?\w|:|\+|-|\.|\[|\])+", input[pos:])                if match:                    value = match.group(0)                    if value == "or":                        yield Token(TokenType.OR, value, pos)                    elif value == "and":                        yield Token(TokenType.AND, value, pos)                    elif value == "not":                        yield Token(TokenType.NOT, value, pos)                    else:                        yield Token(TokenType.IDENT, value, pos)                    pos += len(value)                else:                    raise ParseError(                        pos + 1, 'unexpected character "{}"'.format(input[pos]),                    )        yield Token(TokenType.EOF, "", pos)    def accept(self, type: TokenType, *, reject: bool = False) -> Optional[Token]:        if self.current.type is type:            token = self.current            if token.type is not TokenType.EOF:                self.current = next(self.tokens)            return token        if reject:            self.reject((type,))        return None    def reject(self, expected: Sequence[TokenType]) -> "NoReturn":        raise ParseError(            self.current.pos + 1,            "expected {}; got {}".format(                " OR ".join(type.value for type in expected), self.current.type.value,            ),        )def expression(s: Scanner, matcher: Callable[[str], bool]) -> bool:    if s.accept(TokenType.EOF):        return False    ret = expr(s, matcher)    s.accept(TokenType.EOF, reject=True)    return retdef expr(s: Scanner, matcher: Callable[[str], bool]) -> bool:    ret = and_expr(s, matcher)    while s.accept(TokenType.OR):        rhs = and_expr(s, matcher)        ret = ret or rhs    return retdef and_expr(s: Scanner, matcher: Callable[[str], bool]) -> bool:    ret = not_expr(s, matcher)    while s.accept(TokenType.AND):        rhs = not_expr(s, matcher)        ret = ret and rhs    return retdef not_expr(s: Scanner, matcher: Callable[[str], bool]) -> bool:    if s.accept(TokenType.NOT):        return not not_expr(s, matcher)    if s.accept(TokenType.LPAREN):        ret = expr(s, matcher)        s.accept(TokenType.RPAREN, reject=True)        return ret    ident = s.accept(TokenType.IDENT)    if ident:        return matcher(ident.value)    s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))def evaluate(input: str, matcher: Callable[[str], bool]) -> bool:    """Evaluate a match expression as used by -k and -m.    :param input: The input expression - one line.    :param matcher: Given an identifier, should return whether it matches or not.                    Should be prepared to handle arbitrary strings as input.    Returns whether the entire expression matches or not.    """    return expression(Scanner(input), matcher)diff --git a/src/_pytest/mark/legacy.py b/src/_pytest/mark/legacy.py-- a/src/_pytest/mark/legacy.py++ b/src/_pytest/mark/legacy.py


Question: -k mishandles numbers Using . It seems that pytest cannot handle keyword selection with numbers, like . Considering the following tests: Selecting with works: But selecting with doesn't, as I get all tests: If I make it a string though, using , then it works again: I see there are some notes about selecting based on keywords here but it was not clear if it applied to this case: So, is this a bug? Thanks!

this is a place where we put datastructures used by legacy apis we hope to remove """import keyword from typing import Set  import attr  from _pytest.compat import TYPE_CHECKING from _pytest.config import UsageErrorfrom _pytest.mark.expression import evaluatefrom _pytest.mark.expression import ParseError  if TYPE_CHECKING:     from _pytest.nodes import Item  # noqa: F401 (used in type string)   @attr.sclass MarkMapping:    """Provides a local mapping for markers where item access    resolves to True if the marker is present. """class MarkMatcher:    """A matcher for markers which are present."""      own_mark_names = attr.ib()      @classmethod    def from_item(cls, item):    def from_item(cls, item) -> "MarkMatcher":         mark_names = {mark.name for mark in item.iter_markers()}         return cls(mark_names)     def __getitem__(self, name):    def __call__(self, name: str) -> bool:         return name in self.own_mark_names   @attr.sclass KeywordMapping:    """Provides a local mapping for keywords.    Given a list of names, map any substring of one of these names to True.class KeywordMatcher:    """A matcher for keywords.    Given a list of names, matches any substring of one of these names. The    string inclusion check is case-insensitive.     """      _names = attr.ib(type=Set[str])      @classmethod    def from_item(cls, item: "Item") -> "KeywordMapping":    def from_item(cls, item: "Item") -> "KeywordMatcher":         mapped_names = set()          # Add the names of the current item and any parent items


Question: -k mishandles numbers Using . It seems that pytest cannot handle keyword selection with numbers, like . Considering the following tests: Selecting with works: But selecting with doesn't, as I get all tests: If I make it a string though, using , then it works again: I see there are some notes about selecting based on keywords here but it was not clear if it applied to this case: So, is this a bug? Thanks!

return cls(mapped_names)     def __getitem__(self, subname: str) -> bool:        """Return whether subname is included within stored names.        The string inclusion check is case-insensitive.        """    def __call__(self, subname: str) -> bool:         subname = subname.lower()         names = (name.lower() for name in self._names)


Question: -k mishandles numbers Using . It seems that pytest cannot handle keyword selection with numbers, like . Considering the following tests: Selecting with works: But selecting with doesn't, as I get all tests: If I make it a string though, using , then it works again: I see there are some notes about selecting based on keywords here but it was not clear if it applied to this case: So, is this a bug? Thanks!

return False  python_keywords_allowed_list = ["or", "and", "not"]def matchmark(colitem, markexpr):def matchmark(colitem, markexpr: str) -> bool:     """Tries to match on any marker names, attached to the given colitem."""     try:        return eval(markexpr, {}, MarkMapping.from_item(colitem))    except Exception:        raise UsageError("Wrong expression passed to '-m': {}".format(markexpr))        return evaluate(markexpr, MarkMatcher.from_item(colitem))    except ParseError as e:        raise UsageError(            "Wrong expression passed to '-m': {}: {}".format(markexpr, e)        ) from None  def matchkeyword(colitem, keywordexpr):def matchkeyword(colitem, keywordexpr: str) -> bool:     """Tries to match given keyword expression to given collector item.      Will match on the name of colitem, including the names of its parents.


Question: -k mishandles numbers Using . It seems that pytest cannot handle keyword selection with numbers, like . Considering the following tests: Selecting with works: But selecting with doesn't, as I get all tests: If I make it a string though, using , then it works again: I see there are some notes about selecting based on keywords here but it was not clear if it applied to this case: So, is this a bug? Thanks!

Additionally, matches on names in the 'extra_keyword_matches' set of     any item, as well as names directly assigned to test functions.     """    mapping = KeywordMapping.from_item(colitem)    if " " not in keywordexpr:        # special case to allow for simple "-k pass" and "-k 1.3"        return mapping[keywordexpr]    elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]:        return not mapping[keywordexpr[4:]]    for kwd in keywordexpr.split():        if keyword.iskeyword(kwd) and kwd not in python_keywords_allowed_list:            raise UsageError(                "Python keyword '{}' not accepted in expressions passed to '-k'".format(                    kwd                )            )     try:        return eval(keywordexpr, {}, mapping)    except Exception:        raise UsageError("Wrong expression passed to '-k': {}".format(keywordexpr))        return evaluate(keywordexpr, KeywordMatcher.from_item(colitem))    except ParseError as e:        raise UsageError(            "Wrong expression passed to '-k': {}: {}".format(keywordexpr, e)        ) from None


Question: unittest.TestCase cleanup functions not invoked on test failure stdlib unittest style cleanup functions registered with are not invoked when a test fails. It appears this issue was introduced in pytest version 5.4.0, examples below for version 5.4.1. Ubuntu 18.04.3 LTS Python 3.6.8 pytest 5.4.1

class PdbTrace:     @hookimpl(hookwrapper=True)     def pytest_pyfunc_call(self, pyfuncitem):        _test_pytest_function(pyfuncitem)        wrap_pytest_function_for_tracing(pyfuncitem)         yield  def _test_pytest_function(pyfuncitem):def wrap_pytest_function_for_tracing(pyfuncitem):    """Changes the python function object of the given Function item by a wrapper which actually    enters pdb before calling the python function itself, effectively leaving the user    in the pdb prompt in the first statement of the function.    """     _pdb = pytestPDB._init_pdb("runcall")     testfunction = pyfuncitem.obj


Question: unittest.TestCase cleanup functions not invoked on test failure stdlib unittest style cleanup functions registered with are not invoked when a test fails. It appears this issue was introduced in pytest version 5.4.0, examples below for version 5.4.1. Ubuntu 18.04.3 LTS Python 3.6.8 pytest 5.4.1

pyfuncitem.obj = wrapper  def maybe_wrap_pytest_function_for_tracing(pyfuncitem):    """Wrap the given pytestfunct item for tracing support if --trace was given in    the command line"""    if pyfuncitem.config.getvalue("trace"):        wrap_pytest_function_for_tracing(pyfuncitem) def _enter_pdb(node, excinfo, rep):     # XXX we re-use the TerminalReporter's terminalwriter     # because this seems to avoid some encoding related troublesdiff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py-- a/src/_pytest/unittest.py++ b/src/_pytest/unittest.py


Question: unittest.TestCase cleanup functions not invoked on test failure stdlib unittest style cleanup functions registered with are not invoked when a test fails. It appears this issue was introduced in pytest version 5.4.0, examples below for version 5.4.1. Ubuntu 18.04.3 LTS Python 3.6.8 pytest 5.4.1

""" discovery and running of std-library "unittest" style tests. """<del>import functools</del> import sys import traceback


Question: unittest.TestCase cleanup functions not invoked on test failure stdlib unittest style cleanup functions registered with are not invoked when a test fails. It appears this issue was introduced in pytest version 5.4.0, examples below for version 5.4.1. Ubuntu 18.04.3 LTS Python 3.6.8 pytest 5.4.1

_testcase = None      def setup(self):        self._needs_explicit_tearDown = False        # a bound method to be called during teardown() if set (see 'runtest()')        self._explicit_tearDown = None         self._testcase = self.parent.obj(self.name)         self._obj = getattr(self._testcase, self.name)         if hasattr(self, "_request"):             self._request._fillfixtures()      def teardown(self):        if self._needs_explicit_tearDown:            self._testcase.tearDown()        if self._explicit_tearDown is not None:            self._explicit_tearDown()            self._explicit_tearDown = None         self._testcase = None         self._obj = None


Question: unittest.TestCase cleanup functions not invoked on test failure stdlib unittest style cleanup functions registered with are not invoked when a test fails. It appears this issue was introduced in pytest version 5.4.0, examples below for version 5.4.1. Ubuntu 18.04.3 LTS Python 3.6.8 pytest 5.4.1

return bool(expecting_failure_class or expecting_failure_method)      def runtest(self):        # TODO: move testcase reporter into separate class, this shouldnt be on item        import unittest        from _pytest.debugging import maybe_wrap_pytest_function_for_tracing         testMethod = getattr(self._testcase, self._testcase._testMethodName)        class _GetOutOf_testPartExecutor(KeyboardInterrupt):            """Helper exception to get out of unittests's testPartExecutor (see TestCase.run)."""        @functools.wraps(testMethod)        def wrapped_testMethod(*args, **kwargs):            """Wrap the original method to call into pytest's machinery, so other pytest            features can have a chance to kick in (notably --pdb)"""            try:                self.ihook.pytest_pyfunc_call(pyfuncitem=self)            except unittest.SkipTest:                raise            except Exception as exc:                expecting_failure = self._expecting_failure(testMethod)                if expecting_failure:                    raise                self._needs_explicit_tearDown = True                raise _GetOutOf_testPartExecutor(exc)        maybe_wrap_pytest_function_for_tracing(self)          # let the unittest framework handle async functions         if is_async_function(self.obj):             self._testcase(self)         else:            setattr(self._testcase, self._testcase._testMethodName, wrapped_testMethod)            # when --pdb is given, we want to postpone calling tearDown() otherwise            # when entering the pdb prompt, tearDown() would have probably cleaned up            # instance variables, which makes it difficult to debug            # arguably we could always postpone tearDown(), but this changes the moment where the            # TestCase instance interacts with the results object, so better to only do it            # when absolutely needed            if self.config.getoption("usepdb"):                self._explicit_tearDown = self._testcase.tearDown                setattr(self._testcase, "tearDown", lambda *args: None)            # we need to update the actual bound method with self.obj, because            # wrap_pytest_function_for_tracing replaces self.obj by a wrapper            setattr(self._testcase, self.name, self.obj)             try:                 self._testcase(result=self)            except _GetOutOf_testPartExecutor as exc:                raise exc.args[0] from exc.args[0]             finally:                delattr(self._testcase, self._testcase._testMethodName)                delattr(self._testcase, self.name)      def _prunetraceback(self, excinfo):         Function._prunetraceback(self, excinfo)


Question: Wrong relative path in skip report when tested file is upper than invocation directory The problem is if tested file is upper than invocation directory . It occurs in skip report. Example: path of tested file is: and is called in location: . Instead it should be.

# to point to the item definition, otherwise it will display         # the location of where the skip exception was raised within pytest         _, _, reason = rep.longrepr        filename, line = item.location[:2]        rep.longrepr = filename, line + 1, reason        filename, line = item.reportinfo()[:2]        rep.longrepr = str(filename), line + 1, reason   # called by terminalreporter progress reporting


Question: pytest.doctest.issetuppy raises with LC_ALL=C and UTF-8 chars in runs into an exception when collecting tests from a repository where contains UTF-8 characters, but the locale is set to . Minimal example: : To reproduce: Tested on CentOS 7.7.1908:

RUNNER_CLASS = None  def pytest_collect_file(path, parent):def pytest_collect_file(path: py.path.local, parent):     config = parent.config     if path.ext == ".py":        if config.option.doctestmodules and not _is_setup_py(config, path, parent):        if config.option.doctestmodules and not _is_setup_py(path):             return DoctestModule.from_parent(parent, fspath=path)     elif _is_doctest(config, path, parent):         return DoctestTextfile.from_parent(parent, fspath=path)  def _is_setup_py(config, path, parent):def _is_setup_py(path: py.path.local) -> bool:     if path.basename != "setup.py":         return False    contents = path.read()    return "setuptools" in contents or "distutils" in contents    contents = path.read_binary()    return b"setuptools" in contents or b"distutils" in contents   def _is_doctest(config, path, parent):


Question: BytesWarning when using --setup-show with bytes parameter With Python 3.8.2, pytest 5.4.1 (or latest master; stacktraces are from there) and this file: when running (note the to turn on ByteWarning and treat it as error), I get: Shouldn't that be using or something rather than (implicitly) ?

import pytest<ins>from _pytest._io.saferepr import saferepr</ins>   def pytest_addoption(parser):


Question: BytesWarning when using --setup-show with bytes parameter With Python 3.8.2, pytest 5.4.1 (or latest master; stacktraces are from there) and this file: when running (note the to turn on ByteWarning and treat it as error), I get: Shouldn't that be using or something rather than (implicitly) ?

tw.write(" (fixtures used: {})".format(", ".join(deps)))      if hasattr(fixturedef, "cached_param"):        tw.write("[{}]".format(fixturedef.cached_param))        tw.write("[{}]".format(saferepr(fixturedef.cached_param, maxsize=42)))      tw.flush()


Question: Wrong path to test file when directory changed in fixture Files are shown as relative to new directory when working directory is changed in a fixture. This makes it impossible to jump to the error as the editor is unaware of the directory change. The displayed directory should stay relative to the original directory. The full output is:

from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import NodeKeywords from _pytest.outcomes import fail<ins>from _pytest.pathlib import Path</ins> from _pytest.store import Store  if TYPE_CHECKING:


Question: Wrong path to test file when directory changed in fixture Files are shown as relative to new directory when working directory is changed in a fixture. This makes it impossible to jump to the error as the editor is unaware of the directory change. The displayed directory should stay relative to the original directory. The full output is:

else:             truncate_locals = True         # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False.        # It is possible for a fixture/test to change the CWD while this code runs, which        # would then result in the user seeing confusing paths in the failure message.        # To fix this, if the CWD changed, always display the full absolute path.        # It will be better to just always display paths relative to invocation_dir, but        # this requires a lot of plumbing (#6428).         try:            os.getcwd()            abspath = False            abspath = Path(os.getcwd()) != Path(self.config.invocation_dir)         except OSError:             abspath = True


Question: warn when logging fails Now an expectation will be thrown and written on the output... but no warning is thrown... so the test run can't be marked as failed.

self.records = []         self.stream = StringIO() <ins>    def handleError(self, record: logging.LogRecord) -> None:        if logging.raiseExceptions:            # Fail the test if the log message is bad (emit failed).            # The default behavior of logging is to print "Logging error"            # to stderr with the call stack and some extra details.            # pytest wants to make such mistakes visible during testing.            raise</ins>  class LogCaptureFixture:     """Provides access and control of log capturing."""


Question: warn when logging fails Now an expectation will be thrown and written on the output... but no warning is thrown... so the test run can't be marked as failed.

# File logging.         self.log_file_level = get_log_level_for_setting(config, "log_file_level")         log_file = get_option_ini(config, "log_file") or os.devnull        self.log_file_handler = logging.FileHandler(            log_file, mode="w", encoding="UTF-8"        )        self.log_file_handler = _FileHandler(log_file, mode="w", encoding="UTF-8")         log_file_format = get_option_ini(config, "log_file_format", "log_format")         log_file_date_format = get_option_ini(             config, "log_file_date_format", "log_date_format"


Question: warn when logging fails Now an expectation will be thrown and written on the output... but no warning is thrown... so the test run can't be marked as failed.

self.log_file_handler.close()  <ins>class _FileHandler(logging.FileHandler):    """    Custom FileHandler with pytest tweaks.    """    def handleError(self, record: logging.LogRecord) -> None:        # Handled by LogCaptureHandler.        pass</ins> class _LiveLoggingStreamHandler(logging.StreamHandler):     """     Custom StreamHandler used by the live logging feature: it will write a newline before the first log message


Question: warn when logging fails Now an expectation will be thrown and written on the output... but no warning is thrown... so the test run can't be marked as failed.

self._section_name_shown = True             super().emit(record) <ins>    def handleError(self, record: logging.LogRecord) -> None:        # Handled by LogCaptureHandler.        pass</ins>  class _LiveLoggingNullHandler(logging.NullHandler):     """A handler used when live logging is disabled."""


Question: warn when logging fails Now an expectation will be thrown and written on the output... but no warning is thrown... so the test run can't be marked as failed.

def set_when(self, when):         pass<ins>    def handleError(self, record: logging.LogRecord) -> None:        # Handled by LogCaptureHandler.        pass</ins>


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)

if not getattr(cls, "__test__", True):             return         skipped = getattr(cls, "__unittest_skip__", False)        skipped = _is_skipped(cls)         if not skipped:             self._inject_setup_teardown_fixtures(cls)             self._inject_setup_class_fixture()


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)

@pytest.fixture(scope=scope, autouse=True)     def fixture(self, request):        if getattr(self, "__unittest_skip__", None):        if _is_skipped(self):             reason = self.__unittest_skip_why__             pytest.skip(reason)         if setup is not None:


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)

# arguably we could always postpone tearDown(), but this changes the moment where the             # TestCase instance interacts with the results object, so better to only do it             # when absolutely needed            if self.config.getoption("usepdb"):            if self.config.getoption("usepdb") and not _is_skipped(self.obj):                 self._explicit_tearDown = self._testcase.tearDown                 setattr(self._testcase, "tearDown", lambda *args: None)


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)

classImplements(TestCaseFunction, IReporter)     done.append(1)<ins>def _is_skipped(obj) -> bool:    """Return True if the given object has been marked with @unittest.skip"""    return bool(getattr(obj, "__unittest_skip__", False))</ins>


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)


Question: unittest.TestCase.tearDown executed on skipped tests when running --pdb With this minimal test: test is properly skipped: but when running with , the teardown seems executed: I would have expected the test to be skipped, even with . With , test was also skipped with , so this seem something that have changes between 5.4.2 and 5.4.1. (I would have loved to, but I don't have time to send a PR these days)


Question: pytest~=4.6: While implementing a test for I've hit this: Looking at the repo, it seems to have been fixed on master by as a part of But it still persists in the branch. The fix should be trivial: just add a fallback variable value before if-blocks. No need to backport that whole PR (unless somebody thinks that it should be done, of course). Ref: [4.6.x] Add a fallback for the term report letter When plugins return report objects in an unconventional state, may skip entering if-block branches that declare the variable. It would lead to UnboundLocalError: local variable 'letter' referenced before assignment being raised. This change fixes this by setting the initial value of the before the if-block cascade so that it always has a value. [ ] Include documentation when adding new features. [ ] Include new tests or update existing tests when applicable. [ ] 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: for details. Write sentences in the past or present tense, examples: Improved verbose diff output with sequences. Terminal summary statistics now use multiple colors. Also make sure to end the sentence with a . [ ] Add yourself to in alphabetical order.

reportchars += "w"     elif config.option.disable_warnings and "w" in reportchars:         reportchars = reportchars.replace("w", "")    aliases = {"F", "S"}     for char in reportchars:        # handle old aliases        if char in aliases:            char = char.lower()         if char == "a":             reportopts = "sxXwEf"         elif char == "A":


Question: pytest~=4.6: While implementing a test for I've hit this: Looking at the repo, it seems to have been fixed on master by as a part of But it still persists in the branch. The fix should be trivial: just add a fallback variable value before if-blocks. No need to backport that whole PR (unless somebody thinks that it should be done, of course). Ref: [4.6.x] Add a fallback for the term report letter When plugins return report objects in an unconventional state, may skip entering if-block branches that declare the variable. It would lead to UnboundLocalError: local variable 'letter' referenced before assignment being raised. This change fixes this by setting the initial value of the before the if-block cascade so that it always has a value. [ ] Include documentation when adding new features. [ ] Include new tests or update existing tests when applicable. [ ] 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: for details. Write sentences in the past or present tense, examples: Improved verbose diff output with sequences. Terminal summary statistics now use multiple colors. Also make sure to end the sentence with a . [ ] Add yourself to in alphabetical order.

@pytest.hookimpl(trylast=True)  # after _pytest.runner def pytest_report_teststatus(report):    letter = "F"     if report.passed:         letter = "."     elif report.skipped:         letter = "s"    elif report.failed:        letter = "F"        if report.when != "call":            letter = "f"    return report.outcome, letter, report.outcome.upper()    outcome = report.outcome    if report.when in ("collect", "setup", "teardown") and outcome == "failed":        outcome = "error"        letter = "E"    return outcome, letter, outcome.upper()   @attr.s


Question: pytest~=4.6: While implementing a test for I've hit this: Looking at the repo, it seems to have been fixed on master by as a part of But it still persists in the branch. The fix should be trivial: just add a fallback variable value before if-blocks. No need to backport that whole PR (unless somebody thinks that it should be done, of course). Ref: [4.6.x] Add a fallback for the term report letter When plugins return report objects in an unconventional state, may skip entering if-block branches that declare the variable. It would lead to UnboundLocalError: local variable 'letter' referenced before assignment being raised. This change fixes this by setting the initial value of the before the if-block cascade so that it always has a value. [ ] Include documentation when adding new features. [ ] Include new tests or update existing tests when applicable. [ ] 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: for details. Write sentences in the past or present tense, examples: Improved verbose diff output with sequences. Terminal summary statistics now use multiple colors. Also make sure to end the sentence with a . [ ] Add yourself to in alphabetical order.

"x": show_xfailed,             "X": show_xpassed,             "f": partial(show_simple, "failed"),            "F": partial(show_simple, "failed"),             "s": show_skipped,            "S": show_skipped,             "p": partial(show_simple, "passed"),             "E": partial(show_simple, "error"),         }


Question: Pytest crashes the interpreter on debug build for 3.8+ Short reproducer Related issue for improvement of this behavior:

)  <ins># True, False and None are legal match expression identifiers,# but illegal as Python identifiers. To fix this, this prefix# is added to identifiers in the conversion to Python AST.IDENT_PREFIX = "$"</ins> def expression(s: Scanner) -> ast.Expression:     if s.accept(TokenType.EOF):         ret = ast.NameConstant(False)  # type: ast.expr


Question: Pytest crashes the interpreter on debug build for 3.8+ Short reproducer Related issue for improvement of this behavior:

return ret     ident = s.accept(TokenType.IDENT)     if ident:        return ast.Name(ident.value, ast.Load())        return ast.Name(IDENT_PREFIX + ident.value, ast.Load())     s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))


Question: Pytest crashes the interpreter on debug build for 3.8+ Short reproducer Related issue for improvement of this behavior:

self.matcher = matcher      def __getitem__(self, key: str) -> bool:        return self.matcher(key)        return self.matcher(key[len(IDENT_PREFIX) :])      def __iter__(self) -> Iterator[str]:         raise NotImplementedError()


Question: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pytest-of-jenkins/pytest-' Same issue as in . I think there are still some edge cases where this is not handled correctly. I am running a series of concurrent pytest processes and was able to reproduce the issue. Here is the stack trace: A potential mitigation to this problem might be to generate the numbered dir with a random suffix rather than a sequential one, unless some code depends on this logic:

import atexit<ins>import contextlib</ins> import fnmatch import itertools import os


Question: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pytest-of-jenkins/pytest-' Same issue as in . I think there are still some edge cases where this is not handled correctly. I am running a series of concurrent pytest processes and was able to reproduce the issue. Here is the stack trace: A potential mitigation to this problem might be to generate the numbered dir with a random suffix rather than a sequential one, unless some code depends on this logic:

return False     else:         if lock_time < consider_lock_dead_if_created_before:            lock.unlink()            return True        else:            return False            # wa want to ignore any errors while trying to remove the lock such as:            # - PermissionDenied, like the file permissions have changed since the lock creation            # - FileNotFoundError, in case another pytest process got here first.            # and any other cause of failure.            with contextlib.suppress(OSError):                lock.unlink()                return True        return False   def try_cleanup(path: Path, consider_lock_dead_if_created_before: float) -> None:


Question: Incorrect caching of skipif/xfail string condition evaluation Version: pytest 5.4.3, current master pytest caches the evaluation of the string in e.g. . The caching key is only the string itself (see in ). However, the evaluation also depends on the item's globals, so the caching can lead to incorrect results. Example: Running . Expected: is skipped, is not skipped. Actual: both are skipped. I think the most appropriate fix is to simply remove the caching, which I don't think is necessary really, and inline into .

from ..outcomes import fail from ..outcomes import TEST_OUTCOME from .structures import Markfrom _pytest.config import Config from _pytest.nodes import Itemfrom _pytest.store import StoreKey  evalcache_key = StoreKey[Dict[str, Any]]()def compiled_eval(expr: str, d: Dict[str, object]) -> Any:    import _pytest._code def cached_eval(config: Config, expr: str, d: Dict[str, object]) -> Any:    default = {}  # type: Dict[str, object]    evalcache = config._store.setdefault(evalcache_key, default)    try:        return evalcache[expr]    except KeyError:        import _pytest._code        exprcode = _pytest._code.compile(expr, mode="eval")        evalcache[expr] = x = eval(exprcode, d)        return x    exprcode = _pytest._code.compile(expr, mode="eval")    return eval(exprcode, d)   class MarkEvaluator:


Question: Incorrect caching of skipif/xfail string condition evaluation Version: pytest 5.4.3, current master pytest caches the evaluation of the string in e.g. . The caching key is only the string itself (see in ). However, the evaluation also depends on the item's globals, so the caching can lead to incorrect results. Example: Running . Expected: is skipped, is not skipped. Actual: both are skipped. I think the most appropriate fix is to simply remove the caching, which I don't think is necessary really, and inline into .

self.expr = expr                     if isinstance(expr, str):                         d = self._getglobals()                        result = cached_eval(self.item.config, expr, d)                        result = compiled_eval(expr, d)                     else:                         if "reason" not in mark.kwargs:                             # XXX better be checked at collection time


Question: skipping: --runxfail breaks location reporting pytest versions: 5.4.x, current master When / marks are used to skip a test, for example the expected skip location reported should point to the item itself, and this is indeed what happens when running with : However, adding breaks this: The is only about xfail and should not affect this at all. Hint: the bug is in , the hook.

else:                 rep.outcome = "passed"                 rep.wasxfail = xfailed.reason    elif (    if (         item._store.get(skipped_by_mark_key, True)         and rep.skipped         and type(rep.longrepr) is tuple


Question: Support NOCOLOR to disable colored output is a variable. The general behavior is: A command line application emits colour when attached to a TTY, but no colour otherwise e.g. when attached to a pipe. stops the application from emitting colour even when attached to a TTY My extension to the standard is to add which forces the application to emit colour escape sequences even when not outputting to a TTY e.g. if we want to pipe into a log file with colour. Originally posted by in

return True     if os.environ.get("PY_COLORS") == "0":         return False    if "NO_COLOR" in os.environ:        return False    if "FORCE_COLOR" in os.environ:        return True     return (        hasattr(file, "isatty")        and file.isatty()        and os.environ.get("TERM") != "dumb"        and not (sys.platform.startswith("java") and os._name == "nt")        hasattr(file, "isatty") and file.isatty() and os.environ.get("TERM") != "dumb"     )


Question: --log-file should create subdirectories If you provide a path with a subdirectory, which does not exist, it crashes with. For example execute produces something like this: Maybe someone want to add something like this However, there is the possibility to say that someone is not supposed to pass a directory path there. Originally posted by in

# File logging.         self.log_file_level = get_log_level_for_setting(config, "log_file_level")         log_file = get_option_ini(config, "log_file") or os.devnull        if log_file != os.devnull:            directory = os.path.dirname(os.path.abspath(log_file))            if not os.path.isdir(directory):                os.makedirs(directory)         self.log_file_handler = _FileHandler(log_file, mode="w", encoding="UTF-8")         log_file_format = get_option_ini(config, "log_file_format", "log_format")         log_file_date_format = get_option_ini(             config, "log_file_date_format", "log_date_format"         )         log_file_formatter = logging.Formatter(             log_file_format, datefmt=log_file_date_format         )


Question: pytest 6 (?): UnicodeEncodeError in terminalwriter on Windows Just got this on GitHub Actions with the pytest 6 rc: This is the test using pytest-bdd in qutebrowser: I can't reproduce this consistently - if I'm reading the traceback right, the test failed (probably flaky?) and then pytest failed while printing the traceback... Note that I also have pytest-instafail installed and it shows up in the stacktrace. Not sure if this is actually related to pytest 6, but I've never seen it happen before.

msg = self.markup(msg, **markup)             self._file.write(msg)            try:                self._file.write(msg)            except UnicodeEncodeError:                # Some environments don't support printing general Unicode                # strings, due to misconfiguration or otherwise; in that case,                # print the string escaped to ASCII.                # When the Unicode situation improves we should consider                # letting the error propagate instead of masking it (see #7475                # for one brief attempt).                msg = msg.encode("unicode-escape").decode("ascii")                self._file.write(msg)             if flush:                 self.flush()


Question: Pytest 6: Dynamically adding xfail marker in test no longer ignores failure <!-- Thanks for submitting an issue! Here's a quick checklist for what to provide: --With pytest 5.x, we can dynamically add an xfail to a test object using (see example below). In 5.x this treated the failing test like a a test marked statically with an . With 6.0.0rc0 it raises. <details</details- [ ] pytest and operating system versions Pytest 6.0.1rc0 and MacOS 10.14.5 With 5.4.3 With 6.0.0rc0

@hookimpl(tryfirst=True) def pytest_runtest_setup(item: Item) -> None:    item._store[skipped_by_mark_key] = False     skipped = evaluate_skip_marks(item)    item._store[skipped_by_mark_key] = skipped is not None     if skipped:        item._store[skipped_by_mark_key] = True         skip(skipped.reason)     if not item.config.option.runxfail:        item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item)        if xfailed and not xfailed.run:            xfail("[NOTRUN] " + xfailed.reason)    item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item)    if xfailed and not item.config.option.runxfail and not xfailed.run:        xfail("[NOTRUN] " + xfailed.reason)   @hookimpl(hookwrapper=True)


Question: Pytest 6: Dynamically adding xfail marker in test no longer ignores failure <!-- Thanks for submitting an issue! Here's a quick checklist for what to provide: --With pytest 5.x, we can dynamically add an xfail to a test object using (see example below). In 5.x this treated the failing test like a a test marked statically with an . With 6.0.0rc0 it raises. <details</details- [ ] pytest and operating system versions Pytest 6.0.1rc0 and MacOS 10.14.5 With 5.4.3 With 6.0.0rc0

if xfailed is None:         item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item)     if not item.config.option.runxfail:        if xfailed and not xfailed.run:            xfail("[NOTRUN] " + xfailed.reason)    if xfailed and not item.config.option.runxfail and not xfailed.run:        xfail("[NOTRUN] " + xfailed.reason)      yield     # The test run may have added an xfail mark dynamically.    xfailed = item._store.get(xfailed_key, None)    if xfailed is None:        item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item)  @hookimpl(hookwrapper=True) def pytest_runtest_makereport(item: Item, call: CallInfo[None]):


Question: suggestion: improve raises confusing message when matching [x] a detailed description of the bug or suggestion I would like to check if strings have parenthesis in them when match is not None, so that people have that lightbulb moment, rather than head-scratching when it presents two identical strings as not matching. [ ] output of from the virtual environment you are using I believe this is not applicable right now. I'm happy to provide one if you believe other modules or libraries are causing this behavior. [x] pytest and operating system versions Windows 10 64-bit (I know), all updates installed Pytest 5.4.3 [x] minimal example if possible edited 22:31 (same day) as the example given was the fixed code including escapes and r prefix I believe a more helpful error message

If it matches `True` is returned, otherwise an `AssertionError` is raised.         """         __tracebackhide__ = True        assert re.search(            regexp, str(self.value)        ), "Pattern {!r} does not match {!r}".format(regexp, str(self.value))        msg = "Regex pattern {!r} does not match {!r}."        if regexp == str(self.value):            msg += " Did you mean to `re.escape()` the regex?"        assert re.search(regexp, str(self.value)), msg.format(regexp, str(self.value))         # Return True to allow for "assert excinfo.match()".         return True


Question: Cleaning up temporary directories occasionally raises PermissionError On Windows, I'm finding that pytest occasionally raises an exception starting with while cleaning up its temporary directories. Below is an example of the output of a test session in which the exception arises. The test file contains only the function shown in the output. A necessary condition for the exception is that pytest's base temporary directory already contains at least three temporary directories to cause pytest to try to clean up at least one directory. Also, the exception occurred more often when the computer was under load. ============================= test session starts ============================= platform win32 -- Python 3.7.7, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: C:\Users\Desktop\pytest-garbage collected 1 item F [100%] ================================== FAILURES =================================== ___ testtemp ___ tmppathfactory = TempPathFactory(givenbasetemp=None, trace=<pluggy.tracing.TagTracerSub object at 0x0000026E365FECC8, basetemp=None) def testtemp(tmppathfactory): for in range(1000): ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in mktemp basename = self.ensurerelativetobasetemp(basename) ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in ensurerelativetobasetemp if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp(): ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in getbasetemp prefix="pytest-", root=rootdir, keep=3, locktimeout=LOCKTIMEOUT ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in makenumbereddirwithcleanup considerlockdeadifcreatedbefore=considerlockdeadifcreatedbefore, ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in cleanupnumbereddir trycleanup(path, considerlockdeadifcreatedbefore) ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in trycleanup if ensuredeletable(path, considerlockdeadifcreatedbefore): ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\site-packages\pytest\ in ensuredeletable if not (): ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\ in exists () self = WindowsPath('') def stat(self): """ Return the result of the stat() system call on this path, like () does. """ E PermissionError: [WinError 5] Access is denied: 'C:\Users\\AppData\Local\Temp\pytest-of-\garbage--fd35-4f5b-b6c5-\.lock' ....\Programs\Miniconda3-64\envs\pytest-garbage\lib\ PermissionError =========================== short test summary info =========================== FAILED - PermissionError: [WinError 5] Access is deni... ============================== 1 failed in 0.83s ============================== It seems that sometimes the operating system continued to actually delete the files and directories inside an old directory even after the function (below) completed the call in its first statement to . Then, the second statement found that lingering directory, which renamed to the form . While was attempting again to delete its contents, the operating system finished actually deleting them, and the exception occurred. def cleanupnumbereddir( root: Path, prefix: str, keep: int, considerlockdeadifcreatedbefore: float ) -None: """cleanup for lock driven numbered directories""" for path in cleanupcandidates(root, prefix, keep): trycleanup(path, considerlockdeadifcreatedbefore) for path in ("garbage-"): trycleanup(path, considerlockdeadifcreatedbefore) I tested simply reversing the two statements, so that pytest cleans old directories before numbered directories, and that appeared to prevent the exception in my testing. The operating system is Windows 10.0. Build , the file system is NTFS on a solid-state drive, I'm using a conda environment, and produces: Package Version ------------------ ------------------- atomicwrites 1.4.0 attrs 19.3.0 certifi 2020.6.20 colorama 0.4.3 importlib-metadata 1.7.0 more-itertools 8.4.0 packaging 20.4 pip 20.1.1 pluggy 0.13.1 py 1.9.0 pyparsing 2.4.7 pytest 5.4.3 setuptools 47.3.1.post20200622 six 1.15.0 wcwidth 0.2.5 wheel 0.34.2 wincertstore 0.2 zipp 3.1.0 I also encountered the same exception using pytest version 6.0.0rc1, although the session output differs because pytest* defers the clean-up until exit: ============================= test session starts ============================= platform win32 -- Python 3.7.7, pytest-6.0.0rc1, py-1.9.0, pluggy-0.13.1 rootdir: C:\Users\Desktop\pytest-garbage collected 1 item . [100%] ============================== 1 passed in 2.67s ============================== Error in atexit.runexitfuncs: Traceback (most recent call last): File "c:\users\programs\miniconda3-64\envs\pytest-garbage\lib\", line 1356, in exists () File "c:\users\programs\miniconda3-64\envs\pytest-garbage\lib\", line 1178, in stat return (self) PermissionError: [WinError 5] Access is denied: 'C:\Users\\AppData\Local\Temp\pytest-of-\garbage--f05a-46d7-bd84-\.lock' Is swapping the statements within a good way to resolve this issue?

def ensure_deletable(path: Path, consider_lock_dead_if_created_before: float) -> bool:    """checks if a lock exists and breaks it if its considered dead"""    """checks if `path` is deletable based on whether the lock file is expired"""     if path.is_symlink():         return False     lock = get_lock_path(path)    if not lock.exists():        return True    try:        if not lock.is_file():            return True    except OSError:        # we might not have access to the lock file at all, in this case assume        # we don't have access to the entire directory (#7491).        return False     try:         lock_time = lock.stat().st_mtime     except Exception:


Question: pytest 6.0.0rc1: capfd.readouterr() converts \r to \n I am testing pytest 6.0.0rc1 with Fedora packages. This is the first failure I get, from borgbackup 1.1.13. I've distilled a reproducer: pytest 5: pytest 6: This is Fedora 32 with Python 3.8 (the original failure in borgbackup is Fedora 33 with Python 3.9). I could have not found anything about this change in the changelog nor at hence I assume this is a regression. I've labeled it as such, but feel free to change that.

TemporaryFile(buffering=0),  # type: ignore[arg-type]                 encoding="utf-8",                 errors="replace",<ins>                newline="",</ins>                 write_through=True,             )             if targetfd in patchsysdict:


Question: pytest 6: Traceback in contains repr of The tests fail with pytest 6: This is because of (, "code: remove last usage of ") - it removed the , but the format string uses , so now we get the repr of the object instead of the repr of a string. I believe this should continue to use so the output is the same in all cases. cc

raise         except BaseException:             line = "???"        return "  File %r:%d in %s\n  %s\n" % (self.path, self.lineno + 1, name, line)        # This output does not quite match Python's repr for traceback entries,        # but changing it to do so would break certain plugins.  See        # https://github.com/pytest-dev/pytest/pull/7535/ for details.        return "  File %r:%d in %s\n  %s\n" % (            str(self.path),            self.lineno + 1,            name,            line,        )      @property     def name(self) -> str:


Question: caplog fixture doesn't restore log level after test From the documentation at , "The log levels set are restored automatically at the end of the test". It used to work, but looks broken in new 6.0 release. Minimal example to reproduce: It prints "0" for pytest<6, "42" after.

"""Creates a new funcarg."""         self._item = item         # dict of log name -> log level<ins>        self._initial_handler_level = None  # type: Optional[int]</ins>         self._initial_logger_levels = {}  # type: Dict[Optional[str], int]      def _finalize(self) -> None:


Question: caplog fixture doesn't restore log level after test From the documentation at , "The log levels set are restored automatically at the end of the test". It used to work, but looks broken in new 6.0 release. Minimal example to reproduce: It prints "0" for pytest<6, "42" after.

This restores the log levels changed by :meth:`set_level`.         """         # restore log levels<ins>        if self._initial_handler_level is not None:            self.handler.setLevel(self._initial_handler_level)</ins>         for logger_name, level in self._initial_logger_levels.items():             logger = logging.getLogger(logger_name)             logger.setLevel(level)


Question: caplog fixture doesn't restore log level after test From the documentation at , "The log levels set are restored automatically at the end of the test". It used to work, but looks broken in new 6.0 release. Minimal example to reproduce: It prints "0" for pytest<6, "42" after.

# save the original log-level to restore it during teardown         self._initial_logger_levels.setdefault(logger, logger_obj.level)         logger_obj.setLevel(level)<ins>        self._initial_handler_level = self.handler.level</ins>         self.handler.setLevel(level)      @contextmanager


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

import inspect import os import sys<ins>import warnings</ins> from collections import defaultdict from collections import deque from types import TracebackType


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config.argparsing import Parser<ins>from _pytest.deprecated import FILLFUNCARGS</ins> from _pytest.mark import ParameterSet from _pytest.outcomes import fail from _pytest.outcomes import TEST_OUTCOME


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

def fillfixtures(function: "Function") -> None:     """Fill missing funcargs for a test function."""    # Uncomment this after 6.0 release (#7361)    # warnings.warn(FILLFUNCARGS, stacklevel=2)    warnings.warn(FILLFUNCARGS, stacklevel=2)     try:         request = function._request     except AttributeError:diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py-- a/src/_pytest/hookspec.py++ b/src/_pytest/hookspec.py


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

from pluggy import HookspecMarker  from _pytest.compat import TYPE_CHECKING<ins>from _pytest.deprecated import WARNING_CAPTURED_HOOK</ins>  if TYPE_CHECKING:     import pdb


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

"""  # Uncomment this after 6.0 release (#7361)# @hookspec(historic=True, warn_on_impl=WARNING_CAPTURED_HOOK)@hookspec(historic=True)@hookspec(historic=True, warn_on_impl=WARNING_CAPTURED_HOOK) def pytest_warning_captured(     warning_message: "warnings.WarningMessage",     when: "Literal['config', 'collect', 'runtest']",diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py-- a/src/_pytest/mark/__init__.py++ b/src/_pytest/mark/__init__.py


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

"""Generic mechanism for marking and selecting python functions.""" import typing<ins>import warnings</ins> from typing import AbstractSet from typing import List from typing import Optional


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

from _pytest.config import hookimpl from _pytest.config import UsageError from _pytest.config.argparsing import Parser<ins>from _pytest.deprecated import MINUS_K_COLONfrom _pytest.deprecated import MINUS_K_DASH</ins> from _pytest.store import StoreKey  if TYPE_CHECKING:


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

if keywordexpr.startswith("-"):         # To be removed in pytest 7.0.0.        # Uncomment this after 6.0 release (#7361)        # warnings.warn(MINUS_K_DASH, stacklevel=2)        warnings.warn(MINUS_K_DASH, stacklevel=2)         keywordexpr = "not " + keywordexpr[1:]     selectuntil = False     if keywordexpr[-1:] == ":":         # To be removed in pytest 7.0.0.        # Uncomment this after 6.0 release (#7361)        # warnings.warn(MINUS_K_COLON, stacklevel=2)        warnings.warn(MINUS_K_COLON, stacklevel=2)         selectuntil = True         keywordexpr = keywordexpr[:-1] diff --git a/src/pytest/collect.py b/src/pytest/collect.py-- a/src/pytest/collect.py++ b/src/pytest/collect.py


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

import sysimport warnings from types import ModuleType from typing import Any from typing import List  import pytestfrom _pytest.deprecated import PYTEST_COLLECT_MODULE  COLLECT_FAKEMODULE_ATTRIBUTES = [     "Collector",


Question: Reintroduce warnings postponed in 6.0 A few warnings were introduced near the 6.0 release, so we can't comply with the "2 versions minimum with warnings", so for 6.0 these warnings were suppressed in We should reintroduce them in 6.1.

def __getattr__(self, name: str) -> Any:         if name not in self.__all__:             raise AttributeError(name)        # Uncomment this after 6.0 release (#7361)        # warnings.warn(PYTEST_COLLECT_MODULE.format(name=name), stacklevel=2)        warnings.warn(PYTEST_COLLECT_MODULE.format(name=name), stacklevel=2)         return getattr(pytest, name)


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

"The pytest_warning_captured is deprecated and will be removed in a future release.\n"     "Please use pytest_warning_recorded instead." )FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestDeprecationWarning(    "The gethookproxy() and isinitpath() methods of FSCollector and Package are deprecated; "    "use self.session.gethookproxy() and self.session.isinitpath() instead. ")diff --git a/src/_pytest/main.py b/src/_pytest/main.py-- a/src/_pytest/main.py++ b/src/_pytest/main.py


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

from _pytest.config import directory_arg from _pytest.config import ExitCode from _pytest.config import hookimpl<ins>from _pytest.config import PytestPluginManager</ins> from _pytest.config import UsageError from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureManager


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

items[:] = remaining  <ins>class FSHookProxy:    def __init__(self, pm: PytestPluginManager, remove_mods) -> None:        self.pm = pm        self.remove_mods = remove_mods    def __getattr__(self, name: str):        x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods)        self.__dict__[name] = x        return x</ins> class NoMatch(Exception):     """Matching cannot locate matching names."""


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

return path in self._initialpaths      def gethookproxy(self, fspath: py.path.local):        return super()._gethookproxy(fspath)        # Check if we have the common case of running        # hooks with all conftest.py files.        pm = self.config.pluginmanager        my_conftestmodules = pm._getconftestmodules(            fspath, self.config.getoption("importmode")        )        remove_mods = pm._conftest_plugins.difference(my_conftestmodules)        if remove_mods:            # One or more conftests are not in use at this fspath.            proxy = FSHookProxy(pm, remove_mods)        else:            # All plugins are active for this fspath.            proxy = self.config.hook        return proxy      @overload     def perform_collect(diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py-- a/src/_pytest/nodes.py++ b/src/_pytest/nodes.py


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

from _pytest.compat import TYPE_CHECKING from _pytest.config import Config from _pytest.config import ConftestImportFailurefrom _pytest.config import PytestPluginManagerfrom _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH from _pytest.deprecated import NODE_USE_FROM_PARENT from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureLookupError


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

return fspath.relto(initial_path)  <del>class FSHookProxy:    def __init__(self, pm: PytestPluginManager, remove_mods) -> None:        self.pm = pm        self.remove_mods = remove_mods    def __getattr__(self, name: str):        x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods)        self.__dict__[name] = x        return x</del> class FSCollector(Collector):     def __init__(         self,


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

"""The public constructor."""         return super().from_parent(parent=parent, fspath=fspath, **kw)     def _gethookproxy(self, fspath: py.path.local):        # Check if we have the common case of running        # hooks with all conftest.py files.        pm = self.config.pluginmanager        my_conftestmodules = pm._getconftestmodules(            fspath, self.config.getoption("importmode")        )        remove_mods = pm._conftest_plugins.difference(my_conftestmodules)        if remove_mods:            # One or more conftests are not in use at this fspath.            proxy = FSHookProxy(pm, remove_mods)        else:            # All plugins are active for this fspath.            proxy = self.config.hook        return proxy     def gethookproxy(self, fspath: py.path.local):        raise NotImplementedError()        warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)        return self.session.gethookproxy(fspath)    def isinitpath(self, path: py.path.local) -> bool:        warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)        return self.session.isinitpath(path)      def _recurse(self, direntry: "os.DirEntry[str]") -> bool:         if direntry.name == "__pycache__":             return False         path = py.path.local(direntry.path)        ihook = self._gethookproxy(path.dirpath())        ihook = self.session.gethookproxy(path.dirpath())         if ihook.pytest_ignore_collect(path=path, config=self.config):             return False         for pat in self._norecursepatterns:             if path.check(fnmatch=pat):                 return False        ihook = self._gethookproxy(path)        ihook = self.session.gethookproxy(path)         ihook.pytest_collect_directory(path=path, parent=self)         return True     def isinitpath(self, path: py.path.local) -> bool:        raise NotImplementedError()     def _collectfile(         self, path: py.path.local, handle_dupes: bool = True     ) -> Sequence[Collector]:


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(             path, path.isdir(), path.exists(), path.islink()         )        ihook = self.gethookproxy(path)        if not self.isinitpath(path):        ihook = self.session.gethookproxy(path)        if not self.session.isinitpath(path):             if ihook.pytest_ignore_collect(path=path, config=self.config):                 return () diff --git a/src/_pytest/python.py b/src/_pytest/python.py-- a/src/_pytest/python.py++ b/src/_pytest/python.py


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

from _pytest.config import ExitCode from _pytest.config import hookimpl from _pytest.config.argparsing import Parser<ins>from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH</ins> from _pytest.deprecated import FUNCARGNAMES from _pytest.fixtures import FuncFixtureInfo from _pytest.main import Session


Question: Since pytest 6.0.0, pylint complains about unimplemented abstract methods in custom collector Hi, we have implemented a custom pytest collector that takes testcases from YAML files. Starting with pytest 6.0.0, pylint reports the following about that collector: The collector has worked fine for a long time, and it still works fine. The line pylint reports this on is the class definition of a collector class that is based on pytest.File: The whole source code is here: Versions: Python 3.8.0 (default, Oct 15 2019, 17:49:23). This happens on all Python 3.x versions we used pytest 6.0.1 with (3.5, 3.6, 3.7, 3.8), on macOS and Ubuntu. pylint 2.4.4 astroid 2.3.3 platform linux -- Python 3.8.0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 plugins: cov-2.10.0, yagot-0.5.0, requests-mock-1.8.0 Please let me know in case a collector has to implement these methods.

self.addfinalizer(func)      def gethookproxy(self, fspath: py.path.local):        return super()._gethookproxy(fspath)        warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)        return self.session.gethookproxy(fspath)      def isinitpath(self, path: py.path.local) -> bool:        return path in self.session._initialpaths        warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2)        return self.session.isinitpath(path)      def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:         this_path = self.fspath.dirpath()


Question: logging: handler level restored incorrectly if caplog.setlevel is called more than once pytest version: 6.0.1 The fix in (backported to 6.0.1) has a bug where it does a "set" instead of "setdefault" to the . So if there are multiple calls to , the level will be restored to that of the one-before-last call, instead of the value before the test. Will submit a fix for this shortly.

# Save the original log-level to restore it during teardown.         self._initial_logger_levels.setdefault(logger, logger_obj.level)         logger_obj.setLevel(level)        self._initial_handler_level = self.handler.level        if self._initial_handler_level is None:            self._initial_handler_level = self.handler.level         self.handler.setLevel(level)      @contextmanager


Question: Crash with NameError through decorator during collection pytest crashes when trying to collect the following file: The failure representation works with : I've started writing a test, but it fails in both modes like the first case above:

return                 expect_docstring = False             elif (                not isinstance(item, ast.ImportFrom)                or item.level > 0                or item.module != "__future__"                isinstance(item, ast.ImportFrom)                and item.level == 0                and item.module == "__future__"             ):                lineno = item.lineno                pass            else:                 break             pos += 1        # Special case: for a decorated function, set the lineno to that of the        # first decorator, not the `def`. Issue #4984.        if isinstance(item, ast.FunctionDef) and item.decorator_list:            lineno = item.decorator_list[0].lineno         else:             lineno = item.lineno         imports = [


Question: [Feature] Allow a --sw-skip shorthand cli arg like --sw itself permits The stepwise plugin exposes a shorthand option for the stepwise itself, however it requires a longer arg only for skip, I think these should be consistent and should offer shorthand versions for both. Expected:

from typing import List from typing import Optional<ins>from typing import TYPE_CHECKING</ins>  import pytest from _pytest import nodes


Question: [Feature] Allow a --sw-skip shorthand cli arg like --sw itself permits The stepwise plugin exposes a shorthand option for the stepwise itself, however it requires a longer arg only for skip, I think these should be consistent and should offer shorthand versions for both. Expected:

from _pytest.main import Session from _pytest.reports import TestReport <ins>if TYPE_CHECKING:    from _pytest.cacheprovider import CacheSTEPWISE_CACHE_DIR = "cache/stepwise"</ins>  def pytest_addoption(parser: Parser) -> None:     group = parser.getgroup("general")


Question: [Feature] Allow a --sw-skip shorthand cli arg like --sw itself permits The stepwise plugin exposes a shorthand option for the stepwise itself, however it requires a longer arg only for skip, I think these should be consistent and should offer shorthand versions for both. Expected:

"--sw",         "--stepwise",         action="store_true",        default=False,         dest="stepwise",         help="exit on test failure and continue from last failing test next time",     )     group.addoption(        "--sw-skip",         "--stepwise-skip",         action="store_true",        default=False,         dest="stepwise_skip",         help="ignore the first failing test but stop on the next failing test",     )


Question: [Feature] Allow a --sw-skip shorthand cli arg like --sw itself permits The stepwise plugin exposes a shorthand option for the stepwise itself, however it requires a longer arg only for skip, I think these should be consistent and should offer shorthand versions for both. Expected:

@pytest.hookimpl def pytest_configure(config: Config) -> None:    config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin")    # We should always have a cache as cache provider plugin uses tryfirst=True    if config.getoption("stepwise"):        config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin")def pytest_sessionfinish(session: Session) -> None:    if not session.config.getoption("stepwise"):        assert session.config.cache is not None        # Clear the list of failing tests if the plugin is not active.        session.config.cache.set(STEPWISE_CACHE_DIR, [])   class StepwisePlugin:     def __init__(self, config: Config) -> None:         self.config = config        self.active = config.getvalue("stepwise")         self.session: Optional[Session] = None         self.report_status = ""        if self.active:            assert config.cache is not None            self.lastfailed = config.cache.get("cache/stepwise", None)            self.skip = config.getvalue("stepwise_skip")        assert config.cache is not None        self.cache: Cache = config.cache        self.lastfailed: Optional[str] = self.cache.get(STEPWISE_CACHE_DIR, None)        self.skip: bool = config.getoption("stepwise_skip")      def pytest_sessionstart(self, session: Session) -> None:         self.session = session      def pytest_collection_modifyitems(        self, session: Session, config: Config, items: List[nodes.Item]        self, config: Config, items: List[nodes.Item]     ) -> None:        if not self.active:            return         if not self.lastfailed:             self.report_status = "no previously failed tests, not skipping."             return         already_passed = []        found = False        # Make a list of all tests that have been run before the last failing one.        for item in items:        # check all item nodes until we find a match on last failed        failed_index = None        for index, item in enumerate(items):             if item.nodeid == self.lastfailed:                found = True                failed_index = index                 break            else:                already_passed.append(item)          # If the previously failed test was not found among the test items,         # do not skip any tests.        if not found:        if failed_index is None:             self.report_status = "previously failed test not found, not skipping."            already_passed = []         else:            self.report_status = "skipping {} already passed items.".format(                len(already_passed)            )        for item in already_passed:            items.remove(item)        config.hook.pytest_deselected(items=already_passed)            self.report_status = f"skipping {failed_index} already passed items."            deselected = items[:failed_index]            del items[:failed_index]            config.hook.pytest_deselected(items=deselected)      def pytest_runtest_logreport(self, report: TestReport) -> None:        if not self.active:            return         if report.failed:             if self.skip:                 # Remove test from the failed ones (if it exists) and unset the skip option


Question: [Feature] Allow a --sw-skip shorthand cli arg like --sw itself permits The stepwise plugin exposes a shorthand option for the stepwise itself, however it requires a longer arg only for skip, I think these should be consistent and should offer shorthand versions for both. Expected:

self.lastfailed = None      def pytest_report_collectionfinish(self) -> Optional[str]:        if self.active and self.config.getoption("verbose") >= 0 and self.report_status:            return "stepwise: %s" % self.report_status        if self.config.getoption("verbose") >= 0 and self.report_status:            return f"stepwise: {self.report_status}"         return None     def pytest_sessionfinish(self, session: Session) -> None:        assert self.config.cache is not None        if self.active:            self.config.cache.set("cache/stepwise", self.lastfailed)        else:            # Clear the list of failing tests if the plugin is not active.            self.config.cache.set("cache/stepwise", [])    def pytest_sessionfinish(self) -> None:        self.cache.set(STEPWISE_CACHE_DIR, self.lastfailed)