Skip to content

Commit ee47d2d

Browse files
authored
♻️ refactor: modernize for Python 3.10+ and public pytest APIs (#202)
1 parent a85a746 commit ee47d2d

File tree

9 files changed

+113
-130
lines changed

9 files changed

+113
-130
lines changed

.pre-commit-config.yaml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,31 @@ repos:
55
- id: end-of-file-fixer
66
- id: trailing-whitespace
77
- repo: https://github.com/python-jsonschema/check-jsonschema
8-
rev: 0.36.0
8+
rev: 0.36.1
99
hooks:
1010
- id: check-github-workflows
1111
args: ["--verbose"]
1212
- repo: https://github.com/codespell-project/codespell
1313
rev: v2.4.1
1414
hooks:
1515
- id: codespell
16-
additional_dependencies: ["tomli>=2.2.1"]
17-
- repo: https://github.com/tox-dev/tox-ini-fmt
18-
rev: "1.7.1"
16+
additional_dependencies: ["tomli>=2.4"]
17+
- repo: https://github.com/tox-dev/tox-toml-fmt
18+
rev: "v1.5.4"
1919
hooks:
20-
- id: tox-ini-fmt
21-
args: ["-p", "fix"]
20+
- id: tox-toml-fmt
2221
- repo: https://github.com/tox-dev/pyproject-fmt
23-
rev: "v2.11.1"
22+
rev: "v2.15.2"
2423
hooks:
2524
- id: pyproject-fmt
2625
- repo: https://github.com/astral-sh/ruff-pre-commit
27-
rev: "v0.14.10"
26+
rev: "v0.15.0"
2827
hooks:
2928
- id: ruff-format
3029
- id: ruff
3130
args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"]
3231
- repo: https://github.com/rbubley/mirrors-prettier
33-
rev: "v3.7.4"
32+
rev: "v3.8.1"
3433
hooks:
3534
- id: prettier
3635
args: ["--print-width=120", "--prose-wrap=always"]

pyproject.toml

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
build-backend = "hatchling.build"
33
requires = [
44
"hatch-vcs>=0.5",
5-
"hatchling>=1.27",
5+
"hatchling>=1.28",
66
]
77

88
[project]
99
name = "pytest-print"
10-
description = "pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not stdout)"
10+
description = """\
11+
pytest-print adds the printer fixture you can use to print messages to the user (directly to the pytest runner, not \
12+
stdout)\
13+
"""
1114
readme = "README.md"
1215
keywords = [
1316
"env",
@@ -36,11 +39,11 @@ dynamic = [
3639
"version",
3740
]
3841
dependencies = [
39-
"pytest>=8.4.2",
42+
"pytest>=9.0.2",
4043
]
4144
optional-dependencies.test = [
4245
"covdefaults>=2.3",
43-
"coverage>=7.10.7",
46+
"coverage>=7.13.4",
4447
"pytest-mock>=3.15.1",
4548
]
4649
urls.Homepage = "https://github.com/pytest-dev/pytest-print"
@@ -67,6 +70,7 @@ lint.ignore = [
6770
"D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible
6871
"DOC", # no support
6972
"ISC001", # Conflict with formatter
73+
"RUF067", # code in __init__ modules is intentional
7074
"S104", # Possible binding to all interface
7175
]
7276
lint.per-file-ignores."tests/**/*.py" = [
@@ -93,20 +97,16 @@ count = true
9397
max_supported_python = "3.13"
9498

9599
[tool.coverage]
100+
run.branch = true
101+
run.dynamic_context = "test_function"
102+
run.parallel = true
103+
run.plugins = [
104+
"covdefaults",
105+
]
96106
run.source = [
97107
"pytest_print",
98108
"tests",
99109
]
100-
run.dynamic_context = "test_function"
101-
run.branch = true
102-
run.parallel = true
103-
report.omit = [
104-
"tests/example_*.py",
105-
]
106-
report.fail_under = 100
107-
report.show_missing = true
108-
html.show_contexts = true
109-
html.skip_covered = false
110110
paths.source = [
111111
"src",
112112
".tox*/*/lib/python*/site-packages",
@@ -115,11 +115,13 @@ paths.source = [
115115
"*/src",
116116
"*\\src",
117117
]
118-
run.plugins = [
119-
"covdefaults",
118+
report.fail_under = 100
119+
report.omit = [
120+
"tests/example_*.py",
120121
]
122+
report.show_missing = true
123+
html.show_contexts = true
124+
html.skip_covered = false
121125

122-
[tool.mypy]
123-
python_version = "3.13"
124-
show_error_codes = true
125-
strict = true
126+
[tool.ty]
127+
environment.python-version = "3.14"

src/pytest_print/__init__.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import sys
65
from dataclasses import dataclass, replace
76
from timeit import default_timer
87
from typing import TYPE_CHECKING, Protocol, TypeVar, cast
@@ -11,8 +10,6 @@
1110

1211
if TYPE_CHECKING:
1312
from _pytest.capture import CaptureManager
14-
from _pytest.fixtures import SubRequest
15-
from _pytest.terminal import TerminalReporter
1613

1714

1815
def pytest_addoption(parser: pytest.Parser) -> None:
@@ -45,7 +42,7 @@ def __call__(self, msg: str) -> None:
4542

4643

4744
@pytest.fixture(scope="session")
48-
def printer_session(request: SubRequest) -> Printer:
45+
def printer_session(request: pytest.FixtureRequest) -> Printer:
4946
"""Pytest plugin to print test progress steps in verbose mode (session scoped)."""
5047
return _create(request, _Printer, Formatter())
5148

@@ -76,7 +73,7 @@ def indent(self, *, icon: str) -> PrettyPrinter:
7673

7774

7875
@pytest.fixture(scope="session")
79-
def pretty_printer(request: SubRequest) -> PrettyPrinter:
76+
def pretty_printer(request: pytest.FixtureRequest) -> PrettyPrinter:
8077
"""Pytest plugin to print test progress steps in verbose mode."""
8178
formatter = Formatter(head=" ", icon="⏩", space=" ", indentation=" ", timer_fmt="[{elapsed:.20f}]")
8279
return _create(request, _PrettyPrinter, formatter)
@@ -94,17 +91,16 @@ def __call__(self, *, formatter: Formatter) -> PrettyPrinter:
9491

9592

9693
@pytest.fixture(scope="session")
97-
def create_pretty_printer(request: SubRequest) -> PrettyPrinterFactory:
94+
def create_pretty_printer(request: pytest.FixtureRequest) -> PrettyPrinterFactory:
9895
"""Pytest plugin to print test progress steps in verbose mode."""
99-
Formatter(head=" ", icon="⏩", space=" ", indentation=" ", timer_fmt="[{elapsed:.20f}]")
10096

10197
def meth(*, formatter: Formatter) -> PrettyPrinter:
10298
return _create(request, _PrettyPrinter, formatter)
10399

104100
return meth
105101

106102

107-
@dataclass(frozen=True, **{"slots": True, "kw_only": True} if sys.version_info >= (3, 10) else {})
103+
@dataclass(frozen=True, slots=True, kw_only=True)
108104
class Formatter:
109105
"""Configures how to format messages to be printed."""
110106

@@ -137,7 +133,7 @@ class _Printer:
137133
def __init__(
138134
self,
139135
*,
140-
reporter: TerminalReporter | None,
136+
reporter: pytest.TerminalReporter | None,
141137
capture_manager: CaptureManager | None,
142138
formatter: Formatter,
143139
level: int,
@@ -177,9 +173,9 @@ def indent(self, *, icon: str) -> PrettyPrinter:
177173
_OfType = TypeVar("_OfType", bound=_Printer)
178174

179175

180-
def _create(request: SubRequest, of_type: type[_OfType], formatter: Formatter) -> _OfType:
176+
def _create(request: pytest.FixtureRequest, of_type: type[_OfType], formatter: Formatter) -> _OfType:
181177
return of_type(
182-
reporter=cast("TerminalReporter | None", request.config.pluginmanager.getplugin("terminalreporter"))
178+
reporter=cast("pytest.TerminalReporter | None", request.config.pluginmanager.getplugin("terminalreporter"))
183179
if request.config.getoption("pytest_print_on") or cast("int", request.config.getoption("verbose")) > 0
184180
else None,
185181
capture_manager=cast("CaptureManager | None", request.config.pluginmanager.getplugin("capturemanager")),

tests/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@ def extract_printer_text(lines: list[str]) -> str:
1717
return re.sub(r"[ \t]+\n", "\n", output)
1818

1919

20-
def seed_test(filename: str, testdir: pytest.Testdir) -> pytest.Testdir:
20+
def seed_test(filename: str, pytester: pytest.Pytester) -> pytest.Pytester:
2121
src = Path(__file__).parent / filename
2222
assert src.exists()
23-
dest = Path(str(testdir.tmpdir)) / "test_a.py"
24-
copy2(src, dest)
25-
return testdir
23+
copy2(src, pytester.path / "test_a.py")
24+
return pytester
2625

2726

2827
__all__ = [

tests/test_create_pretty_print.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@
88

99

1010
@pytest.fixture
11-
def example(testdir: pytest.Testdir) -> pytest.Testdir:
12-
return seed_test("example_create_pretty_print.py", testdir)
11+
def example(pytester: pytest.Pytester) -> pytest.Pytester:
12+
return seed_test("example_create_pretty_print.py", pytester)
1313

1414

1515
def fix_floats_in_relative_time(txt: str) -> str:
1616
float_pattern = r"[-+]?\d*\.\d+([eE][-+]?\d+)?"
1717
return re.sub(float_pattern, "0.1", txt)
1818

1919

20-
def test_progress_no_v(example: pytest.Testdir) -> None:
20+
def test_progress_no_v(example: pytest.Pytester) -> None:
2121
result = example.runpytest()
2222
result.assert_outcomes(passed=3)
2323
assert " start server from virtual env" not in result.outlines
2424
assert "global peace" not in result.outlines
2525

2626

27-
def test_progress_v_no_relative(example: pytest.Testdir) -> None:
27+
def test_progress_v_no_relative(example: pytest.Pytester) -> None:
2828
result_verbose = example.runpytest("-v", "--print")
2929
result_verbose.assert_outcomes(passed=3)
3030

@@ -57,7 +57,7 @@ def test_progress_v_no_relative(example: pytest.Testdir) -> None:
5757
assert output == expected
5858

5959

60-
def test_progress_v_relative(example: pytest.Testdir) -> None:
60+
def test_progress_v_relative(example: pytest.Pytester) -> None:
6161
result_verbose_relative = example.runpytest(
6262
"--print",
6363
"-v",
@@ -83,7 +83,7 @@ def test_progress_v_relative(example: pytest.Testdir) -> None:
8383
assert output == expected
8484

8585

86-
def test_progress_no_v_but_with_print_request(example: pytest.Testdir) -> None:
86+
def test_progress_no_v_but_with_print_request(example: pytest.Pytester) -> None:
8787
result = example.runpytest("--print")
8888
result.assert_outcomes(passed=3)
8989
assert " 🚀 start server from virtual env" in result.outlines

tests/test_pretty_print.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99

1010
@pytest.fixture
11-
def example(testdir: pytest.Testdir) -> pytest.Testdir:
12-
return seed_test("example_pretty_print.py", testdir)
11+
def example(pytester: pytest.Pytester) -> pytest.Pytester:
12+
return seed_test("example_pretty_print.py", pytester)
1313

1414

1515
def fix_floats_in_relative_time(txt: str) -> str:
1616
float_pattern = r"[-+]?\d*\.\d+([eE][-+]?\d+)?"
1717
return re.sub(float_pattern, "0.1", txt)
1818

1919

20-
def test_progress_v_no_relative(example: pytest.Testdir) -> None:
20+
def test_progress_v_no_relative(example: pytest.Pytester) -> None:
2121
result = example.runpytest("-v", "--print")
2222
result.assert_outcomes(passed=1)
2323

@@ -37,7 +37,7 @@ def test_progress_v_no_relative(example: pytest.Testdir) -> None:
3737
assert output == expected
3838

3939

40-
def test_progress_v_relative(example: pytest.Testdir) -> None:
40+
def test_progress_v_relative(example: pytest.Pytester) -> None:
4141
result = example.runpytest(
4242
"--print",
4343
"-v",

tests/test_print.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66

77

88
@pytest.fixture
9-
def example(testdir: pytest.Testdir) -> pytest.Testdir:
10-
return seed_test("example_print.py", testdir)
9+
def example(pytester: pytest.Pytester) -> pytest.Pytester:
10+
return seed_test("example_print.py", pytester)
1111

1212

13-
def test_progress_no_v(example: pytest.Testdir) -> None:
13+
def test_progress_no_v(example: pytest.Pytester) -> None:
1414
result = example.runpytest()
1515
result.assert_outcomes(passed=2)
1616
assert " start server from virtual env" not in result.outlines
1717
assert "global peace" not in result.outlines
1818

1919

20-
def test_progress_v_no_relative(example: pytest.Testdir, monkeypatch: pytest.MonkeyPatch) -> None:
20+
def test_progress_v_no_relative(example: pytest.Pytester, monkeypatch: pytest.MonkeyPatch) -> None:
2121
monkeypatch.setattr("_pytest._io.terminalwriter.get_terminal_width", lambda: 80)
2222
monkeypatch.setenv("COLUMNS", str(80))
2323
result_verbose = example.runpytest("-v", "--print")
@@ -40,7 +40,7 @@ def test_progress_v_no_relative(example: pytest.Testdir, monkeypatch: pytest.Mon
4040
assert found == expected
4141

4242

43-
def test_progress_v_relative(example: pytest.Testdir) -> None:
43+
def test_progress_v_relative(example: pytest.Pytester) -> None:
4444
result_verbose_relative = example.runpytest(
4545
"--print",
4646
"-v",
@@ -69,7 +69,7 @@ def test_progress_v_relative(example: pytest.Testdir) -> None:
6969
], session
7070

7171

72-
def test_progress_no_v_but_with_print_request(example: pytest.Testdir) -> None:
72+
def test_progress_no_v_but_with_print_request(example: pytest.Pytester) -> None:
7373
result = example.runpytest("--print")
7474
result.assert_outcomes(passed=2)
7575
assert " start server from virtual env" in result.outlines

0 commit comments

Comments
 (0)