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


# 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


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:


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


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"


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:


)         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


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"


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


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


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


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:


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


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


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


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


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


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


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>


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


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


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


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


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


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:


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


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


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>


"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


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


@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


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


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"]         )


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


"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


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


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     )


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)


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


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


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(


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


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


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


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


_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())


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


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(


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


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


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


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


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)


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.


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


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


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


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


_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


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)


# 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


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


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


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


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:


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


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


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


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


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


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


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


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


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


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>


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


"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"),         }


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


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


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


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


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:


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:


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


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


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


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


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


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


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


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


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:


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


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:


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


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)


# 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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


entries = sorted(os.scandir(path), key=lambda entry: entry.name)     yield from entries     for entry in entries:        if entry.is_dir(follow_symlinks=False) and recurse(entry):        if entry.is_dir() and recurse(entry):             yield from visit(entry.path, recurse)


self._validate_plugins()         self._warn_about_skipped_plugins()         if self.known_args_namespace.strict:            self.issue_config_time_warning(                _pytest.deprecated.STRICT_OPTION, stacklevel=2            )         if self.known_args_namespace.confcutdir is None and self.inipath is not None:             confcutdir = str(self.inipath.parent)             self.known_args_namespace.confcutdir = confcutdirdiff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py-- a/src/_pytest/deprecated.py++ b/src/_pytest/deprecated.py


"The gethookproxy() and isinitpath() methods of FSCollector and Package are deprecated; "     "use self.session.gethookproxy() and self.session.isinitpath() instead. " )STRICT_OPTION = PytestDeprecationWarning(    "The --strict option is deprecated, use --strict-markers instead.")diff --git a/src/_pytest/main.py b/src/_pytest/main.py-- a/src/_pytest/main.py++ b/src/_pytest/main.py


)     group._addoption(         "--strict-markers",        "--strict",         action="store_true",         help="markers not registered in the `markers` section of the configuration file raise errors.",     )    group._addoption(        "--strict", action="store_true", help="(deprecated) alias to --strict-markers.",    )     group._addoption(         "-c",         metavar="file",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


# If the name is not in the set of known marks after updating,             # then it really is time to issue a warning or an error.             if name not in self._markers:                if self._config.option.strict_markers:                if self._config.option.strict_markers or self._config.option.strict:                     fail(                         f"{name!r} not found in `markers` configuration option",                         pytrace=False,


self._notfound.append((report_arg, col))                     continue                 # If __init__.py was the only file requested, then the matched node will be                # the corresponding Package, and the first yielded item will be the __init__                # Module itself, so just use that. If this special case isn't taken, then all                # the files in the package will be yielded.                if argpath.basename == "__init__.py":                    assert isinstance(matching[0], nodes.Collector)                # If __init__.py was the only file requested, then the matched                # node will be the corresponding Package (by default), and the                # first yielded item will be the __init__ Module itself, so                # just use that. If this special case isn't taken, then all the                # files in the package will be yielded.                if argpath.basename == "__init__.py" and isinstance(                    matching[0], Package                ):                     try:                         yield next(iter(matching[0].collect()))                     except StopIteration:


"""Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding         teardown functions (#517)."""         class_fixture = _make_xunit_fixture(            cls, "setUpClass", "tearDownClass", scope="class", pass_self=False            cls,            "setUpClass",            "tearDownClass",            "doClassCleanups",            scope="class",            pass_self=False,         )         if class_fixture:             cls.__pytest_class_setup = class_fixture  # type: ignore[attr-defined]          method_fixture = _make_xunit_fixture(            cls, "setup_method", "teardown_method", scope="function", pass_self=True            cls,            "setup_method",            "teardown_method",            None,            scope="function",            pass_self=True,         )         if method_fixture:             cls.__pytest_method_setup = method_fixture  # type: ignore[attr-defined]   def _make_xunit_fixture(    obj: type, setup_name: str, teardown_name: str, scope: "_Scope", pass_self: bool    obj: type,    setup_name: str,    teardown_name: str,    cleanup_name: Optional[str],    scope: "_Scope",    pass_self: bool, ):     setup = getattr(obj, setup_name, None)     teardown = getattr(obj, teardown_name, None)     if setup is None and teardown is None:         return None     if cleanup_name:        cleanup = getattr(obj, cleanup_name, lambda *args: None)    else:        def cleanup(*args):            pass     @pytest.fixture(         scope=scope,         autouse=True,


reason = self.__unittest_skip_why__             pytest.skip(reason)         if setup is not None:            if pass_self:                setup(self, request.function)            else:                setup()            try:                if pass_self:                    setup(self, request.function)                else:                    setup()            # unittest does not call the cleanup function for every BaseException, so we            # follow this here.            except Exception:                if pass_self:                    cleanup(self)                else:                    cleanup()                raise         yield        if teardown is not None:        try:            if teardown is not None:                if pass_self:                    teardown(self, request.function)                else:                    teardown()        finally:             if pass_self:                teardown(self, request.function)                cleanup(self)             else:                teardown()                cleanup()      return fixture


"warnings",     "logging",     "reports",    *(["unraisableexception", "threadexception"] if sys.version_info >= (3, 8) else []),     "faulthandler", ) diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py-- a/src/_pytest/pytester.py++ b/src/_pytest/pytester.py


