scope.py
Overview
The `scope.py` file defines and manages the concept of *fixture scopes* used in the pytest testing framework. Fixture scopes specify the lifetime and sharing boundaries of fixtures, controlling when and how often fixtures are set up and torn down during test execution.
This module centralizes the `Scope` enumeration and related utilities, enabling consistent handling of fixture scopes across many pytest modules without causing circular imports. It purposely remains lightweight and independent of the broader `fixtures` module to facilitate easy imports and reuse.
The defined scopes are ordered from the narrowest/lower scope (`function`) to the broadest/higher scope (`session`), reflecting the typical lifecycle and visibility of test fixtures.
Classes and Functions
Scope (Enum)
Represents one of the possible fixture scopes in pytest and provides utilities for scope comparison and navigation.
Scopes Defined (from narrowest to broadest):
Scope | Description |
|---|---|
function | Fixture is created for each test function. |
class | Fixture is shared among tests within a class. |
module | Fixture is shared among tests within a module. |
package | Fixture is shared among tests within a package. |
session | Fixture is shared across the entire test session. |
Properties & Methods
Properties (Enum members)
FunctionClassModulePackageSession
Each corresponds to a string literal of the same name.
next_lower(self) -> Scope
Returns the next lower (narrower) scope relative to the current scope.
Returns:
AScopeinstance representing the next lower scope.Raises:
ValueErrorif the current scope is already the lowest (Function).Example:
scope = Scope.Module
lower_scope = scope.next_lower()
print(lower_scope) # Output: Scope.Class
next_higher(self) -> Scope
Returns the next higher (broader) scope relative to the current scope.
Returns:
AScopeinstance representing the next higher scope.Raises:
ValueErrorif the current scope is already the highest (Session).Example:
scope = Scope.Class
higher_scope = scope.next_higher()
print(higher_scope) # Output: Scope.Module
__lt__(self, other: Scope) -> bool
Implements comparison logic to allow ordering of scopes, enabling the use of `<` to compare scopes by their hierarchy.
Parameters:
other: AnotherScopeinstance to compare with.Returns:
Trueifselfis a lower scope thanother,Falseotherwise.Example:
print(Scope.Function < Scope.Module) # Output: True
print(Scope.Session < Scope.Package) # Output: False
from_user(cls, scope_name: _ScopeName, descr: str, where: str | None = None) -> Scope
Class method to convert a user-provided scope name (string) into the corresponding `Scope` enum instance. It performs validation and raises a user-friendly failure via `pytest.fail` if the input is invalid.
Parameters:
scope_name(Literal["session", "package", "module", "class", "function"]): The user provided scope string.descr(str): Description of the entity requesting the scope (used in error messages).where(str | None): Optional context string indicating where the scope name was provided (used in error messages).
Returns:
The correspondingScopeenum instance.Raises:
Callspytest.failwith a descriptive error message ifscope_nameis invalid.Usage:
This method should be used anywhere a user-supplied scope string needs to be safely converted toScope.Example:
scope = Scope.from_user("module", "fixture scope", "in test_config.py")
print(scope) # Output: Scope.Module
If an invalid scope is passed:
Scope.from_user("invalidscope", "fixture scope")
# Will call pytest.fail with message like:
# "fixture scope got an unexpected scope value 'invalidscope'"
Module-level Variables
_ALL_SCOPES
A list of allScopeenum members in order from lowest to highest._SCOPE_INDICES
A dictionary mapping eachScopeinstance to its integer index in_ALL_SCOPESfor fast lookup.HIGH_SCOPES
A list of scopes which can contain many tests (i.e., all scopes exceptFunction), useful for filtering or categorizing scopes by their breadth.
Implementation Details and Algorithms
Ordering:
TheScopeenum members are deliberately ordered from the narrowest (Function) to the broadest (Session) fixture scope.
The ordering enables meaningful comparison operations (via__lt__) and navigation (next_lower,next_higher).Error Handling:
Thefrom_usermethod usespytest.failto report invalid user input instead of raising standard exceptions. This integrates with pytest's test failure reporting infrastructure, providing clean failure messages during test collection or setup.Typing and Compatibility:
Uses Python 3.7+ typing features (Literal,|for union) and@total_orderingdecorator to implement all rich comparison methods by defining only__lt__.Separation of Concerns:
This module intentionally avoids importing or depending on the fullfixturesmodule to reduce import complexity and avoid circular dependencies within pytest codebase.
Interaction with Other System Components
This module is foundational for pytest's fixture management system. It is used wherever fixture scopes need to be interpreted, compared, or validated.
The
Scopeenum and utilities are imported by various pytest modules related to fixture lifecycle management, test collection, and execution phases.The
from_usermethod depends on_pytest.outcomes.failto report errors, linking it to pytest's error handling framework.The
HIGH_SCOPESvariable may be used to categorize or iterate over broader scopes during fixture setup or teardown orchestration.
Visual Diagram
classDiagram
class Scope {
<<Enum>>
+Function: Scope
+Class: Scope
+Module: Scope
+Package: Scope
+Session: Scope
+next_lower() Scope
+next_higher() Scope
+from_user(scope_name: _ScopeName, descr: str, where: Optional[str]) Scope
+__lt__(other: Scope) bool
}
Scope o-- "_ALL_SCOPES: List[Scope]" : uses
Scope o-- "_SCOPE_INDICES: Dict[Scope, int]" : uses
Scope ..> "pytest.outcomes.fail" : calls
Summary
The `scope.py` file encapsulates the concept of fixture scopes in pytest as a strongly ordered `Enum` with convenient navigation and validation methods. It plays a critical role in the fixture management system by providing a simple, lightweight, and consistent interface for scope handling across pytest's codebase. Its design carefully avoids heavy dependencies, making it a reusable utility module.
Example Usage Snippet
from scope import Scope
# Get a scope from user input and handle errors gracefully
try:
user_scope = Scope.from_user("module", "fixture scope")
except Exception:
# This will not usually raise but fail inside pytest
pass
# Compare scopes
if Scope.Function < user_scope:
print(f"{Scope.Function} is narrower than {user_scope}")
# Navigate between scopes
higher = user_scope.next_higher() if user_scope != Scope.Session else user_scope
print(f"Next higher scope after {user_scope} is {higher}")