Question: currentmodule = module         if verbose <= 0 and argname[0] == "_":             continue        tw.write(argname, green=True)        if fixturedef.scope != "function":            tw.write(" [%s scope]" % fixturedef.scope, cyan=True)         if verbose > 0:            funcargspec = "%s -- %s" % (argname, bestrel)        else:            funcargspec = argname        tw.line(funcargspec, green=True)            tw.write(" -- %s" % bestrel, yellow=True)        tw.write("\n")         loc = getlocation(fixturedef.func, curdir)         doc = fixturedef.func.__doc__ or ""         if doc:             write_docstring(tw, doc)         else:             tw.line("    %s: no docstring available" % (loc,), red=True)        tw.line()   def write_docstring(tw, doc, indent="    "):

Display fixture scope with It would be useful to show fixture scopes with ; currently the only way to learn the scope of a fixture is look at the docs (when that is documented) or at the source code.


Question: from _pytest.config import create_terminal_writer from _pytest.pathlib import Path DEFAULT_LOG_FORMAT = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S"

Improve default logging format Currently it is: I think (module name) would be very useful here, instead of just the base filename. (It might also be good to have the relative path there (maybe at the end), but it is usually still very long (but e.g. could be substituted therein)) Currently it would look like this: Using instead:


Question: self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]         session.config.pluginmanager.register(self, "funcmanage")     def _get_direct_parametrize_args(self, node):        """This function returns all the direct parametrization        arguments of a node, so we don't mistake them for fixtures        Check https://github.com/pytest-dev/pytest/issues/5036        This things are done later as well when dealing with parametrization        so this could be improved        """        from _pytest.mark import ParameterSet        parametrize_argnames = []        for marker in node.iter_markers(name="parametrize"):            if not marker.kwargs.get("indirect", False):                p_argnames, _ = ParameterSet._parse_parametrize_args(                    *marker.args, **marker.kwargs                )                parametrize_argnames.extend(p_argnames)        return parametrize_argnames     def getfixtureinfo(self, node, func, cls, funcargs=True):         if funcargs and not getattr(node, "nofuncargs", False):             argnames = getfuncargnames(func, cls=cls)         else:             argnames = ()         usefixtures = itertools.chain.from_iterable(             mark.args for mark in node.iter_markers(name="usefixtures")         )         initialnames = tuple(usefixtures) + argnames         fm = node.session._fixturemanager         initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(            initialnames, node            initialnames, node, ignore_args=self._get_direct_parametrize_args(node)         )         return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs)

does not correctly hide fixtures of the same name (it misses its dependencies) From This works: the parameter in the test correctly hides the fixture so the unique pytest node has id (instead of there being two nodes because of the fixture). However if the fixture that is hidden by the parameter depends on another fixture, that other fixture is mistakenly kept in the fixtures closure, even if it is not needed anymore. Therefore the test fails:


Question: autousenames.extend(basenames)         return autousenames     def getfixtureclosure(self, fixturenames, parentnode):    def getfixtureclosure(self, fixturenames, parentnode, ignore_args=()):         # collect the closure of all fixtures , starting with the given         # fixturenames as the initial set.  As we have to visit all         # factory definitions anyway, we also return an arg2fixturedefs


Question: while lastlen != len(fixturenames_closure):             lastlen = len(fixturenames_closure)             for argname in fixturenames_closure:                if argname in ignore_args:                    continue                 if argname in arg2fixturedefs:                     continue                 fixturedefs = self.getfixturedefs(argname, parentid)diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py-- a/src/_pytest/mark/structures.py++ b/src/_pytest/mark/structures.py


Question: else:             return cls(parameterset, marks=[], id=None)     @classmethod    def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):    @staticmethod    def _parse_parametrize_args(argnames, argvalues, **_):        """It receives an ignored _ (kwargs) argument so this function can        take also calls from parametrize ignoring scope, indirect, and other        arguments..."""         if not isinstance(argnames, (tuple, list)):             argnames = [x.strip() for x in argnames.split(",") if x.strip()]             force_tuple = len(argnames) == 1


Question: parameters = [             ParameterSet.extract_from(x, force_tuple=force_tuple) for x in argvalues         ]<ins>        return argnames, parameters    @classmethod    def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):        argnames, parameters = cls._parse_parametrize_args(argnames, argvalues)</ins>         del argvalues          if parameters:


