Skip to content

Commit 023c6d6

Browse files
committed
Remove usages of typing.Any when possible
1 parent 49f363e commit 023c6d6

File tree

10 files changed

+81
-63
lines changed

10 files changed

+81
-63
lines changed

src/pytest_bdd/compat.py

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

33
from collections.abc import Sequence
44
from importlib.metadata import version
5-
from typing import Any
65

76
from _pytest.fixtures import FixtureDef, FixtureManager, FixtureRequest
87
from _pytest.nodes import Node
@@ -14,10 +13,12 @@
1413

1514
if pytest_version.release >= (8, 1):
1615

17-
def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[FixtureDef] | None:
16+
def getfixturedefs(
17+
fixturemanager: FixtureManager, fixturename: str, node: Node
18+
) -> Sequence[FixtureDef[object]] | None:
1819
return fixturemanager.getfixturedefs(fixturename, node)
1920

20-
def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
21+
def inject_fixture(request: FixtureRequest, arg: str, value: object) -> None:
2122
"""Inject fixture into pytest fixture request.
2223
2324
:param request: pytest fixture request
@@ -38,10 +39,12 @@ def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
3839

3940
else:
4041

41-
def getfixturedefs(fixturemanager: FixtureManager, fixturename: str, node: Node) -> Sequence[FixtureDef] | None:
42+
def getfixturedefs(
43+
fixturemanager: FixtureManager, fixturename: str, node: Node
44+
) -> Sequence[FixtureDef[object]] | None:
4245
return fixturemanager.getfixturedefs(fixturename, node.nodeid) # type: ignore
4346

44-
def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
47+
def inject_fixture(request: FixtureRequest, arg: str, value: object) -> None:
4548
"""Inject fixture into pytest fixture request.
4649
4750
:param request: pytest fixture request

src/pytest_bdd/cucumber_json.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
import math
77
import os
88
import time
9-
import typing
9+
from typing import TYPE_CHECKING, Any, Literal, TypedDict
1010

11-
from .reporting import test_report_context_registry
11+
from typing_extensions import NotRequired
1212

13-
if typing.TYPE_CHECKING:
14-
from typing import Any
13+
from .reporting import test_report_context_registry
1514

15+
if TYPE_CHECKING:
1616
from _pytest.config import Config
1717
from _pytest.config.argparsing import Parser
1818
from _pytest.reports import TestReport
@@ -48,6 +48,12 @@ def unconfigure(config: Config) -> None:
4848
config.pluginmanager.unregister(xml)
4949

5050

51+
class Result(TypedDict):
52+
status: Literal["passed", "failed", "skipped"]
53+
duration: int # in nanoseconds
54+
error_message: NotRequired[str]
55+
56+
5157
class LogBDDCucumberJSON:
5258
"""Logging plugin for cucumber like json output."""
5359

@@ -56,22 +62,28 @@ def __init__(self, logfile: str) -> None:
5662
self.logfile = os.path.normpath(os.path.abspath(logfile))
5763
self.features: dict[str, dict] = {}
5864

59-
def _get_result(self, step: dict[str, Any], report: TestReport, error_message: bool = False) -> dict[str, Any]:
65+
def _get_result(self, step: dict[str, Any], report: TestReport, error_message: bool = False) -> Result:
6066
"""Get scenario test run result.
6167
6268
:param step: `Step` step we get result for
6369
:param report: pytest `Report` object
6470
:return: `dict` in form {"status": "<passed|failed|skipped>", ["error_message": "<error_message>"]}
6571
"""
66-
result: dict[str, Any] = {}
67-
if report.passed or not step["failed"]: # ignore setup/teardown
68-
result = {"status": "passed"}
69-
elif report.failed:
70-
result = {"status": "failed", "error_message": str(report.longrepr) if error_message else ""}
71-
elif report.skipped:
72-
result = {"status": "skipped"}
73-
result["duration"] = int(math.floor((10**9) * step["duration"])) # nanosec
74-
return result
72+
status: Literal["passed", "failed", "skipped"]
73+
res_message = None
74+
if report.outcome == "passed" or not step["failed"]: # ignore setup/teardown
75+
status = "passed"
76+
elif report.outcome == "failed":
77+
status = "failed"
78+
res_message = str(report.longrepr) if error_message else ""
79+
elif report.outcome == "skipped":
80+
status = "skipped"
81+
else:
82+
raise ValueError(f"Unknown test outcome {report.outcome}")
83+
res: Result = {"status": status, "duration": int(math.floor((10**9) * step["duration"]))} # nanosec
84+
if res_message is not None:
85+
res["error_message"] = res_message
86+
return res
7587

