Merge pull request #554 from pytest-dev/misc-internal-improvements
Misc internal improvements
This commit is contained in:
commit
f6865058c3
|
@ -117,7 +117,7 @@ def print_missing_code(scenarios: list[ScenarioTemplate], steps: list[Step]) ->
|
|||
tw.line()
|
||||
|
||||
features = sorted(
|
||||
{scenario.feature for scenario in scenarios}, key=lambda feature: feature.name or feature.filename
|
||||
(scenario.feature for scenario in scenarios), key=lambda feature: feature.name or feature.filename
|
||||
)
|
||||
code = generate_code(features, scenarios, steps)
|
||||
tw.write(code)
|
||||
|
@ -145,9 +145,7 @@ def parse_feature_files(paths: list[str], **kwargs: Any) -> tuple[list[Feature],
|
|||
itertools.chain.from_iterable(feature.scenarios.values() for feature in features),
|
||||
key=lambda scenario: (scenario.feature.name or scenario.feature.filename, scenario.name),
|
||||
)
|
||||
steps = sorted(
|
||||
set(itertools.chain.from_iterable(scenario.steps for scenario in scenarios)), key=lambda step: step.name
|
||||
)
|
||||
steps = sorted((step for scenario in scenarios for step in scenario.steps), key=lambda step: step.name)
|
||||
return features, scenarios, steps
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import re
|
|||
import textwrap
|
||||
import typing
|
||||
from collections import OrderedDict
|
||||
from dataclasses import dataclass, field
|
||||
from typing import cast
|
||||
|
||||
from . import exceptions, types
|
||||
|
@ -28,7 +29,7 @@ STEP_PREFIXES = [
|
|||
]
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from typing import Any, Iterable, Mapping, Match
|
||||
from typing import Any, Iterable, Mapping, Match, Sequence
|
||||
|
||||
|
||||
def split_line(line: str) -> list[str]:
|
||||
|
@ -187,55 +188,34 @@ def parse_feature(basedir: str, filename: str, encoding: str = "utf-8") -> Featu
|
|||
return feature
|
||||
|
||||
|
||||
@dataclass
|
||||
class Feature:
|
||||
"""Feature."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scenarios: OrderedDict,
|
||||
filename: str,
|
||||
rel_filename: str,
|
||||
name: str | None,
|
||||
tags: set,
|
||||
background: Background | None,
|
||||
line_number: int,
|
||||
description: str,
|
||||
) -> None:
|
||||
self.scenarios: dict[str, ScenarioTemplate] = scenarios
|
||||
self.rel_filename: str = rel_filename
|
||||
self.filename: str = filename
|
||||
self.tags: set = tags
|
||||
self.name: str | None = name
|
||||
self.line_number: int = line_number
|
||||
self.description: str = description
|
||||
self.background: Background | None = background
|
||||
scenarios: OrderedDict[str, ScenarioTemplate]
|
||||
filename: str
|
||||
rel_filename: str
|
||||
name: str | None
|
||||
tags: set[str]
|
||||
background: Background | None
|
||||
line_number: int
|
||||
description: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScenarioTemplate:
|
||||
"""A scenario template.
|
||||
|
||||
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, templated: bool, tags=None) -> None:
|
||||
Created when parsing the feature file, it will then be combined with the examples to create a Scenario.
|
||||
"""
|
||||
|
||||
:param str name: Scenario name.
|
||||
:param int line_number: Scenario line number.
|
||||
:param set tags: Set of tags.
|
||||
"""
|
||||
self.feature = feature
|
||||
self.name = name
|
||||
self._steps: list[Step] = []
|
||||
self.examples = Examples()
|
||||
self.line_number = line_number
|
||||
self.tags = tags or set()
|
||||
self.templated = templated
|
||||
feature: Feature
|
||||
name: str
|
||||
line_number: int
|
||||
templated: bool
|
||||
tags: set[str] = field(default_factory=set)
|
||||
examples: Examples | None = field(default_factory=lambda: Examples())
|
||||
_steps: list[Step] = field(init=False, default_factory=list)
|
||||
|
||||
def add_step(self, step: Step) -> None:
|
||||
"""Add step to the scenario.
|
||||
|
||||
:param pytest_bdd.parser.Step step: Step.
|
||||
"""
|
||||
step.scenario = self
|
||||
self._steps.append(step)
|
||||
|
||||
|
@ -263,50 +243,38 @@ class ScenarioTemplate:
|
|||
return Scenario(feature=self.feature, name=self.name, line_number=self.line_number, steps=steps, tags=self.tags)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Scenario:
|
||||
|
||||
"""Scenario."""
|
||||
|
||||
def __init__(self, feature: Feature, name: str, line_number: int, steps: list[Step] = None, tags=None) -> None:
|
||||
"""Scenario constructor.
|
||||
|
||||
:param pytest_bdd.parser.Feature feature: Feature.
|
||||
:param str name: Scenario name.
|
||||
:param int line_number: Scenario line number.
|
||||
:param set tags: Set of tags.
|
||||
"""
|
||||
if steps is None:
|
||||
steps = []
|
||||
self.feature = feature
|
||||
self.name = name
|
||||
self.steps = steps
|
||||
self.line_number = line_number
|
||||
self.tags = tags or set()
|
||||
self.failed = False
|
||||
feature: Feature
|
||||
name: str
|
||||
line_number: int
|
||||
steps: list[Step]
|
||||
tags: set[str] = field(default_factory=set)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Step:
|
||||
|
||||
"""Step."""
|
||||
type: str
|
||||
_name: str
|
||||
line_number: int
|
||||
indent: int
|
||||
keyword: str
|
||||
failed: bool = field(init=False, default=False)
|
||||
scenario: ScenarioTemplate | None = field(init=False, default=None)
|
||||
background: Background | None = field(init=False, default=None)
|
||||
lines: list[str] = field(init=False, default_factory=list)
|
||||
|
||||
def __init__(self, name: str, type: str, indent: int, line_number: int, keyword: str) -> None:
|
||||
"""Step constructor.
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.indent = indent
|
||||
self.line_number = line_number
|
||||
self.keyword = keyword
|
||||
|
||||
:param str name: step name.
|
||||
:param str type: step type.
|
||||
:param int indent: step text indent.
|
||||
:param int line_number: line number.
|
||||
:param str keyword: step keyword.
|
||||
"""
|
||||
self.name: str = name
|
||||
self.keyword: str = keyword
|
||||
self.lines: list[str] = []
|
||||
self.indent: int = indent
|
||||
self.type: str = type
|
||||
self.line_number: int = line_number
|
||||
self.failed: bool = False
|
||||
self.scenario: ScenarioTemplate | None = None
|
||||
self.background: Background | None = None
|
||||
self.failed = False
|
||||
self.scenario = None
|
||||
self.background = None
|
||||
self.lines = []
|
||||
|
||||
def add_line(self, line: str) -> None:
|
||||
"""Add line to the multiple step.
|
||||
|
@ -317,7 +285,6 @@ class Step:
|
|||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Get step name."""
|
||||
multilines_content = textwrap.dedent("\n".join(self.lines)) if self.lines else ""
|
||||
|
||||
# Remove the multiline quotes, if present.
|
||||
|
@ -333,7 +300,6 @@ class Step:
|
|||
|
||||
@name.setter
|
||||
def name(self, value: str) -> None:
|
||||
"""Set step name."""
|
||||
self._name = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
@ -342,10 +308,9 @@ class Step:
|
|||
|
||||
@property
|
||||
def params(self) -> tuple[str, ...]:
|
||||
"""Get step params."""
|
||||
return tuple(frozenset(STEP_PARAM_RE.findall(self.name)))
|
||||
|
||||
def render(self, context: Mapping[str, Any]):
|
||||
def render(self, context: Mapping[str, Any]) -> str:
|
||||
def replacer(m: Match):
|
||||
varname = m.group(1)
|
||||
return str(context[varname])
|
||||
|
@ -353,19 +318,11 @@ class Step:
|
|||
return STEP_PARAM_RE.sub(replacer, self.name)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Background:
|
||||
|
||||
"""Background."""
|
||||
|
||||
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.line_number: int = line_number
|
||||
self.steps: list[Step] = []
|
||||
feature: Feature
|
||||
line_number: int
|
||||
steps: list[Step] = field(init=False, default_factory=list)
|
||||
|
||||
def add_step(self, step: Step) -> None:
|
||||
"""Add step to the background."""
|
||||
|
@ -373,29 +330,20 @@ class Background:
|
|||
self.steps.append(step)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Examples:
|
||||
|
||||
"""Example table."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize examples instance."""
|
||||
self.example_params: list[str] = []
|
||||
self.examples: list[list[str]] = []
|
||||
self.line_number: int | None = None
|
||||
self.name = None
|
||||
line_number: int | None = field(default=None)
|
||||
name: str | None = field(default=None)
|
||||
|
||||
def set_param_names(self, keys: list[str]) -> None:
|
||||
"""Set parameter names.
|
||||
example_params: list[str] = field(init=False, default_factory=list)
|
||||
examples: list[Sequence[str]] = field(init=False, default_factory=list)
|
||||
|
||||
:param names: `list` of `string` parameter names.
|
||||
"""
|
||||
def set_param_names(self, keys: Iterable[str]) -> None:
|
||||
self.example_params = [str(key) for key in keys]
|
||||
|
||||
def add_example(self, values: list[str]) -> None:
|
||||
"""Add example.
|
||||
|
||||
:param values: `list` of `string` parameter values.
|
||||
"""
|
||||
def add_example(self, values: Sequence[str]) -> None:
|
||||
self.examples.append(values)
|
||||
|
||||
def as_contexts(self) -> Iterable[dict[str, Any]]:
|
||||
|
@ -409,7 +357,6 @@ class Examples:
|
|||
yield dict(zip(header, row))
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
"""Bool comparison."""
|
||||
return bool(self.examples)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue