Skip to content

Commit

Permalink
Merge pull request #112 from elchupanebrej/facelift
Browse files Browse the repository at this point in the history
Check and specify compatibility workarounds
  • Loading branch information
elchupanebrej authored Sep 1, 2024
2 parents ec11816 + e062c23 commit 80596a7
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 21 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -U setuptools
pip install "tox~=4.0" "tox-gh-actions~=3.0" codecov
pip install "tox>=4.0" "tox-gh-actions>=3.2" codecov
- name: Test with tox
run: |
tox
- name: Gather codecov
run: |
codecov
- name: Build checking
if: "matrix.python-version == '3.12'"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
submodules: 'recursive'
- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip build twine
Expand Down
3 changes: 2 additions & 1 deletion src/pytest_bdd/allure_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pydantic import BaseModel as PydanticBaseModel

from pytest_bdd.compatibility.allure import ALLURE_INSTALLED
from pytest_bdd.compatibility.pytest import PYTEST81

if ALLURE_INSTALLED:
from allure_commons import hookimpl
Expand All @@ -34,7 +35,7 @@ def __init__(self, allure_logger, allure_cache):
def register_if_allure_accessible(cls, config):
pluginmanager = config.pluginmanager
allure_accessible = pluginmanager.hasplugin("allure_pytest") and config.option.allure_report_dir
if allure_accessible:
if allure_accessible and not PYTEST81:
allure_plugin_manager.get_plugins()

listener = next(
Expand Down
12 changes: 12 additions & 0 deletions src/pytest_bdd/compatibility/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import os
import sys


def relpath(path, start=os.curdir):
try:
return os.path.relpath(path, start)
except ValueError:
if sys.platform == "win32":
return path
else:
raise
7 changes: 4 additions & 3 deletions src/pytest_bdd/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
from enum import Enum
from inspect import isfunction, isgeneratorfunction, signature
from itertools import count, product, starmap
from operator import attrgetter
from typing import Optional, Union

from _pytest.mark import Mark
from decopatch import function_decorator
from makefun import wraps
from pytest import fixture

from pytest_bdd.compatibility.pytest import FixtureRequest
from pytest_bdd.compatibility.pytest import PYTEST7, FixtureRequest
from pytest_bdd.tag_expression import GherkinTagExpression, MarksTagExpression, TagExpression

expression_count_gen = count()
Expand Down Expand Up @@ -57,7 +56,9 @@ def hook(request: FixtureRequest, *args, **kwargs):
{
HookKind.mark: request.node.iter_markers(),
HookKind.tag: map(
lambda tag: Mark(tag.name, args=tuple(), kwargs={}), # type: ignore[no-any-return]
lambda tag: Mark( # type: ignore[no-any-return]
tag.name, args=tuple(), kwargs={}, **({"_ispytest": True} if PYTEST7 else {})
),
request.getfixturevalue("scenario").tags,
),
}[_kind]
Expand Down
3 changes: 2 additions & 1 deletion src/pytest_bdd/message_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
TestStepStarted,
Timestamp,
)
from pytest_bdd.compatibility.path import relpath
from pytest_bdd.compatibility.pytest import (
Config,
FixtureDef,
Expand Down Expand Up @@ -252,7 +253,7 @@ def pytest_fixture_setup(self, fixturedef: FixtureDef, request):
id=cast(PytestBDDIdGeneratorHandler, config).pytest_bdd_id_generator.get_next_id(),
**({"name": hook_name} if hook_name is not None else {}),
source_reference=SourceReference(
uri=os.path.relpath(
uri=relpath(
getfile(func),
str(get_config_root_path(cast(Config, config))),
),
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_bdd/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from functools import partial
from itertools import filterfalse
from operator import contains, itemgetter, methodcaller
from os.path import relpath
from pathlib import Path
from typing import Callable, List, Sequence, Set, Tuple, Union

Expand All @@ -13,6 +12,7 @@
from gherkin.pickles.compiler import Compiler as PicklesCompiler

from pytest_bdd.compatibility.parser import ParserProtocol
from pytest_bdd.compatibility.path import relpath
from pytest_bdd.compatibility.pytest import Config
from pytest_bdd.compatibility.struct_bdd import STRUCT_BDD_INSTALLED
from pytest_bdd.exceptions import FeatureError
Expand Down
32 changes: 28 additions & 4 deletions src/pytest_bdd/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pytest_bdd.collector import FeatureFileModule as FeatureFileCollector
from pytest_bdd.collector import Module as ModuleCollector
from pytest_bdd.compatibility.pytest import (
PYTEST7,
Config,
FixtureRequest,
Mark,
Expand Down Expand Up @@ -144,12 +145,24 @@ def pytest_unconfigure(config: Config) -> None:
cucumber_json.unconfigure(config)


@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(path, parent, module_path=None):
def _pytest_pycollect_makemodule():
with patch("_pytest.python.Module", new=ModuleCollector):
yield


if PYTEST7:

@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(parent, module_path):
yield from _pytest_pycollect_makemodule()

else:

@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(path, parent):
yield from _pytest_pycollect_makemodule()


@pytest.hookimpl(tryfirst=True)
def pytest_plugin_registered(plugin, manager):
if hasattr(plugin, "__file__") and isinstance(plugin, (type, ModuleType)):
Expand Down Expand Up @@ -298,8 +311,8 @@ def pytest_cmdline_main(config: Config) -> Optional[int]:
return generation.cmdline_main(config)


def pytest_collect_file(parent: Collector, path, file_path=None):
file_path = file_path or Path(path)
def _pytest_collect_file(parent: Collector, file_path=None):
file_path = Path(file_path)
config = parent.session.config
is_enabled_feature_autoload = config.getoption("feature_autoload")
if is_enabled_feature_autoload is None:
Expand All @@ -314,6 +327,17 @@ def pytest_collect_file(parent: Collector, path, file_path=None):
return FeatureFileCollector.build(parent=parent, file_path=file_path)


if PYTEST7: # Done intentionally because of API change

def pytest_collect_file(parent: Collector, file_path):
return _pytest_collect_file(parent=parent, file_path=file_path)

else:

def pytest_collect_file(parent: Collector, path): # type: ignore[misc]
return _pytest_collect_file(parent=parent, file_path=path)


@pytest.mark.trylast
def pytest_bdd_convert_tag_to_marks(feature, scenario, tag) -> Optional[Collection[Union[Mark, MarkDecorator]]]:
return [getattr(pytest.mark, tag)]
Expand Down
3 changes: 2 additions & 1 deletion src/pytest_bdd/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def given_beautiful_article(article):
from messages import ExpressionType, Location, Pickle # type:ignore[attr-defined]
from messages import PickleStep as Step # type:ignore[attr-defined]
from messages import SourceReference, StepDefinition, StepDefinitionPattern # type:ignore[attr-defined]
from pytest_bdd.compatibility.path import relpath
from pytest_bdd.compatibility.pytest import Config, Parser, TypeAlias, get_config_root_path
from pytest_bdd.model import Feature, StepType
from pytest_bdd.model.messages_extension import ExpressionType as ExpressionTypeExtension
Expand Down Expand Up @@ -383,7 +384,7 @@ def as_message(self, config: Union[Config, PytestBDDIdGeneratorHandler]):
id=self.id,
pattern=pattern,
source_reference=SourceReference( # type: ignore[call-arg] # migration to pydantic2
uri=os.path.relpath(
uri=relpath(
getfile(self.func),
str(get_config_root_path(cast(Config, config))),
),
Expand Down
17 changes: 14 additions & 3 deletions src/pytest_bdd/struct_bdd/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from pytest_bdd.compatibility.pytest import Config, Module
from pytest_bdd.compatibility.pytest import PYTEST7, Config, Module
from pytest_bdd.mimetypes import Mimetype
from pytest_bdd.struct_bdd.model import StepPrototype
from pytest_bdd.struct_bdd.parser import StructBDDParser
Expand Down Expand Up @@ -45,11 +45,22 @@ def pytest_bdd_is_collectible(self, config: Config, path: Path):
if str(path).endswith(f".bdd.{extension_suffix.value}"):
return True

@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(self, path, parent, module_path=None):
def _pytest_pycollect_makemodule(self):
outcome = yield
res = outcome.get_result()
if isinstance(res, Module):
for member_name, member in getmembers(res.module):
if isinstance(member, StepPrototype) and member_name.startswith("test_"):
setattr(res.module, member_name, member.as_test(res.module.__file__))

if PYTEST7:

@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(self, parent, module_path):
yield from self._pytest_pycollect_makemodule()

else:

@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makemodule(self, path, parent):
yield from self._pytest_pycollect_makemodule()
8 changes: 5 additions & 3 deletions src/pytest_bdd/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
runtime_checkable,
)

from pytest_bdd.compatibility.pytest import PYTEST8, PYTEST81, FixtureDef, fail
from _pytest.fixtures import FixtureDef, FixtureRequest

from pytest_bdd.compatibility.pytest import PYTEST7, PYTEST8, PYTEST81, fail
from pytest_bdd.const import ALPHA_REGEX, PYTHON_REPLACE_REGEX

if TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -147,9 +149,8 @@ def instantiate_from_collection_or_bool(
return cls(bool_or_items, warm_up_keys=warm_up_keys)


def inject_fixture(request, arg, value):
def inject_fixture(request: FixtureRequest, arg: str, value: Any) -> None:
"""Inject fixture into pytest fixture request.
:param request: pytest fixture request
:param arg: argument name
:param value: argument value
Expand All @@ -162,6 +163,7 @@ def inject_fixture(request, arg, value):
func=lambda: value,
scope="function",
params=None,
**({"_ispytest": True} if PYTEST8 else {}),
)
fd.cached_result = (value, 0, None)

Expand Down
2 changes: 2 additions & 0 deletions tests/allure_/test_allure_outline.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

from pytest_bdd import scenario
from pytest_bdd.compatibility.allure import ALLURE_INSTALLED
from pytest_bdd.compatibility.pytest import PYTEST81


@scenario("testdata/allure_/outline.feature", "Scenario outline")
@mark.skipif(not ALLURE_INSTALLED, reason="Allure is not installed")
@mark.skipif(PYTEST81, reason="Allure uses deprecated APIs")
def test_scenario_outline():
pass
2 changes: 2 additions & 0 deletions tests/allure_/test_allure_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

from pytest_bdd import scenario
from pytest_bdd.compatibility.allure import ALLURE_INSTALLED
from pytest_bdd.compatibility.pytest import PYTEST81


@scenario("testdata/allure_//scenario.feature", "Simple passed scenario")
@mark.skipif(not ALLURE_INSTALLED, reason="Allure is not installed")
@mark.skipif(PYTEST81, reason="Allure uses deprecated APIs")
def test_simple_passed_scenario():
pass
2 changes: 1 addition & 1 deletion tests/feature/test_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def test_steps(
second_foo,
request
):
# Original fixture values are recieved from test parameters
# Original fixture values are received from test parameters
assert first_foo == 'first_foo'
assert second_foo == 'second_foo'
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ envlist =
py312-pytest{625, 83, 82, 81, 80, 74, 73, 72, 71, 70, latest}-mypy-lin
py312-pytest{625, 83, 82, 81, 80, 74, 73, 72, 71, 70, latest}-coverage-lin
py312-pytestlatest-gherkin{24, latest}-xdist-coverage-{lin, win, mac}
py312-pytestlatets-allure-coverage-{lin, win, mac}
py312-pytest80-allure-coverage-{lin, win, mac}
py39-pytest{62, 61, 60, 54, 53, 52, 51, 50}-coverage-lin
py38-pytest{62, 54}-coverage-{win, mac}
py{py39, py38, 38}-pytest{62, 54}-coverage-lin
Expand Down

0 comments on commit 80596a7

Please sign in to comment.