1"""

2 Scope definition and related utilities.

3

4 Those are defined here, instead of in the 'fixtures' module because

5 their use is spread across many other pytest modules, and centralizing it in 'fixtures'

6 would cause circular references.

7

8 Also this makes the module light to import, as it should.

9"""

10 from enum import Enum

11 from functools import total_ordering

12 from typing import Optional

13 from typing import TYPE_CHECKING

14

15 if TYPE_CHECKING:

16 from typing_extensions import Literal

17

18 _ScopeName = Literal["session", "package", "module", "class", "function"]

19

20

21@total_ordering

22 class Scope(Enum):

23 """

24 Represents one of the possible fixture scopes in pytest.

25

26 Scopes are ordered from lower to higher, that is:

27

28 ->>> higher ->>>

29

30 Function < Class < Module < Package < Session

31

32 <<<- lower <<<-

33 """

34

35 # Scopes need to be listed from lower to higher.

36 Function: "_ScopeName" = "function"

37 Class: "_ScopeName" = "class"

38 Module: "_ScopeName" = "module"

39 Package: "_ScopeName" = "package"

40 Session: "_ScopeName" = "session"

41

42 def next_lower(self) -> "Scope":

43 """Return the next lower scope."""

44 index = _SCOPE_INDICES[self]

45 if index == 0:

46 raise ValueError(f"{self} is the lower-most scope")

47 return _ALL_SCOPES[index - 1]

48

49 def next_higher(self) -> "Scope":

50 """Return the next higher scope."""

51 index = _SCOPE_INDICES[self]

52 if index == len(_SCOPE_INDICES) - 1:

53 raise ValueError(f"{self} is the upper-most scope")

54 return _ALL_SCOPES[index + 1]

55

56 def __lt__(self, other: "Scope") -> bool:

57 self_index = _SCOPE_INDICES[self]

58 other_index = _SCOPE_INDICES[other]

59 return self_index < other_index

60

61 @classmethod

62 def from_user(

63 cls, scope_name: "_ScopeName", descr: str, where: Optional[str] = None

64 ) -> "Scope":

65 """

66 Given a scope name from the user, return the equivalent Scope enum. Should be used

67 whenever we want to convert a user provided scope name to its enum object.

68

69 If the scope name is invalid, construct a user friendly message and call pytest.fail.

70 """

71 from _pytest.outcomes import fail

72

73 try:

74 # Holding this reference is necessary for mypy at the moment.

75 scope = Scope(scope_name)

76 except ValueError:

77 fail(

78 "{} {}got an unexpected scope value '{}'".format(

79 descr, f"from {where} " if where else "", scope_name

80 ),

81 pytrace=False,

82 )

83 return scope

84

85

86_ALL_SCOPES = list(Scope)

87_SCOPE_INDICES = {scope: index for index, scope in enumerate(_ALL_SCOPES)}

88

89

90# Ordered list of scopes which can contain many tests (in practice all except Function).

91 HIGH_SCOPES = [x for x in Scope if x is not Scope.Function]