7688
def _serialize_tags(self, item: dict[str, Any]) -> list[dict[str, Any]]:
7789
"""Serialize item's tags.

src/pytest_bdd/generation.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
if TYPE_CHECKING:
2727
from collections.abc import Sequence
28-
from typing import Any
2928

3029
from _pytest.config import Config
3130
from _pytest.config.argparsing import Parser
@@ -133,22 +132,26 @@ def print_missing_code(scenarios: list[ScenarioTemplate], steps: list[Step]) ->
133132
tw.write(code)
134133

135134

136-
def _find_step_fixturedef(fixturemanager: FixtureManager, item: Node, step: Step) -> Sequence[FixtureDef[Any]] | None:
135+
def _find_step_fixturedef(
136+
fixturemanager: FixtureManager, item: Node, step: Step
137+
) -> Sequence[FixtureDef[object]] | None:
137138
"""Find step fixturedef."""
138139
with inject_fixturedefs_for_step(step=step, fixturemanager=fixturemanager, node=item):
139140
bdd_name = get_step_fixture_name(step=step)
140141
return getfixturedefs(fixturemanager, bdd_name, item)
141142

142143

143-
def parse_feature_files(paths: list[str], **kwargs: Any) -> tuple[list[Feature], list[ScenarioTemplate], list[Step]]:
144+
def parse_feature_files(
145+
paths: list[str], encoding: str = "utf-8"
146+
) -> tuple[list[Feature], list[ScenarioTemplate], list[Step]]:
144147
"""Parse feature files of given paths.
145148
146149
:param paths: `list` of paths (file or dirs)
147150
148151
:return: `list` of `tuple` in form:
149152
(`list` of `Feature` objects, `list` of `Scenario` objects, `list` of `Step` objects).
150153
"""
151-
features = get_features(paths, **kwargs)
154+
features = get_features(paths, encoding=encoding)
152155
scenarios = sorted(
153156
itertools.chain.from_iterable(feature.scenarios.values() for feature in features),
154157
key=lambda scenario: (scenario.feature.name or scenario.feature.filename, scenario.name),

src/pytest_bdd/gherkin_terminal_reporter.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from .reporting import test_report_context_registry
88

99
if typing.TYPE_CHECKING:
10-
from typing import Any
11-
1210
from _pytest.config import Config
1311
from _pytest.config.argparsing import Parser
1412
from _pytest.reports import TestReport
@@ -50,7 +48,7 @@ def __init__(self, config: Config) -> None:
5048
super().__init__(config)
5149
self.current_rule = None
5250

53-
def pytest_runtest_logreport(self, report: TestReport) -> Any:
51+
def pytest_runtest_logreport(self, report: TestReport) -> None:
5452
rep = report
5553
res = self.config.hook.pytest_report_teststatus(report=rep, config=self.config)
5654
cat, letter, word = res
@@ -120,4 +118,3 @@ def pytest_runtest_logreport(self, report: TestReport) -> Any:
120118
self._tw.write("\n\n")
121119

122120
self.stats.setdefault(cat, []).append(rep)
123-
return None

src/pytest_bdd/parser.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from collections import OrderedDict
77
from collections.abc import Generator, Iterable, Mapping, Sequence
88
from dataclasses import dataclass, field
9-
from typing import Any
109

1110
from .exceptions import StepError
1211
from .gherkin_parser import Background as GherkinBackground
@@ -95,11 +94,11 @@ def add_example(self, values: Sequence[str]) -> None:
9594
"""
9695
self.examples.append([str(value) if value is not None else "" for value in values])
9796

98-
def as_contexts(self) -> Iterable[dict[str, Any]]:
97+
def as_contexts(self) -> Generator[dict[str, str]]:
9998
"""Generate contexts for the examples.
10099
101100
Yields:
102-
Dict[str, Any]: A dictionary mapping parameter names to their values for each example row.
101+
dict[str, str]: A dictionary mapping parameter names to their values for each example row.
103102
"""
104103
for row in self.examples:
105104
assert len(self.example_params) == len(row)
@@ -180,11 +179,11 @@ def steps(self) -> list[Step]:
180179
"""
181180
return self.all_background_steps + self._steps
182181

183-
def render(self, context: Mapping[str, Any]) -> Scenario:
182+
def render(self, context: Mapping[str, object]) -> Scenario:
184183
"""Render the scenario with the given context.
185184
186185
Args:
187-
context (Mapping[str, Any]): The context for rendering steps.
186+
context (Mapping[str, object]): The context for rendering steps.
188187
189188
Returns:
190189
Scenario: A Scenario object with steps rendered based on the context.
@@ -308,11 +307,11 @@ def params(self) -> tuple[str, ...]:
308307
"""
309308
return tuple(frozenset(STEP_PARAM_RE.findall(self.name)))
310309

311-
def render(self, context: Mapping[str, Any]) -> str:
310+
def render(self, context: Mapping[str, object]) -> str:
312311
"""Render the step name with the given context, but avoid replacing text inside angle brackets if context is missing.
313312
314313
Args:
315-
context (Mapping[str, Any]): The context for rendering the step name.
314+
context (Mapping[str, object]): The context for rendering the step name.
316315
317316
Returns:
318317
str: The rendered step name with parameters replaced only if they exist in the context.

src/pytest_bdd/plugin.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from collections.abc import Generator
6-
from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
6+
from typing import TYPE_CHECKING, Callable, TypeVar, cast
77

88
import pytest
99
from typing_extensions import ParamSpec
@@ -99,8 +99,8 @@ def pytest_bdd_step_error(
9999
feature: Feature,
100100
scenario: Scenario,
101101
step: Step,
102-
step_func: Callable[..., Any],
103-
step_func_args: dict,
102+
step_func: Callable[..., object],
103+
step_func_args: dict[str, object],
104104
exception: Exception,
105105
) -> None:
106106
reporting.step_error(request, feature, scenario, step, step_func, step_func_args, exception)
@@ -112,7 +112,7 @@ def pytest_bdd_before_step(
112112
feature: Feature,
113113
scenario: Scenario,
114114
step: Step,
115-
step_func: Callable[..., Any],
115+
step_func: Callable[..., object],
116116
) -> None:
117117
reporting.before_step(request, feature, scenario, step, step_func)
118118

@@ -123,8 +123,8 @@ def pytest_bdd_after_step(
123123
feature: Feature,
124124
scenario: Scenario,
125125
step: Step,
126-
step_func: Callable[..., Any],
127-
step_func_args: dict[str, Any],
126+
step_func: Callable[..., object],
127+
step_func_args: dict[str, object],
128128
) -> None:
129129
reporting.after_step(request, feature, scenario, step, step_func, step_func_args)
130130

src/pytest_bdd/reporting.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __init__(self, step: Step) -> None:
3939
self.step = step
4040
self.started = time.perf_counter()
4141

42-
def serialize(self) -> dict[str, Any]:
42+
def serialize(self) -> dict[str, object]:
4343
"""Serialize the step execution report.
4444
4545
:return: Serialized step execution report.
@@ -103,7 +103,7 @@ def add_step_report(self, step_report: StepReport) -> None:
103103
"""
104104
self.step_reports.append(step_report)
105105

