Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,21 @@ exclude_lines = [
]

[tool.pyright]
# `requires-python` is the floor. Without this, pyright checks against whatever
# interpreter the job installed (3.12 in CI), so a 3.11-only annotation passes.
pythonVersion = "3.10"
#typeCheckingMode = "strict"
reportUnnecessaryTypeIgnoreComment = true
reportMissingTypeStubs = false
reportUnusedCallResult = false
# Every parameter, return and variable in the package is annotated; these keep it so.
# `reportUnknownMemberType` is left out: it gates the typing of our dependencies rather
# than of this package, and pytest types `request.node` as `Any` on purpose.
# https://github.com/pytest-dev/pytest/issues/13888#issuecomment-3511168937
reportMissingParameterType = "error"
reportUnknownParameterType = "error"
reportUnknownVariableType = "error"
reportUnknownArgumentType = "error"
reportExplicitAny = false
reportAny = false
include = ["pytest_examples"]
Expand Down
8 changes: 6 additions & 2 deletions pytest_examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
__all__ = 'find_examples', 'CodeExample', 'EvalExample'


def pytest_addoption(parser) -> None:
def pytest_addoption(parser: pytest.Parser) -> None:
"""Add options to the pytest command line."""
group = parser.getgroup('examples')
group.addoption(
Expand Down Expand Up @@ -50,7 +50,11 @@ def _examples_to_update(pytestconfig: pytest.Config) -> Iterator[list[CodeExampl


@pytest.fixture(name='eval_example')
def eval_example(tmp_path: Path, request: pytest.FixtureRequest, _examples_to_update) -> Iterator[EvalExample]:
def eval_example(
tmp_path: Path,
request: pytest.FixtureRequest,
_examples_to_update: list[CodeExample],
) -> Iterator[EvalExample]:
"""Fixture to return a `EvalExample` instance for running and linting examples."""
eval_ex = EvalExample(tmp_path=tmp_path, pytest_request=request)
yield eval_ex
Expand Down
2 changes: 1 addition & 1 deletion pytest_examples/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ExamplesConfig:
white_space_dot: bool = False
"""If True, replace spaces with `·` in example diffs."""

def black_mode(self):
def black_mode(self) -> BlackMode:
return BlackMode(
line_length=self.line_length,
target_versions={BlackTargetVersion[self.target_version.upper()]} if self.target_version else set(),
Expand Down
6 changes: 3 additions & 3 deletions pytest_examples/eval_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
class EvalExample:
"""Class to run and lint examples."""

def __init__(self, *, tmp_path: Path, pytest_request: pytest.FixtureRequest):
def __init__(self, *, tmp_path: Path, pytest_request: pytest.FixtureRequest) -> None:
self.tmp_path = tmp_path
self._pytest_config = pytest_request.config
self._test_id = pytest_request.node.nodeid
self._test_id: str = pytest_request.node.nodeid
self.to_update: list[CodeExample] = []
self.config: ExamplesConfig = ExamplesConfig()
self.print_callback: Callable[[str], str] | None = None
Expand All @@ -44,7 +44,7 @@ def set_config(
ruff_line_length: int | None = None,
ruff_select: list[str] | None = None,
ruff_ignore: list[str] | None = None,
):
) -> None:
"""Set the config for lints.

Args:
Expand Down
6 changes: 3 additions & 3 deletions pytest_examples/find_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def create(
end_index: int | None = None,
prefix: str = '',
indent: int = 0,
):
) -> CodeExample:
"""Create a `CodeExample`, mostly for testing."""
if end_line is None:
end_line = start_line + source.count('\n')
Expand All @@ -75,7 +75,7 @@ def prefix_settings(self) -> dict[str, str]:

This works on the format `py foo="bar" spam="with space"`.
"""
settings = {}
settings: dict[str, str] = {}
for m in re.finditer(r'([^{\s]+?)=([\'"])(.+?)\2', self.prefix):
settings[m.group(1)] = m.group(3)
return settings
Expand All @@ -98,7 +98,7 @@ def in_py_file(self) -> bool:
"""Whether the example is in a Python file."""
return self.path.suffix == '.py'

def __str__(self):
def __str__(self) -> str:
try:
path = self.path.relative_to(Path.cwd())
except ValueError:
Expand Down
2 changes: 1 addition & 1 deletion pytest_examples/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def ruff_check(
stdout, stderr = p.communicate(example.source, timeout=10)
if p.returncode == 1 and stdout:

def replace_offset(m: re.Match[str]):
def replace_offset(m: re.Match[str]) -> str:
line_number = int(m.group(1))
return f'{example.path}:{line_number + example.start_line}'

Expand Down
21 changes: 8 additions & 13 deletions pytest_examples/run_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from importlib.abc import Loader
from pathlib import Path
from textwrap import indent
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, TypeAlias
from unittest.mock import patch

import pytest
Expand All @@ -28,7 +28,7 @@
__all__ = 'run_code', 'InsertPrintStatements', 'IncludePrint'

parent_frame_id = 4
IncludePrint = Callable[[Path, inspect.FrameInfo, Sequence[Any]], bool]
IncludePrint: TypeAlias = Callable[[Path, inspect.FrameInfo, Sequence[Any]], bool]


def run_code(
Expand Down Expand Up @@ -102,13 +102,14 @@ class Arg:
data: str
is_str: bool = False

def __init__(self, v: Any):
def __init__(self, v: Any) -> None:
if isinstance(v, str):
self.data = v
self.is_str = True
elif isinstance(v, set):
# NOTE! this is not recursive
ordered = ', '.join(repr(x) for x in sorted(v))
items: set[Any] = v
ordered = ', '.join(repr(x) for x in sorted(items))
self.data = f'{{{ordered}}}'
else:
self.data = re.sub('0x[a-f0-9]{8,12}>', '0x0123456789ab>', str(v))
Expand All @@ -134,16 +135,10 @@ class PrintStatement:
sep: str
args: list[Arg]

def __str__(self):
def __str__(self) -> str:
return self.sep.join(map(str, self.args))


def not_print(*args):
import sys

sys.stdout.write(' '.join(map(str, args)) + '\n')


class MockPrintFunction:
__slots__ = 'file', 'statements', 'include_print'

Expand Down Expand Up @@ -186,7 +181,7 @@ def __init__(
enable: bool,
print_callback: Callable[[str], str] | None,
include_print: IncludePrint | None,
):
) -> None:
self.file = python_path
self.config = config
self.print_func = MockPrintFunction(python_path, include_print) if enable else None
Expand All @@ -198,7 +193,7 @@ def __enter__(self) -> None:
self.patch = patch('builtins.print', side_effect=self.print_func)
self.patch.start()

def __exit__(self, *args) -> None:
def __exit__(self, *args: Any) -> None:
if self.patch is not None:
self.patch.stop()

Expand Down
2 changes: 1 addition & 1 deletion pytest_examples/traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def create_example_traceback(exc: Exception, module_path: str, example: CodeExam

Frames outside the example are not included in the new traceback.
"""
frames = []
frames: list[tuple[FrameType, int, int]] = []
tb = exc.__traceback__
while tb is not None:
frame = tb.tb_frame
Expand Down
Loading