Use "from __future__ import annotations" to be less verbose

This commit is contained in:
Alessio Bogon 2022-02-24 15:32:20 +01:00
parent 4fd1ab950c
commit 021aa3a2e3
18 changed files with 97 additions and 77 deletions

View File

@ -22,4 +22,4 @@ repos:
rev: v2.31.0
hooks:
- id: pyupgrade
args: [--py37-plus]
args: ["--py37-plus", "--keep-runtime-typing"]

View File

@ -1,4 +1,5 @@
"""pytest-bdd public API."""
from __future__ import annotations
from pytest_bdd.scenario import scenario, scenarios
from pytest_bdd.steps import given, then, when

View File

@ -1,4 +1,5 @@
"""Cucumber json output formatter."""
from __future__ import annotations
import json
import math
@ -13,7 +14,7 @@ if TYPE_CHECKING:
from _pytest.terminal import TerminalReporter
def add_options(parser: "Parser") -> None:
def add_options(parser: Parser) -> None:
"""Add pytest-bdd options."""
group = parser.getgroup("bdd", "Cucumber JSON")
group.addoption(
@ -27,7 +28,7 @@ def add_options(parser: "Parser") -> None:
)
def configure(config: "Config") -> None:
def configure(config: Config) -> None:
cucumber_json_path = config.option.cucumber_json_path
# prevent opening json log on worker nodes (xdist)
if cucumber_json_path and not hasattr(config, "workerinput"):
@ -35,7 +36,7 @@ def configure(config: "Config") -> None:
config.pluginmanager.register(config._bddcucumberjson)
def unconfigure(config: "Config") -> None:
def unconfigure(config: Config) -> None:
xml = getattr(config, "_bddcucumberjson", None)
if xml is not None:
del config._bddcucumberjson
@ -55,7 +56,7 @@ class LogBDDCucumberJSON:
def append(self, obj):
self.features[-1].append(obj)
def _get_result(self, step: Dict[str, Any], report: "TestReport", error_message: bool = False) -> Dict[str, Any]:
def _get_result(self, step: Dict[str, Any], report: TestReport, error_message: bool = False) -> Dict[str, Any]:
"""Get scenario test run result.
:param step: `Step` step we get result for
@ -86,7 +87,7 @@ class LogBDDCucumberJSON:
"""
return [{"name": tag, "line": item["line_number"] - 1} for tag in item["tags"]]
def pytest_runtest_logreport(self, report: "TestReport") -> None:
def pytest_runtest_logreport(self, report: TestReport) -> None:
try:
scenario = report.scenario
except AttributeError:
@ -145,5 +146,5 @@ class LogBDDCucumberJSON:
with open(self.logfile, "w", encoding="utf-8") as logfile:
logfile.write(json.dumps(list(self.features.values())))
def pytest_terminal_summary(self, terminalreporter: "TerminalReporter") -> None:
def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None:
terminalreporter.write_sep("-", f"generated json file: {self.logfile}")

View File

@ -1,4 +1,5 @@
"""pytest-bdd Exceptions."""
from __future__ import annotations
class ScenarioIsDecoratorOnly(Exception):

View File

@ -23,6 +23,8 @@ Syntax example:
:note: There are no multiline steps, the description of the step must fit in
one line.
"""
from __future__ import annotations
import os.path
import typing

View File

@ -1,4 +1,5 @@
"""pytest-bdd missing test code generation."""
from __future__ import annotations
import itertools
import os.path
@ -50,7 +51,7 @@ def cmdline_main(config: Config) -> Optional[int]:
return show_missing_code(config)
def generate_code(features: "List[Feature]", scenarios: "List[ScenarioTemplate]", steps: "List[Step]") -> str:
def generate_code(features: List[Feature], scenarios: List[ScenarioTemplate], steps: List[Step]) -> str:
"""Generate test code for the given filenames."""
grouped_steps = group_steps(steps)
template = template_lookup.get_template("test.py.mak")
@ -71,7 +72,7 @@ def show_missing_code(config: Config) -> int:
return wrap_session(config, _show_missing_code_main)
def print_missing_code(scenarios: "List[ScenarioTemplate]", steps: "List[Step]") -> None:
def print_missing_code(scenarios: List[ScenarioTemplate], steps: List[Step]) -> None:
"""Print missing code with TerminalWriter."""
tw = py.io.TerminalWriter()
scenario = step = None
@ -138,7 +139,7 @@ def _find_step_fixturedef(
return None
def parse_feature_files(paths: List[str], **kwargs: Any) -> "Tuple[List[Feature], List[ScenarioTemplate], List[Step]]":
def parse_feature_files(paths: List[str], **kwargs: Any) -> Tuple[List[Feature], List[ScenarioTemplate], List[Step]]:
"""Parse feature files of given paths.
:param paths: `list` of paths (file or dirs)
@ -157,7 +158,7 @@ def parse_feature_files(paths: List[str], **kwargs: Any) -> "Tuple[List[Feature]
return features, scenarios, steps
def group_steps(steps: "List[Step]") -> "List[Step]":
def group_steps(steps: List[Step]) -> List[Step]:
"""Group steps by type."""
steps = sorted(steps, key=lambda step: step.type)
seen_steps = set()

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from typing import Any, Optional
from _pytest.config import Config

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
"""Pytest-bdd pytest hooks."""

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import re
import textwrap
@ -75,7 +77,7 @@ def get_step_type(line: str) -> Optional[str]:
return None
def parse_feature(basedir: str, filename: str, encoding: str = "utf-8") -> "Feature":
def parse_feature(basedir: str, filename: str, encoding: str = "utf-8") -> Feature:
"""Parse the feature file.
:param str basedir: Feature files base directory.
@ -186,7 +188,7 @@ class Feature:
rel_filename: str,
name: Optional[str],
tags: Set,
background: "Optional[Background]",
background: Optional[Background],
line_number: int,
description: str,
) -> None:
@ -197,7 +199,7 @@ class Feature:
self.name: Optional[str] = name
self.line_number: int = line_number
self.description: str = description
self.background: "Optional[Background]" = background
self.background: Optional[Background] = background
class ScenarioTemplate:
@ -205,7 +207,7 @@ class ScenarioTemplate:
Created when parsing the feature file, it will then be combined with the examples to create a Scenario."""
def __init__(self, feature: "Feature", name: str, line_number: int, tags=None):
def __init__(self, feature: Feature, name: str, line_number: int, tags=None):
"""
:param str name: Scenario name.
@ -214,12 +216,12 @@ class ScenarioTemplate:
"""
self.feature = feature
self.name = name
self._steps: "typing.List[Step]" = []
self._steps: typing.List[Step] = []
self.examples = Examples()
self.line_number = line_number
self.tags = tags or set()
def add_step(self, step: "Step") -> None:
def add_step(self, step: Step) -> None:
"""Add step to the scenario.
:param pytest_bdd.parser.Step step: Step.
@ -228,11 +230,11 @@ class ScenarioTemplate:
self._steps.append(step)
@property
def steps(self) -> "List[Step]":
def steps(self) -> List[Step]:
background = self.feature.background
return (background.steps if background else []) + self._steps
def render(self, context: typing.Mapping[str, typing.Any]) -> "Scenario":
def render(self, context: typing.Mapping[str, typing.Any]) -> Scenario:
steps = [
Step(
name=templated_step.render(context),
@ -250,7 +252,7 @@ class Scenario:
"""Scenario."""
def __init__(self, feature: "Feature", name: str, line_number: int, steps: "typing.List[Step]", tags=None):
def __init__(self, feature: Feature, name: str, line_number: int, steps: typing.List[Step], tags=None):
"""Scenario constructor.
:param pytest_bdd.parser.Feature feature: Feature.
@ -288,8 +290,8 @@ class Step:
self.failed: bool = False
self.start: int = 0 # TODO: Unused
self.stop: int = 0 # TODO: Unused
self.scenario: "Optional[ScenarioTemplate]" = None
self.background: "Optional[Background]" = None
self.scenario: Optional[ScenarioTemplate] = None
self.background: Optional[Background] = None
def add_line(self, line: str) -> None:
"""Add line to the multiple step.
@ -340,17 +342,17 @@ class Background:
"""Background."""
def __init__(self, feature: "Feature", line_number: int) -> None:
def __init__(self, feature: Feature, line_number: int) -> None:
"""Background constructor.
:param pytest_bdd.parser.Feature feature: Feature.
:param int line_number: Line number.
"""
self.feature: "Feature" = feature
self.feature: Feature = feature
self.line_number: int = line_number
self.steps: "typing.List[Step]" = []
self.steps: typing.List[Step] = []
def add_step(self, step: "Step") -> None:
def add_step(self, step: Step) -> None:
"""Add step to the background."""
step.background = self
self.steps.append(step)

View File

@ -1,8 +1,7 @@
"""Step parsers."""
from __future__ import annotations
import re as base_re
from functools import partial
from typing import Any, Dict, cast
import parse as base_parse

View File

@ -1,4 +1,5 @@
"""Pytest plugin entry point. Used for any fixtures needed."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterator, Optional
@ -17,7 +18,7 @@ if TYPE_CHECKING:
from .parser import Feature, Scenario, Step
def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None:
def pytest_addhooks(pluginmanager: PytestPluginManager) -> None:
"""Register plugin hooks."""
from pytest_bdd import hooks
@ -46,7 +47,7 @@ def _pytest_bdd_example() -> Dict:
return {}
def pytest_addoption(parser: "Parser") -> None:
def pytest_addoption(parser: Parser) -> None:
"""Add pytest-bdd options."""
add_bdd_ini(parser)
cucumber_json.add_options(parser)
@ -54,42 +55,42 @@ def pytest_addoption(parser: "Parser") -> None:
gherkin_terminal_reporter.add_options(parser)
def add_bdd_ini(parser: "Parser") -> None:
def add_bdd_ini(parser: Parser) -> None:
parser.addini("bdd_features_base_dir", "Base features directory.")
@pytest.mark.trylast
def pytest_configure(config: "Config") -> None:
def pytest_configure(config: Config) -> None:
"""Configure all subplugins."""
CONFIG_STACK.append(config)
cucumber_json.configure(config)
gherkin_terminal_reporter.configure(config)
def pytest_unconfigure(config: "Config") -> None:
def pytest_unconfigure(config: Config) -> None:
"""Unconfigure all subplugins."""
CONFIG_STACK.pop()
cucumber_json.unconfigure(config)
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item: "Item", call: "CallInfo") -> Iterator:
def pytest_runtest_makereport(item: Item, call: CallInfo) -> Iterator:
outcome = yield
reporting.runtest_makereport(item, call, outcome.get_result())
@pytest.mark.tryfirst
def pytest_bdd_before_scenario(request: "FixtureRequest", feature: "Feature", scenario: "Scenario") -> None:
def pytest_bdd_before_scenario(request: FixtureRequest, feature: Feature, scenario: Scenario) -> None:
reporting.before_scenario(request, feature, scenario)
@pytest.mark.tryfirst
def pytest_bdd_step_error(
request: "FixtureRequest",
feature: "Feature",
scenario: "Scenario",
step: "Step",
step_func: "Callable",
request: FixtureRequest,
feature: Feature,
scenario: Scenario,
step: Step,
step_func: Callable,
step_func_args: Dict,
exception: Exception,
) -> None:
@ -98,27 +99,27 @@ def pytest_bdd_step_error(
@pytest.mark.tryfirst
def pytest_bdd_before_step(
request: "FixtureRequest", feature: "Feature", scenario: "Scenario", step: "Step", step_func: "Callable"
request: FixtureRequest, feature: Feature, scenario: Scenario, step: Step, step_func: Callable
) -> None:
reporting.before_step(request, feature, scenario, step, step_func)
@pytest.mark.tryfirst
def pytest_bdd_after_step(
request: "FixtureRequest",
feature: "Feature",
scenario: "Scenario",
step: "Step",
step_func: "Callable",
request: FixtureRequest,
feature: Feature,
scenario: Scenario,
step: Step,
step_func: Callable,
step_func_args: Dict[str, Any],
) -> None:
reporting.after_step(request, feature, scenario, step, step_func, step_func_args)
def pytest_cmdline_main(config: "Config") -> Optional[int]:
def pytest_cmdline_main(config: Config) -> Optional[int]:
return generation.cmdline_main(config)
def pytest_bdd_apply_tag(tag: str, function: "Callable") -> "Callable":
def pytest_bdd_apply_tag(tag: str, function: Callable) -> Callable:
mark = getattr(pytest.mark, tag)
return mark(function)

View File

@ -3,6 +3,7 @@
Collection of the scenario execution statuses, timing and other information
that enriches the pytest test reporting.
"""
from __future__ import annotations
import time
from typing import TYPE_CHECKING, Any, Callable, Dict
@ -22,7 +23,7 @@ class StepReport:
failed = False
stopped = None
def __init__(self, step: "Step") -> None:
def __init__(self, step: Step) -> None:
"""Step report constructor.
:param pytest_bdd.parser.Step step: Step.
@ -70,7 +71,7 @@ class ScenarioReport:
"""Scenario execution report."""
# TODO: Remove unused argument "node"
def __init__(self, scenario: "Scenario", node: Any) -> None:
def __init__(self, scenario: Scenario, node: Any) -> None:
"""Scenario report constructor.
:param pytest_bdd.parser.Scenario scenario: Scenario.
@ -80,7 +81,7 @@ class ScenarioReport:
self.step_reports = []
@property
def current_step_report(self) -> "StepReport":
def current_step_report(self) -> StepReport:
"""Get current step report.
:return: Last or current step report.
@ -88,7 +89,7 @@ class ScenarioReport:
"""
return self.step_reports[-1]
def add_step_report(self, step_report: "StepReport") -> None:
def add_step_report(self, step_report: StepReport) -> None:
"""Add new step report.
:param step_report: New current step report.
@ -132,7 +133,7 @@ class ScenarioReport:
self.add_step_report(report)
def runtest_makereport(item: "Item", call: "CallInfo", rep: "TestReport") -> None:
def runtest_makereport(item: Item, call: CallInfo, rep: TestReport) -> None:
"""Store item in the report object."""
try:
scenario_report = item.__scenario_report__
@ -143,17 +144,17 @@ def runtest_makereport(item: "Item", call: "CallInfo", rep: "TestReport") -> Non
rep.item = {"name": item.name}
def before_scenario(request: "FixtureRequest", feature: "Feature", scenario: "Scenario") -> None:
def before_scenario(request: FixtureRequest, feature: Feature, scenario: Scenario) -> None:
"""Create scenario report for the item."""
request.node.__scenario_report__ = ScenarioReport(scenario=scenario, node=request.node)
def step_error(
request: "FixtureRequest",
feature: "Feature",
scenario: "Scenario",
step: "Step",
step_func: "Callable",
request: FixtureRequest,
feature: Feature,
scenario: Scenario,
step: Step,
step_func: Callable,
step_func_args: Dict,
exception: Exception,
) -> None:
@ -161,19 +162,17 @@ def step_error(
request.node.__scenario_report__.fail()
def before_step(
request: "FixtureRequest", feature: "Feature", scenario: "Scenario", step: "Step", step_func: "Callable"
) -> None:
def before_step(request: FixtureRequest, feature: Feature, scenario: Scenario, step: Step, step_func: Callable) -> None:
"""Store step start time."""
request.node.__scenario_report__.add_step_report(StepReport(step=step))
def after_step(
request: "FixtureRequest",
feature: "Feature",
scenario: "Scenario",
step: "Step",
step_func: "Callable",
request: FixtureRequest,
feature: Feature,
scenario: Scenario,
step: Step,
step_func: Callable,
step_func_args: Dict,
) -> None:
"""Finalize the step report as successful."""

View File

@ -10,6 +10,8 @@ test_publish_article = scenario(
scenario_name="Publishing the article",
)
"""
from __future__ import annotations
import collections
import os
import re
@ -57,7 +59,7 @@ def find_argumented_step_fixture_name(
return None
def _find_step_function(request: FixtureRequest, step: "Step", scenario: "Scenario") -> Any:
def _find_step_function(request: FixtureRequest, step: Step, scenario: Scenario) -> Any:
"""Match the step defined by the regular expression pattern.
:param request: PyTest request object.
@ -85,7 +87,7 @@ def _find_step_function(request: FixtureRequest, step: "Step", scenario: "Scenar
)
def _execute_step_function(request: FixtureRequest, scenario: "Scenario", step: "Step", step_func: Callable) -> None:
def _execute_step_function(request: FixtureRequest, scenario: Scenario, step: Step, step_func: Callable) -> None:
"""Execute step function.
:param request: PyTest request.
@ -128,7 +130,7 @@ def _execute_step_function(request: FixtureRequest, scenario: "Scenario", step:
raise
def _execute_scenario(feature: "Feature", scenario: "Scenario", request):
def _execute_scenario(feature: Feature, scenario: Scenario, request):
"""Execute the scenario.
:param feature: Feature.
@ -157,7 +159,7 @@ FakeRequest = collections.namedtuple("FakeRequest", ["module"])
def _get_scenario_decorator(
feature: "Feature", feature_name: str, templated_scenario: "ScenarioTemplate", scenario_name: str
feature: Feature, feature_name: str, templated_scenario: ScenarioTemplate, scenario_name: str
):
# HACK: Ideally we would use `def decorator(fn)`, but we want to return a custom exception
# when the decorator is misused.
@ -202,8 +204,8 @@ def _get_scenario_decorator(
def collect_example_parametrizations(
templated_scenario: "ScenarioTemplate",
) -> "typing.Optional[typing.List[ParameterSet]]":
templated_scenario: ScenarioTemplate,
) -> typing.Optional[typing.List[ParameterSet]]:
# We need to evaluate these iterators and store them as lists, otherwise
# we won't be able to do the cartesian product later (the second iterator will be consumed)
contexts = list(templated_scenario.examples.as_contexts())

View File

@ -1,4 +1,5 @@
"""pytest-bdd scripts."""
from __future__ import annotations
import argparse
import os.path

View File

@ -34,6 +34,7 @@ def given_beautiful_article(article):
pass
"""
from __future__ import annotations
from typing import Any, Callable, Dict, Optional, Union

View File

@ -1,4 +1,5 @@
"""Common type definitions."""
from __future__ import annotations
FEATURE = "feature"
SCENARIO_OUTLINE = "scenario outline"

View File

@ -1,4 +1,6 @@
"""Various utility functions."""
from __future__ import annotations
import base64
import pickle
import re
@ -11,7 +13,7 @@ if typing.TYPE_CHECKING:
from _pytest.config import Config
from _pytest.pytester import RunResult
CONFIG_STACK: "List[Config]" = []
CONFIG_STACK: List[Config] = []
def get_args(func: Callable) -> List[str]:
@ -57,7 +59,7 @@ def dump_obj(*objects: Any) -> None:
print(f"{_DUMP_START}{encoded}{_DUMP_END}")
def collect_dumped_objects(result: "RunResult"):
def collect_dumped_objects(result: RunResult):
"""Parse all the objects dumped with `dump_object` from the result.
Note: You must run the result with output to stdout enabled.

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Optional
import pytest
@ -13,7 +15,7 @@ PYTEST_6 = PYTEST_VERSION >= Version("6")
if PYTEST_6:
def assert_outcomes(
result: "RunResult",
result: RunResult,
passed: int = 0,
skipped: int = 0,
failed: int = 0,
@ -29,7 +31,7 @@ if PYTEST_6:
else:
def assert_outcomes(
result: "RunResult",
result: RunResult,
passed=0,
skipped=0,
failed=0,