pytest

pytest: unit and functional testing with Python.

  1# PYTHON_ARGCOMPLETE_OK
  2"""pytest: unit and functional testing with Python."""
  3
  4from _pytest import __version__
  5from _pytest import version_tuple
  6from _pytest._code import ExceptionInfo
  7from _pytest.assertion import register_assert_rewrite
  8from _pytest.cacheprovider import Cache
  9from _pytest.capture import CaptureFixture
 10from _pytest.config import cmdline
 11from _pytest.config import Config
 12from _pytest.config import console_main
 13from _pytest.config import ExitCode
 14from _pytest.config import hookimpl
 15from _pytest.config import hookspec
 16from _pytest.config import main
 17from _pytest.config import PytestPluginManager
 18from _pytest.config import UsageError
 19from _pytest.config.argparsing import OptionGroup
 20from _pytest.config.argparsing import Parser
 21from _pytest.debugging import pytestPDB as __pytestPDB
 22from _pytest.doctest import DoctestItem
 23from _pytest.fixtures import fixture
 24from _pytest.fixtures import FixtureDef
 25from _pytest.fixtures import FixtureLookupError
 26from _pytest.fixtures import FixtureRequest
 27from _pytest.fixtures import yield_fixture
 28from _pytest.freeze_support import freeze_includes
 29from _pytest.legacypath import TempdirFactory
 30from _pytest.legacypath import Testdir
 31from _pytest.logging import LogCaptureFixture
 32from _pytest.main import Dir
 33from _pytest.main import Session
 34from _pytest.mark import Mark
 35from _pytest.mark import MARK_GEN as mark
 36from _pytest.mark import MarkDecorator
 37from _pytest.mark import MarkGenerator
 38from _pytest.mark import param
 39from _pytest.monkeypatch import MonkeyPatch
 40from _pytest.nodes import Collector
 41from _pytest.nodes import Directory
 42from _pytest.nodes import File
 43from _pytest.nodes import Item
 44from _pytest.outcomes import exit
 45from _pytest.outcomes import fail
 46from _pytest.outcomes import importorskip
 47from _pytest.outcomes import skip
 48from _pytest.outcomes import xfail
 49from _pytest.pytester import HookRecorder
 50from _pytest.pytester import LineMatcher
 51from _pytest.pytester import Pytester
 52from _pytest.pytester import RecordedHookCall
 53from _pytest.pytester import RunResult
 54from _pytest.python import Class
 55from _pytest.python import Function
 56from _pytest.python import Metafunc
 57from _pytest.python import Module
 58from _pytest.python import Package
 59from _pytest.python_api import approx
 60from _pytest.python_api import raises
 61from _pytest.recwarn import deprecated_call
 62from _pytest.recwarn import WarningsRecorder
 63from _pytest.recwarn import warns
 64from _pytest.reports import CollectReport
 65from _pytest.reports import TestReport
 66from _pytest.runner import CallInfo
 67from _pytest.stash import Stash
 68from _pytest.stash import StashKey
 69from _pytest.terminal import TestShortLogReport
 70from _pytest.tmpdir import TempPathFactory
 71from _pytest.warning_types import PytestAssertRewriteWarning
 72from _pytest.warning_types import PytestCacheWarning
 73from _pytest.warning_types import PytestCollectionWarning
 74from _pytest.warning_types import PytestConfigWarning
 75from _pytest.warning_types import PytestDeprecationWarning
 76from _pytest.warning_types import PytestExperimentalApiWarning
 77from _pytest.warning_types import PytestRemovedIn9Warning
 78from _pytest.warning_types import PytestReturnNotNoneWarning
 79from _pytest.warning_types import PytestUnhandledCoroutineWarning
 80from _pytest.warning_types import PytestUnhandledThreadExceptionWarning
 81from _pytest.warning_types import PytestUnknownMarkWarning
 82from _pytest.warning_types import PytestUnraisableExceptionWarning
 83from _pytest.warning_types import PytestWarning
 84
 85
 86set_trace = __pytestPDB.set_trace
 87
 88
 89__all__ = [
 90    "__version__",
 91    "approx",
 92    "Cache",
 93    "CallInfo",
 94    "CaptureFixture",
 95    "Class",
 96    "cmdline",
 97    "Collector",
 98    "CollectReport",
 99    "Config",
100    "console_main",
101    "deprecated_call",
102    "Dir",
103    "Directory",
104    "DoctestItem",
105    "exit",
106    "ExceptionInfo",
107    "ExitCode",
108    "fail",
109    "File",
110    "fixture",
111    "FixtureDef",
112    "FixtureLookupError",
113    "FixtureRequest",
114    "freeze_includes",
115    "Function",
116    "hookimpl",
117    "HookRecorder",
118    "hookspec",
119    "importorskip",
120    "Item",
121    "LineMatcher",
122    "LogCaptureFixture",
123    "main",
124    "mark",
125    "Mark",
126    "MarkDecorator",
127    "MarkGenerator",
128    "Metafunc",
129    "Module",
130    "MonkeyPatch",
131    "OptionGroup",
132    "Package",
133    "param",
134    "Parser",
135    "PytestAssertRewriteWarning",
136    "PytestCacheWarning",
137    "PytestCollectionWarning",
138    "PytestConfigWarning",
139    "PytestDeprecationWarning",
140    "PytestExperimentalApiWarning",
141    "PytestRemovedIn9Warning",
142    "PytestReturnNotNoneWarning",
143    "Pytester",
144    "PytestPluginManager",
145    "PytestUnhandledCoroutineWarning",
146    "PytestUnhandledThreadExceptionWarning",
147    "PytestUnknownMarkWarning",
148    "PytestUnraisableExceptionWarning",
149    "PytestWarning",
150    "raises",
151    "RecordedHookCall",
152    "register_assert_rewrite",
153    "RunResult",
154    "Session",
155    "set_trace",
156    "skip",
157    "Stash",
158    "StashKey",
159    "version_tuple",
160    "TempdirFactory",
161    "TempPathFactory",
162    "Testdir",
163    "TestReport",
164    "TestShortLogReport",
165    "UsageError",
166    "WarningsRecorder",
167    "warns",
168    "xfail",
169    "yield_fixture",
170]
__version__ = '8.2.0'
def approx( expected, rel=None, abs=None, nan_ok: bool = False) -> _pytest.python_api.ApproxBase:
519def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
520    """Assert that two numbers (or two ordered sequences of numbers) are equal to each other
521    within some tolerance.
522
523    Due to the :doc:`python:tutorial/floatingpoint`, numbers that we
524    would intuitively expect to be equal are not always so::
525
526        >>> 0.1 + 0.2 == 0.3
527        False
528
529    This problem is commonly encountered when writing tests, e.g. when making
530    sure that floating-point values are what you expect them to be.  One way to
531    deal with this problem is to assert that two floating-point numbers are
532    equal to within some appropriate tolerance::
533
534        >>> abs((0.1 + 0.2) - 0.3) < 1e-6
535        True
536
537    However, comparisons like this are tedious to write and difficult to
538    understand.  Furthermore, absolute comparisons like the one above are
539    usually discouraged because there's no tolerance that works well for all
540    situations.  ``1e-6`` is good for numbers around ``1``, but too small for
541    very big numbers and too big for very small ones.  It's better to express
542    the tolerance as a fraction of the expected value, but relative comparisons
543    like that are even more difficult to write correctly and concisely.
544
545    The ``approx`` class performs floating-point comparisons using a syntax
546    that's as intuitive as possible::
547
548        >>> from pytest import approx
549        >>> 0.1 + 0.2 == approx(0.3)
550        True
551
552    The same syntax also works for ordered sequences of numbers::
553
554        >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
555        True
556
557    ``numpy`` arrays::
558
559        >>> import numpy as np                                                          # doctest: +SKIP
560        >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP
561        True
562
563    And for a ``numpy`` array against a scalar::
564
565        >>> import numpy as np                                         # doctest: +SKIP
566        >>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3) # doctest: +SKIP
567        True
568
569    Only ordered sequences are supported, because ``approx`` needs
570    to infer the relative position of the sequences without ambiguity. This means
571    ``sets`` and other unordered sequences are not supported.
572
573    Finally, dictionary *values* can also be compared::
574
575        >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6})
576        True
577
578    The comparison will be true if both mappings have the same keys and their
579    respective values match the expected tolerances.
580
581    **Tolerances**
582
583    By default, ``approx`` considers numbers within a relative tolerance of
584    ``1e-6`` (i.e. one part in a million) of its expected value to be equal.
585    This treatment would lead to surprising results if the expected value was
586    ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``.
587    To handle this case less surprisingly, ``approx`` also considers numbers
588    within an absolute tolerance of ``1e-12`` of its expected value to be
589    equal.  Infinity and NaN are special cases.  Infinity is only considered
590    equal to itself, regardless of the relative tolerance.  NaN is not
591    considered equal to anything by default, but you can make it be equal to
592    itself by setting the ``nan_ok`` argument to True.  (This is meant to
593    facilitate comparing arrays that use NaN to mean "no data".)
594
595    Both the relative and absolute tolerances can be changed by passing
596    arguments to the ``approx`` constructor::
597
598        >>> 1.0001 == approx(1)
599        False
600        >>> 1.0001 == approx(1, rel=1e-3)
601        True
602        >>> 1.0001 == approx(1, abs=1e-3)
603        True
604
605    If you specify ``abs`` but not ``rel``, the comparison will not consider
606    the relative tolerance at all.  In other words, two numbers that are within
607    the default relative tolerance of ``1e-6`` will still be considered unequal
608    if they exceed the specified absolute tolerance.  If you specify both
609    ``abs`` and ``rel``, the numbers will be considered equal if either
610    tolerance is met::
611
612        >>> 1 + 1e-8 == approx(1)
613        True
614        >>> 1 + 1e-8 == approx(1, abs=1e-12)
615        False
616        >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
617        True
618
619    You can also use ``approx`` to compare nonnumeric types, or dicts and
620    sequences containing nonnumeric types, in which case it falls back to
621    strict equality. This can be useful for comparing dicts and sequences that
622    can contain optional values::
623
624        >>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None})
625        True
626        >>> [None, 1.0000005] == approx([None,1])
627        True
628        >>> ["foo", 1.0000005] == approx([None,1])
629        False
630
631    If you're thinking about using ``approx``, then you might want to know how
632    it compares to other good ways of comparing floating-point numbers.  All of
633    these algorithms are based on relative and absolute tolerances and should
634    agree for the most part, but they do have meaningful differences:
635
636    - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``:  True if the relative
637      tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute
638      tolerance is met.  Because the relative tolerance is calculated w.r.t.
639      both ``a`` and ``b``, this test is symmetric (i.e.  neither ``a`` nor
640      ``b`` is a "reference value").  You have to specify an absolute tolerance
641      if you want to compare to ``0.0`` because there is no tolerance by
642      default.  More information: :py:func:`math.isclose`.
643
644    - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference
645      between ``a`` and ``b`` is less that the sum of the relative tolerance
646      w.r.t. ``b`` and the absolute tolerance.  Because the relative tolerance
647      is only calculated w.r.t. ``b``, this test is asymmetric and you can
648      think of ``b`` as the reference value.  Support for comparing sequences
649      is provided by :py:func:`numpy.allclose`.  More information:
650      :std:doc:`numpy:reference/generated/numpy.isclose`.
651
652    - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b``
653      are within an absolute tolerance of ``1e-7``.  No relative tolerance is
654      considered , so this function is not appropriate for very large or very
655      small numbers.  Also, it's only available in subclasses of ``unittest.TestCase``
656      and it's ugly because it doesn't follow PEP8.  More information:
657      :py:meth:`unittest.TestCase.assertAlmostEqual`.
658
659    - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative
660      tolerance is met w.r.t. ``b`` or if the absolute tolerance is met.
661      Because the relative tolerance is only calculated w.r.t. ``b``, this test
662      is asymmetric and you can think of ``b`` as the reference value.  In the
663      special case that you explicitly specify an absolute tolerance but not a
664      relative tolerance, only the absolute tolerance is considered.
665
666    .. note::
667
668        ``approx`` can handle numpy arrays, but we recommend the
669        specialised test helpers in :std:doc:`numpy:reference/routines.testing`
670        if you need support for comparisons, NaNs, or ULP-based tolerances.
671
672        To match strings using regex, you can use
673        `Matches <https://github.com/asottile/re-assert#re_assertmatchespattern-str-args-kwargs>`_
674        from the
675        `re_assert package <https://github.com/asottile/re-assert>`_.
676
677    .. warning::
678
679       .. versionchanged:: 3.2
680
681       In order to avoid inconsistent behavior, :py:exc:`TypeError` is
682       raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons.
683       The example below illustrates the problem::
684
685           assert approx(0.1) > 0.1 + 1e-10  # calls approx(0.1).__gt__(0.1 + 1e-10)
686           assert 0.1 + 1e-10 > approx(0.1)  # calls approx(0.1).__lt__(0.1 + 1e-10)
687
688       In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)``
689       to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to
690       comparison. This is because the call hierarchy of rich comparisons
691       follows a fixed behavior. More information: :py:meth:`object.__ge__`
692
693    .. versionchanged:: 3.7.1
694       ``approx`` raises ``TypeError`` when it encounters a dict value or
695       sequence element of nonnumeric type.
696
697    .. versionchanged:: 6.1.0
698       ``approx`` falls back to strict equality for nonnumeric types instead
699       of raising ``TypeError``.
700    """
701    # Delegate the comparison to a class that knows how to deal with the type
702    # of the expected value (e.g. int, float, list, dict, numpy.array, etc).
703    #
704    # The primary responsibility of these classes is to implement ``__eq__()``
705    # and ``__repr__()``.  The former is used to actually check if some
706    # "actual" value is equivalent to the given expected value within the
707    # allowed tolerance.  The latter is used to show the user the expected
708    # value and tolerance, in the case that a test failed.
709    #
710    # The actual logic for making approximate comparisons can be found in
711    # ApproxScalar, which is used to compare individual numbers.  All of the
712    # other Approx classes eventually delegate to this class.  The ApproxBase
713    # class provides some convenient methods and overloads, but isn't really
714    # essential.
715
716    __tracebackhide__ = True
717
718    if isinstance(expected, Decimal):
719        cls: Type[ApproxBase] = ApproxDecimal
720    elif isinstance(expected, Mapping):
721        cls = ApproxMapping
722    elif _is_numpy_array(expected):
723        expected = _as_numpy_array(expected)
724        cls = ApproxNumpy
725    elif (
726        hasattr(expected, "__getitem__")
727        and isinstance(expected, Sized)
728        and not isinstance(expected, (str, bytes))
729    ):
730        cls = ApproxSequenceLike
731    elif isinstance(expected, Collection) and not isinstance(expected, (str, bytes)):
732        msg = f"pytest.approx() only supports ordered sequences, but got: {expected!r}"
733        raise TypeError(msg)
734    else:
735        cls = ApproxScalar
736
737    return cls(expected, rel, abs, nan_ok)

Assert that two numbers (or two ordered sequences of numbers) are equal to each other within some tolerance.

Due to the :doc:python:tutorial/floatingpoint, numbers that we would intuitively expect to be equal are not always so::

>>> 0.1 + 0.2 == 0.3
False

This problem is commonly encountered when writing tests, e.g. when making sure that floating-point values are what you expect them to be. One way to deal with this problem is to assert that two floating-point numbers are equal to within some appropriate tolerance::

>>> abs((0.1 + 0.2) - 0.3) < 1e-6
True

However, comparisons like this are tedious to write and difficult to understand. Furthermore, absolute comparisons like the one above are usually discouraged because there's no tolerance that works well for all situations. 1e-6 is good for numbers around 1, but too small for very big numbers and too big for very small ones. It's better to express the tolerance as a fraction of the expected value, but relative comparisons like that are even more difficult to write correctly and concisely.

The approx class performs floating-point comparisons using a syntax that's as intuitive as possible::

>>> from pytest import approx
>>> 0.1 + 0.2 == approx(0.3)
True

The same syntax also works for ordered sequences of numbers::

>>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
True

numpy arrays::

>>> import numpy as np                                                          # doctest: +SKIP
>>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP
True

And for a numpy array against a scalar::

>>> import numpy as np                                         # doctest: +SKIP
>>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3) # doctest: +SKIP
True

Only ordered sequences are supported, because approx needs to infer the relative position of the sequences without ambiguity. This means sets and other unordered sequences are not supported.

Finally, dictionary values can also be compared::

>>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6})
True

The comparison will be true if both mappings have the same keys and their respective values match the expected tolerances.

Tolerances

By default, approx considers numbers within a relative tolerance of 1e-6 (i.e. one part in a million) of its expected value to be equal. This treatment would lead to surprising results if the expected value was 0.0, because nothing but 0.0 itself is relatively close to 0.0. To handle this case less surprisingly, approx also considers numbers within an absolute tolerance of 1e-12 of its expected value to be equal. Infinity and NaN are special cases. Infinity is only considered equal to itself, regardless of the relative tolerance. NaN is not considered equal to anything by default, but you can make it be equal to itself by setting the nan_ok argument to True. (This is meant to facilitate comparing arrays that use NaN to mean "no data".)

Both the relative and absolute tolerances can be changed by passing arguments to the approx constructor::

>>> 1.0001 == approx(1)
False
>>> 1.0001 == approx(1, rel=1e-3)
True
>>> 1.0001 == approx(1, abs=1e-3)
True

If you specify abs but not rel, the comparison will not consider the relative tolerance at all. In other words, two numbers that are within the default relative tolerance of 1e-6 will still be considered unequal if they exceed the specified absolute tolerance. If you specify both abs and rel, the numbers will be considered equal if either tolerance is met::

>>> 1 + 1e-8 == approx(1)
True
>>> 1 + 1e-8 == approx(1, abs=1e-12)
False
>>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
True

You can also use approx to compare nonnumeric types, or dicts and sequences containing nonnumeric types, in which case it falls back to strict equality. This can be useful for comparing dicts and sequences that can contain optional values::

>>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None})
True
>>> [None, 1.0000005] == approx([None,1])
True
>>> ["foo", 1.0000005] == approx([None,1])
False

If you're thinking about using approx, then you might want to know how it compares to other good ways of comparing floating-point numbers. All of these algorithms are based on relative and absolute tolerances and should agree for the most part, but they do have meaningful differences:

  • math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0): True if the relative tolerance is met w.r.t. either a or b or if the absolute tolerance is met. Because the relative tolerance is calculated w.r.t. both a and b, this test is symmetric (i.e. neither a nor b is a "reference value"). You have to specify an absolute tolerance if you want to compare to 0.0 because there is no tolerance by default. More information: math.isclose().

  • numpy.isclose(a, b, rtol=1e-5, atol=1e-8): True if the difference between a and b is less that the sum of the relative tolerance w.r.t. b and the absolute tolerance. Because the relative tolerance is only calculated w.r.t. b, this test is asymmetric and you can think of b as the reference value. Support for comparing sequences is provided by numpy.allclose(). More information: :std:doc:numpy:reference/generated/numpy.isclose.

  • unittest.TestCase.assertAlmostEqual(a, b): True if a and b are within an absolute tolerance of 1e-7. No relative tolerance is considered , so this function is not appropriate for very large or very small numbers. Also, it's only available in subclasses of unittest.TestCase and it's ugly because it doesn't follow PEP8. More information: unittest.TestCase.assertAlmostEqual().

  • a == pytest.approx(b, rel=1e-6, abs=1e-12): True if the relative tolerance is met w.r.t. b or if the absolute tolerance is met. Because the relative tolerance is only calculated w.r.t. b, this test is asymmetric and you can think of b as the reference value. In the special case that you explicitly specify an absolute tolerance but not a relative tolerance, only the absolute tolerance is considered.

approx can handle numpy arrays, but we recommend the specialised test helpers in :std:doc:numpy:reference/routines.testing if you need support for comparisons, NaNs, or ULP-based tolerances.

To match strings using regex, you can use Matches from the re_assert package .

.. versionchanged:: 3.2

In order to avoid inconsistent behavior, TypeError is raised for >, >=, < and <= comparisons. The example below illustrates the problem::

assert approx(0.1) > 0.1 + 1e-10  # calls approx(0.1).__gt__(0.1 + 1e-10)
assert 0.1 + 1e-10 > approx(0.1)  # calls approx(0.1).__lt__(0.1 + 1e-10)

In the second example one expects approx(0.1).__le__(0.1 + 1e-10) to be called. But instead, approx(0.1).__lt__(0.1 + 1e-10) is used to comparison. This is because the call hierarchy of rich comparisons follows a fixed behavior. More information: object.__ge__()

Changed in version 3.7.1: approx raises TypeError when it encounters a dict value or sequence element of nonnumeric type.

Changed in version 6.1.0: approx falls back to strict equality for nonnumeric types instead of raising TypeError.

@final
@dataclasses.dataclass
class Cache:
 58@final
 59@dataclasses.dataclass
 60class Cache:
 61    """Instance of the `cache` fixture."""
 62
 63    _cachedir: Path = dataclasses.field(repr=False)
 64    _config: Config = dataclasses.field(repr=False)
 65
 66    # Sub-directory under cache-dir for directories created by `mkdir()`.
 67    _CACHE_PREFIX_DIRS = "d"
 68
 69    # Sub-directory under cache-dir for values created by `set()`.
 70    _CACHE_PREFIX_VALUES = "v"
 71
 72    def __init__(
 73        self, cachedir: Path, config: Config, *, _ispytest: bool = False
 74    ) -> None:
 75        check_ispytest(_ispytest)
 76        self._cachedir = cachedir
 77        self._config = config
 78
 79    @classmethod
 80    def for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache":
 81        """Create the Cache instance for a Config.
 82
 83        :meta private:
 84        """
 85        check_ispytest(_ispytest)
 86        cachedir = cls.cache_dir_from_config(config, _ispytest=True)
 87        if config.getoption("cacheclear") and cachedir.is_dir():
 88            cls.clear_cache(cachedir, _ispytest=True)
 89        return cls(cachedir, config, _ispytest=True)
 90
 91    @classmethod
 92    def clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None:
 93        """Clear the sub-directories used to hold cached directories and values.
 94
 95        :meta private:
 96        """
 97        check_ispytest(_ispytest)
 98        for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES):
 99            d = cachedir / prefix
100            if d.is_dir():
101                rm_rf(d)
102
103    @staticmethod
104    def cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path:
105        """Get the path to the cache directory for a Config.
106
107        :meta private:
108        """
109        check_ispytest(_ispytest)
110        return resolve_from_str(config.getini("cache_dir"), config.rootpath)
111
112    def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None:
113        """Issue a cache warning.
114
115        :meta private:
116        """
117        check_ispytest(_ispytest)
118        import warnings
119
120        from _pytest.warning_types import PytestCacheWarning
121
122        warnings.warn(
123            PytestCacheWarning(fmt.format(**args) if args else fmt),
124            self._config.hook,
125            stacklevel=3,
126        )
127
128    def _mkdir(self, path: Path) -> None:
129        self._ensure_cache_dir_and_supporting_files()
130        path.mkdir(exist_ok=True, parents=True)
131
132    def mkdir(self, name: str) -> Path:
133        """Return a directory path object with the given name.
134
135        If the directory does not yet exist, it will be created. You can use
136        it to manage files to e.g. store/retrieve database dumps across test
137        sessions.
138
139        .. versionadded:: 7.0
140
141        :param name:
142            Must be a string not containing a ``/`` separator.
143            Make sure the name contains your plugin or application
144            identifiers to prevent clashes with other cache users.
145        """
146        path = Path(name)
147        if len(path.parts) > 1:
148            raise ValueError("name is not allowed to contain path separators")
149        res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, path)
150        self._mkdir(res)
151        return res
152
153    def _getvaluepath(self, key: str) -> Path:
154        return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))
155
156    def get(self, key: str, default):
157        """Return the cached value for the given key.
158
159        If no value was yet cached or the value cannot be read, the specified
160        default is returned.
161
162        :param key:
163            Must be a ``/`` separated value. Usually the first
164            name is the name of your plugin or your application.
165        :param default:
166            The value to return in case of a cache-miss or invalid cache value.
167        """
168        path = self._getvaluepath(key)
169        try:
170            with path.open("r", encoding="UTF-8") as f:
171                return json.load(f)
172        except (ValueError, OSError):
173            return default
174
175    def set(self, key: str, value: object) -> None:
176        """Save value for the given key.
177
178        :param key:
179            Must be a ``/`` separated value. Usually the first
180            name is the name of your plugin or your application.
181        :param value:
182            Must be of any combination of basic python types,
183            including nested types like lists of dictionaries.
184        """
185        path = self._getvaluepath(key)
186        try:
187            self._mkdir(path.parent)
188        except OSError as exc:
189            self.warn(
190                f"could not create cache path {path}: {exc}",
191                _ispytest=True,
192            )
193            return
194        data = json.dumps(value, ensure_ascii=False, indent=2)
195        try:
196            f = path.open("w", encoding="UTF-8")
197        except OSError as exc:
198            self.warn(
199                f"cache could not write path {path}: {exc}",
200                _ispytest=True,
201            )
202        else:
203            with f:
204                f.write(data)
205
206    def _ensure_cache_dir_and_supporting_files(self) -> None:
207        """Create the cache dir and its supporting files."""
208        if self._cachedir.is_dir():
209            return
210
211        self._cachedir.parent.mkdir(parents=True, exist_ok=True)
212        with tempfile.TemporaryDirectory(
213            prefix="pytest-cache-files-",
214            dir=self._cachedir.parent,
215        ) as newpath:
216            path = Path(newpath)
217            with open(path.joinpath("README.md"), "xt", encoding="UTF-8") as f:
218                f.write(README_CONTENT)
219            with open(path.joinpath(".gitignore"), "xt", encoding="UTF-8") as f:
220                f.write("# Created by pytest automatically.\n*\n")
221            with open(path.joinpath("CACHEDIR.TAG"), "xb") as f:
222                f.write(CACHEDIR_TAG_CONTENT)
223
224            path.rename(self._cachedir)
225            # Create a directory in place of the one we just moved so that `TemporaryDirectory`'s
226            # cleanup doesn't complain.
227            #
228            # TODO: pass ignore_cleanup_errors=True when we no longer support python < 3.10. See
229            # https://github.com/python/cpython/issues/74168. Note that passing delete=False would
230            # do the wrong thing in case of errors and isn't supported until python 3.12.
231            path.mkdir()

Instance of the cache fixture.

Cache( cachedir: pathlib.Path, config: Config, *, _ispytest: bool = False)
72    def __init__(
73        self, cachedir: Path, config: Config, *, _ispytest: bool = False
74    ) -> None:
75        check_ispytest(_ispytest)
76        self._cachedir = cachedir
77        self._config = config
@classmethod
def for_config( cls, config: Config, *, _ispytest: bool = False) -> Cache:
79    @classmethod
80    def for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache":
81        """Create the Cache instance for a Config.
82
83        :meta private:
84        """
85        check_ispytest(_ispytest)
86        cachedir = cls.cache_dir_from_config(config, _ispytest=True)
87        if config.getoption("cacheclear") and cachedir.is_dir():
88            cls.clear_cache(cachedir, _ispytest=True)
89        return cls(cachedir, config, _ispytest=True)

Create the Cache instance for a Config.

:meta private:

@classmethod
def clear_cache(cls, cachedir: pathlib.Path, _ispytest: bool = False) -> None:
 91    @classmethod
 92    def clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None:
 93        """Clear the sub-directories used to hold cached directories and values.
 94
 95        :meta private:
 96        """
 97        check_ispytest(_ispytest)
 98        for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES):
 99            d = cachedir / prefix
100            if d.is_dir():
101                rm_rf(d)

Clear the sub-directories used to hold cached directories and values.

:meta private:

@staticmethod
def cache_dir_from_config( config: Config, *, _ispytest: bool = False) -> pathlib.Path:
103    @staticmethod
104    def cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path:
105        """Get the path to the cache directory for a Config.
106
107        :meta private:
108        """
109        check_ispytest(_ispytest)
110        return resolve_from_str(config.getini("cache_dir"), config.rootpath)

Get the path to the cache directory for a Config.

:meta private:

def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None:
112    def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None:
113        """Issue a cache warning.
114
115        :meta private:
116        """
117        check_ispytest(_ispytest)
118        import warnings
119
120        from _pytest.warning_types import PytestCacheWarning
121
122        warnings.warn(
123            PytestCacheWarning(fmt.format(**args) if args else fmt),
124            self._config.hook,
125            stacklevel=3,
126        )

Issue a cache warning.

:meta private:

def mkdir(self, name: str) -> pathlib.Path:
132    def mkdir(self, name: str) -> Path:
133        """Return a directory path object with the given name.
134
135        If the directory does not yet exist, it will be created. You can use
136        it to manage files to e.g. store/retrieve database dumps across test
137        sessions.
138
139        .. versionadded:: 7.0
140
141        :param name:
142            Must be a string not containing a ``/`` separator.
143            Make sure the name contains your plugin or application
144            identifiers to prevent clashes with other cache users.
145        """
146        path = Path(name)
147        if len(path.parts) > 1:
148            raise ValueError("name is not allowed to contain path separators")
149        res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, path)
150        self._mkdir(res)
151        return res

Return a directory path object with the given name.

If the directory does not yet exist, it will be created. You can use it to manage files to e.g. store/retrieve database dumps across test sessions.

New in version 7.0.

Parameters
  • name: Must be a string not containing a / separator. Make sure the name contains your plugin or application identifiers to prevent clashes with other cache users.
def get(self, key: str, default):
156    def get(self, key: str, default):
157        """Return the cached value for the given key.
158
159        If no value was yet cached or the value cannot be read, the specified
160        default is returned.
161
162        :param key:
163            Must be a ``/`` separated value. Usually the first
164            name is the name of your plugin or your application.
165        :param default:
166            The value to return in case of a cache-miss or invalid cache value.
167        """
168        path = self._getvaluepath(key)
169        try:
170            with path.open("r", encoding="UTF-8") as f:
171                return json.load(f)
172        except (ValueError, OSError):
173            return default

Return the cached value for the given key.

If no value was yet cached or the value cannot be read, the specified default is returned.

Parameters
  • key: Must be a / separated value. Usually the first name is the name of your plugin or your application.
  • default: The value to return in case of a cache-miss or invalid cache value.
def set(self, key: str, value: object) -> None:
175    def set(self, key: str, value: object) -> None:
176        """Save value for the given key.
177
178        :param key:
179            Must be a ``/`` separated value. Usually the first
180            name is the name of your plugin or your application.
181        :param value:
182            Must be of any combination of basic python types,
183            including nested types like lists of dictionaries.
184        """
185        path = self._getvaluepath(key)
186        try:
187            self._mkdir(path.parent)
188        except OSError as exc:
189            self.warn(
190                f"could not create cache path {path}: {exc}",
191                _ispytest=True,
192            )
193            return
194        data = json.dumps(value, ensure_ascii=False, indent=2)
195        try:
196            f = path.open("w", encoding="UTF-8")
197        except OSError as exc:
198            self.warn(
199                f"cache could not write path {path}: {exc}",
200                _ispytest=True,
201            )
202        else:
203            with f:
204                f.write(data)

Save value for the given key.

Parameters
  • key: Must be a / separated value. Usually the first name is the name of your plugin or your application.
  • value: Must be of any combination of basic python types, including nested types like lists of dictionaries.
@final
@dataclasses.dataclass
class CallInfo(typing.Generic[+TResult]):
270@final
271@dataclasses.dataclass
272class CallInfo(Generic[TResult]):
273    """Result/Exception info of a function invocation."""
274
275    _result: Optional[TResult]
276    #: The captured exception of the call, if it raised.
277    excinfo: Optional[ExceptionInfo[BaseException]]
278    #: The system time when the call started, in seconds since the epoch.
279    start: float
280    #: The system time when the call ended, in seconds since the epoch.
281    stop: float
282    #: The call duration, in seconds.
283    duration: float
284    #: The context of invocation: "collect", "setup", "call" or "teardown".
285    when: Literal["collect", "setup", "call", "teardown"]
286
287    def __init__(
288        self,
289        result: Optional[TResult],
290        excinfo: Optional[ExceptionInfo[BaseException]],
291        start: float,
292        stop: float,
293        duration: float,
294        when: Literal["collect", "setup", "call", "teardown"],
295        *,
296        _ispytest: bool = False,
297    ) -> None:
298        check_ispytest(_ispytest)
299        self._result = result
300        self.excinfo = excinfo
301        self.start = start
302        self.stop = stop
303        self.duration = duration
304        self.when = when
305
306    @property
307    def result(self) -> TResult:
308        """The return value of the call, if it didn't raise.
309
310        Can only be accessed if excinfo is None.
311        """
312        if self.excinfo is not None:
313            raise AttributeError(f"{self!r} has no valid result")
314        # The cast is safe because an exception wasn't raised, hence
315        # _result has the expected function return type (which may be
316        #  None, that's why a cast and not an assert).
317        return cast(TResult, self._result)
318
319    @classmethod
320    def from_call(
321        cls,
322        func: Callable[[], TResult],
323        when: Literal["collect", "setup", "call", "teardown"],
324        reraise: Optional[
325            Union[Type[BaseException], Tuple[Type[BaseException], ...]]
326        ] = None,
327    ) -> "CallInfo[TResult]":
328        """Call func, wrapping the result in a CallInfo.
329
330        :param func:
331            The function to call. Called without arguments.
332        :param when:
333            The phase in which the function is called.
334        :param reraise:
335            Exception or exceptions that shall propagate if raised by the
336            function, instead of being wrapped in the CallInfo.
337        """
338        excinfo = None
339        start = timing.time()
340        precise_start = timing.perf_counter()
341        try:
342            result: Optional[TResult] = func()
343        except BaseException:
344            excinfo = ExceptionInfo.from_current()
345            if reraise is not None and isinstance(excinfo.value, reraise):
346                raise
347            result = None
348        # use the perf counter
349        precise_stop = timing.perf_counter()
350        duration = precise_stop - precise_start
351        stop = timing.time()
352        return cls(
353            start=start,
354            stop=stop,
355            duration=duration,
356            when=when,
357            result=result,
358            excinfo=excinfo,
359            _ispytest=True,
360        )
361
362    def __repr__(self) -> str:
363        if self.excinfo is None:
364            return f"<CallInfo when={self.when!r} result: {self._result!r}>"
365        return f"<CallInfo when={self.when!r} excinfo={self.excinfo!r}>"

Result/Exception info of a function invocation.

CallInfo( result: Optional[+TResult], excinfo: Optional[ExceptionInfo[BaseException]], start: float, stop: float, duration: float, when: Literal['collect', 'setup', 'call', 'teardown'], *, _ispytest: bool = False)
287    def __init__(
288        self,
289        result: Optional[TResult],
290        excinfo: Optional[ExceptionInfo[BaseException]],
291        start: float,
292        stop: float,
293        duration: float,
294        when: Literal["collect", "setup", "call", "teardown"],
295        *,
296        _ispytest: bool = False,
297    ) -> None:
298        check_ispytest(_ispytest)
299        self._result = result
300        self.excinfo = excinfo
301        self.start = start
302        self.stop = stop
303        self.duration = duration
304        self.when = when
excinfo: Optional[ExceptionInfo[BaseException]]
start: float
stop: float
duration: float
when: Literal['collect', 'setup', 'call', 'teardown']
result: +TResult
306    @property
307    def result(self) -> TResult:
308        """The return value of the call, if it didn't raise.
309
310        Can only be accessed if excinfo is None.
311        """
312        if self.excinfo is not None:
313            raise AttributeError(f"{self!r} has no valid result")
314        # The cast is safe because an exception wasn't raised, hence
315        # _result has the expected function return type (which may be
316        #  None, that's why a cast and not an assert).
317        return cast(TResult, self._result)

The return value of the call, if it didn't raise.

Can only be accessed if excinfo is None.

@classmethod
def from_call( cls, func: Callable[[], +TResult], when: Literal['collect', 'setup', 'call', 'teardown'], reraise: Union[Type[BaseException], Tuple[Type[BaseException], ...], NoneType] = None) -> CallInfo[+TResult]:
319    @classmethod
320    def from_call(
321        cls,
322        func: Callable[[], TResult],
323        when: Literal["collect", "setup", "call", "teardown"],
324        reraise: Optional[
325            Union[Type[BaseException], Tuple[Type[BaseException], ...]]
326        ] = None,
327    ) -> "CallInfo[TResult]":
328        """Call func, wrapping the result in a CallInfo.
329
330        :param func:
331            The function to call. Called without arguments.
332        :param when:
333            The phase in which the function is called.
334        :param reraise:
335            Exception or exceptions that shall propagate if raised by the
336            function, instead of being wrapped in the CallInfo.
337        """
338        excinfo = None
339        start = timing.time()
340        precise_start = timing.perf_counter()
341        try:
342            result: Optional[TResult] = func()
343        except BaseException:
344            excinfo = ExceptionInfo.from_current()
345            if reraise is not None and isinstance(excinfo.value, reraise):
346                raise
347            result = None
348        # use the perf counter
349        precise_stop = timing.perf_counter()
350        duration = precise_stop - precise_start
351        stop = timing.time()
352        return cls(
353            start=start,
354            stop=stop,
355            duration=duration,
356            when=when,
357            result=result,
358            excinfo=excinfo,
359            _ispytest=True,
360        )

Call func, wrapping the result in a CallInfo.

Parameters
  • func: The function to call. Called without arguments.
  • when: The phase in which the function is called.
  • reraise: Exception or exceptions that shall propagate if raised by the function, instead of being wrapped in the CallInfo.
class CaptureFixture(typing.Generic[~AnyStr]):
895class CaptureFixture(Generic[AnyStr]):
896    """Object returned by the :fixture:`capsys`, :fixture:`capsysbinary`,
897    :fixture:`capfd` and :fixture:`capfdbinary` fixtures."""
898
899    def __init__(
900        self,
901        captureclass: Type[CaptureBase[AnyStr]],
902        request: SubRequest,
903        *,
904        _ispytest: bool = False,
905    ) -> None:
906        check_ispytest(_ispytest)
907        self.captureclass: Type[CaptureBase[AnyStr]] = captureclass
908        self.request = request
909        self._capture: Optional[MultiCapture[AnyStr]] = None
910        self._captured_out: AnyStr = self.captureclass.EMPTY_BUFFER
911        self._captured_err: AnyStr = self.captureclass.EMPTY_BUFFER
912
913    def _start(self) -> None:
914        if self._capture is None:
915            self._capture = MultiCapture(
916                in_=None,
917                out=self.captureclass(1),
918                err=self.captureclass(2),
919            )
920            self._capture.start_capturing()
921
922    def close(self) -> None:
923        if self._capture is not None:
924            out, err = self._capture.pop_outerr_to_orig()
925            self._captured_out += out
926            self._captured_err += err
927            self._capture.stop_capturing()
928            self._capture = None
929
930    def readouterr(self) -> CaptureResult[AnyStr]:
931        """Read and return the captured output so far, resetting the internal
932        buffer.
933
934        :returns:
935            The captured content as a namedtuple with ``out`` and ``err``
936            string attributes.
937        """
938        captured_out, captured_err = self._captured_out, self._captured_err
939        if self._capture is not None:
940            out, err = self._capture.readouterr()
941            captured_out += out
942            captured_err += err
943        self._captured_out = self.captureclass.EMPTY_BUFFER
944        self._captured_err = self.captureclass.EMPTY_BUFFER
945        return CaptureResult(captured_out, captured_err)
946
947    def _suspend(self) -> None:
948        """Suspend this fixture's own capturing temporarily."""
949        if self._capture is not None:
950            self._capture.suspend_capturing()
951
952    def _resume(self) -> None:
953        """Resume this fixture's own capturing temporarily."""
954        if self._capture is not None:
955            self._capture.resume_capturing()
956
957    def _is_started(self) -> bool:
958        """Whether actively capturing -- not disabled or closed."""
959        if self._capture is not None:
960            return self._capture.is_started()
961        return False
962
963    @contextlib.contextmanager
964    def disabled(self) -> Generator[None, None, None]:
965        """Temporarily disable capturing while inside the ``with`` block."""
966        capmanager: CaptureManager = self.request.config.pluginmanager.getplugin(
967            "capturemanager"
968        )
969        with capmanager.global_and_fixture_disabled():
970            yield

Object returned by the :fixture:capsys, :fixture:capsysbinary, :fixture:capfd and :fixture:capfdbinary fixtures.

CaptureFixture( captureclass: Type[_pytest.capture.CaptureBase[~AnyStr]], request: _pytest.fixtures.SubRequest, *, _ispytest: bool = False)
899    def __init__(
900        self,
901        captureclass: Type[CaptureBase[AnyStr]],
902        request: SubRequest,
903        *,
904        _ispytest: bool = False,
905    ) -> None:
906        check_ispytest(_ispytest)
907        self.captureclass: Type[CaptureBase[AnyStr]] = captureclass
908        self.request = request
909        self._capture: Optional[MultiCapture[AnyStr]] = None
910        self._captured_out: AnyStr = self.captureclass.EMPTY_BUFFER
911        self._captured_err: AnyStr = self.captureclass.EMPTY_BUFFER
captureclass: Type[_pytest.capture.CaptureBase[~AnyStr]]
request
def close(self) -> None:
922    def close(self) -> None:
923        if self._capture is not None:
924            out, err = self._capture.pop_outerr_to_orig()
925            self._captured_out += out
926            self._captured_err += err
927            self._capture.stop_capturing()
928            self._capture = None
def readouterr(self) -> _pytest.capture.CaptureResult[~AnyStr]:
930    def readouterr(self) -> CaptureResult[AnyStr]:
931        """Read and return the captured output so far, resetting the internal
932        buffer.
933
934        :returns:
935            The captured content as a namedtuple with ``out`` and ``err``
936            string attributes.
937        """
938        captured_out, captured_err = self._captured_out, self._captured_err
939        if self._capture is not None:
940            out, err = self._capture.readouterr()
941            captured_out += out
942            captured_err += err
943        self._captured_out = self.captureclass.EMPTY_BUFFER
944        self._captured_err = self.captureclass.EMPTY_BUFFER
945        return CaptureResult(captured_out, captured_err)

Read and return the captured output so far, resetting the internal buffer.

:returns: The captured content as a namedtuple with out and err string attributes.

@contextlib.contextmanager
def disabled(self) -> Generator[NoneType, NoneType, NoneType]:
963    @contextlib.contextmanager
964    def disabled(self) -> Generator[None, None, None]:
965        """Temporarily disable capturing while inside the ``with`` block."""
966        capmanager: CaptureManager = self.request.config.pluginmanager.getplugin(
967            "capturemanager"
968        )
969        with capmanager.global_and_fixture_disabled():
970            yield

Temporarily disable capturing while inside the with block.

class Class(_pytest.python.PyCollector):
726class Class(PyCollector):
727    """Collector for test methods (and nested classes) in a Python class."""
728
729    @classmethod
730    def from_parent(cls, parent, *, name, obj=None, **kw) -> "Self":  # type: ignore[override]
731        """The public constructor."""
732        return super().from_parent(name=name, parent=parent, **kw)
733
734    def newinstance(self):
735        return self.obj()
736
737    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
738        if not safe_getattr(self.obj, "__test__", True):
739            return []
740        if hasinit(self.obj):
741            assert self.parent is not None
742            self.warn(
743                PytestCollectionWarning(
744                    f"cannot collect test class {self.obj.__name__!r} because it has a "
745                    f"__init__ constructor (from: {self.parent.nodeid})"
746                )
747            )
748            return []
749        elif hasnew(self.obj):
750            assert self.parent is not None
751            self.warn(
752                PytestCollectionWarning(
753                    f"cannot collect test class {self.obj.__name__!r} because it has a "
754                    f"__new__ constructor (from: {self.parent.nodeid})"
755                )
756            )
757            return []
758
759        self._register_setup_class_fixture()
760        self._register_setup_method_fixture()
761
762        self.session._fixturemanager.parsefactories(self.newinstance(), self.nodeid)
763
764        return super().collect()
765
766    def _register_setup_class_fixture(self) -> None:
767        """Register an autouse, class scoped fixture into the collected class object
768        that invokes setup_class/teardown_class if either or both are available.
769
770        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
771        other fixtures (#517).
772        """
773        setup_class = _get_first_non_fixture_func(self.obj, ("setup_class",))
774        teardown_class = _get_first_non_fixture_func(self.obj, ("teardown_class",))
775        if setup_class is None and teardown_class is None:
776            return
777
778        def xunit_setup_class_fixture(request) -> Generator[None, None, None]:
779            cls = request.cls
780            if setup_class is not None:
781                func = getimfunc(setup_class)
782                _call_with_optional_argument(func, cls)
783            yield
784            if teardown_class is not None:
785                func = getimfunc(teardown_class)
786                _call_with_optional_argument(func, cls)
787
788        self.session._fixturemanager._register_fixture(
789            # Use a unique name to speed up lookup.
790            name=f"_xunit_setup_class_fixture_{self.obj.__qualname__}",
791            func=xunit_setup_class_fixture,
792            nodeid=self.nodeid,
793            scope="class",
794            autouse=True,
795        )
796
797    def _register_setup_method_fixture(self) -> None:
798        """Register an autouse, function scoped fixture into the collected class object
799        that invokes setup_method/teardown_method if either or both are available.
800
801        Using a fixture to invoke these methods ensures we play nicely and unsurprisingly with
802        other fixtures (#517).
803        """
804        setup_name = "setup_method"
805        setup_method = _get_first_non_fixture_func(self.obj, (setup_name,))
806        teardown_name = "teardown_method"
807        teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,))
808        if setup_method is None and teardown_method is None:
809            return
810
811        def xunit_setup_method_fixture(request) -> Generator[None, None, None]:
812            instance = request.instance
813            method = request.function
814            if setup_method is not None:
815                func = getattr(instance, setup_name)
816                _call_with_optional_argument(func, method)
817            yield
818            if teardown_method is not None:
819                func = getattr(instance, teardown_name)
820                _call_with_optional_argument(func, method)
821
822        self.session._fixturemanager._register_fixture(
823            # Use a unique name to speed up lookup.
824            name=f"_xunit_setup_method_fixture_{self.obj.__qualname__}",
825            func=xunit_setup_method_fixture,
826            nodeid=self.nodeid,
827            scope="function",
828            autouse=True,
829        )

Collector for test methods (and nested classes) in a Python class.

@classmethod
def from_parent(cls, parent, *, name, obj=None, **kw) -> Self:
729    @classmethod
730    def from_parent(cls, parent, *, name, obj=None, **kw) -> "Self":  # type: ignore[override]
731        """The public constructor."""
732        return super().from_parent(name=name, parent=parent, **kw)

The public constructor.

def newinstance(self):
734    def newinstance(self):
735        return self.obj()
def collect(self) -> Iterable[Union[Item, Collector]]:
737    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
738        if not safe_getattr(self.obj, "__test__", True):
739            return []
740        if hasinit(self.obj):
741            assert self.parent is not None
742            self.warn(
743                PytestCollectionWarning(
744                    f"cannot collect test class {self.obj.__name__!r} because it has a "
745                    f"__init__ constructor (from: {self.parent.nodeid})"
746                )
747            )
748            return []
749        elif hasnew(self.obj):
750            assert self.parent is not None
751            self.warn(
752                PytestCollectionWarning(
753                    f"cannot collect test class {self.obj.__name__!r} because it has a "
754                    f"__new__ constructor (from: {self.parent.nodeid})"
755                )
756            )
757            return []
758
759        self._register_setup_class_fixture()
760        self._register_setup_method_fixture()
761
762        self.session._fixturemanager.parsefactories(self.newinstance(), self.nodeid)
763
764        return super().collect()

Collect children (items and collectors) for this collector.

Inherited Members
_pytest.nodes.Node
Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
_pytest.python.PyCollector
funcnamefilter
isnosetest
classnamefilter
istestfunction
istestclass
_pytest.python.PyobjMixin
module
cls
instance
obj
getmodpath
reportinfo
Collector
CollectError
repr_failure
class cmdline:
218class cmdline:  # compatibility namespace
219    main = staticmethod(main)
def main( args: Union[List[str], os.PathLike[str], NoneType] = None, plugins: Optional[Sequence[Union[str, object]]] = None) -> Union[int, ExitCode]:
143def main(
144    args: Optional[Union[List[str], "os.PathLike[str]"]] = None,
145    plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
146) -> Union[int, ExitCode]:
147    """Perform an in-process test run.
148
149    :param args:
150        List of command line arguments. If `None` or not given, defaults to reading
151        arguments directly from the process command line (:data:`sys.argv`).
152    :param plugins: List of plugin objects to be auto-registered during initialization.
153
154    :returns: An exit code.
155    """
156    old_pytest_version = os.environ.get("PYTEST_VERSION")
157    try:
158        os.environ["PYTEST_VERSION"] = __version__
159        try:
160            config = _prepareconfig(args, plugins)
161        except ConftestImportFailure as e:
162            exc_info = ExceptionInfo.from_exception(e.cause)
163            tw = TerminalWriter(sys.stderr)
164            tw.line(f"ImportError while loading conftest '{e.path}'.", red=True)
165            exc_info.traceback = exc_info.traceback.filter(
166                filter_traceback_for_conftest_import_failure
167            )
168            exc_repr = (
169                exc_info.getrepr(style="short", chain=False)
170                if exc_info.traceback
171                else exc_info.exconly()
172            )
173            formatted_tb = str(exc_repr)
174            for line in formatted_tb.splitlines():
175                tw.line(line.rstrip(), red=True)
176            return ExitCode.USAGE_ERROR
177        else:
178            try:
179                ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
180                    config=config
181                )
182                try:
183                    return ExitCode(ret)
184                except ValueError:
185                    return ret
186            finally:
187                config._ensure_unconfigure()
188    except UsageError as e:
189        tw = TerminalWriter(sys.stderr)
190        for msg in e.args:
191            tw.line(f"ERROR: {msg}\n", red=True)
192        return ExitCode.USAGE_ERROR
193    finally:
194        if old_pytest_version is None:
195            os.environ.pop("PYTEST_VERSION", None)
196        else:
197            os.environ["PYTEST_VERSION"] = old_pytest_version

Perform an in-process test run.

Parameters
  • args: List of command line arguments. If None or not given, defaults to reading arguments directly from the process command line (sys.argv).
  • plugins: List of plugin objects to be auto-registered during initialization.

:returns: An exit code.

class Collector(_pytest.nodes.Node, abc.ABC):
505class Collector(Node, abc.ABC):
506    """Base class of all collectors.
507
508    Collector create children through `collect()` and thus iteratively build
509    the collection tree.
510    """
511
512    class CollectError(Exception):
513        """An error during collection, contains a custom message."""
514
515    @abc.abstractmethod
516    def collect(self) -> Iterable[Union["Item", "Collector"]]:
517        """Collect children (items and collectors) for this collector."""
518        raise NotImplementedError("abstract")
519
520    # TODO: This omits the style= parameter which breaks Liskov Substitution.
521    def repr_failure(  # type: ignore[override]
522        self, excinfo: ExceptionInfo[BaseException]
523    ) -> Union[str, TerminalRepr]:
524        """Return a representation of a collection failure.
525
526        :param excinfo: Exception information for the failure.
527        """
528        if isinstance(excinfo.value, self.CollectError) and not self.config.getoption(
529            "fulltrace", False
530        ):
531            exc = excinfo.value
532            return str(exc.args[0])
533
534        # Respect explicit tbstyle option, but default to "short"
535        # (_repr_failure_py uses "long" with "fulltrace" option always).
536        tbstyle = self.config.getoption("tbstyle", "auto")
537        if tbstyle == "auto":
538            tbstyle = "short"
539
540        return self._repr_failure_py(excinfo, style=tbstyle)
541
542    def _traceback_filter(self, excinfo: ExceptionInfo[BaseException]) -> Traceback:
543        if hasattr(self, "path"):
544            traceback = excinfo.traceback
545            ntraceback = traceback.cut(path=self.path)
546            if ntraceback == traceback:
547                ntraceback = ntraceback.cut(excludepath=tracebackcutdir)
548            return ntraceback.filter(excinfo)
549        return excinfo.traceback

Base class of all collectors.

Collector create children through collect() and thus iteratively build the collection tree.

@abc.abstractmethod
def collect(self) -> Iterable[Union[Item, Collector]]:
515    @abc.abstractmethod
516    def collect(self) -> Iterable[Union["Item", "Collector"]]:
517        """Collect children (items and collectors) for this collector."""
518        raise NotImplementedError("abstract")

Collect children (items and collectors) for this collector.

def repr_failure( self, excinfo: ExceptionInfo[BaseException]) -> Union[str, _pytest._code.code.TerminalRepr]:
521    def repr_failure(  # type: ignore[override]
522        self, excinfo: ExceptionInfo[BaseException]
523    ) -> Union[str, TerminalRepr]:
524        """Return a representation of a collection failure.
525
526        :param excinfo: Exception information for the failure.
527        """
528        if isinstance(excinfo.value, self.CollectError) and not self.config.getoption(
529            "fulltrace", False
530        ):
531            exc = excinfo.value
532            return str(exc.args[0])
533
534        # Respect explicit tbstyle option, but default to "short"
535        # (_repr_failure_py uses "long" with "fulltrace" option always).
536        tbstyle = self.config.getoption("tbstyle", "auto")
537        if tbstyle == "auto":
538            tbstyle = "short"
539
540        return self._repr_failure_py(excinfo, style=tbstyle)

Return a representation of a collection failure.

Parameters
  • excinfo: Exception information for the failure.
Inherited Members
_pytest.nodes.Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
from_parent
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
class Collector.CollectError(builtins.Exception):
512    class CollectError(Exception):
513        """An error during collection, contains a custom message."""

An error during collection, contains a custom message.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
@final
class CollectReport(_pytest.reports.BaseReport):
386@final
387class CollectReport(BaseReport):
388    """Collection report object.
389
390    Reports can contain arbitrary extra attributes.
391    """
392
393    when = "collect"
394
395    def __init__(
396        self,
397        nodeid: str,
398        outcome: "Literal['passed', 'failed', 'skipped']",
399        longrepr: Union[
400            None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr
401        ],
402        result: Optional[List[Union[Item, Collector]]],
403        sections: Iterable[Tuple[str, str]] = (),
404        **extra,
405    ) -> None:
406        #: Normalized collection nodeid.
407        self.nodeid = nodeid
408
409        #: Test outcome, always one of "passed", "failed", "skipped".
410        self.outcome = outcome
411
412        #: None or a failure representation.
413        self.longrepr = longrepr
414
415        #: The collected items and collection nodes.
416        self.result = result or []
417
418        #: Tuples of str ``(heading, content)`` with extra information
419        #: for the test report. Used by pytest to add text captured
420        #: from ``stdout``, ``stderr``, and intercepted logging events. May
421        #: be used by other plugins to add arbitrary information to reports.
422        self.sections = list(sections)
423
424        self.__dict__.update(extra)
425
426    @property
427    def location(  # type:ignore[override]
428        self,
429    ) -> Optional[Tuple[str, Optional[int], str]]:
430        return (self.fspath, None, self.fspath)
431
432    def __repr__(self) -> str:
433        return f"<CollectReport {self.nodeid!r} lenresult={len(self.result)} outcome={self.outcome!r}>"

Collection report object.

Reports can contain arbitrary extra attributes.

CollectReport( nodeid: str, outcome: Literal['passed', 'failed', 'skipped'], longrepr: Union[NoneType, ExceptionInfo[BaseException], Tuple[str, int, str], str, _pytest._code.code.TerminalRepr], result: Optional[List[Union[Item, Collector]]], sections: Iterable[Tuple[str, str]] = (), **extra)
395    def __init__(
396        self,
397        nodeid: str,
398        outcome: "Literal['passed', 'failed', 'skipped']",
399        longrepr: Union[
400            None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr
401        ],
402        result: Optional[List[Union[Item, Collector]]],
403        sections: Iterable[Tuple[str, str]] = (),
404        **extra,
405    ) -> None:
406        #: Normalized collection nodeid.
407        self.nodeid = nodeid
408
409        #: Test outcome, always one of "passed", "failed", "skipped".
410        self.outcome = outcome
411
412        #: None or a failure representation.
413        self.longrepr = longrepr
414
415        #: The collected items and collection nodes.
416        self.result = result or []
417
418        #: Tuples of str ``(heading, content)`` with extra information
419        #: for the test report. Used by pytest to add text captured
420        #: from ``stdout``, ``stderr``, and intercepted logging events. May
421        #: be used by other plugins to add arbitrary information to reports.
422        self.sections = list(sections)
423
424        self.__dict__.update(extra)
when = 'collect'
nodeid
outcome
longrepr
result
sections
location: Optional[Tuple[str, Optional[int], str]]
426    @property
427    def location(  # type:ignore[override]
428        self,
429    ) -> Optional[Tuple[str, Optional[int], str]]:
430        return (self.fspath, None, self.fspath)
Inherited Members
_pytest.reports.BaseReport
toterminal
get_sections
longreprtext
caplog
capstdout
capstderr
passed
failed
skipped
fspath
count_towards_summary
head_line
@final
class Config:
 974@final
 975class Config:
 976    """Access to configuration values, pluginmanager and plugin hooks.
 977
 978    :param PytestPluginManager pluginmanager:
 979        A pytest PluginManager.
 980
 981    :param InvocationParams invocation_params:
 982        Object containing parameters regarding the :func:`pytest.main`
 983        invocation.
 984    """
 985
 986    @final
 987    @dataclasses.dataclass(frozen=True)
 988    class InvocationParams:
 989        """Holds parameters passed during :func:`pytest.main`.
 990
 991        The object attributes are read-only.
 992
 993        .. versionadded:: 5.1
 994
 995        .. note::
 996
 997            Note that the environment variable ``PYTEST_ADDOPTS`` and the ``addopts``
 998            ini option are handled by pytest, not being included in the ``args`` attribute.
 999
1000            Plugins accessing ``InvocationParams`` must be aware of that.
1001        """
1002
1003        args: Tuple[str, ...]
1004        """The command-line arguments as passed to :func:`pytest.main`."""
1005        plugins: Optional[Sequence[Union[str, _PluggyPlugin]]]
1006        """Extra plugins, might be `None`."""
1007        dir: Path
1008        """The directory from which :func:`pytest.main` was invoked."""
1009
1010        def __init__(
1011            self,
1012            *,
1013            args: Iterable[str],
1014            plugins: Optional[Sequence[Union[str, _PluggyPlugin]]],
1015            dir: Path,
1016        ) -> None:
1017            object.__setattr__(self, "args", tuple(args))
1018            object.__setattr__(self, "plugins", plugins)
1019            object.__setattr__(self, "dir", dir)
1020
1021    class ArgsSource(enum.Enum):
1022        """Indicates the source of the test arguments.
1023
1024        .. versionadded:: 7.2
1025        """
1026
1027        #: Command line arguments.
1028        ARGS = enum.auto()
1029        #: Invocation directory.
1030        INVOCATION_DIR = enum.auto()
1031        INCOVATION_DIR = INVOCATION_DIR  # backwards compatibility alias
1032        #: 'testpaths' configuration value.
1033        TESTPATHS = enum.auto()
1034
1035    def __init__(
1036        self,
1037        pluginmanager: PytestPluginManager,
1038        *,
1039        invocation_params: Optional[InvocationParams] = None,
1040    ) -> None:
1041        from .argparsing import FILE_OR_DIR
1042        from .argparsing import Parser
1043
1044        if invocation_params is None:
1045            invocation_params = self.InvocationParams(
1046                args=(), plugins=None, dir=Path.cwd()
1047            )
1048
1049        self.option = argparse.Namespace()
1050        """Access to command line option as attributes.
1051
1052        :type: argparse.Namespace
1053        """
1054
1055        self.invocation_params = invocation_params
1056        """The parameters with which pytest was invoked.
1057
1058        :type: InvocationParams
1059        """
1060
1061        _a = FILE_OR_DIR
1062        self._parser = Parser(
1063            usage=f"%(prog)s [options] [{_a}] [{_a}] [...]",
1064            processopt=self._processopt,
1065            _ispytest=True,
1066        )
1067        self.pluginmanager = pluginmanager
1068        """The plugin manager handles plugin registration and hook invocation.
1069
1070        :type: PytestPluginManager
1071        """
1072
1073        self.stash = Stash()
1074        """A place where plugins can store information on the config for their
1075        own use.
1076
1077        :type: Stash
1078        """
1079        # Deprecated alias. Was never public. Can be removed in a few releases.
1080        self._store = self.stash
1081
1082        self.trace = self.pluginmanager.trace.root.get("config")
1083        self.hook: pluggy.HookRelay = PathAwareHookProxy(self.pluginmanager.hook)  # type: ignore[assignment]
1084        self._inicache: Dict[str, Any] = {}
1085        self._override_ini: Sequence[str] = ()
1086        self._opt2dest: Dict[str, str] = {}
1087        self._cleanup: List[Callable[[], None]] = []
1088        self.pluginmanager.register(self, "pytestconfig")
1089        self._configured = False
1090        self.hook.pytest_addoption.call_historic(
1091            kwargs=dict(parser=self._parser, pluginmanager=self.pluginmanager)
1092        )
1093        self.args_source = Config.ArgsSource.ARGS
1094        self.args: List[str] = []
1095
1096        if TYPE_CHECKING:
1097            from _pytest.cacheprovider import Cache
1098
1099            self.cache: Optional[Cache] = None
1100
1101    @property
1102    def rootpath(self) -> Path:
1103        """The path to the :ref:`rootdir <rootdir>`.
1104
1105        :type: pathlib.Path
1106
1107        .. versionadded:: 6.1
1108        """
1109        return self._rootpath
1110
1111    @property
1112    def inipath(self) -> Optional[Path]:
1113        """The path to the :ref:`configfile <configfiles>`.
1114
1115        :type: Optional[pathlib.Path]
1116
1117        .. versionadded:: 6.1
1118        """
1119        return self._inipath
1120
1121    def add_cleanup(self, func: Callable[[], None]) -> None:
1122        """Add a function to be called when the config object gets out of
1123        use (usually coinciding with pytest_unconfigure)."""
1124        self._cleanup.append(func)
1125
1126    def _do_configure(self) -> None:
1127        assert not self._configured
1128        self._configured = True
1129        with warnings.catch_warnings():
1130            warnings.simplefilter("default")
1131            self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
1132
1133    def _ensure_unconfigure(self) -> None:
1134        if self._configured:
1135            self._configured = False
1136            self.hook.pytest_unconfigure(config=self)
1137            self.hook.pytest_configure._call_history = []
1138        while self._cleanup:
1139            fin = self._cleanup.pop()
1140            fin()
1141
1142    def get_terminal_writer(self) -> TerminalWriter:
1143        terminalreporter: Optional[TerminalReporter] = self.pluginmanager.get_plugin(
1144            "terminalreporter"
1145        )
1146        assert terminalreporter is not None
1147        return terminalreporter._tw
1148
1149    def pytest_cmdline_parse(
1150        self, pluginmanager: PytestPluginManager, args: List[str]
1151    ) -> "Config":
1152        try:
1153            self.parse(args)
1154        except UsageError:
1155            # Handle --version and --help here in a minimal fashion.
1156            # This gets done via helpconfig normally, but its
1157            # pytest_cmdline_main is not called in case of errors.
1158            if getattr(self.option, "version", False) or "--version" in args:
1159                from _pytest.helpconfig import showversion
1160
1161                showversion(self)
1162            elif (
1163                getattr(self.option, "help", False) or "--help" in args or "-h" in args
1164            ):
1165                self._parser._getparser().print_help()
1166                sys.stdout.write(
1167                    "\nNOTE: displaying only minimal help due to UsageError.\n\n"
1168                )
1169
1170            raise
1171
1172        return self
1173
1174    def notify_exception(
1175        self,
1176        excinfo: ExceptionInfo[BaseException],
1177        option: Optional[argparse.Namespace] = None,
1178    ) -> None:
1179        if option and getattr(option, "fulltrace", False):
1180            style: _TracebackStyle = "long"
1181        else:
1182            style = "native"
1183        excrepr = excinfo.getrepr(
1184            funcargs=True, showlocals=getattr(option, "showlocals", False), style=style
1185        )
1186        res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo)
1187        if not any(res):
1188            for line in str(excrepr).split("\n"):
1189                sys.stderr.write("INTERNALERROR> %s\n" % line)
1190                sys.stderr.flush()
1191
1192    def cwd_relative_nodeid(self, nodeid: str) -> str:
1193        # nodeid's are relative to the rootpath, compute relative to cwd.
1194        if self.invocation_params.dir != self.rootpath:
1195            fullpath = self.rootpath / nodeid
1196            nodeid = bestrelpath(self.invocation_params.dir, fullpath)
1197        return nodeid
1198
1199    @classmethod
1200    def fromdictargs(cls, option_dict, args) -> "Config":
1201        """Constructor usable for subprocesses."""
1202        config = get_config(args)
1203        config.option.__dict__.update(option_dict)
1204        config.parse(args, addopts=False)
1205        for x in config.option.plugins:
1206            config.pluginmanager.consider_pluginarg(x)
1207        return config
1208
1209    def _processopt(self, opt: "Argument") -> None:
1210        for name in opt._short_opts + opt._long_opts:
1211            self._opt2dest[name] = opt.dest
1212
1213        if hasattr(opt, "default"):
1214            if not hasattr(self.option, opt.dest):
1215                setattr(self.option, opt.dest, opt.default)
1216
1217    @hookimpl(trylast=True)
1218    def pytest_load_initial_conftests(self, early_config: "Config") -> None:
1219        # We haven't fully parsed the command line arguments yet, so
1220        # early_config.args it not set yet. But we need it for
1221        # discovering the initial conftests. So "pre-run" the logic here.
1222        # It will be done for real in `parse()`.
1223        args, args_source = early_config._decide_args(
1224            args=early_config.known_args_namespace.file_or_dir,
1225            pyargs=early_config.known_args_namespace.pyargs,
1226            testpaths=early_config.getini("testpaths"),
1227            invocation_dir=early_config.invocation_params.dir,
1228            rootpath=early_config.rootpath,
1229            warn=False,
1230        )
1231        self.pluginmanager._set_initial_conftests(
1232            args=args,
1233            pyargs=early_config.known_args_namespace.pyargs,
1234            noconftest=early_config.known_args_namespace.noconftest,
1235            rootpath=early_config.rootpath,
1236            confcutdir=early_config.known_args_namespace.confcutdir,
1237            invocation_dir=early_config.invocation_params.dir,
1238            importmode=early_config.known_args_namespace.importmode,
1239            consider_namespace_packages=early_config.getini(
1240                "consider_namespace_packages"
1241            ),
1242        )
1243
1244    def _initini(self, args: Sequence[str]) -> None:
1245        ns, unknown_args = self._parser.parse_known_and_unknown_args(
1246            args, namespace=copy.copy(self.option)
1247        )
1248        rootpath, inipath, inicfg = determine_setup(
1249            inifile=ns.inifilename,
1250            args=ns.file_or_dir + unknown_args,
1251            rootdir_cmd_arg=ns.rootdir or None,
1252            invocation_dir=self.invocation_params.dir,
1253        )
1254        self._rootpath = rootpath
1255        self._inipath = inipath
1256        self.inicfg = inicfg
1257        self._parser.extra_info["rootdir"] = str(self.rootpath)
1258        self._parser.extra_info["inifile"] = str(self.inipath)
1259        self._parser.addini("addopts", "Extra command line options", "args")
1260        self._parser.addini("minversion", "Minimally required pytest version")
1261        self._parser.addini(
1262            "required_plugins",
1263            "Plugins that must be present for pytest to run",
1264            type="args",
1265            default=[],
1266        )
1267        self._override_ini = ns.override_ini or ()
1268
1269    def _consider_importhook(self, args: Sequence[str]) -> None:
1270        """Install the PEP 302 import hook if using assertion rewriting.
1271
1272        Needs to parse the --assert=<mode> option from the commandline
1273        and find all the installed plugins to mark them for rewriting
1274        by the importhook.
1275        """
1276        ns, unknown_args = self._parser.parse_known_and_unknown_args(args)
1277        mode = getattr(ns, "assertmode", "plain")
1278        if mode == "rewrite":
1279            import _pytest.assertion
1280
1281            try:
1282                hook = _pytest.assertion.install_importhook(self)
1283            except SystemError:
1284                mode = "plain"
1285            else:
1286                self._mark_plugins_for_rewrite(hook)
1287        self._warn_about_missing_assertion(mode)
1288
1289    def _mark_plugins_for_rewrite(self, hook) -> None:
1290        """Given an importhook, mark for rewrite any top-level
1291        modules or packages in the distribution package for
1292        all pytest plugins."""
1293        self.pluginmanager.rewrite_hook = hook
1294
1295        if os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"):
1296            # We don't autoload from setuptools entry points, no need to continue.
1297            return
1298
1299        package_files = (
1300            str(file)
1301            for dist in importlib.metadata.distributions()
1302            if any(ep.group == "pytest11" for ep in dist.entry_points)
1303            for file in dist.files or []
1304        )
1305
1306        for name in _iter_rewritable_modules(package_files):
1307            hook.mark_rewrite(name)
1308
1309    def _validate_args(self, args: List[str], via: str) -> List[str]:
1310        """Validate known args."""
1311        self._parser._config_source_hint = via  # type: ignore
1312        try:
1313            self._parser.parse_known_and_unknown_args(
1314                args, namespace=copy.copy(self.option)
1315            )
1316        finally:
1317            del self._parser._config_source_hint  # type: ignore
1318
1319        return args
1320
1321    def _decide_args(
1322        self,
1323        *,
1324        args: List[str],
1325        pyargs: bool,
1326        testpaths: List[str],
1327        invocation_dir: Path,
1328        rootpath: Path,
1329        warn: bool,
1330    ) -> Tuple[List[str], ArgsSource]:
1331        """Decide the args (initial paths/nodeids) to use given the relevant inputs.
1332
1333        :param warn: Whether can issue warnings.
1334
1335        :returns: The args and the args source. Guaranteed to be non-empty.
1336        """
1337        if args:
1338            source = Config.ArgsSource.ARGS
1339            result = args
1340        else:
1341            if invocation_dir == rootpath:
1342                source = Config.ArgsSource.TESTPATHS
1343                if pyargs:
1344                    result = testpaths
1345                else:
1346                    result = []
1347                    for path in testpaths:
1348                        result.extend(sorted(glob.iglob(path, recursive=True)))
1349                    if testpaths and not result:
1350                        if warn:
1351                            warning_text = (
1352                                "No files were found in testpaths; "
1353                                "consider removing or adjusting your testpaths configuration. "
1354                                "Searching recursively from the current directory instead."
1355                            )
1356                            self.issue_config_time_warning(
1357                                PytestConfigWarning(warning_text), stacklevel=3
1358                            )
1359            else:
1360                result = []
1361            if not result:
1362                source = Config.ArgsSource.INVOCATION_DIR
1363                result = [str(invocation_dir)]
1364        return result, source
1365
1366    def _preparse(self, args: List[str], addopts: bool = True) -> None:
1367        if addopts:
1368            env_addopts = os.environ.get("PYTEST_ADDOPTS", "")
1369            if len(env_addopts):
1370                args[:] = (
1371                    self._validate_args(shlex.split(env_addopts), "via PYTEST_ADDOPTS")
1372                    + args
1373                )
1374        self._initini(args)
1375        if addopts:
1376            args[:] = (
1377                self._validate_args(self.getini("addopts"), "via addopts config") + args
1378            )
1379
1380        self.known_args_namespace = self._parser.parse_known_args(
1381            args, namespace=copy.copy(self.option)
1382        )
1383        self._checkversion()
1384        self._consider_importhook(args)
1385        self.pluginmanager.consider_preparse(args, exclude_only=False)
1386        if not os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"):
1387            # Don't autoload from setuptools entry point. Only explicitly specified
1388            # plugins are going to be loaded.
1389            self.pluginmanager.load_setuptools_entrypoints("pytest11")
1390        self.pluginmanager.consider_env()
1391
1392        self.known_args_namespace = self._parser.parse_known_args(
1393            args, namespace=copy.copy(self.known_args_namespace)
1394        )
1395
1396        self._validate_plugins()
1397        self._warn_about_skipped_plugins()
1398
1399        if self.known_args_namespace.confcutdir is None:
1400            if self.inipath is not None:
1401                confcutdir = str(self.inipath.parent)
1402            else:
1403                confcutdir = str(self.rootpath)
1404            self.known_args_namespace.confcutdir = confcutdir
1405        try:
1406            self.hook.pytest_load_initial_conftests(
1407                early_config=self, args=args, parser=self._parser
1408            )
1409        except ConftestImportFailure as e:
1410            if self.known_args_namespace.help or self.known_args_namespace.version:
1411                # we don't want to prevent --help/--version to work
1412                # so just let is pass and print a warning at the end
1413                self.issue_config_time_warning(
1414                    PytestConfigWarning(f"could not load initial conftests: {e.path}"),
1415                    stacklevel=2,
1416                )
1417            else:
1418                raise
1419
1420    @hookimpl(wrapper=True)
1421    def pytest_collection(self) -> Generator[None, object, object]:
1422        # Validate invalid ini keys after collection is done so we take in account
1423        # options added by late-loading conftest files.
1424        try:
1425            return (yield)
1426        finally:
1427            self._validate_config_options()
1428
1429    def _checkversion(self) -> None:
1430        import pytest
1431
1432        minver = self.inicfg.get("minversion", None)
1433        if minver:
1434            # Imported lazily to improve start-up time.
1435            from packaging.version import Version
1436
1437            if not isinstance(minver, str):
1438                raise pytest.UsageError(
1439                    "%s: 'minversion' must be a single value" % self.inipath
1440                )
1441
1442            if Version(minver) > Version(pytest.__version__):
1443                raise pytest.UsageError(
1444                    f"{self.inipath}: 'minversion' requires pytest-{minver}, actual pytest-{pytest.__version__}'"
1445                )
1446
1447    def _validate_config_options(self) -> None:
1448        for key in sorted(self._get_unknown_ini_keys()):
1449            self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")
1450
1451    def _validate_plugins(self) -> None:
1452        required_plugins = sorted(self.getini("required_plugins"))
1453        if not required_plugins:
1454            return
1455
1456        # Imported lazily to improve start-up time.
1457        from packaging.requirements import InvalidRequirement
1458        from packaging.requirements import Requirement
1459        from packaging.version import Version
1460
1461        plugin_info = self.pluginmanager.list_plugin_distinfo()
1462        plugin_dist_info = {dist.project_name: dist.version for _, dist in plugin_info}
1463
1464        missing_plugins = []
1465        for required_plugin in required_plugins:
1466            try:
1467                req = Requirement(required_plugin)
1468            except InvalidRequirement:
1469                missing_plugins.append(required_plugin)
1470                continue
1471
1472            if req.name not in plugin_dist_info:
1473                missing_plugins.append(required_plugin)
1474            elif not req.specifier.contains(
1475                Version(plugin_dist_info[req.name]), prereleases=True
1476            ):
1477                missing_plugins.append(required_plugin)
1478
1479        if missing_plugins:
1480            raise UsageError(
1481                "Missing required plugins: {}".format(", ".join(missing_plugins)),
1482            )
1483
1484    def _warn_or_fail_if_strict(self, message: str) -> None:
1485        if self.known_args_namespace.strict_config:
1486            raise UsageError(message)
1487
1488        self.issue_config_time_warning(PytestConfigWarning(message), stacklevel=3)
1489
1490    def _get_unknown_ini_keys(self) -> List[str]:
1491        parser_inicfg = self._parser._inidict
1492        return [name for name in self.inicfg if name not in parser_inicfg]
1493
1494    def parse(self, args: List[str], addopts: bool = True) -> None:
1495        # Parse given cmdline arguments into this config object.
1496        assert (
1497            self.args == []
1498        ), "can only parse cmdline args at most once per Config object"
1499        self.hook.pytest_addhooks.call_historic(
1500            kwargs=dict(pluginmanager=self.pluginmanager)
1501        )
1502        self._preparse(args, addopts=addopts)
1503        self._parser.after_preparse = True  # type: ignore
1504        try:
1505            args = self._parser.parse_setoption(
1506                args, self.option, namespace=self.option
1507            )
1508            self.args, self.args_source = self._decide_args(
1509                args=args,
1510                pyargs=self.known_args_namespace.pyargs,
1511                testpaths=self.getini("testpaths"),
1512                invocation_dir=self.invocation_params.dir,
1513                rootpath=self.rootpath,
1514                warn=True,
1515            )
1516        except PrintHelp:
1517            pass
1518
1519    def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None:
1520        """Issue and handle a warning during the "configure" stage.
1521
1522        During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item``
1523        function because it is not possible to have hook wrappers around ``pytest_configure``.
1524
1525        This function is mainly intended for plugins that need to issue warnings during
1526        ``pytest_configure`` (or similar stages).
1527
1528        :param warning: The warning instance.
1529        :param stacklevel: stacklevel forwarded to warnings.warn.
1530        """
1531        if self.pluginmanager.is_blocked("warnings"):
1532            return
1533
1534        cmdline_filters = self.known_args_namespace.pythonwarnings or []
1535        config_filters = self.getini("filterwarnings")
1536
1537        with warnings.catch_warnings(record=True) as records:
1538            warnings.simplefilter("always", type(warning))
1539            apply_warning_filters(config_filters, cmdline_filters)
1540            warnings.warn(warning, stacklevel=stacklevel)
1541
1542        if records:
1543            frame = sys._getframe(stacklevel - 1)
1544            location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name
1545            self.hook.pytest_warning_recorded.call_historic(
1546                kwargs=dict(
1547                    warning_message=records[0],
1548                    when="config",
1549                    nodeid="",
1550                    location=location,
1551                )
1552            )
1553
1554    def addinivalue_line(self, name: str, line: str) -> None:
1555        """Add a line to an ini-file option. The option must have been
1556        declared but might not yet be set in which case the line becomes
1557        the first line in its value."""
1558        x = self.getini(name)
1559        assert isinstance(x, list)
1560        x.append(line)  # modifies the cached list inline
1561
1562    def getini(self, name: str):
1563        """Return configuration value from an :ref:`ini file <configfiles>`.
1564
1565        If a configuration value is not defined in an
1566        :ref:`ini file <configfiles>`, then the ``default`` value provided while
1567        registering the configuration through
1568        :func:`parser.addini <pytest.Parser.addini>` will be returned.
1569        Please note that you can even provide ``None`` as a valid
1570        default value.
1571
1572        If ``default`` is not provided while registering using
1573        :func:`parser.addini <pytest.Parser.addini>`, then a default value
1574        based on the ``type`` parameter passed to
1575        :func:`parser.addini <pytest.Parser.addini>` will be returned.
1576        The default values based on ``type`` are:
1577        ``paths``, ``pathlist``, ``args`` and ``linelist`` : empty list ``[]``
1578        ``bool`` : ``False``
1579        ``string`` : empty string ``""``
1580
1581        If neither the ``default`` nor the ``type`` parameter is passed
1582        while registering the configuration through
1583        :func:`parser.addini <pytest.Parser.addini>`, then the configuration
1584        is treated as a string and a default empty string '' is returned.
1585
1586        If the specified name hasn't been registered through a prior
1587        :func:`parser.addini <pytest.Parser.addini>` call (usually from a
1588        plugin), a ValueError is raised.
1589        """
1590        try:
1591            return self._inicache[name]
1592        except KeyError:
1593            self._inicache[name] = val = self._getini(name)
1594            return val
1595
1596    # Meant for easy monkeypatching by legacypath plugin.
1597    # Can be inlined back (with no cover removed) once legacypath is gone.
1598    def _getini_unknown_type(self, name: str, type: str, value: Union[str, List[str]]):
1599        msg = f"unknown configuration type: {type}"
1600        raise ValueError(msg, value)  # pragma: no cover
1601
1602    def _getini(self, name: str):
1603        try:
1604            description, type, default = self._parser._inidict[name]
1605        except KeyError as e:
1606            raise ValueError(f"unknown configuration value: {name!r}") from e
1607        override_value = self._get_override_ini_value(name)
1608        if override_value is None:
1609            try:
1610                value = self.inicfg[name]
1611            except KeyError:
1612                return default
1613        else:
1614            value = override_value
1615        # Coerce the values based on types.
1616        #
1617        # Note: some coercions are only required if we are reading from .ini files, because
1618        # the file format doesn't contain type information, but when reading from toml we will
1619        # get either str or list of str values (see _parse_ini_config_from_pyproject_toml).
1620        # For example:
1621        #
1622        #   ini:
1623        #     a_line_list = "tests acceptance"
1624        #   in this case, we need to split the string to obtain a list of strings.
1625        #
1626        #   toml:
1627        #     a_line_list = ["tests", "acceptance"]
1628        #   in this case, we already have a list ready to use.
1629        #
1630        if type == "paths":
1631            dp = (
1632                self.inipath.parent
1633                if self.inipath is not None
1634                else self.invocation_params.dir
1635            )
1636            input_values = shlex.split(value) if isinstance(value, str) else value
1637            return [dp / x for x in input_values]
1638        elif type == "args":
1639            return shlex.split(value) if isinstance(value, str) else value
1640        elif type == "linelist":
1641            if isinstance(value, str):
1642                return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
1643            else:
1644                return value
1645        elif type == "bool":
1646            return _strtobool(str(value).strip())
1647        elif type == "string":
1648            return value
1649        elif type is None:
1650            return value
1651        else:
1652            return self._getini_unknown_type(name, type, value)
1653
1654    def _getconftest_pathlist(self, name: str, path: Path) -> Optional[List[Path]]:
1655        try:
1656            mod, relroots = self.pluginmanager._rget_with_confmod(name, path)
1657        except KeyError:
1658            return None
1659        assert mod.__file__ is not None
1660        modpath = Path(mod.__file__).parent
1661        values: List[Path] = []
1662        for relroot in relroots:
1663            if isinstance(relroot, os.PathLike):
1664                relroot = Path(relroot)
1665            else:
1666                relroot = relroot.replace("/", os.sep)
1667                relroot = absolutepath(modpath / relroot)
1668            values.append(relroot)
1669        return values
1670
1671    def _get_override_ini_value(self, name: str) -> Optional[str]:
1672        value = None
1673        # override_ini is a list of "ini=value" options.
1674        # Always use the last item if multiple values are set for same ini-name,
1675        # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2.
1676        for ini_config in self._override_ini:
1677            try:
1678                key, user_ini_value = ini_config.split("=", 1)
1679            except ValueError as e:
1680                raise UsageError(
1681                    f"-o/--override-ini expects option=value style (got: {ini_config!r})."
1682                ) from e
1683            else:
1684                if key == name:
1685                    value = user_ini_value
1686        return value
1687
1688    def getoption(self, name: str, default=notset, skip: bool = False):
1689        """Return command line option value.
1690
1691        :param name: Name of the option.  You may also specify
1692            the literal ``--OPT`` option instead of the "dest" option name.
1693        :param default: Default value if no option of that name exists.
1694        :param skip: If True, raise pytest.skip if option does not exists
1695            or has a None value.
1696        """
1697        name = self._opt2dest.get(name, name)
1698        try:
1699            val = getattr(self.option, name)
1700            if val is None and skip:
1701                raise AttributeError(name)
1702            return val
1703        except AttributeError as e:
1704            if default is not notset:
1705                return default
1706            if skip:
1707                import pytest
1708
1709                pytest.skip(f"no {name!r} option found")
1710            raise ValueError(f"no option named {name!r}") from e
1711
1712    def getvalue(self, name: str, path=None):
1713        """Deprecated, use getoption() instead."""
1714        return self.getoption(name)
1715
1716    def getvalueorskip(self, name: str, path=None):
1717        """Deprecated, use getoption(skip=True) instead."""
1718        return self.getoption(name, skip=True)
1719
1720    #: Verbosity type for failed assertions (see :confval:`verbosity_assertions`).
1721    VERBOSITY_ASSERTIONS: Final = "assertions"
1722    #: Verbosity type for test case execution (see :confval:`verbosity_test_cases`).
1723    VERBOSITY_TEST_CASES: Final = "test_cases"
1724    _VERBOSITY_INI_DEFAULT: Final = "auto"
1725
1726    def get_verbosity(self, verbosity_type: Optional[str] = None) -> int:
1727        r"""Retrieve the verbosity level for a fine-grained verbosity type.
1728
1729        :param verbosity_type: Verbosity type to get level for. If a level is
1730            configured for the given type, that value will be returned. If the
1731            given type is not a known verbosity type, the global verbosity
1732            level will be returned. If the given type is None (default), the
1733            global verbosity level will be returned.
1734
1735        To configure a level for a fine-grained verbosity type, the
1736        configuration file should have a setting for the configuration name
1737        and a numeric value for the verbosity level. A special value of "auto"
1738        can be used to explicitly use the global verbosity level.
1739
1740        Example:
1741        .. code-block:: ini
1742
1743            # content of pytest.ini
1744            [pytest]
1745            verbosity_assertions = 2
1746
1747        .. code-block:: console
1748
1749            pytest -v
1750
1751        .. code-block:: python
1752
1753            print(config.get_verbosity())  # 1
1754            print(config.get_verbosity(Config.VERBOSITY_ASSERTIONS))  # 2
1755        """
1756        global_level = self.option.verbose
1757        assert isinstance(global_level, int)
1758        if verbosity_type is None:
1759            return global_level
1760
1761        ini_name = Config._verbosity_ini_name(verbosity_type)
1762        if ini_name not in self._parser._inidict:
1763            return global_level
1764
1765        level = self.getini(ini_name)
1766        if level == Config._VERBOSITY_INI_DEFAULT:
1767            return global_level
1768
1769        return int(level)
1770
1771    @staticmethod
1772    def _verbosity_ini_name(verbosity_type: str) -> str:
1773        return f"verbosity_{verbosity_type}"
1774
1775    @staticmethod
1776    def _add_verbosity_ini(parser: "Parser", verbosity_type: str, help: str) -> None:
1777        """Add a output verbosity configuration option for the given output type.
1778
1779        :param parser: Parser for command line arguments and ini-file values.
1780        :param verbosity_type: Fine-grained verbosity category.
1781        :param help: Description of the output this type controls.
1782
1783        The value should be retrieved via a call to
1784        :py:func:`config.get_verbosity(type) <pytest.Config.get_verbosity>`.
1785        """
1786        parser.addini(
1787            Config._verbosity_ini_name(verbosity_type),
1788            help=help,
1789            type="string",
1790            default=Config._VERBOSITY_INI_DEFAULT,
1791        )
1792
1793    def _warn_about_missing_assertion(self, mode: str) -> None:
1794        if not _assertion_supported():
1795            if mode == "plain":
1796                warning_text = (
1797                    "ASSERTIONS ARE NOT EXECUTED"
1798                    " and FAILING TESTS WILL PASS.  Are you"
1799                    " using python -O?"
1800                )
1801            else:
1802                warning_text = (
1803                    "assertions not in test modules or"
1804                    " plugins will be ignored"
1805                    " because assert statements are not executed "
1806                    "by the underlying Python interpreter "
1807                    "(are you using python -O?)\n"
1808                )
1809            self.issue_config_time_warning(
1810                PytestConfigWarning(warning_text),
1811                stacklevel=3,
1812            )
1813
1814    def _warn_about_skipped_plugins(self) -> None:
1815        for module_name, msg in self.pluginmanager.skipped_plugins:
1816            self.issue_config_time_warning(
1817                PytestConfigWarning(f"skipped plugin {module_name!r}: {msg}"),
1818                stacklevel=2,
1819            )

Access to configuration values, pluginmanager and plugin hooks.

Parameters
  • PytestPluginManager pluginmanager: A pytest PluginManager.

  • InvocationParams invocation_params: Object containing parameters regarding the pytest.main() invocation.

Config( pluginmanager: PytestPluginManager, *, invocation_params: Optional[Config.InvocationParams] = None)
1035    def __init__(
1036        self,
1037        pluginmanager: PytestPluginManager,
1038        *,
1039        invocation_params: Optional[InvocationParams] = None,
1040    ) -> None:
1041        from .argparsing import FILE_OR_DIR
1042        from .argparsing import Parser
1043
1044        if invocation_params is None:
1045            invocation_params = self.InvocationParams(
1046                args=(), plugins=None, dir=Path.cwd()
1047            )
1048
1049        self.option = argparse.Namespace()
1050        """Access to command line option as attributes.
1051
1052        :type: argparse.Namespace
1053        """
1054
1055        self.invocation_params = invocation_params
1056        """The parameters with which pytest was invoked.
1057
1058        :type: InvocationParams
1059        """
1060
1061        _a = FILE_OR_DIR
1062        self._parser = Parser(
1063            usage=f"%(prog)s [options] [{_a}] [{_a}] [...]",
1064            processopt=self._processopt,
1065            _ispytest=True,
1066        )
1067        self.pluginmanager = pluginmanager
1068        """The plugin manager handles plugin registration and hook invocation.
1069
1070        :type: PytestPluginManager
1071        """
1072
1073        self.stash = Stash()
1074        """A place where plugins can store information on the config for their
1075        own use.
1076
1077        :type: Stash
1078        """
1079        # Deprecated alias. Was never public. Can be removed in a few releases.
1080        self._store = self.stash
1081
1082        self.trace = self.pluginmanager.trace.root.get("config")
1083        self.hook: pluggy.HookRelay = PathAwareHookProxy(self.pluginmanager.hook)  # type: ignore[assignment]
1084        self._inicache: Dict[str, Any] = {}
1085        self._override_ini: Sequence[str] = ()
1086        self._opt2dest: Dict[str, str] = {}
1087        self._cleanup: List[Callable[[], None]] = []
1088        self.pluginmanager.register(self, "pytestconfig")
1089        self._configured = False
1090        self.hook.pytest_addoption.call_historic(
1091            kwargs=dict(parser=self._parser, pluginmanager=self.pluginmanager)
1092        )
1093        self.args_source = Config.ArgsSource.ARGS
1094        self.args: List[str] = []
1095
1096        if TYPE_CHECKING:
1097            from _pytest.cacheprovider import Cache
1098
1099            self.cache: Optional[Cache] = None
option

Access to command line option as attributes.

invocation_params

The parameters with which pytest was invoked.

pluginmanager

The plugin manager handles plugin registration and hook invocation.

stash

A place where plugins can store information on the config for their own use.

trace
hook: pluggy._hooks.HookRelay
args_source
args: List[str]
rootpath: pathlib.Path
1101    @property
1102    def rootpath(self) -> Path:
1103        """The path to the :ref:`rootdir <rootdir>`.
1104
1105        :type: pathlib.Path
1106
1107        .. versionadded:: 6.1
1108        """
1109        return self._rootpath

The path to the :ref:rootdir <rootdir>.

New in version 6.1.

inipath: Optional[pathlib.Path]
1111    @property
1112    def inipath(self) -> Optional[Path]:
1113        """The path to the :ref:`configfile <configfiles>`.
1114
1115        :type: Optional[pathlib.Path]
1116
1117        .. versionadded:: 6.1
1118        """
1119        return self._inipath

The path to the :ref:configfile <configfiles>.

New in version 6.1.

def add_cleanup(self, func: Callable[[], NoneType]) -> None:
1121    def add_cleanup(self, func: Callable[[], None]) -> None:
1122        """Add a function to be called when the config object gets out of
1123        use (usually coinciding with pytest_unconfigure)."""
1124        self._cleanup.append(func)

Add a function to be called when the config object gets out of use (usually coinciding with pytest_unconfigure).

def get_terminal_writer(self) -> _pytest._io.terminalwriter.TerminalWriter:
1142    def get_terminal_writer(self) -> TerminalWriter:
1143        terminalreporter: Optional[TerminalReporter] = self.pluginmanager.get_plugin(
1144            "terminalreporter"
1145        )
1146        assert terminalreporter is not None
1147        return terminalreporter._tw
def pytest_cmdline_parse( self, pluginmanager: PytestPluginManager, args: List[str]) -> Config:
1149    def pytest_cmdline_parse(
1150        self, pluginmanager: PytestPluginManager, args: List[str]
1151    ) -> "Config":
1152        try:
1153            self.parse(args)
1154        except UsageError:
1155            # Handle --version and --help here in a minimal fashion.
1156            # This gets done via helpconfig normally, but its
1157            # pytest_cmdline_main is not called in case of errors.
1158            if getattr(self.option, "version", False) or "--version" in args:
1159                from _pytest.helpconfig import showversion
1160
1161                showversion(self)
1162            elif (
1163                getattr(self.option, "help", False) or "--help" in args or "-h" in args
1164            ):
1165                self._parser._getparser().print_help()
1166                sys.stdout.write(
1167                    "\nNOTE: displaying only minimal help due to UsageError.\n\n"
1168                )
1169
1170            raise
1171
1172        return self
def notify_exception( self, excinfo: ExceptionInfo[BaseException], option: Optional[argparse.Namespace] = None) -> None:
1174    def notify_exception(
1175        self,
1176        excinfo: ExceptionInfo[BaseException],
1177        option: Optional[argparse.Namespace] = None,
1178    ) -> None:
1179        if option and getattr(option, "fulltrace", False):
1180            style: _TracebackStyle = "long"
1181        else:
1182            style = "native"
1183        excrepr = excinfo.getrepr(
1184            funcargs=True, showlocals=getattr(option, "showlocals", False), style=style
1185        )
1186        res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo)
1187        if not any(res):
1188            for line in str(excrepr).split("\n"):
1189                sys.stderr.write("INTERNALERROR> %s\n" % line)
1190                sys.stderr.flush()
def cwd_relative_nodeid(self, nodeid: str) -> str:
1192    def cwd_relative_nodeid(self, nodeid: str) -> str:
1193        # nodeid's are relative to the rootpath, compute relative to cwd.
1194        if self.invocation_params.dir != self.rootpath:
1195            fullpath = self.rootpath / nodeid
1196            nodeid = bestrelpath(self.invocation_params.dir, fullpath)
1197        return nodeid
@classmethod
def fromdictargs(cls, option_dict, args) -> Config:
1199    @classmethod
1200    def fromdictargs(cls, option_dict, args) -> "Config":
1201        """Constructor usable for subprocesses."""
1202        config = get_config(args)
1203        config.option.__dict__.update(option_dict)
1204        config.parse(args, addopts=False)
1205        for x in config.option.plugins:
1206            config.pluginmanager.consider_pluginarg(x)
1207        return config

Constructor usable for subprocesses.

@hookimpl(trylast=True)
def pytest_load_initial_conftests(self, early_config: Config) -> None:
1217    @hookimpl(trylast=True)
1218    def pytest_load_initial_conftests(self, early_config: "Config") -> None:
1219        # We haven't fully parsed the command line arguments yet, so
1220        # early_config.args it not set yet. But we need it for
1221        # discovering the initial conftests. So "pre-run" the logic here.
1222        # It will be done for real in `parse()`.
1223        args, args_source = early_config._decide_args(
1224            args=early_config.known_args_namespace.file_or_dir,
1225            pyargs=early_config.known_args_namespace.pyargs,
1226            testpaths=early_config.getini("testpaths"),
1227            invocation_dir=early_config.invocation_params.dir,
1228            rootpath=early_config.rootpath,
1229            warn=False,
1230        )
1231        self.pluginmanager._set_initial_conftests(
1232            args=args,
1233            pyargs=early_config.known_args_namespace.pyargs,
1234            noconftest=early_config.known_args_namespace.noconftest,
1235            rootpath=early_config.rootpath,
1236            confcutdir=early_config.known_args_namespace.confcutdir,
1237            invocation_dir=early_config.invocation_params.dir,
1238            importmode=early_config.known_args_namespace.importmode,
1239            consider_namespace_packages=early_config.getini(
1240                "consider_namespace_packages"
1241            ),
1242        )
@hookimpl(wrapper=True)
def pytest_collection(self) -> Generator[NoneType, object, object]:
1420    @hookimpl(wrapper=True)
1421    def pytest_collection(self) -> Generator[None, object, object]:
1422        # Validate invalid ini keys after collection is done so we take in account
1423        # options added by late-loading conftest files.
1424        try:
1425            return (yield)
1426        finally:
1427            self._validate_config_options()
def parse(self, args: List[str], addopts: bool = True) -> None:
1494    def parse(self, args: List[str], addopts: bool = True) -> None:
1495        # Parse given cmdline arguments into this config object.
1496        assert (
1497            self.args == []
1498        ), "can only parse cmdline args at most once per Config object"
1499        self.hook.pytest_addhooks.call_historic(
1500            kwargs=dict(pluginmanager=self.pluginmanager)
1501        )
1502        self._preparse(args, addopts=addopts)
1503        self._parser.after_preparse = True  # type: ignore
1504        try:
1505            args = self._parser.parse_setoption(
1506                args, self.option, namespace=self.option
1507            )
1508            self.args, self.args_source = self._decide_args(
1509                args=args,
1510                pyargs=self.known_args_namespace.pyargs,
1511                testpaths=self.getini("testpaths"),
1512                invocation_dir=self.invocation_params.dir,
1513                rootpath=self.rootpath,
1514                warn=True,
1515            )
1516        except PrintHelp:
1517            pass
def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None:
1519    def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None:
1520        """Issue and handle a warning during the "configure" stage.
1521
1522        During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item``
1523        function because it is not possible to have hook wrappers around ``pytest_configure``.
1524
1525        This function is mainly intended for plugins that need to issue warnings during
1526        ``pytest_configure`` (or similar stages).
1527
1528        :param warning: The warning instance.
1529        :param stacklevel: stacklevel forwarded to warnings.warn.
1530        """
1531        if self.pluginmanager.is_blocked("warnings"):
1532            return
1533
1534        cmdline_filters = self.known_args_namespace.pythonwarnings or []
1535        config_filters = self.getini("filterwarnings")
1536
1537        with warnings.catch_warnings(record=True) as records:
1538            warnings.simplefilter("always", type(warning))
1539            apply_warning_filters(config_filters, cmdline_filters)
1540            warnings.warn(warning, stacklevel=stacklevel)
1541
1542        if records:
1543            frame = sys._getframe(stacklevel - 1)
1544            location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name
1545            self.hook.pytest_warning_recorded.call_historic(
1546                kwargs=dict(
1547                    warning_message=records[0],
1548                    when="config",
1549                    nodeid="",
1550                    location=location,
1551                )
1552            )

Issue and handle a warning during the "configure" stage.

During pytest_configure we can't capture warnings using the catch_warnings_for_item function because it is not possible to have hook wrappers around pytest_configure.

This function is mainly intended for plugins that need to issue warnings during pytest_configure (or similar stages).

Parameters
  • warning: The warning instance.
  • stacklevel: stacklevel forwarded to warnings.warn.
def addinivalue_line(self, name: str, line: str) -> None:
1554    def addinivalue_line(self, name: str, line: str) -> None:
1555        """Add a line to an ini-file option. The option must have been
1556        declared but might not yet be set in which case the line becomes
1557        the first line in its value."""
1558        x = self.getini(name)
1559        assert isinstance(x, list)
1560        x.append(line)  # modifies the cached list inline

Add a line to an ini-file option. The option must have been declared but might not yet be set in which case the line becomes the first line in its value.

def getini(self, name: str):
1562    def getini(self, name: str):
1563        """Return configuration value from an :ref:`ini file <configfiles>`.
1564
1565        If a configuration value is not defined in an
1566        :ref:`ini file <configfiles>`, then the ``default`` value provided while
1567        registering the configuration through
1568        :func:`parser.addini <pytest.Parser.addini>` will be returned.
1569        Please note that you can even provide ``None`` as a valid
1570        default value.
1571
1572        If ``default`` is not provided while registering using
1573        :func:`parser.addini <pytest.Parser.addini>`, then a default value
1574        based on the ``type`` parameter passed to
1575        :func:`parser.addini <pytest.Parser.addini>` will be returned.
1576        The default values based on ``type`` are:
1577        ``paths``, ``pathlist``, ``args`` and ``linelist`` : empty list ``[]``
1578        ``bool`` : ``False``
1579        ``string`` : empty string ``""``
1580
1581        If neither the ``default`` nor the ``type`` parameter is passed
1582        while registering the configuration through
1583        :func:`parser.addini <pytest.Parser.addini>`, then the configuration
1584        is treated as a string and a default empty string '' is returned.
1585
1586        If the specified name hasn't been registered through a prior
1587        :func:`parser.addini <pytest.Parser.addini>` call (usually from a
1588        plugin), a ValueError is raised.
1589        """
1590        try:
1591            return self._inicache[name]
1592        except KeyError:
1593            self._inicache[name] = val = self._getini(name)
1594            return val

Return configuration value from an :ref:ini file <configfiles>.

If a configuration value is not defined in an :ref:ini file <configfiles>, then the default value provided while registering the configuration through parser.addini <pytest.Parser.addini>() will be returned. Please note that you can even provide None as a valid default value.

If default is not provided while registering using parser.addini <pytest.Parser.addini>(), then a default value based on the type parameter passed to parser.addini <pytest.Parser.addini>() will be returned. The default values based on type are: paths, pathlist, args and linelist : empty list [] bool : False string : empty string ""

If neither the default nor the type parameter is passed while registering the configuration through parser.addini <pytest.Parser.addini>(), then the configuration is treated as a string and a default empty string '' is returned.

If the specified name hasn't been registered through a prior parser.addini <pytest.Parser.addini>() call (usually from a plugin), a ValueError is raised.

def getoption(self, name: str, default=<NOTSET>, skip: bool = False):
1688    def getoption(self, name: str, default=notset, skip: bool = False):
1689        """Return command line option value.
1690
1691        :param name: Name of the option.  You may also specify
1692            the literal ``--OPT`` option instead of the "dest" option name.
1693        :param default: Default value if no option of that name exists.
1694        :param skip: If True, raise pytest.skip if option does not exists
1695            or has a None value.
1696        """
1697        name = self._opt2dest.get(name, name)
1698        try:
1699            val = getattr(self.option, name)
1700            if val is None and skip:
1701                raise AttributeError(name)
1702            return val
1703        except AttributeError as e:
1704            if default is not notset:
1705                return default
1706            if skip:
1707                import pytest
1708
1709                pytest.skip(f"no {name!r} option found")
1710            raise ValueError(f"no option named {name!r}") from e

Return command line option value.

Parameters
  • name: Name of the option. You may also specify the literal --OPT option instead of the "dest" option name.
  • default: Default value if no option of that name exists.
  • skip: If True, raise pytest.skip if option does not exists or has a None value.
def getvalue(self, name: str, path=None):
1712    def getvalue(self, name: str, path=None):
1713        """Deprecated, use getoption() instead."""
1714        return self.getoption(name)

Deprecated, use getoption() instead.

def getvalueorskip(self, name: str, path=None):
1716    def getvalueorskip(self, name: str, path=None):
1717        """Deprecated, use getoption(skip=True) instead."""
1718        return self.getoption(name, skip=True)

Deprecated, use getoption(skip=True) instead.

VERBOSITY_ASSERTIONS: Final = 'assertions'
VERBOSITY_TEST_CASES: Final = 'test_cases'
def get_verbosity(self, verbosity_type: Optional[str] = None) -> int:
1726    def get_verbosity(self, verbosity_type: Optional[str] = None) -> int:
1727        r"""Retrieve the verbosity level for a fine-grained verbosity type.
1728
1729        :param verbosity_type: Verbosity type to get level for. If a level is
1730            configured for the given type, that value will be returned. If the
1731            given type is not a known verbosity type, the global verbosity
1732            level will be returned. If the given type is None (default), the
1733            global verbosity level will be returned.
1734
1735        To configure a level for a fine-grained verbosity type, the
1736        configuration file should have a setting for the configuration name
1737        and a numeric value for the verbosity level. A special value of "auto"
1738        can be used to explicitly use the global verbosity level.
1739
1740        Example:
1741        .. code-block:: ini
1742
1743            # content of pytest.ini
1744            [pytest]
1745            verbosity_assertions = 2
1746
1747        .. code-block:: console
1748
1749            pytest -v
1750
1751        .. code-block:: python
1752
1753            print(config.get_verbosity())  # 1
1754            print(config.get_verbosity(Config.VERBOSITY_ASSERTIONS))  # 2
1755        """
1756        global_level = self.option.verbose
1757        assert isinstance(global_level, int)
1758        if verbosity_type is None:
1759            return global_level
1760
1761        ini_name = Config._verbosity_ini_name(verbosity_type)
1762        if ini_name not in self._parser._inidict:
1763            return global_level
1764
1765        level = self.getini(ini_name)
1766        if level == Config._VERBOSITY_INI_DEFAULT:
1767            return global_level
1768
1769        return int(level)

Retrieve the verbosity level for a fine-grained verbosity type.

Parameters
  • verbosity_type: Verbosity type to get level for. If a level is configured for the given type, that value will be returned. If the given type is not a known verbosity type, the global verbosity level will be returned. If the given type is None (default), the global verbosity level will be returned.

To configure a level for a fine-grained verbosity type, the configuration file should have a setting for the configuration name and a numeric value for the verbosity level. A special value of "auto" can be used to explicitly use the global verbosity level.

Example:

# content of pytest.ini
[pytest]
verbosity_assertions = 2
pytest -v
print(config.get_verbosity())  # 1
print(config.get_verbosity(Config.VERBOSITY_ASSERTIONS))  # 2
@final
@dataclasses.dataclass(frozen=True)
class Config.InvocationParams:
 986    @final
 987    @dataclasses.dataclass(frozen=True)
 988    class InvocationParams:
 989        """Holds parameters passed during :func:`pytest.main`.
 990
 991        The object attributes are read-only.
 992
 993        .. versionadded:: 5.1
 994
 995        .. note::
 996
 997            Note that the environment variable ``PYTEST_ADDOPTS`` and the ``addopts``
 998            ini option are handled by pytest, not being included in the ``args`` attribute.
 999
1000            Plugins accessing ``InvocationParams`` must be aware of that.
1001        """
1002
1003        args: Tuple[str, ...]
1004        """The command-line arguments as passed to :func:`pytest.main`."""
1005        plugins: Optional[Sequence[Union[str, _PluggyPlugin]]]
1006        """Extra plugins, might be `None`."""
1007        dir: Path
1008        """The directory from which :func:`pytest.main` was invoked."""
1009
1010        def __init__(
1011            self,
1012            *,
1013            args: Iterable[str],
1014            plugins: Optional[Sequence[Union[str, _PluggyPlugin]]],
1015            dir: Path,
1016        ) -> None:
1017            object.__setattr__(self, "args", tuple(args))
1018            object.__setattr__(self, "plugins", plugins)
1019            object.__setattr__(self, "dir", dir)

Holds parameters passed during pytest.main().

The object attributes are read-only.

New in version 5.1.

Note that the environment variable PYTEST_ADDOPTS and the addopts ini option are handled by pytest, not being included in the args attribute.

Plugins accessing InvocationParams must be aware of that.

Config.InvocationParams( *, args: Iterable[str], plugins: Optional[Sequence[Union[str, object]]], dir: pathlib.Path)
1010        def __init__(
1011            self,
1012            *,
1013            args: Iterable[str],
1014            plugins: Optional[Sequence[Union[str, _PluggyPlugin]]],
1015            dir: Path,
1016        ) -> None:
1017            object.__setattr__(self, "args", tuple(args))
1018            object.__setattr__(self, "plugins", plugins)
1019            object.__setattr__(self, "dir", dir)
args: Tuple[str, ...]

The command-line arguments as passed to pytest.main().

plugins: Optional[Sequence[Union[str, object]]]

Extra plugins, might be None.

The directory from which pytest.main() was invoked.

class Config.ArgsSource(enum.Enum):
1021    class ArgsSource(enum.Enum):
1022        """Indicates the source of the test arguments.
1023
1024        .. versionadded:: 7.2
1025        """
1026
1027        #: Command line arguments.
1028        ARGS = enum.auto()
1029        #: Invocation directory.
1030        INVOCATION_DIR = enum.auto()
1031        INCOVATION_DIR = INVOCATION_DIR  # backwards compatibility alias
1032        #: 'testpaths' configuration value.
1033        TESTPATHS = enum.auto()

Indicates the source of the test arguments.

New in version 7.2.

ARGS = <ArgsSource.ARGS: 1>
INVOCATION_DIR = <ArgsSource.INVOCATION_DIR: 2>
INCOVATION_DIR = <ArgsSource.INVOCATION_DIR: 2>
TESTPATHS = <ArgsSource.TESTPATHS: 3>
Inherited Members
enum.Enum
name
value
def console_main() -> int:
200def console_main() -> int:
201    """The CLI entry point of pytest.
202
203    This function is not meant for programmable use; use `main()` instead.
204    """
205    # https://docs.python.org/3/library/signal.html#note-on-sigpipe
206    try:
207        code = main()
208        sys.stdout.flush()
209        return code
210    except BrokenPipeError:
211        # Python flushes standard streams on exit; redirect remaining output
212        # to devnull to avoid another BrokenPipeError at shutdown
213        devnull = os.open(os.devnull, os.O_WRONLY)
214        os.dup2(devnull, sys.stdout.fileno())
215        return 1  # Python exits with error code 1 on EPIPE

The CLI entry point of pytest.

This function is not meant for programmable use; use main() instead.

def deprecated_call( func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any) -> Union[WarningsRecorder, Any]:
55def deprecated_call(
56    func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any
57) -> Union["WarningsRecorder", Any]:
58    """Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning`` or ``FutureWarning``.
59
60    This function can be used as a context manager::
61
62        >>> import warnings
63        >>> def api_call_v2():
64        ...     warnings.warn('use v3 of this api', DeprecationWarning)
65        ...     return 200
66
67        >>> import pytest
68        >>> with pytest.deprecated_call():
69        ...    assert api_call_v2() == 200
70
71    It can also be used by passing a function and ``*args`` and ``**kwargs``,
72    in which case it will ensure calling ``func(*args, **kwargs)`` produces one of
73    the warnings types above. The return value is the return value of the function.
74
75    In the context manager form you may use the keyword argument ``match`` to assert
76    that the warning matches a text or regex.
77
78    The context manager produces a list of :class:`warnings.WarningMessage` objects,
79    one for each warning raised.
80    """
81    __tracebackhide__ = True
82    if func is not None:
83        args = (func, *args)
84    return warns(
85        (DeprecationWarning, PendingDeprecationWarning, FutureWarning), *args, **kwargs
86    )

Assert that code produces a DeprecationWarning or PendingDeprecationWarning or FutureWarning.

This function can be used as a context manager::

>>> import warnings
>>> def api_call_v2():
...     warnings.warn('use v3 of this api', DeprecationWarning)
...     return 200

>>> import pytest
>>> with pytest.deprecated_call():
...    assert api_call_v2() == 200

It can also be used by passing a function and *args and **kwargs, in which case it will ensure calling func(*args, **kwargs) produces one of the warnings types above. The return value is the return value of the function.

In the context manager form you may use the keyword argument match to assert that the warning matches a text or regex.

The context manager produces a list of warnings.WarningMessage objects, one for each warning raised.

@final
class Dir(pytest.Directory):
492@final
493class Dir(nodes.Directory):
494    """Collector of files in a file system directory.
495
496    .. versionadded:: 8.0
497
498    .. note::
499
500        Python directories with an `__init__.py` file are instead collected by
501        :class:`~pytest.Package` by default. Both are :class:`~pytest.Directory`
502        collectors.
503    """
504
505    @classmethod
506    def from_parent(  # type: ignore[override]
507        cls,
508        parent: nodes.Collector,
509        *,
510        path: Path,
511    ) -> "Self":
512        """The public constructor.
513
514        :param parent: The parent collector of this Dir.
515        :param path: The directory's path.
516        """
517        return super().from_parent(parent=parent, path=path)
518
519    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
520        config = self.config
521        col: Optional[nodes.Collector]
522        cols: Sequence[nodes.Collector]
523        ihook = self.ihook
524        for direntry in scandir(self.path):
525            if direntry.is_dir():
526                path = Path(direntry.path)
527                if not self.session.isinitpath(path, with_parents=True):
528                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
529                        continue
530                col = ihook.pytest_collect_directory(path=path, parent=self)
531                if col is not None:
532                    yield col
533
534            elif direntry.is_file():
535                path = Path(direntry.path)
536                if not self.session.isinitpath(path):
537                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
538                        continue
539                cols = ihook.pytest_collect_file(file_path=path, parent=self)
540                yield from cols

Collector of files in a file system directory.

New in version 8.0.

Python directories with an __init__.py file are instead collected by ~pytest.Package by default. Both are ~pytest.Directory collectors.

@classmethod
def from_parent(cls, parent: Collector, *, path: pathlib.Path) -> Self:
505    @classmethod
506    def from_parent(  # type: ignore[override]
507        cls,
508        parent: nodes.Collector,
509        *,
510        path: Path,
511    ) -> "Self":
512        """The public constructor.
513
514        :param parent: The parent collector of this Dir.
515        :param path: The directory's path.
516        """
517        return super().from_parent(parent=parent, path=path)

The public constructor.

Parameters
  • parent: The parent collector of this Dir.
  • path: The directory's path.
def collect(self) -> Iterable[Union[Item, Collector]]:
519    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
520        config = self.config
521        col: Optional[nodes.Collector]
522        cols: Sequence[nodes.Collector]
523        ihook = self.ihook
524        for direntry in scandir(self.path):
525            if direntry.is_dir():
526                path = Path(direntry.path)
527                if not self.session.isinitpath(path, with_parents=True):
528                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
529                        continue
530                col = ihook.pytest_collect_directory(path=path, parent=self)
531                if col is not None:
532                    yield col
533
534            elif direntry.is_file():
535                path = Path(direntry.path)
536                if not self.session.isinitpath(path):
537                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
538                        continue
539                cols = ihook.pytest_collect_file(file_path=path, parent=self)
540                yield from cols

Collect children (items and collectors) for this collector.

Inherited Members
_pytest.nodes.FSCollector
FSCollector
path
Collector
CollectError
repr_failure
_pytest.nodes.Node
fspath
name
parent
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
class Directory(_pytest.nodes.FSCollector, abc.ABC):
637class Directory(FSCollector, abc.ABC):
638    """Base class for collecting files from a directory.
639
640    A basic directory collector does the following: goes over the files and
641    sub-directories in the directory and creates collectors for them by calling
642    the hooks :hook:`pytest_collect_directory` and :hook:`pytest_collect_file`,
643    after checking that they are not ignored using
644    :hook:`pytest_ignore_collect`.
645
646    The default directory collectors are :class:`~pytest.Dir` and
647    :class:`~pytest.Package`.
648
649    .. versionadded:: 8.0
650
651    :ref:`custom directory collectors`.
652    """

Base class for collecting files from a directory.

A basic directory collector does the following: goes over the files and sub-directories in the directory and creates collectors for them by calling the hooks :hook:pytest_collect_directory and :hook:pytest_collect_file, after checking that they are not ignored using :hook:pytest_ignore_collect.

The default directory collectors are ~pytest.Dir and ~pytest.Package.

New in version 8.0.

:ref:custom directory collectors.

Inherited Members
_pytest.nodes.FSCollector
path
from_parent
Collector
CollectError
collect
repr_failure
_pytest.nodes.Node
fspath
name
parent
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
class DoctestItem(pytest.Item):
255class DoctestItem(Item):
256    def __init__(
257        self,
258        name: str,
259        parent: "Union[DoctestTextfile, DoctestModule]",
260        runner: "doctest.DocTestRunner",
261        dtest: "doctest.DocTest",
262    ) -> None:
263        super().__init__(name, parent)
264        self.runner = runner
265        self.dtest = dtest
266
267        # Stuff needed for fixture support.
268        self.obj = None
269        fm = self.session._fixturemanager
270        fixtureinfo = fm.getfixtureinfo(node=self, func=None, cls=None)
271        self._fixtureinfo = fixtureinfo
272        self.fixturenames = fixtureinfo.names_closure
273        self._initrequest()
274
275    @classmethod
276    def from_parent(  # type: ignore[override]
277        cls,
278        parent: "Union[DoctestTextfile, DoctestModule]",
279        *,
280        name: str,
281        runner: "doctest.DocTestRunner",
282        dtest: "doctest.DocTest",
283    ) -> "Self":
284        # incompatible signature due to imposed limits on subclass
285        """The public named constructor."""
286        return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
287
288    def _initrequest(self) -> None:
289        self.funcargs: Dict[str, object] = {}
290        self._request = TopRequest(self, _ispytest=True)  # type: ignore[arg-type]
291
292    def setup(self) -> None:
293        self._request._fillfixtures()
294        globs = dict(getfixture=self._request.getfixturevalue)
295        for name, value in self._request.getfixturevalue("doctest_namespace").items():
296            globs[name] = value
297        self.dtest.globs.update(globs)
298
299    def runtest(self) -> None:
300        _check_all_skipped(self.dtest)
301        self._disable_output_capturing_for_darwin()
302        failures: List["doctest.DocTestFailure"] = []
303        # Type ignored because we change the type of `out` from what
304        # doctest expects.
305        self.runner.run(self.dtest, out=failures)  # type: ignore[arg-type]
306        if failures:
307            raise MultipleDoctestFailures(failures)
308
309    def _disable_output_capturing_for_darwin(self) -> None:
310        """Disable output capturing. Otherwise, stdout is lost to doctest (#985)."""
311        if platform.system() != "Darwin":
312            return
313        capman = self.config.pluginmanager.getplugin("capturemanager")
314        if capman:
315            capman.suspend_global_capture(in_=True)
316            out, err = capman.read_global_capture()
317            sys.stdout.write(out)
318            sys.stderr.write(err)
319
320    # TODO: Type ignored -- breaks Liskov Substitution.
321    def repr_failure(  # type: ignore[override]
322        self,
323        excinfo: ExceptionInfo[BaseException],
324    ) -> Union[str, TerminalRepr]:
325        import doctest
326
327        failures: Optional[
328            Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
329        ] = None
330        if isinstance(
331            excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
332        ):
333            failures = [excinfo.value]
334        elif isinstance(excinfo.value, MultipleDoctestFailures):
335            failures = excinfo.value.failures
336
337        if failures is None:
338            return super().repr_failure(excinfo)
339
340        reprlocation_lines = []
341        for failure in failures:
342            example = failure.example
343            test = failure.test
344            filename = test.filename
345            if test.lineno is None:
346                lineno = None
347            else:
348                lineno = test.lineno + example.lineno + 1
349            message = type(failure).__name__
350            # TODO: ReprFileLocation doesn't expect a None lineno.
351            reprlocation = ReprFileLocation(filename, lineno, message)  # type: ignore[arg-type]
352            checker = _get_checker()
353            report_choice = _get_report_choice(self.config.getoption("doctestreport"))
354            if lineno is not None:
355                assert failure.test.docstring is not None
356                lines = failure.test.docstring.splitlines(False)
357                # add line numbers to the left of the error message
358                assert test.lineno is not None
359                lines = [
360                    "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)
361                ]
362                # trim docstring error lines to 10
363                lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
364            else:
365                lines = [
366                    "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
367                ]
368                indent = ">>>"
369                for line in example.source.splitlines():
370                    lines.append(f"??? {indent} {line}")
371                    indent = "..."
372            if isinstance(failure, doctest.DocTestFailure):
373                lines += checker.output_difference(
374                    example, failure.got, report_choice
375                ).split("\n")
376            else:
377                inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info)
378                lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
379                lines += [
380                    x.strip("\n") for x in traceback.format_exception(*failure.exc_info)
381                ]
382            reprlocation_lines.append((reprlocation, lines))
383        return ReprFailDoctest(reprlocation_lines)
384
385    def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
386        return self.path, self.dtest.lineno, "[doctest] %s" % self.name

Base class of all test invocation items.

Note that for a single function there might be multiple test invocation items.

DoctestItem( name: str, parent: Union[_pytest.doctest.DoctestTextfile, _pytest.doctest.DoctestModule], runner: doctest.DocTestRunner, dtest: doctest.DocTest)
256    def __init__(
257        self,
258        name: str,
259        parent: "Union[DoctestTextfile, DoctestModule]",
260        runner: "doctest.DocTestRunner",
261        dtest: "doctest.DocTest",
262    ) -> None:
263        super().__init__(name, parent)
264        self.runner = runner
265        self.dtest = dtest
266
267        # Stuff needed for fixture support.
268        self.obj = None
269        fm = self.session._fixturemanager
270        fixtureinfo = fm.getfixtureinfo(node=self, func=None, cls=None)
271        self._fixtureinfo = fixtureinfo
272        self.fixturenames = fixtureinfo.names_closure
273        self._initrequest()
runner
dtest
obj
fixturenames
@classmethod
def from_parent( cls, parent: Union[_pytest.doctest.DoctestTextfile, _pytest.doctest.DoctestModule], *, name: str, runner: doctest.DocTestRunner, dtest: doctest.DocTest) -> Self:
275    @classmethod
276    def from_parent(  # type: ignore[override]
277        cls,
278        parent: "Union[DoctestTextfile, DoctestModule]",
279        *,
280        name: str,
281        runner: "doctest.DocTestRunner",
282        dtest: "doctest.DocTest",
283    ) -> "Self":
284        # incompatible signature due to imposed limits on subclass
285        """The public named constructor."""
286        return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)

The public named constructor.

def setup(self) -> None:
292    def setup(self) -> None:
293        self._request._fillfixtures()
294        globs = dict(getfixture=self._request.getfixturevalue)
295        for name, value in self._request.getfixturevalue("doctest_namespace").items():
296            globs[name] = value
297        self.dtest.globs.update(globs)
def runtest(self) -> None:
299    def runtest(self) -> None:
300        _check_all_skipped(self.dtest)
301        self._disable_output_capturing_for_darwin()
302        failures: List["doctest.DocTestFailure"] = []
303        # Type ignored because we change the type of `out` from what
304        # doctest expects.
305        self.runner.run(self.dtest, out=failures)  # type: ignore[arg-type]
306        if failures:
307            raise MultipleDoctestFailures(failures)

Run the test case for this item.

Must be implemented by subclasses.

seealso :ref:non-python tests.

def repr_failure( self, excinfo: ExceptionInfo[BaseException]) -> Union[str, _pytest._code.code.TerminalRepr]:
321    def repr_failure(  # type: ignore[override]
322        self,
323        excinfo: ExceptionInfo[BaseException],
324    ) -> Union[str, TerminalRepr]:
325        import doctest
326
327        failures: Optional[
328            Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
329        ] = None
330        if isinstance(
331            excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
332        ):
333            failures = [excinfo.value]
334        elif isinstance(excinfo.value, MultipleDoctestFailures):
335            failures = excinfo.value.failures
336
337        if failures is None:
338            return super().repr_failure(excinfo)
339
340        reprlocation_lines = []
341        for failure in failures:
342            example = failure.example
343            test = failure.test
344            filename = test.filename
345            if test.lineno is None:
346                lineno = None
347            else:
348                lineno = test.lineno + example.lineno + 1
349            message = type(failure).__name__
350            # TODO: ReprFileLocation doesn't expect a None lineno.
351            reprlocation = ReprFileLocation(filename, lineno, message)  # type: ignore[arg-type]
352            checker = _get_checker()
353            report_choice = _get_report_choice(self.config.getoption("doctestreport"))
354            if lineno is not None:
355                assert failure.test.docstring is not None
356                lines = failure.test.docstring.splitlines(False)
357                # add line numbers to the left of the error message
358                assert test.lineno is not None
359                lines = [
360                    "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines)
361                ]
362                # trim docstring error lines to 10
363                lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
364            else:
365                lines = [
366                    "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
367                ]
368                indent = ">>>"
369                for line in example.source.splitlines():
370                    lines.append(f"??? {indent} {line}")
371                    indent = "..."
372            if isinstance(failure, doctest.DocTestFailure):
373                lines += checker.output_difference(
374                    example, failure.got, report_choice
375                ).split("\n")
376            else:
377                inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info)
378                lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
379                lines += [
380                    x.strip("\n") for x in traceback.format_exception(*failure.exc_info)
381                ]
382            reprlocation_lines.append((reprlocation, lines))
383        return ReprFailDoctest(reprlocation_lines)

Return a representation of a collection or test failure.

seealso :ref:non-python tests.

Parameters
  • excinfo: Exception information for the failure.
def reportinfo(self) -> Tuple[Union[os.PathLike[str], str], Optional[int], str]:
385    def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
386        return self.path, self.dtest.lineno, "[doctest] %s" % self.name

Get location information for this item for test reports.

Returns a tuple with three elements:

  • The path of the test (default self.path)
  • The 0-based line number of the test (default None)
  • A name of the test to be shown (default "")

seealso :ref:non-python tests.

Inherited Members
Item
nextitem
user_properties
add_report_section
location
_pytest.nodes.Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
def exit(reason: str = '', returncode: Optional[int] = None) -> NoReturn:
105@_with_exception(Exit)
106def exit(
107    reason: str = "",
108    returncode: Optional[int] = None,
109) -> NoReturn:
110    """Exit testing process.
111
112    :param reason:
113        The message to show as the reason for exiting pytest.  reason has a default value
114        only because `msg` is deprecated.
115
116    :param returncode:
117        Return code to be used when exiting pytest. None means the same as ``0`` (no error), same as :func:`sys.exit`.
118    """
119    __tracebackhide__ = True
120    raise Exit(reason, returncode)

Exit testing process.

Parameters
  • reason: The message to show as the reason for exiting pytest. reason has a default value only because msg is deprecated.

  • returncode: Return code to be used when exiting pytest. None means the same as 0 (no error), same as sys.exit().

@final
@dataclasses.dataclass
class ExceptionInfo(typing.Generic[+E]):
443@final
444@dataclasses.dataclass
445class ExceptionInfo(Generic[E]):
446    """Wraps sys.exc_info() objects and offers help for navigating the traceback."""
447
448    _assert_start_repr: ClassVar = "AssertionError('assert "
449
450    _excinfo: Optional[Tuple[Type["E"], "E", TracebackType]]
451    _striptext: str
452    _traceback: Optional[Traceback]
453
454    def __init__(
455        self,
456        excinfo: Optional[Tuple[Type["E"], "E", TracebackType]],
457        striptext: str = "",
458        traceback: Optional[Traceback] = None,
459        *,
460        _ispytest: bool = False,
461    ) -> None:
462        check_ispytest(_ispytest)
463        self._excinfo = excinfo
464        self._striptext = striptext
465        self._traceback = traceback
466
467    @classmethod
468    def from_exception(
469        cls,
470        # Ignoring error: "Cannot use a covariant type variable as a parameter".
471        # This is OK to ignore because this class is (conceptually) readonly.
472        # See https://github.com/python/mypy/issues/7049.
473        exception: E,  # type: ignore[misc]
474        exprinfo: Optional[str] = None,
475    ) -> "ExceptionInfo[E]":
476        """Return an ExceptionInfo for an existing exception.
477
478        The exception must have a non-``None`` ``__traceback__`` attribute,
479        otherwise this function fails with an assertion error. This means that
480        the exception must have been raised, or added a traceback with the
481        :py:meth:`~BaseException.with_traceback()` method.
482
483        :param exprinfo:
484            A text string helping to determine if we should strip
485            ``AssertionError`` from the output. Defaults to the exception
486            message/``__str__()``.
487
488        .. versionadded:: 7.4
489        """
490        assert exception.__traceback__, (
491            "Exceptions passed to ExcInfo.from_exception(...)"
492            " must have a non-None __traceback__."
493        )
494        exc_info = (type(exception), exception, exception.__traceback__)
495        return cls.from_exc_info(exc_info, exprinfo)
496
497    @classmethod
498    def from_exc_info(
499        cls,
500        exc_info: Tuple[Type[E], E, TracebackType],
501        exprinfo: Optional[str] = None,
502    ) -> "ExceptionInfo[E]":
503        """Like :func:`from_exception`, but using old-style exc_info tuple."""
504        _striptext = ""
505        if exprinfo is None and isinstance(exc_info[1], AssertionError):
506            exprinfo = getattr(exc_info[1], "msg", None)
507            if exprinfo is None:
508                exprinfo = saferepr(exc_info[1])
509            if exprinfo and exprinfo.startswith(cls._assert_start_repr):
510                _striptext = "AssertionError: "
511
512        return cls(exc_info, _striptext, _ispytest=True)
513
514    @classmethod
515    def from_current(
516        cls, exprinfo: Optional[str] = None
517    ) -> "ExceptionInfo[BaseException]":
518        """Return an ExceptionInfo matching the current traceback.
519
520        .. warning::
521
522            Experimental API
523
524        :param exprinfo:
525            A text string helping to determine if we should strip
526            ``AssertionError`` from the output. Defaults to the exception
527            message/``__str__()``.
528        """
529        tup = sys.exc_info()
530        assert tup[0] is not None, "no current exception"
531        assert tup[1] is not None, "no current exception"
532        assert tup[2] is not None, "no current exception"
533        exc_info = (tup[0], tup[1], tup[2])
534        return ExceptionInfo.from_exc_info(exc_info, exprinfo)
535
536    @classmethod
537    def for_later(cls) -> "ExceptionInfo[E]":
538        """Return an unfilled ExceptionInfo."""
539        return cls(None, _ispytest=True)
540
541    def fill_unfilled(self, exc_info: Tuple[Type[E], E, TracebackType]) -> None:
542        """Fill an unfilled ExceptionInfo created with ``for_later()``."""
543        assert self._excinfo is None, "ExceptionInfo was already filled"
544        self._excinfo = exc_info
545
546    @property
547    def type(self) -> Type[E]:
548        """The exception class."""
549        assert (
550            self._excinfo is not None
551        ), ".type can only be used after the context manager exits"
552        return self._excinfo[0]
553
554    @property
555    def value(self) -> E:
556        """The exception value."""
557        assert (
558            self._excinfo is not None
559        ), ".value can only be used after the context manager exits"
560        return self._excinfo[1]
561
562    @property
563    def tb(self) -> TracebackType:
564        """The exception raw traceback."""
565        assert (
566            self._excinfo is not None
567        ), ".tb can only be used after the context manager exits"
568        return self._excinfo[2]
569
570    @property
571    def typename(self) -> str:
572        """The type name of the exception."""
573        assert (
574            self._excinfo is not None
575        ), ".typename can only be used after the context manager exits"
576        return self.type.__name__
577
578    @property
579    def traceback(self) -> Traceback:
580        """The traceback."""
581        if self._traceback is None:
582            self._traceback = Traceback(self.tb)
583        return self._traceback
584
585    @traceback.setter
586    def traceback(self, value: Traceback) -> None:
587        self._traceback = value
588
589    def __repr__(self) -> str:
590        if self._excinfo is None:
591            return "<ExceptionInfo for raises contextmanager>"
592        return f"<{self.__class__.__name__} {saferepr(self._excinfo[1])} tblen={len(self.traceback)}>"
593
594    def exconly(self, tryshort: bool = False) -> str:
595        """Return the exception as a string.
596
597        When 'tryshort' resolves to True, and the exception is an
598        AssertionError, only the actual exception part of the exception
599        representation is returned (so 'AssertionError: ' is removed from
600        the beginning).
601        """
602        lines = format_exception_only(self.type, self.value)
603        text = "".join(lines)
604        text = text.rstrip()
605        if tryshort:
606            if text.startswith(self._striptext):
607                text = text[len(self._striptext) :]
608        return text
609
610    def errisinstance(
611        self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]]
612    ) -> bool:
613        """Return True if the exception is an instance of exc.
614
615        Consider using ``isinstance(excinfo.value, exc)`` instead.
616        """
617        return isinstance(self.value, exc)
618
619    def _getreprcrash(self) -> Optional["ReprFileLocation"]:
620        # Find last non-hidden traceback entry that led to the exception of the
621        # traceback, or None if all hidden.
622        for i in range(-1, -len(self.traceback) - 1, -1):
623            entry = self.traceback[i]
624            if not entry.ishidden(self):
625                path, lineno = entry.frame.code.raw.co_filename, entry.lineno
626                exconly = self.exconly(tryshort=True)
627                return ReprFileLocation(path, lineno + 1, exconly)
628        return None
629
630    def getrepr(
631        self,
632        showlocals: bool = False,
633        style: _TracebackStyle = "long",
634        abspath: bool = False,
635        tbfilter: Union[
636            bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
637        ] = True,
638        funcargs: bool = False,
639        truncate_locals: bool = True,
640        chain: bool = True,
641    ) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]:
642        """Return str()able representation of this exception info.
643
644        :param bool showlocals:
645            Show locals per traceback entry.
646            Ignored if ``style=="native"``.
647
648        :param str style:
649            long|short|line|no|native|value traceback style.
650
651        :param bool abspath:
652            If paths should be changed to absolute or left unchanged.
653
654        :param tbfilter:
655            A filter for traceback entries.
656
657            * If false, don't hide any entries.
658            * If true, hide internal entries and entries that contain a local
659              variable ``__tracebackhide__ = True``.
660            * If a callable, delegates the filtering to the callable.
661
662            Ignored if ``style`` is ``"native"``.
663
664        :param bool funcargs:
665            Show fixtures ("funcargs" for legacy purposes) per traceback entry.
666
667        :param bool truncate_locals:
668            With ``showlocals==True``, make sure locals can be safely represented as strings.
669
670        :param bool chain:
671            If chained exceptions in Python 3 should be shown.
672
673        .. versionchanged:: 3.9
674
675            Added the ``chain`` parameter.
676        """
677        if style == "native":
678            return ReprExceptionInfo(
679                reprtraceback=ReprTracebackNative(
680                    traceback.format_exception(
681                        self.type,
682                        self.value,
683                        self.traceback[0]._rawentry if self.traceback else None,
684                    )
685                ),
686                reprcrash=self._getreprcrash(),
687            )
688
689        fmt = FormattedExcinfo(
690            showlocals=showlocals,
691            style=style,
692            abspath=abspath,
693            tbfilter=tbfilter,
694            funcargs=funcargs,
695            truncate_locals=truncate_locals,
696            chain=chain,
697        )
698        return fmt.repr_excinfo(self)
699
700    def _stringify_exception(self, exc: BaseException) -> str:
701        try:
702            notes = getattr(exc, "__notes__", [])
703        except KeyError:
704            # Workaround for https://github.com/python/cpython/issues/98778 on
705            # Python <= 3.9, and some 3.10 and 3.11 patch versions.
706            HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ())
707            if sys.version_info < (3, 12) and isinstance(exc, HTTPError):
708                notes = []
709            else:
710                raise
711
712        return "\n".join(
713            [
714                str(exc),
715                *notes,
716            ]
717        )
718
719    def match(self, regexp: Union[str, Pattern[str]]) -> "Literal[True]":
720        """Check whether the regular expression `regexp` matches the string
721        representation of the exception using :func:`python:re.search`.
722
723        If it matches `True` is returned, otherwise an `AssertionError` is raised.
724        """
725        __tracebackhide__ = True
726        value = self._stringify_exception(self.value)
727        msg = f"Regex pattern did not match.\n Regex: {regexp!r}\n Input: {value!r}"
728        if regexp == value:
729            msg += "\n Did you mean to `re.escape()` the regex?"
730        assert re.search(regexp, value), msg
731        # Return True to allow for "assert excinfo.match()".
732        return True
733
734    def _group_contains(
735        self,
736        exc_group: BaseExceptionGroup[BaseException],
737        expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
738        match: Union[str, Pattern[str], None],
739        target_depth: Optional[int] = None,
740        current_depth: int = 1,
741    ) -> bool:
742        """Return `True` if a `BaseExceptionGroup` contains a matching exception."""
743        if (target_depth is not None) and (current_depth > target_depth):
744            # already descended past the target depth
745            return False
746        for exc in exc_group.exceptions:
747            if isinstance(exc, BaseExceptionGroup):
748                if self._group_contains(
749                    exc, expected_exception, match, target_depth, current_depth + 1
750                ):
751                    return True
752            if (target_depth is not None) and (current_depth != target_depth):
753                # not at the target depth, no match
754                continue
755            if not isinstance(exc, expected_exception):
756                continue
757            if match is not None:
758                value = self._stringify_exception(exc)
759                if not re.search(match, value):
760                    continue
761            return True
762        return False
763
764    def group_contains(
765        self,
766        expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
767        *,
768        match: Union[str, Pattern[str], None] = None,
769        depth: Optional[int] = None,
770    ) -> bool:
771        """Check whether a captured exception group contains a matching exception.
772
773        :param Type[BaseException] | Tuple[Type[BaseException]] expected_exception:
774            The expected exception type, or a tuple if one of multiple possible
775            exception types are expected.
776
777        :param str | Pattern[str] | None match:
778            If specified, a string containing a regular expression,
779            or a regular expression object, that is tested against the string
780            representation of the exception and its `PEP-678 <https://peps.python.org/pep-0678/>` `__notes__`
781            using :func:`re.search`.
782
783            To match a literal string that may contain :ref:`special characters
784            <re-syntax>`, the pattern can first be escaped with :func:`re.escape`.
785
786        :param Optional[int] depth:
787            If `None`, will search for a matching exception at any nesting depth.
788            If >= 1, will only match an exception if it's at the specified depth (depth = 1 being
789            the exceptions contained within the topmost exception group).
790
791        .. versionadded:: 8.0
792        """
793        msg = "Captured exception is not an instance of `BaseExceptionGroup`"
794        assert isinstance(self.value, BaseExceptionGroup), msg
795        msg = "`depth` must be >= 1 if specified"
796        assert (depth is None) or (depth >= 1), msg
797        return self._group_contains(self.value, expected_exception, match, depth)

Wraps sys.exc_info() objects and offers help for navigating the traceback.

ExceptionInfo( excinfo: Optional[Tuple[Type[+E], +E, traceback]], striptext: str = '', traceback: Optional[_pytest._code.code.Traceback] = None, *, _ispytest: bool = False)
454    def __init__(
455        self,
456        excinfo: Optional[Tuple[Type["E"], "E", TracebackType]],
457        striptext: str = "",
458        traceback: Optional[Traceback] = None,
459        *,
460        _ispytest: bool = False,
461    ) -> None:
462        check_ispytest(_ispytest)
463        self._excinfo = excinfo
464        self._striptext = striptext
465        self._traceback = traceback
@classmethod
def from_exception( cls, exception: +E, exprinfo: Optional[str] = None) -> ExceptionInfo[+E]:
467    @classmethod
468    def from_exception(
469        cls,
470        # Ignoring error: "Cannot use a covariant type variable as a parameter".
471        # This is OK to ignore because this class is (conceptually) readonly.
472        # See https://github.com/python/mypy/issues/7049.
473        exception: E,  # type: ignore[misc]
474        exprinfo: Optional[str] = None,
475    ) -> "ExceptionInfo[E]":
476        """Return an ExceptionInfo for an existing exception.
477
478        The exception must have a non-``None`` ``__traceback__`` attribute,
479        otherwise this function fails with an assertion error. This means that
480        the exception must have been raised, or added a traceback with the
481        :py:meth:`~BaseException.with_traceback()` method.
482
483        :param exprinfo:
484            A text string helping to determine if we should strip
485            ``AssertionError`` from the output. Defaults to the exception
486            message/``__str__()``.
487
488        .. versionadded:: 7.4
489        """
490        assert exception.__traceback__, (
491            "Exceptions passed to ExcInfo.from_exception(...)"
492            " must have a non-None __traceback__."
493        )
494        exc_info = (type(exception), exception, exception.__traceback__)
495        return cls.from_exc_info(exc_info, exprinfo)

Return an ExceptionInfo for an existing exception.

The exception must have a non-None __traceback__ attribute, otherwise this function fails with an assertion error. This means that the exception must have been raised, or added a traceback with the ~BaseException.with_traceback()() method.

Parameters
  • exprinfo: A text string helping to determine if we should strip AssertionError from the output. Defaults to the exception message/__str__().

New in version 7.4.

@classmethod
def from_exc_info( cls, exc_info: Tuple[Type[+E], +E, traceback], exprinfo: Optional[str] = None) -> ExceptionInfo[+E]:
497    @classmethod
498    def from_exc_info(
499        cls,
500        exc_info: Tuple[Type[E], E, TracebackType],
501        exprinfo: Optional[str] = None,
502    ) -> "ExceptionInfo[E]":
503        """Like :func:`from_exception`, but using old-style exc_info tuple."""
504        _striptext = ""
505        if exprinfo is None and isinstance(exc_info[1], AssertionError):
506            exprinfo = getattr(exc_info[1], "msg", None)
507            if exprinfo is None:
508                exprinfo = saferepr(exc_info[1])
509            if exprinfo and exprinfo.startswith(cls._assert_start_repr):
510                _striptext = "AssertionError: "
511
512        return cls(exc_info, _striptext, _ispytest=True)

Like from_exception(), but using old-style exc_info tuple.

@classmethod
def from_current( cls, exprinfo: Optional[str] = None) -> ExceptionInfo[BaseException]:
514    @classmethod
515    def from_current(
516        cls, exprinfo: Optional[str] = None
517    ) -> "ExceptionInfo[BaseException]":
518        """Return an ExceptionInfo matching the current traceback.
519
520        .. warning::
521
522            Experimental API
523
524        :param exprinfo:
525            A text string helping to determine if we should strip
526            ``AssertionError`` from the output. Defaults to the exception
527            message/``__str__()``.
528        """
529        tup = sys.exc_info()
530        assert tup[0] is not None, "no current exception"
531        assert tup[1] is not None, "no current exception"
532        assert tup[2] is not None, "no current exception"
533        exc_info = (tup[0], tup[1], tup[2])
534        return ExceptionInfo.from_exc_info(exc_info, exprinfo)

Return an ExceptionInfo matching the current traceback.

Experimental API

Parameters
  • exprinfo: A text string helping to determine if we should strip AssertionError from the output. Defaults to the exception message/__str__().
@classmethod
def for_later(cls) -> ExceptionInfo[+E]:
536    @classmethod
537    def for_later(cls) -> "ExceptionInfo[E]":
538        """Return an unfilled ExceptionInfo."""
539        return cls(None, _ispytest=True)

Return an unfilled ExceptionInfo.

def fill_unfilled(self, exc_info: Tuple[Type[+E], +E, traceback]) -> None:
541    def fill_unfilled(self, exc_info: Tuple[Type[E], E, TracebackType]) -> None:
542        """Fill an unfilled ExceptionInfo created with ``for_later()``."""
543        assert self._excinfo is None, "ExceptionInfo was already filled"
544        self._excinfo = exc_info

Fill an unfilled ExceptionInfo created with for_later().

type: Type[+E]
546    @property
547    def type(self) -> Type[E]:
548        """The exception class."""
549        assert (
550            self._excinfo is not None
551        ), ".type can only be used after the context manager exits"
552        return self._excinfo[0]

The exception class.

value: +E
554    @property
555    def value(self) -> E:
556        """The exception value."""
557        assert (
558            self._excinfo is not None
559        ), ".value can only be used after the context manager exits"
560        return self._excinfo[1]

The exception value.

tb: traceback
562    @property
563    def tb(self) -> TracebackType:
564        """The exception raw traceback."""
565        assert (
566            self._excinfo is not None
567        ), ".tb can only be used after the context manager exits"
568        return self._excinfo[2]

The exception raw traceback.

typename: str
570    @property
571    def typename(self) -> str:
572        """The type name of the exception."""
573        assert (
574            self._excinfo is not None
575        ), ".typename can only be used after the context manager exits"
576        return self.type.__name__

The type name of the exception.

traceback: _pytest._code.code.Traceback
578    @property
579    def traceback(self) -> Traceback:
580        """The traceback."""
581        if self._traceback is None:
582            self._traceback = Traceback(self.tb)
583        return self._traceback

The traceback.

def exconly(self, tryshort: bool = False) -> str:
594    def exconly(self, tryshort: bool = False) -> str:
595        """Return the exception as a string.
596
597        When 'tryshort' resolves to True, and the exception is an
598        AssertionError, only the actual exception part of the exception
599        representation is returned (so 'AssertionError: ' is removed from
600        the beginning).
601        """
602        lines = format_exception_only(self.type, self.value)
603        text = "".join(lines)
604        text = text.rstrip()
605        if tryshort:
606            if text.startswith(self._striptext):
607                text = text[len(self._striptext) :]
608        return text

Return the exception as a string.

When 'tryshort' resolves to True, and the exception is an AssertionError, only the actual exception part of the exception representation is returned (so 'AssertionError: ' is removed from the beginning).

def errisinstance( self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]]) -> bool:
610    def errisinstance(
611        self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]]
612    ) -> bool:
613        """Return True if the exception is an instance of exc.
614
615        Consider using ``isinstance(excinfo.value, exc)`` instead.
616        """
617        return isinstance(self.value, exc)

Return True if the exception is an instance of exc.

Consider using isinstance(excinfo.value, exc) instead.

def getrepr( self, showlocals: bool = False, style: Literal['long', 'short', 'line', 'no', 'native', 'value', 'auto'] = 'long', abspath: bool = False, tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], _pytest._code.code.Traceback]] = True, funcargs: bool = False, truncate_locals: bool = True, chain: bool = True) -> Union[_pytest._code.code.ReprExceptionInfo, _pytest._code.code.ExceptionChainRepr]:
630    def getrepr(
631        self,
632        showlocals: bool = False,
633        style: _TracebackStyle = "long",
634        abspath: bool = False,
635        tbfilter: Union[
636            bool, Callable[["ExceptionInfo[BaseException]"], Traceback]
637        ] = True,
638        funcargs: bool = False,
639        truncate_locals: bool = True,
640        chain: bool = True,
641    ) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]:
642        """Return str()able representation of this exception info.
643
644        :param bool showlocals:
645            Show locals per traceback entry.
646            Ignored if ``style=="native"``.
647
648        :param str style:
649            long|short|line|no|native|value traceback style.
650
651        :param bool abspath:
652            If paths should be changed to absolute or left unchanged.
653
654        :param tbfilter:
655            A filter for traceback entries.
656
657            * If false, don't hide any entries.
658            * If true, hide internal entries and entries that contain a local
659              variable ``__tracebackhide__ = True``.
660            * If a callable, delegates the filtering to the callable.
661
662            Ignored if ``style`` is ``"native"``.
663
664        :param bool funcargs:
665            Show fixtures ("funcargs" for legacy purposes) per traceback entry.
666
667        :param bool truncate_locals:
668            With ``showlocals==True``, make sure locals can be safely represented as strings.
669
670        :param bool chain:
671            If chained exceptions in Python 3 should be shown.
672
673        .. versionchanged:: 3.9
674
675            Added the ``chain`` parameter.
676        """
677        if style == "native":
678            return ReprExceptionInfo(
679                reprtraceback=ReprTracebackNative(
680                    traceback.format_exception(
681                        self.type,
682                        self.value,
683                        self.traceback[0]._rawentry if self.traceback else None,
684                    )
685                ),
686                reprcrash=self._getreprcrash(),
687            )
688
689        fmt = FormattedExcinfo(
690            showlocals=showlocals,
691            style=style,
692            abspath=abspath,
693            tbfilter=tbfilter,
694            funcargs=funcargs,
695            truncate_locals=truncate_locals,
696            chain=chain,
697        )
698        return fmt.repr_excinfo(self)

Return str()able representation of this exception info.

Parameters
  • bool showlocals: Show locals per traceback entry. Ignored if style=="native".

  • str style: long|short|line|no|native|value traceback style.

  • bool abspath: If paths should be changed to absolute or left unchanged.

  • tbfilter: A filter for traceback entries.

    • If false, don't hide any entries.
    • If true, hide internal entries and entries that contain a local variable __tracebackhide__ = True.
    • If a callable, delegates the filtering to the callable.

    Ignored if style is "native".

  • bool funcargs: Show fixtures ("funcargs" for legacy purposes) per traceback entry.

  • bool truncate_locals: With showlocals==True, make sure locals can be safely represented as strings.

  • bool chain: If chained exceptions in Python 3 should be shown.

Changed in version 3.9: Added the chain parameter.

def match(self, regexp: Union[str, Pattern[str]]) -> Literal[True]:
719    def match(self, regexp: Union[str, Pattern[str]]) -> "Literal[True]":
720        """Check whether the regular expression `regexp` matches the string
721        representation of the exception using :func:`python:re.search`.
722
723        If it matches `True` is returned, otherwise an `AssertionError` is raised.
724        """
725        __tracebackhide__ = True
726        value = self._stringify_exception(self.value)
727        msg = f"Regex pattern did not match.\n Regex: {regexp!r}\n Input: {value!r}"
728        if regexp == value:
729            msg += "\n Did you mean to `re.escape()` the regex?"
730        assert re.search(regexp, value), msg
731        # Return True to allow for "assert excinfo.match()".
732        return True

Check whether the regular expression regexp matches the string representation of the exception using python:re.search().

If it matches True is returned, otherwise an AssertionError is raised.

def group_contains( self, expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]], *, match: Union[str, Pattern[str], NoneType] = None, depth: Optional[int] = None) -> bool:
764    def group_contains(
765        self,
766        expected_exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
767        *,
768        match: Union[str, Pattern[str], None] = None,
769        depth: Optional[int] = None,
770    ) -> bool:
771        """Check whether a captured exception group contains a matching exception.
772
773        :param Type[BaseException] | Tuple[Type[BaseException]] expected_exception:
774            The expected exception type, or a tuple if one of multiple possible
775            exception types are expected.
776
777        :param str | Pattern[str] | None match:
778            If specified, a string containing a regular expression,
779            or a regular expression object, that is tested against the string
780            representation of the exception and its `PEP-678 <https://peps.python.org/pep-0678/>` `__notes__`
781            using :func:`re.search`.
782
783            To match a literal string that may contain :ref:`special characters
784            <re-syntax>`, the pattern can first be escaped with :func:`re.escape`.
785
786        :param Optional[int] depth:
787            If `None`, will search for a matching exception at any nesting depth.
788            If >= 1, will only match an exception if it's at the specified depth (depth = 1 being
789            the exceptions contained within the topmost exception group).
790
791        .. versionadded:: 8.0
792        """
793        msg = "Captured exception is not an instance of `BaseExceptionGroup`"
794        assert isinstance(self.value, BaseExceptionGroup), msg
795        msg = "`depth` must be >= 1 if specified"
796        assert (depth is None) or (depth >= 1), msg
797        return self._group_contains(self.value, expected_exception, match, depth)

Check whether a captured exception group contains a matching exception.

Parameters
  • Type[BaseException] | Tuple[Type[BaseException]] expected_exception: The expected exception type, or a tuple if one of multiple possible exception types are expected.

  • str | Pattern[str] | None match: If specified, a string containing a regular expression, or a regular expression object, that is tested against the string representation of the exception and its PEP-678 <https://peps.python.org/pep-0678/> __notes__ using re.search().

    To match a literal string that may contain :ref:special characters <re-syntax>, the pattern can first be escaped with re.escape().

  • Optional[int] depth: If None, will search for a matching exception at any nesting depth. If >= 1, will only match an exception if it's at the specified depth (depth = 1 being the exceptions contained within the topmost exception group).

New in version 8.0.

@final
class ExitCode(enum.IntEnum):
 95@final
 96class ExitCode(enum.IntEnum):
 97    """Encodes the valid exit codes by pytest.
 98
 99    Currently users and plugins may supply other exit codes as well.
100
101    .. versionadded:: 5.0
102    """
103
104    #: Tests passed.
105    OK = 0
106    #: Tests failed.
107    TESTS_FAILED = 1
108    #: pytest was interrupted.
109    INTERRUPTED = 2
110    #: An internal error got in the way.
111    INTERNAL_ERROR = 3
112    #: pytest was misused.
113    USAGE_ERROR = 4
114    #: pytest couldn't find tests.
115    NO_TESTS_COLLECTED = 5

Encodes the valid exit codes by pytest.

Currently users and plugins may supply other exit codes as well.

New in version 5.0.

OK = <ExitCode.OK: 0>
TESTS_FAILED = <ExitCode.TESTS_FAILED: 1>
INTERRUPTED = <ExitCode.INTERRUPTED: 2>
INTERNAL_ERROR = <ExitCode.INTERNAL_ERROR: 3>
USAGE_ERROR = <ExitCode.USAGE_ERROR: 4>
NO_TESTS_COLLECTED = <ExitCode.NO_TESTS_COLLECTED: 5>
Inherited Members
enum.Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
def fail(reason: str = '', pytrace: bool = True) -> NoReturn:
157@_with_exception(Failed)
158def fail(reason: str = "", pytrace: bool = True) -> NoReturn:
159    """Explicitly fail an executing test with the given message.
160
161    :param reason:
162        The message to show the user as reason for the failure.
163
164    :param pytrace:
165        If False, msg represents the full failure information and no
166        python traceback will be reported.
167    """
168    __tracebackhide__ = True
169    raise Failed(msg=reason, pytrace=pytrace)

Explicitly fail an executing test with the given message.

Parameters
  • reason: The message to show the user as reason for the failure.

  • pytrace: If False, msg represents the full failure information and no python traceback will be reported.

class File(_pytest.nodes.FSCollector, abc.ABC):
630class File(FSCollector, abc.ABC):
631    """Base class for collecting tests from a file.
632
633    :ref:`non-python tests`.
634    """

Base class for collecting tests from a file.

:ref:non-python tests.

Inherited Members
_pytest.nodes.FSCollector
path
from_parent
Collector
CollectError
collect
repr_failure
_pytest.nodes.Node
fspath
name
parent
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
def fixture( fixture_function: Optional[~FixtureFunction] = None, *, scope: Union[Literal['session', 'package', 'module', 'class', 'function'], Callable[[str, Config], Literal['session', 'package', 'module', 'class', 'function']]] = 'function', params: Optional[Iterable[object]] = None, autouse: bool = False, ids: Union[Sequence[Optional[object]], Callable[[Any], Optional[object]], NoneType] = None, name: Optional[str] = None) -> Union[_pytest.fixtures.FixtureFunctionMarker, ~FixtureFunction]:
1232def fixture(
1233    fixture_function: Optional[FixtureFunction] = None,
1234    *,
1235    scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function",
1236    params: Optional[Iterable[object]] = None,
1237    autouse: bool = False,
1238    ids: Optional[
1239        Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
1240    ] = None,
1241    name: Optional[str] = None,
1242) -> Union[FixtureFunctionMarker, FixtureFunction]:
1243    """Decorator to mark a fixture factory function.
1244
1245    This decorator can be used, with or without parameters, to define a
1246    fixture function.
1247
1248    The name of the fixture function can later be referenced to cause its
1249    invocation ahead of running tests: test modules or classes can use the
1250    ``pytest.mark.usefixtures(fixturename)`` marker.
1251
1252    Test functions can directly use fixture names as input arguments in which
1253    case the fixture instance returned from the fixture function will be
1254    injected.
1255
1256    Fixtures can provide their values to test functions using ``return`` or
1257    ``yield`` statements. When using ``yield`` the code block after the
1258    ``yield`` statement is executed as teardown code regardless of the test
1259    outcome, and must yield exactly once.
1260
1261    :param scope:
1262        The scope for which this fixture is shared; one of ``"function"``
1263        (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``.
1264
1265        This parameter may also be a callable which receives ``(fixture_name, config)``
1266        as parameters, and must return a ``str`` with one of the values mentioned above.
1267
1268        See :ref:`dynamic scope` in the docs for more information.
1269
1270    :param params:
1271        An optional list of parameters which will cause multiple invocations
1272        of the fixture function and all of the tests using it. The current
1273        parameter is available in ``request.param``.
1274
1275    :param autouse:
1276        If True, the fixture func is activated for all tests that can see it.
1277        If False (the default), an explicit reference is needed to activate
1278        the fixture.
1279
1280    :param ids:
1281        Sequence of ids each corresponding to the params so that they are
1282        part of the test id. If no ids are provided they will be generated
1283        automatically from the params.
1284
1285    :param name:
1286        The name of the fixture. This defaults to the name of the decorated
1287        function. If a fixture is used in the same module in which it is
1288        defined, the function name of the fixture will be shadowed by the
1289        function arg that requests the fixture; one way to resolve this is to
1290        name the decorated function ``fixture_<fixturename>`` and then use
1291        ``@pytest.fixture(name='<fixturename>')``.
1292    """
1293    fixture_marker = FixtureFunctionMarker(
1294        scope=scope,
1295        params=tuple(params) if params is not None else None,
1296        autouse=autouse,
1297        ids=None if ids is None else ids if callable(ids) else tuple(ids),
1298        name=name,
1299        _ispytest=True,
1300    )
1301
1302    # Direct decoration.
1303    if fixture_function:
1304        return fixture_marker(fixture_function)
1305
1306    return fixture_marker

Decorator to mark a fixture factory function.

This decorator can be used, with or without parameters, to define a fixture function.

The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the pytest.mark.usefixtures(fixturename) marker.

Test functions can directly use fixture names as input arguments in which case the fixture instance returned from the fixture function will be injected.

Fixtures can provide their values to test functions using return or yield statements. When using yield the code block after the yield statement is executed as teardown code regardless of the test outcome, and must yield exactly once.

Parameters
  • scope: The scope for which this fixture is shared; one of "function" (default), "class", "module", "package" or "session".

    This parameter may also be a callable which receives (fixture_name, config) as parameters, and must return a str with one of the values mentioned above.

    See :ref:dynamic scope in the docs for more information.

  • params: An optional list of parameters which will cause multiple invocations of the fixture function and all of the tests using it. The current parameter is available in request.param.

  • autouse: If True, the fixture func is activated for all tests that can see it. If False (the default), an explicit reference is needed to activate the fixture.

  • ids: Sequence of ids each corresponding to the params so that they are part of the test id. If no ids are provided they will be generated automatically from the params.

  • name: The name of the fixture. This defaults to the name of the decorated function. If a fixture is used in the same module in which it is defined, the function name of the fixture will be shadowed by the function arg that requests the fixture; one way to resolve this is to name the decorated function fixture_<fixturename> and then use @pytest.fixture(name='<fixturename>').

@final
class FixtureDef(typing.Generic[~FixtureValue]):
 930@final
 931class FixtureDef(Generic[FixtureValue]):
 932    """A container for a fixture definition.
 933
 934    Note: At this time, only explicitly documented fields and methods are
 935    considered public stable API.
 936    """
 937
 938    def __init__(
 939        self,
 940        config: Config,
 941        baseid: Optional[str],
 942        argname: str,
 943        func: "_FixtureFunc[FixtureValue]",
 944        scope: Union[Scope, _ScopeName, Callable[[str, Config], _ScopeName], None],
 945        params: Optional[Sequence[object]],
 946        ids: Optional[
 947            Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]]
 948        ] = None,
 949        *,
 950        _ispytest: bool = False,
 951    ) -> None:
 952        check_ispytest(_ispytest)
 953        # The "base" node ID for the fixture.
 954        #
 955        # This is a node ID prefix. A fixture is only available to a node (e.g.
 956        # a `Function` item) if the fixture's baseid is a nodeid of a parent of
 957        # node.
 958        #
 959        # For a fixture found in a Collector's object (e.g. a `Module`s module,
 960        # a `Class`'s class), the baseid is the Collector's nodeid.
 961        #
 962        # For a fixture found in a conftest plugin, the baseid is the conftest's
 963        # directory path relative to the rootdir.
 964        #
 965        # For other plugins, the baseid is the empty string (always matches).
 966        self.baseid: Final = baseid or ""
 967        # Whether the fixture was found from a node or a conftest in the
 968        # collection tree. Will be false for fixtures defined in non-conftest
 969        # plugins.
 970        self.has_location: Final = baseid is not None
 971        # The fixture factory function.
 972        self.func: Final = func
 973        # The name by which the fixture may be requested.
 974        self.argname: Final = argname
 975        if scope is None:
 976            scope = Scope.Function
 977        elif callable(scope):
 978            scope = _eval_scope_callable(scope, argname, config)
 979        if isinstance(scope, str):
 980            scope = Scope.from_user(
 981                scope, descr=f"Fixture '{func.__name__}'", where=baseid
 982            )
 983        self._scope: Final = scope
 984        # If the fixture is directly parametrized, the parameter values.
 985        self.params: Final = params
 986        # If the fixture is directly parametrized, a tuple of explicit IDs to
 987        # assign to the parameter values, or a callable to generate an ID given
 988        # a parameter value.
 989        self.ids: Final = ids
 990        # The names requested by the fixtures.
 991        self.argnames: Final = getfuncargnames(func, name=argname)
 992        # If the fixture was executed, the current value of the fixture.
 993        # Can change if the fixture is executed with different parameters.
 994        self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
 995        self._finalizers: Final[List[Callable[[], object]]] = []
 996
 997    @property
 998    def scope(self) -> _ScopeName:
 999        """Scope string, one of "function", "class", "module", "package", "session"."""
1000        return self._scope.value
1001
1002    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
1003        self._finalizers.append(finalizer)
1004
1005    def finish(self, request: SubRequest) -> None:
1006        exceptions: List[BaseException] = []
1007        while self._finalizers:
1008            fin = self._finalizers.pop()
1009            try:
1010                fin()
1011            except BaseException as e:
1012                exceptions.append(e)
1013        node = request.node
1014        node.ihook.pytest_fixture_post_finalizer(fixturedef=self, request=request)
1015        # Even if finalization fails, we invalidate the cached fixture
1016        # value and remove all finalizers because they may be bound methods
1017        # which will keep instances alive.
1018        self.cached_result = None
1019        self._finalizers.clear()
1020        if len(exceptions) == 1:
1021            raise exceptions[0]
1022        elif len(exceptions) > 1:
1023            msg = f'errors while tearing down fixture "{self.argname}" of {node}'
1024            raise BaseExceptionGroup(msg, exceptions[::-1])
1025
1026    def execute(self, request: SubRequest) -> FixtureValue:
1027        """Return the value of this fixture, executing it if not cached."""
1028        # Ensure that the dependent fixtures requested by this fixture are loaded.
1029        # This needs to be done before checking if we have a cached value, since
1030        # if a dependent fixture has their cache invalidated, e.g. due to
1031        # parametrization, they finalize themselves and fixtures depending on it
1032        # (which will likely include this fixture) setting `self.cached_result = None`.
1033        # See #4871
1034        requested_fixtures_that_should_finalize_us = []
1035        for argname in self.argnames:
1036            fixturedef = request._get_active_fixturedef(argname)
1037            # Saves requested fixtures in a list so we later can add our finalizer
1038            # to them, ensuring that if a requested fixture gets torn down we get torn
1039            # down first. This is generally handled by SetupState, but still currently
1040            # needed when this fixture is not parametrized but depends on a parametrized
1041            # fixture.
1042            if not isinstance(fixturedef, PseudoFixtureDef):
1043                requested_fixtures_that_should_finalize_us.append(fixturedef)
1044
1045        # Check for (and return) cached value/exception.
1046        my_cache_key = self.cache_key(request)
1047        if self.cached_result is not None:
1048            cache_key = self.cached_result[1]
1049            # note: comparison with `==` can fail (or be expensive) for e.g.
1050            # numpy arrays (#6497).
1051            if my_cache_key is cache_key:
1052                if self.cached_result[2] is not None:
1053                    exc = self.cached_result[2]
1054                    raise exc
1055                else:
1056                    result = self.cached_result[0]
1057                    return result
1058            # We have a previous but differently parametrized fixture instance
1059            # so we need to tear it down before creating a new one.
1060            self.finish(request)
1061            assert self.cached_result is None
1062
1063        # Add finalizer to requested fixtures we saved previously.
1064        # We make sure to do this after checking for cached value to avoid
1065        # adding our finalizer multiple times. (#12135)
1066        finalizer = functools.partial(self.finish, request=request)
1067        for parent_fixture in requested_fixtures_that_should_finalize_us:
1068            parent_fixture.addfinalizer(finalizer)
1069
1070        ihook = request.node.ihook
1071        try:
1072            # Setup the fixture, run the code in it, and cache the value
1073            # in self.cached_result
1074            result = ihook.pytest_fixture_setup(fixturedef=self, request=request)
1075        finally:
1076            # schedule our finalizer, even if the setup failed
1077            request.node.addfinalizer(finalizer)
1078
1079        return result
1080
1081    def cache_key(self, request: SubRequest) -> object:
1082        return getattr(request, "param", None)
1083
1084    def __repr__(self) -> str:
1085        return f"<FixtureDef argname={self.argname!r} scope={self.scope!r} baseid={self.baseid!r}>"

A container for a fixture definition.

Note: At this time, only explicitly documented fields and methods are considered public stable API.

FixtureDef( config: Config, baseid: Optional[str], argname: str, func: Union[Callable[..., ~FixtureValue], Callable[..., Generator[~FixtureValue, NoneType, NoneType]]], scope: Union[_pytest.scope.Scope, Literal['session', 'package', 'module', 'class', 'function'], Callable[[str, Config], Literal['session', 'package', 'module', 'class', 'function']], NoneType], params: Optional[Sequence[object]], ids: Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]], NoneType] = None, *, _ispytest: bool = False)
938    def __init__(
939        self,
940        config: Config,
941        baseid: Optional[str],
942        argname: str,
943        func: "_FixtureFunc[FixtureValue]",
944        scope: Union[Scope, _ScopeName, Callable[[str, Config], _ScopeName], None],
945        params: Optional[Sequence[object]],
946        ids: Optional[
947            Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]]
948        ] = None,
949        *,
950        _ispytest: bool = False,
951    ) -> None:
952        check_ispytest(_ispytest)
953        # The "base" node ID for the fixture.
954        #
955        # This is a node ID prefix. A fixture is only available to a node (e.g.
956        # a `Function` item) if the fixture's baseid is a nodeid of a parent of
957        # node.
958        #
959        # For a fixture found in a Collector's object (e.g. a `Module`s module,
960        # a `Class`'s class), the baseid is the Collector's nodeid.
961        #
962        # For a fixture found in a conftest plugin, the baseid is the conftest's
963        # directory path relative to the rootdir.
964        #
965        # For other plugins, the baseid is the empty string (always matches).
966        self.baseid: Final = baseid or ""
967        # Whether the fixture was found from a node or a conftest in the
968        # collection tree. Will be false for fixtures defined in non-conftest
969        # plugins.
970        self.has_location: Final = baseid is not None
971        # The fixture factory function.
972        self.func: Final = func
973        # The name by which the fixture may be requested.
974        self.argname: Final = argname
975        if scope is None:
976            scope = Scope.Function
977        elif callable(scope):
978            scope = _eval_scope_callable(scope, argname, config)
979        if isinstance(scope, str):
980            scope = Scope.from_user(
981                scope, descr=f"Fixture '{func.__name__}'", where=baseid
982            )
983        self._scope: Final = scope
984        # If the fixture is directly parametrized, the parameter values.
985        self.params: Final = params
986        # If the fixture is directly parametrized, a tuple of explicit IDs to
987        # assign to the parameter values, or a callable to generate an ID given
988        # a parameter value.
989        self.ids: Final = ids
990        # The names requested by the fixtures.
991        self.argnames: Final = getfuncargnames(func, name=argname)
992        # If the fixture was executed, the current value of the fixture.
993        # Can change if the fixture is executed with different parameters.
994        self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
995        self._finalizers: Final[List[Callable[[], object]]] = []
baseid: Final
has_location: Final
func: Final
argname: Final
params: Final
ids: Final
argnames: Final
cached_result: Union[Tuple[~FixtureValue, object, NoneType], Tuple[NoneType, object, BaseException], NoneType]
scope: Literal['session', 'package', 'module', 'class', 'function']
 997    @property
 998    def scope(self) -> _ScopeName:
 999        """Scope string, one of "function", "class", "module", "package", "session"."""
1000        return self._scope.value

Scope string, one of "function", "class", "module", "package", "session".

def addfinalizer(self, finalizer: Callable[[], object]) -> None:
1002    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
1003        self._finalizers.append(finalizer)
def finish(self, request: _pytest.fixtures.SubRequest) -> None:
1005    def finish(self, request: SubRequest) -> None:
1006        exceptions: List[BaseException] = []
1007        while self._finalizers:
1008            fin = self._finalizers.pop()
1009            try:
1010                fin()
1011            except BaseException as e:
1012                exceptions.append(e)
1013        node = request.node
1014        node.ihook.pytest_fixture_post_finalizer(fixturedef=self, request=request)
1015        # Even if finalization fails, we invalidate the cached fixture
1016        # value and remove all finalizers because they may be bound methods
1017        # which will keep instances alive.
1018        self.cached_result = None
1019        self._finalizers.clear()
1020        if len(exceptions) == 1:
1021            raise exceptions[0]
1022        elif len(exceptions) > 1:
1023            msg = f'errors while tearing down fixture "{self.argname}" of {node}'
1024            raise BaseExceptionGroup(msg, exceptions[::-1])
def execute(self, request: _pytest.fixtures.SubRequest) -> ~FixtureValue:
1026    def execute(self, request: SubRequest) -> FixtureValue:
1027        """Return the value of this fixture, executing it if not cached."""
1028        # Ensure that the dependent fixtures requested by this fixture are loaded.
1029        # This needs to be done before checking if we have a cached value, since
1030        # if a dependent fixture has their cache invalidated, e.g. due to
1031        # parametrization, they finalize themselves and fixtures depending on it
1032        # (which will likely include this fixture) setting `self.cached_result = None`.
1033        # See #4871
1034        requested_fixtures_that_should_finalize_us = []
1035        for argname in self.argnames:
1036            fixturedef = request._get_active_fixturedef(argname)
1037            # Saves requested fixtures in a list so we later can add our finalizer
1038            # to them, ensuring that if a requested fixture gets torn down we get torn
1039            # down first. This is generally handled by SetupState, but still currently
1040            # needed when this fixture is not parametrized but depends on a parametrized
1041            # fixture.
1042            if not isinstance(fixturedef, PseudoFixtureDef):
1043                requested_fixtures_that_should_finalize_us.append(fixturedef)
1044
1045        # Check for (and return) cached value/exception.
1046        my_cache_key = self.cache_key(request)
1047        if self.cached_result is not None:
1048            cache_key = self.cached_result[1]
1049            # note: comparison with `==` can fail (or be expensive) for e.g.
1050            # numpy arrays (#6497).
1051            if my_cache_key is cache_key:
1052                if self.cached_result[2] is not None:
1053                    exc = self.cached_result[2]
1054                    raise exc
1055                else:
1056                    result = self.cached_result[0]
1057                    return result
1058            # We have a previous but differently parametrized fixture instance
1059            # so we need to tear it down before creating a new one.
1060            self.finish(request)
1061            assert self.cached_result is None
1062
1063        # Add finalizer to requested fixtures we saved previously.
1064        # We make sure to do this after checking for cached value to avoid
1065        # adding our finalizer multiple times. (#12135)
1066        finalizer = functools.partial(self.finish, request=request)
1067        for parent_fixture in requested_fixtures_that_should_finalize_us:
1068            parent_fixture.addfinalizer(finalizer)
1069
1070        ihook = request.node.ihook
1071        try:
1072            # Setup the fixture, run the code in it, and cache the value
1073            # in self.cached_result
1074            result = ihook.pytest_fixture_setup(fixturedef=self, request=request)
1075        finally:
1076            # schedule our finalizer, even if the setup failed
1077            request.node.addfinalizer(finalizer)
1078
1079        return result

Return the value of this fixture, executing it if not cached.

def cache_key(self, request: _pytest.fixtures.SubRequest) -> object:
1081    def cache_key(self, request: SubRequest) -> object:
1082        return getattr(request, "param", None)
@final
class FixtureLookupError(builtins.LookupError):
777@final
778class FixtureLookupError(LookupError):
779    """Could not return a requested fixture (missing or invalid)."""
780
781    def __init__(
782        self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None
783    ) -> None:
784        self.argname = argname
785        self.request = request
786        self.fixturestack = request._get_fixturestack()
787        self.msg = msg
788
789    def formatrepr(self) -> "FixtureLookupErrorRepr":
790        tblines: List[str] = []
791        addline = tblines.append
792        stack = [self.request._pyfuncitem.obj]
793        stack.extend(map(lambda x: x.func, self.fixturestack))
794        msg = self.msg
795        if msg is not None:
796            # The last fixture raise an error, let's present
797            # it at the requesting side.
798            stack = stack[:-1]
799        for function in stack:
800            fspath, lineno = getfslineno(function)
801            try:
802                lines, _ = inspect.getsourcelines(get_real_func(function))
803            except (OSError, IndexError, TypeError):
804                error_msg = "file %s, line %s: source code not available"
805                addline(error_msg % (fspath, lineno + 1))
806            else:
807                addline(f"file {fspath}, line {lineno + 1}")
808                for i, line in enumerate(lines):
809                    line = line.rstrip()
810                    addline("  " + line)
811                    if line.lstrip().startswith("def"):
812                        break
813
814        if msg is None:
815            fm = self.request._fixturemanager
816            available = set()
817            parent = self.request._pyfuncitem.parent
818            assert parent is not None
819            for name, fixturedefs in fm._arg2fixturedefs.items():
820                faclist = list(fm._matchfactories(fixturedefs, parent))
821                if faclist:
822                    available.add(name)
823            if self.argname in available:
824                msg = (
825                    f" recursive dependency involving fixture '{self.argname}' detected"
826                )
827            else:
828                msg = f"fixture '{self.argname}' not found"
829            msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
830            msg += "\n use 'pytest --fixtures [testpath]' for help on them."
831
832        return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)

Could not return a requested fixture (missing or invalid).

FixtureLookupError( argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None)
781    def __init__(
782        self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None
783    ) -> None:
784        self.argname = argname
785        self.request = request
786        self.fixturestack = request._get_fixturestack()
787        self.msg = msg
argname
request
fixturestack
msg
def formatrepr(self) -> _pytest.fixtures.FixtureLookupErrorRepr:
789    def formatrepr(self) -> "FixtureLookupErrorRepr":
790        tblines: List[str] = []
791        addline = tblines.append
792        stack = [self.request._pyfuncitem.obj]
793        stack.extend(map(lambda x: x.func, self.fixturestack))
794        msg = self.msg
795        if msg is not None:
796            # The last fixture raise an error, let's present
797            # it at the requesting side.
798            stack = stack[:-1]
799        for function in stack:
800            fspath, lineno = getfslineno(function)
801            try:
802                lines, _ = inspect.getsourcelines(get_real_func(function))
803            except (OSError, IndexError, TypeError):
804                error_msg = "file %s, line %s: source code not available"
805                addline(error_msg % (fspath, lineno + 1))
806            else:
807                addline(f"file {fspath}, line {lineno + 1}")
808                for i, line in enumerate(lines):
809                    line = line.rstrip()
810                    addline("  " + line)
811                    if line.lstrip().startswith("def"):
812                        break
813
814        if msg is None:
815            fm = self.request._fixturemanager
816            available = set()
817            parent = self.request._pyfuncitem.parent
818            assert parent is not None
819            for name, fixturedefs in fm._arg2fixturedefs.items():
820                faclist = list(fm._matchfactories(fixturedefs, parent))
821                if faclist:
822                    available.add(name)
823            if self.argname in available:
824                msg = (
825                    f" recursive dependency involving fixture '{self.argname}' detected"
826                )
827            else:
828                msg = f"fixture '{self.argname}' not found"
829            msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
830            msg += "\n use 'pytest --fixtures [testpath]' for help on them."
831
832        return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
Inherited Members
builtins.BaseException
with_traceback
add_note
args
class FixtureRequest(abc.ABC):
342class FixtureRequest(abc.ABC):
343    """The type of the ``request`` fixture.
344
345    A request object gives access to the requesting test context and has a
346    ``param`` attribute in case the fixture is parametrized.
347    """
348
349    def __init__(
350        self,
351        pyfuncitem: "Function",
352        fixturename: Optional[str],
353        arg2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]],
354        fixture_defs: Dict[str, "FixtureDef[Any]"],
355        *,
356        _ispytest: bool = False,
357    ) -> None:
358        check_ispytest(_ispytest)
359        #: Fixture for which this request is being performed.
360        self.fixturename: Final = fixturename
361        self._pyfuncitem: Final = pyfuncitem
362        # The FixtureDefs for each fixture name requested by this item.
363        # Starts from the statically-known fixturedefs resolved during
364        # collection. Dynamically requested fixtures (using
365        # `request.getfixturevalue("foo")`) are added dynamically.
366        self._arg2fixturedefs: Final = arg2fixturedefs
367        # The evaluated argnames so far, mapping to the FixtureDef they resolved
368        # to.
369        self._fixture_defs: Final = fixture_defs
370        # Notes on the type of `param`:
371        # -`request.param` is only defined in parametrized fixtures, and will raise
372        #   AttributeError otherwise. Python typing has no notion of "undefined", so
373        #   this cannot be reflected in the type.
374        # - Technically `param` is only (possibly) defined on SubRequest, not
375        #   FixtureRequest, but the typing of that is still in flux so this cheats.
376        # - In the future we might consider using a generic for the param type, but
377        #   for now just using Any.
378        self.param: Any
379
380    @property
381    def _fixturemanager(self) -> "FixtureManager":
382        return self._pyfuncitem.session._fixturemanager
383
384    @property
385    @abc.abstractmethod
386    def _scope(self) -> Scope:
387        raise NotImplementedError()
388
389    @property
390    def scope(self) -> _ScopeName:
391        """Scope string, one of "function", "class", "module", "package", "session"."""
392        return self._scope.value
393
394    @abc.abstractmethod
395    def _check_scope(
396        self,
397        requested_fixturedef: Union["FixtureDef[object]", PseudoFixtureDef[object]],
398        requested_scope: Scope,
399    ) -> None:
400        raise NotImplementedError()
401
402    @property
403    def fixturenames(self) -> List[str]:
404        """Names of all active fixtures in this request."""
405        result = list(self._pyfuncitem.fixturenames)
406        result.extend(set(self._fixture_defs).difference(result))
407        return result
408
409    @property
410    @abc.abstractmethod
411    def node(self):
412        """Underlying collection node (depends on current request scope)."""
413        raise NotImplementedError()
414
415    @property
416    def config(self) -> Config:
417        """The pytest config object associated with this request."""
418        return self._pyfuncitem.config
419
420    @property
421    def function(self):
422        """Test function object if the request has a per-function scope."""
423        if self.scope != "function":
424            raise AttributeError(
425                f"function not available in {self.scope}-scoped context"
426            )
427        return self._pyfuncitem.obj
428
429    @property
430    def cls(self):
431        """Class (can be None) where the test function was collected."""
432        if self.scope not in ("class", "function"):
433            raise AttributeError(f"cls not available in {self.scope}-scoped context")
434        clscol = self._pyfuncitem.getparent(_pytest.python.Class)
435        if clscol:
436            return clscol.obj
437
438    @property
439    def instance(self):
440        """Instance (can be None) on which test function was collected."""
441        if self.scope != "function":
442            return None
443        return getattr(self._pyfuncitem, "instance", None)
444
445    @property
446    def module(self):
447        """Python module object where the test function was collected."""
448        if self.scope not in ("function", "class", "module"):
449            raise AttributeError(f"module not available in {self.scope}-scoped context")
450        mod = self._pyfuncitem.getparent(_pytest.python.Module)
451        assert mod is not None
452        return mod.obj
453
454    @property
455    def path(self) -> Path:
456        """Path where the test function was collected."""
457        if self.scope not in ("function", "class", "module", "package"):
458            raise AttributeError(f"path not available in {self.scope}-scoped context")
459        return self._pyfuncitem.path
460
461    @property
462    def keywords(self) -> MutableMapping[str, Any]:
463        """Keywords/markers dictionary for the underlying node."""
464        node: nodes.Node = self.node
465        return node.keywords
466
467    @property
468    def session(self) -> "Session":
469        """Pytest session object."""
470        return self._pyfuncitem.session
471
472    @abc.abstractmethod
473    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
474        """Add finalizer/teardown function to be called without arguments after
475        the last test within the requesting test context finished execution."""
476        raise NotImplementedError()
477
478    def applymarker(self, marker: Union[str, MarkDecorator]) -> None:
479        """Apply a marker to a single test function invocation.
480
481        This method is useful if you don't want to have a keyword/marker
482        on all function invocations.
483
484        :param marker:
485            An object created by a call to ``pytest.mark.NAME(...)``.
486        """
487        self.node.add_marker(marker)
488
489    def raiseerror(self, msg: Optional[str]) -> NoReturn:
490        """Raise a FixtureLookupError exception.
491
492        :param msg:
493            An optional custom error message.
494        """
495        raise FixtureLookupError(None, self, msg)
496
497    def getfixturevalue(self, argname: str) -> Any:
498        """Dynamically run a named fixture function.
499
500        Declaring fixtures via function argument is recommended where possible.
501        But if you can only decide whether to use another fixture at test
502        setup time, you may use this function to retrieve it inside a fixture
503        or test function body.
504
505        This method can be used during the test setup phase or the test run
506        phase, but during the test teardown phase a fixture's value may not
507        be available.
508
509        :param argname:
510            The fixture name.
511        :raises pytest.FixtureLookupError:
512            If the given fixture could not be found.
513        """
514        # Note that in addition to the use case described in the docstring,
515        # getfixturevalue() is also called by pytest itself during item and fixture
516        # setup to evaluate the fixtures that are requested statically
517        # (using function parameters, autouse, etc).
518
519        fixturedef = self._get_active_fixturedef(argname)
520        assert fixturedef.cached_result is not None, (
521            f'The fixture value for "{argname}" is not available.  '
522            "This can happen when the fixture has already been torn down."
523        )
524        return fixturedef.cached_result[0]
525
526    def _iter_chain(self) -> Iterator["SubRequest"]:
527        """Yield all SubRequests in the chain, from self up.
528
529        Note: does *not* yield the TopRequest.
530        """
531        current = self
532        while isinstance(current, SubRequest):
533            yield current
534            current = current._parent_request
535
536    def _get_active_fixturedef(
537        self, argname: str
538    ) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]:
539        if argname == "request":
540            cached_result = (self, [0], None)
541            return PseudoFixtureDef(cached_result, Scope.Function)
542
543        # If we already finished computing a fixture by this name in this item,
544        # return it.
545        fixturedef = self._fixture_defs.get(argname)
546        if fixturedef is not None:
547            self._check_scope(fixturedef, fixturedef._scope)
548            return fixturedef
549
550        # Find the appropriate fixturedef.
551        fixturedefs = self._arg2fixturedefs.get(argname, None)
552        if fixturedefs is None:
553            # We arrive here because of a dynamic call to
554            # getfixturevalue(argname) which was naturally
555            # not known at parsing/collection time.
556            fixturedefs = self._fixturemanager.getfixturedefs(argname, self._pyfuncitem)
557            if fixturedefs is not None:
558                self._arg2fixturedefs[argname] = fixturedefs
559        # No fixtures defined with this name.
560        if fixturedefs is None:
561            raise FixtureLookupError(argname, self)
562        # The are no fixtures with this name applicable for the function.
563        if not fixturedefs:
564            raise FixtureLookupError(argname, self)
565        # A fixture may override another fixture with the same name, e.g. a
566        # fixture in a module can override a fixture in a conftest, a fixture in
567        # a class can override a fixture in the module, and so on.
568        # An overriding fixture can request its own name (possibly indirectly);
569        # in this case it gets the value of the fixture it overrides, one level
570        # up.
571        # Check how many `argname`s deep we are, and take the next one.
572        # `fixturedefs` is sorted from furthest to closest, so use negative
573        # indexing to go in reverse.
574        index = -1
575        for request in self._iter_chain():
576            if request.fixturename == argname:
577                index -= 1
578        # If already consumed all of the available levels, fail.
579        if -index > len(fixturedefs):
580            raise FixtureLookupError(argname, self)
581        fixturedef = fixturedefs[index]
582
583        # Prepare a SubRequest object for calling the fixture.
584        try:
585            callspec = self._pyfuncitem.callspec
586        except AttributeError:
587            callspec = None
588        if callspec is not None and argname in callspec.params:
589            param = callspec.params[argname]
590            param_index = callspec.indices[argname]
591            # The parametrize invocation scope overrides the fixture's scope.
592            scope = callspec._arg2scope[argname]
593        else:
594            param = NOTSET
595            param_index = 0
596            scope = fixturedef._scope
597            self._check_fixturedef_without_param(fixturedef)
598        self._check_scope(fixturedef, scope)
599        subrequest = SubRequest(
600            self, scope, param, param_index, fixturedef, _ispytest=True
601        )
602
603        # Make sure the fixture value is cached, running it if it isn't
604        fixturedef.execute(request=subrequest)
605
606        self._fixture_defs[argname] = fixturedef
607        return fixturedef
608
609    def _check_fixturedef_without_param(self, fixturedef: "FixtureDef[object]") -> None:
610        """Check that this request is allowed to execute this fixturedef without
611        a param."""
612        funcitem = self._pyfuncitem
613        has_params = fixturedef.params is not None
614        fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
615        if has_params and fixtures_not_supported:
616            msg = (
617                f"{funcitem.name} does not support fixtures, maybe unittest.TestCase subclass?\n"
618                f"Node id: {funcitem.nodeid}\n"
619                f"Function type: {type(funcitem).__name__}"
620            )
621            fail(msg, pytrace=False)
622        if has_params:
623            frame = inspect.stack()[3]
624            frameinfo = inspect.getframeinfo(frame[0])
625            source_path = absolutepath(frameinfo.filename)
626            source_lineno = frameinfo.lineno
627            try:
628                source_path_str = str(source_path.relative_to(funcitem.config.rootpath))
629            except ValueError:
630                source_path_str = str(source_path)
631            location = getlocation(fixturedef.func, funcitem.config.rootpath)
632            msg = (
633                "The requested fixture has no parameter defined for test:\n"
634                f"    {funcitem.nodeid}\n\n"
635                f"Requested fixture '{fixturedef.argname}' defined in:\n"
636                f"{location}\n\n"
637                f"Requested here:\n"
638                f"{source_path_str}:{source_lineno}"
639            )
640            fail(msg, pytrace=False)
641
642    def _get_fixturestack(self) -> List["FixtureDef[Any]"]:
643        values = [request._fixturedef for request in self._iter_chain()]
644        values.reverse()
645        return values

The type of the request fixture.

A request object gives access to the requesting test context and has a param attribute in case the fixture is parametrized.

fixturename: Final
param: Any
scope: Literal['session', 'package', 'module', 'class', 'function']
389    @property
390    def scope(self) -> _ScopeName:
391        """Scope string, one of "function", "class", "module", "package", "session"."""
392        return self._scope.value

Scope string, one of "function", "class", "module", "package", "session".

fixturenames: List[str]
402    @property
403    def fixturenames(self) -> List[str]:
404        """Names of all active fixtures in this request."""
405        result = list(self._pyfuncitem.fixturenames)
406        result.extend(set(self._fixture_defs).difference(result))
407        return result

Names of all active fixtures in this request.

node
409    @property
410    @abc.abstractmethod
411    def node(self):
412        """Underlying collection node (depends on current request scope)."""
413        raise NotImplementedError()

Underlying collection node (depends on current request scope).

config: Config
415    @property
416    def config(self) -> Config:
417        """The pytest config object associated with this request."""
418        return self._pyfuncitem.config

The pytest config object associated with this request.

function
420    @property
421    def function(self):
422        """Test function object if the request has a per-function scope."""
423        if self.scope != "function":
424            raise AttributeError(
425                f"function not available in {self.scope}-scoped context"
426            )
427        return self._pyfuncitem.obj

Test function object if the request has a per-function scope.

cls
429    @property
430    def cls(self):
431        """Class (can be None) where the test function was collected."""
432        if self.scope not in ("class", "function"):
433            raise AttributeError(f"cls not available in {self.scope}-scoped context")
434        clscol = self._pyfuncitem.getparent(_pytest.python.Class)
435        if clscol:
436            return clscol.obj

Class (can be None) where the test function was collected.

instance
438    @property
439    def instance(self):
440        """Instance (can be None) on which test function was collected."""
441        if self.scope != "function":
442            return None
443        return getattr(self._pyfuncitem, "instance", None)

Instance (can be None) on which test function was collected.

module
445    @property
446    def module(self):
447        """Python module object where the test function was collected."""
448        if self.scope not in ("function", "class", "module"):
449            raise AttributeError(f"module not available in {self.scope}-scoped context")
450        mod = self._pyfuncitem.getparent(_pytest.python.Module)
451        assert mod is not None
452        return mod.obj

Python module object where the test function was collected.

path: pathlib.Path
454    @property
455    def path(self) -> Path:
456        """Path where the test function was collected."""
457        if self.scope not in ("function", "class", "module", "package"):
458            raise AttributeError(f"path not available in {self.scope}-scoped context")
459        return self._pyfuncitem.path

Path where the test function was collected.

keywords: MutableMapping[str, Any]
461    @property
462    def keywords(self) -> MutableMapping[str, Any]:
463        """Keywords/markers dictionary for the underlying node."""
464        node: nodes.Node = self.node
465        return node.keywords

Keywords/markers dictionary for the underlying node.

session: Session
467    @property
468    def session(self) -> "Session":
469        """Pytest session object."""
470        return self._pyfuncitem.session

Pytest session object.

@abc.abstractmethod
def addfinalizer(self, finalizer: Callable[[], object]) -> None:
472    @abc.abstractmethod
473    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
474        """Add finalizer/teardown function to be called without arguments after
475        the last test within the requesting test context finished execution."""
476        raise NotImplementedError()

Add finalizer/teardown function to be called without arguments after the last test within the requesting test context finished execution.

def applymarker(self, marker: Union[str, MarkDecorator]) -> None:
478    def applymarker(self, marker: Union[str, MarkDecorator]) -> None:
479        """Apply a marker to a single test function invocation.
480
481        This method is useful if you don't want to have a keyword/marker
482        on all function invocations.
483
484        :param marker:
485            An object created by a call to ``pytest.mark.NAME(...)``.
486        """
487        self.node.add_marker(marker)

Apply a marker to a single test function invocation.

This method is useful if you don't want to have a keyword/marker on all function invocations.

Parameters
  • marker: An object created by a call to pytest.mark.NAME(...).
def raiseerror(self, msg: Optional[str]) -> NoReturn:
489    def raiseerror(self, msg: Optional[str]) -> NoReturn:
490        """Raise a FixtureLookupError exception.
491
492        :param msg:
493            An optional custom error message.
494        """
495        raise FixtureLookupError(None, self, msg)

Raise a FixtureLookupError exception.

Parameters
  • msg: An optional custom error message.
def getfixturevalue(self, argname: str) -> Any:
497    def getfixturevalue(self, argname: str) -> Any:
498        """Dynamically run a named fixture function.
499
500        Declaring fixtures via function argument is recommended where possible.
501        But if you can only decide whether to use another fixture at test
502        setup time, you may use this function to retrieve it inside a fixture
503        or test function body.
504
505        This method can be used during the test setup phase or the test run
506        phase, but during the test teardown phase a fixture's value may not
507        be available.
508
509        :param argname:
510            The fixture name.
511        :raises pytest.FixtureLookupError:
512            If the given fixture could not be found.
513        """
514        # Note that in addition to the use case described in the docstring,
515        # getfixturevalue() is also called by pytest itself during item and fixture
516        # setup to evaluate the fixtures that are requested statically
517        # (using function parameters, autouse, etc).
518
519        fixturedef = self._get_active_fixturedef(argname)
520        assert fixturedef.cached_result is not None, (
521            f'The fixture value for "{argname}" is not available.  '
522            "This can happen when the fixture has already been torn down."
523        )
524        return fixturedef.cached_result[0]

Dynamically run a named fixture function.

Declaring fixtures via function argument is recommended where possible. But if you can only decide whether to use another fixture at test setup time, you may use this function to retrieve it inside a fixture or test function body.

This method can be used during the test setup phase or the test run phase, but during the test teardown phase a fixture's value may not be available.

Parameters
  • argname: The fixture name.
Raises
def freeze_includes() -> List[str]:
11def freeze_includes() -> List[str]:
12    """Return a list of module names used by pytest that should be
13    included by cx_freeze."""
14    import _pytest
15
16    result = list(_iter_all_modules(_pytest))
17    return result

Return a list of module names used by pytest that should be included by cx_freeze.

class Function(_pytest.python.PyobjMixin, pytest.Item):
1495class Function(PyobjMixin, nodes.Item):
1496    """Item responsible for setting up and executing a Python test function.
1497
1498    :param name:
1499        The full function name, including any decorations like those
1500        added by parametrization (``my_func[my_param]``).
1501    :param parent:
1502        The parent Node.
1503    :param config:
1504        The pytest Config object.
1505    :param callspec:
1506        If given, this function has been parametrized and the callspec contains
1507        meta information about the parametrization.
1508    :param callobj:
1509        If given, the object which will be called when the Function is invoked,
1510        otherwise the callobj will be obtained from ``parent`` using ``originalname``.
1511    :param keywords:
1512        Keywords bound to the function object for "-k" matching.
1513    :param session:
1514        The pytest Session object.
1515    :param fixtureinfo:
1516        Fixture information already resolved at this fixture node..
1517    :param originalname:
1518        The attribute name to use for accessing the underlying function object.
1519        Defaults to ``name``. Set this if name is different from the original name,
1520        for example when it contains decorations like those added by parametrization
1521        (``my_func[my_param]``).
1522    """
1523
1524    # Disable since functions handle it themselves.
1525    _ALLOW_MARKERS = False
1526
1527    def __init__(
1528        self,
1529        name: str,
1530        parent,
1531        config: Optional[Config] = None,
1532        callspec: Optional[CallSpec2] = None,
1533        callobj=NOTSET,
1534        keywords: Optional[Mapping[str, Any]] = None,
1535        session: Optional[Session] = None,
1536        fixtureinfo: Optional[FuncFixtureInfo] = None,
1537        originalname: Optional[str] = None,
1538    ) -> None:
1539        super().__init__(name, parent, config=config, session=session)
1540
1541        if callobj is not NOTSET:
1542            self._obj = callobj
1543            self._instance = getattr(callobj, "__self__", None)
1544
1545        #: Original function name, without any decorations (for example
1546        #: parametrization adds a ``"[...]"`` suffix to function names), used to access
1547        #: the underlying function object from ``parent`` (in case ``callobj`` is not given
1548        #: explicitly).
1549        #:
1550        #: .. versionadded:: 3.0
1551        self.originalname = originalname or name
1552
1553        # Note: when FunctionDefinition is introduced, we should change ``originalname``
1554        # to a readonly property that returns FunctionDefinition.name.
1555
1556        self.own_markers.extend(get_unpacked_marks(self.obj))
1557        if callspec:
1558            self.callspec = callspec
1559            self.own_markers.extend(callspec.marks)
1560
1561        # todo: this is a hell of a hack
1562        # https://github.com/pytest-dev/pytest/issues/4569
1563        # Note: the order of the updates is important here; indicates what
1564        # takes priority (ctor argument over function attributes over markers).
1565        # Take own_markers only; NodeKeywords handles parent traversal on its own.
1566        self.keywords.update((mark.name, mark) for mark in self.own_markers)
1567        self.keywords.update(self.obj.__dict__)
1568        if keywords:
1569            self.keywords.update(keywords)
1570
1571        if fixtureinfo is None:
1572            fm = self.session._fixturemanager
1573            fixtureinfo = fm.getfixtureinfo(self, self.obj, self.cls)
1574        self._fixtureinfo: FuncFixtureInfo = fixtureinfo
1575        self.fixturenames = fixtureinfo.names_closure
1576        self._initrequest()
1577
1578    # todo: determine sound type limitations
1579    @classmethod
1580    def from_parent(cls, parent, **kw) -> "Self":
1581        """The public constructor."""
1582        return super().from_parent(parent=parent, **kw)
1583
1584    def _initrequest(self) -> None:
1585        self.funcargs: Dict[str, object] = {}
1586        self._request = fixtures.TopRequest(self, _ispytest=True)
1587
1588    @property
1589    def function(self):
1590        """Underlying python 'function' object."""
1591        return getimfunc(self.obj)
1592
1593    @property
1594    def instance(self):
1595        try:
1596            return self._instance
1597        except AttributeError:
1598            if isinstance(self.parent, Class):
1599                # Each Function gets a fresh class instance.
1600                self._instance = self._getinstance()
1601            else:
1602                self._instance = None
1603        return self._instance
1604
1605    def _getinstance(self):
1606        if isinstance(self.parent, Class):
1607            # Each Function gets a fresh class instance.
1608            return self.parent.newinstance()
1609        else:
1610            return None
1611
1612    def _getobj(self):
1613        instance = self.instance
1614        if instance is not None:
1615            parent_obj = instance
1616        else:
1617            assert self.parent is not None
1618            parent_obj = self.parent.obj  # type: ignore[attr-defined]
1619        return getattr(parent_obj, self.originalname)
1620
1621    @property
1622    def _pyfuncitem(self):
1623        """(compatonly) for code expecting pytest-2.2 style request objects."""
1624        return self
1625
1626    def runtest(self) -> None:
1627        """Execute the underlying test function."""
1628        self.ihook.pytest_pyfunc_call(pyfuncitem=self)
1629
1630    def setup(self) -> None:
1631        self._request._fillfixtures()
1632
1633    def _traceback_filter(self, excinfo: ExceptionInfo[BaseException]) -> Traceback:
1634        if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False):
1635            code = _pytest._code.Code.from_function(get_real_func(self.obj))
1636            path, firstlineno = code.path, code.firstlineno
1637            traceback = excinfo.traceback
1638            ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
1639            if ntraceback == traceback:
1640                ntraceback = ntraceback.cut(path=path)
1641                if ntraceback == traceback:
1642                    ntraceback = ntraceback.filter(filter_traceback)
1643                    if not ntraceback:
1644                        ntraceback = traceback
1645            ntraceback = ntraceback.filter(excinfo)
1646
1647            # issue364: mark all but first and last frames to
1648            # only show a single-line message for each frame.
1649            if self.config.getoption("tbstyle", "auto") == "auto":
1650                if len(ntraceback) > 2:
1651                    ntraceback = Traceback(
1652                        (
1653                            ntraceback[0],
1654                            *(t.with_repr_style("short") for t in ntraceback[1:-1]),
1655                            ntraceback[-1],
1656                        )
1657                    )
1658
1659            return ntraceback
1660        return excinfo.traceback
1661
1662    # TODO: Type ignored -- breaks Liskov Substitution.
1663    def repr_failure(  # type: ignore[override]
1664        self,
1665        excinfo: ExceptionInfo[BaseException],
1666    ) -> Union[str, TerminalRepr]:
1667        style = self.config.getoption("tbstyle", "auto")
1668        if style == "auto":
1669            style = "long"
1670        return self._repr_failure_py(excinfo, style=style)

Item responsible for setting up and executing a Python test function.

Parameters
  • name: The full function name, including any decorations like those added by parametrization (my_func[my_param]).
  • parent: The parent Node.
  • config: The pytest Config object.
  • callspec: If given, this function has been parametrized and the callspec contains meta information about the parametrization.
  • callobj: If given, the object which will be called when the Function is invoked, otherwise the callobj will be obtained from parent using originalname.
  • keywords: Keywords bound to the function object for "-k" matching.
  • session: The pytest Session object.
  • fixtureinfo: Fixture information already resolved at this fixture node..
  • originalname: The attribute name to use for accessing the underlying function object. Defaults to name. Set this if name is different from the original name, for example when it contains decorations like those added by parametrization (my_func[my_param]).
Function( name: str, parent, config: Optional[Config] = None, callspec: Optional[_pytest.python.CallSpec2] = None, callobj=<NotSetType.token: 0>, keywords: Optional[Mapping[str, Any]] = None, session: Optional[Session] = None, fixtureinfo: Optional[_pytest.fixtures.FuncFixtureInfo] = None, originalname: Optional[str] = None)
1527    def __init__(
1528        self,
1529        name: str,
1530        parent,
1531        config: Optional[Config] = None,
1532        callspec: Optional[CallSpec2] = None,
1533        callobj=NOTSET,
1534        keywords: Optional[Mapping[str, Any]] = None,
1535        session: Optional[Session] = None,
1536        fixtureinfo: Optional[FuncFixtureInfo] = None,
1537        originalname: Optional[str] = None,
1538    ) -> None:
1539        super().__init__(name, parent, config=config, session=session)
1540
1541        if callobj is not NOTSET:
1542            self._obj = callobj
1543            self._instance = getattr(callobj, "__self__", None)
1544
1545        #: Original function name, without any decorations (for example
1546        #: parametrization adds a ``"[...]"`` suffix to function names), used to access
1547        #: the underlying function object from ``parent`` (in case ``callobj`` is not given
1548        #: explicitly).
1549        #:
1550        #: .. versionadded:: 3.0
1551        self.originalname = originalname or name
1552
1553        # Note: when FunctionDefinition is introduced, we should change ``originalname``
1554        # to a readonly property that returns FunctionDefinition.name.
1555
1556        self.own_markers.extend(get_unpacked_marks(self.obj))
1557        if callspec:
1558            self.callspec = callspec
1559            self.own_markers.extend(callspec.marks)
1560
1561        # todo: this is a hell of a hack
1562        # https://github.com/pytest-dev/pytest/issues/4569
1563        # Note: the order of the updates is important here; indicates what
1564        # takes priority (ctor argument over function attributes over markers).
1565        # Take own_markers only; NodeKeywords handles parent traversal on its own.
1566        self.keywords.update((mark.name, mark) for mark in self.own_markers)
1567        self.keywords.update(self.obj.__dict__)
1568        if keywords:
1569            self.keywords.update(keywords)
1570
1571        if fixtureinfo is None:
1572            fm = self.session._fixturemanager
1573            fixtureinfo = fm.getfixtureinfo(self, self.obj, self.cls)
1574        self._fixtureinfo: FuncFixtureInfo = fixtureinfo
1575        self.fixturenames = fixtureinfo.names_closure
1576        self._initrequest()
originalname
fixturenames
@classmethod
def from_parent(cls, parent, **kw) -> Self:
1579    @classmethod
1580    def from_parent(cls, parent, **kw) -> "Self":
1581        """The public constructor."""
1582        return super().from_parent(parent=parent, **kw)

The public constructor.

function
1588    @property
1589    def function(self):
1590        """Underlying python 'function' object."""
1591        return getimfunc(self.obj)

Underlying python 'function' object.

instance
1593    @property
1594    def instance(self):
1595        try:
1596            return self._instance
1597        except AttributeError:
1598            if isinstance(self.parent, Class):
1599                # Each Function gets a fresh class instance.
1600                self._instance = self._getinstance()
1601            else:
1602                self._instance = None
1603        return self._instance

Python instance object the function is bound to.

Returns None if not a test method, e.g. for a standalone test function, a class or a module.

def runtest(self) -> None:
1626    def runtest(self) -> None:
1627        """Execute the underlying test function."""
1628        self.ihook.pytest_pyfunc_call(pyfuncitem=self)

Execute the underlying test function.

def setup(self) -> None:
1630    def setup(self) -> None:
1631        self._request._fillfixtures()
def repr_failure( self, excinfo: ExceptionInfo[BaseException]) -> Union[str, _pytest._code.code.TerminalRepr]:
1663    def repr_failure(  # type: ignore[override]
1664        self,
1665        excinfo: ExceptionInfo[BaseException],
1666    ) -> Union[str, TerminalRepr]:
1667        style = self.config.getoption("tbstyle", "auto")
1668        if style == "auto":
1669            style = "long"
1670        return self._repr_failure_py(excinfo, style=style)

Return a representation of a collection or test failure.

seealso :ref:non-python tests.

Parameters
  • excinfo: Exception information for the failure.
Inherited Members
_pytest.python.PyobjMixin
module
cls
obj
getmodpath
reportinfo
Item
nextitem
user_properties
add_report_section
location
_pytest.nodes.Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
hookimpl = <pluggy._hooks.HookimplMarker object>
@final
class HookRecorder:
253@final
254class HookRecorder:
255    """Record all hooks called in a plugin manager.
256
257    Hook recorders are created by :class:`Pytester`.
258
259    This wraps all the hook calls in the plugin manager, recording each call
260    before propagating the normal calls.
261    """
262
263    def __init__(
264        self, pluginmanager: PytestPluginManager, *, _ispytest: bool = False
265    ) -> None:
266        check_ispytest(_ispytest)
267
268        self._pluginmanager = pluginmanager
269        self.calls: List[RecordedHookCall] = []
270        self.ret: Optional[Union[int, ExitCode]] = None
271
272        def before(hook_name: str, hook_impls, kwargs) -> None:
273            self.calls.append(RecordedHookCall(hook_name, kwargs))
274
275        def after(outcome, hook_name: str, hook_impls, kwargs) -> None:
276            pass
277
278        self._undo_wrapping = pluginmanager.add_hookcall_monitoring(before, after)
279
280    def finish_recording(self) -> None:
281        self._undo_wrapping()
282
283    def getcalls(self, names: Union[str, Iterable[str]]) -> List[RecordedHookCall]:
284        """Get all recorded calls to hooks with the given names (or name)."""
285        if isinstance(names, str):
286            names = names.split()
287        return [call for call in self.calls if call._name in names]
288
289    def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None:
290        __tracebackhide__ = True
291        i = 0
292        entries = list(entries)
293        backlocals = sys._getframe(1).f_locals
294        while entries:
295            name, check = entries.pop(0)
296            for ind, call in enumerate(self.calls[i:]):
297                if call._name == name:
298                    print("NAMEMATCH", name, call)
299                    if eval(check, backlocals, call.__dict__):
300                        print("CHECKERMATCH", repr(check), "->", call)
301                    else:
302                        print("NOCHECKERMATCH", repr(check), "-", call)
303                        continue
304                    i += ind + 1
305                    break
306                print("NONAMEMATCH", name, "with", call)
307            else:
308                fail(f"could not find {name!r} check {check!r}")
309
310    def popcall(self, name: str) -> RecordedHookCall:
311        __tracebackhide__ = True
312        for i, call in enumerate(self.calls):
313            if call._name == name:
314                del self.calls[i]
315                return call
316        lines = [f"could not find call {name!r}, in:"]
317        lines.extend(["  %s" % x for x in self.calls])
318        fail("\n".join(lines))
319
320    def getcall(self, name: str) -> RecordedHookCall:
321        values = self.getcalls(name)
322        assert len(values) == 1, (name, values)
323        return values[0]
324
325    # functionality for test reports
326
327    @overload
328    def getreports(
329        self,
330        names: "Literal['pytest_collectreport']",
331    ) -> Sequence[CollectReport]: ...
332
333    @overload
334    def getreports(
335        self,
336        names: "Literal['pytest_runtest_logreport']",
337    ) -> Sequence[TestReport]: ...
338
339    @overload
340    def getreports(
341        self,
342        names: Union[str, Iterable[str]] = (
343            "pytest_collectreport",
344            "pytest_runtest_logreport",
345        ),
346    ) -> Sequence[Union[CollectReport, TestReport]]: ...
347
348    def getreports(
349        self,
350        names: Union[str, Iterable[str]] = (
351            "pytest_collectreport",
352            "pytest_runtest_logreport",
353        ),
354    ) -> Sequence[Union[CollectReport, TestReport]]:
355        return [x.report for x in self.getcalls(names)]
356
357    def matchreport(
358        self,
359        inamepart: str = "",
360        names: Union[str, Iterable[str]] = (
361            "pytest_runtest_logreport",
362            "pytest_collectreport",
363        ),
364        when: Optional[str] = None,
365    ) -> Union[CollectReport, TestReport]:
366        """Return a testreport whose dotted import path matches."""
367        values = []
368        for rep in self.getreports(names=names):
369            if not when and rep.when != "call" and rep.passed:
370                # setup/teardown passing reports - let's ignore those
371                continue
372            if when and rep.when != when:
373                continue
374            if not inamepart or inamepart in rep.nodeid.split("::"):
375                values.append(rep)
376        if not values:
377            raise ValueError(
378                f"could not find test report matching {inamepart!r}: "
379                "no test reports at all!"
380            )
381        if len(values) > 1:
382            raise ValueError(
383                f"found 2 or more testreports matching {inamepart!r}: {values}"
384            )
385        return values[0]
386
387    @overload
388    def getfailures(
389        self,
390        names: "Literal['pytest_collectreport']",
391    ) -> Sequence[CollectReport]: ...
392
393    @overload
394    def getfailures(
395        self,
396        names: "Literal['pytest_runtest_logreport']",
397    ) -> Sequence[TestReport]: ...
398
399    @overload
400    def getfailures(
401        self,
402        names: Union[str, Iterable[str]] = (
403            "pytest_collectreport",
404            "pytest_runtest_logreport",
405        ),
406    ) -> Sequence[Union[CollectReport, TestReport]]: ...
407
408    def getfailures(
409        self,
410        names: Union[str, Iterable[str]] = (
411            "pytest_collectreport",
412            "pytest_runtest_logreport",
413        ),
414    ) -> Sequence[Union[CollectReport, TestReport]]:
415        return [rep for rep in self.getreports(names) if rep.failed]
416
417    def getfailedcollections(self) -> Sequence[CollectReport]:
418        return self.getfailures("pytest_collectreport")
419
420    def listoutcomes(
421        self,
422    ) -> Tuple[
423        Sequence[TestReport],
424        Sequence[Union[CollectReport, TestReport]],
425        Sequence[Union[CollectReport, TestReport]],
426    ]:
427        passed = []
428        skipped = []
429        failed = []
430        for rep in self.getreports(
431            ("pytest_collectreport", "pytest_runtest_logreport")
432        ):
433            if rep.passed:
434                if rep.when == "call":
435                    assert isinstance(rep, TestReport)
436                    passed.append(rep)
437            elif rep.skipped:
438                skipped.append(rep)
439            else:
440                assert rep.failed, f"Unexpected outcome: {rep!r}"
441                failed.append(rep)
442        return passed, skipped, failed
443
444    def countoutcomes(self) -> List[int]:
445        return [len(x) for x in self.listoutcomes()]
446
447    def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None:
448        __tracebackhide__ = True
449        from _pytest.pytester_assertions import assertoutcome
450
451        outcomes = self.listoutcomes()
452        assertoutcome(
453            outcomes,
454            passed=passed,
455            skipped=skipped,
456            failed=failed,
457        )
458
459    def clear(self) -> None:
460        self.calls[:] = []

Record all hooks called in a plugin manager.

Hook recorders are created by Pytester.

This wraps all the hook calls in the plugin manager, recording each call before propagating the normal calls.

HookRecorder( pluginmanager: PytestPluginManager, *, _ispytest: bool = False)
263    def __init__(
264        self, pluginmanager: PytestPluginManager, *, _ispytest: bool = False
265    ) -> None:
266        check_ispytest(_ispytest)
267
268        self._pluginmanager = pluginmanager
269        self.calls: List[RecordedHookCall] = []
270        self.ret: Optional[Union[int, ExitCode]] = None
271
272        def before(hook_name: str, hook_impls, kwargs) -> None:
273            self.calls.append(RecordedHookCall(hook_name, kwargs))
274
275        def after(outcome, hook_name: str, hook_impls, kwargs) -> None:
276            pass
277
278        self._undo_wrapping = pluginmanager.add_hookcall_monitoring(before, after)
calls: List[RecordedHookCall]
ret: Union[int, ExitCode, NoneType]
def finish_recording(self) -> None:
280    def finish_recording(self) -> None:
281        self._undo_wrapping()
def getcalls( self, names: Union[str, Iterable[str]]) -> List[RecordedHookCall]:
283    def getcalls(self, names: Union[str, Iterable[str]]) -> List[RecordedHookCall]:
284        """Get all recorded calls to hooks with the given names (or name)."""
285        if isinstance(names, str):
286            names = names.split()
287        return [call for call in self.calls if call._name in names]

Get all recorded calls to hooks with the given names (or name).

def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None:
289    def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None:
290        __tracebackhide__ = True
291        i = 0
292        entries = list(entries)
293        backlocals = sys._getframe(1).f_locals
294        while entries:
295            name, check = entries.pop(0)
296            for ind, call in enumerate(self.calls[i:]):
297                if call._name == name:
298                    print("NAMEMATCH", name, call)
299                    if eval(check, backlocals, call.__dict__):
300                        print("CHECKERMATCH", repr(check), "->", call)
301                    else:
302                        print("NOCHECKERMATCH", repr(check), "-", call)
303                        continue
304                    i += ind + 1
305                    break
306                print("NONAMEMATCH", name, "with", call)
307            else:
308                fail(f"could not find {name!r} check {check!r}")
def popcall(self, name: str) -> RecordedHookCall:
310    def popcall(self, name: str) -> RecordedHookCall:
311        __tracebackhide__ = True
312        for i, call in enumerate(self.calls):
313            if call._name == name:
314                del self.calls[i]
315                return call
316        lines = [f"could not find call {name!r}, in:"]
317        lines.extend(["  %s" % x for x in self.calls])
318        fail("\n".join(lines))
def getcall(self, name: str) -> RecordedHookCall:
320    def getcall(self, name: str) -> RecordedHookCall:
321        values = self.getcalls(name)
322        assert len(values) == 1, (name, values)
323        return values[0]
def getreports( self, names: Union[str, Iterable[str]] = ('pytest_collectreport', 'pytest_runtest_logreport')) -> Sequence[Union[CollectReport, TestReport]]:
348    def getreports(
349        self,
350        names: Union[str, Iterable[str]] = (
351            "pytest_collectreport",
352            "pytest_runtest_logreport",
353        ),
354    ) -> Sequence[Union[CollectReport, TestReport]]:
355        return [x.report for x in self.getcalls(names)]
def matchreport( self, inamepart: str = '', names: Union[str, Iterable[str]] = ('pytest_runtest_logreport', 'pytest_collectreport'), when: Optional[str] = None) -> Union[CollectReport, TestReport]:
357    def matchreport(
358        self,
359        inamepart: str = "",
360        names: Union[str, Iterable[str]] = (
361            "pytest_runtest_logreport",
362            "pytest_collectreport",
363        ),
364        when: Optional[str] = None,
365    ) -> Union[CollectReport, TestReport]:
366        """Return a testreport whose dotted import path matches."""
367        values = []
368        for rep in self.getreports(names=names):
369            if not when and rep.when != "call" and rep.passed:
370                # setup/teardown passing reports - let's ignore those
371                continue
372            if when and rep.when != when:
373                continue
374            if not inamepart or inamepart in rep.nodeid.split("::"):
375                values.append(rep)
376        if not values:
377            raise ValueError(
378                f"could not find test report matching {inamepart!r}: "
379                "no test reports at all!"
380            )
381        if len(values) > 1:
382            raise ValueError(
383                f"found 2 or more testreports matching {inamepart!r}: {values}"
384            )
385        return values[0]

Return a testreport whose dotted import path matches.

def getfailures( self, names: Union[str, Iterable[str]] = ('pytest_collectreport', 'pytest_runtest_logreport')) -> Sequence[Union[CollectReport, TestReport]]:
408    def getfailures(
409        self,
410        names: Union[str, Iterable[str]] = (
411            "pytest_collectreport",
412            "pytest_runtest_logreport",
413        ),
414    ) -> Sequence[Union[CollectReport, TestReport]]:
415        return [rep for rep in self.getreports(names) if rep.failed]
def getfailedcollections(self) -> Sequence[CollectReport]:
417    def getfailedcollections(self) -> Sequence[CollectReport]:
418        return self.getfailures("pytest_collectreport")
def listoutcomes( self) -> Tuple[Sequence[TestReport], Sequence[Union[CollectReport, TestReport]], Sequence[Union[CollectReport, TestReport]]]:
420    def listoutcomes(
421        self,
422    ) -> Tuple[
423        Sequence[TestReport],
424        Sequence[Union[CollectReport, TestReport]],
425        Sequence[Union[CollectReport, TestReport]],
426    ]:
427        passed = []
428        skipped = []
429        failed = []
430        for rep in self.getreports(
431            ("pytest_collectreport", "pytest_runtest_logreport")
432        ):
433            if rep.passed:
434                if rep.when == "call":
435                    assert isinstance(rep, TestReport)
436                    passed.append(rep)
437            elif rep.skipped:
438                skipped.append(rep)
439            else:
440                assert rep.failed, f"Unexpected outcome: {rep!r}"
441                failed.append(rep)
442        return passed, skipped, failed
def countoutcomes(self) -> List[int]:
444    def countoutcomes(self) -> List[int]:
445        return [len(x) for x in self.listoutcomes()]
def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None:
447    def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None:
448        __tracebackhide__ = True
449        from _pytest.pytester_assertions import assertoutcome
450
451        outcomes = self.listoutcomes()
452        assertoutcome(
453            outcomes,
454            passed=passed,
455            skipped=skipped,
456            failed=failed,
457        )
def clear(self) -> None:
459    def clear(self) -> None:
460        self.calls[:] = []
hookspec = <pluggy._hooks.HookspecMarker object>
def importorskip( modname: str, minversion: Optional[str] = None, reason: Optional[str] = None, *, exc_type: Optional[Type[ImportError]] = None) -> Any:
197def importorskip(
198    modname: str,
199    minversion: Optional[str] = None,
200    reason: Optional[str] = None,
201    *,
202    exc_type: Optional[Type[ImportError]] = None,
203) -> Any:
204    """Import and return the requested module ``modname``, or skip the
205    current test if the module cannot be imported.
206
207    :param modname:
208        The name of the module to import.
209    :param minversion:
210        If given, the imported module's ``__version__`` attribute must be at
211        least this minimal version, otherwise the test is still skipped.
212    :param reason:
213        If given, this reason is shown as the message when the module cannot
214        be imported.
215    :param exc_type:
216        The exception that should be captured in order to skip modules.
217        Must be :py:class:`ImportError` or a subclass.
218
219        If the module can be imported but raises :class:`ImportError`, pytest will
220        issue a warning to the user, as often users expect the module not to be
221        found (which would raise :class:`ModuleNotFoundError` instead).
222
223        This warning can be suppressed by passing ``exc_type=ImportError`` explicitly.
224
225        See :ref:`import-or-skip-import-error` for details.
226
227
228    :returns:
229        The imported module. This should be assigned to its canonical name.
230
231    Example::
232
233        docutils = pytest.importorskip("docutils")
234
235    .. versionadded:: 8.2
236
237        The ``exc_type`` parameter.
238    """
239    import warnings
240
241    __tracebackhide__ = True
242    compile(modname, "", "eval")  # to catch syntaxerrors
243
244    # Until pytest 9.1, we will warn the user if we catch ImportError (instead of ModuleNotFoundError),
245    # as this might be hiding an installation/environment problem, which is not usually what is intended
246    # when using importorskip() (#11523).
247    # In 9.1, to keep the function signature compatible, we just change the code below to:
248    # 1. Use `exc_type = ModuleNotFoundError` if `exc_type` is not given.
249    # 2. Remove `warn_on_import` and the warning handling.
250    if exc_type is None:
251        exc_type = ImportError
252        warn_on_import_error = True
253    else:
254        warn_on_import_error = False
255
256    skipped: Optional[Skipped] = None
257    warning: Optional[Warning] = None
258
259    with warnings.catch_warnings():
260        # Make sure to ignore ImportWarnings that might happen because
261        # of existing directories with the same name we're trying to
262        # import but without a __init__.py file.
263        warnings.simplefilter("ignore")
264
265        try:
266            __import__(modname)
267        except exc_type as exc:
268            # Do not raise or issue warnings inside the catch_warnings() block.
269            if reason is None:
270                reason = f"could not import {modname!r}: {exc}"
271            skipped = Skipped(reason, allow_module_level=True)
272
273            if warn_on_import_error and not isinstance(exc, ModuleNotFoundError):
274                lines = [
275                    "",
276                    f"Module '{modname}' was found, but when imported by pytest it raised:",
277                    f"    {exc!r}",
278                    "In pytest 9.1 this warning will become an error by default.",
279                    "You can fix the underlying problem, or alternatively overwrite this behavior and silence this "
280                    "warning by passing exc_type=ImportError explicitly.",
281                    "See https://docs.pytest.org/en/stable/deprecations.html#pytest-importorskip-default-behavior-regarding-importerror",
282                ]
283                warning = PytestDeprecationWarning("\n".join(lines))
284
285    if warning:
286        warnings.warn(warning, stacklevel=2)
287    if skipped:
288        raise skipped
289
290    mod = sys.modules[modname]
291    if minversion is None:
292        return mod
293    verattr = getattr(mod, "__version__", None)
294    if minversion is not None:
295        # Imported lazily to improve start-up time.
296        from packaging.version import Version
297
298        if verattr is None or Version(verattr) < Version(minversion):
299            raise Skipped(
300                f"module {modname!r} has __version__ {verattr!r}, required is: {minversion!r}",
301                allow_module_level=True,
302            )
303    return mod

Import and return the requested module modname, or skip the current test if the module cannot be imported.

Parameters
  • modname: The name of the module to import.
  • minversion: If given, the imported module's __version__ attribute must be at least this minimal version, otherwise the test is still skipped.
  • reason: If given, this reason is shown as the message when the module cannot be imported.
  • exc_type: The exception that should be captured in order to skip modules. Must be ImportError or a subclass.

    If the module can be imported but raises ImportError, pytest will issue a warning to the user, as often users expect the module not to be found (which would raise ModuleNotFoundError instead).

    This warning can be suppressed by passing exc_type=ImportError explicitly.

    See :ref:import-or-skip-import-error for details.

:returns: The imported module. This should be assigned to its canonical name.

Example::

docutils = pytest.importorskip("docutils")

New in version 8.2: The exc_type parameter.

class Item(_pytest.nodes.Node, abc.ABC):
655class Item(Node, abc.ABC):
656    """Base class of all test invocation items.
657
658    Note that for a single function there might be multiple test invocation items.
659    """
660
661    nextitem = None
662
663    def __init__(
664        self,
665        name,
666        parent=None,
667        config: Optional[Config] = None,
668        session: Optional["Session"] = None,
669        nodeid: Optional[str] = None,
670        **kw,
671    ) -> None:
672        # The first two arguments are intentionally passed positionally,
673        # to keep plugins who define a node type which inherits from
674        # (pytest.Item, pytest.File) working (see issue #8435).
675        # They can be made kwargs when the deprecation above is done.
676        super().__init__(
677            name,
678            parent,
679            config=config,
680            session=session,
681            nodeid=nodeid,
682            **kw,
683        )
684        self._report_sections: List[Tuple[str, str, str]] = []
685
686        #: A list of tuples (name, value) that holds user defined properties
687        #: for this test.
688        self.user_properties: List[Tuple[str, object]] = []
689
690        self._check_item_and_collector_diamond_inheritance()
691
692    def _check_item_and_collector_diamond_inheritance(self) -> None:
693        """
694        Check if the current type inherits from both File and Collector
695        at the same time, emitting a warning accordingly (#8447).
696        """
697        cls = type(self)
698
699        # We inject an attribute in the type to avoid issuing this warning
700        # for the same class more than once, which is not helpful.
701        # It is a hack, but was deemed acceptable in order to avoid
702        # flooding the user in the common case.
703        attr_name = "_pytest_diamond_inheritance_warning_shown"
704        if getattr(cls, attr_name, False):
705            return
706        setattr(cls, attr_name, True)
707
708        problems = ", ".join(
709            base.__name__ for base in cls.__bases__ if issubclass(base, Collector)
710        )
711        if problems:
712            warnings.warn(
713                f"{cls.__name__} is an Item subclass and should not be a collector, "
714                f"however its bases {problems} are collectors.\n"
715                "Please split the Collectors and the Item into separate node types.\n"
716                "Pytest Doc example: https://docs.pytest.org/en/latest/example/nonpython.html\n"
717                "example pull request on a plugin: https://github.com/asmeurer/pytest-flakes/pull/40/",
718                PytestWarning,
719            )
720
721    @abc.abstractmethod
722    def runtest(self) -> None:
723        """Run the test case for this item.
724
725        Must be implemented by subclasses.
726
727        .. seealso:: :ref:`non-python tests`
728        """
729        raise NotImplementedError("runtest must be implemented by Item subclass")
730
731    def add_report_section(self, when: str, key: str, content: str) -> None:
732        """Add a new report section, similar to what's done internally to add
733        stdout and stderr captured output::
734
735            item.add_report_section("call", "stdout", "report section contents")
736
737        :param str when:
738            One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``.
739        :param str key:
740            Name of the section, can be customized at will. Pytest uses ``"stdout"`` and
741            ``"stderr"`` internally.
742        :param str content:
743            The full contents as a string.
744        """
745        if content:
746            self._report_sections.append((when, key, content))
747
748    def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
749        """Get location information for this item for test reports.
750
751        Returns a tuple with three elements:
752
753        - The path of the test (default ``self.path``)
754        - The 0-based line number of the test (default ``None``)
755        - A name of the test to be shown (default ``""``)
756
757        .. seealso:: :ref:`non-python tests`
758        """
759        return self.path, None, ""
760
761    @cached_property
762    def location(self) -> Tuple[str, Optional[int], str]:
763        """
764        Returns a tuple of ``(relfspath, lineno, testname)`` for this item
765        where ``relfspath`` is file path relative to ``config.rootpath``
766        and lineno is a 0-based line number.
767        """
768        location = self.reportinfo()
769        path = absolutepath(location[0])
770        relfspath = self.session._node_location_to_relpath(path)
771        assert type(location[2]) is str
772        return (relfspath, location[1], location[2])

Base class of all test invocation items.

Note that for a single function there might be multiple test invocation items.

nextitem = None
user_properties: List[Tuple[str, object]]
@abc.abstractmethod
def runtest(self) -> None:
721    @abc.abstractmethod
722    def runtest(self) -> None:
723        """Run the test case for this item.
724
725        Must be implemented by subclasses.
726
727        .. seealso:: :ref:`non-python tests`
728        """
729        raise NotImplementedError("runtest must be implemented by Item subclass")

Run the test case for this item.

Must be implemented by subclasses.

seealso :ref:non-python tests.

def add_report_section(self, when: str, key: str, content: str) -> None:
731    def add_report_section(self, when: str, key: str, content: str) -> None:
732        """Add a new report section, similar to what's done internally to add
733        stdout and stderr captured output::
734
735            item.add_report_section("call", "stdout", "report section contents")
736
737        :param str when:
738            One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``.
739        :param str key:
740            Name of the section, can be customized at will. Pytest uses ``"stdout"`` and
741            ``"stderr"`` internally.
742        :param str content:
743            The full contents as a string.
744        """
745        if content:
746            self._report_sections.append((when, key, content))

Add a new report section, similar to what's done internally to add stdout and stderr captured output::

item.add_report_section("call", "stdout", "report section contents")
Parameters
  • str when: One of the possible capture states, "setup", "call", "teardown".
  • str key: Name of the section, can be customized at will. Pytest uses "stdout" and "stderr" internally.
  • str content: The full contents as a string.
def reportinfo(self) -> Tuple[Union[os.PathLike[str], str], Optional[int], str]:
748    def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
749        """Get location information for this item for test reports.
750
751        Returns a tuple with three elements:
752
753        - The path of the test (default ``self.path``)
754        - The 0-based line number of the test (default ``None``)
755        - A name of the test to be shown (default ``""``)
756
757        .. seealso:: :ref:`non-python tests`
758        """
759        return self.path, None, ""

Get location information for this item for test reports.

Returns a tuple with three elements:

  • The path of the test (default self.path)
  • The 0-based line number of the test (default None)
  • A name of the test to be shown (default "")

seealso :ref:non-python tests.

location: Tuple[str, Optional[int], str]
761    @cached_property
762    def location(self) -> Tuple[str, Optional[int], str]:
763        """
764        Returns a tuple of ``(relfspath, lineno, testname)`` for this item
765        where ``relfspath`` is file path relative to ``config.rootpath``
766        and lineno is a 0-based line number.
767        """
768        location = self.reportinfo()
769        path = absolutepath(location[0])
770        relfspath = self.session._node_location_to_relpath(path)
771        assert type(location[2]) is str
772        return (relfspath, location[1], location[2])

Returns a tuple of (relfspath, lineno, testname) for this item where relfspath is file path relative to config.rootpath and lineno is a 0-based line number.

Inherited Members
_pytest.nodes.Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
from_parent
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
repr_failure
config
session
class LineMatcher:
1547class LineMatcher:
1548    """Flexible matching of text.
1549
1550    This is a convenience class to test large texts like the output of
1551    commands.
1552
1553    The constructor takes a list of lines without their trailing newlines, i.e.
1554    ``text.splitlines()``.
1555    """
1556
1557    def __init__(self, lines: List[str]) -> None:
1558        self.lines = lines
1559        self._log_output: List[str] = []
1560
1561    def __str__(self) -> str:
1562        """Return the entire original text.
1563
1564        .. versionadded:: 6.2
1565            You can use :meth:`str` in older versions.
1566        """
1567        return "\n".join(self.lines)
1568
1569    def _getlines(self, lines2: Union[str, Sequence[str], Source]) -> Sequence[str]:
1570        if isinstance(lines2, str):
1571            lines2 = Source(lines2)
1572        if isinstance(lines2, Source):
1573            lines2 = lines2.strip().lines
1574        return lines2
1575
1576    def fnmatch_lines_random(self, lines2: Sequence[str]) -> None:
1577        """Check lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`)."""
1578        __tracebackhide__ = True
1579        self._match_lines_random(lines2, fnmatch)
1580
1581    def re_match_lines_random(self, lines2: Sequence[str]) -> None:
1582        """Check lines exist in the output in any order (using :func:`python:re.match`)."""
1583        __tracebackhide__ = True
1584        self._match_lines_random(lines2, lambda name, pat: bool(re.match(pat, name)))
1585
1586    def _match_lines_random(
1587        self, lines2: Sequence[str], match_func: Callable[[str, str], bool]
1588    ) -> None:
1589        __tracebackhide__ = True
1590        lines2 = self._getlines(lines2)
1591        for line in lines2:
1592            for x in self.lines:
1593                if line == x or match_func(x, line):
1594                    self._log("matched: ", repr(line))
1595                    break
1596            else:
1597                msg = "line %r not found in output" % line
1598                self._log(msg)
1599                self._fail(msg)
1600
1601    def get_lines_after(self, fnline: str) -> Sequence[str]:
1602        """Return all lines following the given line in the text.
1603
1604        The given line can contain glob wildcards.
1605        """
1606        for i, line in enumerate(self.lines):
1607            if fnline == line or fnmatch(line, fnline):
1608                return self.lines[i + 1 :]
1609        raise ValueError("line %r not found in output" % fnline)
1610
1611    def _log(self, *args) -> None:
1612        self._log_output.append(" ".join(str(x) for x in args))
1613
1614    @property
1615    def _log_text(self) -> str:
1616        return "\n".join(self._log_output)
1617
1618    def fnmatch_lines(
1619        self, lines2: Sequence[str], *, consecutive: bool = False
1620    ) -> None:
1621        """Check lines exist in the output (using :func:`python:fnmatch.fnmatch`).
1622
1623        The argument is a list of lines which have to match and can use glob
1624        wildcards.  If they do not match a pytest.fail() is called.  The
1625        matches and non-matches are also shown as part of the error message.
1626
1627        :param lines2: String patterns to match.
1628        :param consecutive: Match lines consecutively?
1629        """
1630        __tracebackhide__ = True
1631        self._match_lines(lines2, fnmatch, "fnmatch", consecutive=consecutive)
1632
1633    def re_match_lines(
1634        self, lines2: Sequence[str], *, consecutive: bool = False
1635    ) -> None:
1636        """Check lines exist in the output (using :func:`python:re.match`).
1637
1638        The argument is a list of lines which have to match using ``re.match``.
1639        If they do not match a pytest.fail() is called.
1640
1641        The matches and non-matches are also shown as part of the error message.
1642
1643        :param lines2: string patterns to match.
1644        :param consecutive: match lines consecutively?
1645        """
1646        __tracebackhide__ = True
1647        self._match_lines(
1648            lines2,
1649            lambda name, pat: bool(re.match(pat, name)),
1650            "re.match",
1651            consecutive=consecutive,
1652        )
1653
1654    def _match_lines(
1655        self,
1656        lines2: Sequence[str],
1657        match_func: Callable[[str, str], bool],
1658        match_nickname: str,
1659        *,
1660        consecutive: bool = False,
1661    ) -> None:
1662        """Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``.
1663
1664        :param Sequence[str] lines2:
1665            List of string patterns to match. The actual format depends on
1666            ``match_func``.
1667        :param match_func:
1668            A callable ``match_func(line, pattern)`` where line is the
1669            captured line from stdout/stderr and pattern is the matching
1670            pattern.
1671        :param str match_nickname:
1672            The nickname for the match function that will be logged to stdout
1673            when a match occurs.
1674        :param consecutive:
1675            Match lines consecutively?
1676        """
1677        if not isinstance(lines2, collections.abc.Sequence):
1678            raise TypeError(f"invalid type for lines2: {type(lines2).__name__}")
1679        lines2 = self._getlines(lines2)
1680        lines1 = self.lines[:]
1681        extralines = []
1682        __tracebackhide__ = True
1683        wnick = len(match_nickname) + 1
1684        started = False
1685        for line in lines2:
1686            nomatchprinted = False
1687            while lines1:
1688                nextline = lines1.pop(0)
1689                if line == nextline:
1690                    self._log("exact match:", repr(line))
1691                    started = True
1692                    break
1693                elif match_func(nextline, line):
1694                    self._log("%s:" % match_nickname, repr(line))
1695                    self._log(
1696                        "{:>{width}}".format("with:", width=wnick), repr(nextline)
1697                    )
1698                    started = True
1699                    break
1700                else:
1701                    if consecutive and started:
1702                        msg = f"no consecutive match: {line!r}"
1703                        self._log(msg)
1704                        self._log(
1705                            "{:>{width}}".format("with:", width=wnick), repr(nextline)
1706                        )
1707                        self._fail(msg)
1708                    if not nomatchprinted:
1709                        self._log(
1710                            "{:>{width}}".format("nomatch:", width=wnick), repr(line)
1711                        )
1712                        nomatchprinted = True
1713                    self._log("{:>{width}}".format("and:", width=wnick), repr(nextline))
1714                extralines.append(nextline)
1715            else:
1716                msg = f"remains unmatched: {line!r}"
1717                self._log(msg)
1718                self._fail(msg)
1719        self._log_output = []
1720
1721    def no_fnmatch_line(self, pat: str) -> None:
1722        """Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``.
1723
1724        :param str pat: The pattern to match lines.
1725        """
1726        __tracebackhide__ = True
1727        self._no_match_line(pat, fnmatch, "fnmatch")
1728
1729    def no_re_match_line(self, pat: str) -> None:
1730        """Ensure captured lines do not match the given pattern, using ``re.match``.
1731
1732        :param str pat: The regular expression to match lines.
1733        """
1734        __tracebackhide__ = True
1735        self._no_match_line(
1736            pat, lambda name, pat: bool(re.match(pat, name)), "re.match"
1737        )
1738
1739    def _no_match_line(
1740        self, pat: str, match_func: Callable[[str, str], bool], match_nickname: str
1741    ) -> None:
1742        """Ensure captured lines does not have a the given pattern, using ``fnmatch.fnmatch``.
1743
1744        :param str pat: The pattern to match lines.
1745        """
1746        __tracebackhide__ = True
1747        nomatch_printed = False
1748        wnick = len(match_nickname) + 1
1749        for line in self.lines:
1750            if match_func(line, pat):
1751                msg = f"{match_nickname}: {pat!r}"
1752                self._log(msg)
1753                self._log("{:>{width}}".format("with:", width=wnick), repr(line))
1754                self._fail(msg)
1755            else:
1756                if not nomatch_printed:
1757                    self._log("{:>{width}}".format("nomatch:", width=wnick), repr(pat))
1758                    nomatch_printed = True
1759                self._log("{:>{width}}".format("and:", width=wnick), repr(line))
1760        self._log_output = []
1761
1762    def _fail(self, msg: str) -> None:
1763        __tracebackhide__ = True
1764        log_text = self._log_text
1765        self._log_output = []
1766        fail(log_text)
1767
1768    def str(self) -> str:
1769        """Return the entire original text."""
1770        return str(self)

Flexible matching of text.

This is a convenience class to test large texts like the output of commands.

The constructor takes a list of lines without their trailing newlines, i.e. text.splitlines().

LineMatcher(lines: List[str])
1557    def __init__(self, lines: List[str]) -> None:
1558        self.lines = lines
1559        self._log_output: List[str] = []
lines
def fnmatch_lines_random(self, lines2: Sequence[str]) -> None:
1576    def fnmatch_lines_random(self, lines2: Sequence[str]) -> None:
1577        """Check lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`)."""
1578        __tracebackhide__ = True
1579        self._match_lines_random(lines2, fnmatch)

Check lines exist in the output in any order (using python:fnmatch.fnmatch()).

def re_match_lines_random(self, lines2: Sequence[str]) -> None:
1581    def re_match_lines_random(self, lines2: Sequence[str]) -> None:
1582        """Check lines exist in the output in any order (using :func:`python:re.match`)."""
1583        __tracebackhide__ = True
1584        self._match_lines_random(lines2, lambda name, pat: bool(re.match(pat, name)))

Check lines exist in the output in any order (using python:re.match()).

def get_lines_after(self, fnline: str) -> Sequence[str]:
1601    def get_lines_after(self, fnline: str) -> Sequence[str]:
1602        """Return all lines following the given line in the text.
1603
1604        The given line can contain glob wildcards.
1605        """
1606        for i, line in enumerate(self.lines):
1607            if fnline == line or fnmatch(line, fnline):
1608                return self.lines[i + 1 :]
1609        raise ValueError("line %r not found in output" % fnline)

Return all lines following the given line in the text.

The given line can contain glob wildcards.

def fnmatch_lines(self, lines2: Sequence[str], *, consecutive: bool = False) -> None:
1618    def fnmatch_lines(
1619        self, lines2: Sequence[str], *, consecutive: bool = False
1620    ) -> None:
1621        """Check lines exist in the output (using :func:`python:fnmatch.fnmatch`).
1622
1623        The argument is a list of lines which have to match and can use glob
1624        wildcards.  If they do not match a pytest.fail() is called.  The
1625        matches and non-matches are also shown as part of the error message.
1626
1627        :param lines2: String patterns to match.
1628        :param consecutive: Match lines consecutively?
1629        """
1630        __tracebackhide__ = True
1631        self._match_lines(lines2, fnmatch, "fnmatch", consecutive=consecutive)

Check lines exist in the output (using python:fnmatch.fnmatch()).

The argument is a list of lines which have to match and can use glob wildcards. If they do not match a pytest.fail() is called. The matches and non-matches are also shown as part of the error message.

Parameters
  • lines2: String patterns to match.
  • consecutive: Match lines consecutively?
def re_match_lines(self, lines2: Sequence[str], *, consecutive: bool = False) -> None:
1633    def re_match_lines(
1634        self, lines2: Sequence[str], *, consecutive: bool = False
1635    ) -> None:
1636        """Check lines exist in the output (using :func:`python:re.match`).
1637
1638        The argument is a list of lines which have to match using ``re.match``.
1639        If they do not match a pytest.fail() is called.
1640
1641        The matches and non-matches are also shown as part of the error message.
1642
1643        :param lines2: string patterns to match.
1644        :param consecutive: match lines consecutively?
1645        """
1646        __tracebackhide__ = True
1647        self._match_lines(
1648            lines2,
1649            lambda name, pat: bool(re.match(pat, name)),
1650            "re.match",
1651            consecutive=consecutive,
1652        )

Check lines exist in the output (using python:re.match()).

The argument is a list of lines which have to match using re.match. If they do not match a pytest.fail() is called.

The matches and non-matches are also shown as part of the error message.

Parameters
  • lines2: string patterns to match.
  • consecutive: match lines consecutively?
def no_fnmatch_line(self, pat: str) -> None:
1721    def no_fnmatch_line(self, pat: str) -> None:
1722        """Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``.
1723
1724        :param str pat: The pattern to match lines.
1725        """
1726        __tracebackhide__ = True
1727        self._no_match_line(pat, fnmatch, "fnmatch")

Ensure captured lines do not match the given pattern, using fnmatch.fnmatch.

Parameters
  • str pat: The pattern to match lines.
def no_re_match_line(self, pat: str) -> None:
1729    def no_re_match_line(self, pat: str) -> None:
1730        """Ensure captured lines do not match the given pattern, using ``re.match``.
1731
1732        :param str pat: The regular expression to match lines.
1733        """
1734        __tracebackhide__ = True
1735        self._no_match_line(
1736            pat, lambda name, pat: bool(re.match(pat, name)), "re.match"
1737        )

Ensure captured lines do not match the given pattern, using re.match.

Parameters
  • str pat: The regular expression to match lines.
def str(self) -> str:
1768    def str(self) -> str:
1769        """Return the entire original text."""
1770        return str(self)

Return the entire original text.

@final
class LogCaptureFixture:
408@final
409class LogCaptureFixture:
410    """Provides access and control of log capturing."""
411
412    def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None:
413        check_ispytest(_ispytest)
414        self._item = item
415        self._initial_handler_level: Optional[int] = None
416        # Dict of log name -> log level.
417        self._initial_logger_levels: Dict[Optional[str], int] = {}
418        self._initial_disabled_logging_level: Optional[int] = None
419
420    def _finalize(self) -> None:
421        """Finalize the fixture.
422
423        This restores the log levels and the disabled logging levels changed by :meth:`set_level`.
424        """
425        # Restore log levels.
426        if self._initial_handler_level is not None:
427            self.handler.setLevel(self._initial_handler_level)
428        for logger_name, level in self._initial_logger_levels.items():
429            logger = logging.getLogger(logger_name)
430            logger.setLevel(level)
431        # Disable logging at the original disabled logging level.
432        if self._initial_disabled_logging_level is not None:
433            logging.disable(self._initial_disabled_logging_level)
434            self._initial_disabled_logging_level = None
435
436    @property
437    def handler(self) -> LogCaptureHandler:
438        """Get the logging handler used by the fixture."""
439        return self._item.stash[caplog_handler_key]
440
441    def get_records(
442        self, when: Literal["setup", "call", "teardown"]
443    ) -> List[logging.LogRecord]:
444        """Get the logging records for one of the possible test phases.
445
446        :param when:
447            Which test phase to obtain the records from.
448            Valid values are: "setup", "call" and "teardown".
449
450        :returns: The list of captured records at the given stage.
451
452        .. versionadded:: 3.4
453        """
454        return self._item.stash[caplog_records_key].get(when, [])
455
456    @property
457    def text(self) -> str:
458        """The formatted log text."""
459        return _remove_ansi_escape_sequences(self.handler.stream.getvalue())
460
461    @property
462    def records(self) -> List[logging.LogRecord]:
463        """The list of log records."""
464        return self.handler.records
465
466    @property
467    def record_tuples(self) -> List[Tuple[str, int, str]]:
468        """A list of a stripped down version of log records intended
469        for use in assertion comparison.
470
471        The format of the tuple is:
472
473            (logger_name, log_level, message)
474        """
475        return [(r.name, r.levelno, r.getMessage()) for r in self.records]
476
477    @property
478    def messages(self) -> List[str]:
479        """A list of format-interpolated log messages.
480
481        Unlike 'records', which contains the format string and parameters for
482        interpolation, log messages in this list are all interpolated.
483
484        Unlike 'text', which contains the output from the handler, log
485        messages in this list are unadorned with levels, timestamps, etc,
486        making exact comparisons more reliable.
487
488        Note that traceback or stack info (from :func:`logging.exception` or
489        the `exc_info` or `stack_info` arguments to the logging functions) is
490        not included, as this is added by the formatter in the handler.
491
492        .. versionadded:: 3.7
493        """
494        return [r.getMessage() for r in self.records]
495
496    def clear(self) -> None:
497        """Reset the list of log records and the captured log text."""
498        self.handler.clear()
499
500    def _force_enable_logging(
501        self, level: Union[int, str], logger_obj: logging.Logger
502    ) -> int:
503        """Enable the desired logging level if the global level was disabled via ``logging.disabled``.
504
505        Only enables logging levels greater than or equal to the requested ``level``.
506
507        Does nothing if the desired ``level`` wasn't disabled.
508
509        :param level:
510            The logger level caplog should capture.
511            All logging is enabled if a non-standard logging level string is supplied.
512            Valid level strings are in :data:`logging._nameToLevel`.
513        :param logger_obj: The logger object to check.
514
515        :return: The original disabled logging level.
516        """
517        original_disable_level: int = logger_obj.manager.disable
518
519        if isinstance(level, str):
520            # Try to translate the level string to an int for `logging.disable()`
521            level = logging.getLevelName(level)
522
523        if not isinstance(level, int):
524            # The level provided was not valid, so just un-disable all logging.
525            logging.disable(logging.NOTSET)
526        elif not logger_obj.isEnabledFor(level):
527            # Each level is `10` away from other levels.
528            # https://docs.python.org/3/library/logging.html#logging-levels
529            disable_level = max(level - 10, logging.NOTSET)
530            logging.disable(disable_level)
531
532        return original_disable_level
533
534    def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None:
535        """Set the threshold level of a logger for the duration of a test.
536
537        Logging messages which are less severe than this level will not be captured.
538
539        .. versionchanged:: 3.4
540            The levels of the loggers changed by this function will be
541            restored to their initial values at the end of the test.
542
543        Will enable the requested logging level if it was disabled via :func:`logging.disable`.
544
545        :param level: The level.
546        :param logger: The logger to update. If not given, the root logger.
547        """
548        logger_obj = logging.getLogger(logger)
549        # Save the original log-level to restore it during teardown.
550        self._initial_logger_levels.setdefault(logger, logger_obj.level)
551        logger_obj.setLevel(level)
552        if self._initial_handler_level is None:
553            self._initial_handler_level = self.handler.level
554        self.handler.setLevel(level)
555        initial_disabled_logging_level = self._force_enable_logging(level, logger_obj)
556        if self._initial_disabled_logging_level is None:
557            self._initial_disabled_logging_level = initial_disabled_logging_level
558
559    @contextmanager
560    def at_level(
561        self, level: Union[int, str], logger: Optional[str] = None
562    ) -> Generator[None, None, None]:
563        """Context manager that sets the level for capturing of logs. After
564        the end of the 'with' statement the level is restored to its original
565        value.
566
567        Will enable the requested logging level if it was disabled via :func:`logging.disable`.
568
569        :param level: The level.
570        :param logger: The logger to update. If not given, the root logger.
571        """
572        logger_obj = logging.getLogger(logger)
573        orig_level = logger_obj.level
574        logger_obj.setLevel(level)
575        handler_orig_level = self.handler.level
576        self.handler.setLevel(level)
577        original_disable_level = self._force_enable_logging(level, logger_obj)
578        try:
579            yield
580        finally:
581            logger_obj.setLevel(orig_level)
582            self.handler.setLevel(handler_orig_level)
583            logging.disable(original_disable_level)
584
585    @contextmanager
586    def filtering(self, filter_: logging.Filter) -> Generator[None, None, None]:
587        """Context manager that temporarily adds the given filter to the caplog's
588        :meth:`handler` for the 'with' statement block, and removes that filter at the
589        end of the block.
590
591        :param filter_: A custom :class:`logging.Filter` object.
592
593        .. versionadded:: 7.5
594        """
595        self.handler.addFilter(filter_)
596        try:
597            yield
598        finally:
599            self.handler.removeFilter(filter_)

Provides access and control of log capturing.

LogCaptureFixture(item: _pytest.nodes.Node, *, _ispytest: bool = False)
412    def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None:
413        check_ispytest(_ispytest)
414        self._item = item
415        self._initial_handler_level: Optional[int] = None
416        # Dict of log name -> log level.
417        self._initial_logger_levels: Dict[Optional[str], int] = {}
418        self._initial_disabled_logging_level: Optional[int] = None
handler: _pytest.logging.LogCaptureHandler
436    @property
437    def handler(self) -> LogCaptureHandler:
438        """Get the logging handler used by the fixture."""
439        return self._item.stash[caplog_handler_key]

Get the logging handler used by the fixture.

def get_records( self, when: Literal['setup', 'call', 'teardown']) -> List[logging.LogRecord]:
441    def get_records(
442        self, when: Literal["setup", "call", "teardown"]
443    ) -> List[logging.LogRecord]:
444        """Get the logging records for one of the possible test phases.
445
446        :param when:
447            Which test phase to obtain the records from.
448            Valid values are: "setup", "call" and "teardown".
449
450        :returns: The list of captured records at the given stage.
451
452        .. versionadded:: 3.4
453        """
454        return self._item.stash[caplog_records_key].get(when, [])

Get the logging records for one of the possible test phases.

Parameters
  • when: Which test phase to obtain the records from. Valid values are: "setup", "call" and "teardown".

:returns: The list of captured records at the given stage.

New in version 3.4.

text: str
456    @property
457    def text(self) -> str:
458        """The formatted log text."""
459        return _remove_ansi_escape_sequences(self.handler.stream.getvalue())

The formatted log text.

records: List[logging.LogRecord]
461    @property
462    def records(self) -> List[logging.LogRecord]:
463        """The list of log records."""
464        return self.handler.records

The list of log records.

record_tuples: List[Tuple[str, int, str]]
466    @property
467    def record_tuples(self) -> List[Tuple[str, int, str]]:
468        """A list of a stripped down version of log records intended
469        for use in assertion comparison.
470
471        The format of the tuple is:
472
473            (logger_name, log_level, message)
474        """
475        return [(r.name, r.levelno, r.getMessage()) for r in self.records]

A list of a stripped down version of log records intended for use in assertion comparison.

The format of the tuple is:

(logger_name, log_level, message)

messages: List[str]
477    @property
478    def messages(self) -> List[str]:
479        """A list of format-interpolated log messages.
480
481        Unlike 'records', which contains the format string and parameters for
482        interpolation, log messages in this list are all interpolated.
483
484        Unlike 'text', which contains the output from the handler, log
485        messages in this list are unadorned with levels, timestamps, etc,
486        making exact comparisons more reliable.
487
488        Note that traceback or stack info (from :func:`logging.exception` or
489        the `exc_info` or `stack_info` arguments to the logging functions) is
490        not included, as this is added by the formatter in the handler.
491
492        .. versionadded:: 3.7
493        """
494        return [r.getMessage() for r in self.records]

A list of format-interpolated log messages.

Unlike 'records', which contains the format string and parameters for interpolation, log messages in this list are all interpolated.

Unlike 'text', which contains the output from the handler, log messages in this list are unadorned with levels, timestamps, etc, making exact comparisons more reliable.

Note that traceback or stack info (from logging.exception() or the exc_info or stack_info arguments to the logging functions) is not included, as this is added by the formatter in the handler.

New in version 3.7.

def clear(self) -> None:
496    def clear(self) -> None:
497        """Reset the list of log records and the captured log text."""
498        self.handler.clear()

Reset the list of log records and the captured log text.

def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None:
534    def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None:
535        """Set the threshold level of a logger for the duration of a test.
536
537        Logging messages which are less severe than this level will not be captured.
538
539        .. versionchanged:: 3.4
540            The levels of the loggers changed by this function will be
541            restored to their initial values at the end of the test.
542
543        Will enable the requested logging level if it was disabled via :func:`logging.disable`.
544
545        :param level: The level.
546        :param logger: The logger to update. If not given, the root logger.
547        """
548        logger_obj = logging.getLogger(logger)
549        # Save the original log-level to restore it during teardown.
550        self._initial_logger_levels.setdefault(logger, logger_obj.level)
551        logger_obj.setLevel(level)
552        if self._initial_handler_level is None:
553            self._initial_handler_level = self.handler.level
554        self.handler.setLevel(level)
555        initial_disabled_logging_level = self._force_enable_logging(level, logger_obj)
556        if self._initial_disabled_logging_level is None:
557            self._initial_disabled_logging_level = initial_disabled_logging_level

Set the threshold level of a logger for the duration of a test.

Logging messages which are less severe than this level will not be captured.

Changed in version 3.4: The levels of the loggers changed by this function will be restored to their initial values at the end of the test.

Will enable the requested logging level if it was disabled via logging.disable().

Parameters
  • level: The level.
  • logger: The logger to update. If not given, the root logger.
@contextmanager
def at_level( self, level: Union[int, str], logger: Optional[str] = None) -> Generator[NoneType, NoneType, NoneType]:
559    @contextmanager
560    def at_level(
561        self, level: Union[int, str], logger: Optional[str] = None
562    ) -> Generator[None, None, None]:
563        """Context manager that sets the level for capturing of logs. After
564        the end of the 'with' statement the level is restored to its original
565        value.
566
567        Will enable the requested logging level if it was disabled via :func:`logging.disable`.
568
569        :param level: The level.
570        :param logger: The logger to update. If not given, the root logger.
571        """
572        logger_obj = logging.getLogger(logger)
573        orig_level = logger_obj.level
574        logger_obj.setLevel(level)
575        handler_orig_level = self.handler.level
576        self.handler.setLevel(level)
577        original_disable_level = self._force_enable_logging(level, logger_obj)
578        try:
579            yield
580        finally:
581            logger_obj.setLevel(orig_level)
582            self.handler.setLevel(handler_orig_level)
583            logging.disable(original_disable_level)

Context manager that sets the level for capturing of logs. After the end of the 'with' statement the level is restored to its original value.

Will enable the requested logging level if it was disabled via logging.disable().

Parameters
  • level: The level.
  • logger: The logger to update. If not given, the root logger.
@contextmanager
def filtering(self, filter_: logging.Filter) -> Generator[NoneType, NoneType, NoneType]:
585    @contextmanager
586    def filtering(self, filter_: logging.Filter) -> Generator[None, None, None]:
587        """Context manager that temporarily adds the given filter to the caplog's
588        :meth:`handler` for the 'with' statement block, and removes that filter at the
589        end of the block.
590
591        :param filter_: A custom :class:`logging.Filter` object.
592
593        .. versionadded:: 7.5
594        """
595        self.handler.addFilter(filter_)
596        try:
597            yield
598        finally:
599            self.handler.removeFilter(filter_)

Context manager that temporarily adds the given filter to the caplog's handler() for the 'with' statement block, and removes that filter at the end of the block.

Parameters
  • filter_: A custom logging.Filter object.

New in version 7.5.

def main( args: Union[List[str], os.PathLike[str], NoneType] = None, plugins: Optional[Sequence[Union[str, object]]] = None) -> Union[int, ExitCode]:
143def main(
144    args: Optional[Union[List[str], "os.PathLike[str]"]] = None,
145    plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
146) -> Union[int, ExitCode]:
147    """Perform an in-process test run.
148
149    :param args:
150        List of command line arguments. If `None` or not given, defaults to reading
151        arguments directly from the process command line (:data:`sys.argv`).
152    :param plugins: List of plugin objects to be auto-registered during initialization.
153
154    :returns: An exit code.
155    """
156    old_pytest_version = os.environ.get("PYTEST_VERSION")
157    try:
158        os.environ["PYTEST_VERSION"] = __version__
159        try:
160            config = _prepareconfig(args, plugins)
161        except ConftestImportFailure as e:
162            exc_info = ExceptionInfo.from_exception(e.cause)
163            tw = TerminalWriter(sys.stderr)
164            tw.line(f"ImportError while loading conftest '{e.path}'.", red=True)
165            exc_info.traceback = exc_info.traceback.filter(
166                filter_traceback_for_conftest_import_failure
167            )
168            exc_repr = (
169                exc_info.getrepr(style="short", chain=False)
170                if exc_info.traceback
171                else exc_info.exconly()
172            )
173            formatted_tb = str(exc_repr)
174            for line in formatted_tb.splitlines():
175                tw.line(line.rstrip(), red=True)
176            return ExitCode.USAGE_ERROR
177        else:
178            try:
179                ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
180                    config=config
181                )
182                try:
183                    return ExitCode(ret)
184                except ValueError:
185                    return ret
186            finally:
187                config._ensure_unconfigure()
188    except UsageError as e:
189        tw = TerminalWriter(sys.stderr)
190        for msg in e.args:
191            tw.line(f"ERROR: {msg}\n", red=True)
192        return ExitCode.USAGE_ERROR
193    finally:
194        if old_pytest_version is None:
195            os.environ.pop("PYTEST_VERSION", None)
196        else:
197            os.environ["PYTEST_VERSION"] = old_pytest_version

Perform an in-process test run.

Parameters
  • args: List of command line arguments. If None or not given, defaults to reading arguments directly from the process command line (sys.argv).
  • plugins: List of plugin objects to be auto-registered during initialization.

:returns: An exit code.

mark = <MarkGenerator object>
@final
@dataclasses.dataclass(frozen=True)
class Mark:
195@final
196@dataclasses.dataclass(frozen=True)
197class Mark:
198    """A pytest mark."""
199
200    #: Name of the mark.
201    name: str
202    #: Positional arguments of the mark decorator.
203    args: Tuple[Any, ...]
204    #: Keyword arguments of the mark decorator.
205    kwargs: Mapping[str, Any]
206
207    #: Source Mark for ids with parametrize Marks.
208    _param_ids_from: Optional["Mark"] = dataclasses.field(default=None, repr=False)
209    #: Resolved/generated ids with parametrize Marks.
210    _param_ids_generated: Optional[Sequence[str]] = dataclasses.field(
211        default=None, repr=False
212    )
213
214    def __init__(
215        self,
216        name: str,
217        args: Tuple[Any, ...],
218        kwargs: Mapping[str, Any],
219        param_ids_from: Optional["Mark"] = None,
220        param_ids_generated: Optional[Sequence[str]] = None,
221        *,
222        _ispytest: bool = False,
223    ) -> None:
224        """:meta private:"""
225        check_ispytest(_ispytest)
226        # Weirdness to bypass frozen=True.
227        object.__setattr__(self, "name", name)
228        object.__setattr__(self, "args", args)
229        object.__setattr__(self, "kwargs", kwargs)
230        object.__setattr__(self, "_param_ids_from", param_ids_from)
231        object.__setattr__(self, "_param_ids_generated", param_ids_generated)
232
233    def _has_param_ids(self) -> bool:
234        return "ids" in self.kwargs or len(self.args) >= 4
235
236    def combined_with(self, other: "Mark") -> "Mark":
237        """Return a new Mark which is a combination of this
238        Mark and another Mark.
239
240        Combines by appending args and merging kwargs.
241
242        :param Mark other: The mark to combine with.
243        :rtype: Mark
244        """
245        assert self.name == other.name
246
247        # Remember source of ids with parametrize Marks.
248        param_ids_from: Optional[Mark] = None
249        if self.name == "parametrize":
250            if other._has_param_ids():
251                param_ids_from = other
252            elif self._has_param_ids():
253                param_ids_from = self
254
255        return Mark(
256            self.name,
257            self.args + other.args,
258            dict(self.kwargs, **other.kwargs),
259            param_ids_from=param_ids_from,
260            _ispytest=True,
261        )

A pytest mark.

Mark( name: str, args: Tuple[Any, ...], kwargs: Mapping[str, Any], param_ids_from: Optional[Mark] = None, param_ids_generated: Optional[Sequence[str]] = None, *, _ispytest: bool = False)
214    def __init__(
215        self,
216        name: str,
217        args: Tuple[Any, ...],
218        kwargs: Mapping[str, Any],
219        param_ids_from: Optional["Mark"] = None,
220        param_ids_generated: Optional[Sequence[str]] = None,
221        *,
222        _ispytest: bool = False,
223    ) -> None:
224        """:meta private:"""
225        check_ispytest(_ispytest)
226        # Weirdness to bypass frozen=True.
227        object.__setattr__(self, "name", name)
228        object.__setattr__(self, "args", args)
229        object.__setattr__(self, "kwargs", kwargs)
230        object.__setattr__(self, "_param_ids_from", param_ids_from)
231        object.__setattr__(self, "_param_ids_generated", param_ids_generated)

:meta private:

name: str
args: Tuple[Any, ...]
kwargs: Mapping[str, Any]
def combined_with( self, other: Mark) -> Mark:
236    def combined_with(self, other: "Mark") -> "Mark":
237        """Return a new Mark which is a combination of this
238        Mark and another Mark.
239
240        Combines by appending args and merging kwargs.
241
242        :param Mark other: The mark to combine with.
243        :rtype: Mark
244        """
245        assert self.name == other.name
246
247        # Remember source of ids with parametrize Marks.
248        param_ids_from: Optional[Mark] = None
249        if self.name == "parametrize":
250            if other._has_param_ids():
251                param_ids_from = other
252            elif self._has_param_ids():
253                param_ids_from = self
254
255        return Mark(
256            self.name,
257            self.args + other.args,
258            dict(self.kwargs, **other.kwargs),
259            param_ids_from=param_ids_from,
260            _ispytest=True,
261        )

Return a new Mark which is a combination of this Mark and another Mark.

Combines by appending args and merging kwargs.

Parameters
  • Mark other: The mark to combine with.
@dataclasses.dataclass
class MarkDecorator:
270@dataclasses.dataclass
271class MarkDecorator:
272    """A decorator for applying a mark on test functions and classes.
273
274    ``MarkDecorators`` are created with ``pytest.mark``::
275
276        mark1 = pytest.mark.NAME  # Simple MarkDecorator
277        mark2 = pytest.mark.NAME(name1=value)  # Parametrized MarkDecorator
278
279    and can then be applied as decorators to test functions::
280
281        @mark2
282        def test_function():
283            pass
284
285    When a ``MarkDecorator`` is called, it does the following:
286
287    1. If called with a single class as its only positional argument and no
288       additional keyword arguments, it attaches the mark to the class so it
289       gets applied automatically to all test cases found in that class.
290
291    2. If called with a single function as its only positional argument and
292       no additional keyword arguments, it attaches the mark to the function,
293       containing all the arguments already stored internally in the
294       ``MarkDecorator``.
295
296    3. When called in any other case, it returns a new ``MarkDecorator``
297       instance with the original ``MarkDecorator``'s content updated with
298       the arguments passed to this call.
299
300    Note: The rules above prevent a ``MarkDecorator`` from storing only a
301    single function or class reference as its positional argument with no
302    additional keyword or positional arguments. You can work around this by
303    using `with_args()`.
304    """
305
306    mark: Mark
307
308    def __init__(self, mark: Mark, *, _ispytest: bool = False) -> None:
309        """:meta private:"""
310        check_ispytest(_ispytest)
311        self.mark = mark
312
313    @property
314    def name(self) -> str:
315        """Alias for mark.name."""
316        return self.mark.name
317
318    @property
319    def args(self) -> Tuple[Any, ...]:
320        """Alias for mark.args."""
321        return self.mark.args
322
323    @property
324    def kwargs(self) -> Mapping[str, Any]:
325        """Alias for mark.kwargs."""
326        return self.mark.kwargs
327
328    @property
329    def markname(self) -> str:
330        """:meta private:"""
331        return self.name  # for backward-compat (2.4.1 had this attr)
332
333    def with_args(self, *args: object, **kwargs: object) -> "MarkDecorator":
334        """Return a MarkDecorator with extra arguments added.
335
336        Unlike calling the MarkDecorator, with_args() can be used even
337        if the sole argument is a callable/class.
338        """
339        mark = Mark(self.name, args, kwargs, _ispytest=True)
340        return MarkDecorator(self.mark.combined_with(mark), _ispytest=True)
341
342    # Type ignored because the overloads overlap with an incompatible
343    # return type. Not much we can do about that. Thankfully mypy picks
344    # the first match so it works out even if we break the rules.
345    @overload
346    def __call__(self, arg: Markable) -> Markable:  # type: ignore[overload-overlap]
347        pass
348
349    @overload
350    def __call__(self, *args: object, **kwargs: object) -> "MarkDecorator":
351        pass
352
353    def __call__(self, *args: object, **kwargs: object):
354        """Call the MarkDecorator."""
355        if args and not kwargs:
356            func = args[0]
357            is_class = inspect.isclass(func)
358            if len(args) == 1 and (istestfunc(func) or is_class):
359                store_mark(func, self.mark, stacklevel=3)
360                return func
361        return self.with_args(*args, **kwargs)

A decorator for applying a mark on test functions and classes.

MarkDecorators are created with pytest.mark::

mark1 = pytest.mark.NAME  # Simple MarkDecorator
mark2 = pytest.mark.NAME(name1=value)  # Parametrized MarkDecorator

and can then be applied as decorators to test functions::

@mark2
def test_function():
    pass

When a MarkDecorator is called, it does the following:

  1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches the mark to the class so it gets applied automatically to all test cases found in that class.

  2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches the mark to the function, containing all the arguments already stored internally in the MarkDecorator.

  3. When called in any other case, it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call.

Note: The rules above prevent a MarkDecorator from storing only a single function or class reference as its positional argument with no additional keyword or positional arguments. You can work around this by using with_args().

MarkDecorator(mark: Mark, *, _ispytest: bool = False)
308    def __init__(self, mark: Mark, *, _ispytest: bool = False) -> None:
309        """:meta private:"""
310        check_ispytest(_ispytest)
311        self.mark = mark

:meta private:

mark: Mark
name: str
313    @property
314    def name(self) -> str:
315        """Alias for mark.name."""
316        return self.mark.name

Alias for mark.name.

args: Tuple[Any, ...]
318    @property
319    def args(self) -> Tuple[Any, ...]:
320        """Alias for mark.args."""
321        return self.mark.args

Alias for mark.args.

kwargs: Mapping[str, Any]
323    @property
324    def kwargs(self) -> Mapping[str, Any]:
325        """Alias for mark.kwargs."""
326        return self.mark.kwargs

Alias for mark.kwargs.

markname: str
328    @property
329    def markname(self) -> str:
330        """:meta private:"""
331        return self.name  # for backward-compat (2.4.1 had this attr)

:meta private:

def with_args( self, *args: object, **kwargs: object) -> MarkDecorator:
333    def with_args(self, *args: object, **kwargs: object) -> "MarkDecorator":
334        """Return a MarkDecorator with extra arguments added.
335
336        Unlike calling the MarkDecorator, with_args() can be used even
337        if the sole argument is a callable/class.
338        """
339        mark = Mark(self.name, args, kwargs, _ispytest=True)
340        return MarkDecorator(self.mark.combined_with(mark), _ispytest=True)

Return a MarkDecorator with extra arguments added.

Unlike calling the MarkDecorator, with_args() can be used even if the sole argument is a callable/class.

@final
class MarkGenerator:
493@final
494class MarkGenerator:
495    """Factory for :class:`MarkDecorator` objects - exposed as
496    a ``pytest.mark`` singleton instance.
497
498    Example::
499
500         import pytest
501
502
503         @pytest.mark.slowtest
504         def test_function():
505             pass
506
507    applies a 'slowtest' :class:`Mark` on ``test_function``.
508    """
509
510    # See TYPE_CHECKING above.
511    if TYPE_CHECKING:
512        skip: _SkipMarkDecorator
513        skipif: _SkipifMarkDecorator
514        xfail: _XfailMarkDecorator
515        parametrize: _ParametrizeMarkDecorator
516        usefixtures: _UsefixturesMarkDecorator
517        filterwarnings: _FilterwarningsMarkDecorator
518
519    def __init__(self, *, _ispytest: bool = False) -> None:
520        check_ispytest(_ispytest)
521        self._config: Optional[Config] = None
522        self._markers: Set[str] = set()
523
524    def __getattr__(self, name: str) -> MarkDecorator:
525        """Generate a new :class:`MarkDecorator` with the given name."""
526        if name[0] == "_":
527            raise AttributeError("Marker name must NOT start with underscore")
528
529        if self._config is not None:
530            # We store a set of markers as a performance optimisation - if a mark
531            # name is in the set we definitely know it, but a mark may be known and
532            # not in the set.  We therefore start by updating the set!
533            if name not in self._markers:
534                for line in self._config.getini("markers"):
535                    # example lines: "skipif(condition): skip the given test if..."
536                    # or "hypothesis: tests which use Hypothesis", so to get the
537                    # marker name we split on both `:` and `(`.
538                    marker = line.split(":")[0].split("(")[0].strip()
539                    self._markers.add(marker)
540
541            # If the name is not in the set of known marks after updating,
542            # then it really is time to issue a warning or an error.
543            if name not in self._markers:
544                if self._config.option.strict_markers or self._config.option.strict:
545                    fail(
546                        f"{name!r} not found in `markers` configuration option",
547                        pytrace=False,
548                    )
549
550                # Raise a specific error for common misspellings of "parametrize".
551                if name in ["parameterize", "parametrise", "parameterise"]:
552                    __tracebackhide__ = True
553                    fail(f"Unknown '{name}' mark, did you mean 'parametrize'?")
554
555                warnings.warn(
556                    "Unknown pytest.mark.%s - is this a typo?  You can register "
557                    "custom marks to avoid this warning - for details, see "
558                    "https://docs.pytest.org/en/stable/how-to/mark.html" % name,
559                    PytestUnknownMarkWarning,
560                    2,
561                )
562
563        return MarkDecorator(Mark(name, (), {}, _ispytest=True), _ispytest=True)

Factory for MarkDecorator objects - exposed as a pytest.mark singleton instance.

Example::

 import pytest


 @pytest.mark.slowtest
 def test_function():
     pass

applies a 'slowtest' Mark on test_function.

MarkGenerator(*, _ispytest: bool = False)
519    def __init__(self, *, _ispytest: bool = False) -> None:
520        check_ispytest(_ispytest)
521        self._config: Optional[Config] = None
522        self._markers: Set[str] = set()
@final
class Metafunc:
1087@final
1088class Metafunc:
1089    """Objects passed to the :hook:`pytest_generate_tests` hook.
1090
1091    They help to inspect a test function and to generate tests according to
1092    test configuration or values specified in the class or module where a
1093    test function is defined.
1094    """
1095
1096    def __init__(
1097        self,
1098        definition: "FunctionDefinition",
1099        fixtureinfo: fixtures.FuncFixtureInfo,
1100        config: Config,
1101        cls=None,
1102        module=None,
1103        *,
1104        _ispytest: bool = False,
1105    ) -> None:
1106        check_ispytest(_ispytest)
1107
1108        #: Access to the underlying :class:`_pytest.python.FunctionDefinition`.
1109        self.definition = definition
1110
1111        #: Access to the :class:`pytest.Config` object for the test session.
1112        self.config = config
1113
1114        #: The module object where the test function is defined in.
1115        self.module = module
1116
1117        #: Underlying Python test function.
1118        self.function = definition.obj
1119
1120        #: Set of fixture names required by the test function.
1121        self.fixturenames = fixtureinfo.names_closure
1122
1123        #: Class object where the test function is defined in or ``None``.
1124        self.cls = cls
1125
1126        self._arg2fixturedefs = fixtureinfo.name2fixturedefs
1127
1128        # Result of parametrize().
1129        self._calls: List[CallSpec2] = []
1130
1131    def parametrize(
1132        self,
1133        argnames: Union[str, Sequence[str]],
1134        argvalues: Iterable[Union[ParameterSet, Sequence[object], object]],
1135        indirect: Union[bool, Sequence[str]] = False,
1136        ids: Optional[
1137            Union[Iterable[Optional[object]], Callable[[Any], Optional[object]]]
1138        ] = None,
1139        scope: Optional[_ScopeName] = None,
1140        *,
1141        _param_mark: Optional[Mark] = None,
1142    ) -> None:
1143        """Add new invocations to the underlying test function using the list
1144        of argvalues for the given argnames. Parametrization is performed
1145        during the collection phase. If you need to setup expensive resources
1146        see about setting indirect to do it rather than at test setup time.
1147
1148        Can be called multiple times per test function (but only on different
1149        argument names), in which case each call parametrizes all previous
1150        parametrizations, e.g.
1151
1152        ::
1153
1154            unparametrized:         t
1155            parametrize ["x", "y"]: t[x], t[y]
1156            parametrize [1, 2]:     t[x-1], t[x-2], t[y-1], t[y-2]
1157
1158        :param argnames:
1159            A comma-separated string denoting one or more argument names, or
1160            a list/tuple of argument strings.
1161
1162        :param argvalues:
1163            The list of argvalues determines how often a test is invoked with
1164            different argument values.
1165
1166            If only one argname was specified argvalues is a list of values.
1167            If N argnames were specified, argvalues must be a list of
1168            N-tuples, where each tuple-element specifies a value for its
1169            respective argname.
1170
1171        :param indirect:
1172            A list of arguments' names (subset of argnames) or a boolean.
1173            If True the list contains all names from the argnames. Each
1174            argvalue corresponding to an argname in this list will
1175            be passed as request.param to its respective argname fixture
1176            function so that it can perform more expensive setups during the
1177            setup phase of a test rather than at collection time.
1178
1179        :param ids:
1180            Sequence of (or generator for) ids for ``argvalues``,
1181            or a callable to return part of the id for each argvalue.
1182
1183            With sequences (and generators like ``itertools.count()``) the
1184            returned ids should be of type ``string``, ``int``, ``float``,
1185            ``bool``, or ``None``.
1186            They are mapped to the corresponding index in ``argvalues``.
1187            ``None`` means to use the auto-generated id.
1188
1189            If it is a callable it will be called for each entry in
1190            ``argvalues``, and the return value is used as part of the
1191            auto-generated id for the whole set (where parts are joined with
1192            dashes ("-")).
1193            This is useful to provide more specific ids for certain items, e.g.
1194            dates.  Returning ``None`` will use an auto-generated id.
1195
1196            If no ids are provided they will be generated automatically from
1197            the argvalues.
1198
1199        :param scope:
1200            If specified it denotes the scope of the parameters.
1201            The scope is used for grouping tests by parameter instances.
1202            It will also override any fixture-function defined scope, allowing
1203            to set a dynamic scope using test context or configuration.
1204        """
1205        argnames, parametersets = ParameterSet._for_parametrize(
1206            argnames,
1207            argvalues,
1208            self.function,
1209            self.config,
1210            nodeid=self.definition.nodeid,
1211        )
1212        del argvalues
1213
1214        if "request" in argnames:
1215            fail(
1216                "'request' is a reserved name and cannot be used in @pytest.mark.parametrize",
1217                pytrace=False,
1218            )
1219
1220        if scope is not None:
1221            scope_ = Scope.from_user(
1222                scope, descr=f"parametrize() call in {self.function.__name__}"
1223            )
1224        else:
1225            scope_ = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
1226
1227        self._validate_if_using_arg_names(argnames, indirect)
1228
1229        # Use any already (possibly) generated ids with parametrize Marks.
1230        if _param_mark and _param_mark._param_ids_from:
1231            generated_ids = _param_mark._param_ids_from._param_ids_generated
1232            if generated_ids is not None:
1233                ids = generated_ids
1234
1235        ids = self._resolve_parameter_set_ids(
1236            argnames, ids, parametersets, nodeid=self.definition.nodeid
1237        )
1238
1239        # Store used (possibly generated) ids with parametrize Marks.
1240        if _param_mark and _param_mark._param_ids_from and generated_ids is None:
1241            object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)
1242
1243        # Add funcargs as fixturedefs to fixtureinfo.arg2fixturedefs by registering
1244        # artificial "pseudo" FixtureDef's so that later at test execution time we can
1245        # rely on a proper FixtureDef to exist for fixture setup.
1246        node = None
1247        # If we have a scope that is higher than function, we need
1248        # to make sure we only ever create an according fixturedef on
1249        # a per-scope basis. We thus store and cache the fixturedef on the
1250        # node related to the scope.
1251        if scope_ is not Scope.Function:
1252            collector = self.definition.parent
1253            assert collector is not None
1254            node = get_scope_node(collector, scope_)
1255            if node is None:
1256                # If used class scope and there is no class, use module-level
1257                # collector (for now).
1258                if scope_ is Scope.Class:
1259                    assert isinstance(collector, Module)
1260                    node = collector
1261                # If used package scope and there is no package, use session
1262                # (for now).
1263                elif scope_ is Scope.Package:
1264                    node = collector.session
1265                else:
1266                    assert False, f"Unhandled missing scope: {scope}"
1267        if node is None:
1268            name2pseudofixturedef = None
1269        else:
1270            default: Dict[str, FixtureDef[Any]] = {}
1271            name2pseudofixturedef = node.stash.setdefault(
1272                name2pseudofixturedef_key, default
1273            )
1274        arg_directness = self._resolve_args_directness(argnames, indirect)
1275        for argname in argnames:
1276            if arg_directness[argname] == "indirect":
1277                continue
1278            if name2pseudofixturedef is not None and argname in name2pseudofixturedef:
1279                fixturedef = name2pseudofixturedef[argname]
1280            else:
1281                fixturedef = FixtureDef(
1282                    config=self.config,
1283                    baseid="",
1284                    argname=argname,
1285                    func=get_direct_param_fixture_func,
1286                    scope=scope_,
1287                    params=None,
1288                    ids=None,
1289                    _ispytest=True,
1290                )
1291                if name2pseudofixturedef is not None:
1292                    name2pseudofixturedef[argname] = fixturedef
1293            self._arg2fixturedefs[argname] = [fixturedef]
1294
1295        # Create the new calls: if we are parametrize() multiple times (by applying the decorator
1296        # more than once) then we accumulate those calls generating the cartesian product
1297        # of all calls.
1298        newcalls = []
1299        for callspec in self._calls or [CallSpec2()]:
1300            for param_index, (param_id, param_set) in enumerate(
1301                zip(ids, parametersets)
1302            ):
1303                newcallspec = callspec.setmulti(
1304                    argnames=argnames,
1305                    valset=param_set.values,
1306                    id=param_id,
1307                    marks=param_set.marks,
1308                    scope=scope_,
1309                    param_index=param_index,
1310                )
1311                newcalls.append(newcallspec)
1312        self._calls = newcalls
1313
1314    def _resolve_parameter_set_ids(
1315        self,
1316        argnames: Sequence[str],
1317        ids: Optional[
1318            Union[Iterable[Optional[object]], Callable[[Any], Optional[object]]]
1319        ],
1320        parametersets: Sequence[ParameterSet],
1321        nodeid: str,
1322    ) -> List[str]:
1323        """Resolve the actual ids for the given parameter sets.
1324
1325        :param argnames:
1326            Argument names passed to ``parametrize()``.
1327        :param ids:
1328            The `ids` parameter of the ``parametrize()`` call (see docs).
1329        :param parametersets:
1330            The parameter sets, each containing a set of values corresponding
1331            to ``argnames``.
1332        :param nodeid str:
1333            The nodeid of the definition item that generated this
1334            parametrization.
1335        :returns:
1336            List with ids for each parameter set given.
1337        """
1338        if ids is None:
1339            idfn = None
1340            ids_ = None
1341        elif callable(ids):
1342            idfn = ids
1343            ids_ = None
1344        else:
1345            idfn = None
1346            ids_ = self._validate_ids(ids, parametersets, self.function.__name__)
1347        id_maker = IdMaker(
1348            argnames,
1349            parametersets,
1350            idfn,
1351            ids_,
1352            self.config,
1353            nodeid=nodeid,
1354            func_name=self.function.__name__,
1355        )
1356        return id_maker.make_unique_parameterset_ids()
1357
1358    def _validate_ids(
1359        self,
1360        ids: Iterable[Optional[object]],
1361        parametersets: Sequence[ParameterSet],
1362        func_name: str,
1363    ) -> List[Optional[object]]:
1364        try:
1365            num_ids = len(ids)  # type: ignore[arg-type]
1366        except TypeError:
1367            try:
1368                iter(ids)
1369            except TypeError as e:
1370                raise TypeError("ids must be a callable or an iterable") from e
1371            num_ids = len(parametersets)
1372
1373        # num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849
1374        if num_ids != len(parametersets) and num_ids != 0:
1375            msg = "In {}: {} parameter sets specified, with different number of ids: {}"
1376            fail(msg.format(func_name, len(parametersets), num_ids), pytrace=False)
1377
1378        return list(itertools.islice(ids, num_ids))
1379
1380    def _resolve_args_directness(
1381        self,
1382        argnames: Sequence[str],
1383        indirect: Union[bool, Sequence[str]],
1384    ) -> Dict[str, Literal["indirect", "direct"]]:
1385        """Resolve if each parametrized argument must be considered an indirect
1386        parameter to a fixture of the same name, or a direct parameter to the
1387        parametrized function, based on the ``indirect`` parameter of the
1388        parametrized() call.
1389
1390        :param argnames:
1391            List of argument names passed to ``parametrize()``.
1392        :param indirect:
1393            Same as the ``indirect`` parameter of ``parametrize()``.
1394        :returns
1395            A dict mapping each arg name to either "indirect" or "direct".
1396        """
1397        arg_directness: Dict[str, Literal["indirect", "direct"]]
1398        if isinstance(indirect, bool):
1399            arg_directness = dict.fromkeys(
1400                argnames, "indirect" if indirect else "direct"
1401            )
1402        elif isinstance(indirect, Sequence):
1403            arg_directness = dict.fromkeys(argnames, "direct")
1404            for arg in indirect:
1405                if arg not in argnames:
1406                    fail(
1407                        f"In {self.function.__name__}: indirect fixture '{arg}' doesn't exist",
1408                        pytrace=False,
1409                    )
1410                arg_directness[arg] = "indirect"
1411        else:
1412            fail(
1413                f"In {self.function.__name__}: expected Sequence or boolean"
1414                f" for indirect, got {type(indirect).__name__}",
1415                pytrace=False,
1416            )
1417        return arg_directness
1418
1419    def _validate_if_using_arg_names(
1420        self,
1421        argnames: Sequence[str],
1422        indirect: Union[bool, Sequence[str]],
1423    ) -> None:
1424        """Check if all argnames are being used, by default values, or directly/indirectly.
1425
1426        :param List[str] argnames: List of argument names passed to ``parametrize()``.
1427        :param indirect: Same as the ``indirect`` parameter of ``parametrize()``.
1428        :raises ValueError: If validation fails.
1429        """
1430        default_arg_names = set(get_default_arg_names(self.function))
1431        func_name = self.function.__name__
1432        for arg in argnames:
1433            if arg not in self.fixturenames:
1434                if arg in default_arg_names:
1435                    fail(
1436                        f"In {func_name}: function already takes an argument '{arg}' with a default value",
1437                        pytrace=False,
1438                    )
1439                else:
1440                    if isinstance(indirect, Sequence):
1441                        name = "fixture" if arg in indirect else "argument"
1442                    else:
1443                        name = "fixture" if indirect else "argument"
1444                    fail(
1445                        f"In {func_name}: function uses no {name} '{arg}'",
1446                        pytrace=False,
1447                    )

Objects passed to the :hook:pytest_generate_tests hook.

They help to inspect a test function and to generate tests according to test configuration or values specified in the class or module where a test function is defined.

Metafunc( definition: _pytest.python.FunctionDefinition, fixtureinfo: _pytest.fixtures.FuncFixtureInfo, config: Config, cls=None, module=None, *, _ispytest: bool = False)
1096    def __init__(
1097        self,
1098        definition: "FunctionDefinition",
1099        fixtureinfo: fixtures.FuncFixtureInfo,
1100        config: Config,
1101        cls=None,
1102        module=None,
1103        *,
1104        _ispytest: bool = False,
1105    ) -> None:
1106        check_ispytest(_ispytest)
1107
1108        #: Access to the underlying :class:`_pytest.python.FunctionDefinition`.
1109        self.definition = definition
1110
1111        #: Access to the :class:`pytest.Config` object for the test session.
1112        self.config = config
1113
1114        #: The module object where the test function is defined in.
1115        self.module = module
1116
1117        #: Underlying Python test function.
1118        self.function = definition.obj
1119
1120        #: Set of fixture names required by the test function.
1121        self.fixturenames = fixtureinfo.names_closure
1122
1123        #: Class object where the test function is defined in or ``None``.
1124        self.cls = cls
1125
1126        self._arg2fixturedefs = fixtureinfo.name2fixturedefs
1127
1128        # Result of parametrize().
1129        self._calls: List[CallSpec2] = []
definition
config
module
function
fixturenames
cls
def parametrize( self, argnames: Union[str, Sequence[str]], argvalues: Iterable[Union[_pytest.mark.structures.ParameterSet, Sequence[object], object]], indirect: Union[bool, Sequence[str]] = False, ids: Union[Iterable[Optional[object]], Callable[[Any], Optional[object]], NoneType] = None, scope: Optional[Literal['session', 'package', 'module', 'class', 'function']] = None, *, _param_mark: Optional[Mark] = None) -> None:
1131    def parametrize(
1132        self,
1133        argnames: Union[str, Sequence[str]],
1134        argvalues: Iterable[Union[ParameterSet, Sequence[object], object]],
1135        indirect: Union[bool, Sequence[str]] = False,
1136        ids: Optional[
1137            Union[Iterable[Optional[object]], Callable[[Any], Optional[object]]]
1138        ] = None,
1139        scope: Optional[_ScopeName] = None,
1140        *,
1141        _param_mark: Optional[Mark] = None,
1142    ) -> None:
1143        """Add new invocations to the underlying test function using the list
1144        of argvalues for the given argnames. Parametrization is performed
1145        during the collection phase. If you need to setup expensive resources
1146        see about setting indirect to do it rather than at test setup time.
1147
1148        Can be called multiple times per test function (but only on different
1149        argument names), in which case each call parametrizes all previous
1150        parametrizations, e.g.
1151
1152        ::
1153
1154            unparametrized:         t
1155            parametrize ["x", "y"]: t[x], t[y]
1156            parametrize [1, 2]:     t[x-1], t[x-2], t[y-1], t[y-2]
1157
1158        :param argnames:
1159            A comma-separated string denoting one or more argument names, or
1160            a list/tuple of argument strings.
1161
1162        :param argvalues:
1163            The list of argvalues determines how often a test is invoked with
1164            different argument values.
1165
1166            If only one argname was specified argvalues is a list of values.
1167            If N argnames were specified, argvalues must be a list of
1168            N-tuples, where each tuple-element specifies a value for its
1169            respective argname.
1170
1171        :param indirect:
1172            A list of arguments' names (subset of argnames) or a boolean.
1173            If True the list contains all names from the argnames. Each
1174            argvalue corresponding to an argname in this list will
1175            be passed as request.param to its respective argname fixture
1176            function so that it can perform more expensive setups during the
1177            setup phase of a test rather than at collection time.
1178
1179        :param ids:
1180            Sequence of (or generator for) ids for ``argvalues``,
1181            or a callable to return part of the id for each argvalue.
1182
1183            With sequences (and generators like ``itertools.count()``) the
1184            returned ids should be of type ``string``, ``int``, ``float``,
1185            ``bool``, or ``None``.
1186            They are mapped to the corresponding index in ``argvalues``.
1187            ``None`` means to use the auto-generated id.
1188
1189            If it is a callable it will be called for each entry in
1190            ``argvalues``, and the return value is used as part of the
1191            auto-generated id for the whole set (where parts are joined with
1192            dashes ("-")).
1193            This is useful to provide more specific ids for certain items, e.g.
1194            dates.  Returning ``None`` will use an auto-generated id.
1195
1196            If no ids are provided they will be generated automatically from
1197            the argvalues.
1198
1199        :param scope:
1200            If specified it denotes the scope of the parameters.
1201            The scope is used for grouping tests by parameter instances.
1202            It will also override any fixture-function defined scope, allowing
1203            to set a dynamic scope using test context or configuration.
1204        """
1205        argnames, parametersets = ParameterSet._for_parametrize(
1206            argnames,
1207            argvalues,
1208            self.function,
1209            self.config,
1210            nodeid=self.definition.nodeid,
1211        )
1212        del argvalues
1213
1214        if "request" in argnames:
1215            fail(
1216                "'request' is a reserved name and cannot be used in @pytest.mark.parametrize",
1217                pytrace=False,
1218            )
1219
1220        if scope is not None:
1221            scope_ = Scope.from_user(
1222                scope, descr=f"parametrize() call in {self.function.__name__}"
1223            )
1224        else:
1225            scope_ = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
1226
1227        self._validate_if_using_arg_names(argnames, indirect)
1228
1229        # Use any already (possibly) generated ids with parametrize Marks.
1230        if _param_mark and _param_mark._param_ids_from:
1231            generated_ids = _param_mark._param_ids_from._param_ids_generated
1232            if generated_ids is not None:
1233                ids = generated_ids
1234
1235        ids = self._resolve_parameter_set_ids(
1236            argnames, ids, parametersets, nodeid=self.definition.nodeid
1237        )
1238
1239        # Store used (possibly generated) ids with parametrize Marks.
1240        if _param_mark and _param_mark._param_ids_from and generated_ids is None:
1241            object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)
1242
1243        # Add funcargs as fixturedefs to fixtureinfo.arg2fixturedefs by registering
1244        # artificial "pseudo" FixtureDef's so that later at test execution time we can
1245        # rely on a proper FixtureDef to exist for fixture setup.
1246        node = None
1247        # If we have a scope that is higher than function, we need
1248        # to make sure we only ever create an according fixturedef on
1249        # a per-scope basis. We thus store and cache the fixturedef on the
1250        # node related to the scope.
1251        if scope_ is not Scope.Function:
1252            collector = self.definition.parent
1253            assert collector is not None
1254            node = get_scope_node(collector, scope_)
1255            if node is None:
1256                # If used class scope and there is no class, use module-level
1257                # collector (for now).
1258                if scope_ is Scope.Class:
1259                    assert isinstance(collector, Module)
1260                    node = collector
1261                # If used package scope and there is no package, use session
1262                # (for now).
1263                elif scope_ is Scope.Package:
1264                    node = collector.session
1265                else:
1266                    assert False, f"Unhandled missing scope: {scope}"
1267        if node is None:
1268            name2pseudofixturedef = None
1269        else:
1270            default: Dict[str, FixtureDef[Any]] = {}
1271            name2pseudofixturedef = node.stash.setdefault(
1272                name2pseudofixturedef_key, default
1273            )
1274        arg_directness = self._resolve_args_directness(argnames, indirect)
1275        for argname in argnames:
1276            if arg_directness[argname] == "indirect":
1277                continue
1278            if name2pseudofixturedef is not None and argname in name2pseudofixturedef:
1279                fixturedef = name2pseudofixturedef[argname]
1280            else:
1281                fixturedef = FixtureDef(
1282                    config=self.config,
1283                    baseid="",
1284                    argname=argname,
1285                    func=get_direct_param_fixture_func,
1286                    scope=scope_,
1287                    params=None,
1288                    ids=None,
1289                    _ispytest=True,
1290                )
1291                if name2pseudofixturedef is not None:
1292                    name2pseudofixturedef[argname] = fixturedef
1293            self._arg2fixturedefs[argname] = [fixturedef]
1294
1295        # Create the new calls: if we are parametrize() multiple times (by applying the decorator
1296        # more than once) then we accumulate those calls generating the cartesian product
1297        # of all calls.
1298        newcalls = []
1299        for callspec in self._calls or [CallSpec2()]:
1300            for param_index, (param_id, param_set) in enumerate(
1301                zip(ids, parametersets)
1302            ):
1303                newcallspec = callspec.setmulti(
1304                    argnames=argnames,
1305                    valset=param_set.values,
1306                    id=param_id,
1307                    marks=param_set.marks,
1308                    scope=scope_,
1309                    param_index=param_index,
1310                )
1311                newcalls.append(newcallspec)
1312        self._calls = newcalls

Add new invocations to the underlying test function using the list of argvalues for the given argnames. Parametrization is performed during the collection phase. If you need to setup expensive resources see about setting indirect to do it rather than at test setup time.

Can be called multiple times per test function (but only on different argument names), in which case each call parametrizes all previous parametrizations, e.g.

::

unparametrized:         t
parametrize ["x", "y"]: t[x], t[y]
parametrize [1, 2]:     t[x-1], t[x-2], t[y-1], t[y-2]
Parameters
  • argnames: A comma-separated string denoting one or more argument names, or a list/tuple of argument strings.

  • argvalues: The list of argvalues determines how often a test is invoked with different argument values.

    If only one argname was specified argvalues is a list of values. If N argnames were specified, argvalues must be a list of N-tuples, where each tuple-element specifies a value for its respective argname.

  • indirect: A list of arguments' names (subset of argnames) or a boolean. If True the list contains all names from the argnames. Each argvalue corresponding to an argname in this list will be passed as request.param to its respective argname fixture function so that it can perform more expensive setups during the setup phase of a test rather than at collection time.

  • ids: Sequence of (or generator for) ids for argvalues, or a callable to return part of the id for each argvalue.

    With sequences (and generators like itertools.count()) the returned ids should be of type string, int, float, bool, or None. They are mapped to the corresponding index in argvalues. None means to use the auto-generated id.

    If it is a callable it will be called for each entry in argvalues, and the return value is used as part of the auto-generated id for the whole set (where parts are joined with dashes ("-")). This is useful to provide more specific ids for certain items, e.g. dates. Returning None will use an auto-generated id.

    If no ids are provided they will be generated automatically from the argvalues.

  • scope: If specified it denotes the scope of the parameters. The scope is used for grouping tests by parameter instances. It will also override any fixture-function defined scope, allowing to set a dynamic scope using test context or configuration.

class Module(pytest.File, _pytest.python.PyCollector):
537class Module(nodes.File, PyCollector):
538    """Collector for test classes and functions in a Python module."""
539
540    def _getobj(self):
541        return importtestmodule(self.path, self.config)
542
543    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
544        self._register_setup_module_fixture()
545        self._register_setup_function_fixture()
546        self.session._fixturemanager.parsefactories(self)
547        return super().collect()
548
549    def _register_setup_module_fixture(self) -> None:
550        """Register an autouse, module-scoped fixture for the collected module object
551        that invokes setUpModule/tearDownModule if either or both are available.
552
553        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
554        other fixtures (#517).
555        """
556        setup_module = _get_first_non_fixture_func(
557            self.obj, ("setUpModule", "setup_module")
558        )
559        teardown_module = _get_first_non_fixture_func(
560            self.obj, ("tearDownModule", "teardown_module")
561        )
562
563        if setup_module is None and teardown_module is None:
564            return
565
566        def xunit_setup_module_fixture(request) -> Generator[None, None, None]:
567            module = request.module
568            if setup_module is not None:
569                _call_with_optional_argument(setup_module, module)
570            yield
571            if teardown_module is not None:
572                _call_with_optional_argument(teardown_module, module)
573
574        self.session._fixturemanager._register_fixture(
575            # Use a unique name to speed up lookup.
576            name=f"_xunit_setup_module_fixture_{self.obj.__name__}",
577            func=xunit_setup_module_fixture,
578            nodeid=self.nodeid,
579            scope="module",
580            autouse=True,
581        )
582
583    def _register_setup_function_fixture(self) -> None:
584        """Register an autouse, function-scoped fixture for the collected module object
585        that invokes setup_function/teardown_function if either or both are available.
586
587        Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
588        other fixtures (#517).
589        """
590        setup_function = _get_first_non_fixture_func(self.obj, ("setup_function",))
591        teardown_function = _get_first_non_fixture_func(
592            self.obj, ("teardown_function",)
593        )
594        if setup_function is None and teardown_function is None:
595            return
596
597        def xunit_setup_function_fixture(request) -> Generator[None, None, None]:
598            if request.instance is not None:
599                # in this case we are bound to an instance, so we need to let
600                # setup_method handle this
601                yield
602                return
603            function = request.function
604            if setup_function is not None:
605                _call_with_optional_argument(setup_function, function)
606            yield
607            if teardown_function is not None:
608                _call_with_optional_argument(teardown_function, function)
609
610        self.session._fixturemanager._register_fixture(
611            # Use a unique name to speed up lookup.
612            name=f"_xunit_setup_function_fixture_{self.obj.__name__}",
613            func=xunit_setup_function_fixture,
614            nodeid=self.nodeid,
615            scope="function",
616            autouse=True,
617        )

Collector for test classes and functions in a Python module.

def collect(self) -> Iterable[Union[Item, Collector]]:
543    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
544        self._register_setup_module_fixture()
545        self._register_setup_function_fixture()
546        self.session._fixturemanager.parsefactories(self)
547        return super().collect()

Collect children (items and collectors) for this collector.

Inherited Members
_pytest.nodes.FSCollector
FSCollector
path
from_parent
_pytest.python.PyCollector
funcnamefilter
isnosetest
classnamefilter
istestfunction
istestclass
_pytest.python.PyobjMixin
module
cls
instance
obj
getmodpath
reportinfo
Collector
CollectError
repr_failure
_pytest.nodes.Node
fspath
name
parent
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
@final
class MonkeyPatch:
119@final
120class MonkeyPatch:
121    """Helper to conveniently monkeypatch attributes/items/environment
122    variables/syspath.
123
124    Returned by the :fixture:`monkeypatch` fixture.
125
126    .. versionchanged:: 6.2
127        Can now also be used directly as `pytest.MonkeyPatch()`, for when
128        the fixture is not available. In this case, use
129        :meth:`with MonkeyPatch.context() as mp: <context>` or remember to call
130        :meth:`undo` explicitly.
131    """
132
133    def __init__(self) -> None:
134        self._setattr: List[Tuple[object, str, object]] = []
135        self._setitem: List[Tuple[Mapping[Any, Any], object, object]] = []
136        self._cwd: Optional[str] = None
137        self._savesyspath: Optional[List[str]] = None
138
139    @classmethod
140    @contextmanager
141    def context(cls) -> Generator["MonkeyPatch", None, None]:
142        """Context manager that returns a new :class:`MonkeyPatch` object
143        which undoes any patching done inside the ``with`` block upon exit.
144
145        Example:
146        .. code-block:: python
147
148            import functools
149
150
151            def test_partial(monkeypatch):
152                with monkeypatch.context() as m:
153                    m.setattr(functools, "partial", 3)
154
155        Useful in situations where it is desired to undo some patches before the test ends,
156        such as mocking ``stdlib`` functions that might break pytest itself if mocked (for examples
157        of this see :issue:`3290`).
158        """
159        m = cls()
160        try:
161            yield m
162        finally:
163            m.undo()
164
165    @overload
166    def setattr(
167        self,
168        target: str,
169        name: object,
170        value: Notset = ...,
171        raising: bool = ...,
172    ) -> None: ...
173
174    @overload
175    def setattr(
176        self,
177        target: object,
178        name: str,
179        value: object,
180        raising: bool = ...,
181    ) -> None: ...
182
183    def setattr(
184        self,
185        target: Union[str, object],
186        name: Union[object, str],
187        value: object = notset,
188        raising: bool = True,
189    ) -> None:
190        """
191        Set attribute value on target, memorizing the old value.
192
193        For example:
194
195        .. code-block:: python
196
197            import os
198
199            monkeypatch.setattr(os, "getcwd", lambda: "/")
200
201        The code above replaces the :func:`os.getcwd` function by a ``lambda`` which
202        always returns ``"/"``.
203
204        For convenience, you can specify a string as ``target`` which
205        will be interpreted as a dotted import path, with the last part
206        being the attribute name:
207
208        .. code-block:: python
209
210            monkeypatch.setattr("os.getcwd", lambda: "/")
211
212        Raises :class:`AttributeError` if the attribute does not exist, unless
213        ``raising`` is set to False.
214
215        **Where to patch**
216
217        ``monkeypatch.setattr`` works by (temporarily) changing the object that a name points to with another one.
218        There can be many names pointing to any individual object, so for patching to work you must ensure
219        that you patch the name used by the system under test.
220
221        See the section :ref:`Where to patch <python:where-to-patch>` in the :mod:`unittest.mock`
222        docs for a complete explanation, which is meant for :func:`unittest.mock.patch` but
223        applies to ``monkeypatch.setattr`` as well.
224        """
225        __tracebackhide__ = True
226        import inspect
227
228        if isinstance(value, Notset):
229            if not isinstance(target, str):
230                raise TypeError(
231                    "use setattr(target, name, value) or "
232                    "setattr(target, value) with target being a dotted "
233                    "import string"
234                )
235            value = name
236            name, target = derive_importpath(target, raising)
237        else:
238            if not isinstance(name, str):
239                raise TypeError(
240                    "use setattr(target, name, value) with name being a string or "
241                    "setattr(target, value) with target being a dotted "
242                    "import string"
243                )
244
245        oldval = getattr(target, name, notset)
246        if raising and oldval is notset:
247            raise AttributeError(f"{target!r} has no attribute {name!r}")
248
249        # avoid class descriptors like staticmethod/classmethod
250        if inspect.isclass(target):
251            oldval = target.__dict__.get(name, notset)
252        self._setattr.append((target, name, oldval))
253        setattr(target, name, value)
254
255    def delattr(
256        self,
257        target: Union[object, str],
258        name: Union[str, Notset] = notset,
259        raising: bool = True,
260    ) -> None:
261        """Delete attribute ``name`` from ``target``.
262
263        If no ``name`` is specified and ``target`` is a string
264        it will be interpreted as a dotted import path with the
265        last part being the attribute name.
266
267        Raises AttributeError it the attribute does not exist, unless
268        ``raising`` is set to False.
269        """
270        __tracebackhide__ = True
271        import inspect
272
273        if isinstance(name, Notset):
274            if not isinstance(target, str):
275                raise TypeError(
276                    "use delattr(target, name) or "
277                    "delattr(target) with target being a dotted "
278                    "import string"
279                )
280            name, target = derive_importpath(target, raising)
281
282        if not hasattr(target, name):
283            if raising:
284                raise AttributeError(name)
285        else:
286            oldval = getattr(target, name, notset)
287            # Avoid class descriptors like staticmethod/classmethod.
288            if inspect.isclass(target):
289                oldval = target.__dict__.get(name, notset)
290            self._setattr.append((target, name, oldval))
291            delattr(target, name)
292
293    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
294        """Set dictionary entry ``name`` to value."""
295        self._setitem.append((dic, name, dic.get(name, notset)))
296        # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
297        dic[name] = value  # type: ignore[index]
298
299    def delitem(self, dic: Mapping[K, V], name: K, raising: bool = True) -> None:
300        """Delete ``name`` from dict.
301
302        Raises ``KeyError`` if it doesn't exist, unless ``raising`` is set to
303        False.
304        """
305        if name not in dic:
306            if raising:
307                raise KeyError(name)
308        else:
309            self._setitem.append((dic, name, dic.get(name, notset)))
310            # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
311            del dic[name]  # type: ignore[attr-defined]
312
313    def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None:
314        """Set environment variable ``name`` to ``value``.
315
316        If ``prepend`` is a character, read the current environment variable
317        value and prepend the ``value`` adjoined with the ``prepend``
318        character.
319        """
320        if not isinstance(value, str):
321            warnings.warn(  # type: ignore[unreachable]
322                PytestWarning(
323                    f"Value of environment variable {name} type should be str, but got "
324                    f"{value!r} (type: {type(value).__name__}); converted to str implicitly"
325                ),
326                stacklevel=2,
327            )
328            value = str(value)
329        if prepend and name in os.environ:
330            value = value + prepend + os.environ[name]
331        self.setitem(os.environ, name, value)
332
333    def delenv(self, name: str, raising: bool = True) -> None:
334        """Delete ``name`` from the environment.
335
336        Raises ``KeyError`` if it does not exist, unless ``raising`` is set to
337        False.
338        """
339        environ: MutableMapping[str, str] = os.environ
340        self.delitem(environ, name, raising=raising)
341
342    def syspath_prepend(self, path) -> None:
343        """Prepend ``path`` to ``sys.path`` list of import locations."""
344        if self._savesyspath is None:
345            self._savesyspath = sys.path[:]
346        sys.path.insert(0, str(path))
347
348        # https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171
349        # this is only needed when pkg_resources was already loaded by the namespace package
350        if "pkg_resources" in sys.modules:
351            from pkg_resources import fixup_namespace_packages
352
353            fixup_namespace_packages(str(path))
354
355        # A call to syspathinsert() usually means that the caller wants to
356        # import some dynamically created files, thus with python3 we
357        # invalidate its import caches.
358        # This is especially important when any namespace package is in use,
359        # since then the mtime based FileFinder cache (that gets created in
360        # this case already) gets not invalidated when writing the new files
361        # quickly afterwards.
362        from importlib import invalidate_caches
363
364        invalidate_caches()
365
366    def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None:
367        """Change the current working directory to the specified path.
368
369        :param path:
370            The path to change into.
371        """
372        if self._cwd is None:
373            self._cwd = os.getcwd()
374        os.chdir(path)
375
376    def undo(self) -> None:
377        """Undo previous changes.
378
379        This call consumes the undo stack. Calling it a second time has no
380        effect unless you do more monkeypatching after the undo call.
381
382        There is generally no need to call `undo()`, since it is
383        called automatically during tear-down.
384
385        .. note::
386            The same `monkeypatch` fixture is used across a
387            single test function invocation. If `monkeypatch` is used both by
388            the test function itself and one of the test fixtures,
389            calling `undo()` will undo all of the changes made in
390            both functions.
391
392            Prefer to use :meth:`context() <pytest.MonkeyPatch.context>` instead.
393        """
394        for obj, name, value in reversed(self._setattr):
395            if value is not notset:
396                setattr(obj, name, value)
397            else:
398                delattr(obj, name)
399        self._setattr[:] = []
400        for dictionary, key, value in reversed(self._setitem):
401            if value is notset:
402                try:
403                    # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
404                    del dictionary[key]  # type: ignore[attr-defined]
405                except KeyError:
406                    pass  # Was already deleted, so we have the desired state.
407            else:
408                # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
409                dictionary[key] = value  # type: ignore[index]
410        self._setitem[:] = []
411        if self._savesyspath is not None:
412            sys.path[:] = self._savesyspath
413            self._savesyspath = None
414
415        if self._cwd is not None:
416            os.chdir(self._cwd)
417            self._cwd = None

Helper to conveniently monkeypatch attributes/items/environment variables/syspath.

Returned by the :fixture:monkeypatch fixture.

Changed in version 6.2: Can now also be used directly as pytest.MonkeyPatch(), for when the fixture is not available. In this case, use with MonkeyPatch.context() as mp: <context>() or remember to call undo() explicitly.

@classmethod
@contextmanager
def context(cls) -> Generator[MonkeyPatch, NoneType, NoneType]:
139    @classmethod
140    @contextmanager
141    def context(cls) -> Generator["MonkeyPatch", None, None]:
142        """Context manager that returns a new :class:`MonkeyPatch` object
143        which undoes any patching done inside the ``with`` block upon exit.
144
145        Example:
146        .. code-block:: python
147
148            import functools
149
150
151            def test_partial(monkeypatch):
152                with monkeypatch.context() as m:
153                    m.setattr(functools, "partial", 3)
154
155        Useful in situations where it is desired to undo some patches before the test ends,
156        such as mocking ``stdlib`` functions that might break pytest itself if mocked (for examples
157        of this see :issue:`3290`).
158        """
159        m = cls()
160        try:
161            yield m
162        finally:
163            m.undo()

Context manager that returns a new MonkeyPatch object which undoes any patching done inside the with block upon exit.

Example:

import functools


def test_partial(monkeypatch):
    with monkeypatch.context() as m:
        m.setattr(functools, "partial", 3)

Useful in situations where it is desired to undo some patches before the test ends, such as mocking stdlib functions that might break pytest itself if mocked (for examples of this see :issue:3290).

def setattr( self, target: Union[str, object], name: Union[object, str], value: object = <notset>, raising: bool = True) -> None:
183    def setattr(
184        self,
185        target: Union[str, object],
186        name: Union[object, str],
187        value: object = notset,
188        raising: bool = True,
189    ) -> None:
190        """
191        Set attribute value on target, memorizing the old value.
192
193        For example:
194
195        .. code-block:: python
196
197            import os
198
199            monkeypatch.setattr(os, "getcwd", lambda: "/")
200
201        The code above replaces the :func:`os.getcwd` function by a ``lambda`` which
202        always returns ``"/"``.
203
204        For convenience, you can specify a string as ``target`` which
205        will be interpreted as a dotted import path, with the last part
206        being the attribute name:
207
208        .. code-block:: python
209
210            monkeypatch.setattr("os.getcwd", lambda: "/")
211
212        Raises :class:`AttributeError` if the attribute does not exist, unless
213        ``raising`` is set to False.
214
215        **Where to patch**
216
217        ``monkeypatch.setattr`` works by (temporarily) changing the object that a name points to with another one.
218        There can be many names pointing to any individual object, so for patching to work you must ensure
219        that you patch the name used by the system under test.
220
221        See the section :ref:`Where to patch <python:where-to-patch>` in the :mod:`unittest.mock`
222        docs for a complete explanation, which is meant for :func:`unittest.mock.patch` but
223        applies to ``monkeypatch.setattr`` as well.
224        """
225        __tracebackhide__ = True
226        import inspect
227
228        if isinstance(value, Notset):
229            if not isinstance(target, str):
230                raise TypeError(
231                    "use setattr(target, name, value) or "
232                    "setattr(target, value) with target being a dotted "
233                    "import string"
234                )
235            value = name
236            name, target = derive_importpath(target, raising)
237        else:
238            if not isinstance(name, str):
239                raise TypeError(
240                    "use setattr(target, name, value) with name being a string or "
241                    "setattr(target, value) with target being a dotted "
242                    "import string"
243                )
244
245        oldval = getattr(target, name, notset)
246        if raising and oldval is notset:
247            raise AttributeError(f"{target!r} has no attribute {name!r}")
248
249        # avoid class descriptors like staticmethod/classmethod
250        if inspect.isclass(target):
251            oldval = target.__dict__.get(name, notset)
252        self._setattr.append((target, name, oldval))
253        setattr(target, name, value)

Set attribute value on target, memorizing the old value.

For example:

import os

monkeypatch.setattr(os, "getcwd", lambda: "/")

The code above replaces the os.getcwd() function by a lambda which always returns "/".

For convenience, you can specify a string as target which will be interpreted as a dotted import path, with the last part being the attribute name:

monkeypatch.setattr("os.getcwd", lambda: "/")

Raises AttributeError if the attribute does not exist, unless raising is set to False.

Where to patch

monkeypatch.setattr works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.

See the section :ref:Where to patch <python:where-to-patch> in the unittest.mock docs for a complete explanation, which is meant for unittest.mock.patch() but applies to monkeypatch.setattr as well.

def delattr( self, target: Union[object, str], name: Union[str, _pytest.monkeypatch.Notset] = <notset>, raising: bool = True) -> None:
255    def delattr(
256        self,
257        target: Union[object, str],
258        name: Union[str, Notset] = notset,
259        raising: bool = True,
260    ) -> None:
261        """Delete attribute ``name`` from ``target``.
262
263        If no ``name`` is specified and ``target`` is a string
264        it will be interpreted as a dotted import path with the
265        last part being the attribute name.
266
267        Raises AttributeError it the attribute does not exist, unless
268        ``raising`` is set to False.
269        """
270        __tracebackhide__ = True
271        import inspect
272
273        if isinstance(name, Notset):
274            if not isinstance(target, str):
275                raise TypeError(
276                    "use delattr(target, name) or "
277                    "delattr(target) with target being a dotted "
278                    "import string"
279                )
280            name, target = derive_importpath(target, raising)
281
282        if not hasattr(target, name):
283            if raising:
284                raise AttributeError(name)
285        else:
286            oldval = getattr(target, name, notset)
287            # Avoid class descriptors like staticmethod/classmethod.
288            if inspect.isclass(target):
289                oldval = target.__dict__.get(name, notset)
290            self._setattr.append((target, name, oldval))
291            delattr(target, name)

Delete attribute name from target.

If no name is specified and target is a string it will be interpreted as a dotted import path with the last part being the attribute name.

Raises AttributeError it the attribute does not exist, unless raising is set to False.

def setitem(self, dic: Mapping[~K, ~V], name: ~K, value: ~V) -> None:
293    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
294        """Set dictionary entry ``name`` to value."""
295        self._setitem.append((dic, name, dic.get(name, notset)))
296        # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
297        dic[name] = value  # type: ignore[index]

Set dictionary entry name to value.

def delitem(self, dic: Mapping[~K, ~V], name: ~K, raising: bool = True) -> None:
299    def delitem(self, dic: Mapping[K, V], name: K, raising: bool = True) -> None:
300        """Delete ``name`` from dict.
301
302        Raises ``KeyError`` if it doesn't exist, unless ``raising`` is set to
303        False.
304        """
305        if name not in dic:
306            if raising:
307                raise KeyError(name)
308        else:
309            self._setitem.append((dic, name, dic.get(name, notset)))
310            # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
311            del dic[name]  # type: ignore[attr-defined]

Delete name from dict.

Raises KeyError if it doesn't exist, unless raising is set to False.

def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None:
313    def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None:
314        """Set environment variable ``name`` to ``value``.
315
316        If ``prepend`` is a character, read the current environment variable
317        value and prepend the ``value`` adjoined with the ``prepend``
318        character.
319        """
320        if not isinstance(value, str):
321            warnings.warn(  # type: ignore[unreachable]
322                PytestWarning(
323                    f"Value of environment variable {name} type should be str, but got "
324                    f"{value!r} (type: {type(value).__name__}); converted to str implicitly"
325                ),
326                stacklevel=2,
327            )
328            value = str(value)
329        if prepend and name in os.environ:
330            value = value + prepend + os.environ[name]
331        self.setitem(os.environ, name, value)

Set environment variable name to value.

If prepend is a character, read the current environment variable value and prepend the value adjoined with the prepend character.

def delenv(self, name: str, raising: bool = True) -> None:
333    def delenv(self, name: str, raising: bool = True) -> None:
334        """Delete ``name`` from the environment.
335
336        Raises ``KeyError`` if it does not exist, unless ``raising`` is set to
337        False.
338        """
339        environ: MutableMapping[str, str] = os.environ
340        self.delitem(environ, name, raising=raising)

Delete name from the environment.

Raises KeyError if it does not exist, unless raising is set to False.

def syspath_prepend(self, path) -> None:
342    def syspath_prepend(self, path) -> None:
343        """Prepend ``path`` to ``sys.path`` list of import locations."""
344        if self._savesyspath is None:
345            self._savesyspath = sys.path[:]
346        sys.path.insert(0, str(path))
347
348        # https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171
349        # this is only needed when pkg_resources was already loaded by the namespace package
350        if "pkg_resources" in sys.modules:
351            from pkg_resources import fixup_namespace_packages
352
353            fixup_namespace_packages(str(path))
354
355        # A call to syspathinsert() usually means that the caller wants to
356        # import some dynamically created files, thus with python3 we
357        # invalidate its import caches.
358        # This is especially important when any namespace package is in use,
359        # since then the mtime based FileFinder cache (that gets created in
360        # this case already) gets not invalidated when writing the new files
361        # quickly afterwards.
362        from importlib import invalidate_caches
363
364        invalidate_caches()

Prepend path to sys.path list of import locations.

def chdir(self, path: Union[str, os.PathLike[str]]) -> None:
366    def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None:
367        """Change the current working directory to the specified path.
368
369        :param path:
370            The path to change into.
371        """
372        if self._cwd is None:
373            self._cwd = os.getcwd()
374        os.chdir(path)

Change the current working directory to the specified path.

Parameters
  • path: The path to change into.
def undo(self) -> None:
376    def undo(self) -> None:
377        """Undo previous changes.
378
379        This call consumes the undo stack. Calling it a second time has no
380        effect unless you do more monkeypatching after the undo call.
381
382        There is generally no need to call `undo()`, since it is
383        called automatically during tear-down.
384
385        .. note::
386            The same `monkeypatch` fixture is used across a
387            single test function invocation. If `monkeypatch` is used both by
388            the test function itself and one of the test fixtures,
389            calling `undo()` will undo all of the changes made in
390            both functions.
391
392            Prefer to use :meth:`context() <pytest.MonkeyPatch.context>` instead.
393        """
394        for obj, name, value in reversed(self._setattr):
395            if value is not notset:
396                setattr(obj, name, value)
397            else:
398                delattr(obj, name)
399        self._setattr[:] = []
400        for dictionary, key, value in reversed(self._setitem):
401            if value is notset:
402                try:
403                    # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
404                    del dictionary[key]  # type: ignore[attr-defined]
405                except KeyError:
406                    pass  # Was already deleted, so we have the desired state.
407            else:
408                # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict
409                dictionary[key] = value  # type: ignore[index]
410        self._setitem[:] = []
411        if self._savesyspath is not None:
412            sys.path[:] = self._savesyspath
413            self._savesyspath = None
414
415        if self._cwd is not None:
416            os.chdir(self._cwd)
417            self._cwd = None

Undo previous changes.

This call consumes the undo stack. Calling it a second time has no effect unless you do more monkeypatching after the undo call.

There is generally no need to call undo(), since it is called automatically during tear-down.

The same monkeypatch fixture is used across a single test function invocation. If monkeypatch is used both by the test function itself and one of the test fixtures, calling undo() will undo all of the changes made in both functions.

Prefer to use context() <pytest.MonkeyPatch.context>() instead.

class OptionGroup:
352class OptionGroup:
353    """A group of options shown in its own section."""
354
355    def __init__(
356        self,
357        name: str,
358        description: str = "",
359        parser: Optional[Parser] = None,
360        *,
361        _ispytest: bool = False,
362    ) -> None:
363        check_ispytest(_ispytest)
364        self.name = name
365        self.description = description
366        self.options: List[Argument] = []
367        self.parser = parser
368
369    def addoption(self, *opts: str, **attrs: Any) -> None:
370        """Add an option to this group.
371
372        If a shortened version of a long option is specified, it will
373        be suppressed in the help. ``addoption('--twowords', '--two-words')``
374        results in help showing ``--two-words`` only, but ``--twowords`` gets
375        accepted **and** the automatic destination is in ``args.twowords``.
376
377        :param opts:
378            Option names, can be short or long options.
379        :param attrs:
380            Same attributes as the argparse library's :meth:`add_argument()
381            <argparse.ArgumentParser.add_argument>` function accepts.
382        """
383        conflict = set(opts).intersection(
384            name for opt in self.options for name in opt.names()
385        )
386        if conflict:
387            raise ValueError("option names %s already added" % conflict)
388        option = Argument(*opts, **attrs)
389        self._addoption_instance(option, shortupper=False)
390
391    def _addoption(self, *opts: str, **attrs: Any) -> None:
392        option = Argument(*opts, **attrs)
393        self._addoption_instance(option, shortupper=True)
394
395    def _addoption_instance(self, option: "Argument", shortupper: bool = False) -> None:
396        if not shortupper:
397            for opt in option._short_opts:
398                if opt[0] == "-" and opt[1].islower():
399                    raise ValueError("lowercase shortoptions reserved")
400        if self.parser:
401            self.parser.processoption(option)
402        self.options.append(option)

A group of options shown in its own section.

OptionGroup( name: str, description: str = '', parser: Optional[Parser] = None, *, _ispytest: bool = False)
355    def __init__(
356        self,
357        name: str,
358        description: str = "",
359        parser: Optional[Parser] = None,
360        *,
361        _ispytest: bool = False,
362    ) -> None:
363        check_ispytest(_ispytest)
364        self.name = name
365        self.description = description
366        self.options: List[Argument] = []
367        self.parser = parser
name
description
options: List[_pytest.config.argparsing.Argument]
parser
def addoption(self, *opts: str, **attrs: Any) -> None:
369    def addoption(self, *opts: str, **attrs: Any) -> None:
370        """Add an option to this group.
371
372        If a shortened version of a long option is specified, it will
373        be suppressed in the help. ``addoption('--twowords', '--two-words')``
374        results in help showing ``--two-words`` only, but ``--twowords`` gets
375        accepted **and** the automatic destination is in ``args.twowords``.
376
377        :param opts:
378            Option names, can be short or long options.
379        :param attrs:
380            Same attributes as the argparse library's :meth:`add_argument()
381            <argparse.ArgumentParser.add_argument>` function accepts.
382        """
383        conflict = set(opts).intersection(
384            name for opt in self.options for name in opt.names()
385        )
386        if conflict:
387            raise ValueError("option names %s already added" % conflict)
388        option = Argument(*opts, **attrs)
389        self._addoption_instance(option, shortupper=False)

Add an option to this group.

If a shortened version of a long option is specified, it will be suppressed in the help. addoption('--twowords', '--two-words') results in help showing --two-words only, but --twowords gets accepted and the automatic destination is in args.twowords.

Parameters
  • opts: Option names, can be short or long options.
  • attrs: Same attributes as the argparse library's add_argument() <argparse.ArgumentParser.add_argument>() function accepts.
class Package(pytest.Directory):
620class Package(nodes.Directory):
621    """Collector for files and directories in a Python packages -- directories
622    with an `__init__.py` file.
623
624    .. note::
625
626        Directories without an `__init__.py` file are instead collected by
627        :class:`~pytest.Dir` by default. Both are :class:`~pytest.Directory`
628        collectors.
629
630    .. versionchanged:: 8.0
631
632        Now inherits from :class:`~pytest.Directory`.
633    """
634
635    def __init__(
636        self,
637        fspath: Optional[LEGACY_PATH],
638        parent: nodes.Collector,
639        # NOTE: following args are unused:
640        config=None,
641        session=None,
642        nodeid=None,
643        path: Optional[Path] = None,
644    ) -> None:
645        # NOTE: Could be just the following, but kept as-is for compat.
646        # super().__init__(self, fspath, parent=parent)
647        session = parent.session
648        super().__init__(
649            fspath=fspath,
650            path=path,
651            parent=parent,
652            config=config,
653            session=session,
654            nodeid=nodeid,
655        )
656
657    def setup(self) -> None:
658        init_mod = importtestmodule(self.path / "__init__.py", self.config)
659
660        # Not using fixtures to call setup_module here because autouse fixtures
661        # from packages are not called automatically (#4085).
662        setup_module = _get_first_non_fixture_func(
663            init_mod, ("setUpModule", "setup_module")
664        )
665        if setup_module is not None:
666            _call_with_optional_argument(setup_module, init_mod)
667
668        teardown_module = _get_first_non_fixture_func(
669            init_mod, ("tearDownModule", "teardown_module")
670        )
671        if teardown_module is not None:
672            func = partial(_call_with_optional_argument, teardown_module, init_mod)
673            self.addfinalizer(func)
674
675    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
676        # Always collect __init__.py first.
677        def sort_key(entry: "os.DirEntry[str]") -> object:
678            return (entry.name != "__init__.py", entry.name)
679
680        config = self.config
681        col: Optional[nodes.Collector]
682        cols: Sequence[nodes.Collector]
683        ihook = self.ihook
684        for direntry in scandir(self.path, sort_key):
685            if direntry.is_dir():
686                path = Path(direntry.path)
687                if not self.session.isinitpath(path, with_parents=True):
688                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
689                        continue
690                col = ihook.pytest_collect_directory(path=path, parent=self)
691                if col is not None:
692                    yield col
693
694            elif direntry.is_file():
695                path = Path(direntry.path)
696                if not self.session.isinitpath(path):
697                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
698                        continue
699                cols = ihook.pytest_collect_file(file_path=path, parent=self)
700                yield from cols

Collector for files and directories in a Python packages -- directories with an __init__.py file.

Directories without an __init__.py file are instead collected by ~pytest.Dir by default. Both are ~pytest.Directory collectors.

Changed in version 8.0: Now inherits from ~pytest.Directory.

Package( fspath: Optional[_pytest._py.path.LocalPath], parent: Collector, config=None, session=None, nodeid=None, path: Optional[pathlib.Path] = None)
635    def __init__(
636        self,
637        fspath: Optional[LEGACY_PATH],
638        parent: nodes.Collector,
639        # NOTE: following args are unused:
640        config=None,
641        session=None,
642        nodeid=None,
643        path: Optional[Path] = None,
644    ) -> None:
645        # NOTE: Could be just the following, but kept as-is for compat.
646        # super().__init__(self, fspath, parent=parent)
647        session = parent.session
648        super().__init__(
649            fspath=fspath,
650            path=path,
651            parent=parent,
652            config=config,
653            session=session,
654            nodeid=nodeid,
655        )
def setup(self) -> None:
657    def setup(self) -> None:
658        init_mod = importtestmodule(self.path / "__init__.py", self.config)
659
660        # Not using fixtures to call setup_module here because autouse fixtures
661        # from packages are not called automatically (#4085).
662        setup_module = _get_first_non_fixture_func(
663            init_mod, ("setUpModule", "setup_module")
664        )
665        if setup_module is not None:
666            _call_with_optional_argument(setup_module, init_mod)
667
668        teardown_module = _get_first_non_fixture_func(
669            init_mod, ("tearDownModule", "teardown_module")
670        )
671        if teardown_module is not None:
672            func = partial(_call_with_optional_argument, teardown_module, init_mod)
673            self.addfinalizer(func)
def collect(self) -> Iterable[Union[Item, Collector]]:
675    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
676        # Always collect __init__.py first.
677        def sort_key(entry: "os.DirEntry[str]") -> object:
678            return (entry.name != "__init__.py", entry.name)
679
680        config = self.config
681        col: Optional[nodes.Collector]
682        cols: Sequence[nodes.Collector]
683        ihook = self.ihook
684        for direntry in scandir(self.path, sort_key):
685            if direntry.is_dir():
686                path = Path(direntry.path)
687                if not self.session.isinitpath(path, with_parents=True):
688                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
689                        continue
690                col = ihook.pytest_collect_directory(path=path, parent=self)
691                if col is not None:
692                    yield col
693
694            elif direntry.is_file():
695                path = Path(direntry.path)
696                if not self.session.isinitpath(path):
697                    if ihook.pytest_ignore_collect(collection_path=path, config=config):
698                        continue
699                cols = ihook.pytest_collect_file(file_path=path, parent=self)
700                yield from cols

Collect children (items and collectors) for this collector.

Inherited Members
_pytest.nodes.FSCollector
path
from_parent
Collector
CollectError
repr_failure
_pytest.nodes.Node
fspath
name
parent
keywords
own_markers
extra_keyword_matches
stash
ihook
warn
nodeid
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
def param( *values: object, marks: Union[MarkDecorator, Collection[Union[MarkDecorator, Mark]]] = (), id: Optional[str] = None) -> _pytest.mark.structures.ParameterSet:
46def param(
47    *values: object,
48    marks: Union[MarkDecorator, Collection[Union[MarkDecorator, Mark]]] = (),
49    id: Optional[str] = None,
50) -> ParameterSet:
51    """Specify a parameter in `pytest.mark.parametrize`_ calls or
52    :ref:`parametrized fixtures <fixture-parametrize-marks>`.
53
54    .. code-block:: python
55
56        @pytest.mark.parametrize(
57            "test_input,expected",
58            [
59                ("3+5", 8),
60                pytest.param("6*9", 42, marks=pytest.mark.xfail),
61            ],
62        )
63        def test_eval(test_input, expected):
64            assert eval(test_input) == expected
65
66    :param values: Variable args of the values of the parameter set, in order.
67    :param marks: A single mark or a list of marks to be applied to this parameter set.
68    :param id: The id to attribute to this parameter set.
69    """
70    return ParameterSet.param(*values, marks=marks, id=id)

Specify a parameter in pytest.mark.parametrize_ calls or :ref:parametrized fixtures <fixture-parametrize-marks>.

@pytest.mark.parametrize(
    "test_input,expected",
    [
        ("3+5", 8),
        pytest.param("6*9", 42, marks=pytest.mark.xfail),
    ],
)
def test_eval(test_input, expected):
    assert eval(test_input) == expected
Parameters
  • values: Variable args of the values of the parameter set, in order.
  • marks: A single mark or a list of marks to be applied to this parameter set.
  • id: The id to attribute to this parameter set.
@final
class Parser:
 37@final
 38class Parser:
 39    """Parser for command line arguments and ini-file values.
 40
 41    :ivar extra_info: Dict of generic param -> value to display in case
 42        there's an error processing the command line arguments.
 43    """
 44
 45    prog: Optional[str] = None
 46
 47    def __init__(
 48        self,
 49        usage: Optional[str] = None,
 50        processopt: Optional[Callable[["Argument"], None]] = None,
 51        *,
 52        _ispytest: bool = False,
 53    ) -> None:
 54        check_ispytest(_ispytest)
 55        self._anonymous = OptionGroup("Custom options", parser=self, _ispytest=True)
 56        self._groups: List[OptionGroup] = []
 57        self._processopt = processopt
 58        self._usage = usage
 59        self._inidict: Dict[str, Tuple[str, Optional[str], Any]] = {}
 60        self._ininames: List[str] = []
 61        self.extra_info: Dict[str, Any] = {}
 62
 63    def processoption(self, option: "Argument") -> None:
 64        if self._processopt:
 65            if option.dest:
 66                self._processopt(option)
 67
 68    def getgroup(
 69        self, name: str, description: str = "", after: Optional[str] = None
 70    ) -> "OptionGroup":
 71        """Get (or create) a named option Group.
 72
 73        :param name: Name of the option group.
 74        :param description: Long description for --help output.
 75        :param after: Name of another group, used for ordering --help output.
 76        :returns: The option group.
 77
 78        The returned group object has an ``addoption`` method with the same
 79        signature as :func:`parser.addoption <pytest.Parser.addoption>` but
 80        will be shown in the respective group in the output of
 81        ``pytest --help``.
 82        """
 83        for group in self._groups:
 84            if group.name == name:
 85                return group
 86        group = OptionGroup(name, description, parser=self, _ispytest=True)
 87        i = 0
 88        for i, grp in enumerate(self._groups):
 89            if grp.name == after:
 90                break
 91        self._groups.insert(i + 1, group)
 92        return group
 93
 94    def addoption(self, *opts: str, **attrs: Any) -> None:
 95        """Register a command line option.
 96
 97        :param opts:
 98            Option names, can be short or long options.
 99        :param attrs:
100            Same attributes as the argparse library's :meth:`add_argument()
101            <argparse.ArgumentParser.add_argument>` function accepts.
102
103        After command line parsing, options are available on the pytest config
104        object via ``config.option.NAME`` where ``NAME`` is usually set
105        by passing a ``dest`` attribute, for example
106        ``addoption("--long", dest="NAME", ...)``.
107        """
108        self._anonymous.addoption(*opts, **attrs)
109
110    def parse(
111        self,
112        args: Sequence[Union[str, "os.PathLike[str]"]],
113        namespace: Optional[argparse.Namespace] = None,
114    ) -> argparse.Namespace:
115        from _pytest._argcomplete import try_argcomplete
116
117        self.optparser = self._getparser()
118        try_argcomplete(self.optparser)
119        strargs = [os.fspath(x) for x in args]
120        return self.optparser.parse_args(strargs, namespace=namespace)
121
122    def _getparser(self) -> "MyOptionParser":
123        from _pytest._argcomplete import filescompleter
124
125        optparser = MyOptionParser(self, self.extra_info, prog=self.prog)
126        groups = [*self._groups, self._anonymous]
127        for group in groups:
128            if group.options:
129                desc = group.description or group.name
130                arggroup = optparser.add_argument_group(desc)
131                for option in group.options:
132                    n = option.names()
133                    a = option.attrs()
134                    arggroup.add_argument(*n, **a)
135        file_or_dir_arg = optparser.add_argument(FILE_OR_DIR, nargs="*")
136        # bash like autocompletion for dirs (appending '/')
137        # Type ignored because typeshed doesn't know about argcomplete.
138        file_or_dir_arg.completer = filescompleter  # type: ignore
139        return optparser
140
141    def parse_setoption(
142        self,
143        args: Sequence[Union[str, "os.PathLike[str]"]],
144        option: argparse.Namespace,
145        namespace: Optional[argparse.Namespace] = None,
146    ) -> List[str]:
147        parsedoption = self.parse(args, namespace=namespace)
148        for name, value in parsedoption.__dict__.items():
149            setattr(option, name, value)
150        return cast(List[str], getattr(parsedoption, FILE_OR_DIR))
151
152    def parse_known_args(
153        self,
154        args: Sequence[Union[str, "os.PathLike[str]"]],
155        namespace: Optional[argparse.Namespace] = None,
156    ) -> argparse.Namespace:
157        """Parse the known arguments at this point.
158
159        :returns: An argparse namespace object.
160        """
161        return self.parse_known_and_unknown_args(args, namespace=namespace)[0]
162
163    def parse_known_and_unknown_args(
164        self,
165        args: Sequence[Union[str, "os.PathLike[str]"]],
166        namespace: Optional[argparse.Namespace] = None,
167    ) -> Tuple[argparse.Namespace, List[str]]:
168        """Parse the known arguments at this point, and also return the
169        remaining unknown arguments.
170
171        :returns:
172            A tuple containing an argparse namespace object for the known
173            arguments, and a list of the unknown arguments.
174        """
175        optparser = self._getparser()
176        strargs = [os.fspath(x) for x in args]
177        return optparser.parse_known_args(strargs, namespace=namespace)
178
179    def addini(
180        self,
181        name: str,
182        help: str,
183        type: Optional[
184            Literal["string", "paths", "pathlist", "args", "linelist", "bool"]
185        ] = None,
186        default: Any = NOT_SET,
187    ) -> None:
188        """Register an ini-file option.
189
190        :param name:
191            Name of the ini-variable.
192        :param type:
193            Type of the variable. Can be:
194
195                * ``string``: a string
196                * ``bool``: a boolean
197                * ``args``: a list of strings, separated as in a shell
198                * ``linelist``: a list of strings, separated by line breaks
199                * ``paths``: a list of :class:`pathlib.Path`, separated as in a shell
200                * ``pathlist``: a list of ``py.path``, separated as in a shell
201
202            For ``paths`` and ``pathlist`` types, they are considered relative to the ini-file.
203            In case the execution is happening without an ini-file defined,
204            they will be considered relative to the current working directory (for example with ``--override-ini``).
205
206            .. versionadded:: 7.0
207                The ``paths`` variable type.
208
209            .. versionadded:: 8.1
210                Use the current working directory to resolve ``paths`` and ``pathlist`` in the absence of an ini-file.
211
212            Defaults to ``string`` if ``None`` or not passed.
213        :param default:
214            Default value if no ini-file option exists but is queried.
215
216        The value of ini-variables can be retrieved via a call to
217        :py:func:`config.getini(name) <pytest.Config.getini>`.
218        """
219        assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool")
220        if default is NOT_SET:
221            default = get_ini_default_for_type(type)
222
223        self._inidict[name] = (help, type, default)
224        self._ininames.append(name)

Parser for command line arguments and ini-file values.

:ivar extra_info: Dict of generic param -> value to display in case there's an error processing the command line arguments.

Parser( usage: Optional[str] = None, processopt: Optional[Callable[[_pytest.config.argparsing.Argument], NoneType]] = None, *, _ispytest: bool = False)
47    def __init__(
48        self,
49        usage: Optional[str] = None,
50        processopt: Optional[Callable[["Argument"], None]] = None,
51        *,
52        _ispytest: bool = False,
53    ) -> None:
54        check_ispytest(_ispytest)
55        self._anonymous = OptionGroup("Custom options", parser=self, _ispytest=True)
56        self._groups: List[OptionGroup] = []
57        self._processopt = processopt
58        self._usage = usage
59        self._inidict: Dict[str, Tuple[str, Optional[str], Any]] = {}
60        self._ininames: List[str] = []
61        self.extra_info: Dict[str, Any] = {}
prog: Optional[str] = None
extra_info: Dict[str, Any]
def processoption(self, option: _pytest.config.argparsing.Argument) -> None:
63    def processoption(self, option: "Argument") -> None:
64        if self._processopt:
65            if option.dest:
66                self._processopt(option)
def getgroup( self, name: str, description: str = '', after: Optional[str] = None) -> OptionGroup:
68    def getgroup(
69        self, name: str, description: str = "", after: Optional[str] = None
70    ) -> "OptionGroup":
71        """Get (or create) a named option Group.
72
73        :param name: Name of the option group.
74        :param description: Long description for --help output.
75        :param after: Name of another group, used for ordering --help output.
76        :returns: The option group.
77
78        The returned group object has an ``addoption`` method with the same
79        signature as :func:`parser.addoption <pytest.Parser.addoption>` but
80        will be shown in the respective group in the output of
81        ``pytest --help``.
82        """
83        for group in self._groups:
84            if group.name == name:
85                return group
86        group = OptionGroup(name, description, parser=self, _ispytest=True)
87        i = 0
88        for i, grp in enumerate(self._groups):
89            if grp.name == after:
90                break
91        self._groups.insert(i + 1, group)
92        return group

Get (or create) a named option Group.

Parameters
  • name: Name of the option group.
  • description: Long description for --help output.
  • after: Name of another group, used for ordering --help output. :returns: The option group.

The returned group object has an addoption method with the same signature as parser.addoption <pytest.Parser.addoption>() but will be shown in the respective group in the output of pytest --help.

def addoption(self, *opts: str, **attrs: Any) -> None:
 94    def addoption(self, *opts: str, **attrs: Any) -> None:
 95        """Register a command line option.
 96
 97        :param opts:
 98            Option names, can be short or long options.
 99        :param attrs:
100            Same attributes as the argparse library's :meth:`add_argument()
101            <argparse.ArgumentParser.add_argument>` function accepts.
102
103        After command line parsing, options are available on the pytest config
104        object via ``config.option.NAME`` where ``NAME`` is usually set
105        by passing a ``dest`` attribute, for example
106        ``addoption("--long", dest="NAME", ...)``.
107        """
108        self._anonymous.addoption(*opts, **attrs)

Register a command line option.

Parameters
  • opts: Option names, can be short or long options.
  • attrs: Same attributes as the argparse library's add_argument() <argparse.ArgumentParser.add_argument>() function accepts.

After command line parsing, options are available on the pytest config object via config.option.NAME where NAME is usually set by passing a dest attribute, for example addoption("--long", dest="NAME", ...).

def parse( self, args: Sequence[Union[str, os.PathLike[str]]], namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace:
110    def parse(
111        self,
112        args: Sequence[Union[str, "os.PathLike[str]"]],
113        namespace: Optional[argparse.Namespace] = None,
114    ) -> argparse.Namespace:
115        from _pytest._argcomplete import try_argcomplete
116
117        self.optparser = self._getparser()
118        try_argcomplete(self.optparser)
119        strargs = [os.fspath(x) for x in args]
120        return self.optparser.parse_args(strargs, namespace=namespace)
def parse_setoption( self, args: Sequence[Union[str, os.PathLike[str]]], option: argparse.Namespace, namespace: Optional[argparse.Namespace] = None) -> List[str]:
141    def parse_setoption(
142        self,
143        args: Sequence[Union[str, "os.PathLike[str]"]],
144        option: argparse.Namespace,
145        namespace: Optional[argparse.Namespace] = None,
146    ) -> List[str]:
147        parsedoption = self.parse(args, namespace=namespace)
148        for name, value in parsedoption.__dict__.items():
149            setattr(option, name, value)
150        return cast(List[str], getattr(parsedoption, FILE_OR_DIR))
def parse_known_args( self, args: Sequence[Union[str, os.PathLike[str]]], namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace:
152    def parse_known_args(
153        self,
154        args: Sequence[Union[str, "os.PathLike[str]"]],
155        namespace: Optional[argparse.Namespace] = None,
156    ) -> argparse.Namespace:
157        """Parse the known arguments at this point.
158
159        :returns: An argparse namespace object.
160        """
161        return self.parse_known_and_unknown_args(args, namespace=namespace)[0]

Parse the known arguments at this point.

:returns: An argparse namespace object.

def parse_known_and_unknown_args( self, args: Sequence[Union[str, os.PathLike[str]]], namespace: Optional[argparse.Namespace] = None) -> Tuple[argparse.Namespace, List[str]]:
163    def parse_known_and_unknown_args(
164        self,
165        args: Sequence[Union[str, "os.PathLike[str]"]],
166        namespace: Optional[argparse.Namespace] = None,
167    ) -> Tuple[argparse.Namespace, List[str]]:
168        """Parse the known arguments at this point, and also return the
169        remaining unknown arguments.
170
171        :returns:
172            A tuple containing an argparse namespace object for the known
173            arguments, and a list of the unknown arguments.
174        """
175        optparser = self._getparser()
176        strargs = [os.fspath(x) for x in args]
177        return optparser.parse_known_args(strargs, namespace=namespace)

Parse the known arguments at this point, and also return the remaining unknown arguments.

:returns: A tuple containing an argparse namespace object for the known arguments, and a list of the unknown arguments.

def addini( self, name: str, help: str, type: Optional[Literal['string', 'paths', 'pathlist', 'args', 'linelist', 'bool']] = None, default: Any = <notset>) -> None:
179    def addini(
180        self,
181        name: str,
182        help: str,
183        type: Optional[
184            Literal["string", "paths", "pathlist", "args", "linelist", "bool"]
185        ] = None,
186        default: Any = NOT_SET,
187    ) -> None:
188        """Register an ini-file option.
189
190        :param name:
191            Name of the ini-variable.
192        :param type:
193            Type of the variable. Can be:
194
195                * ``string``: a string
196                * ``bool``: a boolean
197                * ``args``: a list of strings, separated as in a shell
198                * ``linelist``: a list of strings, separated by line breaks
199                * ``paths``: a list of :class:`pathlib.Path`, separated as in a shell
200                * ``pathlist``: a list of ``py.path``, separated as in a shell
201
202            For ``paths`` and ``pathlist`` types, they are considered relative to the ini-file.
203            In case the execution is happening without an ini-file defined,
204            they will be considered relative to the current working directory (for example with ``--override-ini``).
205
206            .. versionadded:: 7.0
207                The ``paths`` variable type.
208
209            .. versionadded:: 8.1
210                Use the current working directory to resolve ``paths`` and ``pathlist`` in the absence of an ini-file.
211
212            Defaults to ``string`` if ``None`` or not passed.
213        :param default:
214            Default value if no ini-file option exists but is queried.
215
216        The value of ini-variables can be retrieved via a call to
217        :py:func:`config.getini(name) <pytest.Config.getini>`.
218        """
219        assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool")
220        if default is NOT_SET:
221            default = get_ini_default_for_type(type)
222
223        self._inidict[name] = (help, type, default)
224        self._ininames.append(name)

Register an ini-file option.

Parameters
  • name: Name of the ini-variable.
  • type: Type of the variable. Can be:

    * ``string``: a string
    * ``bool``: a boolean
    * ``args``: a list of strings, separated as in a shell
    * ``linelist``: a list of strings, separated by line breaks
    * ``paths``: a list of `pathlib.Path`, separated as in a shell
    * ``pathlist``: a list of ``py.path``, separated as in a shell
    

    For paths and pathlist types, they are considered relative to the ini-file. In case the execution is happening without an ini-file defined, they will be considered relative to the current working directory (for example with --override-ini).

    New in version 7.0: The paths variable type.

    New in version 8.1: Use the current working directory to resolve paths and pathlist in the absence of an ini-file.

    Defaults to string if None or not passed.

  • default: Default value if no ini-file option exists but is queried.

The value of ini-variables can be retrieved via a call to config.getini(name) <pytest.Config.getini>().

class PytestAssertRewriteWarning(PytestWarning):

Warning emitted by the pytest assert rewrite module.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestCacheWarning(PytestWarning):

Warning emitted by the cache plugin in various situations.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestCollectionWarning(PytestWarning):

Warning emitted when pytest is not able to collect a file or symbol in a module.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestConfigWarning(PytestWarning):

Warning emitted for configuration issues.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestDeprecationWarning(PytestWarning, builtins.DeprecationWarning):

Warning class for features that will be removed in a future version.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestExperimentalApiWarning(PytestWarning, builtins.FutureWarning):

Warning category used to denote experiments in pytest.

Use sparingly as the API might change or even be removed completely in a future version.

@classmethod
def simple(cls, apiname: str) -> PytestExperimentalApiWarning:
75    @classmethod
76    def simple(cls, apiname: str) -> "PytestExperimentalApiWarning":
77        return cls(f"{apiname} is an experimental api that may change over time")
Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestRemovedIn9Warning(PytestDeprecationWarning):

Warning class for features that will be removed in pytest 9.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestReturnNotNoneWarning(PytestWarning):

Warning emitted when a test function is returning value other than None.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
@final
class Pytester:
 650@final
 651class Pytester:
 652    """
 653    Facilities to write tests/configuration files, execute pytest in isolation, and match
 654    against expected output, perfect for black-box testing of pytest plugins.
 655
 656    It attempts to isolate the test run from external factors as much as possible, modifying
 657    the current working directory to :attr:`path` and environment variables during initialization.
 658    """
 659
 660    __test__ = False
 661
 662    CLOSE_STDIN: "Final" = NOTSET
 663
 664    class TimeoutExpired(Exception):
 665        pass
 666
 667    def __init__(
 668        self,
 669        request: FixtureRequest,
 670        tmp_path_factory: TempPathFactory,
 671        monkeypatch: MonkeyPatch,
 672        *,
 673        _ispytest: bool = False,
 674    ) -> None:
 675        check_ispytest(_ispytest)
 676        self._request = request
 677        self._mod_collections: WeakKeyDictionary[
 678            Collector, List[Union[Item, Collector]]
 679        ] = WeakKeyDictionary()
 680        if request.function:
 681            name: str = request.function.__name__
 682        else:
 683            name = request.node.name
 684        self._name = name
 685        self._path: Path = tmp_path_factory.mktemp(name, numbered=True)
 686        #: A list of plugins to use with :py:meth:`parseconfig` and
 687        #: :py:meth:`runpytest`.  Initially this is an empty list but plugins can
 688        #: be added to the list.  The type of items to add to the list depends on
 689        #: the method using them so refer to them for details.
 690        self.plugins: List[Union[str, _PluggyPlugin]] = []
 691        self._sys_path_snapshot = SysPathsSnapshot()
 692        self._sys_modules_snapshot = self.__take_sys_modules_snapshot()
 693        self._request.addfinalizer(self._finalize)
 694        self._method = self._request.config.getoption("--runpytest")
 695        self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True)
 696
 697        self._monkeypatch = mp = monkeypatch
 698        self.chdir()
 699        mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot))
 700        # Ensure no unexpected caching via tox.
 701        mp.delenv("TOX_ENV_DIR", raising=False)
 702        # Discard outer pytest options.
 703        mp.delenv("PYTEST_ADDOPTS", raising=False)
 704        # Ensure no user config is used.
 705        tmphome = str(self.path)
 706        mp.setenv("HOME", tmphome)
 707        mp.setenv("USERPROFILE", tmphome)
 708        # Do not use colors for inner runs by default.
 709        mp.setenv("PY_COLORS", "0")
 710
 711    @property
 712    def path(self) -> Path:
 713        """Temporary directory path used to create files/run tests from, etc."""
 714        return self._path
 715
 716    def __repr__(self) -> str:
 717        return f"<Pytester {self.path!r}>"
 718
 719    def _finalize(self) -> None:
 720        """
 721        Clean up global state artifacts.
 722
 723        Some methods modify the global interpreter state and this tries to
 724        clean this up. It does not remove the temporary directory however so
 725        it can be looked at after the test run has finished.
 726        """
 727        self._sys_modules_snapshot.restore()
 728        self._sys_path_snapshot.restore()
 729
 730    def __take_sys_modules_snapshot(self) -> SysModulesSnapshot:
 731        # Some zope modules used by twisted-related tests keep internal state
 732        # and can't be deleted; we had some trouble in the past with
 733        # `zope.interface` for example.
 734        #
 735        # Preserve readline due to https://bugs.python.org/issue41033.
 736        # pexpect issues a SIGWINCH.
 737        def preserve_module(name):
 738            return name.startswith(("zope", "readline"))
 739
 740        return SysModulesSnapshot(preserve=preserve_module)
 741
 742    def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder:
 743        """Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`."""
 744        pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True)  # type: ignore[attr-defined]
 745        self._request.addfinalizer(reprec.finish_recording)
 746        return reprec
 747
 748    def chdir(self) -> None:
 749        """Cd into the temporary directory.
 750
 751        This is done automatically upon instantiation.
 752        """
 753        self._monkeypatch.chdir(self.path)
 754
 755    def _makefile(
 756        self,
 757        ext: str,
 758        lines: Sequence[Union[Any, bytes]],
 759        files: Dict[str, str],
 760        encoding: str = "utf-8",
 761    ) -> Path:
 762        items = list(files.items())
 763
 764        if ext and not ext.startswith("."):
 765            raise ValueError(
 766                f"pytester.makefile expects a file extension, try .{ext} instead of {ext}"
 767            )
 768
 769        def to_text(s: Union[Any, bytes]) -> str:
 770            return s.decode(encoding) if isinstance(s, bytes) else str(s)
 771
 772        if lines:
 773            source = "\n".join(to_text(x) for x in lines)
 774            basename = self._name
 775            items.insert(0, (basename, source))
 776
 777        ret = None
 778        for basename, value in items:
 779            p = self.path.joinpath(basename).with_suffix(ext)
 780            p.parent.mkdir(parents=True, exist_ok=True)
 781            source_ = Source(value)
 782            source = "\n".join(to_text(line) for line in source_.lines)
 783            p.write_text(source.strip(), encoding=encoding)
 784            if ret is None:
 785                ret = p
 786        assert ret is not None
 787        return ret
 788
 789    def makefile(self, ext: str, *args: str, **kwargs: str) -> Path:
 790        r"""Create new text file(s) in the test directory.
 791
 792        :param ext:
 793            The extension the file(s) should use, including the dot, e.g. `.py`.
 794        :param args:
 795            All args are treated as strings and joined using newlines.
 796            The result is written as contents to the file.  The name of the
 797            file is based on the test function requesting this fixture.
 798        :param kwargs:
 799            Each keyword is the name of a file, while the value of it will
 800            be written as contents of the file.
 801        :returns:
 802            The first created file.
 803
 804        Examples:
 805        .. code-block:: python
 806
 807            pytester.makefile(".txt", "line1", "line2")
 808
 809            pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n")
 810
 811        To create binary files, use :meth:`pathlib.Path.write_bytes` directly:
 812
 813        .. code-block:: python
 814
 815            filename = pytester.path.joinpath("foo.bin")
 816            filename.write_bytes(b"...")
 817        """
 818        return self._makefile(ext, args, kwargs)
 819
 820    def makeconftest(self, source: str) -> Path:
 821        """Write a conftest.py file.
 822
 823        :param source: The contents.
 824        :returns: The conftest.py file.
 825        """
 826        return self.makepyfile(conftest=source)
 827
 828    def makeini(self, source: str) -> Path:
 829        """Write a tox.ini file.
 830
 831        :param source: The contents.
 832        :returns: The tox.ini file.
 833        """
 834        return self.makefile(".ini", tox=source)
 835
 836    def getinicfg(self, source: str) -> SectionWrapper:
 837        """Return the pytest section from the tox.ini config file."""
 838        p = self.makeini(source)
 839        return IniConfig(str(p))["pytest"]
 840
 841    def makepyprojecttoml(self, source: str) -> Path:
 842        """Write a pyproject.toml file.
 843
 844        :param source: The contents.
 845        :returns: The pyproject.ini file.
 846
 847        .. versionadded:: 6.0
 848        """
 849        return self.makefile(".toml", pyproject=source)
 850
 851    def makepyfile(self, *args, **kwargs) -> Path:
 852        r"""Shortcut for .makefile() with a .py extension.
 853
 854        Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting
 855        existing files.
 856
 857        Examples:
 858        .. code-block:: python
 859
 860            def test_something(pytester):
 861                # Initial file is created test_something.py.
 862                pytester.makepyfile("foobar")
 863                # To create multiple files, pass kwargs accordingly.
 864                pytester.makepyfile(custom="foobar")
 865                # At this point, both 'test_something.py' & 'custom.py' exist in the test directory.
 866
 867        """
 868        return self._makefile(".py", args, kwargs)
 869
 870    def maketxtfile(self, *args, **kwargs) -> Path:
 871        r"""Shortcut for .makefile() with a .txt extension.
 872
 873        Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting
 874        existing files.
 875
 876        Examples:
 877        .. code-block:: python
 878
 879            def test_something(pytester):
 880                # Initial file is created test_something.txt.
 881                pytester.maketxtfile("foobar")
 882                # To create multiple files, pass kwargs accordingly.
 883                pytester.maketxtfile(custom="foobar")
 884                # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory.
 885
 886        """
 887        return self._makefile(".txt", args, kwargs)
 888
 889    def syspathinsert(
 890        self, path: Optional[Union[str, "os.PathLike[str]"]] = None
 891    ) -> None:
 892        """Prepend a directory to sys.path, defaults to :attr:`path`.
 893
 894        This is undone automatically when this object dies at the end of each
 895        test.
 896
 897        :param path:
 898            The path.
 899        """
 900        if path is None:
 901            path = self.path
 902
 903        self._monkeypatch.syspath_prepend(str(path))
 904
 905    def mkdir(self, name: Union[str, "os.PathLike[str]"]) -> Path:
 906        """Create a new (sub)directory.
 907
 908        :param name:
 909            The name of the directory, relative to the pytester path.
 910        :returns:
 911            The created directory.
 912        """
 913        p = self.path / name
 914        p.mkdir()
 915        return p
 916
 917    def mkpydir(self, name: Union[str, "os.PathLike[str]"]) -> Path:
 918        """Create a new python package.
 919
 920        This creates a (sub)directory with an empty ``__init__.py`` file so it
 921        gets recognised as a Python package.
 922        """
 923        p = self.path / name
 924        p.mkdir()
 925        p.joinpath("__init__.py").touch()
 926        return p
 927
 928    def copy_example(self, name: Optional[str] = None) -> Path:
 929        """Copy file from project's directory into the testdir.
 930
 931        :param name:
 932            The name of the file to copy.
 933        :return:
 934            Path to the copied directory (inside ``self.path``).
 935        """
 936        example_dir_ = self._request.config.getini("pytester_example_dir")
 937        if example_dir_ is None:
 938            raise ValueError("pytester_example_dir is unset, can't copy examples")
 939        example_dir: Path = self._request.config.rootpath / example_dir_
 940
 941        for extra_element in self._request.node.iter_markers("pytester_example_path"):
 942            assert extra_element.args
 943            example_dir = example_dir.joinpath(*extra_element.args)
 944
 945        if name is None:
 946            func_name = self._name
 947            maybe_dir = example_dir / func_name
 948            maybe_file = example_dir / (func_name + ".py")
 949
 950            if maybe_dir.is_dir():
 951                example_path = maybe_dir
 952            elif maybe_file.is_file():
 953                example_path = maybe_file
 954            else:
 955                raise LookupError(
 956                    f"{func_name} can't be found as module or package in {example_dir}"
 957                )
 958        else:
 959            example_path = example_dir.joinpath(name)
 960
 961        if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
 962            shutil.copytree(example_path, self.path, symlinks=True, dirs_exist_ok=True)
 963            return self.path
 964        elif example_path.is_file():
 965            result = self.path.joinpath(example_path.name)
 966            shutil.copy(example_path, result)
 967            return result
 968        else:
 969            raise LookupError(
 970                f'example "{example_path}" is not found as a file or directory'
 971            )
 972
 973    def getnode(
 974        self, config: Config, arg: Union[str, "os.PathLike[str]"]
 975    ) -> Union[Collector, Item]:
 976        """Get the collection node of a file.
 977
 978        :param config:
 979           A pytest config.
 980           See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it.
 981        :param arg:
 982            Path to the file.
 983        :returns:
 984            The node.
 985        """
 986        session = Session.from_config(config)
 987        assert "::" not in str(arg)
 988        p = Path(os.path.abspath(arg))
 989        config.hook.pytest_sessionstart(session=session)
 990        res = session.perform_collect([str(p)], genitems=False)[0]
 991        config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
 992        return res
 993
 994    def getpathnode(
 995        self, path: Union[str, "os.PathLike[str]"]
 996    ) -> Union[Collector, Item]:
 997        """Return the collection node of a file.
 998
 999        This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to
1000        create the (configured) pytest Config instance.
1001
1002        :param path:
1003            Path to the file.
1004        :returns:
1005            The node.
1006        """
1007        path = Path(path)
1008        config = self.parseconfigure(path)
1009        session = Session.from_config(config)
1010        x = bestrelpath(session.path, path)
1011        config.hook.pytest_sessionstart(session=session)
1012        res = session.perform_collect([x], genitems=False)[0]
1013        config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
1014        return res
1015
1016    def genitems(self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]:
1017        """Generate all test items from a collection node.
1018
1019        This recurses into the collection node and returns a list of all the
1020        test items contained within.
1021
1022        :param colitems:
1023            The collection nodes.
1024        :returns:
1025            The collected items.
1026        """
1027        session = colitems[0].session
1028        result: List[Item] = []
1029        for colitem in colitems:
1030            result.extend(session.genitems(colitem))
1031        return result
1032
1033    def runitem(self, source: str) -> Any:
1034        """Run the "test_func" Item.
1035
1036        The calling test instance (class containing the test method) must
1037        provide a ``.getrunner()`` method which should return a runner which
1038        can run the test protocol for a single item, e.g.
1039        ``_pytest.runner.runtestprotocol``.
1040        """
1041        # used from runner functional tests
1042        item = self.getitem(source)
1043        # the test class where we are called from wants to provide the runner
1044        testclassinstance = self._request.instance
1045        runner = testclassinstance.getrunner()
1046        return runner(item)
1047
1048    def inline_runsource(self, source: str, *cmdlineargs) -> HookRecorder:
1049        """Run a test module in process using ``pytest.main()``.
1050
1051        This run writes "source" into a temporary file and runs
1052        ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance
1053        for the result.
1054
1055        :param source: The source code of the test module.
1056        :param cmdlineargs: Any extra command line arguments to use.
1057        """
1058        p = self.makepyfile(source)
1059        values = [*list(cmdlineargs), p]
1060        return self.inline_run(*values)
1061
1062    def inline_genitems(self, *args) -> Tuple[List[Item], HookRecorder]:
1063        """Run ``pytest.main(['--collect-only'])`` in-process.
1064
1065        Runs the :py:func:`pytest.main` function to run all of pytest inside
1066        the test process itself like :py:meth:`inline_run`, but returns a
1067        tuple of the collected items and a :py:class:`HookRecorder` instance.
1068        """
1069        rec = self.inline_run("--collect-only", *args)
1070        items = [x.item for x in rec.getcalls("pytest_itemcollected")]
1071        return items, rec
1072
1073    def inline_run(
1074        self,
1075        *args: Union[str, "os.PathLike[str]"],
1076        plugins=(),
1077        no_reraise_ctrlc: bool = False,
1078    ) -> HookRecorder:
1079        """Run ``pytest.main()`` in-process, returning a HookRecorder.
1080
1081        Runs the :py:func:`pytest.main` function to run all of pytest inside
1082        the test process itself.  This means it can return a
1083        :py:class:`HookRecorder` instance which gives more detailed results
1084        from that run than can be done by matching stdout/stderr from
1085        :py:meth:`runpytest`.
1086
1087        :param args:
1088            Command line arguments to pass to :py:func:`pytest.main`.
1089        :param plugins:
1090            Extra plugin instances the ``pytest.main()`` instance should use.
1091        :param no_reraise_ctrlc:
1092            Typically we reraise keyboard interrupts from the child run. If
1093            True, the KeyboardInterrupt exception is captured.
1094        """
1095        # (maybe a cpython bug?) the importlib cache sometimes isn't updated
1096        # properly between file creation and inline_run (especially if imports
1097        # are interspersed with file creation)
1098        importlib.invalidate_caches()
1099
1100        plugins = list(plugins)
1101        finalizers = []
1102        try:
1103            # Any sys.module or sys.path changes done while running pytest
1104            # inline should be reverted after the test run completes to avoid
1105            # clashing with later inline tests run within the same pytest test,
1106            # e.g. just because they use matching test module names.
1107            finalizers.append(self.__take_sys_modules_snapshot().restore)
1108            finalizers.append(SysPathsSnapshot().restore)
1109
1110            # Important note:
1111            # - our tests should not leave any other references/registrations
1112            #   laying around other than possibly loaded test modules
1113            #   referenced from sys.modules, as nothing will clean those up
1114            #   automatically
1115
1116            rec = []
1117
1118            class Collect:
1119                def pytest_configure(x, config: Config) -> None:
1120                    rec.append(self.make_hook_recorder(config.pluginmanager))
1121
1122            plugins.append(Collect())
1123            ret = main([str(x) for x in args], plugins=plugins)
1124            if len(rec) == 1:
1125                reprec = rec.pop()
1126            else:
1127
1128                class reprec:  # type: ignore
1129                    pass
1130
1131            reprec.ret = ret
1132
1133            # Typically we reraise keyboard interrupts from the child run
1134            # because it's our user requesting interruption of the testing.
1135            if ret == ExitCode.INTERRUPTED and not no_reraise_ctrlc:
1136                calls = reprec.getcalls("pytest_keyboard_interrupt")
1137                if calls and calls[-1].excinfo.type == KeyboardInterrupt:
1138                    raise KeyboardInterrupt()
1139            return reprec
1140        finally:
1141            for finalizer in finalizers:
1142                finalizer()
1143
1144    def runpytest_inprocess(
1145        self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any
1146    ) -> RunResult:
1147        """Return result of running pytest in-process, providing a similar
1148        interface to what self.runpytest() provides."""
1149        syspathinsert = kwargs.pop("syspathinsert", False)
1150
1151        if syspathinsert:
1152            self.syspathinsert()
1153        now = timing.time()
1154        capture = _get_multicapture("sys")
1155        capture.start_capturing()
1156        try:
1157            try:
1158                reprec = self.inline_run(*args, **kwargs)
1159            except SystemExit as e:
1160                ret = e.args[0]
1161                try:
1162                    ret = ExitCode(e.args[0])
1163                except ValueError:
1164                    pass
1165
1166                class reprec:  # type: ignore
1167                    ret = ret
1168
1169            except Exception:
1170                traceback.print_exc()
1171
1172                class reprec:  # type: ignore
1173                    ret = ExitCode(3)
1174
1175        finally:
1176            out, err = capture.readouterr()
1177            capture.stop_capturing()
1178            sys.stdout.write(out)
1179            sys.stderr.write(err)
1180
1181        assert reprec.ret is not None
1182        res = RunResult(
1183            reprec.ret, out.splitlines(), err.splitlines(), timing.time() - now
1184        )
1185        res.reprec = reprec  # type: ignore
1186        return res
1187
1188    def runpytest(
1189        self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any
1190    ) -> RunResult:
1191        """Run pytest inline or in a subprocess, depending on the command line
1192        option "--runpytest" and return a :py:class:`~pytest.RunResult`."""
1193        new_args = self._ensure_basetemp(args)
1194        if self._method == "inprocess":
1195            return self.runpytest_inprocess(*new_args, **kwargs)
1196        elif self._method == "subprocess":
1197            return self.runpytest_subprocess(*new_args, **kwargs)
1198        raise RuntimeError(f"Unrecognized runpytest option: {self._method}")
1199
1200    def _ensure_basetemp(
1201        self, args: Sequence[Union[str, "os.PathLike[str]"]]
1202    ) -> List[Union[str, "os.PathLike[str]"]]:
1203        new_args = list(args)
1204        for x in new_args:
1205            if str(x).startswith("--basetemp"):
1206                break
1207        else:
1208            new_args.append("--basetemp=%s" % self.path.parent.joinpath("basetemp"))
1209        return new_args
1210
1211    def parseconfig(self, *args: Union[str, "os.PathLike[str]"]) -> Config:
1212        """Return a new pytest :class:`pytest.Config` instance from given
1213        commandline args.
1214
1215        This invokes the pytest bootstrapping code in _pytest.config to create a
1216        new :py:class:`pytest.PytestPluginManager` and call the
1217        :hook:`pytest_cmdline_parse` hook to create a new :class:`pytest.Config`
1218        instance.
1219
1220        If :attr:`plugins` has been populated they should be plugin modules
1221        to be registered with the plugin manager.
1222        """
1223        import _pytest.config
1224
1225        new_args = self._ensure_basetemp(args)
1226        new_args = [str(x) for x in new_args]
1227
1228        config = _pytest.config._prepareconfig(new_args, self.plugins)  # type: ignore[arg-type]
1229        # we don't know what the test will do with this half-setup config
1230        # object and thus we make sure it gets unconfigured properly in any
1231        # case (otherwise capturing could still be active, for example)
1232        self._request.addfinalizer(config._ensure_unconfigure)
1233        return config
1234
1235    def parseconfigure(self, *args: Union[str, "os.PathLike[str]"]) -> Config:
1236        """Return a new pytest configured Config instance.
1237
1238        Returns a new :py:class:`pytest.Config` instance like
1239        :py:meth:`parseconfig`, but also calls the :hook:`pytest_configure`
1240        hook.
1241        """
1242        config = self.parseconfig(*args)
1243        config._do_configure()
1244        return config
1245
1246    def getitem(
1247        self, source: Union[str, "os.PathLike[str]"], funcname: str = "test_func"
1248    ) -> Item:
1249        """Return the test item for a test function.
1250
1251        Writes the source to a python file and runs pytest's collection on
1252        the resulting module, returning the test item for the requested
1253        function name.
1254
1255        :param source:
1256            The module source.
1257        :param funcname:
1258            The name of the test function for which to return a test item.
1259        :returns:
1260            The test item.
1261        """
1262        items = self.getitems(source)
1263        for item in items:
1264            if item.name == funcname:
1265                return item
1266        assert 0, f"{funcname!r} item not found in module:\n{source}\nitems: {items}"
1267
1268    def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]:
1269        """Return all test items collected from the module.
1270
1271        Writes the source to a Python file and runs pytest's collection on
1272        the resulting module, returning all test items contained within.
1273        """
1274        modcol = self.getmodulecol(source)
1275        return self.genitems([modcol])
1276
1277    def getmodulecol(
1278        self,
1279        source: Union[str, "os.PathLike[str]"],
1280        configargs=(),
1281        *,
1282        withinit: bool = False,
1283    ):
1284        """Return the module collection node for ``source``.
1285
1286        Writes ``source`` to a file using :py:meth:`makepyfile` and then
1287        runs the pytest collection on it, returning the collection node for the
1288        test module.
1289
1290        :param source:
1291            The source code of the module to collect.
1292
1293        :param configargs:
1294            Any extra arguments to pass to :py:meth:`parseconfigure`.
1295
1296        :param withinit:
1297            Whether to also write an ``__init__.py`` file to the same
1298            directory to ensure it is a package.
1299        """
1300        if isinstance(source, os.PathLike):
1301            path = self.path.joinpath(source)
1302            assert not withinit, "not supported for paths"
1303        else:
1304            kw = {self._name: str(source)}
1305            path = self.makepyfile(**kw)
1306        if withinit:
1307            self.makepyfile(__init__="#")
1308        self.config = config = self.parseconfigure(path, *configargs)
1309        return self.getnode(config, path)
1310
1311    def collect_by_name(
1312        self, modcol: Collector, name: str
1313    ) -> Optional[Union[Item, Collector]]:
1314        """Return the collection node for name from the module collection.
1315
1316        Searches a module collection node for a collection node matching the
1317        given name.
1318
1319        :param modcol: A module collection node; see :py:meth:`getmodulecol`.
1320        :param name: The name of the node to return.
1321        """
1322        if modcol not in self._mod_collections:
1323            self._mod_collections[modcol] = list(modcol.collect())
1324        for colitem in self._mod_collections[modcol]:
1325            if colitem.name == name:
1326                return colitem
1327        return None
1328
1329    def popen(
1330        self,
1331        cmdargs: Sequence[Union[str, "os.PathLike[str]"]],
1332        stdout: Union[int, TextIO] = subprocess.PIPE,
1333        stderr: Union[int, TextIO] = subprocess.PIPE,
1334        stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN,
1335        **kw,
1336    ):
1337        """Invoke :py:class:`subprocess.Popen`.
1338
1339        Calls :py:class:`subprocess.Popen` making sure the current working
1340        directory is in ``PYTHONPATH``.
1341
1342        You probably want to use :py:meth:`run` instead.
1343        """
1344        env = os.environ.copy()
1345        env["PYTHONPATH"] = os.pathsep.join(
1346            filter(None, [os.getcwd(), env.get("PYTHONPATH", "")])
1347        )
1348        kw["env"] = env
1349
1350        if stdin is self.CLOSE_STDIN:
1351            kw["stdin"] = subprocess.PIPE
1352        elif isinstance(stdin, bytes):
1353            kw["stdin"] = subprocess.PIPE
1354        else:
1355            kw["stdin"] = stdin
1356
1357        popen = subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw)
1358        if stdin is self.CLOSE_STDIN:
1359            assert popen.stdin is not None
1360            popen.stdin.close()
1361        elif isinstance(stdin, bytes):
1362            assert popen.stdin is not None
1363            popen.stdin.write(stdin)
1364
1365        return popen
1366
1367    def run(
1368        self,
1369        *cmdargs: Union[str, "os.PathLike[str]"],
1370        timeout: Optional[float] = None,
1371        stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN,
1372    ) -> RunResult:
1373        """Run a command with arguments.
1374
1375        Run a process using :py:class:`subprocess.Popen` saving the stdout and
1376        stderr.
1377
1378        :param cmdargs:
1379            The sequence of arguments to pass to :py:class:`subprocess.Popen`,
1380            with path-like objects being converted to :py:class:`str`
1381            automatically.
1382        :param timeout:
1383            The period in seconds after which to timeout and raise
1384            :py:class:`Pytester.TimeoutExpired`.
1385        :param stdin:
1386            Optional standard input.
1387
1388            - If it is ``CLOSE_STDIN`` (Default), then this method calls
1389              :py:class:`subprocess.Popen` with ``stdin=subprocess.PIPE``, and
1390              the standard input is closed immediately after the new command is
1391              started.
1392
1393            - If it is of type :py:class:`bytes`, these bytes are sent to the
1394              standard input of the command.
1395
1396            - Otherwise, it is passed through to :py:class:`subprocess.Popen`.
1397              For further information in this case, consult the document of the
1398              ``stdin`` parameter in :py:class:`subprocess.Popen`.
1399        :returns:
1400            The result.
1401        """
1402        __tracebackhide__ = True
1403
1404        cmdargs = tuple(os.fspath(arg) for arg in cmdargs)
1405        p1 = self.path.joinpath("stdout")
1406        p2 = self.path.joinpath("stderr")
1407        print("running:", *cmdargs)
1408        print("     in:", Path.cwd())
1409
1410        with p1.open("w", encoding="utf8") as f1, p2.open("w", encoding="utf8") as f2:
1411            now = timing.time()
1412            popen = self.popen(
1413                cmdargs,
1414                stdin=stdin,
1415                stdout=f1,
1416                stderr=f2,
1417                close_fds=(sys.platform != "win32"),
1418            )
1419            if popen.stdin is not None:
1420                popen.stdin.close()
1421
1422            def handle_timeout() -> None:
1423                __tracebackhide__ = True
1424
1425                timeout_message = f"{timeout} second timeout expired running: {cmdargs}"
1426
1427                popen.kill()
1428                popen.wait()
1429                raise self.TimeoutExpired(timeout_message)
1430
1431            if timeout is None:
1432                ret = popen.wait()
1433            else:
1434                try:
1435                    ret = popen.wait(timeout)
1436                except subprocess.TimeoutExpired:
1437                    handle_timeout()
1438
1439        with p1.open(encoding="utf8") as f1, p2.open(encoding="utf8") as f2:
1440            out = f1.read().splitlines()
1441            err = f2.read().splitlines()
1442
1443        self._dump_lines(out, sys.stdout)
1444        self._dump_lines(err, sys.stderr)
1445
1446        with contextlib.suppress(ValueError):
1447            ret = ExitCode(ret)
1448        return RunResult(ret, out, err, timing.time() - now)
1449
1450    def _dump_lines(self, lines, fp):
1451        try:
1452            for line in lines:
1453                print(line, file=fp)
1454        except UnicodeEncodeError:
1455            print(f"couldn't print to {fp} because of encoding")
1456
1457    def _getpytestargs(self) -> Tuple[str, ...]:
1458        return sys.executable, "-mpytest"
1459
1460    def runpython(self, script: "os.PathLike[str]") -> RunResult:
1461        """Run a python script using sys.executable as interpreter."""
1462        return self.run(sys.executable, script)
1463
1464    def runpython_c(self, command: str) -> RunResult:
1465        """Run ``python -c "command"``."""
1466        return self.run(sys.executable, "-c", command)
1467
1468    def runpytest_subprocess(
1469        self, *args: Union[str, "os.PathLike[str]"], timeout: Optional[float] = None
1470    ) -> RunResult:
1471        """Run pytest as a subprocess with given arguments.
1472
1473        Any plugins added to the :py:attr:`plugins` list will be added using the
1474        ``-p`` command line option.  Additionally ``--basetemp`` is used to put
1475        any temporary files and directories in a numbered directory prefixed
1476        with "runpytest-" to not conflict with the normal numbered pytest
1477        location for temporary files and directories.
1478
1479        :param args:
1480            The sequence of arguments to pass to the pytest subprocess.
1481        :param timeout:
1482            The period in seconds after which to timeout and raise
1483            :py:class:`Pytester.TimeoutExpired`.
1484        :returns:
1485            The result.
1486        """
1487        __tracebackhide__ = True
1488        p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700)
1489        args = ("--basetemp=%s" % p, *args)
1490        plugins = [x for x in self.plugins if isinstance(x, str)]
1491        if plugins:
1492            args = ("-p", plugins[0], *args)
1493        args = self._getpytestargs() + args
1494        return self.run(*args, timeout=timeout)
1495
1496    def spawn_pytest(
1497        self, string: str, expect_timeout: float = 10.0
1498    ) -> "pexpect.spawn":
1499        """Run pytest using pexpect.
1500
1501        This makes sure to use the right pytest and sets up the temporary
1502        directory locations.
1503
1504        The pexpect child is returned.
1505        """
1506        basetemp = self.path / "temp-pexpect"
1507        basetemp.mkdir(mode=0o700)
1508        invoke = " ".join(map(str, self._getpytestargs()))
1509        cmd = f"{invoke} --basetemp={basetemp} {string}"
1510        return self.spawn(cmd, expect_timeout=expect_timeout)
1511
1512    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
1513        """Run a command using pexpect.
1514
1515        The pexpect child is returned.
1516        """
1517        pexpect = importorskip("pexpect", "3.0")
1518        if hasattr(sys, "pypy_version_info") and "64" in platform.machine():
1519            skip("pypy-64 bit not supported")
1520        if not hasattr(pexpect, "spawn"):
1521            skip("pexpect.spawn not available")
1522        logfile = self.path.joinpath("spawn.out").open("wb")
1523
1524        child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout)
1525        self._request.addfinalizer(logfile.close)
1526        return child

Facilities to write tests/configuration files, execute pytest in isolation, and match against expected output, perfect for black-box testing of pytest plugins.

It attempts to isolate the test run from external factors as much as possible, modifying the current working directory to path and environment variables during initialization.

Pytester( request: FixtureRequest, tmp_path_factory: TempPathFactory, monkeypatch: MonkeyPatch, *, _ispytest: bool = False)
667    def __init__(
668        self,
669        request: FixtureRequest,
670        tmp_path_factory: TempPathFactory,
671        monkeypatch: MonkeyPatch,
672        *,
673        _ispytest: bool = False,
674    ) -> None:
675        check_ispytest(_ispytest)
676        self._request = request
677        self._mod_collections: WeakKeyDictionary[
678            Collector, List[Union[Item, Collector]]
679        ] = WeakKeyDictionary()
680        if request.function:
681            name: str = request.function.__name__
682        else:
683            name = request.node.name
684        self._name = name
685        self._path: Path = tmp_path_factory.mktemp(name, numbered=True)
686        #: A list of plugins to use with :py:meth:`parseconfig` and
687        #: :py:meth:`runpytest`.  Initially this is an empty list but plugins can
688        #: be added to the list.  The type of items to add to the list depends on
689        #: the method using them so refer to them for details.
690        self.plugins: List[Union[str, _PluggyPlugin]] = []
691        self._sys_path_snapshot = SysPathsSnapshot()
692        self._sys_modules_snapshot = self.__take_sys_modules_snapshot()
693        self._request.addfinalizer(self._finalize)
694        self._method = self._request.config.getoption("--runpytest")
695        self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True)
696
697        self._monkeypatch = mp = monkeypatch
698        self.chdir()
699        mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot))
700        # Ensure no unexpected caching via tox.
701        mp.delenv("TOX_ENV_DIR", raising=False)
702        # Discard outer pytest options.
703        mp.delenv("PYTEST_ADDOPTS", raising=False)
704        # Ensure no user config is used.
705        tmphome = str(self.path)
706        mp.setenv("HOME", tmphome)
707        mp.setenv("USERPROFILE", tmphome)
708        # Do not use colors for inner runs by default.
709        mp.setenv("PY_COLORS", "0")
CLOSE_STDIN: Final = <NotSetType.token: 0>
plugins: List[Union[str, object]]
path: pathlib.Path
711    @property
712    def path(self) -> Path:
713        """Temporary directory path used to create files/run tests from, etc."""
714        return self._path

Temporary directory path used to create files/run tests from, etc.

def make_hook_recorder( self, pluginmanager: PytestPluginManager) -> HookRecorder:
742    def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder:
743        """Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`."""
744        pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True)  # type: ignore[attr-defined]
745        self._request.addfinalizer(reprec.finish_recording)
746        return reprec

Create a new HookRecorder for a PytestPluginManager.

def chdir(self) -> None:
748    def chdir(self) -> None:
749        """Cd into the temporary directory.
750
751        This is done automatically upon instantiation.
752        """
753        self._monkeypatch.chdir(self.path)

Cd into the temporary directory.

This is done automatically upon instantiation.

def makefile(self, ext: str, *args: str, **kwargs: str) -> pathlib.Path:
789    def makefile(self, ext: str, *args: str, **kwargs: str) -> Path:
790        r"""Create new text file(s) in the test directory.
791
792        :param ext:
793            The extension the file(s) should use, including the dot, e.g. `.py`.
794        :param args:
795            All args are treated as strings and joined using newlines.
796            The result is written as contents to the file.  The name of the
797            file is based on the test function requesting this fixture.
798        :param kwargs:
799            Each keyword is the name of a file, while the value of it will
800            be written as contents of the file.
801        :returns:
802            The first created file.
803
804        Examples:
805        .. code-block:: python
806
807            pytester.makefile(".txt", "line1", "line2")
808
809            pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n")
810
811        To create binary files, use :meth:`pathlib.Path.write_bytes` directly:
812
813        .. code-block:: python
814
815            filename = pytester.path.joinpath("foo.bin")
816            filename.write_bytes(b"...")
817        """
818        return self._makefile(ext, args, kwargs)

Create new text file(s) in the test directory.

Parameters
  • ext: The extension the file(s) should use, including the dot, e.g. .py.
  • args: All args are treated as strings and joined using newlines. The result is written as contents to the file. The name of the file is based on the test function requesting this fixture.
  • kwargs: Each keyword is the name of a file, while the value of it will be written as contents of the file. :returns: The first created file.

Examples:

pytester.makefile(".txt", "line1", "line2")

pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n")

To create binary files, use pathlib.Path.write_bytes() directly:

filename = pytester.path.joinpath("foo.bin")
filename.write_bytes(b"...")
def makeconftest(self, source: str) -> pathlib.Path:
820    def makeconftest(self, source: str) -> Path:
821        """Write a conftest.py file.
822
823        :param source: The contents.
824        :returns: The conftest.py file.
825        """
826        return self.makepyfile(conftest=source)

Write a conftest.py file.

Parameters
  • source: The contents. :returns: The conftest.py file.
def makeini(self, source: str) -> pathlib.Path:
828    def makeini(self, source: str) -> Path:
829        """Write a tox.ini file.
830
831        :param source: The contents.
832        :returns: The tox.ini file.
833        """
834        return self.makefile(".ini", tox=source)

Write a tox.ini file.

Parameters
  • source: The contents. :returns: The tox.ini file.
def getinicfg(self, source: str) -> iniconfig.SectionWrapper:
836    def getinicfg(self, source: str) -> SectionWrapper:
837        """Return the pytest section from the tox.ini config file."""
838        p = self.makeini(source)
839        return IniConfig(str(p))["pytest"]

Return the pytest section from the tox.ini config file.

def makepyprojecttoml(self, source: str) -> pathlib.Path:
841    def makepyprojecttoml(self, source: str) -> Path:
842        """Write a pyproject.toml file.
843
844        :param source: The contents.
845        :returns: The pyproject.ini file.
846
847        .. versionadded:: 6.0
848        """
849        return self.makefile(".toml", pyproject=source)

Write a pyproject.toml file.

Parameters
  • source: The contents. :returns: The pyproject.ini file.

New in version 6.0.

def makepyfile(self, *args, **kwargs) -> pathlib.Path:
851    def makepyfile(self, *args, **kwargs) -> Path:
852        r"""Shortcut for .makefile() with a .py extension.
853
854        Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting
855        existing files.
856
857        Examples:
858        .. code-block:: python
859
860            def test_something(pytester):
861                # Initial file is created test_something.py.
862                pytester.makepyfile("foobar")
863                # To create multiple files, pass kwargs accordingly.
864                pytester.makepyfile(custom="foobar")
865                # At this point, both 'test_something.py' & 'custom.py' exist in the test directory.
866
867        """
868        return self._makefile(".py", args, kwargs)

Shortcut for .makefile() with a .py extension.

Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting existing files.

Examples:

def test_something(pytester):
    # Initial file is created test_something.py.
    pytester.makepyfile("foobar")
    # To create multiple files, pass kwargs accordingly.
    pytester.makepyfile(custom="foobar")
    # At this point, both 'test_something.py' & 'custom.py' exist in the test directory.
def maketxtfile(self, *args, **kwargs) -> pathlib.Path:
870    def maketxtfile(self, *args, **kwargs) -> Path:
871        r"""Shortcut for .makefile() with a .txt extension.
872
873        Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting
874        existing files.
875
876        Examples:
877        .. code-block:: python
878
879            def test_something(pytester):
880                # Initial file is created test_something.txt.
881                pytester.maketxtfile("foobar")
882                # To create multiple files, pass kwargs accordingly.
883                pytester.maketxtfile(custom="foobar")
884                # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory.
885
886        """
887        return self._makefile(".txt", args, kwargs)

Shortcut for .makefile() with a .txt extension.

Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting existing files.

Examples:

def test_something(pytester):
    # Initial file is created test_something.txt.
    pytester.maketxtfile("foobar")
    # To create multiple files, pass kwargs accordingly.
    pytester.maketxtfile(custom="foobar")
    # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory.
def syspathinsert(self, path: Union[str, os.PathLike[str], NoneType] = None) -> None:
889    def syspathinsert(
890        self, path: Optional[Union[str, "os.PathLike[str]"]] = None
891    ) -> None:
892        """Prepend a directory to sys.path, defaults to :attr:`path`.
893
894        This is undone automatically when this object dies at the end of each
895        test.
896
897        :param path:
898            The path.
899        """
900        if path is None:
901            path = self.path
902
903        self._monkeypatch.syspath_prepend(str(path))

Prepend a directory to sys.path, defaults to path.

This is undone automatically when this object dies at the end of each test.

Parameters
  • path: The path.
def mkdir(self, name: Union[str, os.PathLike[str]]) -> pathlib.Path:
905    def mkdir(self, name: Union[str, "os.PathLike[str]"]) -> Path:
906        """Create a new (sub)directory.
907
908        :param name:
909            The name of the directory, relative to the pytester path.
910        :returns:
911            The created directory.
912        """
913        p = self.path / name
914        p.mkdir()
915        return p

Create a new (sub)directory.

Parameters
  • name: The name of the directory, relative to the pytester path. :returns: The created directory.
def mkpydir(self, name: Union[str, os.PathLike[str]]) -> pathlib.Path:
917    def mkpydir(self, name: Union[str, "os.PathLike[str]"]) -> Path:
918        """Create a new python package.
919
920        This creates a (sub)directory with an empty ``__init__.py`` file so it
921        gets recognised as a Python package.
922        """
923        p = self.path / name
924        p.mkdir()
925        p.joinpath("__init__.py").touch()
926        return p

Create a new python package.

This creates a (sub)directory with an empty __init__.py file so it gets recognised as a Python package.

def copy_example(self, name: Optional[str] = None) -> pathlib.Path:
928    def copy_example(self, name: Optional[str] = None) -> Path:
929        """Copy file from project's directory into the testdir.
930
931        :param name:
932            The name of the file to copy.
933        :return:
934            Path to the copied directory (inside ``self.path``).
935        """
936        example_dir_ = self._request.config.getini("pytester_example_dir")
937        if example_dir_ is None:
938            raise ValueError("pytester_example_dir is unset, can't copy examples")
939        example_dir: Path = self._request.config.rootpath / example_dir_
940
941        for extra_element in self._request.node.iter_markers("pytester_example_path"):
942            assert extra_element.args
943            example_dir = example_dir.joinpath(*extra_element.args)
944
945        if name is None:
946            func_name = self._name
947            maybe_dir = example_dir / func_name
948            maybe_file = example_dir / (func_name + ".py")
949
950            if maybe_dir.is_dir():
951                example_path = maybe_dir
952            elif maybe_file.is_file():
953                example_path = maybe_file
954            else:
955                raise LookupError(
956                    f"{func_name} can't be found as module or package in {example_dir}"
957                )
958        else:
959            example_path = example_dir.joinpath(name)
960
961        if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file():
962            shutil.copytree(example_path, self.path, symlinks=True, dirs_exist_ok=True)
963            return self.path
964        elif example_path.is_file():
965            result = self.path.joinpath(example_path.name)
966            shutil.copy(example_path, result)
967            return result
968        else:
969            raise LookupError(
970                f'example "{example_path}" is not found as a file or directory'
971            )

Copy file from project's directory into the testdir.

Parameters
  • name: The name of the file to copy.
Returns
Path to the copied directory (inside ``self.path``).
def getnode( self, config: Config, arg: Union[str, os.PathLike[str]]) -> Union[Collector, Item]:
973    def getnode(
974        self, config: Config, arg: Union[str, "os.PathLike[str]"]
975    ) -> Union[Collector, Item]:
976        """Get the collection node of a file.
977
978        :param config:
979           A pytest config.
980           See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it.
981        :param arg:
982            Path to the file.
983        :returns:
984            The node.
985        """
986        session = Session.from_config(config)
987        assert "::" not in str(arg)
988        p = Path(os.path.abspath(arg))
989        config.hook.pytest_sessionstart(session=session)
990        res = session.perform_collect([str(p)], genitems=False)[0]
991        config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
992        return res

Get the collection node of a file.

Parameters
def getpathnode( self, path: Union[str, os.PathLike[str]]) -> Union[Collector, Item]:
 994    def getpathnode(
 995        self, path: Union[str, "os.PathLike[str]"]
 996    ) -> Union[Collector, Item]:
 997        """Return the collection node of a file.
 998
 999        This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to
1000        create the (configured) pytest Config instance.
1001
1002        :param path:
1003            Path to the file.
1004        :returns:
1005            The node.
1006        """
1007        path = Path(path)
1008        config = self.parseconfigure(path)
1009        session = Session.from_config(config)
1010        x = bestrelpath(session.path, path)
1011        config.hook.pytest_sessionstart(session=session)
1012        res = session.perform_collect([x], genitems=False)[0]
1013        config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK)
1014        return res

Return the collection node of a file.

This is like getnode() but uses parseconfigure() to create the (configured) pytest Config instance.

Parameters
  • path: Path to the file. :returns: The node.
def genitems( self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]:
1016    def genitems(self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]:
1017        """Generate all test items from a collection node.
1018
1019        This recurses into the collection node and returns a list of all the
1020        test items contained within.
1021
1022        :param colitems:
1023            The collection nodes.
1024        :returns:
1025            The collected items.
1026        """
1027        session = colitems[0].session
1028        result: List[Item] = []
1029        for colitem in colitems:
1030            result.extend(session.genitems(colitem))
1031        return result

Generate all test items from a collection node.

This recurses into the collection node and returns a list of all the test items contained within.

Parameters
  • colitems: The collection nodes. :returns: The collected items.
def runitem(self, source: str) -> Any:
1033    def runitem(self, source: str) -> Any:
1034        """Run the "test_func" Item.
1035
1036        The calling test instance (class containing the test method) must
1037        provide a ``.getrunner()`` method which should return a runner which
1038        can run the test protocol for a single item, e.g.
1039        ``_pytest.runner.runtestprotocol``.
1040        """
1041        # used from runner functional tests
1042        item = self.getitem(source)
1043        # the test class where we are called from wants to provide the runner
1044        testclassinstance = self._request.instance
1045        runner = testclassinstance.getrunner()
1046        return runner(item)

Run the "test_func" Item.

The calling test instance (class containing the test method) must provide a .getrunner() method which should return a runner which can run the test protocol for a single item, e.g. _pytest.runner.runtestprotocol.

def inline_runsource(self, source: str, *cmdlineargs) -> HookRecorder:
1048    def inline_runsource(self, source: str, *cmdlineargs) -> HookRecorder:
1049        """Run a test module in process using ``pytest.main()``.
1050
1051        This run writes "source" into a temporary file and runs
1052        ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance
1053        for the result.
1054
1055        :param source: The source code of the test module.
1056        :param cmdlineargs: Any extra command line arguments to use.
1057        """
1058        p = self.makepyfile(source)
1059        values = [*list(cmdlineargs), p]
1060        return self.inline_run(*values)

Run a test module in process using pytest.main().

This run writes "source" into a temporary file and runs pytest.main() on it, returning a HookRecorder instance for the result.

Parameters
  • source: The source code of the test module.
  • cmdlineargs: Any extra command line arguments to use.
def inline_genitems( self, *args) -> Tuple[List[Item], HookRecorder]:
1062    def inline_genitems(self, *args) -> Tuple[List[Item], HookRecorder]:
1063        """Run ``pytest.main(['--collect-only'])`` in-process.
1064
1065        Runs the :py:func:`pytest.main` function to run all of pytest inside
1066        the test process itself like :py:meth:`inline_run`, but returns a
1067        tuple of the collected items and a :py:class:`HookRecorder` instance.
1068        """
1069        rec = self.inline_run("--collect-only", *args)
1070        items = [x.item for x in rec.getcalls("pytest_itemcollected")]
1071        return items, rec

Run pytest.main(['--collect-only']) in-process.

Runs the pytest.main() function to run all of pytest inside the test process itself like inline_run(), but returns a tuple of the collected items and a HookRecorder instance.

def inline_run( self, *args: Union[str, os.PathLike[str]], plugins=(), no_reraise_ctrlc: bool = False) -> HookRecorder:
1073    def inline_run(
1074        self,
1075        *args: Union[str, "os.PathLike[str]"],
1076        plugins=(),
1077        no_reraise_ctrlc: bool = False,
1078    ) -> HookRecorder:
1079        """Run ``pytest.main()`` in-process, returning a HookRecorder.
1080
1081        Runs the :py:func:`pytest.main` function to run all of pytest inside
1082        the test process itself.  This means it can return a
1083        :py:class:`HookRecorder` instance which gives more detailed results
1084        from that run than can be done by matching stdout/stderr from
1085        :py:meth:`runpytest`.
1086
1087        :param args:
1088            Command line arguments to pass to :py:func:`pytest.main`.
1089        :param plugins:
1090            Extra plugin instances the ``pytest.main()`` instance should use.
1091        :param no_reraise_ctrlc:
1092            Typically we reraise keyboard interrupts from the child run. If
1093            True, the KeyboardInterrupt exception is captured.
1094        """
1095        # (maybe a cpython bug?) the importlib cache sometimes isn't updated
1096        # properly between file creation and inline_run (especially if imports
1097        # are interspersed with file creation)
1098        importlib.invalidate_caches()
1099
1100        plugins = list(plugins)
1101        finalizers = []
1102        try:
1103            # Any sys.module or sys.path changes done while running pytest
1104            # inline should be reverted after the test run completes to avoid
1105            # clashing with later inline tests run within the same pytest test,
1106            # e.g. just because they use matching test module names.
1107            finalizers.append(self.__take_sys_modules_snapshot().restore)
1108            finalizers.append(SysPathsSnapshot().restore)
1109
1110            # Important note:
1111            # - our tests should not leave any other references/registrations
1112            #   laying around other than possibly loaded test modules
1113            #   referenced from sys.modules, as nothing will clean those up
1114            #   automatically
1115
1116            rec = []
1117
1118            class Collect:
1119                def pytest_configure(x, config: Config) -> None:
1120                    rec.append(self.make_hook_recorder(config.pluginmanager))
1121
1122            plugins.append(Collect())
1123            ret = main([str(x) for x in args], plugins=plugins)
1124            if len(rec) == 1:
1125                reprec = rec.pop()
1126            else:
1127
1128                class reprec:  # type: ignore
1129                    pass
1130
1131            reprec.ret = ret
1132
1133            # Typically we reraise keyboard interrupts from the child run
1134            # because it's our user requesting interruption of the testing.
1135            if ret == ExitCode.INTERRUPTED and not no_reraise_ctrlc:
1136                calls = reprec.getcalls("pytest_keyboard_interrupt")
1137                if calls and calls[-1].excinfo.type == KeyboardInterrupt:
1138                    raise KeyboardInterrupt()
1139            return reprec
1140        finally:
1141            for finalizer in finalizers:
1142                finalizer()

Run pytest.main() in-process, returning a HookRecorder.

Runs the pytest.main() function to run all of pytest inside the test process itself. This means it can return a HookRecorder instance which gives more detailed results from that run than can be done by matching stdout/stderr from runpytest().

Parameters
  • args: Command line arguments to pass to pytest.main().
  • plugins: Extra plugin instances the pytest.main() instance should use.
  • no_reraise_ctrlc: Typically we reraise keyboard interrupts from the child run. If True, the KeyboardInterrupt exception is captured.
def runpytest_inprocess( self, *args: Union[str, os.PathLike[str]], **kwargs: Any) -> RunResult:
1144    def runpytest_inprocess(
1145        self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any
1146    ) -> RunResult:
1147        """Return result of running pytest in-process, providing a similar
1148        interface to what self.runpytest() provides."""
1149        syspathinsert = kwargs.pop("syspathinsert", False)
1150
1151        if syspathinsert:
1152            self.syspathinsert()
1153        now = timing.time()
1154        capture = _get_multicapture("sys")
1155        capture.start_capturing()
1156        try:
1157            try:
1158                reprec = self.inline_run(*args, **kwargs)
1159            except SystemExit as e:
1160                ret = e.args[0]
1161                try:
1162                    ret = ExitCode(e.args[0])
1163                except ValueError:
1164                    pass
1165
1166                class reprec:  # type: ignore
1167                    ret = ret
1168
1169            except Exception:
1170                traceback.print_exc()
1171
1172                class reprec:  # type: ignore
1173                    ret = ExitCode(3)
1174
1175        finally:
1176            out, err = capture.readouterr()
1177            capture.stop_capturing()
1178            sys.stdout.write(out)
1179            sys.stderr.write(err)
1180
1181        assert reprec.ret is not None
1182        res = RunResult(
1183            reprec.ret, out.splitlines(), err.splitlines(), timing.time() - now
1184        )
1185        res.reprec = reprec  # type: ignore
1186        return res

Return result of running pytest in-process, providing a similar interface to what self.runpytest() provides.

def runpytest( self, *args: Union[str, os.PathLike[str]], **kwargs: Any) -> RunResult:
1188    def runpytest(
1189        self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any
1190    ) -> RunResult:
1191        """Run pytest inline or in a subprocess, depending on the command line
1192        option "--runpytest" and return a :py:class:`~pytest.RunResult`."""
1193        new_args = self._ensure_basetemp(args)
1194        if self._method == "inprocess":
1195            return self.runpytest_inprocess(*new_args, **kwargs)
1196        elif self._method == "subprocess":
1197            return self.runpytest_subprocess(*new_args, **kwargs)
1198        raise RuntimeError(f"Unrecognized runpytest option: {self._method}")

Run pytest inline or in a subprocess, depending on the command line option "--runpytest" and return a ~pytest.RunResult.

def parseconfig(self, *args: Union[str, os.PathLike[str]]) -> Config:
1211    def parseconfig(self, *args: Union[str, "os.PathLike[str]"]) -> Config:
1212        """Return a new pytest :class:`pytest.Config` instance from given
1213        commandline args.
1214
1215        This invokes the pytest bootstrapping code in _pytest.config to create a
1216        new :py:class:`pytest.PytestPluginManager` and call the
1217        :hook:`pytest_cmdline_parse` hook to create a new :class:`pytest.Config`
1218        instance.
1219
1220        If :attr:`plugins` has been populated they should be plugin modules
1221        to be registered with the plugin manager.
1222        """
1223        import _pytest.config
1224
1225        new_args = self._ensure_basetemp(args)
1226        new_args = [str(x) for x in new_args]
1227
1228        config = _pytest.config._prepareconfig(new_args, self.plugins)  # type: ignore[arg-type]
1229        # we don't know what the test will do with this half-setup config
1230        # object and thus we make sure it gets unconfigured properly in any
1231        # case (otherwise capturing could still be active, for example)
1232        self._request.addfinalizer(config._ensure_unconfigure)
1233        return config

Return a new pytest pytest.Config instance from given commandline args.

This invokes the pytest bootstrapping code in _pytest.config to create a new pytest.PytestPluginManager and call the :hook:pytest_cmdline_parse hook to create a new pytest.Config instance.

If plugins has been populated they should be plugin modules to be registered with the plugin manager.

def parseconfigure(self, *args: Union[str, os.PathLike[str]]) -> Config:
1235    def parseconfigure(self, *args: Union[str, "os.PathLike[str]"]) -> Config:
1236        """Return a new pytest configured Config instance.
1237
1238        Returns a new :py:class:`pytest.Config` instance like
1239        :py:meth:`parseconfig`, but also calls the :hook:`pytest_configure`
1240        hook.
1241        """
1242        config = self.parseconfig(*args)
1243        config._do_configure()
1244        return config

Return a new pytest configured Config instance.

Returns a new pytest.Config instance like parseconfig(), but also calls the :hook:pytest_configure hook.

def getitem( self, source: Union[str, os.PathLike[str]], funcname: str = 'test_func') -> Item:
1246    def getitem(
1247        self, source: Union[str, "os.PathLike[str]"], funcname: str = "test_func"
1248    ) -> Item:
1249        """Return the test item for a test function.
1250
1251        Writes the source to a python file and runs pytest's collection on
1252        the resulting module, returning the test item for the requested
1253        function name.
1254
1255        :param source:
1256            The module source.
1257        :param funcname:
1258            The name of the test function for which to return a test item.
1259        :returns:
1260            The test item.
1261        """
1262        items = self.getitems(source)
1263        for item in items:
1264            if item.name == funcname:
1265                return item
1266        assert 0, f"{funcname!r} item not found in module:\n{source}\nitems: {items}"

Return the test item for a test function.

Writes the source to a python file and runs pytest's collection on the resulting module, returning the test item for the requested function name.

Parameters
  • source: The module source.
  • funcname: The name of the test function for which to return a test item. :returns: The test item.
def getitems(self, source: Union[str, os.PathLike[str]]) -> List[Item]:
1268    def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]:
1269        """Return all test items collected from the module.
1270
1271        Writes the source to a Python file and runs pytest's collection on
1272        the resulting module, returning all test items contained within.
1273        """
1274        modcol = self.getmodulecol(source)
1275        return self.genitems([modcol])

Return all test items collected from the module.

Writes the source to a Python file and runs pytest's collection on the resulting module, returning all test items contained within.

def getmodulecol( self, source: Union[str, os.PathLike[str]], configargs=(), *, withinit: bool = False):
1277    def getmodulecol(
1278        self,
1279        source: Union[str, "os.PathLike[str]"],
1280        configargs=(),
1281        *,
1282        withinit: bool = False,
1283    ):
1284        """Return the module collection node for ``source``.
1285
1286        Writes ``source`` to a file using :py:meth:`makepyfile` and then
1287        runs the pytest collection on it, returning the collection node for the
1288        test module.
1289
1290        :param source:
1291            The source code of the module to collect.
1292
1293        :param configargs:
1294            Any extra arguments to pass to :py:meth:`parseconfigure`.
1295
1296        :param withinit:
1297            Whether to also write an ``__init__.py`` file to the same
1298            directory to ensure it is a package.
1299        """
1300        if isinstance(source, os.PathLike):
1301            path = self.path.joinpath(source)
1302            assert not withinit, "not supported for paths"
1303        else:
1304            kw = {self._name: str(source)}
1305            path = self.makepyfile(**kw)
1306        if withinit:
1307            self.makepyfile(__init__="#")
1308        self.config = config = self.parseconfigure(path, *configargs)
1309        return self.getnode(config, path)

Return the module collection node for source.

Writes source to a file using makepyfile() and then runs the pytest collection on it, returning the collection node for the test module.

Parameters
  • source: The source code of the module to collect.

  • configargs: Any extra arguments to pass to parseconfigure().

  • withinit: Whether to also write an __init__.py file to the same directory to ensure it is a package.

def collect_by_name( self, modcol: Collector, name: str) -> Union[Item, Collector, NoneType]:
1311    def collect_by_name(
1312        self, modcol: Collector, name: str
1313    ) -> Optional[Union[Item, Collector]]:
1314        """Return the collection node for name from the module collection.
1315
1316        Searches a module collection node for a collection node matching the
1317        given name.
1318
1319        :param modcol: A module collection node; see :py:meth:`getmodulecol`.
1320        :param name: The name of the node to return.
1321        """
1322        if modcol not in self._mod_collections:
1323            self._mod_collections[modcol] = list(modcol.collect())
1324        for colitem in self._mod_collections[modcol]:
1325            if colitem.name == name:
1326                return colitem
1327        return None

Return the collection node for name from the module collection.

Searches a module collection node for a collection node matching the given name.

Parameters
  • modcol: A module collection node; see getmodulecol().
  • name: The name of the node to return.
def popen( self, cmdargs: Sequence[Union[str, os.PathLike[str]]], stdout: Union[int, TextIO] = -1, stderr: Union[int, TextIO] = -1, stdin: Union[_pytest.compat.NotSetType, bytes, IO[Any], int] = <NotSetType.token: 0>, **kw):
1329    def popen(
1330        self,
1331        cmdargs: Sequence[Union[str, "os.PathLike[str]"]],
1332        stdout: Union[int, TextIO] = subprocess.PIPE,
1333        stderr: Union[int, TextIO] = subprocess.PIPE,
1334        stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN,
1335        **kw,
1336    ):
1337        """Invoke :py:class:`subprocess.Popen`.
1338
1339        Calls :py:class:`subprocess.Popen` making sure the current working
1340        directory is in ``PYTHONPATH``.
1341
1342        You probably want to use :py:meth:`run` instead.
1343        """
1344        env = os.environ.copy()
1345        env["PYTHONPATH"] = os.pathsep.join(
1346            filter(None, [os.getcwd(), env.get("PYTHONPATH", "")])
1347        )
1348        kw["env"] = env
1349
1350        if stdin is self.CLOSE_STDIN:
1351            kw["stdin"] = subprocess.PIPE
1352        elif isinstance(stdin, bytes):
1353            kw["stdin"] = subprocess.PIPE
1354        else:
1355            kw["stdin"] = stdin
1356
1357        popen = subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw)
1358        if stdin is self.CLOSE_STDIN:
1359            assert popen.stdin is not None
1360            popen.stdin.close()
1361        elif isinstance(stdin, bytes):
1362            assert popen.stdin is not None
1363            popen.stdin.write(stdin)
1364
1365        return popen

Invoke subprocess.Popen.

Calls subprocess.Popen making sure the current working directory is in PYTHONPATH.

You probably want to use run() instead.

def run( self, *cmdargs: Union[str, os.PathLike[str]], timeout: Optional[float] = None, stdin: Union[_pytest.compat.NotSetType, bytes, IO[Any], int] = <NotSetType.token: 0>) -> RunResult:
1367    def run(
1368        self,
1369        *cmdargs: Union[str, "os.PathLike[str]"],
1370        timeout: Optional[float] = None,
1371        stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN,
1372    ) -> RunResult:
1373        """Run a command with arguments.
1374
1375        Run a process using :py:class:`subprocess.Popen` saving the stdout and
1376        stderr.
1377
1378        :param cmdargs:
1379            The sequence of arguments to pass to :py:class:`subprocess.Popen`,
1380            with path-like objects being converted to :py:class:`str`
1381            automatically.
1382        :param timeout:
1383            The period in seconds after which to timeout and raise
1384            :py:class:`Pytester.TimeoutExpired`.
1385        :param stdin:
1386            Optional standard input.
1387
1388            - If it is ``CLOSE_STDIN`` (Default), then this method calls
1389              :py:class:`subprocess.Popen` with ``stdin=subprocess.PIPE``, and
1390              the standard input is closed immediately after the new command is
1391              started.
1392
1393            - If it is of type :py:class:`bytes`, these bytes are sent to the
1394              standard input of the command.
1395
1396            - Otherwise, it is passed through to :py:class:`subprocess.Popen`.
1397              For further information in this case, consult the document of the
1398              ``stdin`` parameter in :py:class:`subprocess.Popen`.
1399        :returns:
1400            The result.
1401        """
1402        __tracebackhide__ = True
1403
1404        cmdargs = tuple(os.fspath(arg) for arg in cmdargs)
1405        p1 = self.path.joinpath("stdout")
1406        p2 = self.path.joinpath("stderr")
1407        print("running:", *cmdargs)
1408        print("     in:", Path.cwd())
1409
1410        with p1.open("w", encoding="utf8") as f1, p2.open("w", encoding="utf8") as f2:
1411            now = timing.time()
1412            popen = self.popen(
1413                cmdargs,
1414                stdin=stdin,
1415                stdout=f1,
1416                stderr=f2,
1417                close_fds=(sys.platform != "win32"),
1418            )
1419            if popen.stdin is not None:
1420                popen.stdin.close()
1421
1422            def handle_timeout() -> None:
1423                __tracebackhide__ = True
1424
1425                timeout_message = f"{timeout} second timeout expired running: {cmdargs}"
1426
1427                popen.kill()
1428                popen.wait()
1429                raise self.TimeoutExpired(timeout_message)
1430
1431            if timeout is None:
1432                ret = popen.wait()
1433            else:
1434                try:
1435                    ret = popen.wait(timeout)
1436                except subprocess.TimeoutExpired:
1437                    handle_timeout()
1438
1439        with p1.open(encoding="utf8") as f1, p2.open(encoding="utf8") as f2:
1440            out = f1.read().splitlines()
1441            err = f2.read().splitlines()
1442
1443        self._dump_lines(out, sys.stdout)
1444        self._dump_lines(err, sys.stderr)
1445
1446        with contextlib.suppress(ValueError):
1447            ret = ExitCode(ret)
1448        return RunResult(ret, out, err, timing.time() - now)

Run a command with arguments.

Run a process using subprocess.Popen saving the stdout and stderr.

Parameters
  • cmdargs: The sequence of arguments to pass to subprocess.Popen, with path-like objects being converted to str automatically.
  • timeout: The period in seconds after which to timeout and raise Pytester.TimeoutExpired.
  • stdin: Optional standard input.

    • If it is CLOSE_STDIN (Default), then this method calls subprocess.Popen with stdin=subprocess.PIPE, and the standard input is closed immediately after the new command is started.

    • If it is of type bytes, these bytes are sent to the standard input of the command.

    • Otherwise, it is passed through to subprocess.Popen. For further information in this case, consult the document of the stdin parameter in subprocess.Popen. :returns: The result.

def runpython(self, script: os.PathLike[str]) -> RunResult:
1460    def runpython(self, script: "os.PathLike[str]") -> RunResult:
1461        """Run a python script using sys.executable as interpreter."""
1462        return self.run(sys.executable, script)

Run a python script using sys.executable as interpreter.

def runpython_c(self, command: str) -> RunResult:
1464    def runpython_c(self, command: str) -> RunResult:
1465        """Run ``python -c "command"``."""
1466        return self.run(sys.executable, "-c", command)

Run python -c "command".

def runpytest_subprocess( self, *args: Union[str, os.PathLike[str]], timeout: Optional[float] = None) -> RunResult:
1468    def runpytest_subprocess(
1469        self, *args: Union[str, "os.PathLike[str]"], timeout: Optional[float] = None
1470    ) -> RunResult:
1471        """Run pytest as a subprocess with given arguments.
1472
1473        Any plugins added to the :py:attr:`plugins` list will be added using the
1474        ``-p`` command line option.  Additionally ``--basetemp`` is used to put
1475        any temporary files and directories in a numbered directory prefixed
1476        with "runpytest-" to not conflict with the normal numbered pytest
1477        location for temporary files and directories.
1478
1479        :param args:
1480            The sequence of arguments to pass to the pytest subprocess.
1481        :param timeout:
1482            The period in seconds after which to timeout and raise
1483            :py:class:`Pytester.TimeoutExpired`.
1484        :returns:
1485            The result.
1486        """
1487        __tracebackhide__ = True
1488        p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700)
1489        args = ("--basetemp=%s" % p, *args)
1490        plugins = [x for x in self.plugins if isinstance(x, str)]
1491        if plugins:
1492            args = ("-p", plugins[0], *args)
1493        args = self._getpytestargs() + args
1494        return self.run(*args, timeout=timeout)

Run pytest as a subprocess with given arguments.

Any plugins added to the plugins list will be added using the -p command line option. Additionally --basetemp is used to put any temporary files and directories in a numbered directory prefixed with "runpytest-" to not conflict with the normal numbered pytest location for temporary files and directories.

Parameters
  • args: The sequence of arguments to pass to the pytest subprocess.
  • timeout: The period in seconds after which to timeout and raise Pytester.TimeoutExpired. :returns: The result.
def spawn_pytest( self, string: str, expect_timeout: float = 10.0) -> pexpect.pty_spawn.spawn:
1496    def spawn_pytest(
1497        self, string: str, expect_timeout: float = 10.0
1498    ) -> "pexpect.spawn":
1499        """Run pytest using pexpect.
1500
1501        This makes sure to use the right pytest and sets up the temporary
1502        directory locations.
1503
1504        The pexpect child is returned.
1505        """
1506        basetemp = self.path / "temp-pexpect"
1507        basetemp.mkdir(mode=0o700)
1508        invoke = " ".join(map(str, self._getpytestargs()))
1509        cmd = f"{invoke} --basetemp={basetemp} {string}"
1510        return self.spawn(cmd, expect_timeout=expect_timeout)

Run pytest using pexpect.

This makes sure to use the right pytest and sets up the temporary directory locations.

The pexpect child is returned.

def spawn(self, cmd: str, expect_timeout: float = 10.0) -> pexpect.pty_spawn.spawn:
1512    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
1513        """Run a command using pexpect.
1514
1515        The pexpect child is returned.
1516        """
1517        pexpect = importorskip("pexpect", "3.0")
1518        if hasattr(sys, "pypy_version_info") and "64" in platform.machine():
1519            skip("pypy-64 bit not supported")
1520        if not hasattr(pexpect, "spawn"):
1521            skip("pexpect.spawn not available")
1522        logfile = self.path.joinpath("spawn.out").open("wb")
1523
1524        child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout)
1525        self._request.addfinalizer(logfile.close)
1526        return child

Run a command using pexpect.

The pexpect child is returned.

class Pytester.TimeoutExpired(builtins.Exception):
664    class TimeoutExpired(Exception):
665        pass

Common base class for all non-exit exceptions.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
@final
class PytestPluginManager(pluggy._manager.PluginManager):
396@final
397class PytestPluginManager(PluginManager):
398    """A :py:class:`pluggy.PluginManager <pluggy.PluginManager>` with
399    additional pytest-specific functionality:
400
401    * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and
402      ``pytest_plugins`` global variables found in plugins being loaded.
403    * ``conftest.py`` loading during start-up.
404    """
405
406    def __init__(self) -> None:
407        import _pytest.assertion
408
409        super().__init__("pytest")
410
411        # -- State related to local conftest plugins.
412        # All loaded conftest modules.
413        self._conftest_plugins: Set[types.ModuleType] = set()
414        # All conftest modules applicable for a directory.
415        # This includes the directory's own conftest modules as well
416        # as those of its parent directories.
417        self._dirpath2confmods: Dict[Path, List[types.ModuleType]] = {}
418        # Cutoff directory above which conftests are no longer discovered.
419        self._confcutdir: Optional[Path] = None
420        # If set, conftest loading is skipped.
421        self._noconftest = False
422
423        # _getconftestmodules()'s call to _get_directory() causes a stat
424        # storm when it's called potentially thousands of times in a test
425        # session (#9478), often with the same path, so cache it.
426        self._get_directory = lru_cache(256)(_get_directory)
427
428        # plugins that were explicitly skipped with pytest.skip
429        # list of (module name, skip reason)
430        # previously we would issue a warning when a plugin was skipped, but
431        # since we refactored warnings as first citizens of Config, they are
432        # just stored here to be used later.
433        self.skipped_plugins: List[Tuple[str, str]] = []
434
435        self.add_hookspecs(_pytest.hookspec)
436        self.register(self)
437        if os.environ.get("PYTEST_DEBUG"):
438            err: IO[str] = sys.stderr
439            encoding: str = getattr(err, "encoding", "utf8")
440            try:
441                err = open(
442                    os.dup(err.fileno()),
443                    mode=err.mode,
444                    buffering=1,
445                    encoding=encoding,
446                )
447            except Exception:
448                pass
449            self.trace.root.setwriter(err.write)
450            self.enable_tracing()
451
452        # Config._consider_importhook will set a real object if required.
453        self.rewrite_hook = _pytest.assertion.DummyRewriteHook()
454        # Used to know when we are importing conftests after the pytest_configure stage.
455        self._configured = False
456
457    def parse_hookimpl_opts(
458        self, plugin: _PluggyPlugin, name: str
459    ) -> Optional[HookimplOpts]:
460        """:meta private:"""
461        # pytest hooks are always prefixed with "pytest_",
462        # so we avoid accessing possibly non-readable attributes
463        # (see issue #1073).
464        if not name.startswith("pytest_"):
465            return None
466        # Ignore names which can not be hooks.
467        if name == "pytest_plugins":
468            return None
469
470        opts = super().parse_hookimpl_opts(plugin, name)
471        if opts is not None:
472            return opts
473
474        method = getattr(plugin, name)
475        # Consider only actual functions for hooks (#3775).
476        if not inspect.isroutine(method):
477            return None
478        # Collect unmarked hooks as long as they have the `pytest_' prefix.
479        return _get_legacy_hook_marks(  # type: ignore[return-value]
480            method, "impl", ("tryfirst", "trylast", "optionalhook", "hookwrapper")
481        )
482
483    def parse_hookspec_opts(self, module_or_class, name: str) -> Optional[HookspecOpts]:
484        """:meta private:"""
485        opts = super().parse_hookspec_opts(module_or_class, name)
486        if opts is None:
487            method = getattr(module_or_class, name)
488            if name.startswith("pytest_"):
489                opts = _get_legacy_hook_marks(  # type: ignore[assignment]
490                    method,
491                    "spec",
492                    ("firstresult", "historic"),
493                )
494        return opts
495
496    def register(
497        self, plugin: _PluggyPlugin, name: Optional[str] = None
498    ) -> Optional[str]:
499        if name in _pytest.deprecated.DEPRECATED_EXTERNAL_PLUGINS:
500            warnings.warn(
501                PytestConfigWarning(
502                    "{} plugin has been merged into the core, "
503                    "please remove it from your requirements.".format(
504                        name.replace("_", "-")
505                    )
506                )
507            )
508            return None
509        plugin_name = super().register(plugin, name)
510        if plugin_name is not None:
511            self.hook.pytest_plugin_registered.call_historic(
512                kwargs=dict(
513                    plugin=plugin,
514                    plugin_name=plugin_name,
515                    manager=self,
516                )
517            )
518
519            if isinstance(plugin, types.ModuleType):
520                self.consider_module(plugin)
521        return plugin_name
522
523    def getplugin(self, name: str):
524        # Support deprecated naming because plugins (xdist e.g.) use it.
525        plugin: Optional[_PluggyPlugin] = self.get_plugin(name)
526        return plugin
527
528    def hasplugin(self, name: str) -> bool:
529        """Return whether a plugin with the given name is registered."""
530        return bool(self.get_plugin(name))
531
532    def pytest_configure(self, config: "Config") -> None:
533        """:meta private:"""
534        # XXX now that the pluginmanager exposes hookimpl(tryfirst...)
535        # we should remove tryfirst/trylast as markers.
536        config.addinivalue_line(
537            "markers",
538            "tryfirst: mark a hook implementation function such that the "
539            "plugin machinery will try to call it first/as early as possible. "
540            "DEPRECATED, use @pytest.hookimpl(tryfirst=True) instead.",
541        )
542        config.addinivalue_line(
543            "markers",
544            "trylast: mark a hook implementation function such that the "
545            "plugin machinery will try to call it last/as late as possible. "
546            "DEPRECATED, use @pytest.hookimpl(trylast=True) instead.",
547        )
548        self._configured = True
549
550    #
551    # Internal API for local conftest plugin handling.
552    #
553    def _set_initial_conftests(
554        self,
555        args: Sequence[Union[str, Path]],
556        pyargs: bool,
557        noconftest: bool,
558        rootpath: Path,
559        confcutdir: Optional[Path],
560        invocation_dir: Path,
561        importmode: Union[ImportMode, str],
562        *,
563        consider_namespace_packages: bool,
564    ) -> None:
565        """Load initial conftest files given a preparsed "namespace".
566
567        As conftest files may add their own command line options which have
568        arguments ('--my-opt somepath') we might get some false positives.
569        All builtin and 3rd party plugins will have been loaded, however, so
570        common options will not confuse our logic here.
571        """
572        self._confcutdir = (
573            absolutepath(invocation_dir / confcutdir) if confcutdir else None
574        )
575        self._noconftest = noconftest
576        self._using_pyargs = pyargs
577        foundanchor = False
578        for intitial_path in args:
579            path = str(intitial_path)
580            # remove node-id syntax
581            i = path.find("::")
582            if i != -1:
583                path = path[:i]
584            anchor = absolutepath(invocation_dir / path)
585
586            # Ensure we do not break if what appears to be an anchor
587            # is in fact a very long option (#10169, #11394).
588            if safe_exists(anchor):
589                self._try_load_conftest(
590                    anchor,
591                    importmode,
592                    rootpath,
593                    consider_namespace_packages=consider_namespace_packages,
594                )
595                foundanchor = True
596        if not foundanchor:
597            self._try_load_conftest(
598                invocation_dir,
599                importmode,
600                rootpath,
601                consider_namespace_packages=consider_namespace_packages,
602            )
603
604    def _is_in_confcutdir(self, path: Path) -> bool:
605        """Whether to consider the given path to load conftests from."""
606        if self._confcutdir is None:
607            return True
608        # The semantics here are literally:
609        #   Do not load a conftest if it is found upwards from confcut dir.
610        # But this is *not* the same as:
611        #   Load only conftests from confcutdir or below.
612        # At first glance they might seem the same thing, however we do support use cases where
613        # we want to load conftests that are not found in confcutdir or below, but are found
614        # in completely different directory hierarchies like packages installed
615        # in out-of-source trees.
616        # (see #9767 for a regression where the logic was inverted).
617        return path not in self._confcutdir.parents
618
619    def _try_load_conftest(
620        self,
621        anchor: Path,
622        importmode: Union[str, ImportMode],
623        rootpath: Path,
624        *,
625        consider_namespace_packages: bool,
626    ) -> None:
627        self._loadconftestmodules(
628            anchor,
629            importmode,
630            rootpath,
631            consider_namespace_packages=consider_namespace_packages,
632        )
633        # let's also consider test* subdirs
634        if anchor.is_dir():
635            for x in anchor.glob("test*"):
636                if x.is_dir():
637                    self._loadconftestmodules(
638                        x,
639                        importmode,
640                        rootpath,
641                        consider_namespace_packages=consider_namespace_packages,
642                    )
643
644    def _loadconftestmodules(
645        self,
646        path: Path,
647        importmode: Union[str, ImportMode],
648        rootpath: Path,
649        *,
650        consider_namespace_packages: bool,
651    ) -> None:
652        if self._noconftest:
653            return
654
655        directory = self._get_directory(path)
656
657        # Optimization: avoid repeated searches in the same directory.
658        # Assumes always called with same importmode and rootpath.
659        if directory in self._dirpath2confmods:
660            return
661
662        clist = []
663        for parent in reversed((directory, *directory.parents)):
664            if self._is_in_confcutdir(parent):
665                conftestpath = parent / "conftest.py"
666                if conftestpath.is_file():
667                    mod = self._importconftest(
668                        conftestpath,
669                        importmode,
670                        rootpath,
671                        consider_namespace_packages=consider_namespace_packages,
672                    )
673                    clist.append(mod)
674        self._dirpath2confmods[directory] = clist
675
676    def _getconftestmodules(self, path: Path) -> Sequence[types.ModuleType]:
677        directory = self._get_directory(path)
678        return self._dirpath2confmods.get(directory, ())
679
680    def _rget_with_confmod(
681        self,
682        name: str,
683        path: Path,
684    ) -> Tuple[types.ModuleType, Any]:
685        modules = self._getconftestmodules(path)
686        for mod in reversed(modules):
687            try:
688                return mod, getattr(mod, name)
689            except AttributeError:
690                continue
691        raise KeyError(name)
692
693    def _importconftest(
694        self,
695        conftestpath: Path,
696        importmode: Union[str, ImportMode],
697        rootpath: Path,
698        *,
699        consider_namespace_packages: bool,
700    ) -> types.ModuleType:
701        conftestpath_plugin_name = str(conftestpath)
702        existing = self.get_plugin(conftestpath_plugin_name)
703        if existing is not None:
704            return cast(types.ModuleType, existing)
705
706        # conftest.py files there are not in a Python package all have module
707        # name "conftest", and thus conflict with each other. Clear the existing
708        # before loading the new one, otherwise the existing one will be
709        # returned from the module cache.
710        pkgpath = resolve_package_path(conftestpath)
711        if pkgpath is None:
712            try:
713                del sys.modules[conftestpath.stem]
714            except KeyError:
715                pass
716
717        try:
718            mod = import_path(
719                conftestpath,
720                mode=importmode,
721                root=rootpath,
722                consider_namespace_packages=consider_namespace_packages,
723            )
724        except Exception as e:
725            assert e.__traceback__ is not None
726            raise ConftestImportFailure(conftestpath, cause=e) from e
727
728        self._check_non_top_pytest_plugins(mod, conftestpath)
729
730        self._conftest_plugins.add(mod)
731        dirpath = conftestpath.parent
732        if dirpath in self._dirpath2confmods:
733            for path, mods in self._dirpath2confmods.items():
734                if dirpath in path.parents or path == dirpath:
735                    if mod in mods:
736                        raise AssertionError(
737                            f"While trying to load conftest path {conftestpath!s}, "
738                            f"found that the module {mod} is already loaded with path {mod.__file__}. "
739                            "This is not supposed to happen. Please report this issue to pytest."
740                        )
741                    mods.append(mod)
742        self.trace(f"loading conftestmodule {mod!r}")
743        self.consider_conftest(mod, registration_name=conftestpath_plugin_name)
744        return mod
745
746    def _check_non_top_pytest_plugins(
747        self,
748        mod: types.ModuleType,
749        conftestpath: Path,
750    ) -> None:
751        if (
752            hasattr(mod, "pytest_plugins")
753            and self._configured
754            and not self._using_pyargs
755        ):
756            msg = (
757                "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported:\n"
758                "It affects the entire test suite instead of just below the conftest as expected.\n"
759                "  {}\n"
760                "Please move it to a top level conftest file at the rootdir:\n"
761                "  {}\n"
762                "For more information, visit:\n"
763                "  https://docs.pytest.org/en/stable/deprecations.html#pytest-plugins-in-non-top-level-conftest-files"
764            )
765            fail(msg.format(conftestpath, self._confcutdir), pytrace=False)
766
767    #
768    # API for bootstrapping plugin loading
769    #
770    #
771
772    def consider_preparse(
773        self, args: Sequence[str], *, exclude_only: bool = False
774    ) -> None:
775        """:meta private:"""
776        i = 0
777        n = len(args)
778        while i < n:
779            opt = args[i]
780            i += 1
781            if isinstance(opt, str):
782                if opt == "-p":
783                    try:
784                        parg = args[i]
785                    except IndexError:
786                        return
787                    i += 1
788                elif opt.startswith("-p"):
789                    parg = opt[2:]
790                else:
791                    continue
792                parg = parg.strip()
793                if exclude_only and not parg.startswith("no:"):
794                    continue
795                self.consider_pluginarg(parg)
796
797    def consider_pluginarg(self, arg: str) -> None:
798        """:meta private:"""
799        if arg.startswith("no:"):
800            name = arg[3:]
801            if name in essential_plugins:
802                raise UsageError("plugin %s cannot be disabled" % name)
803
804            # PR #4304: remove stepwise if cacheprovider is blocked.
805            if name == "cacheprovider":
806                self.set_blocked("stepwise")
807                self.set_blocked("pytest_stepwise")
808
809            self.set_blocked(name)
810            if not name.startswith("pytest_"):
811                self.set_blocked("pytest_" + name)
812        else:
813            name = arg
814            # Unblock the plugin.
815            self.unblock(name)
816            if not name.startswith("pytest_"):
817                self.unblock("pytest_" + name)
818            self.import_plugin(arg, consider_entry_points=True)
819
820    def consider_conftest(
821        self, conftestmodule: types.ModuleType, registration_name: str
822    ) -> None:
823        """:meta private:"""
824        self.register(conftestmodule, name=registration_name)
825
826    def consider_env(self) -> None:
827        """:meta private:"""
828        self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))
829
830    def consider_module(self, mod: types.ModuleType) -> None:
831        """:meta private:"""
832        self._import_plugin_specs(getattr(mod, "pytest_plugins", []))
833
834    def _import_plugin_specs(
835        self, spec: Union[None, types.ModuleType, str, Sequence[str]]
836    ) -> None:
837        plugins = _get_plugin_specs_as_list(spec)
838        for import_spec in plugins:
839            self.import_plugin(import_spec)
840
841    def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None:
842        """Import a plugin with ``modname``.
843
844        If ``consider_entry_points`` is True, entry point names are also
845        considered to find a plugin.
846        """
847        # Most often modname refers to builtin modules, e.g. "pytester",
848        # "terminal" or "capture".  Those plugins are registered under their
849        # basename for historic purposes but must be imported with the
850        # _pytest prefix.
851        assert isinstance(modname, str), (
852            "module name as text required, got %r" % modname
853        )
854        if self.is_blocked(modname) or self.get_plugin(modname) is not None:
855            return
856
857        importspec = "_pytest." + modname if modname in builtin_plugins else modname
858        self.rewrite_hook.mark_rewrite(importspec)
859
860        if consider_entry_points:
861            loaded = self.load_setuptools_entrypoints("pytest11", name=modname)
862            if loaded:
863                return
864
865        try:
866            __import__(importspec)
867        except ImportError as e:
868            raise ImportError(
869                f'Error importing plugin "{modname}": {e.args[0]}'
870            ).with_traceback(e.__traceback__) from e
871
872        except Skipped as e:
873            self.skipped_plugins.append((modname, e.msg or ""))
874        else:
875            mod = sys.modules[importspec]
876            self.register(mod, modname)

A pluggy.PluginManager <pluggy.PluginManager> with additional pytest-specific functionality:

  • Loading plugins from the command line, PYTEST_PLUGINS env variable and pytest_plugins global variables found in plugins being loaded.
  • conftest.py loading during start-up.
skipped_plugins: List[Tuple[str, str]]
rewrite_hook
def parse_hookimpl_opts(self, plugin: object, name: str) -> Optional[pluggy._hooks.HookimplOpts]:
457    def parse_hookimpl_opts(
458        self, plugin: _PluggyPlugin, name: str
459    ) -> Optional[HookimplOpts]:
460        """:meta private:"""
461        # pytest hooks are always prefixed with "pytest_",
462        # so we avoid accessing possibly non-readable attributes
463        # (see issue #1073).
464        if not name.startswith("pytest_"):
465            return None
466        # Ignore names which can not be hooks.
467        if name == "pytest_plugins":
468            return None
469
470        opts = super().parse_hookimpl_opts(plugin, name)
471        if opts is not None:
472            return opts
473
474        method = getattr(plugin, name)
475        # Consider only actual functions for hooks (#3775).
476        if not inspect.isroutine(method):
477            return None
478        # Collect unmarked hooks as long as they have the `pytest_' prefix.
479        return _get_legacy_hook_marks(  # type: ignore[return-value]
480            method, "impl", ("tryfirst", "trylast", "optionalhook", "hookwrapper")
481        )

:meta private:

def parse_hookspec_opts(self, module_or_class, name: str) -> Optional[pluggy._hooks.HookspecOpts]:
483    def parse_hookspec_opts(self, module_or_class, name: str) -> Optional[HookspecOpts]:
484        """:meta private:"""
485        opts = super().parse_hookspec_opts(module_or_class, name)
486        if opts is None:
487            method = getattr(module_or_class, name)
488            if name.startswith("pytest_"):
489                opts = _get_legacy_hook_marks(  # type: ignore[assignment]
490                    method,
491                    "spec",
492                    ("firstresult", "historic"),
493                )
494        return opts

:meta private:

def register(self, plugin: object, name: Optional[str] = None) -> Optional[str]:
496    def register(
497        self, plugin: _PluggyPlugin, name: Optional[str] = None
498    ) -> Optional[str]:
499        if name in _pytest.deprecated.DEPRECATED_EXTERNAL_PLUGINS:
500            warnings.warn(
501                PytestConfigWarning(
502                    "{} plugin has been merged into the core, "
503                    "please remove it from your requirements.".format(
504                        name.replace("_", "-")
505                    )
506                )
507            )
508            return None
509        plugin_name = super().register(plugin, name)
510        if plugin_name is not None:
511            self.hook.pytest_plugin_registered.call_historic(
512                kwargs=dict(
513                    plugin=plugin,
514                    plugin_name=plugin_name,
515                    manager=self,
516                )
517            )
518
519            if isinstance(plugin, types.ModuleType):
520                self.consider_module(plugin)
521        return plugin_name

Register a plugin and return its name.

Parameters
  • name: The name under which to register the plugin. If not specified, a name is generated using get_canonical_name().

:returns: The plugin name. If the name is blocked from registering, returns None.

If the plugin is already registered, raises a ValueError.

def getplugin(self, name: str):
523    def getplugin(self, name: str):
524        # Support deprecated naming because plugins (xdist e.g.) use it.
525        plugin: Optional[_PluggyPlugin] = self.get_plugin(name)
526        return plugin
def hasplugin(self, name: str) -> bool:
528    def hasplugin(self, name: str) -> bool:
529        """Return whether a plugin with the given name is registered."""
530        return bool(self.get_plugin(name))

Return whether a plugin with the given name is registered.

def pytest_configure(self, config: Config) -> None:
532    def pytest_configure(self, config: "Config") -> None:
533        """:meta private:"""
534        # XXX now that the pluginmanager exposes hookimpl(tryfirst...)
535        # we should remove tryfirst/trylast as markers.
536        config.addinivalue_line(
537            "markers",
538            "tryfirst: mark a hook implementation function such that the "
539            "plugin machinery will try to call it first/as early as possible. "
540            "DEPRECATED, use @pytest.hookimpl(tryfirst=True) instead.",
541        )
542        config.addinivalue_line(
543            "markers",
544            "trylast: mark a hook implementation function such that the "
545            "plugin machinery will try to call it last/as late as possible. "
546            "DEPRECATED, use @pytest.hookimpl(trylast=True) instead.",
547        )
548        self._configured = True

:meta private:

def consider_preparse(self, args: Sequence[str], *, exclude_only: bool = False) -> None:
772    def consider_preparse(
773        self, args: Sequence[str], *, exclude_only: bool = False
774    ) -> None:
775        """:meta private:"""
776        i = 0
777        n = len(args)
778        while i < n:
779            opt = args[i]
780            i += 1
781            if isinstance(opt, str):
782                if opt == "-p":
783                    try:
784                        parg = args[i]
785                    except IndexError:
786                        return
787                    i += 1
788                elif opt.startswith("-p"):
789                    parg = opt[2:]
790                else:
791                    continue
792                parg = parg.strip()
793                if exclude_only and not parg.startswith("no:"):
794                    continue
795                self.consider_pluginarg(parg)

:meta private:

def consider_pluginarg(self, arg: str) -> None:
797    def consider_pluginarg(self, arg: str) -> None:
798        """:meta private:"""
799        if arg.startswith("no:"):
800            name = arg[3:]
801            if name in essential_plugins:
802                raise UsageError("plugin %s cannot be disabled" % name)
803
804            # PR #4304: remove stepwise if cacheprovider is blocked.
805            if name == "cacheprovider":
806                self.set_blocked("stepwise")
807                self.set_blocked("pytest_stepwise")
808
809            self.set_blocked(name)
810            if not name.startswith("pytest_"):
811                self.set_blocked("pytest_" + name)
812        else:
813            name = arg
814            # Unblock the plugin.
815            self.unblock(name)
816            if not name.startswith("pytest_"):
817                self.unblock("pytest_" + name)
818            self.import_plugin(arg, consider_entry_points=True)

:meta private:

def consider_conftest(self, conftestmodule: module, registration_name: str) -> None:
820    def consider_conftest(
821        self, conftestmodule: types.ModuleType, registration_name: str
822    ) -> None:
823        """:meta private:"""
824        self.register(conftestmodule, name=registration_name)

:meta private:

def consider_env(self) -> None:
826    def consider_env(self) -> None:
827        """:meta private:"""
828        self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))

:meta private:

def consider_module(self, mod: module) -> None:
830    def consider_module(self, mod: types.ModuleType) -> None:
831        """:meta private:"""
832        self._import_plugin_specs(getattr(mod, "pytest_plugins", []))

:meta private:

def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None:
841    def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None:
842        """Import a plugin with ``modname``.
843
844        If ``consider_entry_points`` is True, entry point names are also
845        considered to find a plugin.
846        """
847        # Most often modname refers to builtin modules, e.g. "pytester",
848        # "terminal" or "capture".  Those plugins are registered under their
849        # basename for historic purposes but must be imported with the
850        # _pytest prefix.
851        assert isinstance(modname, str), (
852            "module name as text required, got %r" % modname
853        )
854        if self.is_blocked(modname) or self.get_plugin(modname) is not None:
855            return
856
857        importspec = "_pytest." + modname if modname in builtin_plugins else modname
858        self.rewrite_hook.mark_rewrite(importspec)
859
860        if consider_entry_points:
861            loaded = self.load_setuptools_entrypoints("pytest11", name=modname)
862            if loaded:
863                return
864
865        try:
866            __import__(importspec)
867        except ImportError as e:
868            raise ImportError(
869                f'Error importing plugin "{modname}": {e.args[0]}'
870            ).with_traceback(e.__traceback__) from e
871
872        except Skipped as e:
873            self.skipped_plugins.append((modname, e.msg or ""))
874        else:
875            mod = sys.modules[importspec]
876            self.register(mod, modname)

Import a plugin with modname.

If consider_entry_points is True, entry point names are also considered to find a plugin.

Inherited Members
pluggy._manager.PluginManager
project_name
hook
trace
unregister
set_blocked
is_blocked
unblock
add_hookspecs
get_plugins
is_registered
get_canonical_name
get_plugin
has_plugin
get_name
check_pending
load_setuptools_entrypoints
list_plugin_distinfo
list_name_plugin
get_hookcallers
add_hookcall_monitoring
enable_tracing
subset_hook_caller
class PytestUnhandledCoroutineWarning(PytestReturnNotNoneWarning):

Warning emitted for an unhandled coroutine.

A coroutine was encountered when collecting test functions, but was not handled by any async-aware plugin. Coroutine test functions are not natively supported.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestUnhandledThreadExceptionWarning(PytestWarning):

An unhandled exception occurred in a ~threading.Thread.

Such exceptions don't propagate normally.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestUnknownMarkWarning(PytestWarning):

Warning emitted on use of unknown markers.

See :ref:mark for details.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestUnraisableExceptionWarning(PytestWarning):

An unraisable exception was reported.

Unraisable exceptions are exceptions raised in __del__ <object.__del__>() implementations and similar situations when the exception cannot be raised as normal.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
class PytestWarning(builtins.UserWarning):

Base class for all warnings emitted by pytest.

Inherited Members
builtins.UserWarning
UserWarning
builtins.BaseException
with_traceback
add_note
args
def raises( expected_exception: Union[Type[~E], Tuple[Type[~E], ...]], *args: Any, **kwargs: Any) -> Union[_pytest.python_api.RaisesContext[~E], ExceptionInfo[~E]]:
789def raises(
790    expected_exception: Union[Type[E], Tuple[Type[E], ...]], *args: Any, **kwargs: Any
791) -> Union["RaisesContext[E]", _pytest._code.ExceptionInfo[E]]:
792    r"""Assert that a code block/function call raises an exception type, or one of its subclasses.
793
794    :param expected_exception:
795        The expected exception type, or a tuple if one of multiple possible
796        exception types are expected. Note that subclasses of the passed exceptions
797        will also match.
798
799    :kwparam str | re.Pattern[str] | None match:
800        If specified, a string containing a regular expression,
801        or a regular expression object, that is tested against the string
802        representation of the exception and its :pep:`678` `__notes__`
803        using :func:`re.search`.
804
805        To match a literal string that may contain :ref:`special characters
806        <re-syntax>`, the pattern can first be escaped with :func:`re.escape`.
807
808        (This is only used when ``pytest.raises`` is used as a context manager,
809        and passed through to the function otherwise.
810        When using ``pytest.raises`` as a function, you can use:
811        ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.)
812
813    Use ``pytest.raises`` as a context manager, which will capture the exception of the given
814    type, or any of its subclasses::
815
816        >>> import pytest
817        >>> with pytest.raises(ZeroDivisionError):
818        ...    1/0
819
820    If the code block does not raise the expected exception (:class:`ZeroDivisionError` in the example
821    above), or no exception at all, the check will fail instead.
822
823    You can also use the keyword argument ``match`` to assert that the
824    exception matches a text or regex::
825
826        >>> with pytest.raises(ValueError, match='must be 0 or None'):
827        ...     raise ValueError("value must be 0 or None")
828
829        >>> with pytest.raises(ValueError, match=r'must be \d+$'):
830        ...     raise ValueError("value must be 42")
831
832    The ``match`` argument searches the formatted exception string, which includes any
833    `PEP-678 <https://peps.python.org/pep-0678/>`__ ``__notes__``:
834
835        >>> with pytest.raises(ValueError, match=r"had a note added"):  # doctest: +SKIP
836        ...     e = ValueError("value must be 42")
837        ...     e.add_note("had a note added")
838        ...     raise e
839
840    The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the
841    details of the captured exception::
842
843        >>> with pytest.raises(ValueError) as exc_info:
844        ...     raise ValueError("value must be 42")
845        >>> assert exc_info.type is ValueError
846        >>> assert exc_info.value.args[0] == "value must be 42"
847
848    .. warning::
849
850       Given that ``pytest.raises`` matches subclasses, be wary of using it to match :class:`Exception` like this::
851
852           with pytest.raises(Exception):  # Careful, this will catch ANY exception raised.
853               some_function()
854
855       Because :class:`Exception` is the base class of almost all exceptions, it is easy for this to hide
856       real bugs, where the user wrote this expecting a specific exception, but some other exception is being
857       raised due to a bug introduced during a refactoring.
858
859       Avoid using ``pytest.raises`` to catch :class:`Exception` unless certain that you really want to catch
860       **any** exception raised.
861
862    .. note::
863
864       When using ``pytest.raises`` as a context manager, it's worthwhile to
865       note that normal context manager rules apply and that the exception
866       raised *must* be the final line in the scope of the context manager.
867       Lines of code after that, within the scope of the context manager will
868       not be executed. For example::
869
870           >>> value = 15
871           >>> with pytest.raises(ValueError) as exc_info:
872           ...     if value > 10:
873           ...         raise ValueError("value must be <= 10")
874           ...     assert exc_info.type is ValueError  # This will not execute.
875
876       Instead, the following approach must be taken (note the difference in
877       scope)::
878
879           >>> with pytest.raises(ValueError) as exc_info:
880           ...     if value > 10:
881           ...         raise ValueError("value must be <= 10")
882           ...
883           >>> assert exc_info.type is ValueError
884
885    **Using with** ``pytest.mark.parametrize``
886
887    When using :ref:`pytest.mark.parametrize ref`
888    it is possible to parametrize tests such that
889    some runs raise an exception and others do not.
890
891    See :ref:`parametrizing_conditional_raising` for an example.
892
893    .. seealso::
894
895        :ref:`assertraises` for more examples and detailed discussion.
896
897    **Legacy form**
898
899    It is possible to specify a callable by passing a to-be-called lambda::
900
901        >>> raises(ZeroDivisionError, lambda: 1/0)
902        <ExceptionInfo ...>
903
904    or you can specify an arbitrary callable with arguments::
905
906        >>> def f(x): return 1/x
907        ...
908        >>> raises(ZeroDivisionError, f, 0)
909        <ExceptionInfo ...>
910        >>> raises(ZeroDivisionError, f, x=0)
911        <ExceptionInfo ...>
912
913    The form above is fully supported but discouraged for new code because the
914    context manager form is regarded as more readable and less error-prone.
915
916    .. note::
917        Similar to caught exception objects in Python, explicitly clearing
918        local references to returned ``ExceptionInfo`` objects can
919        help the Python interpreter speed up its garbage collection.
920
921        Clearing those references breaks a reference cycle
922        (``ExceptionInfo`` --> caught exception --> frame stack raising
923        the exception --> current frame stack --> local variables -->
924        ``ExceptionInfo``) which makes Python keep all objects referenced
925        from that cycle (including all local variables in the current
926        frame) alive until the next cyclic garbage collection run.
927        More detailed information can be found in the official Python
928        documentation for :ref:`the try statement <python:try>`.
929    """
930    __tracebackhide__ = True
931
932    if not expected_exception:
933        raise ValueError(
934            f"Expected an exception type or a tuple of exception types, but got `{expected_exception!r}`. "
935            f"Raising exceptions is already understood as failing the test, so you don't need "
936            f"any special code to say 'this should never raise an exception'."
937        )
938    if isinstance(expected_exception, type):
939        expected_exceptions: Tuple[Type[E], ...] = (expected_exception,)
940    else:
941        expected_exceptions = expected_exception
942    for exc in expected_exceptions:
943        if not isinstance(exc, type) or not issubclass(exc, BaseException):
944            msg = "expected exception must be a BaseException type, not {}"  # type: ignore[unreachable]
945            not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__
946            raise TypeError(msg.format(not_a))
947
948    message = f"DID NOT RAISE {expected_exception}"
949
950    if not args:
951        match: Optional[Union[str, Pattern[str]]] = kwargs.pop("match", None)
952        if kwargs:
953            msg = "Unexpected keyword arguments passed to pytest.raises: "
954            msg += ", ".join(sorted(kwargs))
955            msg += "\nUse context-manager form instead?"
956            raise TypeError(msg)
957        return RaisesContext(expected_exception, message, match)
958    else:
959        func = args[0]
960        if not callable(func):
961            raise TypeError(f"{func!r} object (type: {type(func)}) must be callable")
962        try:
963            func(*args[1:], **kwargs)
964        except expected_exception as e:
965            return _pytest._code.ExceptionInfo.from_exception(e)
966    fail(message)

Assert that a code block/function call raises an exception type, or one of its subclasses.

Parameters
  • expected_exception: The expected exception type, or a tuple if one of multiple possible exception types are expected. Note that subclasses of the passed exceptions will also match.

:kwparam str | re.Pattern[str] | None match: If specified, a string containing a regular expression, or a regular expression object, that is tested against the string representation of the exception and its :pep:678 __notes__ using re.search().

To match a literal string that may contain :ref:`special characters
<re-syntax>`, the pattern can first be escaped with `re.escape()`.

(This is only used when ``pytest.raises`` is used as a context manager,
and passed through to the function otherwise.
When using ``pytest.raises`` as a function, you can use:
``pytest.raises(Exc, func, match="passed on").match("my pattern")``.)

Use pytest.raises as a context manager, which will capture the exception of the given type, or any of its subclasses::

>>> import pytest
>>> with pytest.raises(ZeroDivisionError):
...    1/0

If the code block does not raise the expected exception (ZeroDivisionError in the example above), or no exception at all, the check will fail instead.

You can also use the keyword argument match to assert that the exception matches a text or regex::

>>> with pytest.raises(ValueError, match='must be 0 or None'):
...     raise ValueError("value must be 0 or None")

>>> with pytest.raises(ValueError, match=r'must be \d+$'):
...     raise ValueError("value must be 42")

The match argument searches the formatted exception string, which includes any PEP-678 _ __notes__:

>>> with pytest.raises(ValueError, match=r"had a note added"):  # doctest: +SKIP
...     e = ValueError("value must be 42")
...     e.add_note("had a note added")
...     raise e

The context manager produces an ExceptionInfo object which can be used to inspect the details of the captured exception::

>>> with pytest.raises(ValueError) as exc_info:
...     raise ValueError("value must be 42")
>>> assert exc_info.type is ValueError
>>> assert exc_info.value.args[0] == "value must be 42"

Given that pytest.raises matches subclasses, be wary of using it to match Exception like this::

with pytest.raises(Exception):  # Careful, this will catch ANY exception raised.
    some_function()

Because Exception is the base class of almost all exceptions, it is easy for this to hide real bugs, where the user wrote this expecting a specific exception, but some other exception is being raised due to a bug introduced during a refactoring.

Avoid using pytest.raises to catch Exception unless certain that you really want to catch any exception raised.

When using pytest.raises as a context manager, it's worthwhile to note that normal context manager rules apply and that the exception raised must be the final line in the scope of the context manager. Lines of code after that, within the scope of the context manager will not be executed. For example::

>>> value = 15
>>> with pytest.raises(ValueError) as exc_info:
...     if value > 10:
...         raise ValueError("value must be <= 10")
...     assert exc_info.type is ValueError  # This will not execute.

Instead, the following approach must be taken (note the difference in scope)::

>>> with pytest.raises(ValueError) as exc_info:
...     if value > 10:
...         raise ValueError("value must be <= 10")
...
>>> assert exc_info.type is ValueError

Using with pytest.mark.parametrize

When using :ref:pytest.mark.parametrize ref it is possible to parametrize tests such that some runs raise an exception and others do not.

See :ref:parametrizing_conditional_raising for an example.

seealso: :ref:assertraises for more examples and detailed discussion.

Legacy form

It is possible to specify a callable by passing a to-be-called lambda::

>>> raises(ZeroDivisionError, lambda: 1/0)
<ExceptionInfo ...>

or you can specify an arbitrary callable with arguments::

>>> def f(x): return 1/x
...
>>> raises(ZeroDivisionError, f, 0)
<ExceptionInfo ...>
>>> raises(ZeroDivisionError, f, x=0)
<ExceptionInfo ...>

The form above is fully supported but discouraged for new code because the context manager form is regarded as more readable and less error-prone.

Similar to caught exception objects in Python, explicitly clearing local references to returned ExceptionInfo objects can help the Python interpreter speed up its garbage collection.

Clearing those references breaks a reference cycle (ExceptionInfo --> caught exception --> frame stack raising the exception --> current frame stack --> local variables --> ExceptionInfo) which makes Python keep all objects referenced from that cycle (including all local variables in the current frame) alive until the next cyclic garbage collection run. More detailed information can be found in the official Python documentation for :ref:the try statement <python:try>.

@final
class RecordedHookCall:
225@final
226class RecordedHookCall:
227    """A recorded call to a hook.
228
229    The arguments to the hook call are set as attributes.
230    For example:
231
232    .. code-block:: python
233
234        calls = hook_recorder.getcalls("pytest_runtest_setup")
235        # Suppose pytest_runtest_setup was called once with `item=an_item`.
236        assert calls[0].item is an_item
237    """
238
239    def __init__(self, name: str, kwargs) -> None:
240        self.__dict__.update(kwargs)
241        self._name = name
242
243    def __repr__(self) -> str:
244        d = self.__dict__.copy()
245        del d["_name"]
246        return f"<RecordedHookCall {self._name!r}(**{d!r})>"
247
248    if TYPE_CHECKING:
249        # The class has undetermined attributes, this tells mypy about it.
250        def __getattr__(self, key: str): ...

A recorded call to a hook.

The arguments to the hook call are set as attributes. For example:

calls = hook_recorder.getcalls("pytest_runtest_setup")
# Suppose pytest_runtest_setup was called once with `item=an_item`.
assert calls[0].item is an_item
RecordedHookCall(name: str, kwargs)
239    def __init__(self, name: str, kwargs) -> None:
240        self.__dict__.update(kwargs)
241        self._name = name
def register_assert_rewrite(*names: str) -> None:
59def register_assert_rewrite(*names: str) -> None:
60    """Register one or more module names to be rewritten on import.
61
62    This function will make sure that this module or all modules inside
63    the package will get their assert statements rewritten.
64    Thus you should make sure to call this before the module is
65    actually imported, usually in your __init__.py if you are a plugin
66    using a package.
67
68    :param names: The module names to register.
69    """
70    for name in names:
71        if not isinstance(name, str):
72            msg = "expected module names as *args, got {0} instead"  # type: ignore[unreachable]
73            raise TypeError(msg.format(repr(names)))
74    for hook in sys.meta_path:
75        if isinstance(hook, rewrite.AssertionRewritingHook):
76            importhook = hook
77            break
78    else:
79        # TODO(typing): Add a protocol for mark_rewrite() and use it
80        # for importhook and for PytestPluginManager.rewrite_hook.
81        importhook = DummyRewriteHook()  # type: ignore
82    importhook.mark_rewrite(*names)

Register one or more module names to be rewritten on import.

This function will make sure that this module or all modules inside the package will get their assert statements rewritten. Thus you should make sure to call this before the module is actually imported, usually in your __init__.py if you are a plugin using a package.

Parameters
  • names: The module names to register.
@final
class RunResult:
521@final
522class RunResult:
523    """The result of running a command from :class:`~pytest.Pytester`."""
524
525    def __init__(
526        self,
527        ret: Union[int, ExitCode],
528        outlines: List[str],
529        errlines: List[str],
530        duration: float,
531    ) -> None:
532        try:
533            self.ret: Union[int, ExitCode] = ExitCode(ret)
534            """The return value."""
535        except ValueError:
536            self.ret = ret
537        self.outlines = outlines
538        """List of lines captured from stdout."""
539        self.errlines = errlines
540        """List of lines captured from stderr."""
541        self.stdout = LineMatcher(outlines)
542        """:class:`~pytest.LineMatcher` of stdout.
543
544        Use e.g. :func:`str(stdout) <pytest.LineMatcher.__str__()>` to reconstruct stdout, or the commonly used
545        :func:`stdout.fnmatch_lines() <pytest.LineMatcher.fnmatch_lines()>` method.
546        """
547        self.stderr = LineMatcher(errlines)
548        """:class:`~pytest.LineMatcher` of stderr."""
549        self.duration = duration
550        """Duration in seconds."""
551
552    def __repr__(self) -> str:
553        return (
554            "<RunResult ret=%s len(stdout.lines)=%d len(stderr.lines)=%d duration=%.2fs>"
555            % (self.ret, len(self.stdout.lines), len(self.stderr.lines), self.duration)
556        )
557
558    def parseoutcomes(self) -> Dict[str, int]:
559        """Return a dictionary of outcome noun -> count from parsing the terminal
560        output that the test process produced.
561
562        The returned nouns will always be in plural form::
563
564            ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====
565
566        Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``.
567        """
568        return self.parse_summary_nouns(self.outlines)
569
570    @classmethod
571    def parse_summary_nouns(cls, lines) -> Dict[str, int]:
572        """Extract the nouns from a pytest terminal summary line.
573
574        It always returns the plural noun for consistency::
575
576            ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====
577
578        Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``.
579        """
580        for line in reversed(lines):
581            if rex_session_duration.search(line):
582                outcomes = rex_outcome.findall(line)
583                ret = {noun: int(count) for (count, noun) in outcomes}
584                break
585        else:
586            raise ValueError("Pytest terminal summary report not found")
587
588        to_plural = {
589            "warning": "warnings",
590            "error": "errors",
591        }
592        return {to_plural.get(k, k): v for k, v in ret.items()}
593
594    def assert_outcomes(
595        self,
596        passed: int = 0,
597        skipped: int = 0,
598        failed: int = 0,
599        errors: int = 0,
600        xpassed: int = 0,
601        xfailed: int = 0,
602        warnings: Optional[int] = None,
603        deselected: Optional[int] = None,
604    ) -> None:
605        """
606        Assert that the specified outcomes appear with the respective
607        numbers (0 means it didn't occur) in the text output from a test run.
608
609        ``warnings`` and ``deselected`` are only checked if not None.
610        """
611        __tracebackhide__ = True
612        from _pytest.pytester_assertions import assert_outcomes
613
614        outcomes = self.parseoutcomes()
615        assert_outcomes(
616            outcomes,
617            passed=passed,
618            skipped=skipped,
619            failed=failed,
620            errors=errors,
621            xpassed=xpassed,
622            xfailed=xfailed,
623            warnings=warnings,
624            deselected=deselected,
625        )

The result of running a command from ~pytest.Pytester.

RunResult( ret: Union[int, ExitCode], outlines: List[str], errlines: List[str], duration: float)
525    def __init__(
526        self,
527        ret: Union[int, ExitCode],
528        outlines: List[str],
529        errlines: List[str],
530        duration: float,
531    ) -> None:
532        try:
533            self.ret: Union[int, ExitCode] = ExitCode(ret)
534            """The return value."""
535        except ValueError:
536            self.ret = ret
537        self.outlines = outlines
538        """List of lines captured from stdout."""
539        self.errlines = errlines
540        """List of lines captured from stderr."""
541        self.stdout = LineMatcher(outlines)
542        """:class:`~pytest.LineMatcher` of stdout.
543
544        Use e.g. :func:`str(stdout) <pytest.LineMatcher.__str__()>` to reconstruct stdout, or the commonly used
545        :func:`stdout.fnmatch_lines() <pytest.LineMatcher.fnmatch_lines()>` method.
546        """
547        self.stderr = LineMatcher(errlines)
548        """:class:`~pytest.LineMatcher` of stderr."""
549        self.duration = duration
550        """Duration in seconds."""
outlines

List of lines captured from stdout.

errlines

List of lines captured from stderr.

stdout

~pytest.LineMatcher of stdout.

Use e.g. str(stdout) <pytest.LineMatcher.__str__()>() to reconstruct stdout, or the commonly used stdout.fnmatch_lines() <pytest.LineMatcher.fnmatch_lines()>() method.

stderr

~pytest.LineMatcher of stderr.

duration

Duration in seconds.

def parseoutcomes(self) -> Dict[str, int]:
558    def parseoutcomes(self) -> Dict[str, int]:
559        """Return a dictionary of outcome noun -> count from parsing the terminal
560        output that the test process produced.
561
562        The returned nouns will always be in plural form::
563
564            ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====
565
566        Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``.
567        """
568        return self.parse_summary_nouns(self.outlines)

Return a dictionary of outcome noun -> count from parsing the terminal output that the test process produced.

The returned nouns will always be in plural form::

======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====

Will return {"failed": 1, "passed": 1, "warnings": 1, "errors": 1}.

@classmethod
def parse_summary_nouns(cls, lines) -> Dict[str, int]:
570    @classmethod
571    def parse_summary_nouns(cls, lines) -> Dict[str, int]:
572        """Extract the nouns from a pytest terminal summary line.
573
574        It always returns the plural noun for consistency::
575
576            ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====
577
578        Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``.
579        """
580        for line in reversed(lines):
581            if rex_session_duration.search(line):
582                outcomes = rex_outcome.findall(line)
583                ret = {noun: int(count) for (count, noun) in outcomes}
584                break
585        else:
586            raise ValueError("Pytest terminal summary report not found")
587
588        to_plural = {
589            "warning": "warnings",
590            "error": "errors",
591        }
592        return {to_plural.get(k, k): v for k, v in ret.items()}

Extract the nouns from a pytest terminal summary line.

It always returns the plural noun for consistency::

======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ====

Will return {"failed": 1, "passed": 1, "warnings": 1, "errors": 1}.

def assert_outcomes( self, passed: int = 0, skipped: int = 0, failed: int = 0, errors: int = 0, xpassed: int = 0, xfailed: int = 0, warnings: Optional[int] = None, deselected: Optional[int] = None) -> None:
594    def assert_outcomes(
595        self,
596        passed: int = 0,
597        skipped: int = 0,
598        failed: int = 0,
599        errors: int = 0,
600        xpassed: int = 0,
601        xfailed: int = 0,
602        warnings: Optional[int] = None,
603        deselected: Optional[int] = None,
604    ) -> None:
605        """
606        Assert that the specified outcomes appear with the respective
607        numbers (0 means it didn't occur) in the text output from a test run.
608
609        ``warnings`` and ``deselected`` are only checked if not None.
610        """
611        __tracebackhide__ = True
612        from _pytest.pytester_assertions import assert_outcomes
613
614        outcomes = self.parseoutcomes()
615        assert_outcomes(
616            outcomes,
617            passed=passed,
618            skipped=skipped,
619            failed=failed,
620            errors=errors,
621            xpassed=xpassed,
622            xfailed=xfailed,
623            warnings=warnings,
624            deselected=deselected,
625        )

Assert that the specified outcomes appear with the respective numbers (0 means it didn't occur) in the text output from a test run.

warnings and deselected are only checked if not None.

@final
class Session(pytest.Collector):
543@final
544class Session(nodes.Collector):
545    """The root of the collection tree.
546
547    ``Session`` collects the initial paths given as arguments to pytest.
548    """
549
550    Interrupted = Interrupted
551    Failed = Failed
552    # Set on the session by runner.pytest_sessionstart.
553    _setupstate: SetupState
554    # Set on the session by fixtures.pytest_sessionstart.
555    _fixturemanager: FixtureManager
556    exitstatus: Union[int, ExitCode]
557
558    def __init__(self, config: Config) -> None:
559        super().__init__(
560            name="",
561            path=config.rootpath,
562            fspath=None,
563            parent=None,
564            config=config,
565            session=self,
566            nodeid="",
567        )
568        self.testsfailed = 0
569        self.testscollected = 0
570        self._shouldstop: Union[bool, str] = False
571        self._shouldfail: Union[bool, str] = False
572        self.trace = config.trace.root.get("collection")
573        self._initialpaths: FrozenSet[Path] = frozenset()
574        self._initialpaths_with_parents: FrozenSet[Path] = frozenset()
575        self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
576        self._initial_parts: List[CollectionArgument] = []
577        self._collection_cache: Dict[nodes.Collector, CollectReport] = {}
578        self.items: List[nodes.Item] = []
579
580        self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath)
581
582        self.config.pluginmanager.register(self, name="session")
583
584    @classmethod
585    def from_config(cls, config: Config) -> "Session":
586        session: Session = cls._create(config=config)
587        return session
588
589    def __repr__(self) -> str:
590        return "<%s %s exitstatus=%r testsfailed=%d testscollected=%d>" % (
591            self.__class__.__name__,
592            self.name,
593            getattr(self, "exitstatus", "<UNSET>"),
594            self.testsfailed,
595            self.testscollected,
596        )
597
598    @property
599    def shouldstop(self) -> Union[bool, str]:
600        return self._shouldstop
601
602    @shouldstop.setter
603    def shouldstop(self, value: Union[bool, str]) -> None:
604        # The runner checks shouldfail and assumes that if it is set we are
605        # definitely stopping, so prevent unsetting it.
606        if value is False and self._shouldstop:
607            warnings.warn(
608                PytestWarning(
609                    "session.shouldstop cannot be unset after it has been set; ignoring."
610                ),
611                stacklevel=2,
612            )
613            return
614        self._shouldstop = value
615
616    @property
617    def shouldfail(self) -> Union[bool, str]:
618        return self._shouldfail
619
620    @shouldfail.setter
621    def shouldfail(self, value: Union[bool, str]) -> None:
622        # The runner checks shouldfail and assumes that if it is set we are
623        # definitely stopping, so prevent unsetting it.
624        if value is False and self._shouldfail:
625            warnings.warn(
626                PytestWarning(
627                    "session.shouldfail cannot be unset after it has been set; ignoring."
628                ),
629                stacklevel=2,
630            )
631            return
632        self._shouldfail = value
633
634    @property
635    def startpath(self) -> Path:
636        """The path from which pytest was invoked.
637
638        .. versionadded:: 7.0.0
639        """
640        return self.config.invocation_params.dir
641
642    def _node_location_to_relpath(self, node_path: Path) -> str:
643        # bestrelpath is a quite slow function.
644        return self._bestrelpathcache[node_path]
645
646    @hookimpl(tryfirst=True)
647    def pytest_collectstart(self) -> None:
648        if self.shouldfail:
649            raise self.Failed(self.shouldfail)
650        if self.shouldstop:
651            raise self.Interrupted(self.shouldstop)
652
653    @hookimpl(tryfirst=True)
654    def pytest_runtest_logreport(
655        self, report: Union[TestReport, CollectReport]
656    ) -> None:
657        if report.failed and not hasattr(report, "wasxfail"):
658            self.testsfailed += 1
659            maxfail = self.config.getvalue("maxfail")
660            if maxfail and self.testsfailed >= maxfail:
661                self.shouldfail = "stopping after %d failures" % (self.testsfailed)
662
663    pytest_collectreport = pytest_runtest_logreport
664
665    def isinitpath(
666        self,
667        path: Union[str, "os.PathLike[str]"],
668        *,
669        with_parents: bool = False,
670    ) -> bool:
671        """Is path an initial path?
672
673        An initial path is a path explicitly given to pytest on the command
674        line.
675
676        :param with_parents:
677            If set, also return True if the path is a parent of an initial path.
678
679        .. versionchanged:: 8.0
680            Added the ``with_parents`` parameter.
681        """
682        # Optimization: Path(Path(...)) is much slower than isinstance.
683        path_ = path if isinstance(path, Path) else Path(path)
684        if with_parents:
685            return path_ in self._initialpaths_with_parents
686        else:
687            return path_ in self._initialpaths
688
689    def gethookproxy(self, fspath: "os.PathLike[str]") -> pluggy.HookRelay:
690        # Optimization: Path(Path(...)) is much slower than isinstance.
691        path = fspath if isinstance(fspath, Path) else Path(fspath)
692        pm = self.config.pluginmanager
693        # Check if we have the common case of running
694        # hooks with all conftest.py files.
695        my_conftestmodules = pm._getconftestmodules(path)
696        remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
697        proxy: pluggy.HookRelay
698        if remove_mods:
699            # One or more conftests are not in use at this path.
700            proxy = PathAwareHookProxy(FSHookProxy(pm, remove_mods))  # type: ignore[arg-type,assignment]
701        else:
702            # All plugins are active for this fspath.
703            proxy = self.config.hook
704        return proxy
705
706    def _collect_path(
707        self,
708        path: Path,
709        path_cache: Dict[Path, Sequence[nodes.Collector]],
710    ) -> Sequence[nodes.Collector]:
711        """Create a Collector for the given path.
712
713        `path_cache` makes it so the same Collectors are returned for the same
714        path.
715        """
716        if path in path_cache:
717            return path_cache[path]
718
719        if path.is_dir():
720            ihook = self.gethookproxy(path.parent)
721            col: Optional[nodes.Collector] = ihook.pytest_collect_directory(
722                path=path, parent=self
723            )
724            cols: Sequence[nodes.Collector] = (col,) if col is not None else ()
725
726        elif path.is_file():
727            ihook = self.gethookproxy(path)
728            cols = ihook.pytest_collect_file(file_path=path, parent=self)
729
730        else:
731            # Broken symlink or invalid/missing file.
732            cols = ()
733
734        path_cache[path] = cols
735        return cols
736
737    @overload
738    def perform_collect(
739        self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ...
740    ) -> Sequence[nodes.Item]: ...
741
742    @overload
743    def perform_collect(
744        self, args: Optional[Sequence[str]] = ..., genitems: bool = ...
745    ) -> Sequence[Union[nodes.Item, nodes.Collector]]: ...
746
747    def perform_collect(
748        self, args: Optional[Sequence[str]] = None, genitems: bool = True
749    ) -> Sequence[Union[nodes.Item, nodes.Collector]]:
750        """Perform the collection phase for this session.
751
752        This is called by the default :hook:`pytest_collection` hook
753        implementation; see the documentation of this hook for more details.
754        For testing purposes, it may also be called directly on a fresh
755        ``Session``.
756
757        This function normally recursively expands any collectors collected
758        from the session to their items, and only items are returned. For
759        testing purposes, this may be suppressed by passing ``genitems=False``,
760        in which case the return value contains these collectors unexpanded,
761        and ``session.items`` is empty.
762        """
763        if args is None:
764            args = self.config.args
765
766        self.trace("perform_collect", self, args)
767        self.trace.root.indent += 1
768
769        hook = self.config.hook
770
771        self._notfound = []
772        self._initial_parts = []
773        self._collection_cache = {}
774        self.items = []
775        items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
776        try:
777            initialpaths: List[Path] = []
778            initialpaths_with_parents: List[Path] = []
779            for arg in args:
780                collection_argument = resolve_collection_argument(
781                    self.config.invocation_params.dir,
782                    arg,
783                    as_pypath=self.config.option.pyargs,
784                )
785                self._initial_parts.append(collection_argument)
786                initialpaths.append(collection_argument.path)
787                initialpaths_with_parents.append(collection_argument.path)
788                initialpaths_with_parents.extend(collection_argument.path.parents)
789            self._initialpaths = frozenset(initialpaths)
790            self._initialpaths_with_parents = frozenset(initialpaths_with_parents)
791
792            rep = collect_one_node(self)
793            self.ihook.pytest_collectreport(report=rep)
794            self.trace.root.indent -= 1
795            if self._notfound:
796                errors = []
797                for arg, collectors in self._notfound:
798                    if collectors:
799                        errors.append(
800                            f"not found: {arg}\n(no match in any of {collectors!r})"
801                        )
802                    else:
803                        errors.append(f"found no collectors for {arg}")
804
805                raise UsageError(*errors)
806
807            if not genitems:
808                items = rep.result
809            else:
810                if rep.passed:
811                    for node in rep.result:
812                        self.items.extend(self.genitems(node))
813
814            self.config.pluginmanager.check_pending()
815            hook.pytest_collection_modifyitems(
816                session=self, config=self.config, items=items
817            )
818        finally:
819            self._notfound = []
820            self._initial_parts = []
821            self._collection_cache = {}
822            hook.pytest_collection_finish(session=self)
823
824        if genitems:
825            self.testscollected = len(items)
826
827        return items
828
829    def _collect_one_node(
830        self,
831        node: nodes.Collector,
832        handle_dupes: bool = True,
833    ) -> Tuple[CollectReport, bool]:
834        if node in self._collection_cache and handle_dupes:
835            rep = self._collection_cache[node]
836            return rep, True
837        else:
838            rep = collect_one_node(node)
839            self._collection_cache[node] = rep
840            return rep, False
841
842    def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
843        # This is a cache for the root directories of the initial paths.
844        # We can't use collection_cache for Session because of its special
845        # role as the bootstrapping collector.
846        path_cache: Dict[Path, Sequence[nodes.Collector]] = {}
847
848        pm = self.config.pluginmanager
849
850        for collection_argument in self._initial_parts:
851            self.trace("processing argument", collection_argument)
852            self.trace.root.indent += 1
853
854            argpath = collection_argument.path
855            names = collection_argument.parts
856            module_name = collection_argument.module_name
857
858            # resolve_collection_argument() ensures this.
859            if argpath.is_dir():
860                assert not names, f"invalid arg {(argpath, names)!r}"
861
862            paths = [argpath]
863            # Add relevant parents of the path, from the root, e.g.
864            #   /a/b/c.py -> [/, /a, /a/b, /a/b/c.py]
865            if module_name is None:
866                # Paths outside of the confcutdir should not be considered.
867                for path in argpath.parents:
868                    if not pm._is_in_confcutdir(path):
869                        break
870                    paths.insert(0, path)
871            else:
872                # For --pyargs arguments, only consider paths matching the module
873                # name. Paths beyond the package hierarchy are not included.
874                module_name_parts = module_name.split(".")
875                for i, path in enumerate(argpath.parents, 2):
876                    if i > len(module_name_parts) or path.stem != module_name_parts[-i]:
877                        break
878                    paths.insert(0, path)
879
880            # Start going over the parts from the root, collecting each level
881            # and discarding all nodes which don't match the level's part.
882            any_matched_in_initial_part = False
883            notfound_collectors = []
884            work: List[
885                Tuple[Union[nodes.Collector, nodes.Item], List[Union[Path, str]]]
886            ] = [(self, [*paths, *names])]
887            while work:
888                matchnode, matchparts = work.pop()
889
890                # Pop'd all of the parts, this is a match.
891                if not matchparts:
892                    yield matchnode
893                    any_matched_in_initial_part = True
894                    continue
895
896                # Should have been matched by now, discard.
897                if not isinstance(matchnode, nodes.Collector):
898                    continue
899
900                # Collect this level of matching.
901                # Collecting Session (self) is done directly to avoid endless
902                # recursion to this function.
903                subnodes: Sequence[Union[nodes.Collector, nodes.Item]]
904                if isinstance(matchnode, Session):
905                    assert isinstance(matchparts[0], Path)
906                    subnodes = matchnode._collect_path(matchparts[0], path_cache)
907                else:
908                    # For backward compat, files given directly multiple
909                    # times on the command line should not be deduplicated.
910                    handle_dupes = not (
911                        len(matchparts) == 1
912                        and isinstance(matchparts[0], Path)
913                        and matchparts[0].is_file()
914                    )
915                    rep, duplicate = self._collect_one_node(matchnode, handle_dupes)
916                    if not duplicate and not rep.passed:
917                        # Report collection failures here to avoid failing to
918                        # run some test specified in the command line because
919                        # the module could not be imported (#134).
920                        matchnode.ihook.pytest_collectreport(report=rep)
921                    if not rep.passed:
922                        continue
923                    subnodes = rep.result
924
925                # Prune this level.
926                any_matched_in_collector = False
927                for node in reversed(subnodes):
928                    # Path part e.g. `/a/b/` in `/a/b/test_file.py::TestIt::test_it`.
929                    if isinstance(matchparts[0], Path):
930                        is_match = node.path == matchparts[0]
931                        if sys.platform == "win32" and not is_match:
932                            # In case the file paths do not match, fallback to samefile() to
933                            # account for short-paths on Windows (#11895).
934                            same_file = os.path.samefile(node.path, matchparts[0])
935                            # We don't want to match links to the current node,
936                            # otherwise we would match the same file more than once (#12039).
937                            is_match = same_file and (
938                                os.path.islink(node.path)
939                                == os.path.islink(matchparts[0])
940                            )
941
942                    # Name part e.g. `TestIt` in `/a/b/test_file.py::TestIt::test_it`.
943                    else:
944                        # TODO: Remove parametrized workaround once collection structure contains
945                        # parametrization.
946                        is_match = (
947                            node.name == matchparts[0]
948                            or node.name.split("[")[0] == matchparts[0]
949                        )
950                    if is_match:
951                        work.append((node, matchparts[1:]))
952                        any_matched_in_collector = True
953
954                if not any_matched_in_collector:
955                    notfound_collectors.append(matchnode)
956
957            if not any_matched_in_initial_part:
958                report_arg = "::".join((str(argpath), *names))
959                self._notfound.append((report_arg, notfound_collectors))
960
961            self.trace.root.indent -= 1
962
963    def genitems(
964        self, node: Union[nodes.Item, nodes.Collector]
965    ) -> Iterator[nodes.Item]:
966        self.trace("genitems", node)
967        if isinstance(node, nodes.Item):
968            node.ihook.pytest_itemcollected(item=node)
969            yield node
970        else:
971            assert isinstance(node, nodes.Collector)
972            keepduplicates = self.config.getoption("keepduplicates")
973            # For backward compat, dedup only applies to files.
974            handle_dupes = not (keepduplicates and isinstance(node, nodes.File))
975            rep, duplicate = self._collect_one_node(node, handle_dupes)
976            if duplicate and not keepduplicates:
977                return
978            if rep.passed:
979                for subnode in rep.result:
980                    yield from self.genitems(subnode)
981            if not duplicate:
982                node.ihook.pytest_collectreport(report=rep)

The root of the collection tree.

Session collects the initial paths given as arguments to pytest.

Session(config: Config)
558    def __init__(self, config: Config) -> None:
559        super().__init__(
560            name="",
561            path=config.rootpath,
562            fspath=None,
563            parent=None,
564            config=config,
565            session=self,
566            nodeid="",
567        )
568        self.testsfailed = 0
569        self.testscollected = 0
570        self._shouldstop: Union[bool, str] = False
571        self._shouldfail: Union[bool, str] = False
572        self.trace = config.trace.root.get("collection")
573        self._initialpaths: FrozenSet[Path] = frozenset()
574        self._initialpaths_with_parents: FrozenSet[Path] = frozenset()
575        self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
576        self._initial_parts: List[CollectionArgument] = []
577        self._collection_cache: Dict[nodes.Collector, CollectReport] = {}
578        self.items: List[nodes.Item] = []
579
580        self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath)
581
582        self.config.pluginmanager.register(self, name="session")
exitstatus: Union[int, ExitCode]
testsfailed
testscollected
trace
items: List[Item]
@classmethod
def from_config(cls, config: Config) -> Session:
584    @classmethod
585    def from_config(cls, config: Config) -> "Session":
586        session: Session = cls._create(config=config)
587        return session
shouldstop: Union[bool, str]
598    @property
599    def shouldstop(self) -> Union[bool, str]:
600        return self._shouldstop
shouldfail: Union[bool, str]
616    @property
617    def shouldfail(self) -> Union[bool, str]:
618        return self._shouldfail
startpath: pathlib.Path
634    @property
635    def startpath(self) -> Path:
636        """The path from which pytest was invoked.
637
638        .. versionadded:: 7.0.0
639        """
640        return self.config.invocation_params.dir

The path from which pytest was invoked.

New in version 7.0.0.

@hookimpl(tryfirst=True)
def pytest_collectstart(self) -> None:
646    @hookimpl(tryfirst=True)
647    def pytest_collectstart(self) -> None:
648        if self.shouldfail:
649            raise self.Failed(self.shouldfail)
650        if self.shouldstop:
651            raise self.Interrupted(self.shouldstop)
@hookimpl(tryfirst=True)
def pytest_runtest_logreport( self, report: Union[TestReport, CollectReport]) -> None:
653    @hookimpl(tryfirst=True)
654    def pytest_runtest_logreport(
655        self, report: Union[TestReport, CollectReport]
656    ) -> None:
657        if report.failed and not hasattr(report, "wasxfail"):
658            self.testsfailed += 1
659            maxfail = self.config.getvalue("maxfail")
660            if maxfail and self.testsfailed >= maxfail:
661                self.shouldfail = "stopping after %d failures" % (self.testsfailed)
@hookimpl(tryfirst=True)
def pytest_collectreport( self, report: Union[TestReport, CollectReport]) -> None:
653    @hookimpl(tryfirst=True)
654    def pytest_runtest_logreport(
655        self, report: Union[TestReport, CollectReport]
656    ) -> None:
657        if report.failed and not hasattr(report, "wasxfail"):
658            self.testsfailed += 1
659            maxfail = self.config.getvalue("maxfail")
660            if maxfail and self.testsfailed >= maxfail:
661                self.shouldfail = "stopping after %d failures" % (self.testsfailed)
def isinitpath( self, path: Union[str, os.PathLike[str]], *, with_parents: bool = False) -> bool:
665    def isinitpath(
666        self,
667        path: Union[str, "os.PathLike[str]"],
668        *,
669        with_parents: bool = False,
670    ) -> bool:
671        """Is path an initial path?
672
673        An initial path is a path explicitly given to pytest on the command
674        line.
675
676        :param with_parents:
677            If set, also return True if the path is a parent of an initial path.
678
679        .. versionchanged:: 8.0
680            Added the ``with_parents`` parameter.
681        """
682        # Optimization: Path(Path(...)) is much slower than isinstance.
683        path_ = path if isinstance(path, Path) else Path(path)
684        if with_parents:
685            return path_ in self._initialpaths_with_parents
686        else:
687            return path_ in self._initialpaths

Is path an initial path?

An initial path is a path explicitly given to pytest on the command line.

Parameters
  • with_parents: If set, also return True if the path is a parent of an initial path.

Changed in version 8.0: Added the with_parents parameter.

def gethookproxy(self, fspath: os.PathLike[str]) -> pluggy._hooks.HookRelay:
689    def gethookproxy(self, fspath: "os.PathLike[str]") -> pluggy.HookRelay:
690        # Optimization: Path(Path(...)) is much slower than isinstance.
691        path = fspath if isinstance(fspath, Path) else Path(fspath)
692        pm = self.config.pluginmanager
693        # Check if we have the common case of running
694        # hooks with all conftest.py files.
695        my_conftestmodules = pm._getconftestmodules(path)
696        remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
697        proxy: pluggy.HookRelay
698        if remove_mods:
699            # One or more conftests are not in use at this path.
700            proxy = PathAwareHookProxy(FSHookProxy(pm, remove_mods))  # type: ignore[arg-type,assignment]
701        else:
702            # All plugins are active for this fspath.
703            proxy = self.config.hook
704        return proxy
def perform_collect( self, args: Optional[Sequence[str]] = None, genitems: bool = True) -> Sequence[Union[Item, Collector]]:
747    def perform_collect(
748        self, args: Optional[Sequence[str]] = None, genitems: bool = True
749    ) -> Sequence[Union[nodes.Item, nodes.Collector]]:
750        """Perform the collection phase for this session.
751
752        This is called by the default :hook:`pytest_collection` hook
753        implementation; see the documentation of this hook for more details.
754        For testing purposes, it may also be called directly on a fresh
755        ``Session``.
756
757        This function normally recursively expands any collectors collected
758        from the session to their items, and only items are returned. For
759        testing purposes, this may be suppressed by passing ``genitems=False``,
760        in which case the return value contains these collectors unexpanded,
761        and ``session.items`` is empty.
762        """
763        if args is None:
764            args = self.config.args
765
766        self.trace("perform_collect", self, args)
767        self.trace.root.indent += 1
768
769        hook = self.config.hook
770
771        self._notfound = []
772        self._initial_parts = []
773        self._collection_cache = {}
774        self.items = []
775        items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
776        try:
777            initialpaths: List[Path] = []
778            initialpaths_with_parents: List[Path] = []
779            for arg in args:
780                collection_argument = resolve_collection_argument(
781                    self.config.invocation_params.dir,
782                    arg,
783                    as_pypath=self.config.option.pyargs,
784                )
785                self._initial_parts.append(collection_argument)
786                initialpaths.append(collection_argument.path)
787                initialpaths_with_parents.append(collection_argument.path)
788                initialpaths_with_parents.extend(collection_argument.path.parents)
789            self._initialpaths = frozenset(initialpaths)
790            self._initialpaths_with_parents = frozenset(initialpaths_with_parents)
791
792            rep = collect_one_node(self)
793            self.ihook.pytest_collectreport(report=rep)
794            self.trace.root.indent -= 1
795            if self._notfound:
796                errors = []
797                for arg, collectors in self._notfound:
798                    if collectors:
799                        errors.append(
800                            f"not found: {arg}\n(no match in any of {collectors!r})"
801                        )
802                    else:
803                        errors.append(f"found no collectors for {arg}")
804
805                raise UsageError(*errors)
806
807            if not genitems:
808                items = rep.result
809            else:
810                if rep.passed:
811                    for node in rep.result:
812                        self.items.extend(self.genitems(node))
813
814            self.config.pluginmanager.check_pending()
815            hook.pytest_collection_modifyitems(
816                session=self, config=self.config, items=items
817            )
818        finally:
819            self._notfound = []
820            self._initial_parts = []
821            self._collection_cache = {}
822            hook.pytest_collection_finish(session=self)
823
824        if genitems:
825            self.testscollected = len(items)
826
827        return items

Perform the collection phase for this session.

This is called by the default :hook:pytest_collection hook implementation; see the documentation of this hook for more details. For testing purposes, it may also be called directly on a fresh Session.

This function normally recursively expands any collectors collected from the session to their items, and only items are returned. For testing purposes, this may be suppressed by passing genitems=False, in which case the return value contains these collectors unexpanded, and session.items is empty.

def collect(self) -> Iterator[Union[Item, Collector]]:
842    def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
843        # This is a cache for the root directories of the initial paths.
844        # We can't use collection_cache for Session because of its special
845        # role as the bootstrapping collector.
846        path_cache: Dict[Path, Sequence[nodes.Collector]] = {}
847
848        pm = self.config.pluginmanager
849
850        for collection_argument in self._initial_parts:
851            self.trace("processing argument", collection_argument)
852            self.trace.root.indent += 1
853
854            argpath = collection_argument.path
855            names = collection_argument.parts
856            module_name = collection_argument.module_name
857
858            # resolve_collection_argument() ensures this.
859            if argpath.is_dir():
860                assert not names, f"invalid arg {(argpath, names)!r}"
861
862            paths = [argpath]
863            # Add relevant parents of the path, from the root, e.g.
864            #   /a/b/c.py -> [/, /a, /a/b, /a/b/c.py]
865            if module_name is None:
866                # Paths outside of the confcutdir should not be considered.
867                for path in argpath.parents:
868                    if not pm._is_in_confcutdir(path):
869                        break
870                    paths.insert(0, path)
871            else:
872                # For --pyargs arguments, only consider paths matching the module
873                # name. Paths beyond the package hierarchy are not included.
874                module_name_parts = module_name.split(".")
875                for i, path in enumerate(argpath.parents, 2):
876                    if i > len(module_name_parts) or path.stem != module_name_parts[-i]:
877                        break
878                    paths.insert(0, path)
879
880            # Start going over the parts from the root, collecting each level
881            # and discarding all nodes which don't match the level's part.
882            any_matched_in_initial_part = False
883            notfound_collectors = []
884            work: List[
885                Tuple[Union[nodes.Collector, nodes.Item], List[Union[Path, str]]]
886            ] = [(self, [*paths, *names])]
887            while work:
888                matchnode, matchparts = work.pop()
889
890                # Pop'd all of the parts, this is a match.
891                if not matchparts:
892                    yield matchnode
893                    any_matched_in_initial_part = True
894                    continue
895
896                # Should have been matched by now, discard.
897                if not isinstance(matchnode, nodes.Collector):
898                    continue
899
900                # Collect this level of matching.
901                # Collecting Session (self) is done directly to avoid endless
902                # recursion to this function.
903                subnodes: Sequence[Union[nodes.Collector, nodes.Item]]
904                if isinstance(matchnode, Session):
905                    assert isinstance(matchparts[0], Path)
906                    subnodes = matchnode._collect_path(matchparts[0], path_cache)
907                else:
908                    # For backward compat, files given directly multiple
909                    # times on the command line should not be deduplicated.
910                    handle_dupes = not (
911                        len(matchparts) == 1
912                        and isinstance(matchparts[0], Path)
913                        and matchparts[0].is_file()
914                    )
915                    rep, duplicate = self._collect_one_node(matchnode, handle_dupes)
916                    if not duplicate and not rep.passed:
917                        # Report collection failures here to avoid failing to
918                        # run some test specified in the command line because
919                        # the module could not be imported (#134).
920                        matchnode.ihook.pytest_collectreport(report=rep)
921                    if not rep.passed:
922                        continue
923                    subnodes = rep.result
924
925                # Prune this level.
926                any_matched_in_collector = False
927                for node in reversed(subnodes):
928                    # Path part e.g. `/a/b/` in `/a/b/test_file.py::TestIt::test_it`.
929                    if isinstance(matchparts[0], Path):
930                        is_match = node.path == matchparts[0]
931                        if sys.platform == "win32" and not is_match:
932                            # In case the file paths do not match, fallback to samefile() to
933                            # account for short-paths on Windows (#11895).
934                            same_file = os.path.samefile(node.path, matchparts[0])
935                            # We don't want to match links to the current node,
936                            # otherwise we would match the same file more than once (#12039).
937                            is_match = same_file and (
938                                os.path.islink(node.path)
939                                == os.path.islink(matchparts[0])
940                            )
941
942                    # Name part e.g. `TestIt` in `/a/b/test_file.py::TestIt::test_it`.
943                    else:
944                        # TODO: Remove parametrized workaround once collection structure contains
945                        # parametrization.
946                        is_match = (
947                            node.name == matchparts[0]
948                            or node.name.split("[")[0] == matchparts[0]
949                        )
950                    if is_match:
951                        work.append((node, matchparts[1:]))
952                        any_matched_in_collector = True
953
954                if not any_matched_in_collector:
955                    notfound_collectors.append(matchnode)
956
957            if not any_matched_in_initial_part:
958                report_arg = "::".join((str(argpath), *names))
959                self._notfound.append((report_arg, notfound_collectors))
960
961            self.trace.root.indent -= 1

Collect children (items and collectors) for this collector.

def genitems( self, node: Union[Item, Collector]) -> Iterator[Item]:
963    def genitems(
964        self, node: Union[nodes.Item, nodes.Collector]
965    ) -> Iterator[nodes.Item]:
966        self.trace("genitems", node)
967        if isinstance(node, nodes.Item):
968            node.ihook.pytest_itemcollected(item=node)
969            yield node
970        else:
971            assert isinstance(node, nodes.Collector)
972            keepduplicates = self.config.getoption("keepduplicates")
973            # For backward compat, dedup only applies to files.
974            handle_dupes = not (keepduplicates and isinstance(node, nodes.File))
975            rep, duplicate = self._collect_one_node(node, handle_dupes)
976            if duplicate and not keepduplicates:
977                return
978            if rep.passed:
979                for subnode in rep.result:
980                    yield from self.genitems(subnode)
981            if not duplicate:
982                node.ihook.pytest_collectreport(report=rep)
Inherited Members
Collector
CollectError
repr_failure
_pytest.nodes.Node
fspath
name
parent
path
keywords
own_markers
extra_keyword_matches
stash
from_parent
ihook
warn
nodeid
setup
teardown
iter_parents
listchain
add_marker
iter_markers
iter_markers_with_node
get_closest_marker
listextrakeywords
listnames
addfinalizer
getparent
config
session
class Session.Interrupted(builtins.KeyboardInterrupt):

Signals that the test run was interrupted.

Inherited Members
builtins.KeyboardInterrupt
KeyboardInterrupt
builtins.BaseException
with_traceback
add_note
args
class Session.Failed(builtins.Exception):
476class Failed(Exception):
477    """Signals a stop as failed test run."""

Signals a stop as failed test run.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
@classmethod
def set_trace(*args, **kwargs) -> None:
279    @classmethod
280    def set_trace(cls, *args, **kwargs) -> None:
281        """Invoke debugging via ``Pdb.set_trace``, dropping any IO capturing."""
282        frame = sys._getframe().f_back
283        _pdb = cls._init_pdb("set_trace", *args, **kwargs)
284        _pdb.set_trace(frame)

Invoke debugging via Pdb.set_trace, dropping any IO capturing.

def skip(reason: str = '', *, allow_module_level: bool = False) -> NoReturn:
123@_with_exception(Skipped)
124def skip(
125    reason: str = "",
126    *,
127    allow_module_level: bool = False,
128) -> NoReturn:
129    """Skip an executing test with the given message.
130
131    This function should be called only during testing (setup, call or teardown) or
132    during collection by using the ``allow_module_level`` flag.  This function can
133    be called in doctests as well.
134
135    :param reason:
136        The message to show the user as reason for the skip.
137
138    :param allow_module_level:
139        Allows this function to be called at module level.
140        Raising the skip exception at module level will stop
141        the execution of the module and prevent the collection of all tests in the module,
142        even those defined before the `skip` call.
143
144        Defaults to False.
145
146    .. note::
147        It is better to use the :ref:`pytest.mark.skipif ref` marker when
148        possible to declare a test to be skipped under certain conditions
149        like mismatching platforms or dependencies.
150        Similarly, use the ``# doctest: +SKIP`` directive (see :py:data:`doctest.SKIP`)
151        to skip a doctest statically.
152    """
153    __tracebackhide__ = True
154    raise Skipped(msg=reason, allow_module_level=allow_module_level)

Skip an executing test with the given message.

This function should be called only during testing (setup, call or teardown) or during collection by using the allow_module_level flag. This function can be called in doctests as well.

Parameters
  • reason: The message to show the user as reason for the skip.

  • allow_module_level: Allows this function to be called at module level. Raising the skip exception at module level will stop the execution of the module and prevent the collection of all tests in the module, even those defined before the skip call.

    Defaults to False.

It is better to use the :ref:pytest.mark.skipif ref marker when possible to declare a test to be skipped under certain conditions like mismatching platforms or dependencies. Similarly, use the # doctest: +SKIP directive (see doctest.SKIP) to skip a doctest statically.

class Stash:
 30class Stash:
 31    r"""``Stash`` is a type-safe heterogeneous mutable mapping that
 32    allows keys and value types to be defined separately from
 33    where it (the ``Stash``) is created.
 34
 35    Usually you will be given an object which has a ``Stash``, for example
 36    :class:`~pytest.Config` or a :class:`~_pytest.nodes.Node`:
 37
 38    .. code-block:: python
 39
 40        stash: Stash = some_object.stash
 41
 42    If a module or plugin wants to store data in this ``Stash``, it creates
 43    :class:`StashKey`\s for its keys (at the module level):
 44
 45    .. code-block:: python
 46
 47        # At the top-level of the module
 48        some_str_key = StashKey[str]()
 49        some_bool_key = StashKey[bool]()
 50
 51    To store information:
 52
 53    .. code-block:: python
 54
 55        # Value type must match the key.
 56        stash[some_str_key] = "value"
 57        stash[some_bool_key] = True
 58
 59    To retrieve the information:
 60
 61    .. code-block:: python
 62
 63        # The static type of some_str is str.
 64        some_str = stash[some_str_key]
 65        # The static type of some_bool is bool.
 66        some_bool = stash[some_bool_key]
 67
 68    .. versionadded:: 7.0
 69    """
 70
 71    __slots__ = ("_storage",)
 72
 73    def __init__(self) -> None:
 74        self._storage: Dict[StashKey[Any], object] = {}
 75
 76    def __setitem__(self, key: StashKey[T], value: T) -> None:
 77        """Set a value for key."""
 78        self._storage[key] = value
 79
 80    def __getitem__(self, key: StashKey[T]) -> T:
 81        """Get the value for key.
 82
 83        Raises ``KeyError`` if the key wasn't set before.
 84        """
 85        return cast(T, self._storage[key])
 86
 87    def get(self, key: StashKey[T], default: D) -> Union[T, D]:
 88        """Get the value for key, or return default if the key wasn't set
 89        before."""
 90        try:
 91            return self[key]
 92        except KeyError:
 93            return default
 94
 95    def setdefault(self, key: StashKey[T], default: T) -> T:
 96        """Return the value of key if already set, otherwise set the value
 97        of key to default and return default."""
 98        try:
 99            return self[key]
100        except KeyError:
101            self[key] = default
102            return default
103
104    def __delitem__(self, key: StashKey[T]) -> None:
105        """Delete the value for key.
106
107        Raises ``KeyError`` if the key wasn't set before.
108        """
109        del self._storage[key]
110
111    def __contains__(self, key: StashKey[T]) -> bool:
112        """Return whether key was set."""
113        return key in self._storage
114
115    def __len__(self) -> int:
116        """Return how many items exist in the stash."""
117        return len(self._storage)

Stash is a type-safe heterogeneous mutable mapping that allows keys and value types to be defined separately from where it (the Stash) is created.

Usually you will be given an object which has a Stash, for example ~pytest.Config or a ~_pytest.nodes.Node:

stash: Stash = some_object.stash

If a module or plugin wants to store data in this Stash, it creates StashKey\s for its keys (at the module level):

# At the top-level of the module
some_str_key = StashKey[str]()
some_bool_key = StashKey[bool]()

To store information:

# Value type must match the key.
stash[some_str_key] = "value"
stash[some_bool_key] = True

To retrieve the information:

# The static type of some_str is str.
some_str = stash[some_str_key]
# The static type of some_bool is bool.
some_bool = stash[some_bool_key]

New in version 7.0.

def get(self, key: StashKey[~T], default: ~D) -> Union[~T, ~D]:
87    def get(self, key: StashKey[T], default: D) -> Union[T, D]:
88        """Get the value for key, or return default if the key wasn't set
89        before."""
90        try:
91            return self[key]
92        except KeyError:
93            return default

Get the value for key, or return default if the key wasn't set before.

def setdefault(self, key: StashKey[~T], default: ~T) -> ~T:
 95    def setdefault(self, key: StashKey[T], default: T) -> T:
 96        """Return the value of key if already set, otherwise set the value
 97        of key to default and return default."""
 98        try:
 99            return self[key]
100        except KeyError:
101            self[key] = default
102            return default

Return the value of key if already set, otherwise set the value of key to default and return default.

class StashKey(typing.Generic[~T]):
17class StashKey(Generic[T]):
18    """``StashKey`` is an object used as a key to a :class:`Stash`.
19
20    A ``StashKey`` is associated with the type ``T`` of the value of the key.
21
22    A ``StashKey`` is unique and cannot conflict with another key.
23
24    .. versionadded:: 7.0
25    """
26
27    __slots__ = ()

StashKey is an object used as a key to a Stash.

A StashKey is associated with the type T of the value of the key.

A StashKey is unique and cannot conflict with another key.

New in version 7.0.

version_tuple = (8, 2, 0)
@final
@dataclasses.dataclass
class TempdirFactory:
272@final
273@dataclasses.dataclass
274class TempdirFactory:
275    """Backward compatibility wrapper that implements ``py.path.local``
276    for :class:`TempPathFactory`.
277
278    .. note::
279        These days, it is preferred to use ``tmp_path_factory``.
280
281        :ref:`About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>`.
282
283    """
284
285    _tmppath_factory: TempPathFactory
286
287    def __init__(
288        self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False
289    ) -> None:
290        check_ispytest(_ispytest)
291        self._tmppath_factory = tmppath_factory
292
293    def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
294        """Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object."""
295        return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())
296
297    def getbasetemp(self) -> LEGACY_PATH:
298        """Same as :meth:`TempPathFactory.getbasetemp`, but returns a ``py.path.local`` object."""
299        return legacy_path(self._tmppath_factory.getbasetemp().resolve())

Backward compatibility wrapper that implements py.path.local for TempPathFactory.

These days, it is preferred to use tmp_path_factory.

:ref:About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>.

TempdirFactory( tmppath_factory: TempPathFactory, *, _ispytest: bool = False)
287    def __init__(
288        self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False
289    ) -> None:
290        check_ispytest(_ispytest)
291        self._tmppath_factory = tmppath_factory
def mktemp(self, basename: str, numbered: bool = True) -> _pytest._py.path.LocalPath:
293    def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH:
294        """Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object."""
295        return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve())

Same as TempPathFactory.mktemp(), but returns a py.path.local object.

def getbasetemp(self) -> _pytest._py.path.LocalPath:
297    def getbasetemp(self) -> LEGACY_PATH:
298        """Same as :meth:`TempPathFactory.getbasetemp`, but returns a ``py.path.local`` object."""
299        return legacy_path(self._tmppath_factory.getbasetemp().resolve())

Same as TempPathFactory.getbasetemp(), but returns a py.path.local object.

@final
@dataclasses.dataclass
class TempPathFactory:
 42@final
 43@dataclasses.dataclass
 44class TempPathFactory:
 45    """Factory for temporary directories under the common base temp directory.
 46
 47    The base directory can be configured using the ``--basetemp`` option.
 48    """
 49
 50    _given_basetemp: Optional[Path]
 51    # pluggy TagTracerSub, not currently exposed, so Any.
 52    _trace: Any
 53    _basetemp: Optional[Path]
 54    _retention_count: int
 55    _retention_policy: RetentionType
 56
 57    def __init__(
 58        self,
 59        given_basetemp: Optional[Path],
 60        retention_count: int,
 61        retention_policy: RetentionType,
 62        trace,
 63        basetemp: Optional[Path] = None,
 64        *,
 65        _ispytest: bool = False,
 66    ) -> None:
 67        check_ispytest(_ispytest)
 68        if given_basetemp is None:
 69            self._given_basetemp = None
 70        else:
 71            # Use os.path.abspath() to get absolute path instead of resolve() as it
 72            # does not work the same in all platforms (see #4427).
 73            # Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012).
 74            self._given_basetemp = Path(os.path.abspath(str(given_basetemp)))
 75        self._trace = trace
 76        self._retention_count = retention_count
 77        self._retention_policy = retention_policy
 78        self._basetemp = basetemp
 79
 80    @classmethod
 81    def from_config(
 82        cls,
 83        config: Config,
 84        *,
 85        _ispytest: bool = False,
 86    ) -> "TempPathFactory":
 87        """Create a factory according to pytest configuration.
 88
 89        :meta private:
 90        """
 91        check_ispytest(_ispytest)
 92        count = int(config.getini("tmp_path_retention_count"))
 93        if count < 0:
 94            raise ValueError(
 95                f"tmp_path_retention_count must be >= 0. Current input: {count}."
 96            )
 97
 98        policy = config.getini("tmp_path_retention_policy")
 99        if policy not in ("all", "failed", "none"):
100            raise ValueError(
101                f"tmp_path_retention_policy must be either all, failed, none. Current input: {policy}."
102            )
103
104        return cls(
105            given_basetemp=config.option.basetemp,
106            trace=config.trace.get("tmpdir"),
107            retention_count=count,
108            retention_policy=policy,
109            _ispytest=True,
110        )
111
112    def _ensure_relative_to_basetemp(self, basename: str) -> str:
113        basename = os.path.normpath(basename)
114        if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp():
115            raise ValueError(f"{basename} is not a normalized and relative path")
116        return basename
117
118    def mktemp(self, basename: str, numbered: bool = True) -> Path:
119        """Create a new temporary directory managed by the factory.
120
121        :param basename:
122            Directory base name, must be a relative path.
123
124        :param numbered:
125            If ``True``, ensure the directory is unique by adding a numbered
126            suffix greater than any existing one: ``basename="foo-"`` and ``numbered=True``
127            means that this function will create directories named ``"foo-0"``,
128            ``"foo-1"``, ``"foo-2"`` and so on.
129
130        :returns:
131            The path to the new directory.
132        """
133        basename = self._ensure_relative_to_basetemp(basename)
134        if not numbered:
135            p = self.getbasetemp().joinpath(basename)
136            p.mkdir(mode=0o700)
137        else:
138            p = make_numbered_dir(root=self.getbasetemp(), prefix=basename, mode=0o700)
139            self._trace("mktemp", p)
140        return p
141
142    def getbasetemp(self) -> Path:
143        """Return the base temporary directory, creating it if needed.
144
145        :returns:
146            The base temporary directory.
147        """
148        if self._basetemp is not None:
149            return self._basetemp
150
151        if self._given_basetemp is not None:
152            basetemp = self._given_basetemp
153            if basetemp.exists():
154                rm_rf(basetemp)
155            basetemp.mkdir(mode=0o700)
156            basetemp = basetemp.resolve()
157        else:
158            from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT")
159            temproot = Path(from_env or tempfile.gettempdir()).resolve()
160            user = get_user() or "unknown"
161            # use a sub-directory in the temproot to speed-up
162            # make_numbered_dir() call
163            rootdir = temproot.joinpath(f"pytest-of-{user}")
164            try:
165                rootdir.mkdir(mode=0o700, exist_ok=True)
166            except OSError:
167                # getuser() likely returned illegal characters for the platform, use unknown back off mechanism
168                rootdir = temproot.joinpath("pytest-of-unknown")
169                rootdir.mkdir(mode=0o700, exist_ok=True)
170            # Because we use exist_ok=True with a predictable name, make sure
171            # we are the owners, to prevent any funny business (on unix, where
172            # temproot is usually shared).
173            # Also, to keep things private, fixup any world-readable temp
174            # rootdir's permissions. Historically 0o755 was used, so we can't
175            # just error out on this, at least for a while.
176            uid = get_user_id()
177            if uid is not None:
178                rootdir_stat = rootdir.stat()
179                if rootdir_stat.st_uid != uid:
180                    raise OSError(
181                        f"The temporary directory {rootdir} is not owned by the current user. "
182                        "Fix this and try again."
183                    )
184                if (rootdir_stat.st_mode & 0o077) != 0:
185                    os.chmod(rootdir, rootdir_stat.st_mode & ~0o077)
186            keep = self._retention_count
187            if self._retention_policy == "none":
188                keep = 0
189            basetemp = make_numbered_dir_with_cleanup(
190                prefix="pytest-",
191                root=rootdir,
192                keep=keep,
193                lock_timeout=LOCK_TIMEOUT,
194                mode=0o700,
195            )
196        assert basetemp is not None, basetemp
197        self._basetemp = basetemp
198        self._trace("new basetemp", basetemp)
199        return basetemp

Factory for temporary directories under the common base temp directory.

The base directory can be configured using the --basetemp option.

TempPathFactory( given_basetemp: Optional[pathlib.Path], retention_count: int, retention_policy: Literal['all', 'failed', 'none'], trace, basetemp: Optional[pathlib.Path] = None, *, _ispytest: bool = False)
57    def __init__(
58        self,
59        given_basetemp: Optional[Path],
60        retention_count: int,
61        retention_policy: RetentionType,
62        trace,
63        basetemp: Optional[Path] = None,
64        *,
65        _ispytest: bool = False,
66    ) -> None:
67        check_ispytest(_ispytest)
68        if given_basetemp is None:
69            self._given_basetemp = None
70        else:
71            # Use os.path.abspath() to get absolute path instead of resolve() as it
72            # does not work the same in all platforms (see #4427).
73            # Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012).
74            self._given_basetemp = Path(os.path.abspath(str(given_basetemp)))
75        self._trace = trace
76        self._retention_count = retention_count
77        self._retention_policy = retention_policy
78        self._basetemp = basetemp
@classmethod
def from_config( cls, config: Config, *, _ispytest: bool = False) -> TempPathFactory:
 80    @classmethod
 81    def from_config(
 82        cls,
 83        config: Config,
 84        *,
 85        _ispytest: bool = False,
 86    ) -> "TempPathFactory":
 87        """Create a factory according to pytest configuration.
 88
 89        :meta private:
 90        """
 91        check_ispytest(_ispytest)
 92        count = int(config.getini("tmp_path_retention_count"))
 93        if count < 0:
 94            raise ValueError(
 95                f"tmp_path_retention_count must be >= 0. Current input: {count}."
 96            )
 97
 98        policy = config.getini("tmp_path_retention_policy")
 99        if policy not in ("all", "failed", "none"):
100            raise ValueError(
101                f"tmp_path_retention_policy must be either all, failed, none. Current input: {policy}."
102            )
103
104        return cls(
105            given_basetemp=config.option.basetemp,
106            trace=config.trace.get("tmpdir"),
107            retention_count=count,
108            retention_policy=policy,
109            _ispytest=True,
110        )

Create a factory according to pytest configuration.

:meta private:

def mktemp(self, basename: str, numbered: bool = True) -> pathlib.Path:
118    def mktemp(self, basename: str, numbered: bool = True) -> Path:
119        """Create a new temporary directory managed by the factory.
120
121        :param basename:
122            Directory base name, must be a relative path.
123
124        :param numbered:
125            If ``True``, ensure the directory is unique by adding a numbered
126            suffix greater than any existing one: ``basename="foo-"`` and ``numbered=True``
127            means that this function will create directories named ``"foo-0"``,
128            ``"foo-1"``, ``"foo-2"`` and so on.
129
130        :returns:
131            The path to the new directory.
132        """
133        basename = self._ensure_relative_to_basetemp(basename)
134        if not numbered:
135            p = self.getbasetemp().joinpath(basename)
136            p.mkdir(mode=0o700)
137        else:
138            p = make_numbered_dir(root=self.getbasetemp(), prefix=basename, mode=0o700)
139            self._trace("mktemp", p)
140        return p

Create a new temporary directory managed by the factory.

Parameters
  • basename: Directory base name, must be a relative path.

  • numbered: If True, ensure the directory is unique by adding a numbered suffix 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.

:returns: The path to the new directory.

def getbasetemp(self) -> pathlib.Path:
142    def getbasetemp(self) -> Path:
143        """Return the base temporary directory, creating it if needed.
144
145        :returns:
146            The base temporary directory.
147        """
148        if self._basetemp is not None:
149            return self._basetemp
150
151        if self._given_basetemp is not None:
152            basetemp = self._given_basetemp
153            if basetemp.exists():
154                rm_rf(basetemp)
155            basetemp.mkdir(mode=0o700)
156            basetemp = basetemp.resolve()
157        else:
158            from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT")
159            temproot = Path(from_env or tempfile.gettempdir()).resolve()
160            user = get_user() or "unknown"
161            # use a sub-directory in the temproot to speed-up
162            # make_numbered_dir() call
163            rootdir = temproot.joinpath(f"pytest-of-{user}")
164            try:
165                rootdir.mkdir(mode=0o700, exist_ok=True)
166            except OSError:
167                # getuser() likely returned illegal characters for the platform, use unknown back off mechanism
168                rootdir = temproot.joinpath("pytest-of-unknown")
169                rootdir.mkdir(mode=0o700, exist_ok=True)
170            # Because we use exist_ok=True with a predictable name, make sure
171            # we are the owners, to prevent any funny business (on unix, where
172            # temproot is usually shared).
173            # Also, to keep things private, fixup any world-readable temp
174            # rootdir's permissions. Historically 0o755 was used, so we can't
175            # just error out on this, at least for a while.
176            uid = get_user_id()
177            if uid is not None:
178                rootdir_stat = rootdir.stat()
179                if rootdir_stat.st_uid != uid:
180                    raise OSError(
181                        f"The temporary directory {rootdir} is not owned by the current user. "
182                        "Fix this and try again."
183                    )
184                if (rootdir_stat.st_mode & 0o077) != 0:
185                    os.chmod(rootdir, rootdir_stat.st_mode & ~0o077)
186            keep = self._retention_count
187            if self._retention_policy == "none":
188                keep = 0
189            basetemp = make_numbered_dir_with_cleanup(
190                prefix="pytest-",
191                root=rootdir,
192                keep=keep,
193                lock_timeout=LOCK_TIMEOUT,
194                mode=0o700,
195            )
196        assert basetemp is not None, basetemp
197        self._basetemp = basetemp
198        self._trace("new basetemp", basetemp)
199        return basetemp

Return the base temporary directory, creating it if needed.

:returns: The base temporary directory.

@final
class Testdir:
 43@final
 44class Testdir:
 45    """
 46    Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead.
 47
 48    All methods just forward to an internal :class:`Pytester` instance, converting results
 49    to `legacy_path` objects as necessary.
 50    """
 51
 52    __test__ = False
 53
 54    CLOSE_STDIN: "Final" = Pytester.CLOSE_STDIN
 55    TimeoutExpired: "Final" = Pytester.TimeoutExpired
 56
 57    def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None:
 58        check_ispytest(_ispytest)
 59        self._pytester = pytester
 60
 61    @property
 62    def tmpdir(self) -> LEGACY_PATH:
 63        """Temporary directory where tests are executed."""
 64        return legacy_path(self._pytester.path)
 65
 66    @property
 67    def test_tmproot(self) -> LEGACY_PATH:
 68        return legacy_path(self._pytester._test_tmproot)
 69
 70    @property
 71    def request(self):
 72        return self._pytester._request
 73
 74    @property
 75    def plugins(self):
 76        return self._pytester.plugins
 77
 78    @plugins.setter
 79    def plugins(self, plugins):
 80        self._pytester.plugins = plugins
 81
 82    @property
 83    def monkeypatch(self) -> MonkeyPatch:
 84        return self._pytester._monkeypatch
 85
 86    def make_hook_recorder(self, pluginmanager) -> HookRecorder:
 87        """See :meth:`Pytester.make_hook_recorder`."""
 88        return self._pytester.make_hook_recorder(pluginmanager)
 89
 90    def chdir(self) -> None:
 91        """See :meth:`Pytester.chdir`."""
 92        return self._pytester.chdir()
 93
 94    def finalize(self) -> None:
 95        return self._pytester._finalize()
 96
 97    def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH:
 98        """See :meth:`Pytester.makefile`."""
 99        if ext and not ext.startswith("."):
100            # pytester.makefile is going to throw a ValueError in a way that
101            # testdir.makefile did not, because
102            # pathlib.Path is stricter suffixes than py.path
103            # This ext arguments is likely user error, but since testdir has
104            # allowed this, we will prepend "." as a workaround to avoid breaking
105            # testdir usage that worked before
106            ext = "." + ext
107        return legacy_path(self._pytester.makefile(ext, *args, **kwargs))
108
109    def makeconftest(self, source) -> LEGACY_PATH:
110        """See :meth:`Pytester.makeconftest`."""
111        return legacy_path(self._pytester.makeconftest(source))
112
113    def makeini(self, source) -> LEGACY_PATH:
114        """See :meth:`Pytester.makeini`."""
115        return legacy_path(self._pytester.makeini(source))
116
117    def getinicfg(self, source: str) -> SectionWrapper:
118        """See :meth:`Pytester.getinicfg`."""
119        return self._pytester.getinicfg(source)
120
121    def makepyprojecttoml(self, source) -> LEGACY_PATH:
122        """See :meth:`Pytester.makepyprojecttoml`."""
123        return legacy_path(self._pytester.makepyprojecttoml(source))
124
125    def makepyfile(self, *args, **kwargs) -> LEGACY_PATH:
126        """See :meth:`Pytester.makepyfile`."""
127        return legacy_path(self._pytester.makepyfile(*args, **kwargs))
128
129    def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH:
130        """See :meth:`Pytester.maketxtfile`."""
131        return legacy_path(self._pytester.maketxtfile(*args, **kwargs))
132
133    def syspathinsert(self, path=None) -> None:
134        """See :meth:`Pytester.syspathinsert`."""
135        return self._pytester.syspathinsert(path)
136
137    def mkdir(self, name) -> LEGACY_PATH:
138        """See :meth:`Pytester.mkdir`."""
139        return legacy_path(self._pytester.mkdir(name))
140
141    def mkpydir(self, name) -> LEGACY_PATH:
142        """See :meth:`Pytester.mkpydir`."""
143        return legacy_path(self._pytester.mkpydir(name))
144
145    def copy_example(self, name=None) -> LEGACY_PATH:
146        """See :meth:`Pytester.copy_example`."""
147        return legacy_path(self._pytester.copy_example(name))
148
149    def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]:
150        """See :meth:`Pytester.getnode`."""
151        return self._pytester.getnode(config, arg)
152
153    def getpathnode(self, path):
154        """See :meth:`Pytester.getpathnode`."""
155        return self._pytester.getpathnode(path)
156
157    def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]:
158        """See :meth:`Pytester.genitems`."""
159        return self._pytester.genitems(colitems)
160
161    def runitem(self, source):
162        """See :meth:`Pytester.runitem`."""
163        return self._pytester.runitem(source)
164
165    def inline_runsource(self, source, *cmdlineargs):
166        """See :meth:`Pytester.inline_runsource`."""
167        return self._pytester.inline_runsource(source, *cmdlineargs)
168
169    def inline_genitems(self, *args):
170        """See :meth:`Pytester.inline_genitems`."""
171        return self._pytester.inline_genitems(*args)
172
173    def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
174        """See :meth:`Pytester.inline_run`."""
175        return self._pytester.inline_run(
176            *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc
177        )
178
179    def runpytest_inprocess(self, *args, **kwargs) -> RunResult:
180        """See :meth:`Pytester.runpytest_inprocess`."""
181        return self._pytester.runpytest_inprocess(*args, **kwargs)
182
183    def runpytest(self, *args, **kwargs) -> RunResult:
184        """See :meth:`Pytester.runpytest`."""
185        return self._pytester.runpytest(*args, **kwargs)
186
187    def parseconfig(self, *args) -> Config:
188        """See :meth:`Pytester.parseconfig`."""
189        return self._pytester.parseconfig(*args)
190
191    def parseconfigure(self, *args) -> Config:
192        """See :meth:`Pytester.parseconfigure`."""
193        return self._pytester.parseconfigure(*args)
194
195    def getitem(self, source, funcname="test_func"):
196        """See :meth:`Pytester.getitem`."""
197        return self._pytester.getitem(source, funcname)
198
199    def getitems(self, source):
200        """See :meth:`Pytester.getitems`."""
201        return self._pytester.getitems(source)
202
203    def getmodulecol(self, source, configargs=(), withinit=False):
204        """See :meth:`Pytester.getmodulecol`."""
205        return self._pytester.getmodulecol(
206            source, configargs=configargs, withinit=withinit
207        )
208
209    def collect_by_name(
210        self, modcol: Collector, name: str
211    ) -> Optional[Union[Item, Collector]]:
212        """See :meth:`Pytester.collect_by_name`."""
213        return self._pytester.collect_by_name(modcol, name)
214
215    def popen(
216        self,
217        cmdargs,
218        stdout=subprocess.PIPE,
219        stderr=subprocess.PIPE,
220        stdin=CLOSE_STDIN,
221        **kw,
222    ):
223        """See :meth:`Pytester.popen`."""
224        return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw)
225
226    def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult:
227        """See :meth:`Pytester.run`."""
228        return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin)
229
230    def runpython(self, script) -> RunResult:
231        """See :meth:`Pytester.runpython`."""
232        return self._pytester.runpython(script)
233
234    def runpython_c(self, command):
235        """See :meth:`Pytester.runpython_c`."""
236        return self._pytester.runpython_c(command)
237
238    def runpytest_subprocess(self, *args, timeout=None) -> RunResult:
239        """See :meth:`Pytester.runpytest_subprocess`."""
240        return self._pytester.runpytest_subprocess(*args, timeout=timeout)
241
242    def spawn_pytest(
243        self, string: str, expect_timeout: float = 10.0
244    ) -> "pexpect.spawn":
245        """See :meth:`Pytester.spawn_pytest`."""
246        return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout)
247
248    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
249        """See :meth:`Pytester.spawn`."""
250        return self._pytester.spawn(cmd, expect_timeout=expect_timeout)
251
252    def __repr__(self) -> str:
253        return f"<Testdir {self.tmpdir!r}>"
254
255    def __str__(self) -> str:
256        return str(self.tmpdir)

Similar to Pytester, but this class works with legacy legacy_path objects instead.

All methods just forward to an internal Pytester instance, converting results to legacy_path objects as necessary.

Testdir(pytester: Pytester, *, _ispytest: bool = False)
57    def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None:
58        check_ispytest(_ispytest)
59        self._pytester = pytester
CLOSE_STDIN: Final = <NotSetType.token: 0>
tmpdir: _pytest._py.path.LocalPath
61    @property
62    def tmpdir(self) -> LEGACY_PATH:
63        """Temporary directory where tests are executed."""
64        return legacy_path(self._pytester.path)

Temporary directory where tests are executed.

test_tmproot: _pytest._py.path.LocalPath
66    @property
67    def test_tmproot(self) -> LEGACY_PATH:
68        return legacy_path(self._pytester._test_tmproot)
request
70    @property
71    def request(self):
72        return self._pytester._request
plugins
74    @property
75    def plugins(self):
76        return self._pytester.plugins
monkeypatch: MonkeyPatch
82    @property
83    def monkeypatch(self) -> MonkeyPatch:
84        return self._pytester._monkeypatch
def make_hook_recorder(self, pluginmanager) -> HookRecorder:
86    def make_hook_recorder(self, pluginmanager) -> HookRecorder:
87        """See :meth:`Pytester.make_hook_recorder`."""
88        return self._pytester.make_hook_recorder(pluginmanager)
def chdir(self) -> None:
90    def chdir(self) -> None:
91        """See :meth:`Pytester.chdir`."""
92        return self._pytester.chdir()
def finalize(self) -> None:
94    def finalize(self) -> None:
95        return self._pytester._finalize()
def makefile(self, ext, *args, **kwargs) -> _pytest._py.path.LocalPath:
 97    def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH:
 98        """See :meth:`Pytester.makefile`."""
 99        if ext and not ext.startswith("."):
100            # pytester.makefile is going to throw a ValueError in a way that
101            # testdir.makefile did not, because
102            # pathlib.Path is stricter suffixes than py.path
103            # This ext arguments is likely user error, but since testdir has
104            # allowed this, we will prepend "." as a workaround to avoid breaking
105            # testdir usage that worked before
106            ext = "." + ext
107        return legacy_path(self._pytester.makefile(ext, *args, **kwargs))
def makeconftest(self, source) -> _pytest._py.path.LocalPath:
109    def makeconftest(self, source) -> LEGACY_PATH:
110        """See :meth:`Pytester.makeconftest`."""
111        return legacy_path(self._pytester.makeconftest(source))
def makeini(self, source) -> _pytest._py.path.LocalPath:
113    def makeini(self, source) -> LEGACY_PATH:
114        """See :meth:`Pytester.makeini`."""
115        return legacy_path(self._pytester.makeini(source))
def getinicfg(self, source: str) -> iniconfig.SectionWrapper:
117    def getinicfg(self, source: str) -> SectionWrapper:
118        """See :meth:`Pytester.getinicfg`."""
119        return self._pytester.getinicfg(source)
def makepyprojecttoml(self, source) -> _pytest._py.path.LocalPath:
121    def makepyprojecttoml(self, source) -> LEGACY_PATH:
122        """See :meth:`Pytester.makepyprojecttoml`."""
123        return legacy_path(self._pytester.makepyprojecttoml(source))
def makepyfile(self, *args, **kwargs) -> _pytest._py.path.LocalPath:
125    def makepyfile(self, *args, **kwargs) -> LEGACY_PATH:
126        """See :meth:`Pytester.makepyfile`."""
127        return legacy_path(self._pytester.makepyfile(*args, **kwargs))
def maketxtfile(self, *args, **kwargs) -> _pytest._py.path.LocalPath:
129    def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH:
130        """See :meth:`Pytester.maketxtfile`."""
131        return legacy_path(self._pytester.maketxtfile(*args, **kwargs))
def syspathinsert(self, path=None) -> None:
133    def syspathinsert(self, path=None) -> None:
134        """See :meth:`Pytester.syspathinsert`."""
135        return self._pytester.syspathinsert(path)
def mkdir(self, name) -> _pytest._py.path.LocalPath:
137    def mkdir(self, name) -> LEGACY_PATH:
138        """See :meth:`Pytester.mkdir`."""
139        return legacy_path(self._pytester.mkdir(name))
def mkpydir(self, name) -> _pytest._py.path.LocalPath:
141    def mkpydir(self, name) -> LEGACY_PATH:
142        """See :meth:`Pytester.mkpydir`."""
143        return legacy_path(self._pytester.mkpydir(name))
def copy_example(self, name=None) -> _pytest._py.path.LocalPath:
145    def copy_example(self, name=None) -> LEGACY_PATH:
146        """See :meth:`Pytester.copy_example`."""
147        return legacy_path(self._pytester.copy_example(name))
def getnode( self, config: Config, arg) -> Union[Item, Collector, NoneType]:
149    def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]:
150        """See :meth:`Pytester.getnode`."""
151        return self._pytester.getnode(config, arg)
def getpathnode(self, path):
153    def getpathnode(self, path):
154        """See :meth:`Pytester.getpathnode`."""
155        return self._pytester.getpathnode(path)
def genitems( self, colitems: List[Union[Item, Collector]]) -> List[Item]:
157    def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]:
158        """See :meth:`Pytester.genitems`."""
159        return self._pytester.genitems(colitems)
def runitem(self, source):
161    def runitem(self, source):
162        """See :meth:`Pytester.runitem`."""
163        return self._pytester.runitem(source)
def inline_runsource(self, source, *cmdlineargs):
165    def inline_runsource(self, source, *cmdlineargs):
166        """See :meth:`Pytester.inline_runsource`."""
167        return self._pytester.inline_runsource(source, *cmdlineargs)
def inline_genitems(self, *args):
169    def inline_genitems(self, *args):
170        """See :meth:`Pytester.inline_genitems`."""
171        return self._pytester.inline_genitems(*args)
def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
173    def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
174        """See :meth:`Pytester.inline_run`."""
175        return self._pytester.inline_run(
176            *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc
177        )
def runpytest_inprocess(self, *args, **kwargs) -> RunResult:
179    def runpytest_inprocess(self, *args, **kwargs) -> RunResult:
180        """See :meth:`Pytester.runpytest_inprocess`."""
181        return self._pytester.runpytest_inprocess(*args, **kwargs)
def runpytest(self, *args, **kwargs) -> RunResult:
183    def runpytest(self, *args, **kwargs) -> RunResult:
184        """See :meth:`Pytester.runpytest`."""
185        return self._pytester.runpytest(*args, **kwargs)
def parseconfig(self, *args) -> Config:
187    def parseconfig(self, *args) -> Config:
188        """See :meth:`Pytester.parseconfig`."""
189        return self._pytester.parseconfig(*args)
def parseconfigure(self, *args) -> Config:
191    def parseconfigure(self, *args) -> Config:
192        """See :meth:`Pytester.parseconfigure`."""
193        return self._pytester.parseconfigure(*args)
def getitem(self, source, funcname='test_func'):
195    def getitem(self, source, funcname="test_func"):
196        """See :meth:`Pytester.getitem`."""
197        return self._pytester.getitem(source, funcname)
def getitems(self, source):
199    def getitems(self, source):
200        """See :meth:`Pytester.getitems`."""
201        return self._pytester.getitems(source)
def getmodulecol(self, source, configargs=(), withinit=False):
203    def getmodulecol(self, source, configargs=(), withinit=False):
204        """See :meth:`Pytester.getmodulecol`."""
205        return self._pytester.getmodulecol(
206            source, configargs=configargs, withinit=withinit
207        )
def collect_by_name( self, modcol: Collector, name: str) -> Union[Item, Collector, NoneType]:
209    def collect_by_name(
210        self, modcol: Collector, name: str
211    ) -> Optional[Union[Item, Collector]]:
212        """See :meth:`Pytester.collect_by_name`."""
213        return self._pytester.collect_by_name(modcol, name)
def popen( self, cmdargs, stdout=-1, stderr=-1, stdin=<NotSetType.token: 0>, **kw):
215    def popen(
216        self,
217        cmdargs,
218        stdout=subprocess.PIPE,
219        stderr=subprocess.PIPE,
220        stdin=CLOSE_STDIN,
221        **kw,
222    ):
223        """See :meth:`Pytester.popen`."""
224        return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw)
def run( self, *cmdargs, timeout=None, stdin=<NotSetType.token: 0>) -> RunResult:
226    def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult:
227        """See :meth:`Pytester.run`."""
228        return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin)
def runpython(self, script) -> RunResult:
230    def runpython(self, script) -> RunResult:
231        """See :meth:`Pytester.runpython`."""
232        return self._pytester.runpython(script)
def runpython_c(self, command):
234    def runpython_c(self, command):
235        """See :meth:`Pytester.runpython_c`."""
236        return self._pytester.runpython_c(command)
def runpytest_subprocess(self, *args, timeout=None) -> RunResult:
238    def runpytest_subprocess(self, *args, timeout=None) -> RunResult:
239        """See :meth:`Pytester.runpytest_subprocess`."""
240        return self._pytester.runpytest_subprocess(*args, timeout=timeout)
def spawn_pytest( self, string: str, expect_timeout: float = 10.0) -> pexpect.pty_spawn.spawn:
242    def spawn_pytest(
243        self, string: str, expect_timeout: float = 10.0
244    ) -> "pexpect.spawn":
245        """See :meth:`Pytester.spawn_pytest`."""
246        return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout)
def spawn(self, cmd: str, expect_timeout: float = 10.0) -> pexpect.pty_spawn.spawn:
248    def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn":
249        """See :meth:`Pytester.spawn`."""
250        return self._pytester.spawn(cmd, expect_timeout=expect_timeout)
class Testdir.TimeoutExpired(builtins.Exception):
664    class TimeoutExpired(Exception):
665        pass

Common base class for all non-exit exceptions.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
@final
class TestReport(_pytest.reports.BaseReport):
244@final
245class TestReport(BaseReport):
246    """Basic test report object (also used for setup and teardown calls if
247    they fail).
248
249    Reports can contain arbitrary extra attributes.
250    """
251
252    __test__ = False
253    # Defined by skipping plugin.
254    # xfail reason if xfailed, otherwise not defined. Use hasattr to distinguish.
255    wasxfail: str
256
257    def __init__(
258        self,
259        nodeid: str,
260        location: Tuple[str, Optional[int], str],
261        keywords: Mapping[str, Any],
262        outcome: Literal["passed", "failed", "skipped"],
263        longrepr: Union[
264            None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr
265        ],
266        when: Literal["setup", "call", "teardown"],
267        sections: Iterable[Tuple[str, str]] = (),
268        duration: float = 0,
269        start: float = 0,
270        stop: float = 0,
271        user_properties: Optional[Iterable[Tuple[str, object]]] = None,
272        **extra,
273    ) -> None:
274        #: Normalized collection nodeid.
275        self.nodeid = nodeid
276
277        #: A (filesystempath, lineno, domaininfo) tuple indicating the
278        #: actual location of a test item - it might be different from the
279        #: collected one e.g. if a method is inherited from a different module.
280        #: The filesystempath may be relative to ``config.rootdir``.
281        #: The line number is 0-based.
282        self.location: Tuple[str, Optional[int], str] = location
283
284        #: A name -> value dictionary containing all keywords and
285        #: markers associated with a test invocation.
286        self.keywords: Mapping[str, Any] = keywords
287
288        #: Test outcome, always one of "passed", "failed", "skipped".
289        self.outcome = outcome
290
291        #: None or a failure representation.
292        self.longrepr = longrepr
293
294        #: One of 'setup', 'call', 'teardown' to indicate runtest phase.
295        self.when = when
296
297        #: User properties is a list of tuples (name, value) that holds user
298        #: defined properties of the test.
299        self.user_properties = list(user_properties or [])
300
301        #: Tuples of str ``(heading, content)`` with extra information
302        #: for the test report. Used by pytest to add text captured
303        #: from ``stdout``, ``stderr``, and intercepted logging events. May
304        #: be used by other plugins to add arbitrary information to reports.
305        self.sections = list(sections)
306
307        #: Time it took to run just the test.
308        self.duration: float = duration
309
310        #: The system time when the call started, in seconds since the epoch.
311        self.start: float = start
312        #: The system time when the call ended, in seconds since the epoch.
313        self.stop: float = stop
314
315        self.__dict__.update(extra)
316
317    def __repr__(self) -> str:
318        return f"<{self.__class__.__name__} {self.nodeid!r} when={self.when!r} outcome={self.outcome!r}>"
319
320    @classmethod
321    def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport":
322        """Create and fill a TestReport with standard item and call info.
323
324        :param item: The item.
325        :param call: The call info.
326        """
327        when = call.when
328        # Remove "collect" from the Literal type -- only for collection calls.
329        assert when != "collect"
330        duration = call.duration
331        start = call.start
332        stop = call.stop
333        keywords = {x: 1 for x in item.keywords}
334        excinfo = call.excinfo
335        sections = []
336        if not call.excinfo:
337            outcome: Literal["passed", "failed", "skipped"] = "passed"
338            longrepr: Union[
339                None,
340                ExceptionInfo[BaseException],
341                Tuple[str, int, str],
342                str,
343                TerminalRepr,
344            ] = None
345        else:
346            if not isinstance(excinfo, ExceptionInfo):
347                outcome = "failed"
348                longrepr = excinfo
349            elif isinstance(excinfo.value, skip.Exception):
350                outcome = "skipped"
351                r = excinfo._getreprcrash()
352                assert (
353                    r is not None
354                ), "There should always be a traceback entry for skipping a test."
355                if excinfo.value._use_item_location:
356                    path, line = item.reportinfo()[:2]
357                    assert line is not None
358                    longrepr = os.fspath(path), line + 1, r.message
359                else:
360                    longrepr = (str(r.path), r.lineno, r.message)
361            else:
362                outcome = "failed"
363                if call.when == "call":
364                    longrepr = item.repr_failure(excinfo)
365                else:  # exception in setup or teardown
366                    longrepr = item._repr_failure_py(
367                        excinfo, style=item.config.getoption("tbstyle", "auto")
368                    )
369        for rwhen, key, content in item._report_sections:
370            sections.append((f"Captured {key} {rwhen}", content))
371        return cls(
372            item.nodeid,
373            item.location,
374            keywords,
375            outcome,
376            longrepr,
377            when,
378            sections,
379            duration,
380            start,
381            stop,
382            user_properties=item.user_properties,
383        )

Basic test report object (also used for setup and teardown calls if they fail).

Reports can contain arbitrary extra attributes.

TestReport( nodeid: str, location: Tuple[str, Optional[int], str], keywords: Mapping[str, Any], outcome: Literal['passed', 'failed', 'skipped'], longrepr: Union[NoneType, ExceptionInfo[BaseException], Tuple[str, int, str], str, _pytest._code.code.TerminalRepr], when: Literal['setup', 'call', 'teardown'], sections: Iterable[Tuple[str, str]] = (), duration: float = 0, start: float = 0, stop: float = 0, user_properties: Optional[Iterable[Tuple[str, object]]] = None, **extra)
257    def __init__(
258        self,
259        nodeid: str,
260        location: Tuple[str, Optional[int], str],
261        keywords: Mapping[str, Any],
262        outcome: Literal["passed", "failed", "skipped"],
263        longrepr: Union[
264            None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr
265        ],
266        when: Literal["setup", "call", "teardown"],
267        sections: Iterable[Tuple[str, str]] = (),
268        duration: float = 0,
269        start: float = 0,
270        stop: float = 0,
271        user_properties: Optional[Iterable[Tuple[str, object]]] = None,
272        **extra,
273    ) -> None:
274        #: Normalized collection nodeid.
275        self.nodeid = nodeid
276
277        #: A (filesystempath, lineno, domaininfo) tuple indicating the
278        #: actual location of a test item - it might be different from the
279        #: collected one e.g. if a method is inherited from a different module.
280        #: The filesystempath may be relative to ``config.rootdir``.
281        #: The line number is 0-based.
282        self.location: Tuple[str, Optional[int], str] = location
283
284        #: A name -> value dictionary containing all keywords and
285        #: markers associated with a test invocation.
286        self.keywords: Mapping[str, Any] = keywords
287
288        #: Test outcome, always one of "passed", "failed", "skipped".
289        self.outcome = outcome
290
291        #: None or a failure representation.
292        self.longrepr = longrepr
293
294        #: One of 'setup', 'call', 'teardown' to indicate runtest phase.
295        self.when = when
296
297        #: User properties is a list of tuples (name, value) that holds user
298        #: defined properties of the test.
299        self.user_properties = list(user_properties or [])
300
301        #: Tuples of str ``(heading, content)`` with extra information
302        #: for the test report. Used by pytest to add text captured
303        #: from ``stdout``, ``stderr``, and intercepted logging events. May
304        #: be used by other plugins to add arbitrary information to reports.
305        self.sections = list(sections)
306
307        #: Time it took to run just the test.
308        self.duration: float = duration
309
310        #: The system time when the call started, in seconds since the epoch.
311        self.start: float = start
312        #: The system time when the call ended, in seconds since the epoch.
313        self.stop: float = stop
314
315        self.__dict__.update(extra)
wasxfail: str
nodeid
location: Tuple[str, Optional[int], str]
keywords: Mapping[str, Any]
outcome
longrepr
when
user_properties
sections
duration: float
start: float
stop: float
@classmethod
def from_item_and_call( cls, item: Item, call: CallInfo[NoneType]) -> TestReport:
320    @classmethod
321    def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport":
322        """Create and fill a TestReport with standard item and call info.
323
324        :param item: The item.
325        :param call: The call info.
326        """
327        when = call.when
328        # Remove "collect" from the Literal type -- only for collection calls.
329        assert when != "collect"
330        duration = call.duration
331        start = call.start
332        stop = call.stop
333        keywords = {x: 1 for x in item.keywords}
334        excinfo = call.excinfo
335        sections = []
336        if not call.excinfo:
337            outcome: Literal["passed", "failed", "skipped"] = "passed"
338            longrepr: Union[
339                None,
340                ExceptionInfo[BaseException],
341                Tuple[str, int, str],
342                str,
343                TerminalRepr,
344            ] = None
345        else:
346            if not isinstance(excinfo, ExceptionInfo):
347                outcome = "failed"
348                longrepr = excinfo
349            elif isinstance(excinfo.value, skip.Exception):
350                outcome = "skipped"
351                r = excinfo._getreprcrash()
352                assert (
353                    r is not None
354                ), "There should always be a traceback entry for skipping a test."
355                if excinfo.value._use_item_location:
356                    path, line = item.reportinfo()[:2]
357                    assert line is not None
358                    longrepr = os.fspath(path), line + 1, r.message
359                else:
360                    longrepr = (str(r.path), r.lineno, r.message)
361            else:
362                outcome = "failed"
363                if call.when == "call":
364                    longrepr = item.repr_failure(excinfo)
365                else:  # exception in setup or teardown
366                    longrepr = item._repr_failure_py(
367                        excinfo, style=item.config.getoption("tbstyle", "auto")
368                    )
369        for rwhen, key, content in item._report_sections:
370            sections.append((f"Captured {key} {rwhen}", content))
371        return cls(
372            item.nodeid,
373            item.location,
374            keywords,
375            outcome,
376            longrepr,
377            when,
378            sections,
379            duration,
380            start,
381            stop,
382            user_properties=item.user_properties,
383        )

Create and fill a TestReport with standard item and call info.

Parameters
  • item: The item.
  • call: The call info.
Inherited Members
_pytest.reports.BaseReport
toterminal
get_sections
longreprtext
caplog
capstdout
capstderr
passed
failed
skipped
fspath
count_towards_summary
head_line
class TestShortLogReport(typing.NamedTuple):
118class TestShortLogReport(NamedTuple):
119    """Used to store the test status result category, shortletter and verbose word.
120    For example ``"rerun", "R", ("RERUN", {"yellow": True})``.
121
122    :ivar category:
123        The class of result, for example ``“passed”``, ``“skipped”``, ``“error”``, or the empty string.
124
125    :ivar letter:
126        The short letter shown as testing progresses, for example ``"."``, ``"s"``, ``"E"``, or the empty string.
127
128    :ivar word:
129        Verbose word is shown as testing progresses in verbose mode, for example ``"PASSED"``, ``"SKIPPED"``,
130        ``"ERROR"``, or the empty string.
131    """
132
133    category: str
134    letter: str
135    word: Union[str, Tuple[str, Mapping[str, bool]]]

Used to store the test status result category, shortletter and verbose word. For example "rerun", "R", ("RERUN", {"yellow": True}).

:ivar category: The class of result, for example “passed”, “skipped”, “error”, or the empty string.

:ivar letter: The short letter shown as testing progresses, for example ".", "s", "E", or the empty string.

:ivar word: Verbose word is shown as testing progresses in verbose mode, for example "PASSED", "SKIPPED", "ERROR", or the empty string.

TestShortLogReport( category: str, letter: str, word: Union[str, Tuple[str, Mapping[str, bool]]])

Create new instance of TestShortLogReport(category, letter, word)

category: str

Alias for field number 0

letter: str

Alias for field number 1

word: Union[str, Tuple[str, Mapping[str, bool]]]

Alias for field number 2

Inherited Members
builtins.tuple
index
count
@final
class UsageError(builtins.Exception):
5@final
6class UsageError(Exception):
7    """Error in pytest usage or invocation."""

Error in pytest usage or invocation.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
class WarningsRecorder(warnings.catch_warnings):
170class WarningsRecorder(warnings.catch_warnings):  # type:ignore[type-arg]
171    """A context manager to record raised warnings.
172
173    Each recorded warning is an instance of :class:`warnings.WarningMessage`.
174
175    Adapted from `warnings.catch_warnings`.
176
177    .. note::
178        ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
179        differently; see :ref:`ensuring_function_triggers`.
180
181    """
182
183    def __init__(self, *, _ispytest: bool = False) -> None:
184        check_ispytest(_ispytest)
185        super().__init__(record=True)
186        self._entered = False
187        self._list: List[warnings.WarningMessage] = []
188
189    @property
190    def list(self) -> List["warnings.WarningMessage"]:
191        """The list of recorded warnings."""
192        return self._list
193
194    def __getitem__(self, i: int) -> "warnings.WarningMessage":
195        """Get a recorded warning by index."""
196        return self._list[i]
197
198    def __iter__(self) -> Iterator["warnings.WarningMessage"]:
199        """Iterate through the recorded warnings."""
200        return iter(self._list)
201
202    def __len__(self) -> int:
203        """The number of recorded warnings."""
204        return len(self._list)
205
206    def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
207        """Pop the first recorded warning which is an instance of ``cls``,
208        but not an instance of a child class of any other match.
209        Raises ``AssertionError`` if there is no match.
210        """
211        best_idx: Optional[int] = None
212        for i, w in enumerate(self._list):
213            if w.category == cls:
214                return self._list.pop(i)  # exact match, stop looking
215            if issubclass(w.category, cls) and (
216                best_idx is None
217                or not issubclass(w.category, self._list[best_idx].category)
218            ):
219                best_idx = i
220        if best_idx is not None:
221            return self._list.pop(best_idx)
222        __tracebackhide__ = True
223        raise AssertionError(f"{cls!r} not found in warning list")
224
225    def clear(self) -> None:
226        """Clear the list of recorded warnings."""
227        self._list[:] = []
228
229    # Type ignored because it doesn't exactly warnings.catch_warnings.__enter__
230    # -- it returns a List but we only emulate one.
231    def __enter__(self) -> "WarningsRecorder":  # type: ignore
232        if self._entered:
233            __tracebackhide__ = True
234            raise RuntimeError(f"Cannot enter {self!r} twice")
235        _list = super().__enter__()
236        # record=True means it's None.
237        assert _list is not None
238        self._list = _list
239        warnings.simplefilter("always")
240        return self
241
242    def __exit__(
243        self,
244        exc_type: Optional[Type[BaseException]],
245        exc_val: Optional[BaseException],
246        exc_tb: Optional[TracebackType],
247    ) -> None:
248        if not self._entered:
249            __tracebackhide__ = True
250            raise RuntimeError(f"Cannot exit {self!r} without entering first")
251
252        super().__exit__(exc_type, exc_val, exc_tb)
253
254        # Built-in catch_warnings does not reset entered state so we do it
255        # manually here for this context manager to become reusable.
256        self._entered = False

A context manager to record raised warnings.

Each recorded warning is an instance of warnings.WarningMessage.

Adapted from warnings.catch_warnings.

DeprecationWarning and PendingDeprecationWarning are treated differently; see :ref:ensuring_function_triggers.

WarningsRecorder(*, _ispytest: bool = False)
183    def __init__(self, *, _ispytest: bool = False) -> None:
184        check_ispytest(_ispytest)
185        super().__init__(record=True)
186        self._entered = False
187        self._list: List[warnings.WarningMessage] = []

Specify whether to record warnings and if an alternative module should be used other than sys.modules['warnings'].

For compatibility with Python 3.0, please consider all arguments to be keyword-only.

list: List[warnings.WarningMessage]
189    @property
190    def list(self) -> List["warnings.WarningMessage"]:
191        """The list of recorded warnings."""
192        return self._list

The list of recorded warnings.

def pop(self, cls: Type[Warning] = <class 'Warning'>) -> warnings.WarningMessage:
206    def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage":
207        """Pop the first recorded warning which is an instance of ``cls``,
208        but not an instance of a child class of any other match.
209        Raises ``AssertionError`` if there is no match.
210        """
211        best_idx: Optional[int] = None
212        for i, w in enumerate(self._list):
213            if w.category == cls:
214                return self._list.pop(i)  # exact match, stop looking
215            if issubclass(w.category, cls) and (
216                best_idx is None
217                or not issubclass(w.category, self._list[best_idx].category)
218            ):
219                best_idx = i
220        if best_idx is not None:
221            return self._list.pop(best_idx)
222        __tracebackhide__ = True
223        raise AssertionError(f"{cls!r} not found in warning list")

Pop the first recorded warning which is an instance of cls, but not an instance of a child class of any other match. Raises AssertionError if there is no match.

def clear(self) -> None:
225    def clear(self) -> None:
226        """Clear the list of recorded warnings."""
227        self._list[:] = []

Clear the list of recorded warnings.

def warns( expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = <class 'Warning'>, *args: Any, match: Union[str, Pattern[str], NoneType] = None, **kwargs: Any) -> Union[_pytest.recwarn.WarningsChecker, Any]:
106def warns(
107    expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = Warning,
108    *args: Any,
109    match: Optional[Union[str, Pattern[str]]] = None,
110    **kwargs: Any,
111) -> Union["WarningsChecker", Any]:
112    r"""Assert that code raises a particular class of warning.
113
114    Specifically, the parameter ``expected_warning`` can be a warning class or tuple
115    of warning classes, and the code inside the ``with`` block must issue at least one
116    warning of that class or classes.
117
118    This helper produces a list of :class:`warnings.WarningMessage` objects, one for
119    each warning emitted (regardless of whether it is an ``expected_warning`` or not).
120    Since pytest 8.0, unmatched warnings are also re-emitted when the context closes.
121
122    This function can be used as a context manager::
123
124        >>> import pytest
125        >>> with pytest.warns(RuntimeWarning):
126        ...    warnings.warn("my warning", RuntimeWarning)
127
128    In the context manager form you may use the keyword argument ``match`` to assert
129    that the warning matches a text or regex::
130
131        >>> with pytest.warns(UserWarning, match='must be 0 or None'):
132        ...     warnings.warn("value must be 0 or None", UserWarning)
133
134        >>> with pytest.warns(UserWarning, match=r'must be \d+$'):
135        ...     warnings.warn("value must be 42", UserWarning)
136
137        >>> with pytest.warns(UserWarning):  # catch re-emitted warning
138        ...     with pytest.warns(UserWarning, match=r'must be \d+$'):
139        ...         warnings.warn("this is not here", UserWarning)
140        Traceback (most recent call last):
141          ...
142        Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...
143
144    **Using with** ``pytest.mark.parametrize``
145
146    When using :ref:`pytest.mark.parametrize ref` it is possible to parametrize tests
147    such that some runs raise a warning and others do not.
148
149    This could be achieved in the same way as with exceptions, see
150    :ref:`parametrizing_conditional_raising` for an example.
151
152    """
153    __tracebackhide__ = True
154    if not args:
155        if kwargs:
156            argnames = ", ".join(sorted(kwargs))
157            raise TypeError(
158                f"Unexpected keyword arguments passed to pytest.warns: {argnames}"
159                "\nUse context-manager form instead?"
160            )
161        return WarningsChecker(expected_warning, match_expr=match, _ispytest=True)
162    else:
163        func = args[0]
164        if not callable(func):
165            raise TypeError(f"{func!r} object (type: {type(func)}) must be callable")
166        with WarningsChecker(expected_warning, _ispytest=True):
167            return func(*args[1:], **kwargs)

Assert that code raises a particular class of warning.

Specifically, the parameter expected_warning can be a warning class or tuple of warning classes, and the code inside the with block must issue at least one warning of that class or classes.

This helper produces a list of warnings.WarningMessage objects, one for each warning emitted (regardless of whether it is an expected_warning or not). Since pytest 8.0, unmatched warnings are also re-emitted when the context closes.

This function can be used as a context manager::

>>> import pytest
>>> with pytest.warns(RuntimeWarning):
...    warnings.warn("my warning", RuntimeWarning)

In the context manager form you may use the keyword argument match to assert that the warning matches a text or regex::

>>> with pytest.warns(UserWarning, match='must be 0 or None'):
...     warnings.warn("value must be 0 or None", UserWarning)

>>> with pytest.warns(UserWarning, match=r'must be \d+$'):
...     warnings.warn("value must be 42", UserWarning)

>>> with pytest.warns(UserWarning):  # catch re-emitted warning
...     with pytest.warns(UserWarning, match=r'must be \d+$'):
...         warnings.warn("this is not here", UserWarning)
Traceback (most recent call last):
  ...
Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted...

Using with pytest.mark.parametrize

When using :ref:pytest.mark.parametrize ref it is possible to parametrize tests such that some runs raise a warning and others do not.

This could be achieved in the same way as with exceptions, see :ref:parametrizing_conditional_raising for an example.

def xfail(reason: str = '') -> NoReturn:
176@_with_exception(XFailed)
177def xfail(reason: str = "") -> NoReturn:
178    """Imperatively xfail an executing test or setup function with the given reason.
179
180    This function should be called only during testing (setup, call or teardown).
181
182    No other code is executed after using ``xfail()`` (it is implemented
183    internally by raising an exception).
184
185    :param reason:
186        The message to show the user as reason for the xfail.
187
188    .. note::
189        It is better to use the :ref:`pytest.mark.xfail ref` marker when
190        possible to declare a test to be xfailed under certain conditions
191        like known bugs or missing features.
192    """
193    __tracebackhide__ = True
194    raise XFailed(reason)

Imperatively xfail an executing test or setup function with the given reason.

This function should be called only during testing (setup, call or teardown).

No other code is executed after using xfail() (it is implemented internally by raising an exception).

Parameters
  • reason: The message to show the user as reason for the xfail.

It is better to use the :ref:pytest.mark.xfail ref marker when possible to declare a test to be xfailed under certain conditions like known bugs or missing features.

def yield_fixture( fixture_function=None, *args, scope='function', params=None, autouse=False, ids=None, name=None):
1309def yield_fixture(
1310    fixture_function=None,
1311    *args,
1312    scope="function",
1313    params=None,
1314    autouse=False,
1315    ids=None,
1316    name=None,
1317):
1318    """(Return a) decorator to mark a yield-fixture factory function.
1319
1320    .. deprecated:: 3.0
1321        Use :py:func:`pytest.fixture` directly instead.
1322    """
1323    warnings.warn(YIELD_FIXTURE, stacklevel=2)
1324    return fixture(
1325        fixture_function,
1326        *args,
1327        scope=scope,
1328        params=params,
1329        autouse=autouse,
1330        ids=ids,
1331        name=name,
1332    )

(Return a) decorator to mark a yield-fixture factory function.

Deprecated since version 3.0: Use pytest.fixture() directly instead.