Question: """Ensure that file.name is a string."""         return repr(self.buffer) <ins>    @property    def mode(self):        return self.buffer.mode.replace("b", "")</ins>     def __getattr__(self, name):         return getattr(object.__getattribute__(self, "buffer"), name)

pytest.capture.EncodedFile mode should not include (binary) <!-- Thanks for submitting an issue! Here's a quick checklist for what to provide: --- [x] a detailed description of the bug or suggestion Exception when youtube-dl logs to pytest captured output. Youtube-dl looks for in to decide whether to writes or . incorrectly advertises , the mode of the underlying stream. Its method raises an exception when passed . [x] output of from the virtual environment you are using [x] pytest and operating system versions [x] minimal example if possible


Question: """Ensure that file.name is a string."""         return repr(self.buffer)     @property    def mode(self):        return self.buffer.mode.replace("b", "")     def __getattr__(self, name):         return getattr(object.__getattribute__(self, "buffer"), name) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py-- a/src/_pytest/terminal.py++ b/src/_pytest/terminal.py

Invalid unicode in with Jython With: Jython 2.7.1 and pytest 4.5.0, I'm having the error below: The error happens because has the following unicode literal: . I'm not sure about the proper fix... in that function seems to be doing a and later does , so, I'm not even sure if we're dealing with or there on Python 2 because it's mixed (my guess is bytes, but I'm not really sure). If it's bytes, doing it an actual literal instead of a literal -- i.e.: remove the -- does make Jython happy (would that be an appropriate solution?)


Question: # u'😄' will result in a High Surrogate (U+D83D) character, which is                     # rendered as u'�'; in this case we just strip that character out as it                     # serves no purpose being rendered                    msg = msg.rstrip(u"\uD83D")                    try:                        surrogate = six.unichr(0xD83D)                        msg = msg.rstrip(surrogate)                    except ValueError:  # pragma: no cover                        # Jython cannot represent this lone surrogate at all (#5256):                        # ValueError: unichr() arg is a lone surrogate in range                        #     (0xD800, 0xDFFF) (Jython UTF-16 encoding)                        # ignore this case as it shouldn't appear in the string anyway                        pass                 msg += ellipsis             line += sep + msg     return line


Question: force_tuple = len(argnames) == 1         else:             force_tuple = False        parameters = [        return argnames, force_tuple    @staticmethod    def _parse_parametrize_parameters(argvalues, force_tuple):        return [             ParameterSet.extract_from(x, force_tuple=force_tuple) for x in argvalues         ]        return argnames, parameters      @classmethod     def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):        argnames, parameters = cls._parse_parametrize_args(argnames, argvalues)        argnames, force_tuple = cls._parse_parametrize_args(argnames, argvalues)        parameters = cls._parse_parametrize_parameters(argvalues, force_tuple)         del argvalues          if parameters:

Version 4.6.0 skips tests without apparent reason Since version 4.6.0 pytest skips tests without apparent reason: https://travis- [x] pytest and operating system versions: pytest 4.6.0 on Ubuntu Xenial @ Travis CI [x] minimal example if possible: link above I can't understand why it happens, so I had to immediately rollback to 4.5.0 and fix this version in dev dependencies.


Question: import platform import sys import traceback<ins>import warnings</ins> from contextlib import contextmanager  import pytest

KeyError: 'wrapped' with from xxx import yyy [X] Include a detailed description of the bug or suggestion [ ] of the virtual environment you are using [X] pytest and operating system versions [X] Minimal example if possible I implemented and for automated testing. When I run the , I get a when I perform a . In the example I included, I do not get the KeyError if I comment out the line: ... from sty import fg ... No virtual environment used. Python: 3.6.5 & 3.7.1 PyTest: 4.4.0 OS: MacOS Mojave 10.14.4 I created a very simple . If I clone the repo and call either or in the root directory, I get the error. My apologies if this bug is obvious or I am doing something wrong.


Question: from _pytest.compat import safe_getattr from _pytest.fixtures import FixtureRequest from _pytest.outcomes import Skipped<ins>from _pytest.warning_types import PytestWarning</ins>  DOCTEST_REPORT_CHOICE_NONE = "none" DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"


Question: else:          def _mock_aware_unwrap(obj, stop=None):            if stop is None:                return real_unwrap(obj, stop=_is_mocked)            else:            try:                if stop is None or stop is _is_mocked:                    return real_unwrap(obj, stop=_is_mocked)                 return real_unwrap(obj, stop=lambda obj: _is_mocked(obj) or stop(obj))            except Exception as e:                warnings.warn(                    "Got %r when unwrapping %r.  This is usually caused "                    "by a violation of Python's object protocol; see e.g. "                    "https://github.com/pytest-dev/pytest/issues/5080" % (e, obj),                    PytestWarning,                )                raise          inspect.unwrap = _mock_aware_unwrap         try:


Question: )         return fmt.repr_excinfo(self) <del>    def __str__(self):        if self._excinfo is None:            return repr(self)        entry = self.traceback[-1]        loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())        return str(loc)</del>     def match(self, regexp):         """         Check whether the regular expression 'regexp' is found in the string

str() on the context variable doesn't behave same as normal exception catch Pytest 4.6.2, macOS 10.14.5 prints But prints In order to get the full error message, one must do , which is documented, but this is a different interaction. Any chance the behavior could be changed to eliminate this gotcha? Pip list gives


Question: def _compare_eq_sequence(left, right, verbose=0):    comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes)     explanation = []     len_left = len(left)     len_right = len(right)     for i in range(min(len_left, len_right)):         if left[i] != right[i]:            if comparing_bytes:                # when comparing bytes, we want to see their ascii representation                # instead of their numeric values (#5260)                # using a slice gives us the ascii representation:                # >>> s = b'foo'                # >>> s[0]                # 102                # >>> s[0:1]                # b'f'                left_value = left[i : i + 1]                right_value = right[i : i + 1]            else:                left_value = left[i]                right_value = right[i]             explanation += [                "At index {} diff: {!r} != {!r}".format(i, left[i], right[i])                "At index {} diff: {!r} != {!r}".format(i, left_value, right_value)             ]             break    len_diff = len_left - len_right     if comparing_bytes:        # when comparing bytes, it doesn't help to show the "sides contain one or more items"        # longer explanation, so skip it        return explanation    len_diff = len_left - len_right     if len_diff:         if len_diff > 0:             dir_with_more = "Left"

Confusing assertion rewriting message with byte strings The comparison with assertion rewriting for byte strings is confusing: 52 is the ASCII ordinal of "4" here. It became clear to me when using another example: Not sure what should/could be done here.


Question: )         logfile.write('<?xml version="1.0" encoding="utf-8"?>')         logfile.write(            Junit.testsuite(                self._get_global_properties_node(),                [x.to_xml() for x in self.node_reporters_ordered],                name=self.suite_name,                errors=self.stats["error"],                failures=self.stats["failure"],                skipped=self.stats["skipped"],                tests=numtests,                time="%.3f" % suite_time_delta,            ).unicode(indent=0)        suite_node = Junit.testsuite(            self._get_global_properties_node(),            [x.to_xml() for x in self.node_reporters_ordered],            name=self.suite_name,            errors=self.stats["error"],            failures=self.stats["failure"],            skipped=self.stats["skipped"],            tests=numtests,            time="%.3f" % suite_time_delta,         )        logfile.write(Junit.testsuites([suite_node]).unicode(indent=0))         logfile.close()      def pytest_terminal_summary(self, terminalreporter):

xunit2 format does not contain a root <testsuitestag junitfamily=xunit2 option still generates an old xml format tests report. junitfamily=xunit2 creates the .xml file in the legacy formatOS: MAC OS Mojave == 10.14.5 Sample output from the tests by running:


Question: def pytest_collect_file(parent, path):    if path.ext == ".yml" and path.basename.startswith("test"):    if path.ext == ".yaml" and path.basename.startswith("test"):         return YamlFile(path, parent)  diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py-- a/src/_pytest/_code/code.py++ b/src/_pytest/_code/code.py

pytest stepwise doesn't work with xfail strict failures recommended pytest-runner in setuprequires means packages fail to install often The recommendation to add to means that all users of that package end up with an unnecessary pytest-runner package installed. This is bad because it bypasses pip hashes and


Question: """         __tracebackhide__ = True         if not re.search(regexp, str(self.value)):            assert 0, "Pattern '{!s}' not found in '{!s}'".format(regexp, self.value)            assert 0, "Pattern {!r} not found in {!r}".format(regexp, str(self.value))         return True  diff --git a/src/_pytest/stepwise.py b/src/_pytest/stepwise.py-- a/src/_pytest/stepwise.py++ b/src/_pytest/stepwise.py


Question: def pytest_runtest_logreport(self, report):         # Skip this hook if plugin is not active or the test is xfailed.        if not self.active or "xfail" in report.keywords:        if not self.active:             return          if report.failed:


Question: patchings = getattr(function, "patchings", None)     if not patchings:         return 0    mock_modules = [sys.modules.get("mock"), sys.modules.get("unittest.mock")]    if any(mock_modules):        sentinels = [m.DEFAULT for m in mock_modules if m is not None]        return len(            [p for p in patchings if not p.attribute_name and p.new in sentinels]        )    return len(patchings)    mock_sentinel = getattr(sys.modules.get("mock"), "DEFAULT", object())    ut_mock_sentinel = getattr(sys.modules.get("unittest.mock"), "DEFAULT", object())    return len(        [            p            for p in patchings            if not p.attribute_name            and (p.new is mock_sentinel or p.new is ut_mock_sentinel)        ]    )   def getfuncargnames(function, is_method=False, cls=None):

ValueError when collecting tests that patch an array <!-- Thanks for submitting an issue! Here's a quick checklist for what to provide: --I'm trying to run pytest with a test file that contains patch where "new" is an array, for example: from import patch ([-5.5, 3.0])) ... This works fine with pytest 3.1.3, but when using pytest 3.6.0 the following error is received upon collection: Seems like a bug, that was introduced by the following fix: when using like: ([-5.5, 3.0])), p.new is an array and the check: "p.new in sentinels" returns an array of booleans instead of a boolean which causes the ValueError.


Question: """ import functools import osimport platform import re import sys import timefrom datetime import datetime  import py

Hostname and timestamp properties in generated JUnit XML reports Pytest enables generating JUnit XML reports of the tests. However, there are some properties missing, specifically and from the XML element. Is there an option to include them? Example of a pytest XML report: Example of a junit XML report:


Question: skipped=self.stats["skipped"],             tests=numtests,             time="%.3f" % suite_time_delta,<ins>            timestamp=datetime.fromtimestamp(self.suite_start_time).isoformat(),            hostname=platform.node(),</ins>         )         logfile.write(Junit.testsuites([suite_node]).unicode(indent=0))         logfile.close()


Question: import py <ins>from _pytest._code.code import ExceptionChainRepr</ins> from _pytest._code.code import ExceptionInfo from _pytest._code.code import ReprEntry from _pytest._code.code import ReprEntryNative

exception serialization should include chained exceptions given some simple tests: when run without xdist it displays whole exception trace nicely : but when run with xdist (), it just displays the last one: my setup:


Question: Experimental method.         """        def disassembled_report(rep):            reprtraceback = rep.longrepr.reprtraceback.__dict__.copy()            reprcrash = rep.longrepr.reprcrash.__dict__.copy()            new_entries = []            for entry in reprtraceback["reprentries"]:                entry_data = {                    "type": type(entry).__name__,                    "data": entry.__dict__.copy(),                }                for key, value in entry_data["data"].items():                    if hasattr(value, "__dict__"):                        entry_data["data"][key] = value.__dict__.copy()                new_entries.append(entry_data)            reprtraceback["reprentries"] = new_entries            return {                "reprcrash": reprcrash,                "reprtraceback": reprtraceback,                "sections": rep.longrepr.sections,            }        d = self.__dict__.copy()        if hasattr(self.longrepr, "toterminal"):            if hasattr(self.longrepr, "reprtraceback") and hasattr(                self.longrepr, "reprcrash"            ):                d["longrepr"] = disassembled_report(self)            else:                d["longrepr"] = str(self.longrepr)        else:            d["longrepr"] = self.longrepr        for name in d:            if isinstance(d[name], (py.path.local, Path)):                d[name] = str(d[name])            elif name == "result":                d[name] = None  # for now        return d        return _report_to_json(self)      @classmethod     def _from_json(cls, reportdict):


Question: Experimental method.         """        if reportdict["longrepr"]:            if (                "reprcrash" in reportdict["longrepr"]                and "reprtraceback" in reportdict["longrepr"]            ):                reprtraceback = reportdict["longrepr"]["reprtraceback"]                reprcrash = reportdict["longrepr"]["reprcrash"]                unserialized_entries = []                reprentry = None                for entry_data in reprtraceback["reprentries"]:                    data = entry_data["data"]                    entry_type = entry_data["type"]                    if entry_type == "ReprEntry":                        reprfuncargs = None                        reprfileloc = None                        reprlocals = None                        if data["reprfuncargs"]:                            reprfuncargs = ReprFuncArgs(**data["reprfuncargs"])                        if data["reprfileloc"]:                            reprfileloc = ReprFileLocation(**data["reprfileloc"])                        if data["reprlocals"]:                            reprlocals = ReprLocals(data["reprlocals"]["lines"])                        reprentry = ReprEntry(                            lines=data["lines"],                            reprfuncargs=reprfuncargs,                            reprlocals=reprlocals,                            filelocrepr=reprfileloc,                            style=data["style"],                        )                    elif entry_type == "ReprEntryNative":                        reprentry = ReprEntryNative(data["lines"])                    else:                        _report_unserialization_failure(entry_type, cls, reportdict)                    unserialized_entries.append(reprentry)                reprtraceback["reprentries"] = unserialized_entries                exception_info = ReprExceptionInfo(                    reprtraceback=ReprTraceback(**reprtraceback),                    reprcrash=ReprFileLocation(**reprcrash),                )                for section in reportdict["longrepr"]["sections"]:                    exception_info.addsection(*section)                reportdict["longrepr"] = exception_info        return cls(**reportdict)        kwargs = _report_kwargs_from_json(reportdict)        return cls(**kwargs)   def _report_unserialization_failure(type_name, report_class, reportdict):


Question: assert False, "Unknown report_type unserialize data: {}".format(             data["_report_type"]         )<ins>def _report_to_json(report):    """    This was originally the serialize_report() function from xdist (ca03269).    Returns the contents of this report as a dict of builtin entries, suitable for    serialization.    """    def serialize_repr_entry(entry):        entry_data = {"type": type(entry).__name__, "data": entry.__dict__.copy()}        for key, value in entry_data["data"].items():            if hasattr(value, "__dict__"):                entry_data["data"][key] = value.__dict__.copy()        return entry_data    def serialize_repr_traceback(reprtraceback):        result = reprtraceback.__dict__.copy()        result["reprentries"] = [            serialize_repr_entry(x) for x in reprtraceback.reprentries        ]        return result    def serialize_repr_crash(reprcrash):        return reprcrash.__dict__.copy()    def serialize_longrepr(rep):        result = {            "reprcrash": serialize_repr_crash(rep.longrepr.reprcrash),            "reprtraceback": serialize_repr_traceback(rep.longrepr.reprtraceback),            "sections": rep.longrepr.sections,        }        if isinstance(rep.longrepr, ExceptionChainRepr):            result["chain"] = []            for repr_traceback, repr_crash, description in rep.longrepr.chain:                result["chain"].append(                    (                        serialize_repr_traceback(repr_traceback),                        serialize_repr_crash(repr_crash),                        description,                    )                )        else:            result["chain"] = None        return result    d = report.__dict__.copy()    if hasattr(report.longrepr, "toterminal"):        if hasattr(report.longrepr, "reprtraceback") and hasattr(            report.longrepr, "reprcrash"        ):            d["longrepr"] = serialize_longrepr(report)        else:            d["longrepr"] = str(report.longrepr)    else:        d["longrepr"] = report.longrepr    for name in d:        if isinstance(d[name], (py.path.local, Path)):            d[name] = str(d[name])        elif name == "result":            d[name] = None  # for now    return ddef _report_kwargs_from_json(reportdict):    """    This was originally the serialize_report() function from xdist (ca03269).    Returns **kwargs that can be used to construct a TestReport or CollectReport instance.    """    def deserialize_repr_entry(entry_data):        data = entry_data["data"]        entry_type = entry_data["type"]        if entry_type == "ReprEntry":            reprfuncargs = None            reprfileloc = None            reprlocals = None            if data["reprfuncargs"]:                reprfuncargs = ReprFuncArgs(**data["reprfuncargs"])            if data["reprfileloc"]:                reprfileloc = ReprFileLocation(**data["reprfileloc"])            if data["reprlocals"]:                reprlocals = ReprLocals(data["reprlocals"]["lines"])            reprentry = ReprEntry(                lines=data["lines"],                reprfuncargs=reprfuncargs,                reprlocals=reprlocals,                filelocrepr=reprfileloc,                style=data["style"],            )        elif entry_type == "ReprEntryNative":            reprentry = ReprEntryNative(data["lines"])        else:            _report_unserialization_failure(entry_type, TestReport, reportdict)        return reprentry    def deserialize_repr_traceback(repr_traceback_dict):        repr_traceback_dict["reprentries"] = [            deserialize_repr_entry(x) for x in repr_traceback_dict["reprentries"]        ]        return ReprTraceback(**repr_traceback_dict)    def deserialize_repr_crash(repr_crash_dict):        return ReprFileLocation(**repr_crash_dict)    if (        reportdict["longrepr"]        and "reprcrash" in reportdict["longrepr"]        and "reprtraceback" in reportdict["longrepr"]    ):        reprtraceback = deserialize_repr_traceback(            reportdict["longrepr"]["reprtraceback"]        )        reprcrash = deserialize_repr_crash(reportdict["longrepr"]["reprcrash"])        if reportdict["longrepr"]["chain"]:            chain = []            for repr_traceback_data, repr_crash_data, description in reportdict[                "longrepr"            ]["chain"]:                chain.append(                    (                        deserialize_repr_traceback(repr_traceback_data),                        deserialize_repr_crash(repr_crash_data),                        description,                    )                )            exception_info = ExceptionChainRepr(chain)        else:            exception_info = ReprExceptionInfo(reprtraceback, reprcrash)        for section in reportdict["longrepr"]["sections"]:            exception_info.addsection(*section)        reportdict["longrepr"] = exception_info    return reportdict</ins>


Question: from urllib.request import urlopen     from urllib.parse import urlencode     params = {"code": contents, "lexer": "python3", "expiry": "1week"}    params = {"code": contents, "lexer": "text", "expiry": "1week"}     url = "https://bpaste.net"     try:         response = (

Lexer "python3" in --pastebin feature causes HTTP errors The option currently submits the output of to using : For some , this will raise a "HTTP Error 400: Bad Request". As an example: with the attached . This is the underlying cause for the problems mentioned in . The call goes through fine if is changed from to . This would seem like the right thing to do in any case: the console output of a run that is being uploaded is not Python code, but arbitrary text.


Question: from urllib.request import urlopen         from urllib.parse import urlencode     params = {        "code": contents,        "lexer": "python3" if sys.version_info[0] >= 3 else "python",        "expiry": "1week",    }    params = {"code": contents, "lexer": "text", "expiry": "1week"}     url = "https://bpaste.net"     response = urlopen(url, data=urlencode(params).encode("ascii")).read()     m = re.search(r'href="/raw/(\w+)"', response.decode("utf-8"))


Question: from _pytest.compat import importlib_metadata from _pytest.outcomes import fail from _pytest.outcomes import Skipped<del>from _pytest.pathlib import unique_path</del> from _pytest.warning_types import PytestConfigWarning  hookimpl = HookimplMarker("pytest")

2 ImportError while loading conftest (windows import folder casing issues) 1 works fine. after upgrade to 5.1.2, the path was converted to lower case


Question: """         current = py.path.local()         self._confcutdir = (            unique_path(current.join(namespace.confcutdir, abs=True))            current.join(namespace.confcutdir, abs=True)             if namespace.confcutdir             else None         )


Question: else:             directory = path         directory = unique_path(directory)         # XXX these days we may rather want to use config.rootdir         # and allow users to opt into looking into the rootdir parent         # directories instead of requiring to specify confcutdir         clist = []        for parent in directory.parts():        for parent in directory.realpath().parts():             if self._confcutdir and self._confcutdir.relto(parent):                 continue             conftestpath = parent.join("conftest.py")


Question: raise KeyError(name)      def _importconftest(self, conftestpath):        # Use realpath to avoid loading the same conftest twice        # Use a resolved Path object as key to avoid loading the same conftest twice         # with build systems that create build directories containing         # symlinks to actual files.        conftestpath = unique_path(conftestpath)        # Using Path().resolve() is better than py.path.realpath because        # it resolves to the correct path/drive in case-insensitive file systems (#5792)        key = Path(str(conftestpath)).resolve()         try:            return self._conftestpath2mod[conftestpath]            return self._conftestpath2mod[key]         except KeyError:             pkgpath = conftestpath.pypkgpath()             if pkgpath is None:


Question: raise ConftestImportFailure(conftestpath, sys.exc_info())              self._conftest_plugins.add(mod)            self._conftestpath2mod[conftestpath] = mod            self._conftestpath2mod[key] = mod             dirpath = conftestpath.dirpath()             if dirpath in self._dirpath2confmods:                 for path, mods in self._dirpath2confmods.items():diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py-- a/src/_pytest/pathlib.py++ b/src/_pytest/pathlib.py


Question: from os.path import expanduser from os.path import expandvars from os.path import isabs<del>from os.path import normcase</del> from os.path import sep from posixpath import sep as posix_sep


Question: def parts(s):     parts = s.split(sep)     return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))}<del>def unique_path(path):    """Returns a unique path in case-insensitive (but case-preserving) file    systems such as Windows.    This is needed only for ``py.path.local``; ``pathlib.Path`` handles this    natively with ``resolve()``."""    return type(path)(normcase(str(path.realpath())))</del>


Question: "assertion",     "junitxml",     "resultlog",    "report_log",     "doctest",     "cacheprovider",     "freeze_support",diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py-- a/src/_pytest/hookspec.py++ b/src/_pytest/hookspec.py

Provide an alternative to --result-log After discussion in , mentions he would like to provide a replacement to in the core before removing it (). This potentially is an easy contribution given that we have the plugin already which can be used as a starting point. I would like for us to discuss how that "log file" will look like in this issue. I understand the rationale is to provide a line-based log file, which can be parsed using standard tools. I have used a log file in the past where each line was a JSON object, something like: pytest would then write each line to the file during , like does now. I suppose we also want to add an option to replay the tests in a log file, so users can reproduce a previous run that was saved to a log? you also mentioned that would not be an appropriate replacement, can you elaborate on why?


Question: @hookspec(firstresult=True) def pytest_report_to_serializable(config, report):     """<del>    .. warning::        This hook is experimental and subject to change between pytest releases, even        bug fixes.        The intent is for this to be used by plugins maintained by the core-devs, such        as ``pytest-xdist``, ``pytest-subtests``, and as a replacement for the internal        'resultlog' plugin.        In the future it might become part of the public hook API.</del>     Serializes the given report object into a data structure suitable for sending     over the wire, e.g. converted to JSON.     """


Question: @hookspec(firstresult=True) def pytest_report_from_serializable(config, data):     """    .. warning::        This hook is experimental and subject to change between pytest releases, even        bug fixes.        The intent is for this to be used by plugins maintained by the core-devs, such        as ``pytest-xdist``, ``pytest-subtests``, and as a replacement for the internal        'resultlog' plugin.        In the future it might become part of the public hook API.     Restores a report object previously serialized with pytest_report_to_serializable().     """ diff --git a/src/_pytest/report_log.py b/src/_pytest/report_log.pynew file mode 100644-- /dev/null++ b/src/_pytest/report_log.py


Question: import jsonfrom pathlib import Pathimport pytestdef pytest_addoption(parser):    group = parser.getgroup("terminal reporting", "report-log plugin options")    group.addoption(        "--report-log",        action="store",        metavar="path",        default=None,        help="Path to line-based json objects of test session events.",    )def pytest_configure(config):    report_log = config.option.report_log    if report_log and not hasattr(config, "slaveinput"):        config._report_log_plugin = ReportLogPlugin(config, Path(report_log))        config.pluginmanager.register(config._report_log_plugin)def pytest_unconfigure(config):    report_log_plugin = getattr(config, "_report_log_plugin", None)    if report_log_plugin:        report_log_plugin.close()        del config._report_log_pluginclass ReportLogPlugin:    def __init__(self, config, log_path: Path):        self._config = config        self._log_path = log_path        log_path.parent.mkdir(parents=True, exist_ok=True)        self._file = log_path.open("w", buffering=1, encoding="UTF-8")    def close(self):        if self._file is not None:            self._file.close()            self._file = None    def _write_json_data(self, data):        self._file.write(json.dumps(data) + "\n")        self._file.flush()    def pytest_sessionstart(self):        data = {"pytest_version": pytest.__version__, "$report_type": "SessionStart"}        self._write_json_data(data)    def pytest_sessionfinish(self, exitstatus):        data = {"exitstatus": exitstatus, "$report_type": "SessionFinish"}        self._write_json_data(data)    def pytest_runtest_logreport(self, report):        data = self._config.hook.pytest_report_to_serializable(            config=self._config, report=report        )        self._write_json_data(data)    def pytest_collectreport(self, report):        data = self._config.hook.pytest_report_to_serializable(            config=self._config, report=report        )        self._write_json_data(data)    def pytest_terminal_summary(self, terminalreporter):        terminalreporter.write_sep(            "-", "generated report log file: {}".format(self._log_path)        )diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py-- a/src/_pytest/reports.py++ b/src/_pytest/reports.py


