-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Refactor internal scope handling by introducing Scope enum #8913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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.
| 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): | ||
nicoddemus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """ | ||
| 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": | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how often do we use this in lookup? i see us using those all over the time regenerating them all the time off hand i cant tell of we have this in inner loops, but i'd really like to keep it out of loops in particular list(Scopes) looks like something we should just make a constant
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very rarely I think, but initially I had those implemented as external utility functions and cached. I'm happy to implement it like that again, if you agree.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done slightly different than the other time, and more in line with what you suggested before, let me know what you think. |
||
| """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: | ||
nicoddemus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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] | ||
nicoddemus marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.