historical-notes.rst
Overview
This file serves as a comprehensive historical record of changes and deprecated features in **pytest**, a popular Python testing framework. It documents how specific functionalities, especially related to markers, fixtures, configuration, and plugins, have evolved across different pytest versions. The purpose of this document is to assist users and developers in understanding legacy behaviors, facilitate migration from older pytest versions, and provide context for certain design decisions.
The file is written in reStructuredText format (`.rst`) and is intended to be included in the pytest documentation to aid users who encounter or maintain older codebases.
Detailed Explanations
Marker revamp and iteration
**Section Reference:** `marker-revamp`
**Purpose:** Describes the major redesign of pytest's marker system introduced in pytest 3.6.
**Key Concepts:**
Old Behavior:
Markers were stored by modifying the dict of test functions directly, resulting in confusing inheritance and inconsistent APIs. Different marker sources (decorators, parameterization, dynamic additions) used different internal representations (MarkerInfo,MarkDecorator), causing bugs.New API:
Introduced the methodNode.iter_markers()to provide a consistent way to iterate over markers, solving problems related to marker inheritance, accessibility (modules/classes/functions), and merging multiple marks.
**Implications:** Users should move away from deprecated methods like [Node.get_marker()](/projects/286/67332) and adopt `iter_markers()` and `get_closest_marker()` for reliable marker access.
**Usage Example:**
for skipif_marker in item.iter_markers("skipif"):
condition = skipif_marker.args[0]
# Evaluate condition here
Updating code
**Section Reference:** `update marker code`
**Purpose:** Guidance on migrating old marker access patterns to the new API.
**Two scenarios for marker handling:**
Overwriting marks: Only the closest mark matters (e.g., log level).
marker = item.get_closest_marker("log_level") if marker: level = marker.args[0]Additive marks: All marks apply (e.g., multiple skipif conditions).
for skipif in item.iter_markers("skipif"): condition = skipif.args[0] # process condition
Related issues
Lists important bugs and feature requests resolved by the marker revamp, with issue numbers for reference. Examples include:
Marker inheritance issues (e.g., nested classes, class hierarchies)
Marker merging and argument handling
Compatibility fixes for parameterization and marker application
cache plugin integrated into the core
Explains that the formerly third-party `pytest-cache` plugin has been integrated into pytest core, with some limitations (only JSON serializable data can be cached).
funcargs and pytest_funcarg__
Describes the legacy fixture declaration method using the `pytest_funcarg__NAME` naming convention before the introduction of `@pytest.fixture` in version 2.3. This method is still supported but deprecated.
@pytest.yield_fixture decorator
Before pytest 2.10, `yield_fixture` was required to write fixtures using yield for teardown. Post-2.10, normal fixtures support `yield` natively, and `yield_fixture` is deprecated.
[pytest] header in setup.cfg
Previously the configuration section header was `[pytest]`. Due to conflicts with distutils commands, `[tool:pytest]` is now recommended for `setup.cfg`. For `pytest.ini` and `tox.ini`, `[pytest]` remains the section name.
Applying marks to @pytest.mark.parametrize parameters
Prior to version 3.1, marking individual parameters in `parametrize` used a hacky syntax that was incomplete and buggy. This old syntax is planned for removal in pytest 4.0.
@pytest.mark.parametrize argument names as tuple
Before 2.4, argument names in parametrize had to be specified as a tuple. Now a simpler comma-separated string syntax is preferred.
setup: is now an "autouse fixture"
The old `pytest.setup` hook was replaced by autouse fixtures starting before pytest 2.3.
Conditions as strings instead of booleans
Before pytest 2.4, skipif/xfail conditions were expressed as strings evaluated via `eval()`. Since then, boolean expressions are preferred for better importability and encapsulation. String conditions remain supported.
**Evaluation namespace:** includes `sys`, `os`, `pytest.config`, and module globals.
**Example:**
@pytest.mark.skipif("sys.version_info >= (3,3)")
def test_func():
...
is better written as:
@pytest.mark.skipif(sys.version_info >= (3,3), reason="Python version too low")
def test_func():
...
pytest.set_trace()
Deprecated since version 2.4. Use standard Python debugger calls (`import pdb; pdb.set_trace()`) instead.
"compat" properties
Access to types such as `Module`, `Function`, `Class`, etc. through `Node` objects is deprecated since pytest 3.9. Users should import these directly from the `pytest` module.
Important Implementation Details
The marker revamp involved a significant redesign of internal marker storage and retrieval, moving away from direct dictionary manipulation toward a consistent API (
Node.iter_markers()), improving reliability across test nodes (modules, classes, functions).Condition evaluation for skipif/xfail uses dynamic namespace construction combining system modules and test globals for string-based conditions.
The integration of
pytest-cacheinto core standardizes caching behavior, with JSON serializability constraints.The fixture system evolved from magic naming (
pytest_funcarg__) to decorators (@pytest.fixture), improving readability and maintainability.
Interactions With Other Parts of the System
Markers: This file references the internal
Nodeclass and its methods (get_marker(),get_closest_marker(),iter_markers()), which are part of the pytest node hierarchy and test collection mechanism.Cache Plugin: The caching mechanism mentioned here interacts with pytest's core plugin system and test session lifecycle.
Fixtures: The legacy fixture mechanisms relate to pytest's fixture management subsystem.
Configuration Files: Changes to config file section names affect pytest's configuration parsing components.
Parametrization: The handling of marks on parameters relates to pytest's test parameterization engine.
Debugging: The deprecation of
pytest.set_trace()affects the debugging support utilities.
Visual Diagram: Marker API Evolution Class Diagram
classDiagram
class Node {
+get_marker(name): MarkerInfo (deprecated)
+get_closest_marker(name): Mark
+iter_markers(name=None): iterator~Mark~
}
class MarkerInfo {
+name: str
+args: tuple
+kwargs: dict
}
class Mark {
+name: str
+args: tuple
+kwargs: dict
}
Node --> MarkerInfo : old marker API
Node --> Mark : new marker API
Summary
The [historical-notes.rst](/projects/286/67223) file is a vital resource documenting the evolution of key pytest features. It helps users migrate older tests to newer pytest versions and understand the rationale behind deprecated practices and new recommended patterns. The focus on markers, fixtures, configuration, and plugins highlights pytest's continuous improvement and commitment to usability and robustness.