stderr=f2,                 close_fds=(sys.platform != "win32"),             )            if isinstance(stdin, bytes):            if popen.stdin is not None:                 popen.stdin.close()              def handle_timeout() -> None:diff --git a/src/_pytest/threadexception.py b/src/_pytest/threadexception.pynew file mode 100644-- /dev/null++ b/src/_pytest/threadexception.py


import threadingimport tracebackimport warningsfrom types import TracebackTypefrom typing import Anyfrom typing import Callablefrom typing import Generatorfrom typing import Optionalfrom typing import Typeimport pytest# Copied from cpython/Lib/test/support/threading_helper.py, with modifications.class catch_threading_exception:    """Context manager catching threading.Thread exception using    threading.excepthook.    Storing exc_value using a custom hook can create a reference cycle. The    reference cycle is broken explicitly when the context manager exits.    Storing thread using a custom hook can resurrect it if it is set to an    object which is being finalized. Exiting the context manager clears the    stored object.    Usage:        with threading_helper.catch_threading_exception() as cm:            # code spawning a thread which raises an exception            ...            # check the thread exception: use cm.args            ...        # cm.args attribute no longer exists at this point        # (to break a reference cycle)    """    def __init__(self) -> None:        # See https://github.com/python/typeshed/issues/4767 regarding the underscore.        self.args: Optional["threading._ExceptHookArgs"] = None        self._old_hook: Optional[Callable[["threading._ExceptHookArgs"], Any]] = None    def _hook(self, args: "threading._ExceptHookArgs") -> None:        self.args = args    def __enter__(self) -> "catch_threading_exception":        self._old_hook = threading.excepthook        threading.excepthook = self._hook        return self    def __exit__(        self,        exc_type: Optional[Type[BaseException]],        exc_val: Optional[BaseException],        exc_tb: Optional[TracebackType],    ) -> None:        assert self._old_hook is not None        threading.excepthook = self._old_hook        self._old_hook = None        del self.argsdef thread_exception_runtest_hook() -> Generator[None, None, None]:    with catch_threading_exception() as cm:        yield        if cm.args:            if cm.args.thread is not None:                thread_name = cm.args.thread.name            else:                thread_name = "<unknown>"            msg = f"Exception in thread {thread_name}\n\n"            msg += "".join(                traceback.format_exception(                    cm.args.exc_type, cm.args.exc_value, cm.args.exc_traceback,                )            )            warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))@pytest.hookimpl(hookwrapper=True, trylast=True)def pytest_runtest_setup() -> Generator[None, None, None]:    yield from thread_exception_runtest_hook()@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_call() -> Generator[None, None, None]:    yield from thread_exception_runtest_hook()@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_teardown() -> Generator[None, None, None]:    yield from thread_exception_runtest_hook()diff --git a/src/_pytest/unraisableexception.py b/src/_pytest/unraisableexception.pynew file mode 100644-- /dev/null++ b/src/_pytest/unraisableexception.py


