parent
							
								
									ef5d81ad5c
								
							
						
					
					
						commit
						a83b359cf0
					
				| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					The private ``CallSpec2._arg2scopenum`` attribute has been removed after an internal refactoring.
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import sys
 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from collections import defaultdict
 | 
					from collections import defaultdict
 | 
				
			||||||
from collections import deque
 | 
					from collections import deque
 | 
				
			||||||
 | 
					from contextlib import suppress
 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
from types import TracebackType
 | 
					from types import TracebackType
 | 
				
			||||||
from typing import Any
 | 
					from typing import Any
 | 
				
			||||||
| 
						 | 
					@ -62,20 +63,21 @@ from _pytest.outcomes import fail
 | 
				
			||||||
from _pytest.outcomes import TEST_OUTCOME
 | 
					from _pytest.outcomes import TEST_OUTCOME
 | 
				
			||||||
from _pytest.pathlib import absolutepath
 | 
					from _pytest.pathlib import absolutepath
 | 
				
			||||||
from _pytest.pathlib import bestrelpath
 | 
					from _pytest.pathlib import bestrelpath
 | 
				
			||||||
 | 
					from _pytest.scope import HIGH_SCOPES
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
from _pytest.stash import StashKey
 | 
					from _pytest.stash import StashKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from typing import Deque
 | 
					    from typing import Deque
 | 
				
			||||||
    from typing import NoReturn
 | 
					    from typing import NoReturn
 | 
				
			||||||
    from typing_extensions import Literal
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from _pytest.scope import _ScopeName
 | 
				
			||||||
    from _pytest.main import Session
 | 
					    from _pytest.main import Session
 | 
				
			||||||
    from _pytest.python import CallSpec2
 | 
					    from _pytest.python import CallSpec2
 | 
				
			||||||
    from _pytest.python import Function
 | 
					    from _pytest.python import Function
 | 
				
			||||||
    from _pytest.python import Metafunc
 | 
					    from _pytest.python import Metafunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _Scope = Literal["session", "package", "module", "class", "function"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The value of the fixture -- return/yield of the fixture function (type variable).
 | 
					# The value of the fixture -- return/yield of the fixture function (type variable).
 | 
				
			||||||
FixtureValue = TypeVar("FixtureValue")
 | 
					FixtureValue = TypeVar("FixtureValue")
 | 
				
			||||||
| 
						 | 
					@ -104,10 +106,10 @@ _FixtureCachedResult = Union[
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@attr.s(frozen=True)
 | 
					@attr.s(frozen=True, auto_attribs=True)
 | 
				
			||||||
class PseudoFixtureDef(Generic[FixtureValue]):
 | 
					class PseudoFixtureDef(Generic[FixtureValue]):
 | 
				
			||||||
    cached_result = attr.ib(type="_FixtureCachedResult[FixtureValue]")
 | 
					    cached_result: "_FixtureCachedResult[FixtureValue]"
 | 
				
			||||||
    scope = attr.ib(type="_Scope")
 | 
					    _scope: Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_sessionstart(session: "Session") -> None:
 | 
					def pytest_sessionstart(session: "Session") -> None:
 | 
				
			||||||
| 
						 | 
					@ -130,19 +132,19 @@ def get_scope_package(node, fixturedef: "FixtureDef[object]"):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_scope_node(
 | 
					def get_scope_node(
 | 
				
			||||||
    node: nodes.Node, scope: "_Scope"
 | 
					    node: nodes.Node, scope: Scope
 | 
				
			||||||
) -> Optional[Union[nodes.Item, nodes.Collector]]:
 | 
					) -> Optional[Union[nodes.Item, nodes.Collector]]:
 | 
				
			||||||
    import _pytest.python
 | 
					    import _pytest.python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if scope == "function":
 | 
					    if scope is Scope.Function:
 | 
				
			||||||
        return node.getparent(nodes.Item)
 | 
					        return node.getparent(nodes.Item)
 | 
				
			||||||
    elif scope == "class":
 | 
					    elif scope is Scope.Class:
 | 
				
			||||||
        return node.getparent(_pytest.python.Class)
 | 
					        return node.getparent(_pytest.python.Class)
 | 
				
			||||||
    elif scope == "module":
 | 
					    elif scope is Scope.Module:
 | 
				
			||||||
        return node.getparent(_pytest.python.Module)
 | 
					        return node.getparent(_pytest.python.Module)
 | 
				
			||||||
    elif scope == "package":
 | 
					    elif scope is Scope.Package:
 | 
				
			||||||
        return node.getparent(_pytest.python.Package)
 | 
					        return node.getparent(_pytest.python.Package)
 | 
				
			||||||
    elif scope == "session":
 | 
					    elif scope is Scope.Session:
 | 
				
			||||||
        return node.getparent(_pytest.main.Session)
 | 
					        return node.getparent(_pytest.main.Session)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        assert_never(scope)
 | 
					        assert_never(scope)
 | 
				
			||||||
| 
						 | 
					@ -166,7 +168,7 @@ def add_funcarg_pseudo_fixture_def(
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    # Collect funcargs of all callspecs into a list of values.
 | 
					    # Collect funcargs of all callspecs into a list of values.
 | 
				
			||||||
    arg2params: Dict[str, List[object]] = {}
 | 
					    arg2params: Dict[str, List[object]] = {}
 | 
				
			||||||
    arg2scope: Dict[str, _Scope] = {}
 | 
					    arg2scope: Dict[str, Scope] = {}
 | 
				
			||||||
    for callspec in metafunc._calls:
 | 
					    for callspec in metafunc._calls:
 | 
				
			||||||
        for argname, argvalue in callspec.funcargs.items():
 | 
					        for argname, argvalue in callspec.funcargs.items():
 | 
				
			||||||
            assert argname not in callspec.params
 | 
					            assert argname not in callspec.params
 | 
				
			||||||
| 
						 | 
					@ -175,8 +177,8 @@ def add_funcarg_pseudo_fixture_def(
 | 
				
			||||||
            callspec.indices[argname] = len(arg2params_list)
 | 
					            callspec.indices[argname] = len(arg2params_list)
 | 
				
			||||||
            arg2params_list.append(argvalue)
 | 
					            arg2params_list.append(argvalue)
 | 
				
			||||||
            if argname not in arg2scope:
 | 
					            if argname not in arg2scope:
 | 
				
			||||||
                scopenum = callspec._arg2scopenum.get(argname, scopenum_function)
 | 
					                scope = callspec._arg2scope.get(argname, Scope.Function)
 | 
				
			||||||
                arg2scope[argname] = scopes[scopenum]
 | 
					                arg2scope[argname] = scope
 | 
				
			||||||
        callspec.funcargs.clear()
 | 
					        callspec.funcargs.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Register artificial FixtureDef's so that later at test execution
 | 
					    # Register artificial FixtureDef's so that later at test execution
 | 
				
			||||||
| 
						 | 
					@ -189,10 +191,12 @@ def add_funcarg_pseudo_fixture_def(
 | 
				
			||||||
        # node related to the scope.
 | 
					        # node related to the scope.
 | 
				
			||||||
        scope = arg2scope[argname]
 | 
					        scope = arg2scope[argname]
 | 
				
			||||||
        node = None
 | 
					        node = None
 | 
				
			||||||
        if scope != "function":
 | 
					        if scope is not Scope.Function:
 | 
				
			||||||
            node = get_scope_node(collector, scope)
 | 
					            node = get_scope_node(collector, scope)
 | 
				
			||||||
            if node is None:
 | 
					            if node is None:
 | 
				
			||||||
                assert scope == "class" and isinstance(collector, _pytest.python.Module)
 | 
					                assert scope is Scope.Class and isinstance(
 | 
				
			||||||
 | 
					                    collector, _pytest.python.Module
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                # Use module-level collector for class-scope (for now).
 | 
					                # Use module-level collector for class-scope (for now).
 | 
				
			||||||
                node = collector
 | 
					                node = collector
 | 
				
			||||||
        if node is None:
 | 
					        if node is None:
 | 
				
			||||||
| 
						 | 
					@ -238,10 +242,10 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
 | 
				
			||||||
_Key = Tuple[object, ...]
 | 
					_Key = Tuple[object, ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_parametrized_fixture_keys(item: nodes.Item, scopenum: int) -> Iterator[_Key]:
 | 
					def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_Key]:
 | 
				
			||||||
    """Return list of keys for all parametrized arguments which match
 | 
					    """Return list of keys for all parametrized arguments which match
 | 
				
			||||||
    the specified scope."""
 | 
					    the specified scope."""
 | 
				
			||||||
    assert scopenum < scopenum_function  # function
 | 
					    assert scope is not Scope.Function
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        callspec = item.callspec  # type: ignore[attr-defined]
 | 
					        callspec = item.callspec  # type: ignore[attr-defined]
 | 
				
			||||||
    except AttributeError:
 | 
					    except AttributeError:
 | 
				
			||||||
| 
						 | 
					@ -252,67 +256,71 @@ def get_parametrized_fixture_keys(item: nodes.Item, scopenum: int) -> Iterator[_
 | 
				
			||||||
        # sort this so that different calls to
 | 
					        # sort this so that different calls to
 | 
				
			||||||
        # get_parametrized_fixture_keys will be deterministic.
 | 
					        # get_parametrized_fixture_keys will be deterministic.
 | 
				
			||||||
        for argname, param_index in sorted(cs.indices.items()):
 | 
					        for argname, param_index in sorted(cs.indices.items()):
 | 
				
			||||||
            if cs._arg2scopenum[argname] != scopenum:
 | 
					            if cs._arg2scope[argname] != scope:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            if scopenum == 0:  # session
 | 
					            if scope is Scope.Session:
 | 
				
			||||||
                key: _Key = (argname, param_index)
 | 
					                key: _Key = (argname, param_index)
 | 
				
			||||||
            elif scopenum == 1:  # package
 | 
					            elif scope is Scope.Package:
 | 
				
			||||||
                key = (argname, param_index, item.path.parent)
 | 
					                key = (argname, param_index, item.path.parent)
 | 
				
			||||||
            elif scopenum == 2:  # module
 | 
					            elif scope is Scope.Module:
 | 
				
			||||||
                key = (argname, param_index, item.path)
 | 
					                key = (argname, param_index, item.path)
 | 
				
			||||||
            elif scopenum == 3:  # class
 | 
					            elif scope is Scope.Class:
 | 
				
			||||||
                item_cls = item.cls  # type: ignore[attr-defined]
 | 
					                item_cls = item.cls  # type: ignore[attr-defined]
 | 
				
			||||||
                key = (argname, param_index, item.path, item_cls)
 | 
					                key = (argname, param_index, item.path, item_cls)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                assert_never(scope)
 | 
				
			||||||
            yield key
 | 
					            yield key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Algorithm for sorting on a per-parametrized resource setup basis.
 | 
					# Algorithm for sorting on a per-parametrized resource setup basis.
 | 
				
			||||||
# It is called for scopenum==0 (session) first and performs sorting
 | 
					# It is called for Session scope first and performs sorting
 | 
				
			||||||
# down to the lower scopes such as to minimize number of "high scope"
 | 
					# down to the lower scopes such as to minimize number of "high scope"
 | 
				
			||||||
# setups and teardowns.
 | 
					# setups and teardowns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]:
 | 
					def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]:
 | 
				
			||||||
    argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]] = {}
 | 
					    argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]] = {}
 | 
				
			||||||
    items_by_argkey: Dict[int, Dict[_Key, Deque[nodes.Item]]] = {}
 | 
					    items_by_argkey: Dict[Scope, Dict[_Key, Deque[nodes.Item]]] = {}
 | 
				
			||||||
    for scopenum in range(scopenum_function):
 | 
					    for scope in HIGH_SCOPES:
 | 
				
			||||||
        d: Dict[nodes.Item, Dict[_Key, None]] = {}
 | 
					        d: Dict[nodes.Item, Dict[_Key, None]] = {}
 | 
				
			||||||
        argkeys_cache[scopenum] = d
 | 
					        argkeys_cache[scope] = d
 | 
				
			||||||
        item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque)
 | 
					        item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque)
 | 
				
			||||||
        items_by_argkey[scopenum] = item_d
 | 
					        items_by_argkey[scope] = item_d
 | 
				
			||||||
        for item in items:
 | 
					        for item in items:
 | 
				
			||||||
            keys = dict.fromkeys(get_parametrized_fixture_keys(item, scopenum), None)
 | 
					            keys = dict.fromkeys(get_parametrized_fixture_keys(item, scope), None)
 | 
				
			||||||
            if keys:
 | 
					            if keys:
 | 
				
			||||||
                d[item] = keys
 | 
					                d[item] = keys
 | 
				
			||||||
                for key in keys:
 | 
					                for key in keys:
 | 
				
			||||||
                    item_d[key].append(item)
 | 
					                    item_d[key].append(item)
 | 
				
			||||||
    items_dict = dict.fromkeys(items, None)
 | 
					    items_dict = dict.fromkeys(items, None)
 | 
				
			||||||
    return list(reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, 0))
 | 
					    return list(
 | 
				
			||||||
 | 
					        reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, Scope.Session)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def fix_cache_order(
 | 
					def fix_cache_order(
 | 
				
			||||||
    item: nodes.Item,
 | 
					    item: nodes.Item,
 | 
				
			||||||
    argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]],
 | 
					    argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]],
 | 
				
			||||||
    items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]],
 | 
					    items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]],
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
    for scopenum in range(scopenum_function):
 | 
					    for scope in HIGH_SCOPES:
 | 
				
			||||||
        for key in argkeys_cache[scopenum].get(item, []):
 | 
					        for key in argkeys_cache[scope].get(item, []):
 | 
				
			||||||
            items_by_argkey[scopenum][key].appendleft(item)
 | 
					            items_by_argkey[scope][key].appendleft(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reorder_items_atscope(
 | 
					def reorder_items_atscope(
 | 
				
			||||||
    items: Dict[nodes.Item, None],
 | 
					    items: Dict[nodes.Item, None],
 | 
				
			||||||
    argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]],
 | 
					    argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]],
 | 
				
			||||||
    items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]],
 | 
					    items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]],
 | 
				
			||||||
    scopenum: int,
 | 
					    scope: Scope,
 | 
				
			||||||
) -> Dict[nodes.Item, None]:
 | 
					) -> Dict[nodes.Item, None]:
 | 
				
			||||||
    if scopenum >= scopenum_function or len(items) < 3:
 | 
					    if scope is Scope.Function or len(items) < 3:
 | 
				
			||||||
        return items
 | 
					        return items
 | 
				
			||||||
    ignore: Set[Optional[_Key]] = set()
 | 
					    ignore: Set[Optional[_Key]] = set()
 | 
				
			||||||
    items_deque = deque(items)
 | 
					    items_deque = deque(items)
 | 
				
			||||||
    items_done: Dict[nodes.Item, None] = {}
 | 
					    items_done: Dict[nodes.Item, None] = {}
 | 
				
			||||||
    scoped_items_by_argkey = items_by_argkey[scopenum]
 | 
					    scoped_items_by_argkey = items_by_argkey[scope]
 | 
				
			||||||
    scoped_argkeys_cache = argkeys_cache[scopenum]
 | 
					    scoped_argkeys_cache = argkeys_cache[scope]
 | 
				
			||||||
    while items_deque:
 | 
					    while items_deque:
 | 
				
			||||||
        no_argkey_group: Dict[nodes.Item, None] = {}
 | 
					        no_argkey_group: Dict[nodes.Item, None] = {}
 | 
				
			||||||
        slicing_argkey = None
 | 
					        slicing_argkey = None
 | 
				
			||||||
| 
						 | 
					@ -338,7 +346,7 @@ def reorder_items_atscope(
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
        if no_argkey_group:
 | 
					        if no_argkey_group:
 | 
				
			||||||
            no_argkey_group = reorder_items_atscope(
 | 
					            no_argkey_group = reorder_items_atscope(
 | 
				
			||||||
                no_argkey_group, argkeys_cache, items_by_argkey, scopenum + 1
 | 
					                no_argkey_group, argkeys_cache, items_by_argkey, scope.next_lower()
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            for item in no_argkey_group:
 | 
					            for item in no_argkey_group:
 | 
				
			||||||
                items_done[item] = None
 | 
					                items_done[item] = None
 | 
				
			||||||
| 
						 | 
					@ -437,14 +445,18 @@ class FixtureRequest:
 | 
				
			||||||
        self._pyfuncitem = pyfuncitem
 | 
					        self._pyfuncitem = pyfuncitem
 | 
				
			||||||
        #: Fixture for which this request is being performed.
 | 
					        #: Fixture for which this request is being performed.
 | 
				
			||||||
        self.fixturename: Optional[str] = None
 | 
					        self.fixturename: Optional[str] = None
 | 
				
			||||||
        #: Scope string, one of "function", "class", "module", "session".
 | 
					        self._scope = Scope.Function
 | 
				
			||||||
        self.scope: _Scope = "function"
 | 
					 | 
				
			||||||
        self._fixture_defs: Dict[str, FixtureDef[Any]] = {}
 | 
					        self._fixture_defs: Dict[str, FixtureDef[Any]] = {}
 | 
				
			||||||
        fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo
 | 
					        fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo
 | 
				
			||||||
        self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
 | 
					        self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
 | 
				
			||||||
        self._arg2index: Dict[str, int] = {}
 | 
					        self._arg2index: Dict[str, int] = {}
 | 
				
			||||||
        self._fixturemanager: FixtureManager = pyfuncitem.session._fixturemanager
 | 
					        self._fixturemanager: FixtureManager = pyfuncitem.session._fixturemanager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def scope(self) -> "_ScopeName":
 | 
				
			||||||
 | 
					        """Scope string, one of "function", "class", "module", "package", "session"."""
 | 
				
			||||||
 | 
					        return self._scope.value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def fixturenames(self) -> List[str]:
 | 
					    def fixturenames(self) -> List[str]:
 | 
				
			||||||
        """Names of all active fixtures in this request."""
 | 
					        """Names of all active fixtures in this request."""
 | 
				
			||||||
| 
						 | 
					@ -455,7 +467,7 @@ class FixtureRequest:
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def node(self):
 | 
					    def node(self):
 | 
				
			||||||
        """Underlying collection node (depends on current request scope)."""
 | 
					        """Underlying collection node (depends on current request scope)."""
 | 
				
			||||||
        return self._getscopeitem(self.scope)
 | 
					        return self._getscopeitem(self._scope)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]":
 | 
					    def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]":
 | 
				
			||||||
        fixturedefs = self._arg2fixturedefs.get(argname, None)
 | 
					        fixturedefs = self._arg2fixturedefs.get(argname, None)
 | 
				
			||||||
| 
						 | 
					@ -598,8 +610,7 @@ class FixtureRequest:
 | 
				
			||||||
            except FixtureLookupError:
 | 
					            except FixtureLookupError:
 | 
				
			||||||
                if argname == "request":
 | 
					                if argname == "request":
 | 
				
			||||||
                    cached_result = (self, [0], None)
 | 
					                    cached_result = (self, [0], None)
 | 
				
			||||||
                    scope: _Scope = "function"
 | 
					                    return PseudoFixtureDef(cached_result, Scope.Function)
 | 
				
			||||||
                    return PseudoFixtureDef(cached_result, scope)
 | 
					 | 
				
			||||||
                raise
 | 
					                raise
 | 
				
			||||||
        # Remove indent to prevent the python3 exception
 | 
					        # Remove indent to prevent the python3 exception
 | 
				
			||||||
        # from leaking into the call.
 | 
					        # from leaking into the call.
 | 
				
			||||||
| 
						 | 
					@ -628,7 +639,7 @@ class FixtureRequest:
 | 
				
			||||||
        # (latter managed by fixturedef)
 | 
					        # (latter managed by fixturedef)
 | 
				
			||||||
        argname = fixturedef.argname
 | 
					        argname = fixturedef.argname
 | 
				
			||||||
        funcitem = self._pyfuncitem
 | 
					        funcitem = self._pyfuncitem
 | 
				
			||||||
        scope = fixturedef.scope
 | 
					        scope = fixturedef._scope
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            param = funcitem.callspec.getparam(argname)
 | 
					            param = funcitem.callspec.getparam(argname)
 | 
				
			||||||
        except (AttributeError, ValueError):
 | 
					        except (AttributeError, ValueError):
 | 
				
			||||||
| 
						 | 
					@ -675,16 +686,15 @@ class FixtureRequest:
 | 
				
			||||||
            param_index = funcitem.callspec.indices[argname]
 | 
					            param_index = funcitem.callspec.indices[argname]
 | 
				
			||||||
            # If a parametrize invocation set a scope it will override
 | 
					            # If a parametrize invocation set a scope it will override
 | 
				
			||||||
            # the static scope defined with the fixture function.
 | 
					            # the static scope defined with the fixture function.
 | 
				
			||||||
            paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
 | 
					            with suppress(KeyError):
 | 
				
			||||||
            if paramscopenum is not None:
 | 
					                scope = funcitem.callspec._arg2scope[argname]
 | 
				
			||||||
                scope = scopes[paramscopenum]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subrequest = SubRequest(
 | 
					        subrequest = SubRequest(
 | 
				
			||||||
            self, scope, param, param_index, fixturedef, _ispytest=True
 | 
					            self, scope, param, param_index, fixturedef, _ispytest=True
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Check if a higher-level scoped fixture accesses a lower level one.
 | 
					        # Check if a higher-level scoped fixture accesses a lower level one.
 | 
				
			||||||
        subrequest._check_scope(argname, self.scope, scope)
 | 
					        subrequest._check_scope(argname, self._scope, scope)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            # Call the fixture function.
 | 
					            # Call the fixture function.
 | 
				
			||||||
            fixturedef.execute(request=subrequest)
 | 
					            fixturedef.execute(request=subrequest)
 | 
				
			||||||
| 
						 | 
					@ -700,19 +710,18 @@ class FixtureRequest:
 | 
				
			||||||
    def _check_scope(
 | 
					    def _check_scope(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        argname: str,
 | 
					        argname: str,
 | 
				
			||||||
        invoking_scope: "_Scope",
 | 
					        invoking_scope: Scope,
 | 
				
			||||||
        requested_scope: "_Scope",
 | 
					        requested_scope: Scope,
 | 
				
			||||||
    ) -> None:
 | 
					    ) -> None:
 | 
				
			||||||
        if argname == "request":
 | 
					        if argname == "request":
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        if scopemismatch(invoking_scope, requested_scope):
 | 
					        if invoking_scope > requested_scope:
 | 
				
			||||||
            # Try to report something helpful.
 | 
					            # Try to report something helpful.
 | 
				
			||||||
            lines = self._factorytraceback()
 | 
					            text = "\n".join(self._factorytraceback())
 | 
				
			||||||
            fail(
 | 
					            fail(
 | 
				
			||||||
                "ScopeMismatch: You tried to access the %r scoped "
 | 
					                f"ScopeMismatch: You tried to access the {requested_scope.value} scoped "
 | 
				
			||||||
                "fixture %r with a %r scoped request object, "
 | 
					                f"fixture {argname} with a {invoking_scope.value} scoped request object, "
 | 
				
			||||||
                "involved factories\n%s"
 | 
					                f"involved factories:\n{text}",
 | 
				
			||||||
                % ((requested_scope, argname, invoking_scope, "\n".join(lines))),
 | 
					 | 
				
			||||||
                pytrace=False,
 | 
					                pytrace=False,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -730,17 +739,21 @@ class FixtureRequest:
 | 
				
			||||||
            lines.append("%s:%d:  def %s%s" % (p, lineno + 1, factory.__name__, args))
 | 
					            lines.append("%s:%d:  def %s%s" % (p, lineno + 1, factory.__name__, args))
 | 
				
			||||||
        return lines
 | 
					        return lines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _getscopeitem(self, scope: "_Scope") -> Union[nodes.Item, nodes.Collector]:
 | 
					    def _getscopeitem(
 | 
				
			||||||
        if scope == "function":
 | 
					        self, scope: Union[Scope, "_ScopeName"]
 | 
				
			||||||
 | 
					    ) -> Union[nodes.Item, nodes.Collector]:
 | 
				
			||||||
 | 
					        if isinstance(scope, str):
 | 
				
			||||||
 | 
					            scope = Scope(scope)
 | 
				
			||||||
 | 
					        if scope is Scope.Function:
 | 
				
			||||||
            # This might also be a non-function Item despite its attribute name.
 | 
					            # This might also be a non-function Item despite its attribute name.
 | 
				
			||||||
            node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem
 | 
					            node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem
 | 
				
			||||||
        elif scope == "package":
 | 
					        elif scope is Scope.Package:
 | 
				
			||||||
            # FIXME: _fixturedef is not defined on FixtureRequest (this class),
 | 
					            # FIXME: _fixturedef is not defined on FixtureRequest (this class),
 | 
				
			||||||
            # but on FixtureRequest (a subclass).
 | 
					            # but on FixtureRequest (a subclass).
 | 
				
			||||||
            node = get_scope_package(self._pyfuncitem, self._fixturedef)  # type: ignore[attr-defined]
 | 
					            node = get_scope_package(self._pyfuncitem, self._fixturedef)  # type: ignore[attr-defined]
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            node = get_scope_node(self._pyfuncitem, scope)
 | 
					            node = get_scope_node(self._pyfuncitem, scope)
 | 
				
			||||||
        if node is None and scope == "class":
 | 
					        if node is None and scope is Scope.Class:
 | 
				
			||||||
            # Fallback to function item itself.
 | 
					            # Fallback to function item itself.
 | 
				
			||||||
            node = self._pyfuncitem
 | 
					            node = self._pyfuncitem
 | 
				
			||||||
        assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format(
 | 
					        assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format(
 | 
				
			||||||
| 
						 | 
					@ -759,7 +772,7 @@ class SubRequest(FixtureRequest):
 | 
				
			||||||
    def __init__(
 | 
					    def __init__(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        request: "FixtureRequest",
 | 
					        request: "FixtureRequest",
 | 
				
			||||||
        scope: "_Scope",
 | 
					        scope: Scope,
 | 
				
			||||||
        param: Any,
 | 
					        param: Any,
 | 
				
			||||||
        param_index: int,
 | 
					        param_index: int,
 | 
				
			||||||
        fixturedef: "FixtureDef[object]",
 | 
					        fixturedef: "FixtureDef[object]",
 | 
				
			||||||
| 
						 | 
					@ -772,7 +785,7 @@ class SubRequest(FixtureRequest):
 | 
				
			||||||
        if param is not NOTSET:
 | 
					        if param is not NOTSET:
 | 
				
			||||||
            self.param = param
 | 
					            self.param = param
 | 
				
			||||||
        self.param_index = param_index
 | 
					        self.param_index = param_index
 | 
				
			||||||
        self.scope = scope
 | 
					        self._scope = scope
 | 
				
			||||||
        self._fixturedef = fixturedef
 | 
					        self._fixturedef = fixturedef
 | 
				
			||||||
        self._pyfuncitem = request._pyfuncitem
 | 
					        self._pyfuncitem = request._pyfuncitem
 | 
				
			||||||
        self._fixture_defs = request._fixture_defs
 | 
					        self._fixture_defs = request._fixture_defs
 | 
				
			||||||
| 
						 | 
					@ -801,29 +814,6 @@ class SubRequest(FixtureRequest):
 | 
				
			||||||
        super()._schedule_finalizers(fixturedef, subrequest)
 | 
					        super()._schedule_finalizers(fixturedef, subrequest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
scopes: List["_Scope"] = ["session", "package", "module", "class", "function"]
 | 
					 | 
				
			||||||
scopenum_function = scopes.index("function")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def scopemismatch(currentscope: "_Scope", newscope: "_Scope") -> bool:
 | 
					 | 
				
			||||||
    return scopes.index(newscope) > scopes.index(currentscope)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def scope2index(scope: str, descr: str, where: Optional[str] = None) -> int:
 | 
					 | 
				
			||||||
    """Look up the index of ``scope`` and raise a descriptive value error
 | 
					 | 
				
			||||||
    if not defined."""
 | 
					 | 
				
			||||||
    strscopes: Sequence[str] = scopes
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        return strscopes.index(scope)
 | 
					 | 
				
			||||||
    except ValueError:
 | 
					 | 
				
			||||||
        fail(
 | 
					 | 
				
			||||||
            "{} {}got an unexpected scope value '{}'".format(
 | 
					 | 
				
			||||||
                descr, f"from {where} " if where else "", scope
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            pytrace=False,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@final
 | 
					@final
 | 
				
			||||||
class FixtureLookupError(LookupError):
 | 
					class FixtureLookupError(LookupError):
 | 
				
			||||||
    """Could not return a requested fixture (missing or invalid)."""
 | 
					    """Could not return a requested fixture (missing or invalid)."""
 | 
				
			||||||
| 
						 | 
					@ -955,10 +945,10 @@ def _teardown_yield_fixture(fixturefunc, it) -> None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _eval_scope_callable(
 | 
					def _eval_scope_callable(
 | 
				
			||||||
    scope_callable: "Callable[[str, Config], _Scope]",
 | 
					    scope_callable: "Callable[[str, Config], _ScopeName]",
 | 
				
			||||||
    fixture_name: str,
 | 
					    fixture_name: str,
 | 
				
			||||||
    config: Config,
 | 
					    config: Config,
 | 
				
			||||||
) -> "_Scope":
 | 
					) -> "_ScopeName":
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        # Type ignored because there is no typing mechanism to specify
 | 
					        # Type ignored because there is no typing mechanism to specify
 | 
				
			||||||
        # keyword arguments, currently.
 | 
					        # keyword arguments, currently.
 | 
				
			||||||
| 
						 | 
					@ -989,7 +979,7 @@ class FixtureDef(Generic[FixtureValue]):
 | 
				
			||||||
        baseid: Optional[str],
 | 
					        baseid: Optional[str],
 | 
				
			||||||
        argname: str,
 | 
					        argname: str,
 | 
				
			||||||
        func: "_FixtureFunc[FixtureValue]",
 | 
					        func: "_FixtureFunc[FixtureValue]",
 | 
				
			||||||
        scope: "Union[_Scope, Callable[[str, Config], _Scope]]",
 | 
					        scope: Union[Scope, "_ScopeName", Callable[[str, Config], "_ScopeName"], None],
 | 
				
			||||||
        params: Optional[Sequence[object]],
 | 
					        params: Optional[Sequence[object]],
 | 
				
			||||||
        unittest: bool = False,
 | 
					        unittest: bool = False,
 | 
				
			||||||
        ids: Optional[
 | 
					        ids: Optional[
 | 
				
			||||||
| 
						 | 
					@ -1004,17 +994,16 @@ class FixtureDef(Generic[FixtureValue]):
 | 
				
			||||||
        self.has_location = baseid is not None
 | 
					        self.has_location = baseid is not None
 | 
				
			||||||
        self.func = func
 | 
					        self.func = func
 | 
				
			||||||
        self.argname = argname
 | 
					        self.argname = argname
 | 
				
			||||||
        if callable(scope):
 | 
					        if scope is None:
 | 
				
			||||||
            scope_ = _eval_scope_callable(scope, argname, fixturemanager.config)
 | 
					            scope = Scope.Function
 | 
				
			||||||
        else:
 | 
					        elif callable(scope):
 | 
				
			||||||
            scope_ = scope
 | 
					            scope = _eval_scope_callable(scope, argname, fixturemanager.config)
 | 
				
			||||||
        self.scopenum = scope2index(
 | 
					
 | 
				
			||||||
            # TODO: Check if the `or` here is really necessary.
 | 
					        if isinstance(scope, str):
 | 
				
			||||||
            scope_ or "function",  # type: ignore[unreachable]
 | 
					            scope = Scope.from_user(
 | 
				
			||||||
            descr=f"Fixture '{func.__name__}'",
 | 
					                scope, descr=f"Fixture '{func.__name__}'", where=baseid
 | 
				
			||||||
            where=baseid,
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        self.scope = scope_
 | 
					        self._scope = scope
 | 
				
			||||||
        self.params: Optional[Sequence[object]] = params
 | 
					        self.params: Optional[Sequence[object]] = params
 | 
				
			||||||
        self.argnames: Tuple[str, ...] = getfuncargnames(
 | 
					        self.argnames: Tuple[str, ...] = getfuncargnames(
 | 
				
			||||||
            func, name=argname, is_method=unittest
 | 
					            func, name=argname, is_method=unittest
 | 
				
			||||||
| 
						 | 
					@ -1024,6 +1013,11 @@ class FixtureDef(Generic[FixtureValue]):
 | 
				
			||||||
        self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
 | 
					        self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
 | 
				
			||||||
        self._finalizers: List[Callable[[], object]] = []
 | 
					        self._finalizers: List[Callable[[], object]] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def scope(self) -> "_ScopeName":
 | 
				
			||||||
 | 
					        """Scope string, one of "function", "class", "module", "package", "session"."""
 | 
				
			||||||
 | 
					        return self._scope.value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
 | 
					    def addfinalizer(self, finalizer: Callable[[], object]) -> None:
 | 
				
			||||||
        self._finalizers.append(finalizer)
 | 
					        self._finalizers.append(finalizer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1126,7 +1120,7 @@ def pytest_fixture_setup(
 | 
				
			||||||
        fixdef = request._get_active_fixturedef(argname)
 | 
					        fixdef = request._get_active_fixturedef(argname)
 | 
				
			||||||
        assert fixdef.cached_result is not None
 | 
					        assert fixdef.cached_result is not None
 | 
				
			||||||
        result, arg_cache_key, exc = fixdef.cached_result
 | 
					        result, arg_cache_key, exc = fixdef.cached_result
 | 
				
			||||||
        request._check_scope(argname, request.scope, fixdef.scope)
 | 
					        request._check_scope(argname, request._scope, fixdef._scope)
 | 
				
			||||||
        kwargs[argname] = result
 | 
					        kwargs[argname] = result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fixturefunc = resolve_fixture_function(fixturedef, request)
 | 
					    fixturefunc = resolve_fixture_function(fixturedef, request)
 | 
				
			||||||
| 
						 | 
					@ -1195,18 +1189,17 @@ def wrap_function_to_error_out_if_called_directly(
 | 
				
			||||||
@final
 | 
					@final
 | 
				
			||||||
@attr.s(frozen=True)
 | 
					@attr.s(frozen=True)
 | 
				
			||||||
class FixtureFunctionMarker:
 | 
					class FixtureFunctionMarker:
 | 
				
			||||||
    scope = attr.ib(type="Union[_Scope, Callable[[str, Config], _Scope]]")
 | 
					    scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = attr.ib()
 | 
				
			||||||
    params = attr.ib(type=Optional[Tuple[object, ...]], converter=_params_converter)
 | 
					    params: Optional[Tuple[object, ...]] = attr.ib(converter=_params_converter)
 | 
				
			||||||
    autouse = attr.ib(type=bool, default=False)
 | 
					    autouse: bool = attr.ib(default=False)
 | 
				
			||||||
    ids = attr.ib(
 | 
					    ids: Union[
 | 
				
			||||||
        type=Union[
 | 
					 | 
				
			||||||
        Tuple[Union[None, str, float, int, bool], ...],
 | 
					        Tuple[Union[None, str, float, int, bool], ...],
 | 
				
			||||||
        Callable[[Any], Optional[object]],
 | 
					        Callable[[Any], Optional[object]],
 | 
				
			||||||
        ],
 | 
					    ] = attr.ib(
 | 
				
			||||||
        default=None,
 | 
					        default=None,
 | 
				
			||||||
        converter=_ensure_immutable_ids,
 | 
					        converter=_ensure_immutable_ids,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    name = attr.ib(type=Optional[str], default=None)
 | 
					    name: Optional[str] = attr.ib(default=None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __call__(self, function: FixtureFunction) -> FixtureFunction:
 | 
					    def __call__(self, function: FixtureFunction) -> FixtureFunction:
 | 
				
			||||||
        if inspect.isclass(function):
 | 
					        if inspect.isclass(function):
 | 
				
			||||||
| 
						 | 
					@ -1238,7 +1231,7 @@ class FixtureFunctionMarker:
 | 
				
			||||||
def fixture(
 | 
					def fixture(
 | 
				
			||||||
    fixture_function: FixtureFunction,
 | 
					    fixture_function: FixtureFunction,
 | 
				
			||||||
    *,
 | 
					    *,
 | 
				
			||||||
    scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ...,
 | 
					    scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
 | 
				
			||||||
    params: Optional[Iterable[object]] = ...,
 | 
					    params: Optional[Iterable[object]] = ...,
 | 
				
			||||||
    autouse: bool = ...,
 | 
					    autouse: bool = ...,
 | 
				
			||||||
    ids: Optional[
 | 
					    ids: Optional[
 | 
				
			||||||
| 
						 | 
					@ -1256,7 +1249,7 @@ def fixture(
 | 
				
			||||||
def fixture(
 | 
					def fixture(
 | 
				
			||||||
    fixture_function: None = ...,
 | 
					    fixture_function: None = ...,
 | 
				
			||||||
    *,
 | 
					    *,
 | 
				
			||||||
    scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ...,
 | 
					    scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
 | 
				
			||||||
    params: Optional[Iterable[object]] = ...,
 | 
					    params: Optional[Iterable[object]] = ...,
 | 
				
			||||||
    autouse: bool = ...,
 | 
					    autouse: bool = ...,
 | 
				
			||||||
    ids: Optional[
 | 
					    ids: Optional[
 | 
				
			||||||
| 
						 | 
					@ -1273,7 +1266,7 @@ def fixture(
 | 
				
			||||||
def fixture(
 | 
					def fixture(
 | 
				
			||||||
    fixture_function: Optional[FixtureFunction] = None,
 | 
					    fixture_function: Optional[FixtureFunction] = None,
 | 
				
			||||||
    *,
 | 
					    *,
 | 
				
			||||||
    scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function",
 | 
					    scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function",
 | 
				
			||||||
    params: Optional[Iterable[object]] = None,
 | 
					    params: Optional[Iterable[object]] = None,
 | 
				
			||||||
    autouse: bool = False,
 | 
					    autouse: bool = False,
 | 
				
			||||||
    ids: Optional[
 | 
					    ids: Optional[
 | 
				
			||||||
| 
						 | 
					@ -1552,15 +1545,15 @@ class FixtureManager:
 | 
				
			||||||
                    arg2fixturedefs[argname] = fixturedefs
 | 
					                    arg2fixturedefs[argname] = fixturedefs
 | 
				
			||||||
                    merge(fixturedefs[-1].argnames)
 | 
					                    merge(fixturedefs[-1].argnames)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def sort_by_scope(arg_name: str) -> int:
 | 
					        def sort_by_scope(arg_name: str) -> Scope:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                fixturedefs = arg2fixturedefs[arg_name]
 | 
					                fixturedefs = arg2fixturedefs[arg_name]
 | 
				
			||||||
            except KeyError:
 | 
					            except KeyError:
 | 
				
			||||||
                return scopes.index("function")
 | 
					                return Scope.Function
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return fixturedefs[-1].scopenum
 | 
					                return fixturedefs[-1]._scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fixturenames_closure.sort(key=sort_by_scope)
 | 
					        fixturenames_closure.sort(key=sort_by_scope, reverse=True)
 | 
				
			||||||
        return initialnames, fixturenames_closure, arg2fixturedefs
 | 
					        return initialnames, fixturenames_closure, arg2fixturedefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def pytest_generate_tests(self, metafunc: "Metafunc") -> None:
 | 
					    def pytest_generate_tests(self, metafunc: "Metafunc") -> None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -400,7 +400,7 @@ def store_mark(obj, mark: Mark) -> None:
 | 
				
			||||||
# Typing for builtin pytest marks. This is cheating; it gives builtin marks
 | 
					# Typing for builtin pytest marks. This is cheating; it gives builtin marks
 | 
				
			||||||
# special privilege, and breaks modularity. But practicality beats purity...
 | 
					# special privilege, and breaks modularity. But practicality beats purity...
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from _pytest.fixtures import _Scope
 | 
					    from _pytest.scope import _ScopeName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class _SkipMarkDecorator(MarkDecorator):
 | 
					    class _SkipMarkDecorator(MarkDecorator):
 | 
				
			||||||
        @overload  # type: ignore[override,misc]
 | 
					        @overload  # type: ignore[override,misc]
 | 
				
			||||||
| 
						 | 
					@ -450,7 +450,7 @@ if TYPE_CHECKING:
 | 
				
			||||||
                    Callable[[Any], Optional[object]],
 | 
					                    Callable[[Any], Optional[object]],
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
            ] = ...,
 | 
					            ] = ...,
 | 
				
			||||||
            scope: Optional[_Scope] = ...,
 | 
					            scope: Optional[_ScopeName] = ...,
 | 
				
			||||||
        ) -> MarkDecorator:
 | 
					        ) -> MarkDecorator:
 | 
				
			||||||
            ...
 | 
					            ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,12 +72,13 @@ from _pytest.pathlib import import_path
 | 
				
			||||||
from _pytest.pathlib import ImportPathMismatchError
 | 
					from _pytest.pathlib import ImportPathMismatchError
 | 
				
			||||||
from _pytest.pathlib import parts
 | 
					from _pytest.pathlib import parts
 | 
				
			||||||
from _pytest.pathlib import visit
 | 
					from _pytest.pathlib import visit
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
from _pytest.warning_types import PytestCollectionWarning
 | 
					from _pytest.warning_types import PytestCollectionWarning
 | 
				
			||||||
from _pytest.warning_types import PytestUnhandledCoroutineWarning
 | 
					from _pytest.warning_types import PytestUnhandledCoroutineWarning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from typing_extensions import Literal
 | 
					    from typing_extensions import Literal
 | 
				
			||||||
    from _pytest.fixtures import _Scope
 | 
					    from _pytest.scope import _ScopeName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_addoption(parser: Parser) -> None:
 | 
					def pytest_addoption(parser: Parser) -> None:
 | 
				
			||||||
| 
						 | 
					@ -896,7 +897,7 @@ class CallSpec2:
 | 
				
			||||||
        self._idlist: List[str] = []
 | 
					        self._idlist: List[str] = []
 | 
				
			||||||
        self.params: Dict[str, object] = {}
 | 
					        self.params: Dict[str, object] = {}
 | 
				
			||||||
        # Used for sorting parametrized resources.
 | 
					        # Used for sorting parametrized resources.
 | 
				
			||||||
        self._arg2scopenum: Dict[str, int] = {}
 | 
					        self._arg2scope: Dict[str, Scope] = {}
 | 
				
			||||||
        self.marks: List[Mark] = []
 | 
					        self.marks: List[Mark] = []
 | 
				
			||||||
        self.indices: Dict[str, int] = {}
 | 
					        self.indices: Dict[str, int] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -906,7 +907,7 @@ class CallSpec2:
 | 
				
			||||||
        cs.params.update(self.params)
 | 
					        cs.params.update(self.params)
 | 
				
			||||||
        cs.marks.extend(self.marks)
 | 
					        cs.marks.extend(self.marks)
 | 
				
			||||||
        cs.indices.update(self.indices)
 | 
					        cs.indices.update(self.indices)
 | 
				
			||||||
        cs._arg2scopenum.update(self._arg2scopenum)
 | 
					        cs._arg2scope.update(self._arg2scope)
 | 
				
			||||||
        cs._idlist = list(self._idlist)
 | 
					        cs._idlist = list(self._idlist)
 | 
				
			||||||
        return cs
 | 
					        return cs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -927,7 +928,7 @@ class CallSpec2:
 | 
				
			||||||
        valset: Iterable[object],
 | 
					        valset: Iterable[object],
 | 
				
			||||||
        id: str,
 | 
					        id: str,
 | 
				
			||||||
        marks: Iterable[Union[Mark, MarkDecorator]],
 | 
					        marks: Iterable[Union[Mark, MarkDecorator]],
 | 
				
			||||||
        scopenum: int,
 | 
					        scope: Scope,
 | 
				
			||||||
        param_index: int,
 | 
					        param_index: int,
 | 
				
			||||||
    ) -> None:
 | 
					    ) -> None:
 | 
				
			||||||
        for arg, val in zip(argnames, valset):
 | 
					        for arg, val in zip(argnames, valset):
 | 
				
			||||||
| 
						 | 
					@ -941,7 +942,7 @@ class CallSpec2:
 | 
				
			||||||
            else:  # pragma: no cover
 | 
					            else:  # pragma: no cover
 | 
				
			||||||
                assert False, f"Unhandled valtype for arg: {valtype_for_arg}"
 | 
					                assert False, f"Unhandled valtype for arg: {valtype_for_arg}"
 | 
				
			||||||
            self.indices[arg] = param_index
 | 
					            self.indices[arg] = param_index
 | 
				
			||||||
            self._arg2scopenum[arg] = scopenum
 | 
					            self._arg2scope[arg] = scope
 | 
				
			||||||
        self._idlist.append(id)
 | 
					        self._idlist.append(id)
 | 
				
			||||||
        self.marks.extend(normalize_mark_list(marks))
 | 
					        self.marks.extend(normalize_mark_list(marks))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -999,7 +1000,7 @@ class Metafunc:
 | 
				
			||||||
                Callable[[Any], Optional[object]],
 | 
					                Callable[[Any], Optional[object]],
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        ] = None,
 | 
					        ] = None,
 | 
				
			||||||
        scope: "Optional[_Scope]" = None,
 | 
					        scope: "Optional[_ScopeName]" = None,
 | 
				
			||||||
        *,
 | 
					        *,
 | 
				
			||||||
        _param_mark: Optional[Mark] = None,
 | 
					        _param_mark: Optional[Mark] = None,
 | 
				
			||||||
    ) -> None:
 | 
					    ) -> None:
 | 
				
			||||||
| 
						 | 
					@ -1055,8 +1056,6 @@ class Metafunc:
 | 
				
			||||||
            It will also override any fixture-function defined scope, allowing
 | 
					            It will also override any fixture-function defined scope, allowing
 | 
				
			||||||
            to set a dynamic scope using test context or configuration.
 | 
					            to set a dynamic scope using test context or configuration.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        from _pytest.fixtures import scope2index
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        argnames, parameters = ParameterSet._for_parametrize(
 | 
					        argnames, parameters = ParameterSet._for_parametrize(
 | 
				
			||||||
            argnames,
 | 
					            argnames,
 | 
				
			||||||
            argvalues,
 | 
					            argvalues,
 | 
				
			||||||
| 
						 | 
					@ -1072,8 +1071,12 @@ class Metafunc:
 | 
				
			||||||
                pytrace=False,
 | 
					                pytrace=False,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if scope is None:
 | 
					        if scope is not None:
 | 
				
			||||||
            scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
 | 
					            scope_ = Scope.from_user(
 | 
				
			||||||
 | 
					                scope, descr=f"parametrize() call in {self.function.__name__}"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            scope_ = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._validate_if_using_arg_names(argnames, indirect)
 | 
					        self._validate_if_using_arg_names(argnames, indirect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1093,10 +1096,6 @@ class Metafunc:
 | 
				
			||||||
        if _param_mark and _param_mark._param_ids_from and generated_ids is None:
 | 
					        if _param_mark and _param_mark._param_ids_from and generated_ids is None:
 | 
				
			||||||
            object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)
 | 
					            object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        scopenum = scope2index(
 | 
					 | 
				
			||||||
            scope, descr=f"parametrize() call in {self.function.__name__}"
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Create the new calls: if we are parametrize() multiple times (by applying the decorator
 | 
					        # Create the new calls: if we are parametrize() multiple times (by applying the decorator
 | 
				
			||||||
        # more than once) then we accumulate those calls generating the cartesian product
 | 
					        # more than once) then we accumulate those calls generating the cartesian product
 | 
				
			||||||
        # of all calls.
 | 
					        # of all calls.
 | 
				
			||||||
| 
						 | 
					@ -1110,7 +1109,7 @@ class Metafunc:
 | 
				
			||||||
                    param_set.values,
 | 
					                    param_set.values,
 | 
				
			||||||
                    param_id,
 | 
					                    param_id,
 | 
				
			||||||
                    param_set.marks,
 | 
					                    param_set.marks,
 | 
				
			||||||
                    scopenum,
 | 
					                    scope_,
 | 
				
			||||||
                    param_index,
 | 
					                    param_index,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                newcalls.append(newcallspec)
 | 
					                newcalls.append(newcallspec)
 | 
				
			||||||
| 
						 | 
					@ -1263,7 +1262,7 @@ def _find_parametrized_scope(
 | 
				
			||||||
    argnames: Sequence[str],
 | 
					    argnames: Sequence[str],
 | 
				
			||||||
    arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[object]]],
 | 
					    arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[object]]],
 | 
				
			||||||
    indirect: Union[bool, Sequence[str]],
 | 
					    indirect: Union[bool, Sequence[str]],
 | 
				
			||||||
) -> "fixtures._Scope":
 | 
					) -> Scope:
 | 
				
			||||||
    """Find the most appropriate scope for a parametrized call based on its arguments.
 | 
					    """Find the most appropriate scope for a parametrized call based on its arguments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    When there's at least one direct argument, always use "function" scope.
 | 
					    When there's at least one direct argument, always use "function" scope.
 | 
				
			||||||
| 
						 | 
					@ -1281,17 +1280,14 @@ def _find_parametrized_scope(
 | 
				
			||||||
    if all_arguments_are_fixtures:
 | 
					    if all_arguments_are_fixtures:
 | 
				
			||||||
        fixturedefs = arg2fixturedefs or {}
 | 
					        fixturedefs = arg2fixturedefs or {}
 | 
				
			||||||
        used_scopes = [
 | 
					        used_scopes = [
 | 
				
			||||||
            fixturedef[0].scope
 | 
					            fixturedef[0]._scope
 | 
				
			||||||
            for name, fixturedef in fixturedefs.items()
 | 
					            for name, fixturedef in fixturedefs.items()
 | 
				
			||||||
            if name in argnames
 | 
					            if name in argnames
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        if used_scopes:
 | 
					 | 
				
			||||||
        # Takes the most narrow scope from used fixtures.
 | 
					        # Takes the most narrow scope from used fixtures.
 | 
				
			||||||
            for scope in reversed(fixtures.scopes):
 | 
					        return min(used_scopes, default=Scope.Function)
 | 
				
			||||||
                if scope in used_scopes:
 | 
					 | 
				
			||||||
                    return scope
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return "function"
 | 
					    return Scope.Function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _ascii_escaped_by_config(val: Union[str, bytes], config: Optional[Config]) -> str:
 | 
					def _ascii_escaped_by_config(val: Union[str, bytes], config: Optional[Config]) -> str:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					Scope definition and related utilities.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Those are defined here, instead of in the 'fixtures' module because
 | 
				
			||||||
 | 
					their use is spread across many other pytest modules, and centralizing it in 'fixtures'
 | 
				
			||||||
 | 
					would cause circular references.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also this makes the module light to import, as it should.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					from enum import Enum
 | 
				
			||||||
 | 
					from functools import total_ordering
 | 
				
			||||||
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					from typing import TYPE_CHECKING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
 | 
					    from typing_extensions import Literal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _ScopeName = Literal["session", "package", "module", "class", "function"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@total_ordering
 | 
				
			||||||
 | 
					class Scope(Enum):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Represents one of the possible fixture scopes in pytest.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Scopes are ordered from lower to higher, that is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              ->>> higher ->>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Function < Class < Module < Package < Session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <<<- lower  <<<-
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Scopes need to be listed from lower to higher.
 | 
				
			||||||
 | 
					    Function: "_ScopeName" = "function"
 | 
				
			||||||
 | 
					    Class: "_ScopeName" = "class"
 | 
				
			||||||
 | 
					    Module: "_ScopeName" = "module"
 | 
				
			||||||
 | 
					    Package: "_ScopeName" = "package"
 | 
				
			||||||
 | 
					    Session: "_ScopeName" = "session"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next_lower(self) -> "Scope":
 | 
				
			||||||
 | 
					        """Return the next lower scope."""
 | 
				
			||||||
 | 
					        index = _SCOPE_INDICES[self]
 | 
				
			||||||
 | 
					        if index == 0:
 | 
				
			||||||
 | 
					            raise ValueError(f"{self} is the lower-most scope")
 | 
				
			||||||
 | 
					        return _ALL_SCOPES[index - 1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next_higher(self) -> "Scope":
 | 
				
			||||||
 | 
					        """Return the next higher scope."""
 | 
				
			||||||
 | 
					        index = _SCOPE_INDICES[self]
 | 
				
			||||||
 | 
					        if index == len(_SCOPE_INDICES) - 1:
 | 
				
			||||||
 | 
					            raise ValueError(f"{self} is the upper-most scope")
 | 
				
			||||||
 | 
					        return _ALL_SCOPES[index + 1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __lt__(self, other: "Scope") -> bool:
 | 
				
			||||||
 | 
					        self_index = _SCOPE_INDICES[self]
 | 
				
			||||||
 | 
					        other_index = _SCOPE_INDICES[other]
 | 
				
			||||||
 | 
					        return self_index < other_index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def from_user(
 | 
				
			||||||
 | 
					        cls, scope_name: "_ScopeName", descr: str, where: Optional[str] = None
 | 
				
			||||||
 | 
					    ) -> "Scope":
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Given a scope name from the user, return the equivalent Scope enum. Should be used
 | 
				
			||||||
 | 
					        whenever we want to convert a user provided scope name to its enum object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the scope name is invalid, construct a user friendly message and call pytest.fail.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        from _pytest.outcomes import fail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return Scope(scope_name)
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            fail(
 | 
				
			||||||
 | 
					                "{} {}got an unexpected scope value '{}'".format(
 | 
				
			||||||
 | 
					                    descr, f"from {where} " if where else "", scope_name
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                pytrace=False,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_ALL_SCOPES = list(Scope)
 | 
				
			||||||
 | 
					_SCOPE_INDICES = {scope: index for index, scope in enumerate(_ALL_SCOPES)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Ordered list of scopes which can contain many tests (in practice all except Function).
 | 
				
			||||||
 | 
					HIGH_SCOPES = [x for x in Scope if x is not Scope.Function]
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ from _pytest.config import ExitCode
 | 
				
			||||||
from _pytest.config.argparsing import Parser
 | 
					from _pytest.config.argparsing import Parser
 | 
				
			||||||
from _pytest.fixtures import FixtureDef
 | 
					from _pytest.fixtures import FixtureDef
 | 
				
			||||||
from _pytest.fixtures import SubRequest
 | 
					from _pytest.fixtures import SubRequest
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_addoption(parser: Parser) -> None:
 | 
					def pytest_addoption(parser: Parser) -> None:
 | 
				
			||||||
| 
						 | 
					@ -64,7 +65,9 @@ def _show_fixture_action(fixturedef: FixtureDef[object], msg: str) -> None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tw = config.get_terminal_writer()
 | 
					    tw = config.get_terminal_writer()
 | 
				
			||||||
    tw.line()
 | 
					    tw.line()
 | 
				
			||||||
    tw.write(" " * 2 * fixturedef.scopenum)
 | 
					    # Use smaller indentation the higher the scope: Session = 0, Package = 1, etc.
 | 
				
			||||||
 | 
					    scope_indent = list(reversed(Scope)).index(fixturedef._scope)
 | 
				
			||||||
 | 
					    tw.write(" " * 2 * scope_indent)
 | 
				
			||||||
    tw.write(
 | 
					    tw.write(
 | 
				
			||||||
        "{step} {scope} {fixture}".format(
 | 
					        "{step} {scope} {fixture}".format(
 | 
				
			||||||
            step=msg.ljust(8),  # align the output to TEARDOWN
 | 
					            step=msg.ljust(8),  # align the output to TEARDOWN
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,13 +29,12 @@ from _pytest.python import Class
 | 
				
			||||||
from _pytest.python import Function
 | 
					from _pytest.python import Function
 | 
				
			||||||
from _pytest.python import PyCollector
 | 
					from _pytest.python import PyCollector
 | 
				
			||||||
from _pytest.runner import CallInfo
 | 
					from _pytest.runner import CallInfo
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    import unittest
 | 
					    import unittest
 | 
				
			||||||
    import twisted.trial.unittest
 | 
					    import twisted.trial.unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from _pytest.fixtures import _Scope
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _SysExcInfoType = Union[
 | 
					    _SysExcInfoType = Union[
 | 
				
			||||||
        Tuple[Type[BaseException], BaseException, types.TracebackType],
 | 
					        Tuple[Type[BaseException], BaseException, types.TracebackType],
 | 
				
			||||||
        Tuple[None, None, None],
 | 
					        Tuple[None, None, None],
 | 
				
			||||||
| 
						 | 
					@ -102,7 +101,7 @@ class UnitTestCase(Class):
 | 
				
			||||||
            "setUpClass",
 | 
					            "setUpClass",
 | 
				
			||||||
            "tearDownClass",
 | 
					            "tearDownClass",
 | 
				
			||||||
            "doClassCleanups",
 | 
					            "doClassCleanups",
 | 
				
			||||||
            scope="class",
 | 
					            scope=Scope.Class,
 | 
				
			||||||
            pass_self=False,
 | 
					            pass_self=False,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        if class_fixture:
 | 
					        if class_fixture:
 | 
				
			||||||
| 
						 | 
					@ -113,7 +112,7 @@ class UnitTestCase(Class):
 | 
				
			||||||
            "setup_method",
 | 
					            "setup_method",
 | 
				
			||||||
            "teardown_method",
 | 
					            "teardown_method",
 | 
				
			||||||
            None,
 | 
					            None,
 | 
				
			||||||
            scope="function",
 | 
					            scope=Scope.Function,
 | 
				
			||||||
            pass_self=True,
 | 
					            pass_self=True,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        if method_fixture:
 | 
					        if method_fixture:
 | 
				
			||||||
| 
						 | 
					@ -125,7 +124,7 @@ def _make_xunit_fixture(
 | 
				
			||||||
    setup_name: str,
 | 
					    setup_name: str,
 | 
				
			||||||
    teardown_name: str,
 | 
					    teardown_name: str,
 | 
				
			||||||
    cleanup_name: Optional[str],
 | 
					    cleanup_name: Optional[str],
 | 
				
			||||||
    scope: "_Scope",
 | 
					    scope: Scope,
 | 
				
			||||||
    pass_self: bool,
 | 
					    pass_self: bool,
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    setup = getattr(obj, setup_name, None)
 | 
					    setup = getattr(obj, setup_name, None)
 | 
				
			||||||
| 
						 | 
					@ -141,7 +140,7 @@ def _make_xunit_fixture(
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.fixture(
 | 
					    @pytest.fixture(
 | 
				
			||||||
        scope=scope,
 | 
					        scope=scope.value,
 | 
				
			||||||
        autouse=True,
 | 
					        autouse=True,
 | 
				
			||||||
        # Use a unique name to speed up lookup.
 | 
					        # Use a unique name to speed up lookup.
 | 
				
			||||||
        name=f"_unittest_{setup_name}_fixture_{obj.__qualname__}",
 | 
					        name=f"_unittest_{setup_name}_fixture_{obj.__qualname__}",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ from _pytest.outcomes import fail
 | 
				
			||||||
from _pytest.pytester import Pytester
 | 
					from _pytest.pytester import Pytester
 | 
				
			||||||
from _pytest.python import _idval
 | 
					from _pytest.python import _idval
 | 
				
			||||||
from _pytest.python import idmaker
 | 
					from _pytest.python import idmaker
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestMetafunc:
 | 
					class TestMetafunc:
 | 
				
			||||||
| 
						 | 
					@ -142,16 +143,16 @@ class TestMetafunc:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @attr.s
 | 
					        @attr.s
 | 
				
			||||||
        class DummyFixtureDef:
 | 
					        class DummyFixtureDef:
 | 
				
			||||||
            scope = attr.ib()
 | 
					            _scope = attr.ib()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fixtures_defs = cast(
 | 
					        fixtures_defs = cast(
 | 
				
			||||||
            Dict[str, Sequence[fixtures.FixtureDef[object]]],
 | 
					            Dict[str, Sequence[fixtures.FixtureDef[object]]],
 | 
				
			||||||
            dict(
 | 
					            dict(
 | 
				
			||||||
                session_fix=[DummyFixtureDef("session")],
 | 
					                session_fix=[DummyFixtureDef(Scope.Session)],
 | 
				
			||||||
                package_fix=[DummyFixtureDef("package")],
 | 
					                package_fix=[DummyFixtureDef(Scope.Package)],
 | 
				
			||||||
                module_fix=[DummyFixtureDef("module")],
 | 
					                module_fix=[DummyFixtureDef(Scope.Module)],
 | 
				
			||||||
                class_fix=[DummyFixtureDef("class")],
 | 
					                class_fix=[DummyFixtureDef(Scope.Class)],
 | 
				
			||||||
                func_fix=[DummyFixtureDef("function")],
 | 
					                func_fix=[DummyFixtureDef(Scope.Function)],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,29 +161,33 @@ class TestMetafunc:
 | 
				
			||||||
        def find_scope(argnames, indirect):
 | 
					        def find_scope(argnames, indirect):
 | 
				
			||||||
            return _find_parametrized_scope(argnames, fixtures_defs, indirect=indirect)
 | 
					            return _find_parametrized_scope(argnames, fixtures_defs, indirect=indirect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert find_scope(["func_fix"], indirect=True) == "function"
 | 
					        assert find_scope(["func_fix"], indirect=True) == Scope.Function
 | 
				
			||||||
        assert find_scope(["class_fix"], indirect=True) == "class"
 | 
					        assert find_scope(["class_fix"], indirect=True) == Scope.Class
 | 
				
			||||||
        assert find_scope(["module_fix"], indirect=True) == "module"
 | 
					        assert find_scope(["module_fix"], indirect=True) == Scope.Module
 | 
				
			||||||
        assert find_scope(["package_fix"], indirect=True) == "package"
 | 
					        assert find_scope(["package_fix"], indirect=True) == Scope.Package
 | 
				
			||||||
        assert find_scope(["session_fix"], indirect=True) == "session"
 | 
					        assert find_scope(["session_fix"], indirect=True) == Scope.Session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert find_scope(["class_fix", "func_fix"], indirect=True) == "function"
 | 
					        assert find_scope(["class_fix", "func_fix"], indirect=True) == Scope.Function
 | 
				
			||||||
        assert find_scope(["func_fix", "session_fix"], indirect=True) == "function"
 | 
					        assert find_scope(["func_fix", "session_fix"], indirect=True) == Scope.Function
 | 
				
			||||||
        assert find_scope(["session_fix", "class_fix"], indirect=True) == "class"
 | 
					        assert find_scope(["session_fix", "class_fix"], indirect=True) == Scope.Class
 | 
				
			||||||
        assert find_scope(["package_fix", "session_fix"], indirect=True) == "package"
 | 
					        assert (
 | 
				
			||||||
        assert find_scope(["module_fix", "session_fix"], indirect=True) == "module"
 | 
					            find_scope(["package_fix", "session_fix"], indirect=True) == Scope.Package
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        assert find_scope(["module_fix", "session_fix"], indirect=True) == Scope.Module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # when indirect is False or is not for all scopes, always use function
 | 
					        # when indirect is False or is not for all scopes, always use function
 | 
				
			||||||
        assert find_scope(["session_fix", "module_fix"], indirect=False) == "function"
 | 
					        assert (
 | 
				
			||||||
 | 
					            find_scope(["session_fix", "module_fix"], indirect=False) == Scope.Function
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        assert (
 | 
					        assert (
 | 
				
			||||||
            find_scope(["session_fix", "module_fix"], indirect=["module_fix"])
 | 
					            find_scope(["session_fix", "module_fix"], indirect=["module_fix"])
 | 
				
			||||||
            == "function"
 | 
					            == Scope.Function
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert (
 | 
					        assert (
 | 
				
			||||||
            find_scope(
 | 
					            find_scope(
 | 
				
			||||||
                ["session_fix", "module_fix"], indirect=["session_fix", "module_fix"]
 | 
					                ["session_fix", "module_fix"], indirect=["session_fix", "module_fix"]
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            == "module"
 | 
					            == Scope.Module
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parametrize_and_id(self) -> None:
 | 
					    def test_parametrize_and_id(self) -> None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from _pytest.scope import Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_ordering() -> None:
 | 
				
			||||||
 | 
					    assert Scope.Session > Scope.Package
 | 
				
			||||||
 | 
					    assert Scope.Package > Scope.Module
 | 
				
			||||||
 | 
					    assert Scope.Module > Scope.Class
 | 
				
			||||||
 | 
					    assert Scope.Class > Scope.Function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_next_lower() -> None:
 | 
				
			||||||
 | 
					    assert Scope.Session.next_lower() is Scope.Package
 | 
				
			||||||
 | 
					    assert Scope.Package.next_lower() is Scope.Module
 | 
				
			||||||
 | 
					    assert Scope.Module.next_lower() is Scope.Class
 | 
				
			||||||
 | 
					    assert Scope.Class.next_lower() is Scope.Function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError, match="Function is the lower-most scope"):
 | 
				
			||||||
 | 
					        Scope.Function.next_lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_next_higher() -> None:
 | 
				
			||||||
 | 
					    assert Scope.Function.next_higher() is Scope.Class
 | 
				
			||||||
 | 
					    assert Scope.Class.next_higher() is Scope.Module
 | 
				
			||||||
 | 
					    assert Scope.Module.next_higher() is Scope.Package
 | 
				
			||||||
 | 
					    assert Scope.Package.next_higher() is Scope.Session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with pytest.raises(ValueError, match="Session is the upper-most scope"):
 | 
				
			||||||
 | 
					        Scope.Session.next_higher()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_from_user() -> None:
 | 
				
			||||||
 | 
					    assert Scope.from_user("module", "for parametrize", "some::id") is Scope.Module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expected_msg = "for parametrize from some::id got an unexpected scope value 'foo'"
 | 
				
			||||||
 | 
					    with pytest.raises(pytest.fail.Exception, match=re.escape(expected_msg)):
 | 
				
			||||||
 | 
					        Scope.from_user("foo", "for parametrize", "some::id")  # type:ignore[arg-type]
 | 
				
			||||||
		Loading…
	
		Reference in New Issue