diff --git a/allure-behave/setup.py b/allure-behave/setup.py index 4eefa3bc..018cfc62 100644 --- a/allure-behave/setup.py +++ b/allure-behave/setup.py @@ -61,7 +61,8 @@ def main(): packages=["allure_behave"], package_dir={"allure_behave": "src"}, setup_requires=setup_requires, - install_requires=install_requires + install_requires=install_requires, + python_requires=">=3.8", ) if __name__ == "__main__": diff --git a/allure-behave/src/formatter.py b/allure-behave/src/formatter.py index fd5576f1..2ba27701 100644 --- a/allure-behave/src/formatter.py +++ b/allure-behave/src/formatter.py @@ -9,7 +9,7 @@ class AllureFormatter(Formatter): def __init__(self, stream_opener, config): - super(AllureFormatter, self).__init__(stream_opener, config) + super().__init__(stream_opener, config) self.listener = AllureListener(config) self.file_logger = AllureFileLogger(self.stream_opener.name) diff --git a/allure-nose2/setup.py b/allure-nose2/setup.py index 4d03ddbc..4b51b510 100644 --- a/allure-nose2/setup.py +++ b/allure-nose2/setup.py @@ -59,7 +59,8 @@ def main(): packages=["allure_nose2"], package_dir={"allure_nose2": "src"}, setup_requires=setup_requires, - install_requires=install_requires + install_requires=install_requires, + python_requires=">=3.8", ) diff --git a/allure-pytest-bdd/setup.py b/allure-pytest-bdd/setup.py index 4c77133a..51d6311b 100644 --- a/allure-pytest-bdd/setup.py +++ b/allure-pytest-bdd/setup.py @@ -63,7 +63,8 @@ def main(): package_dir={"allure_pytest_bdd": "src"}, entry_points={"pytest11": ["allure_pytest_bdd = allure_pytest_bdd.plugin"]}, setup_requires=setup_requires, - install_requires=install_requires + install_requires=install_requires, + python_requires=">=3.8", ) diff --git a/allure-pytest/setup.py b/allure-pytest/setup.py index de5ea954..3fd70d7a 100644 --- a/allure-pytest/setup.py +++ b/allure-pytest/setup.py @@ -76,7 +76,8 @@ def main(): package_dir={"allure_pytest": "src"}, entry_points={"pytest11": ["allure_pytest = allure_pytest.plugin"]}, setup_requires=setup_requires, - install_requires=install_requires + install_requires=install_requires, + python_requires=">=3.8", ) if __name__ == "__main__": diff --git a/allure-python-commons-test/setup.py b/allure-python-commons-test/setup.py index 8b7c3266..f1dc965c 100644 --- a/allure-python-commons-test/setup.py +++ b/allure-python-commons-test/setup.py @@ -50,7 +50,8 @@ def main(): long_description_content_type="text/markdown", packages=["allure_commons_test"], package_dir={"allure_commons_test": "src"}, - install_requires=install_requires + install_requires=install_requires, + python_requires=">=3.8", ) if __name__ == "__main__": diff --git a/allure-python-commons/setup.py b/allure-python-commons/setup.py index 75bb2332..b54a2bc7 100644 --- a/allure-python-commons/setup.py +++ b/allure-python-commons/setup.py @@ -56,7 +56,7 @@ def main(): }, package_dir={"": "src"}, install_requires=install_requires, - python_requires=">=3.6" + python_requires=">=3.8", ) diff --git a/allure-python-commons/src/allure_commons/_allure.py b/allure-python-commons/src/allure_commons/_allure.py index 08fb5a87..e552b430 100644 --- a/allure-python-commons/src/allure_commons/_allure.py +++ b/allure-python-commons/src/allure_commons/_allure.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from functools import wraps -from typing import Any, Callable, TypeVar, Union, overload +from typing import Any, Callable, TypeVar, overload from allure_commons._core import plugin_manager from allure_commons.types import LabelType, LinkType, ParameterMode @@ -133,7 +135,7 @@ def link(url, link_type=LinkType.LINK, name=None): plugin_manager.hook.add_link(url=url, link_type=link_type, name=name) @staticmethod - def parameter(name, value, excluded=None, mode: Union[ParameterMode, None] = None): + def parameter(name, value, excluded=None, mode: ParameterMode | None = None): plugin_manager.hook.add_parameter(name=name, value=value, excluded=excluded, mode=mode) @staticmethod @@ -162,7 +164,7 @@ def manual(): @overload -def step(title: str) -> "StepContext": +def step(title: str) -> StepContext: ... diff --git a/allure-python-commons/src/allure_commons/logger.py b/allure-python-commons/src/allure_commons/logger.py index da3df2da..4f76d9c6 100644 --- a/allure-python-commons/src/allure_commons/logger.py +++ b/allure-python-commons/src/allure_commons/logger.py @@ -1,4 +1,3 @@ -import io import os from pathlib import Path import json @@ -22,7 +21,7 @@ def _report_item(self, item): indent = INDENT if os.environ.get("ALLURE_INDENT_OUTPUT") else None filename = item.file_pattern.format(prefix=uuid.uuid4()) data = asdict(item, filter=lambda _, v: v or v is False) - with io.open(self._report_dir / filename, "w", encoding="utf8") as json_file: + with open(self._report_dir / filename, "w", encoding="utf8") as json_file: json.dump(data, json_file, indent=indent, ensure_ascii=False) @hookimpl diff --git a/allure-python-commons/src/allure_commons/utils.py b/allure-python-commons/src/allure_commons/utils.py index c50cb7ec..19dea4e5 100644 --- a/allure-python-commons/src/allure_commons/utils.py +++ b/allure-python-commons/src/allure_commons/utils.py @@ -1,6 +1,5 @@ import os import string -import sys import time import uuid import json @@ -41,7 +40,7 @@ def platform_label(): def thread_tag(): - return "{0}-{1}".format(os.getpid(), threading.current_thread().name) + return f"{os.getpid()}-{threading.current_thread().name}" def host_tag(): @@ -245,13 +244,7 @@ def func_parameters(func, *args, **kwargs): args_dict.pop(arg_spec.args[0], None) if kwargs: - if sys.version_info < (3, 7): - # Sort alphabetically as old python versions does - # not preserve call order for kwargs. - arg_order.extend(sorted(list(kwargs.keys()))) - else: - # Keep py3.7 behaviour to preserve kwargs order - arg_order.extend(list(kwargs.keys())) + arg_order.extend(list(kwargs.keys())) parameters.update(kwargs) parameters.update(args_dict) @@ -328,7 +321,7 @@ def get_testplan(): file_path = os.environ.get("ALLURE_TESTPLAN_PATH") if file_path and os.path.exists(file_path): - with open(file_path, "r") as plan_file: + with open(file_path) as plan_file: plan = json.load(plan_file) planned_tests = plan.get("tests", []) diff --git a/allure-robotframework/setup.py b/allure-robotframework/setup.py index ca07e98f..dd110a17 100644 --- a/allure-robotframework/setup.py +++ b/allure-robotframework/setup.py @@ -62,4 +62,5 @@ def get_readme(fname): long_description=get_readme("README.md"), long_description_content_type="text/markdown", classifiers=classifiers, + python_requires=">=3.8", ) diff --git a/pyproject.toml b/pyproject.toml index b43cc5cb..0a8b529c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ extend-exclude = [ "tests/allure_behave/acceptance/behave_support/background/background_steps.py", ] line-length = 120 +target-version = "py38" [tool.ruff.lint] select = [ @@ -33,5 +34,6 @@ select = [ "E", # pycodestyle errors "F", # pyflakes "Q", # flake8-quotes + "UP", # pyupgrade "W", # pycodestyle warnings ] diff --git a/tests/allure_pytest/pytest_runner.py b/tests/allure_pytest/pytest_runner.py index a90f5041..d5c5d7ef 100644 --- a/tests/allure_pytest/pytest_runner.py +++ b/tests/allure_pytest/pytest_runner.py @@ -1,8 +1,10 @@ +from __future__ import annotations + from doctest import script_from_examples from pathlib import Path from pytest import FixtureRequest, Pytester, StashKey from tests.e2e import AllureFrameworkRunner, altered_env, PathlikeT -from typing import Sequence, Tuple, Union +from typing import Sequence from allure_commons.logger import AllureMemoryLogger @@ -123,7 +125,7 @@ def run_docpath_examples( def run_pytest( self, - *testfile_literals: Union[str, Tuple[PathlikeT, str]], + *testfile_literals: str | tuple[PathlikeT, str], conftest_literal: str = None, cli_args: Sequence[str] = None, testplan: dict = None @@ -131,7 +133,7 @@ def run_pytest( """Runs a nested pytest session in an isolated allure context. Arguments: - *testfile_literals (str | Tuple[str | Path, str]): test files to + *testfile_literals (str | tuple[str | Path, str]): test files to run. Each test file is represented either as a content string or as a tuple of a path and a string. The path should be relative to the pytester's path. diff --git a/tests/allure_robotframework/robot_runner.py b/tests/allure_robotframework/robot_runner.py index 1d019ffe..b1ed3c55 100644 --- a/tests/allure_robotframework/robot_runner.py +++ b/tests/allure_robotframework/robot_runner.py @@ -1,7 +1,9 @@ +from __future__ import annotations + import robot from pytest import FixtureRequest, Pytester from tests.e2e import AllureFrameworkRunner, PathlikeT -from typing import Sequence, Mapping, Union +from typing import Sequence, Mapping from allure_robotframework import allure_robotframework @@ -12,7 +14,7 @@ class AllureRobotRunner(AllureFrameworkRunner): def __init__(self, request: FixtureRequest, pytester: Pytester): super().__init__(request, pytester, AllureRobotRunner.LOGGER_PATH) - self.rootdir: Union[str, None] = None + self.rootdir: str | None = None def run_robotframework( self, diff --git a/tests/e2e.py b/tests/e2e.py index 5453e6fa..985eedc7 100644 --- a/tests/e2e.py +++ b/tests/e2e.py @@ -3,11 +3,12 @@ """ +from __future__ import annotations + import docutils import docutils.nodes import docutils.parsers.rst import json -import mock import pytest import shutil import warnings @@ -18,7 +19,8 @@ from packaging.version import parse as parse_version from pathlib import Path from pytest import FixtureRequest, Pytester, MonkeyPatch -from typing import Tuple, Mapping, TypeVar, Generator, Callable, Union +from typing import Mapping, TypeVar, Generator, Callable +from unittest import mock import allure_commons from allure_commons.logger import AllureMemoryLogger @@ -56,7 +58,7 @@ def version_gte(package: str, major: int, minor: int = 0, micro: int = 0): return not version_lt(package, major, minor, micro) -PathlikeT = Union[str, Path] +PathlikeT = TypeVar("PathlikeT", str, Path) @contextmanager @@ -167,7 +169,7 @@ def allure_file_context( def find_node_with_docstring( request: FixtureRequest -) -> Union[Tuple[pytest.Item, str], Tuple[None, None]]: +) -> tuple[pytest.Item, str] | tuple[None, None]: """Find a docstring associated with a test function. It first checks the function itself and then, if no docstring was found, @@ -191,7 +193,7 @@ def find_node_with_docstring( def find_node_with_docstring_or_throw( request: FixtureRequest -) -> Tuple[pytest.Item, str]: +) -> tuple[pytest.Item, str]: """Find a docstring associated with a test function. It first checks the function itself and then, if no docstring was found, @@ -468,7 +470,7 @@ def _get_all_content(self, paths=None, literals=None, rst_ids=None): document. Returns: - List[str]: a list of strings, each representing a file content. + list[str]: a list of strings, each representing a file content. """ @@ -510,7 +512,7 @@ def _create_files( extension may be omitted) to its ID in the .rst document. Returns: - List[Path]: a list of the newly created file paths. + list[Path]: a list of the newly created file paths. """ return self._copy_files(paths) + self._make_files_from_literals( extension, @@ -526,7 +528,7 @@ def _make_files_from_literals(self, extension, literals): its content (an extension can be omitted). Returns: - List[Path]: a list of the newly created file paths. + list[Path]: a list of the newly created file paths. """ return [ @@ -544,7 +546,7 @@ def _copy_files(self, src_paths): relative to the current test directory. Returns: - List[Path]: a list of the newly created file paths. + list[Path]: a list of the newly created file paths. """ dst_paths = [] for p in src_paths or []: @@ -567,7 +569,7 @@ def _make_files_from_rst( extension may be omitted) to its ID in the .rst document. Returns: - List[Path]: a list of the newly created file paths. + list[Path]: a list of the newly created file paths. """ return [ @@ -590,7 +592,7 @@ def _read_file(self, path: PathlikeT, basepath: PathlikeT = None): if basepath is None: basepath = self.request.path.parent path = basepath / path - with open(path, mode="r", encoding="utf-8") as f: + with open(path, encoding="utf-8") as f: return f.read() def _cache_docstring_test_result(