106-
def serialize(self) -> dict[str, Any]:
106+
def serialize(self) -> dict[str, object]:
107107
"""Serialize scenario execution report in order to transfer reporting from nodes in the distributed mode.
108108
109109
:return: Serialized report.
@@ -178,8 +178,8 @@ def step_error(
178178
feature: Feature,
179179
scenario: Scenario,
180180
step: Step,
181-
step_func: Callable[..., Any],
182-
step_func_args: dict,
181+
step_func: Callable[..., object],
182+
step_func_args: dict[str, object],
183183
exception: Exception,
184184
) -> None:
185185
"""Finalize the step report as failed."""

src/pytest_bdd/scenario.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
PYTHON_REPLACE_REGEX = re.compile(r"\W")
4545
ALPHA_REGEX = re.compile(r"^\d+_*")
4646

47-
scenario_wrapper_template_registry: WeakKeyDictionary[Callable[..., Any], ScenarioTemplate] = WeakKeyDictionary()
47+
scenario_wrapper_template_registry: WeakKeyDictionary[Callable[..., object], ScenarioTemplate] = WeakKeyDictionary()
4848

4949

50-
def find_fixturedefs_for_step(step: Step, fixturemanager: FixtureManager, node: Node) -> Iterable[FixtureDef[Any]]:
50+
def find_fixturedefs_for_step(step: Step, fixturemanager: FixtureManager, node: Node) -> Iterable[FixtureDef[object]]:
5151
"""Find the fixture defs that can parse a step."""
5252
# happens to be that _arg2fixturedefs is changed during the iteration so we use a copy
5353
fixture_def_by_name = list(fixturemanager._arg2fixturedefs.items())
@@ -64,7 +64,7 @@ def find_fixturedefs_for_step(step: Step, fixturemanager: FixtureManager, node:
6464
if not match:
6565
continue
6666

67-
fixturedefs = cast(list[FixtureDef[Any]], getfixturedefs(fixturemanager, fixturename, node) or [])
67+
fixturedefs = list(getfixturedefs(fixturemanager, fixturename, node) or [])
6868
if fixturedef not in fixturedefs:
6969
continue
7070

src/pytest_bdd/steps.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def _(article):
4141
from collections.abc import Iterable
4242
from dataclasses import dataclass, field
4343
from itertools import count
44-
from typing import Any, Callable, Literal, TypeVar
44+
from typing import Callable, Literal, TypeVar
4545
from weakref import WeakKeyDictionary
4646

4747
import pytest
@@ -54,7 +54,7 @@ def _(article):
5454
P = ParamSpec("P")
5555
T = TypeVar("T")
5656

57-
step_function_context_registry: WeakKeyDictionary[Callable[..., Any], StepFunctionContext] = WeakKeyDictionary()
57+
step_function_context_registry: WeakKeyDictionary[Callable[..., object], StepFunctionContext] = WeakKeyDictionary()
5858

5959

6060
@enum.unique
@@ -66,9 +66,9 @@ class StepNamePrefix(enum.Enum):
6666
@dataclass
6767
class StepFunctionContext:
6868
type: Literal["given", "when", "then"] | None
69-
step_func: Callable[..., Any]
69+
step_func: Callable[..., object]
7070
parser: StepParser
71-
converters: dict[str, Callable[[str], Any]] = field(default_factory=dict)
71+
converters: dict[str, Callable[[str], object]] = field(default_factory=dict)
7272
target_fixture: str | None = None
7373

7474

@@ -79,7 +79,7 @@ def get_step_fixture_name(step: Step) -> str:
7979

8080
def given(
8181
name: str | StepParser,
82-
converters: dict[str, Callable[[str], Any]] | None = None,
82+
converters: dict[str, Callable[[str], object]] | None = None,
8383
target_fixture: str | None = None,
8484
stacklevel: int = 1,
8585
) -> Callable[[Callable[P, T]], Callable[P, T]]:
@@ -98,7 +98,7 @@ def given(
9898

9999
def when(
100100
name: str | StepParser,
101-
converters: dict[str, Callable[[str], Any]] | None = None,
101+
converters: dict[str, Callable[[str], object]] | None = None,
102102
target_fixture: str | None = None,
103103
stacklevel: int = 1,
104104
) -> Callable[[Callable[P, T]], Callable[P, T]]:
@@ -117,7 +117,7 @@ def when(
117117

118118
def then(
119119
name: str | StepParser,
120-
converters: dict[str, Callable[[str], Any]] | None = None,
120+
converters: dict[str, Callable[[str], object]] | None = None,
121121
target_fixture: str | None = None,
122122
stacklevel: int = 1,
123123
) -> Callable[[Callable[P, T]], Callable[P, T]]:
@@ -137,7 +137,7 @@ def then(
137137
def step(
138138
name: str | StepParser,
139139
type_: Literal["given", "when", "then"] | None = None,
140-
converters: dict[str, Callable[[str], Any]] | None = None,
140+
converters: dict[str, Callable[[str], object]] | None = None,
141141
target_fixture: str | None = None,
142142
stacklevel: int = 1,
143143
) -> Callable[[Callable[P, T]], Callable[P, T]]:

0 commit comments

Comments
 (0)