import sysimport tracebackimport warningsfrom types import TracebackTypefrom typing import Anyfrom typing import Callablefrom typing import Generatorfrom typing import Optionalfrom typing import Typeimport pytest# Copied from cpython/Lib/test/support/__init__.py, with modifications.class catch_unraisable_exception:    """Context manager catching unraisable exception using sys.unraisablehook.    Storing the exception value (cm.unraisable.exc_value) creates a reference    cycle. The reference cycle is broken explicitly when the context manager    exits.    Storing the object (cm.unraisable.object) can resurrect it if it is set to    an object which is being finalized. Exiting the context manager clears the    stored object.    Usage:        with catch_unraisable_exception() as cm:            # code creating an "unraisable exception"            ...            # check the unraisable exception: use cm.unraisable            ...        # cm.unraisable attribute no longer exists at this point        # (to break a reference cycle)    """    def __init__(self) -> None:        self.unraisable: Optional["sys.UnraisableHookArgs"] = None        self._old_hook: Optional[Callable[["sys.UnraisableHookArgs"], Any]] = None    def _hook(self, unraisable: "sys.UnraisableHookArgs") -> None:        # Storing unraisable.object can resurrect an object which is being        # finalized. Storing unraisable.exc_value creates a reference cycle.        self.unraisable = unraisable    def __enter__(self) -> "catch_unraisable_exception":        self._old_hook = sys.unraisablehook        sys.unraisablehook = self._hook        return self    def __exit__(        self,        exc_type: Optional[Type[BaseException]],        exc_val: Optional[BaseException],        exc_tb: Optional[TracebackType],    ) -> None:        assert self._old_hook is not None        sys.unraisablehook = self._old_hook        self._old_hook = None        del self.unraisabledef unraisable_exception_runtest_hook() -> Generator[None, None, None]:    with catch_unraisable_exception() as cm:        yield        if cm.unraisable:            if cm.unraisable.err_msg is not None:                err_msg = cm.unraisable.err_msg            else:                err_msg = "Exception ignored in"            msg = f"{err_msg}: {cm.unraisable.object!r}\n\n"            msg += "".join(                traceback.format_exception(                    cm.unraisable.exc_type,                    cm.unraisable.exc_value,                    cm.unraisable.exc_traceback,                )            )            warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_setup() -> Generator[None, None, None]:    yield from unraisable_exception_runtest_hook()@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_call() -> Generator[None, None, None]:    yield from unraisable_exception_runtest_hook()@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_teardown() -> Generator[None, None, None]:    yield from unraisable_exception_runtest_hook()diff --git a/src/_pytest/warning_types.py b/src/_pytest/warning_types.py-- a/src/_pytest/warning_types.py++ b/src/_pytest/warning_types.py


__module__ = "pytest"  @finalclass PytestUnraisableExceptionWarning(PytestWarning):    """An unraisable exception was reported.    Unraisable exceptions are exceptions raised in :meth:`__del__ <object.__del__>`    implementations and similar situations when the exception cannot be raised    as normal.    """    __module__ = "pytest"@finalclass PytestUnhandledThreadExceptionWarning(PytestWarning):    """An unhandled exception occurred in a :class:`~threading.Thread`.    Such exceptions don't propagate normally.    """    __module__ = "pytest" _W = TypeVar("_W", bound=PytestWarning)  diff --git a/src/pytest/__init__.py b/src/pytest/__init__.py-- a/src/pytest/__init__.py++ b/src/pytest/__init__.py


from _pytest.warning_types import PytestDeprecationWarning from _pytest.warning_types import PytestExperimentalApiWarning from _pytest.warning_types import PytestUnhandledCoroutineWarningfrom _pytest.warning_types import PytestUnhandledThreadExceptionWarning from _pytest.warning_types import PytestUnknownMarkWarningfrom _pytest.warning_types import PytestUnraisableExceptionWarning from _pytest.warning_types import PytestWarning  set_trace = __pytestPDB.set_trace


"PytestDeprecationWarning",     "PytestExperimentalApiWarning",     "PytestUnhandledCoroutineWarning",    "PytestUnhandledThreadExceptionWarning",     "PytestUnknownMarkWarning",    "PytestUnraisableExceptionWarning",     "PytestWarning",     "raises",     "register_assert_rewrite",


"""  # -------------------------------------------------------------------------# Hooks for influencing skipping# -------------------------------------------------------------------------def pytest_markeval_namespace(config: "Config") -> Dict[str, Any]:    """Called when constructing the globals dictionary used for    evaluating string conditions in xfail/skipif markers.    This is useful when the condition for a marker requires    objects that are expensive or impossible to obtain during    collection time, which is required by normal boolean    conditions.    .. versionadded:: 6.2    :param _pytest.config.Config config: The pytest config object.    :returns: A dictionary of additional globals to add.    """ # ------------------------------------------------------------------------- # error handling and internal debugging hooks # -------------------------------------------------------------------------diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py-- a/src/_pytest/skipping.py++ b/src/_pytest/skipping.py


import platform import sys import traceback<ins>from collections.abc import Mapping</ins> from typing import Generator from typing import Optional from typing import Tuple


"platform": platform,             "config": item.config,         }<ins>        for dictionary in reversed(            item.ihook.pytest_markeval_namespace(config=item.config)        ):            if not isinstance(dictionary, Mapping):                raise ValueError(                    "pytest_markeval_namespace() needs to return a dict, got {!r}".format(                        dictionary                    )                )            globals_.update(dictionary)</ins>         if hasattr(item, "obj"):             globals_.update(item.obj.__globals__)  # type: ignore[attr-defined]         try:


@staticmethod     def _get_stderr_fileno():         try:            return sys.stderr.fileno()            fileno = sys.stderr.fileno()            # The Twisted Logger will return an invalid file descriptor since it is not backed            # by an FD. So, let's also forward this to the same code path as with pytest-xdist.            if fileno == -1:                raise AttributeError()            return fileno         except (AttributeError, io.UnsupportedOperation):             # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.             # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors


# use a sub-directory in the temproot to speed-up             # make_numbered_dir() call             rootdir = temproot.joinpath(f"pytest-of-{user}")            rootdir.mkdir(exist_ok=True)            try:                rootdir.mkdir(exist_ok=True)            except OSError:                # getuser() likely returned illegal characters for the platform, use unknown back off mechanism                rootdir = temproot.joinpath("pytest-of-unknown")                rootdir.mkdir(exist_ok=True)             basetemp = make_numbered_dir_with_cleanup(                 prefix="pytest-", root=rootdir, keep=3, lock_timeout=LOCK_TIMEOUT             )


autouse=True,             scope="module",             # Use a unique name to speed up lookup.            name=f"xunit_setup_module_fixture_{self.obj.__name__}",            name=f"_xunit_setup_module_fixture_{self.obj.__name__}",         )         def xunit_setup_module_fixture(request) -> Generator[None, None, None]:             if setup_module is not None:


autouse=True,             scope="function",             # Use a unique name to speed up lookup.            name=f"xunit_setup_function_fixture_{self.obj.__name__}",            name=f"_xunit_setup_function_fixture_{self.obj.__name__}",         )         def xunit_setup_function_fixture(request) -> Generator[None, None, None]:             if request.instance is not None:


autouse=True,             scope="class",             # Use a unique name to speed up lookup.            name=f"xunit_setup_class_fixture_{self.obj.__qualname__}",            name=f"_xunit_setup_class_fixture_{self.obj.__qualname__}",         )         def xunit_setup_class_fixture(cls) -> Generator[None, None, None]:             if setup_class is not None: