Merge pull request #758 from kieran-ryan/ruff-migration
Migrate `black`, `flake8`, `isort`, `pyupgrade` linters and formatters to `ruff`
This commit is contained in:
commit
a870b66217
|
@ -1,33 +1,16 @@
|
|||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
# If you update the version here, also update it in tox.ini (py*-pytestlatest-linters)
|
||||
rev: 24.10.0
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: f0b5944bef86f50d875305821a0ab0d8c601e465 # frozen: v0.8.4
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.19.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py39-plus"]
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: "7.1.1"
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [
|
||||
"flake8-pyproject",
|
||||
"flake8-bugbear",
|
||||
]
|
||||
- id: ruff
|
||||
args: [ --fix ]
|
||||
- id: ruff-format
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"charliermarsh.ruff"
|
||||
]
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
from __future__ import annotations
|
||||
|
||||
from importlib import metadata as _metadata
|
||||
|
||||
|
|
|
@ -57,21 +57,29 @@ sphinx-autobuild = "*"
|
|||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
target-version = ["py39", "py310", "py311", "py312", "py313"]
|
||||
|
||||
[tool.flake8]
|
||||
# E1: indentation: already covered by `black`
|
||||
# E2: whitespace: already covered by `black`
|
||||
# E3: blank line: already covered by `black`
|
||||
# E501: line length: already covered by `black`
|
||||
extend-ignore = "E1,E2,E3,E501"
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
line_length = 120
|
||||
multi_line_output = 3
|
||||
target-version = "py39"
|
||||
lint.select = [
|
||||
"B", # flake8-bugbear
|
||||
"BLE", # flake8-blind-except
|
||||
"C4", # flake8-comprehensions
|
||||
"E4", # pycodestyle - error - import
|
||||
"E7", # pycodestyle - error - statement
|
||||
"E9", # pycodestyle - error - runtime
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"ISC", # flake8-implicit-str-concat
|
||||
"PERF", # perflint
|
||||
"UP", # pyupgrade
|
||||
]
|
||||
lint.ignore = [
|
||||
# Covered by formatter
|
||||
"ISC001" # single-line-implicit-string-concatenation
|
||||
]
|
||||
lint.isort.required-imports = [
|
||||
"from __future__ import annotations",
|
||||
]
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
|
|
|
@ -31,10 +31,9 @@ def configure(config: Config) -> None:
|
|||
raise Exception(
|
||||
"gherkin-terminal-reporter is not compatible with any other terminal reporter."
|
||||
"You can use only one terminal reporter."
|
||||
"Currently '{0}' is used."
|
||||
"Please decide to use one by deactivating {0} or gherkin-terminal-reporter.".format(
|
||||
current_reporter.__class__
|
||||
)
|
||||
f"Currently '{current_reporter.__class__}' is used."
|
||||
f"Please decide to use one by deactivating {current_reporter.__class__} "
|
||||
"or gherkin-terminal-reporter."
|
||||
)
|
||||
gherkin_reporter = GherkinTerminalReporter(config)
|
||||
config.pluginmanager.unregister(current_reporter)
|
||||
|
|
|
@ -10,14 +10,12 @@ from dataclasses import dataclass, field
|
|||
|
||||
from .exceptions import StepError
|
||||
from .gherkin_parser import Background as GherkinBackground
|
||||
from .gherkin_parser import DataTable
|
||||
from .gherkin_parser import DataTable, GherkinDocument, get_gherkin_document
|
||||
from .gherkin_parser import Feature as GherkinFeature
|
||||
from .gherkin_parser import GherkinDocument
|
||||
from .gherkin_parser import Rule as GherkinRule
|
||||
from .gherkin_parser import Scenario as GherkinScenario
|
||||
from .gherkin_parser import Step as GherkinStep
|
||||
from .gherkin_parser import Tag as GherkinTag
|
||||
from .gherkin_parser import get_gherkin_document
|
||||
from .types import STEP_TYPE_BY_PARSER_KEYWORD
|
||||
|
||||
PARAM_RE = re.compile(r"<(.+?)>")
|
||||
|
@ -48,7 +46,7 @@ def get_tag_names(tag_data: list[GherkinTag]) -> set[str]:
|
|||
"""Extract tag names from tag data.
|
||||
|
||||
Args:
|
||||
tag_data (List[dict]): The tag data to extract names from.
|
||||
tag_data (list[dict]): The tag data to extract names from.
|
||||
|
||||
Returns:
|
||||
set[str]: A set of tag names.
|
||||
|
@ -66,7 +64,7 @@ class Feature:
|
|||
rel_filename (str): The relative path of the feature file.
|
||||
name (str): The name of the feature.
|
||||
tags (set[str]): A set of tags associated with the feature.
|
||||
background (Optional[Background]): The background steps for the feature, if any.
|
||||
background (Background | None): The background steps for the feature, if any.
|
||||
line_number (int): The line number where the feature starts in the file.
|
||||
description (str): The description of the feature.
|
||||
"""
|
||||
|
@ -88,10 +86,10 @@ class Examples:
|
|||
"""Represents examples used in scenarios for parameterization.
|
||||
|
||||
Attributes:
|
||||
line_number (Optional[int]): The line number where the examples start.
|
||||
name (Optional[str]): The name of the examples.
|
||||
example_params (List[str]): The names of the parameters for the examples.
|
||||
examples (List[Sequence[str]]): The list of example rows.
|
||||
line_number (int | None): The line number where the examples start.
|
||||
name (str | None): The name of the examples.
|
||||
example_params (list[str]): The names of the parameters for the examples.
|
||||
examples (list[Sequence[str]]): The list of example rows.
|
||||
"""
|
||||
|
||||
line_number: int | None = None
|
||||
|
@ -154,11 +152,11 @@ class ScenarioTemplate:
|
|||
name (str): The name of the scenario.
|
||||
line_number (int): The line number where the scenario starts in the file.
|
||||
templated (bool): Whether the scenario is templated.
|
||||
description (Optional[str]): The description of the scenario.
|
||||
description (str | None): The description of the scenario.
|
||||
tags (set[str]): A set of tags associated with the scenario.
|
||||
_steps (List[Step]): The list of steps in the scenario (internal use only).
|
||||
examples (Optional[Examples]): The examples used for parameterization in the scenario.
|
||||
rule (Optional[Rule]): The rule to which the scenario may belong (None = no rule).
|
||||
_steps (list[Step]): The list of steps in the scenario (internal use only).
|
||||
examples (Examples | None): The examples used for parameterization in the scenario.
|
||||
rule (Rule | None): The rule to which the scenario may belong (None = no rule).
|
||||
"""
|
||||
|
||||
feature: Feature
|
||||
|
@ -197,7 +195,7 @@ class ScenarioTemplate:
|
|||
"""Get all steps for the scenario, including background steps.
|
||||
|
||||
Returns:
|
||||
List[Step]: A list of steps, including any background steps from the feature.
|
||||
list[Step]: A list of steps, including any background steps from the feature.
|
||||
"""
|
||||
return self.all_background_steps + self._steps
|
||||
|
||||
|
@ -244,8 +242,8 @@ class Scenario:
|
|||
keyword (str): The keyword used to define the scenario.
|
||||
name (str): The name of the scenario.
|
||||
line_number (int): The line number where the scenario starts in the file.
|
||||
steps (List[Step]): The list of steps in the scenario.
|
||||
description (Optional[str]): The description of the scenario.
|
||||
steps (list[Step]): The list of steps in the scenario.
|
||||
description (str | None): The description of the scenario.
|
||||
tags (set[str]): A set of tags associated with the scenario.
|
||||
"""
|
||||
|
||||
|
@ -270,8 +268,8 @@ class Step:
|
|||
indent (int): The indentation level of the step.
|
||||
keyword (str): The keyword used for the step (e.g., 'Given', 'When', 'Then').
|
||||
failed (bool): Whether the step has failed (internal use only).
|
||||
scenario (Optional[ScenarioTemplate]): The scenario to which this step belongs (internal use only).
|
||||
background (Optional[Background]): The background to which this step belongs (internal use only).
|
||||
scenario (ScenarioTemplate | None): The scenario to which this step belongs (internal use only).
|
||||
background (Background | None): The background to which this step belongs (internal use only).
|
||||
"""
|
||||
|
||||
type: str
|
||||
|
@ -346,7 +344,7 @@ class Background:
|
|||
|
||||
Attributes:
|
||||
line_number (int): The line number where the background starts in the file.
|
||||
steps (List[Step]): The list of steps in the background.
|
||||
steps (list[Step]): The list of steps in the background.
|
||||
"""
|
||||
|
||||
line_number: int
|
||||
|
@ -371,7 +369,7 @@ class FeatureParser:
|
|||
encoding (str): File encoding of the feature file to parse.
|
||||
"""
|
||||
|
||||
def __init__(self, basedir: str, filename: str, encoding: str = "utf-8"):
|
||||
def __init__(self, basedir: str, filename: str, encoding: str = "utf-8") -> None:
|
||||
self.abs_filename = os.path.abspath(os.path.join(basedir, filename))
|
||||
self.rel_filename = os.path.join(os.path.basename(basedir), filename)
|
||||
self.encoding = encoding
|
||||
|
@ -380,10 +378,10 @@ class FeatureParser:
|
|||
"""Parse a list of step data into Step objects.
|
||||
|
||||
Args:
|
||||
steps_data (List[dict]): The list of step data.
|
||||
steps_data (list[dict]): The list of step data.
|
||||
|
||||
Returns:
|
||||
List[Step]: A list of Step objects.
|
||||
list[Step]: A list of Step objects.
|
||||
"""
|
||||
|
||||
if not steps_data:
|
||||
|
@ -423,7 +421,7 @@ class FeatureParser:
|
|||
Args:
|
||||
scenario_data (dict): The dictionary containing scenario data.
|
||||
feature (Feature): The feature to which this scenario belongs.
|
||||
rule (Optional[Rule]): The rule to which this scenario may belong. (None = no rule)
|
||||
rule (Rule | None): The rule to which this scenario may belong. (None = no rule)
|
||||
|
||||
Returns:
|
||||
ScenarioTemplate: A ScenarioTemplate object representing the parsed scenario.
|
||||
|
|
|
@ -188,9 +188,9 @@ def parse_step_arguments(step: Step, context: StepFunctionContext) -> dict[str,
|
|||
"""Parse step arguments."""
|
||||
parsed_args = context.parser.parse_arguments(step.name)
|
||||
|
||||
assert parsed_args is not None, (
|
||||
f"Unexpected `NoneType` returned from " f"parse_arguments(...) in parser: {context.parser!r}"
|
||||
)
|
||||
assert (
|
||||
parsed_args is not None
|
||||
), f"Unexpected `NoneType` returned from parse_arguments(...) in parser: {context.parser!r}"
|
||||
|
||||
reserved_args = set(parsed_args.keys()) & STEP_ARGUMENTS_RESERVED_NAMES
|
||||
if reserved_args:
|
||||
|
@ -386,7 +386,7 @@ def scenario(
|
|||
feature_name = feature.name or "[Empty]"
|
||||
raise exceptions.ScenarioNotFound(
|
||||
f'Scenario "{scenario_name}" in feature "{feature_name}" in {feature.filename} is not found.'
|
||||
)
|
||||
) from None
|
||||
|
||||
return _get_scenario_decorator(
|
||||
feature=feature, feature_name=feature_name, templated_scenario=scenario, scenario_name=scenario_name
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Step arguments tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Step arguments tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Step arguments tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
pytest_plugins = "pytester"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from src.pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test step alias when decorated multiple times."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test feature background."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
FEATURE = '''\
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test descriptions."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test feature base dir."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
@ -59,12 +61,10 @@ def test_feature_path_by_param_ok(pytester, base_dir):
|
|||
|
||||
def prepare_testdir(pytester, ini_base_dir):
|
||||
pytester.makeini(
|
||||
"""
|
||||
f"""
|
||||
[pytest]
|
||||
bdd_features_base_dir={}
|
||||
""".format(
|
||||
ini_base_dir
|
||||
)
|
||||
bdd_features_base_dir={ini_base_dir}
|
||||
"""
|
||||
)
|
||||
|
||||
feature_file = pytester.mkdir("features").joinpath("steps.feature")
|
||||
|
@ -77,7 +77,7 @@ def prepare_testdir(pytester, ini_base_dir):
|
|||
)
|
||||
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
f"""
|
||||
import os.path
|
||||
|
||||
import pytest
|
||||
|
@ -103,7 +103,7 @@ def prepare_testdir(pytester, ini_base_dir):
|
|||
scenarios(FEATURE)
|
||||
else:
|
||||
scenario(FEATURE, scenario_name)
|
||||
assert os.path.abspath(os.path.join('{}', FEATURE)) in str(exc.value)
|
||||
assert os.path.abspath(os.path.join('{ini_base_dir}', FEATURE)) in str(exc.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -145,7 +145,5 @@ def prepare_testdir(pytester, ini_base_dir):
|
|||
else:
|
||||
scenario(FEATURE, scenario_name, features_base_dir='features')
|
||||
|
||||
""".format(
|
||||
ini_base_dir
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -200,9 +200,7 @@ def test_step_parameters_should_be_replaced_by_their_values(pytester):
|
|||
Examples:
|
||||
| start | eat | left |
|
||||
|{start}|{eat}|{left}|
|
||||
""".format(
|
||||
**example
|
||||
)
|
||||
""".format(**example)
|
||||
),
|
||||
)
|
||||
pytester.makepyfile(
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test no scenarios defined in the feature file."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Scenario Outline tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
@ -333,7 +335,7 @@ def test_variable_reuse(pytester):
|
|||
outline=textwrap.dedent(
|
||||
"""\
|
||||
Feature: Example parameters reuse
|
||||
Scenario Outline: Check for example parameter re-use
|
||||
Scenario Outline: Check for example parameter reuse
|
||||
Given the param is initially set from the example table as <param>
|
||||
When a step arg of the same name is set to "other"
|
||||
Then the param is still set from the example table as <param>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Scenario Outline with empty example values tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""Test scenario reporting."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
from typing import Optional
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -11,7 +12,7 @@ from pytest_bdd.reporting import test_report_context_registry
|
|||
class OfType:
|
||||
"""Helper object comparison to which is always 'equal'."""
|
||||
|
||||
def __init__(self, type: Optional[type] = None) -> None:
|
||||
def __init__(self, type: type | None = None) -> None:
|
||||
self.type = type
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Function name same as step name."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test scenario decorator."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test scenarios shortcut."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test tags."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test wrong feature syntax."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Code generation and assertion tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import textwrap
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
Check the parent givens are collected and overridden in the local conftest.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
@ -233,7 +235,7 @@ def test_local(pytester):
|
|||
|
||||
def test_uses_correct_step_in_the_hierarchy(pytester):
|
||||
"""
|
||||
Test regression found in issue #524, where we couldn't find the correct step implemntation in the
|
||||
Test regression found in issue #524, where we couldn't find the correct step implementation in the
|
||||
hierarchy of files/folder as expected.
|
||||
This test uses many files and folders that act as decoy, while the real step implementation is defined
|
||||
in the last file (test_b/test_b.py).
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from src.pytest_bdd.gherkin_parser import (
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test code generation command."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Main command."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Test code generation command."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
@ -31,11 +33,7 @@ def test_migrate(monkeypatch, capsys, pytester):
|
|||
expected = textwrap.dedent(
|
||||
"""
|
||||
migrated: {0}/test_foo.py
|
||||
skipped: {0}/__init__.py""".format(
|
||||
str(tests)
|
||||
)[
|
||||
1:
|
||||
]
|
||||
skipped: {0}/__init__.py""".format(str(tests))[1:]
|
||||
)
|
||||
assert out == expected
|
||||
assert tests.joinpath("test_foo.py").read_text() == textwrap.dedent(
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
from typing import Any, Callable
|
||||
from unittest import mock
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from src.pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Given tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Tests for testing cases when we have unicode in feature file."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import textwrap
|
||||
|
||||
from pytest_bdd.utils import collect_dumped_objects
|
||||
|
|
Loading…
Reference in New Issue