init.py
Overview
This module provides a generic mechanism for marking and selecting Python test functions within the pytest framework. Its primary focus is on handling test parameterization and filtering tests based on keywords or markers. It exposes core utilities such as the `param` function for defining parameter sets, and classes for matching keywords and markers in test selection. The module integrates tightly with pytest's command line interface (CLI) and collection hooks to enable expressive and flexible test selection using `-k` (keyword expressions) and `-m` (marker expressions) options.
Public API
The following names are exported for external use:
HIDDEN_PARAMMARK_GENMarkMarkDecoratorMarkGeneratorParameterSetget_empty_parameterset_markparam(function)
Detailed Explanations
Function: param
param(
*values: object,
marks: MarkDecorator | Collection[MarkDecorator | Mark] = (),
id: str | _HiddenParam | None = None,
) -> ParameterSet
Creates a parameter set for use in `pytest.mark.parametrize` calls or parametrized fixtures.
Parameters:
*values(object): Positional values defining a single parameter set in order.marks(MarkDecorator or Collection of MarkDecorator/Mark): Marks to apply to this parameter set (e.g.,pytest.mark.xfail).id(str orHIDDEN_PARAMor None): An optional identifier for the parameter set. IfHIDDEN_PARAMis used, the parameter set is hidden from the test name to avoid cluttering test output.
Returns:
AParameterSetinstance representing the parameter tuple with any associated marks and id.Usage Example:
import pytest
@pytest.mark.parametrize(
"input, expected",
[
("3+5", 8),
pytest.param("6*9", 42, marks=pytest.mark.xfail),
],
)
def test_eval(input, expected):
assert eval(input) == expected
Function: pytest_addoption
pytest_addoption(parser: Parser) -> None
Pytest hook to add CLI options related to test selection by keyword and marker expressions, as well as options to display registered markers.
Parameters:
parser(Parser): The pytest argument parser.
Functionality:
Adds
-koption for filtering tests by substring keyword expressions.Adds
-moption for filtering tests by marker expressions.Adds
--markersto display all registered markers.Adds ini-file options for registering markers and the default behavior for empty parameter sets.
Function: pytest_cmdline_main
def pytest_cmdline_main(config: Config) -> int | ExitCode | None
Pytest hook executed early during command line main execution.
Parameters:
config(Config): The pytest configuration object.
Functionality:
If
--markersis specified, this function outputs all markers registered in the current pytest session and then exits with status 0.Otherwise, returns
Noneto continue normal pytest execution.
Class: KeywordMatcher
@dataclasses.dataclass
class KeywordMatcher:
_names: AbstractSet[str]
@classmethod
def from_item(cls, item: Item) -> KeywordMatcher:
...
def __call__(self, subname: str, /) -> bool:
...
Matches tests based on keyword expressions (used with `-k`).
Attributes:
_names(AbstractSet[str]): A set of all relevant names to be matched against, including item names, parent names, extra keywords, function attributes, and marker names.
Methods:
from_item(item: Item) -> KeywordMatcher
Creates a matcher from a test item by collecting all relevant names for keyword matching.__call__(subname: str, /) -> bool
ReturnsTrueif thesubname(case-insensitive) is a substring of any name in_names. RaisesUsageErrorif called with keyword arguments.
Usage:
matcher = KeywordMatcher.from_item(test_item)
if matcher("somekeyword"):
# matched
Function: deselect_by_keyword
def deselect_by_keyword(items: list[Item], config: Config) -> None
Filters out test items that do not match the keyword expression provided via the `-k` option.
Parameters:
items(list ofItem): The list of collected test items.config(Config): The pytest configuration object.
Operation:
Parses the keyword expression using
_parse_expression.Retains only items for which the expression evaluates to
Truewhen passed aKeywordMatcher.Calls
pytest_deselectedhook for deselected items.
Class: MarkMatcher
@dataclasses.dataclass
class MarkMatcher:
own_mark_name_mapping: dict[str, list[Mark]]
@classmethod
def from_markers(cls, markers: Iterable[Mark]) -> MarkMatcher:
...
def __call__(self, name: str, /, **kwargs: str | int | bool | None) -> bool:
...
Matches test items based on marker expressions (used with `-m`).
Attributes:
own_mark_name_mapping(dict): Maps marker names to a list ofMarkinstances on an item.
Methods:
from_markers(markers: Iterable[Mark]) -> MarkMatcher
Builds a mapping from marker names to marks.__call__(name: str, /, **kwargs) -> bool
ReturnsTrueif any mark with the given name matches all specified keyword arguments exactly.
Usage:
matcher = MarkMatcher.from_markers(item.iter_markers())
if matcher("xfail", reason="some reason"):
# matched
Function: deselect_by_mark
def deselect_by_mark(items: list[Item], config: Config) -> None
Filters out test items that do not match the marker expression provided via the `-m` option.
Parameters:
items(list ofItem): The list of collected test items.config(Config): The pytest configuration object.
Operation:
Parses the marker expression using
_parse_expression.Retains items where the expression evaluates to
Truewhen passed aMarkMatcher.Calls
pytest_deselectedhook for deselected items.
Function: _parse_expression
def _parse_expression(expr: str, exc_message: str) -> Expression
Parses a string expression into an `Expression` object, handling parse errors by raising `UsageError` with a custom message.
Parameters:
expr(str): The expression string.exc_message(str): A message to include if parsing fails.
Returns:
Expression: A compiled expression object usable for evaluation.
Raises:
UsageErrorif expression parsing fails.
Hook: pytest_collection_modifyitems
def pytest_collection_modifyitems(items: list[Item], config: Config) -> None
Modifies the list of collected test items by deselecting tests based on keyword and marker expressions.
Parameters:
items(list ofItem): List of collected test items.config(Config): The pytest configuration object.
Operation:
Calls
deselect_by_keywordanddeselect_by_markto filter the items list in-place.
Hook: pytest_configure
def pytest_configure(config: Config) -> None
Called during pytest configuration phase.
Saves the current mark generator's configuration.
Sets the mark generator's config to the current pytest configuration.
Validates the ini option for empty parameter sets, raising
UsageErrorif invalid.
Hook: pytest_unconfigure
def pytest_unconfigure(config: Config) -> None
Called during pytest unconfiguration phase.
Restores the mark generator's previous configuration from the pytest stash.
Important Implementation Details
Expression Parsing and Evaluation:
Expressions for both keyword (-k) and marker (-m) selectors are parsed using theExpression.compile()method from the importedexpressionmodule. This allows complex logical expressions (e.g.,mark1 and not mark2) to be evaluated efficiently.Keyword Matching Strategy:
TheKeywordMatcherbuilds a comprehensive set of names including test item names, parent names, extra keyword matches, function attributes, and marker names to perform case-insensitive substring matching.Marker Matching Strategy:
TheMarkMatchermaps marker names to their instances on a test item and allows matching on marker names and specific keyword arguments.Integration with pytest Hooks:
The module hooks into pytest's CLI and collection lifecycle to add options, modify collected test items, and handle configuration changes related to test selection and parameterization.
Interactions with Other System Components
Imports from
structures.py,expression.py,config.py, andstash.py:
Utilizes data structures for marks, parameter sets, and expressions, and integrates with pytest's configuration and stash mechanisms.Interaction with pytest CLI and Collection System:
Implements hooks (pytest_addoption,pytest_cmdline_main,pytest_collection_modifyitems,pytest_configure,pytest_unconfigure) to influence CLI options and test item filtering.Test Item Objects (
Item):
Works heavily with pytest'sItemobjects representing collected tests to determine matching by keyword or marker.
Visual Diagram
classDiagram
class KeywordMatcher {
-_names: AbstractSet[str]
+from_item(item: Item) KeywordMatcher
+__call__(subname: str) bool
}
class MarkMatcher {
-own_mark_name_mapping: dict[str, list[Mark]]
+from_markers(markers: Iterable[Mark]) MarkMatcher
+__call__(name: str, **kwargs) bool
}
class ParameterSet {
+param(*values, marks=(), id=None) ParameterSet
}
class __init__py {
+param(*values, marks=(), id=None) ParameterSet
+pytest_addoption(parser: Parser)
+pytest_cmdline_main(config: Config) int | ExitCode | None
+deselect_by_keyword(items: list[Item], config: Config)
+deselect_by_mark(items: list[Item], config: Config)
+pytest_collection_modifyitems(items: list[Item], config: Config)
+pytest_configure(config: Config)
+pytest_unconfigure(config: Config)
}
__init__py --> ParameterSet : uses
__init__py --> KeywordMatcher : uses
__init__py --> MarkMatcher : uses
ParameterSet ..> MarkDecorator : composition
MarkMatcher ..> Mark : composition
KeywordMatcher ..> Item : depends on
MarkMatcher ..> Item : depends on
Summary
This [__init__.py](/projects/286/67254) file is a core component in pytest's marking and test selection system. It provides the machinery to define parameter sets with optional marks, parse CLI options for selecting tests based on keyword and marker expressions, and integrate these selections into the test collection and execution lifecycle. By leveraging expression parsing and matchers for keywords and markers, it enables powerful and flexible test filtering capabilities accessible directly via command line options.