Question: def pytest_report_to_serializable(report):     if isinstance(report, (TestReport, CollectReport)):         data = report._to_json()        data["_report_type"] = report.__class__.__name__        data["$report_type"] = report.__class__.__name__         return data   def pytest_report_from_serializable(data):    if "_report_type" in data:        if data["_report_type"] == "TestReport":    if "$report_type" in data:        if data["$report_type"] == "TestReport":             return TestReport._from_json(data)        elif data["_report_type"] == "CollectReport":        elif data["$report_type"] == "CollectReport":             return CollectReport._from_json(data)         assert False, "Unknown report_type unserialize data: {}".format(            data["_report_type"]            data["$report_type"]         )


Question: group.addoption(         "--collectonly",         "--collect-only",<ins>        "--co",</ins>         action="store_true",         help="only collect tests, don't execute them.",     ),

pytest --collect-only needs a one char shortcut command I find myself needing to run very often and that cli argument is a very long to type one. I do think that it would be great to allocate a character for it, not sure which one yet. Please use up/down thumbs to vote if you would find it useful or not and eventually proposing which char should be used. Clearly this is a change very easy to implement but first I want to see if others would find it useful or not. pytest --collect-only needs a one char shortcut command I find myself needing to run very often and that cli argument is a very long to type one. I do think that it would be great to allocate a character for it, not sure which one yet. Please use up/down thumbs to vote if you would find it useful or not and eventually proposing which char should be used. Clearly this is a change very easy to implement but first I want to see if others would find it useful or not.


Question: "Passing arguments to pytest.fixture() as positional arguments is deprecated - pass them "     "as a keyword argument instead." )JUNIT_XML_DEFAULT_FAMILY = PytestDeprecationWarning(    "The 'junit_family' default value will change to 'xunit2' in pytest 6.0.\n"    "Add 'junit_family=legacy' to your pytest.ini file to silence this warning and make your suite compatible.")diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py-- a/src/_pytest/junitxml.py++ b/src/_pytest/junitxml.py

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


Question: import py  import pytestfrom _pytest import deprecated from _pytest import nodes from _pytest.config import filename_argfrom _pytest.warnings import _issue_warning_captured   class Junit(py.xml.Namespace):


Question: 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: 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: @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."""

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):


Question: 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: 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: break             parts.append(name)         parts.reverse()        s = ".".join(parts)        return s.replace(".[", "[")        return ".".join(parts)      def reportinfo(self):         # XXX caching?

'.[' 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.


Question: 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

--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:


Question: 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):

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:


Question: 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()

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


Question: _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: 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.  """

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.


Question: 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(

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


Question: 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

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?


Question: 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: 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

-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!


Question: 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: 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: 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: 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: 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

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


Question: 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: """ discovery and running of std-library "unittest" style tests. """<del>import functools</del> import sys import traceback


Question: _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: 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: # 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

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.


Question: 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):

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:


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

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) ?


Question: 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: 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:

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:


Question: 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: 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."""

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.


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


Question: 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()

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.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: # 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: 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: 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: @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: # 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: 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: 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":

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.


Question: @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: "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: )  <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

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


Question: 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: 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: import atexit<ins>import contextlib</ins> import fnmatch import itertools import os

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:


Question: 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: 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:

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 .


Question: 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: 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

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.


Question: 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"     )

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


Question: # 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         )

--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


Question: 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()

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.


Question: @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)

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


Question: 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: 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

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


Question: 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:

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) .


Question: 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:

\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.


Question: 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:

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?


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

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.


Question: 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:

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


Question: """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:

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.


Question: 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: # 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