Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor internal scope handling by introducing Scope enum
This replaces the internal use of string literals and "scopenum" to a proper Scope enum, which also centralizes ordering, getting higher and lower scopes, etc. Another benefit is that it helps the type checker by introducing a proper type, and improves readability. Added a trivial changelog as courtesy for plugin authors that used the removed attribute. This is _mostly_ an internal change, however due to historical reasons, the API of the following _internal_ objects has changed slightly: * `CallSpec2`: `_arg2scopenum` renamed to `_arg2scope` for consistency. * `FixtureRequest`: Previously contained a `scope: str` attribute. Changed attribute to `_scope: Scope`, with a read-only property `scope -> str`. * `SubRequest.__init__` parameter changed from `_Scope` to `Scope`.
- Loading branch information
1 parent
6247a95
commit e151f2e
Showing
9 changed files
with
298 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The private ``CallSpec2._arg2scopenum`` attribute has been removed after an internal refactoring. |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.