From a4cb74e8646dc3cfaa1c4d5b36e0d21f177332e6 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 10 Nov 2024 19:25:05 +0100 Subject: [PATCH 1/9] Upgrade doc and CI after dropping python 3.8 --- .github/workflows/prepare-release-pr.yml | 2 +- .github/workflows/test.yml | 103 +++++++++++++---------- .pre-commit-config.yaml | 4 + CONTRIBUTING.rst | 2 +- README.rst | 2 +- changelog/12874.breaking.rst | 1 + doc/en/backwards-compatibility.rst | 1 + pyproject.toml | 7 +- scripts/generate-gh-release-notes.py | 2 +- scripts/update-plugin-list.py | 4 +- src/_pytest/_code/code.py | 15 ++-- src/_pytest/_code/source.py | 4 +- src/_pytest/_io/pprint.py | 2 +- src/_pytest/_io/terminalwriter.py | 2 +- src/_pytest/assertion/__init__.py | 2 +- src/_pytest/assertion/rewrite.py | 6 +- src/_pytest/assertion/util.py | 6 +- src/_pytest/cacheprovider.py | 4 +- src/_pytest/capture.py | 6 +- src/_pytest/config/__init__.py | 10 +-- src/_pytest/config/argparsing.py | 7 +- src/_pytest/config/compat.py | 2 +- src/_pytest/config/findpaths.py | 4 +- src/_pytest/debugging.py | 2 +- src/_pytest/doctest.py | 8 +- src/_pytest/faulthandler.py | 2 +- src/_pytest/fixtures.py | 24 +++--- src/_pytest/freeze_support.py | 2 +- src/_pytest/helpconfig.py | 2 +- src/_pytest/hookspec.py | 4 +- src/_pytest/junitxml.py | 2 +- src/_pytest/logging.py | 25 +++--- src/_pytest/main.py | 9 +- src/_pytest/mark/__init__.py | 4 +- src/_pytest/mark/expression.py | 6 +- src/_pytest/mark/structures.py | 12 +-- src/_pytest/monkeypatch.py | 6 +- src/_pytest/nodes.py | 6 +- src/_pytest/outcomes.py | 3 +- src/_pytest/pathlib.py | 4 +- src/_pytest/pytester.py | 6 +- src/_pytest/pytester_assertions.py | 2 +- src/_pytest/python.py | 15 ++-- src/_pytest/python_api.py | 10 +-- src/_pytest/recwarn.py | 6 +- src/_pytest/reports.py | 8 +- src/_pytest/setuponly.py | 2 +- src/_pytest/skipping.py | 2 +- src/_pytest/terminal.py | 6 +- src/_pytest/threadexception.py | 2 +- src/_pytest/tmpdir.py | 5 +- src/_pytest/unittest.py | 10 +-- src/_pytest/unraisableexception.py | 2 +- src/_pytest/warnings.py | 2 +- testing/code/test_excinfo.py | 4 +- testing/code/test_source.py | 2 +- testing/conftest.py | 2 +- testing/io/test_terminalwriter.py | 2 +- testing/logging/test_fixture.py | 2 +- testing/python/metafunc.py | 7 +- testing/test_assertion.py | 2 +- testing/test_assertrewrite.py | 4 +- testing/test_cacheprovider.py | 4 +- testing/test_capture.py | 2 +- testing/test_config.py | 2 +- testing/test_conftest.py | 7 +- testing/test_monkeypatch.py | 2 +- testing/test_pathlib.py | 6 +- testing/test_reports.py | 2 +- tox.ini | 9 +- 70 files changed, 230 insertions(+), 226 deletions(-) create mode 100644 changelog/12874.breaking.rst diff --git a/.github/workflows/prepare-release-pr.yml b/.github/workflows/prepare-release-pr.yml index 1bb23fab844..f46b5cecda5 100644 --- a/.github/workflows/prepare-release-pr.yml +++ b/.github/workflows/prepare-release-pr.yml @@ -34,7 +34,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version: "3.x" - name: Install dependencies run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c1ea62f6c8b..30536706afb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,25 +54,24 @@ jobs: fail-fast: false matrix: name: [ - "windows-py38", - "windows-py38-pluggy", - "windows-py39", + "windows-py39-unittestextras", + "windows-py39-pluggy", + "windows-py39-xdist", "windows-py310", "windows-py311", "windows-py312", "windows-py313", - "ubuntu-py38", - "ubuntu-py38-pluggy", - "ubuntu-py38-freeze", - "ubuntu-py39", - "ubuntu-py310", + "ubuntu-py39-lsof-numpy-pexpect", + "ubuntu-py39-pluggy", + "ubuntu-py39-freeze", + "ubuntu-py39-xdist", + "ubuntu-py310-xdist", "ubuntu-py311", "ubuntu-py312", - "ubuntu-py313", - "ubuntu-pypy3", + "ubuntu-py313-pexpect", + "ubuntu-pypy3-xdist", - "macos-py38", "macos-py39", "macos-py310", "macos-py312", @@ -83,106 +82,122 @@ jobs: ] include: - - name: "windows-py38" - python: "3.8" + - name: "windows-py39-unittestextras" + python: "3.9" os: windows-latest - tox_env: "py38-unittestextras" + tox_env: "py39-unittestextras" use_coverage: true - - name: "windows-py38-pluggy" - python: "3.8" + + - name: "windows-py39-pluggy" + python: "3.9" os: windows-latest - tox_env: "py38-pluggymain-pylib-xdist" - - name: "windows-py39" + tox_env: "py39-pluggymain-pylib-xdist" + + - name: "windows-py39-xdist" python: "3.9" os: windows-latest tox_env: "py39-xdist" + - name: "windows-py310" python: "3.10" os: windows-latest tox_env: "py310-xdist" + - name: "windows-py311" python: "3.11" os: windows-latest tox_env: "py311" + - name: "windows-py312" python: "3.12" os: windows-latest tox_env: "py312" + - name: "windows-py313" - python: "3.13-dev" + python: "3.13" os: windows-latest tox_env: "py313" - - name: "ubuntu-py38" - python: "3.8" + + - name: "ubuntu-py39-lsof-numpy-pexpect" + python: "3.9" os: ubuntu-latest - tox_env: "py38-lsof-numpy-pexpect" - use_coverage: true - - name: "ubuntu-py38-pluggy" - python: "3.8" + tox_env: "py39-lsof-numpy-pexpect" + + - name: "ubuntu-py39-pluggy" + python: "3.9" os: ubuntu-latest - tox_env: "py38-pluggymain-pylib-xdist" - - name: "ubuntu-py38-freeze" - python: "3.8" + tox_env: "py39-pluggymain-pylib-xdist" + + - name: "ubuntu-py39-freeze" + python: "3.9" os: ubuntu-latest - tox_env: "py38-freeze" - - name: "ubuntu-py39" + tox_env: "py39-freeze" + + - name: "ubuntu-py39-xdist" python: "3.9" os: ubuntu-latest tox_env: "py39-xdist" - - name: "ubuntu-py310" + + - name: "ubuntu-py310-xdist" python: "3.10" os: ubuntu-latest tox_env: "py310-xdist" + - name: "ubuntu-py311" python: "3.11" os: ubuntu-latest tox_env: "py311" use_coverage: true + - name: "ubuntu-py312" python: "3.12" os: ubuntu-latest tox_env: "py312" use_coverage: true - - name: "ubuntu-py313" - python: "3.13-dev" + + - name: "ubuntu-py313-pexpect" + python: "3.13" os: ubuntu-latest tox_env: "py313-pexpect" use_coverage: true - - name: "ubuntu-pypy3" + + - name: "ubuntu-pypy3-xdist" python: "pypy-3.9" os: ubuntu-latest tox_env: "pypy3-xdist" - - name: "macos-py38" - python: "3.8" - os: macos-latest - tox_env: "py38-xdist" + - name: "macos-py39" python: "3.9" os: macos-latest tox_env: "py39-xdist" use_coverage: true + - name: "macos-py310" python: "3.10" os: macos-latest tox_env: "py310-xdist" + - name: "macos-py312" python: "3.12" os: macos-latest tox_env: "py312-xdist" + - name: "macos-py313" - python: "3.13-dev" + python: "3.13" os: macos-latest tox_env: "py313-xdist" + - name: "plugins" python: "3.12" os: ubuntu-latest tox_env: "plugins" + - name: "doctesting" - python: "3.8" + python: "3.9" os: ubuntu-latest tox_env: "doctesting" use_coverage: true @@ -192,12 +207,12 @@ jobs: contains( fromJSON( '[ - "windows-py38-pluggy", + "windows-py39-pluggy", "windows-py313", - "ubuntu-py38-pluggy", - "ubuntu-py38-freeze", + "ubuntu-py39-pluggy", + "ubuntu-py39-freeze", "ubuntu-py313", - "macos-py38", + "macos-py39", "macos-py313" ]' ), diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e7be8cf6db..cb02fd0f00f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,6 +53,10 @@ repos: rev: v3.19.0 hooks: - id: pyupgrade + args: + - "--py39-plus" + # Manual because ruff does what pyupgrade does and the two are not out of sync + # often enough to make launching pyupgrade everytime worth it stages: [manual] - repo: local hooks: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d615e5fb113..56824a43ff4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -270,7 +270,7 @@ Here is a simple overview, with pytest-specific bits: #. Run all the tests - You need to have Python 3.8 or later available in your system. Now + You need to have Python 3.9 or later available in your system. Now running tests is as simple as issuing this command:: $ tox -e linting,py39 diff --git a/README.rst b/README.rst index a81e082cdd7..091afc363da 100644 --- a/README.rst +++ b/README.rst @@ -97,7 +97,7 @@ Features - Can run `unittest `_ (or trial) test suites out of the box -- Python 3.8+ or PyPy3 +- Python 3.9+ or PyPy3 - Rich plugin architecture, with over 1300+ `external plugins `_ and thriving community diff --git a/changelog/12874.breaking.rst b/changelog/12874.breaking.rst new file mode 100644 index 00000000000..a442586eeb5 --- /dev/null +++ b/changelog/12874.breaking.rst @@ -0,0 +1 @@ +We dropped support for Python 3.8 following its end of life (2024-10-07). diff --git a/doc/en/backwards-compatibility.rst b/doc/en/backwards-compatibility.rst index c0feb833ce1..82f678b4dea 100644 --- a/doc/en/backwards-compatibility.rst +++ b/doc/en/backwards-compatibility.rst @@ -83,6 +83,7 @@ Released pytest versions support all Python versions that are actively maintaine ============== =================== pytest version min. Python version ============== =================== +8.4+ 3.9+ 8.0+ 3.8+ 7.1+ 3.7+ 6.2 - 7.0 3.6+ diff --git a/pyproject.toml b/pyproject.toml index 50fcfc65353..0541da9906e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ authors = [ { name = "Florian Bruhin" }, { name = "Others (See AUTHORS)" }, ] -requires-python = ">=3.8" +requires-python = ">=3.9" classifiers = [ "Development Status :: 6 - Mature", "Intended Audience :: Developers", @@ -33,7 +33,6 @@ classifiers = [ "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -85,7 +84,7 @@ write_to = "src/_pytest/_version.py" [tool.black] target-version = [ - 'py38', + 'py39', ] [tool.ruff] @@ -508,7 +507,7 @@ files = [ mypy_path = [ "src", ] -python_version = "3.8" +python_version = "3.9" check_untyped_defs = true disallow_any_generics = true disallow_untyped_defs = true diff --git a/scripts/generate-gh-release-notes.py b/scripts/generate-gh-release-notes.py index 7f195ba1e0a..b6d92d085e1 100644 --- a/scripts/generate-gh-release-notes.py +++ b/scripts/generate-gh-release-notes.py @@ -11,10 +11,10 @@ from __future__ import annotations +from collections.abc import Sequence from pathlib import Path import re import sys -from typing import Sequence import pypandoc diff --git a/scripts/update-plugin-list.py b/scripts/update-plugin-list.py index 556004d9e98..693a25a00cc 100644 --- a/scripts/update-plugin-list.py +++ b/scripts/update-plugin-list.py @@ -1,14 +1,14 @@ # mypy: disallow-untyped-defs from __future__ import annotations +from collections.abc import Iterable +from collections.abc import Iterator import datetime import pathlib import re from textwrap import dedent from textwrap import indent from typing import Any -from typing import Iterable -from typing import Iterator from typing import TypedDict import packaging.version diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index dd3fd7addb6..ea7415be23e 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -2,6 +2,9 @@ from __future__ import annotations import ast +from collections.abc import Iterable +from collections.abc import Mapping +from collections.abc import Sequence import dataclasses import inspect from inspect import CO_VARARGS @@ -10,6 +13,7 @@ import os from pathlib import Path import re +from re import Pattern import sys import traceback from traceback import format_exception_only @@ -22,16 +26,9 @@ from typing import Final from typing import final from typing import Generic -from typing import Iterable -from typing import List from typing import Literal -from typing import Mapping from typing import overload -from typing import Pattern -from typing import Sequence from typing import SupportsIndex -from typing import Tuple -from typing import Type from typing import TypeVar from typing import Union @@ -56,7 +53,7 @@ TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"] -EXCEPTION_OR_MORE = Union[Type[BaseException], Tuple[Type[BaseException], ...]] +EXCEPTION_OR_MORE = Union[type[BaseException], tuple[type[BaseException], ...]] class Code: @@ -320,7 +317,7 @@ def name(self) -> str: return self.frame.code.raw.co_name -class Traceback(List[TracebackEntry]): +class Traceback(list[TracebackEntry]): """Traceback objects encapsulate and offer higher level access to Traceback entries.""" def __init__( diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index 604aff8ba19..e24ee3a260e 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -3,12 +3,12 @@ import ast from bisect import bisect_right +from collections.abc import Iterable +from collections.abc import Iterator import inspect import textwrap import tokenize import types -from typing import Iterable -from typing import Iterator from typing import overload import warnings diff --git a/src/_pytest/_io/pprint.py b/src/_pytest/_io/pprint.py index 7a6433d9128..d212b773166 100644 --- a/src/_pytest/_io/pprint.py +++ b/src/_pytest/_io/pprint.py @@ -16,6 +16,7 @@ from __future__ import annotations import collections as _collections +from collections.abc import Iterator import dataclasses as _dataclasses from io import StringIO as _StringIO import re @@ -23,7 +24,6 @@ from typing import Any from typing import Callable from typing import IO -from typing import Iterator class _safe_key: diff --git a/src/_pytest/_io/terminalwriter.py b/src/_pytest/_io/terminalwriter.py index 70ebd3d061b..50ce463f6b2 100644 --- a/src/_pytest/_io/terminalwriter.py +++ b/src/_pytest/_io/terminalwriter.py @@ -2,12 +2,12 @@ from __future__ import annotations +from collections.abc import Sequence import os import shutil import sys from typing import final from typing import Literal -from typing import Sequence from typing import TextIO from typing import TYPE_CHECKING diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index cbdf9fa0298..532b96fe431 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -3,9 +3,9 @@ from __future__ import annotations +from collections.abc import Generator import sys from typing import Any -from typing import Generator from typing import TYPE_CHECKING from _pytest.assertion import rewrite diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 37c09b03467..05934797a14 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -4,6 +4,9 @@ import ast from collections import defaultdict +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Sequence import errno import functools import importlib.abc @@ -21,9 +24,6 @@ import types from typing import Callable from typing import IO -from typing import Iterable -from typing import Iterator -from typing import Sequence from typing import TYPE_CHECKING from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 4dc1af4af03..3593f0ce036 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -4,16 +4,16 @@ from __future__ import annotations import collections.abc +from collections.abc import Iterable +from collections.abc import Mapping +from collections.abc import Sequence import os import pprint from typing import AbstractSet from typing import Any from typing import Callable -from typing import Iterable from typing import Literal -from typing import Mapping from typing import Protocol -from typing import Sequence from unicodedata import normalize from _pytest import outcomes diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index 1b236efdc9b..bf643d6f4dc 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -5,6 +5,8 @@ # pytest-cache version. from __future__ import annotations +from collections.abc import Generator +from collections.abc import Iterable import dataclasses import errno import json @@ -12,8 +14,6 @@ from pathlib import Path import tempfile from typing import final -from typing import Generator -from typing import Iterable from .pathlib import resolve_from_str from .pathlib import rm_rf diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 2ac3b6bbc7f..93a3b04182e 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -5,6 +5,9 @@ import abc import collections +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Iterator import contextlib import io from io import UnsupportedOperation @@ -18,10 +21,7 @@ from typing import cast from typing import Final from typing import final -from typing import Generator from typing import Generic -from typing import Iterable -from typing import Iterator from typing import Literal from typing import NamedTuple from typing import TextIO diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 92cf565e85f..5ec4d7b52ea 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -5,6 +5,10 @@ import argparse import collections.abc +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Sequence import contextlib import copy import dataclasses @@ -26,11 +30,7 @@ from typing import cast from typing import Final from typing import final -from typing import Generator from typing import IO -from typing import Iterable -from typing import Iterator -from typing import Sequence from typing import TextIO from typing import Type from typing import TYPE_CHECKING @@ -1978,7 +1978,7 @@ def _resolve_warning_category(category: str) -> type[Warning]: cat = getattr(m, klass) if not issubclass(cat, Warning): raise UsageError(f"{cat} is not a Warning subclass") - return cast(Type[Warning], cat) + return cast(type[Warning], cat) def apply_warning_filters( diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index 85aa4632702..455d2d8db26 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -2,6 +2,8 @@ from __future__ import annotations import argparse +from collections.abc import Mapping +from collections.abc import Sequence from gettext import gettext import os import sys @@ -9,11 +11,8 @@ from typing import Callable from typing import cast from typing import final -from typing import List from typing import Literal -from typing import Mapping from typing import NoReturn -from typing import Sequence import _pytest._io from _pytest.config.exceptions import UsageError @@ -144,7 +143,7 @@ def parse_setoption( parsedoption = self.parse(args, namespace=namespace) for name, value in parsedoption.__dict__.items(): setattr(option, name, value) - return cast(List[str], getattr(parsedoption, FILE_OR_DIR)) + return cast(list[str], getattr(parsedoption, FILE_OR_DIR)) def parse_known_args( self, diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index 2856d85d195..21eab4c7e47 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,9 +1,9 @@ from __future__ import annotations +from collections.abc import Mapping import functools from pathlib import Path from typing import Any -from typing import Mapping import warnings import pluggy diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py index ce4c990b810..a7f45bf593e 100644 --- a/src/_pytest/config/findpaths.py +++ b/src/_pytest/config/findpaths.py @@ -1,10 +1,10 @@ from __future__ import annotations +from collections.abc import Iterable +from collections.abc import Sequence import os from pathlib import Path import sys -from typing import Iterable -from typing import Sequence import iniconfig diff --git a/src/_pytest/debugging.py b/src/_pytest/debugging.py index 763606cd60e..665d8536262 100644 --- a/src/_pytest/debugging.py +++ b/src/_pytest/debugging.py @@ -5,12 +5,12 @@ from __future__ import annotations import argparse +from collections.abc import Generator import functools import sys import types from typing import Any from typing import Callable -from typing import Generator import unittest from _pytest import outcomes diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index 384dea976ad..a1f680570d8 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -4,21 +4,21 @@ from __future__ import annotations import bdb +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Sequence from contextlib import contextmanager import functools import inspect import os from pathlib import Path import platform +from re import Pattern import sys import traceback import types from typing import Any from typing import Callable -from typing import Generator -from typing import Iterable -from typing import Pattern -from typing import Sequence from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/faulthandler.py b/src/_pytest/faulthandler.py index d16aea1eb88..79efc1d1704 100644 --- a/src/_pytest/faulthandler.py +++ b/src/_pytest/faulthandler.py @@ -1,8 +1,8 @@ from __future__ import annotations +from collections.abc import Generator import os import sys -from typing import Generator from _pytest.config import Config from _pytest.config.argparsing import Parser diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 5817e88f47d..c4a8a09f84a 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -4,6 +4,13 @@ import abc from collections import defaultdict from collections import deque +from collections import OrderedDict +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Mapping +from collections.abc import MutableMapping +from collections.abc import Sequence import dataclasses import functools import inspect @@ -15,21 +22,12 @@ from typing import Any from typing import Callable from typing import cast -from typing import Dict from typing import Final from typing import final -from typing import Generator from typing import Generic -from typing import Iterable -from typing import Iterator -from typing import Mapping -from typing import MutableMapping from typing import NoReturn from typing import Optional -from typing import OrderedDict from typing import overload -from typing import Sequence -from typing import Tuple from typing import TYPE_CHECKING from typing import TypeVar from typing import Union @@ -95,19 +93,19 @@ ] # The type of FixtureDef.cached_result (type alias generic in fixture value). _FixtureCachedResult = Union[ - Tuple[ + tuple[ # The result. FixtureValue, # Cache key. object, None, ], - Tuple[ + tuple[ None, # Cache key. object, # The exception and the original traceback. - Tuple[BaseException, Optional[types.TracebackType]], + tuple[BaseException, Optional[types.TracebackType]], ], ] @@ -177,7 +175,7 @@ class FixtureArgKey: _V = TypeVar("_V") -OrderedSet = Dict[_V, None] +OrderedSet = dict[_V, None] def get_parametrized_fixture_argkeys( diff --git a/src/_pytest/freeze_support.py b/src/_pytest/freeze_support.py index 2ba6f9b8bcc..959ff071d86 100644 --- a/src/_pytest/freeze_support.py +++ b/src/_pytest/freeze_support.py @@ -3,8 +3,8 @@ from __future__ import annotations +from collections.abc import Iterator import types -from typing import Iterator def freeze_includes() -> list[str]: diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index 1886d5c9342..3d607189dbe 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -4,9 +4,9 @@ from __future__ import annotations from argparse import Action +from collections.abc import Generator import os import sys -from typing import Generator from _pytest.config import Config from _pytest.config import ExitCode diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index 0a41b0aca47..8b20061d6f0 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -5,10 +5,10 @@ from __future__ import annotations +from collections.abc import Mapping +from collections.abc import Sequence from pathlib import Path from typing import Any -from typing import Mapping -from typing import Sequence from typing import TYPE_CHECKING from pluggy import HookspecMarker diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index efe6f489b48..46c456a5b6e 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -16,8 +16,8 @@ import os import platform import re +from re import Match from typing import Callable -from typing import Match import xml.etree.ElementTree as ET from _pytest import nodes diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 08c826ff6d4..00645dae2da 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -3,6 +3,8 @@ from __future__ import annotations +from collections.abc import Generator +from collections.abc import Mapping from contextlib import contextmanager from contextlib import nullcontext from datetime import datetime @@ -17,13 +19,9 @@ import re from types import TracebackType from typing import AbstractSet -from typing import Dict from typing import final -from typing import Generator from typing import Generic -from typing import List from typing import Literal -from typing import Mapping from typing import TYPE_CHECKING from typing import TypeVar @@ -53,7 +51,7 @@ DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S" _ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m") caplog_handler_key = StashKey["LogCaptureHandler"]() -caplog_records_key = StashKey[Dict[str, List[logging.LogRecord]]]() +caplog_records_key = StashKey[dict[str, list[logging.LogRecord]]]() def _remove_ansi_escape_sequences(text: str) -> str: @@ -813,13 +811,16 @@ def pytest_runtest_logreport(self) -> None: def _runtest_for(self, item: nodes.Item, when: str) -> Generator[None]: """Implement the internals of the pytest_runtest_xxx() hooks.""" - with catching_logs( - self.caplog_handler, - level=self.log_level, - ) as caplog_handler, catching_logs( - self.report_handler, - level=self.log_level, - ) as report_handler: + with ( + catching_logs( + self.caplog_handler, + level=self.log_level, + ) as caplog_handler, + catching_logs( + self.report_handler, + level=self.log_level, + ) as report_handler, + ): caplog_handler.reset() report_handler.reset() item.stash[caplog_records_key][when] = caplog_handler.records diff --git a/src/_pytest/main.py b/src/_pytest/main.py index e5534e98d69..1e18a60141d 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -3,6 +3,9 @@ from __future__ import annotations import argparse +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Sequence import dataclasses import fnmatch import functools @@ -13,13 +16,9 @@ import sys from typing import AbstractSet from typing import Callable -from typing import Dict from typing import final -from typing import Iterable -from typing import Iterator from typing import Literal from typing import overload -from typing import Sequence from typing import TYPE_CHECKING import warnings @@ -476,7 +475,7 @@ class Failed(Exception): @dataclasses.dataclass -class _bestrelpath_cache(Dict[Path, str]): +class _bestrelpath_cache(dict[Path, str]): __slots__ = ("path",) path: Path diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index a6f0155751a..c8c51d19aa0 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -3,10 +3,10 @@ from __future__ import annotations import collections +from collections.abc import Collection +from collections.abc import Iterable import dataclasses from typing import AbstractSet -from typing import Collection -from typing import Iterable from typing import Optional from typing import TYPE_CHECKING diff --git a/src/_pytest/mark/expression.py b/src/_pytest/mark/expression.py index 89cc0e94d3b..d0ab190e3b6 100644 --- a/src/_pytest/mark/expression.py +++ b/src/_pytest/mark/expression.py @@ -23,18 +23,18 @@ from __future__ import annotations import ast +from collections.abc import Iterator +from collections.abc import Mapping +from collections.abc import Sequence import dataclasses import enum import keyword import re import types -from typing import Iterator from typing import Literal -from typing import Mapping from typing import NoReturn from typing import overload from typing import Protocol -from typing import Sequence __all__ = [ diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 14650a64759..09ef7d02cef 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -2,19 +2,19 @@ from __future__ import annotations import collections.abc +from collections.abc import Collection +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Mapping +from collections.abc import MutableMapping +from collections.abc import Sequence import dataclasses import inspect from typing import Any from typing import Callable -from typing import Collection from typing import final -from typing import Iterable -from typing import Iterator -from typing import Mapping -from typing import MutableMapping from typing import NamedTuple from typing import overload -from typing import Sequence from typing import TYPE_CHECKING from typing import TypeVar from typing import Union diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index 46eb1724e35..1285e571551 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -3,15 +3,15 @@ from __future__ import annotations +from collections.abc import Generator +from collections.abc import Mapping +from collections.abc import MutableMapping from contextlib import contextmanager import os import re import sys from typing import Any from typing import final -from typing import Generator -from typing import Mapping -from typing import MutableMapping from typing import overload from typing import TypeVar import warnings diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 51bc5174628..e84fb37c9d0 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -2,6 +2,9 @@ from __future__ import annotations import abc +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import MutableMapping from functools import cached_property from inspect import signature import os @@ -10,9 +13,6 @@ from typing import Any from typing import Callable from typing import cast -from typing import Iterable -from typing import Iterator -from typing import MutableMapping from typing import NoReturn from typing import overload from typing import TYPE_CHECKING diff --git a/src/_pytest/outcomes.py b/src/_pytest/outcomes.py index 5b20803e586..ab39bac61b9 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -9,7 +9,6 @@ from typing import cast from typing import NoReturn from typing import Protocol -from typing import Type from typing import TypeVar from .warning_types import PytestDeprecationWarning @@ -82,7 +81,7 @@ def __init__( # Ideally would just be `exit.Exception = Exit` etc. _F = TypeVar("_F", bound=Callable[..., object]) -_ET = TypeVar("_ET", bound=Type[BaseException]) +_ET = TypeVar("_ET", bound=type[BaseException]) class _WithException(Protocol[_F, _ET]): diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index dd36559ce1b..f6392561951 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -1,6 +1,8 @@ from __future__ import annotations import atexit +from collections.abc import Iterable +from collections.abc import Iterator import contextlib from enum import Enum from errno import EBADF @@ -27,8 +29,6 @@ from types import ModuleType from typing import Any from typing import Callable -from typing import Iterable -from typing import Iterator from typing import TypeVar import uuid import warnings diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 3f7520ee4ad..d19151391b0 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -7,6 +7,9 @@ from __future__ import annotations import collections.abc +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Sequence import contextlib from fnmatch import fnmatch import gc @@ -25,12 +28,9 @@ from typing import Callable from typing import Final from typing import final -from typing import Generator from typing import IO -from typing import Iterable from typing import Literal from typing import overload -from typing import Sequence from typing import TextIO from typing import TYPE_CHECKING from weakref import WeakKeyDictionary diff --git a/src/_pytest/pytester_assertions.py b/src/_pytest/pytester_assertions.py index d543798f75a..915cc8a10ff 100644 --- a/src/_pytest/pytester_assertions.py +++ b/src/_pytest/pytester_assertions.py @@ -6,7 +6,7 @@ # module to not be already imported. from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from _pytest.reports import CollectReport from _pytest.reports import TestReport diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 1456b5212d4..153fbf8893b 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -6,6 +6,11 @@ import abc from collections import Counter from collections import defaultdict +from collections.abc import Generator +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Mapping +from collections.abc import Sequence import dataclasses import enum import fnmatch @@ -14,18 +19,12 @@ import itertools import os from pathlib import Path +from re import Pattern import types from typing import Any from typing import Callable -from typing import Dict from typing import final -from typing import Generator -from typing import Iterable -from typing import Iterator from typing import Literal -from typing import Mapping -from typing import Pattern -from typing import Sequence from typing import TYPE_CHECKING import warnings @@ -1078,7 +1077,7 @@ def get_direct_param_fixture_func(request: FixtureRequest) -> Any: # Used for storing pseudo fixturedefs for direct parametrization. -name2pseudofixturedef_key = StashKey[Dict[str, FixtureDef[Any]]]() +name2pseudofixturedef_key = StashKey[dict[str, FixtureDef[Any]]]() @final diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index d2107c2fc78..30a630c42ff 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -2,24 +2,22 @@ from __future__ import annotations from collections.abc import Collection +from collections.abc import Mapping +from collections.abc import Sequence from collections.abc import Sized from decimal import Decimal import math from numbers import Complex import pprint import re +from re import Pattern from types import TracebackType from typing import Any from typing import Callable from typing import cast from typing import ContextManager from typing import final -from typing import Mapping from typing import overload -from typing import Pattern -from typing import Sequence -from typing import Tuple -from typing import Type from typing import TYPE_CHECKING from typing import TypeVar @@ -1017,7 +1015,7 @@ def __exit__( if not issubclass(exc_type, self.expected_exception): return False # Cast to narrow the exception type now that it's verified. - exc_info = cast(Tuple[Type[E], E, TracebackType], (exc_type, exc_val, exc_tb)) + exc_info = cast(tuple[type[E], E, TracebackType], (exc_type, exc_val, exc_tb)) self.excinfo.fill_unfilled(exc_info) if self.match_expr is not None: self.excinfo.match(self.match_expr) diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 0dc002edd94..fc26fcc78e4 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -3,16 +3,16 @@ from __future__ import annotations +from collections.abc import Generator +from collections.abc import Iterator from pprint import pformat import re +from re import Pattern from types import TracebackType from typing import Any from typing import Callable from typing import final -from typing import Generator -from typing import Iterator from typing import overload -from typing import Pattern from typing import TYPE_CHECKING from typing import TypeVar diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py index 77cbf773e23..4d926ef6c9e 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -1,6 +1,10 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Mapping +from collections.abc import Sequence import dataclasses from io import StringIO import os @@ -8,12 +12,8 @@ from typing import Any from typing import cast from typing import final -from typing import Iterable -from typing import Iterator from typing import Literal -from typing import Mapping from typing import NoReturn -from typing import Sequence from typing import TYPE_CHECKING from _pytest._code.code import ExceptionChainRepr diff --git a/src/_pytest/setuponly.py b/src/_pytest/setuponly.py index de297f408d3..1e887a896f5 100644 --- a/src/_pytest/setuponly.py +++ b/src/_pytest/setuponly.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generator +from collections.abc import Generator from _pytest._io.saferepr import saferepr from _pytest.config import Config diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index 9818be2ab03..8fa17a01eb0 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -3,13 +3,13 @@ from __future__ import annotations +from collections.abc import Generator from collections.abc import Mapping import dataclasses import os import platform import sys import traceback -from typing import Generator from typing import Optional from _pytest.config import Config diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 55ef1ea8eee..d2baee40d9c 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -8,6 +8,9 @@ import argparse from collections import Counter +from collections.abc import Generator +from collections.abc import Mapping +from collections.abc import Sequence import dataclasses import datetime from functools import partial @@ -20,11 +23,8 @@ from typing import Callable from typing import ClassVar from typing import final -from typing import Generator from typing import Literal -from typing import Mapping from typing import NamedTuple -from typing import Sequence from typing import TextIO from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/threadexception.py b/src/_pytest/threadexception.py index c1ed80387aa..49560bf7d7f 100644 --- a/src/_pytest/threadexception.py +++ b/src/_pytest/threadexception.py @@ -1,11 +1,11 @@ from __future__ import annotations +from collections.abc import Generator import threading import traceback from types import TracebackType from typing import Any from typing import Callable -from typing import Generator from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 1731a4b8d0d..c5b51c87741 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -3,6 +3,7 @@ from __future__ import annotations +from collections.abc import Generator import dataclasses import os from pathlib import Path @@ -10,9 +11,7 @@ from shutil import rmtree import tempfile from typing import Any -from typing import Dict from typing import final -from typing import Generator from typing import Literal from .pathlib import cleanup_dead_symlinks @@ -34,7 +33,7 @@ from _pytest.stash import StashKey -tmppath_result_key = StashKey[Dict[str, bool]]() +tmppath_result_key = StashKey[dict[str, bool]]() RetentionType = Literal["all", "failed", "none"] diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index 8cecd4f9339..6d967b972ee 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -3,16 +3,14 @@ from __future__ import annotations +from collections.abc import Generator +from collections.abc import Iterable import inspect import sys import traceback import types from typing import Any from typing import Callable -from typing import Generator -from typing import Iterable -from typing import Tuple -from typing import Type from typing import TYPE_CHECKING from typing import Union @@ -43,8 +41,8 @@ _SysExcInfoType = Union[ - Tuple[Type[BaseException], BaseException, types.TracebackType], - Tuple[None, None, None], + tuple[type[BaseException], BaseException, types.TracebackType], + tuple[None, None, None], ] diff --git a/src/_pytest/unraisableexception.py b/src/_pytest/unraisableexception.py index 77a2de20041..9ef583137e1 100644 --- a/src/_pytest/unraisableexception.py +++ b/src/_pytest/unraisableexception.py @@ -1,11 +1,11 @@ from __future__ import annotations +from collections.abc import Generator import sys import traceback from types import TracebackType from typing import Any from typing import Callable -from typing import Generator from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index eeb4772649d..87cdbda288f 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -1,9 +1,9 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator from contextlib import contextmanager import sys -from typing import Generator from typing import Literal import warnings diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index ab56904d040..22e695977e1 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -964,8 +964,8 @@ def raiseos(): upframe = sys._getframe().f_back assert upframe is not None if upframe.f_code.co_name == "_makepath": - # Only raise with expected calls, but not via e.g. inspect for - # py38-windows. + # Only raise with expected calls, and not accidentally via 'inspect' + # See 79ae86cc3f76d69460e1c7beca4ce95e68ab80a6 raised += 1 raise OSError(2, "custom_oserror") return orig_path_cwd() diff --git a/testing/code/test_source.py b/testing/code/test_source.py index a00259976c4..d78d9e7025a 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -336,7 +336,7 @@ def test_findsource(monkeypatch) -> None: assert src is not None assert "if 1:" in str(src) - d: Dict[str, Any] = {} + d: dict[str, Any] = {} eval(co, d) src, lineno = findsource(d["x"]) assert src is not None diff --git a/testing/conftest.py b/testing/conftest.py index 69af03324d6..110ad0d9b35 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,10 +1,10 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator import dataclasses import re import sys -from typing import Generator from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester diff --git a/testing/io/test_terminalwriter.py b/testing/io/test_terminalwriter.py index 92cde240a11..f14e884b1f0 100644 --- a/testing/io/test_terminalwriter.py +++ b/testing/io/test_terminalwriter.py @@ -1,13 +1,13 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator import io import os from pathlib import Path import re import shutil import sys -from typing import Generator from unittest import mock from _pytest._io import terminalwriter diff --git a/testing/logging/test_fixture.py b/testing/logging/test_fixture.py index 0603eaba218..5f94cb8508a 100644 --- a/testing/logging/test_fixture.py +++ b/testing/logging/test_fixture.py @@ -2,8 +2,8 @@ # mypy: disallow-untyped-defs from __future__ import annotations +from collections.abc import Iterator import logging -from typing import Iterator from _pytest.logging import caplog_records_key from _pytest.pytester import Pytester diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 0a4ebf2c9af..df6dbaee0fd 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -1,6 +1,8 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Iterator +from collections.abc import Sequence import dataclasses import itertools import re @@ -8,9 +10,6 @@ import textwrap from typing import Any from typing import cast -from typing import Dict -from typing import Iterator -from typing import Sequence import hypothesis from hypothesis import strategies @@ -154,7 +153,7 @@ class DummyFixtureDef: _scope: Scope fixtures_defs = cast( - Dict[str, Sequence[fixtures.FixtureDef[object]]], + dict[str, Sequence[fixtures.FixtureDef[object]]], dict( session_fix=[DummyFixtureDef(Scope.Session)], package_fix=[DummyFixtureDef(Scope.Package)], diff --git a/testing/test_assertion.py b/testing/test_assertion.py index b10ca1c91f4..a14c4125cf6 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -1,10 +1,10 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import MutableSequence import sys import textwrap from typing import Any -from typing import MutableSequence from typing import NamedTuple import attr diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 7be473d897a..2a988149daf 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -2,6 +2,8 @@ from __future__ import annotations import ast +from collections.abc import Generator +from collections.abc import Mapping import dis import errno from functools import partial @@ -17,8 +19,6 @@ import sys import textwrap from typing import cast -from typing import Generator -from typing import Mapping from unittest import mock import zipfile diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index 94bc55d3047..1ba4659d84e 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -1,13 +1,13 @@ from __future__ import annotations +from collections.abc import Generator +from collections.abc import Sequence from enum import auto from enum import Enum import os from pathlib import Path import shutil from typing import Any -from typing import Generator -from typing import Sequence from _pytest.compat import assert_never from _pytest.config import ExitCode diff --git a/testing/test_capture.py b/testing/test_capture.py index 328de740e8a..98986af6f1f 100644 --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,6 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator import contextlib import io from io import UnsupportedOperation @@ -10,7 +11,6 @@ import textwrap from typing import BinaryIO from typing import cast -from typing import Generator from typing import TextIO from _pytest import capture diff --git a/testing/test_config.py b/testing/test_config.py index b2825678b46..53f26269f09 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1,6 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Sequence import dataclasses import importlib.metadata import os @@ -9,7 +10,6 @@ import sys import textwrap from typing import Any -from typing import Sequence import _pytest._code from _pytest.config import _get_plugin_specs_as_list diff --git a/testing/test_conftest.py b/testing/test_conftest.py index ea60c1909c2..bbb1d301ebe 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -1,13 +1,12 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator +from collections.abc import Sequence import os from pathlib import Path import textwrap from typing import cast -from typing import Generator -from typing import List -from typing import Sequence from _pytest.config import ExitCode from _pytest.config import PytestPluginManager @@ -459,7 +458,7 @@ def impct(p, importmode, root, consider_namespace_packages): rootpath=pytester.path, consider_namespace_packages=False, ) - mods = cast(List[Path], conftest._getconftestmodules(sub)) + mods = cast(list[Path], conftest._getconftestmodules(sub)) expected = [ct1, ct2] assert mods == expected diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index 7c62d90f2b9..ad75273d703 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -1,12 +1,12 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator import os from pathlib import Path import re import sys import textwrap -from typing import Generator from _pytest.monkeypatch import MonkeyPatch from _pytest.pytester import Pytester diff --git a/testing/test_pathlib.py b/testing/test_pathlib.py index 62359303f3b..436a6b9cae3 100644 --- a/testing/test_pathlib.py +++ b/testing/test_pathlib.py @@ -1,6 +1,9 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Generator +from collections.abc import Iterator +from collections.abc import Sequence import errno import importlib.abc import importlib.machinery @@ -12,9 +15,6 @@ from textwrap import dedent from types import ModuleType from typing import Any -from typing import Generator -from typing import Iterator -from typing import Sequence import unittest.mock from _pytest.config import ExitCode diff --git a/testing/test_reports.py b/testing/test_reports.py index 3e314d2aade..7a893981838 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -1,7 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations -from typing import Sequence +from collections.abc import Sequence from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionRepr diff --git a/tox.ini b/tox.ini index 61563ca2c5f..80fae513142 100644 --- a/tox.ini +++ b/tox.ini @@ -4,18 +4,17 @@ minversion = 3.20.0 distshare = {homedir}/.tox/distshare envlist = linting - py38 py39 py310 py311 py312 py313 pypy3 - py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib} + py39-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib} doctesting doctesting-coverage plugins - py38-freeze + py39-freeze docs docs-checklinks @@ -58,7 +57,7 @@ setenv = PYTHONWARNDEFAULTENCODING=1 # Configuration to run with coverage similar to CI, e.g. - # "tox -e py38-coverage". + # "tox -e py39-coverage". coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess coverage: COVERAGE_FILE={toxinidir}/.coverage @@ -178,7 +177,7 @@ commands = pytest pytest_twisted_integration.py pytest simple_integration.py --force-sugar --flakes -[testenv:py38-freeze] +[testenv:py39-freeze] description = test pytest frozen with `pyinstaller` under `{basepython}` changedir = testing/freeze From 05ed0d0f943ce25b635e92e4e166524435386018 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 10 Nov 2024 15:43:08 +0100 Subject: [PATCH 2/9] Enable pylint's python 3.8 typing checks (deprecated-typing-alias) --- pyproject.toml | 1 - src/_pytest/_code/code.py | 2 +- src/_pytest/_io/pprint.py | 2 +- src/_pytest/_py/error.py | 2 +- src/_pytest/_py/path.py | 2 +- src/_pytest/assertion/rewrite.py | 2 +- src/_pytest/assertion/util.py | 2 +- src/_pytest/compat.py | 2 +- src/_pytest/config/__init__.py | 2 +- src/_pytest/config/argparsing.py | 2 +- src/_pytest/debugging.py | 2 +- src/_pytest/doctest.py | 2 +- src/_pytest/fixtures.py | 8 +++----- src/_pytest/junitxml.py | 2 +- src/_pytest/main.py | 2 +- src/_pytest/mark/structures.py | 2 +- src/_pytest/nodes.py | 2 +- src/_pytest/outcomes.py | 2 +- src/_pytest/pathlib.py | 2 +- src/_pytest/pytester.py | 2 +- src/_pytest/python.py | 2 +- src/_pytest/python_api.py | 2 +- src/_pytest/recwarn.py | 2 +- src/_pytest/runner.py | 2 +- src/_pytest/terminal.py | 2 +- src/_pytest/threadexception.py | 2 +- src/_pytest/unittest.py | 2 +- src/_pytest/unraisableexception.py | 2 +- testing/test_doctest.py | 2 +- testing/test_mark_expression.py | 2 +- testing/test_tmpdir.py | 2 +- 31 files changed, 32 insertions(+), 35 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0541da9906e..6856e652829 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -229,7 +229,6 @@ disable = [ "deprecated-argument", "deprecated-attribute", "deprecated-class", - "deprecated-typing-alias", "disallowed-name", # foo / bar are used often in tests "duplicate-code", "else-if-used", # not activated by default, PLR5501 disabled in ruff diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index ea7415be23e..14ac545490f 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -2,6 +2,7 @@ from __future__ import annotations import ast +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Mapping from collections.abc import Sequence @@ -21,7 +22,6 @@ from types import FrameType from types import TracebackType from typing import Any -from typing import Callable from typing import ClassVar from typing import Final from typing import final diff --git a/src/_pytest/_io/pprint.py b/src/_pytest/_io/pprint.py index d212b773166..ca780c41344 100644 --- a/src/_pytest/_io/pprint.py +++ b/src/_pytest/_io/pprint.py @@ -16,13 +16,13 @@ from __future__ import annotations import collections as _collections +from collections.abc import Callable from collections.abc import Iterator import dataclasses as _dataclasses from io import StringIO as _StringIO import re import types as _types from typing import Any -from typing import Callable from typing import IO diff --git a/src/_pytest/_py/error.py b/src/_pytest/_py/error.py index ab3a4ed318e..3a63304008a 100644 --- a/src/_pytest/_py/error.py +++ b/src/_pytest/_py/error.py @@ -2,10 +2,10 @@ from __future__ import annotations +from collections.abc import Callable import errno import os import sys -from typing import Callable from typing import TYPE_CHECKING from typing import TypeVar diff --git a/src/_pytest/_py/path.py b/src/_pytest/_py/path.py index c7ab1182f4a..e353c1a9b52 100644 --- a/src/_pytest/_py/path.py +++ b/src/_pytest/_py/path.py @@ -4,6 +4,7 @@ from __future__ import annotations import atexit +from collections.abc import Callable from contextlib import contextmanager import fnmatch import importlib.util @@ -23,7 +24,6 @@ from stat import S_ISREG import sys from typing import Any -from typing import Callable from typing import cast from typing import Literal from typing import overload diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 05934797a14..93a08a4e69f 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -4,6 +4,7 @@ import ast from collections import defaultdict +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Iterator from collections.abc import Sequence @@ -22,7 +23,6 @@ import sys import tokenize import types -from typing import Callable from typing import IO from typing import TYPE_CHECKING diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 3593f0ce036..49e977171b9 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -4,6 +4,7 @@ from __future__ import annotations import collections.abc +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Mapping from collections.abc import Sequence @@ -11,7 +12,6 @@ import pprint from typing import AbstractSet from typing import Any -from typing import Callable from typing import Literal from typing import Protocol from unicodedata import normalize diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 82aea5e635e..2f7413d466a 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -3,6 +3,7 @@ from __future__ import annotations +from collections.abc import Callable import dataclasses import enum import functools @@ -13,7 +14,6 @@ from pathlib import Path import sys from typing import Any -from typing import Callable from typing import Final from typing import NoReturn diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 5ec4d7b52ea..fb012d081e1 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -5,6 +5,7 @@ import argparse import collections.abc +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Iterator @@ -26,7 +27,6 @@ import types from types import FunctionType from typing import Any -from typing import Callable from typing import cast from typing import Final from typing import final diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index 455d2d8db26..5a4e2e7993e 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -2,13 +2,13 @@ from __future__ import annotations import argparse +from collections.abc import Callable from collections.abc import Mapping from collections.abc import Sequence from gettext import gettext import os import sys from typing import Any -from typing import Callable from typing import cast from typing import final from typing import Literal diff --git a/src/_pytest/debugging.py b/src/_pytest/debugging.py index 665d8536262..a9886c29d3c 100644 --- a/src/_pytest/debugging.py +++ b/src/_pytest/debugging.py @@ -5,12 +5,12 @@ from __future__ import annotations import argparse +from collections.abc import Callable from collections.abc import Generator import functools import sys import types from typing import Any -from typing import Callable import unittest from _pytest import outcomes diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index a1f680570d8..94868d06106 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -4,6 +4,7 @@ from __future__ import annotations import bdb +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Sequence @@ -18,7 +19,6 @@ import traceback import types from typing import Any -from typing import Callable from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index c4a8a09f84a..80c4ec962b8 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -5,6 +5,7 @@ from collections import defaultdict from collections import deque from collections import OrderedDict +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Iterator @@ -20,7 +21,6 @@ import types from typing import AbstractSet from typing import Any -from typing import Callable from typing import cast from typing import Final from typing import final @@ -89,7 +89,7 @@ FixtureFunction = TypeVar("FixtureFunction", bound=Callable[..., object]) # The type of a fixture function (type alias generic in fixture value). _FixtureFunc = Union[ - Callable[..., FixtureValue], Callable[..., Generator[FixtureValue, None, None]] + Callable[..., FixtureValue], Callable[..., Generator[FixtureValue]] ] # The type of FixtureDef.cached_result (type alias generic in fixture value). _FixtureCachedResult = Union[ @@ -891,9 +891,7 @@ def call_fixture_func( fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs ) -> FixtureValue: if inspect.isgeneratorfunction(fixturefunc): - fixturefunc = cast( - Callable[..., Generator[FixtureValue, None, None]], fixturefunc - ) + fixturefunc = cast(Callable[..., Generator[FixtureValue]], fixturefunc) generator = fixturefunc(**kwargs) try: fixture_result = next(generator) diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 46c456a5b6e..af072f0d1a4 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -10,6 +10,7 @@ from __future__ import annotations +from collections.abc import Callable from datetime import datetime from datetime import timezone import functools @@ -17,7 +18,6 @@ import platform import re from re import Match -from typing import Callable import xml.etree.ElementTree as ET from _pytest import nodes diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 1e18a60141d..ebd94c84c76 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Iterator from collections.abc import Sequence @@ -15,7 +16,6 @@ from pathlib import Path import sys from typing import AbstractSet -from typing import Callable from typing import final from typing import Literal from typing import overload diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 09ef7d02cef..d1e0a49b62d 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -2,6 +2,7 @@ from __future__ import annotations import collections.abc +from collections.abc import Callable from collections.abc import Collection from collections.abc import Iterable from collections.abc import Iterator @@ -11,7 +12,6 @@ import dataclasses import inspect from typing import Any -from typing import Callable from typing import final from typing import NamedTuple from typing import overload diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index e84fb37c9d0..5b50fbc92cb 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -2,6 +2,7 @@ from __future__ import annotations import abc +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Iterator from collections.abc import MutableMapping @@ -11,7 +12,6 @@ import pathlib from pathlib import Path from typing import Any -from typing import Callable from typing import cast from typing import NoReturn from typing import overload diff --git a/src/_pytest/outcomes.py b/src/_pytest/outcomes.py index ab39bac61b9..d792382a9c1 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -3,9 +3,9 @@ from __future__ import annotations +from collections.abc import Callable import sys from typing import Any -from typing import Callable from typing import cast from typing import NoReturn from typing import Protocol diff --git a/src/_pytest/pathlib.py b/src/_pytest/pathlib.py index f6392561951..55b27985d31 100644 --- a/src/_pytest/pathlib.py +++ b/src/_pytest/pathlib.py @@ -1,6 +1,7 @@ from __future__ import annotations import atexit +from collections.abc import Callable from collections.abc import Iterable from collections.abc import Iterator import contextlib @@ -28,7 +29,6 @@ import types from types import ModuleType from typing import Any -from typing import Callable from typing import TypeVar import uuid import warnings diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index d19151391b0..056be52a4ed 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -7,6 +7,7 @@ from __future__ import annotations import collections.abc +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Sequence @@ -25,7 +26,6 @@ import sys import traceback from typing import Any -from typing import Callable from typing import Final from typing import final from typing import IO diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 153fbf8893b..3a42b43d0a1 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -6,6 +6,7 @@ import abc from collections import Counter from collections import defaultdict +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable from collections.abc import Iterator @@ -22,7 +23,6 @@ from re import Pattern import types from typing import Any -from typing import Callable from typing import final from typing import Literal from typing import TYPE_CHECKING diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 30a630c42ff..aae0bd50ce0 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -1,6 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Callable from collections.abc import Collection from collections.abc import Mapping from collections.abc import Sequence @@ -13,7 +14,6 @@ from re import Pattern from types import TracebackType from typing import Any -from typing import Callable from typing import cast from typing import ContextManager from typing import final diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index fc26fcc78e4..b168bbe746d 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -3,6 +3,7 @@ from __future__ import annotations +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterator from pprint import pformat @@ -10,7 +11,6 @@ from re import Pattern from types import TracebackType from typing import Any -from typing import Callable from typing import final from typing import overload from typing import TYPE_CHECKING diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index 0b60301bf5f..5189efce538 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -4,11 +4,11 @@ from __future__ import annotations import bdb +from collections.abc import Callable import dataclasses import os import sys import types -from typing import Callable from typing import cast from typing import final from typing import Generic diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index d2baee40d9c..a74f73bff17 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -8,6 +8,7 @@ import argparse from collections import Counter +from collections.abc import Callable from collections.abc import Generator from collections.abc import Mapping from collections.abc import Sequence @@ -20,7 +21,6 @@ import sys import textwrap from typing import Any -from typing import Callable from typing import ClassVar from typing import final from typing import Literal diff --git a/src/_pytest/threadexception.py b/src/_pytest/threadexception.py index 49560bf7d7f..4a76a9d9000 100644 --- a/src/_pytest/threadexception.py +++ b/src/_pytest/threadexception.py @@ -1,11 +1,11 @@ from __future__ import annotations +from collections.abc import Callable from collections.abc import Generator import threading import traceback from types import TracebackType from typing import Any -from typing import Callable from typing import TYPE_CHECKING import warnings diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index 6d967b972ee..04d50b53090 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -3,6 +3,7 @@ from __future__ import annotations +from collections.abc import Callable from collections.abc import Generator from collections.abc import Iterable import inspect @@ -10,7 +11,6 @@ import traceback import types from typing import Any -from typing import Callable from typing import TYPE_CHECKING from typing import Union diff --git a/src/_pytest/unraisableexception.py b/src/_pytest/unraisableexception.py index 9ef583137e1..5796b37715d 100644 --- a/src/_pytest/unraisableexception.py +++ b/src/_pytest/unraisableexception.py @@ -1,11 +1,11 @@ from __future__ import annotations +from collections.abc import Callable from collections.abc import Generator import sys import traceback from types import TracebackType from typing import Any -from typing import Callable from typing import TYPE_CHECKING import warnings diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 4aa4876c711..d3ad09da871 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -1,11 +1,11 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Callable import inspect from pathlib import Path import sys import textwrap -from typing import Callable from _pytest.doctest import _get_checker from _pytest.doctest import _is_main_py diff --git a/testing/test_mark_expression.py b/testing/test_mark_expression.py index a61a9f21560..884c4b5af88 100644 --- a/testing/test_mark_expression.py +++ b/testing/test_mark_expression.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Callable +from collections.abc import Callable from typing import cast from _pytest.mark import MarkMatcher diff --git a/testing/test_tmpdir.py b/testing/test_tmpdir.py index 865d8e0b05c..016588a143d 100644 --- a/testing/test_tmpdir.py +++ b/testing/test_tmpdir.py @@ -1,12 +1,12 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Callable import dataclasses import os from pathlib import Path import stat import sys -from typing import Callable from typing import cast import warnings From f57b26b76c064535f54f5d9cd612ae888254be8f Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Thu, 10 Oct 2024 18:22:48 +0200 Subject: [PATCH 3/9] Remove code that is impossible to reach on python 3.9+ --- src/_pytest/config/argparsing.py | 40 -------------------------------- testing/test_assertrewrite.py | 4 ---- 2 files changed, 44 deletions(-) diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index 5a4e2e7993e..d535fe1096a 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -5,9 +5,7 @@ from collections.abc import Callable from collections.abc import Mapping from collections.abc import Sequence -from gettext import gettext import os -import sys from typing import Any from typing import cast from typing import final @@ -446,44 +444,6 @@ def parse_args( # type: ignore getattr(parsed, FILE_OR_DIR).extend(unrecognized) return parsed - if sys.version_info < (3, 9): # pragma: no cover - # Backport of https://github.com/python/cpython/pull/14316 so we can - # disable long --argument abbreviations without breaking short flags. - def _parse_optional( - self, arg_string: str - ) -> tuple[argparse.Action | None, str, str | None] | None: - if not arg_string: - return None - if arg_string[0] not in self.prefix_chars: - return None - if arg_string in self._option_string_actions: - action = self._option_string_actions[arg_string] - return action, arg_string, None - if len(arg_string) == 1: - return None - if "=" in arg_string: - option_string, explicit_arg = arg_string.split("=", 1) - if option_string in self._option_string_actions: - action = self._option_string_actions[option_string] - return action, option_string, explicit_arg - if self.allow_abbrev or not arg_string.startswith("--"): - option_tuples = self._get_option_tuples(arg_string) - if len(option_tuples) > 1: - msg = gettext( - "ambiguous option: %(option)s could match %(matches)s" - ) - options = ", ".join(option for _, option, _ in option_tuples) - self.error(msg % {"option": arg_string, "matches": options}) - elif len(option_tuples) == 1: - (option_tuple,) = option_tuples - return option_tuple - if self._negative_number_matcher.match(arg_string): - if not self._has_negative_number_optionals: - return None - if " " in arg_string: - return None - return None, arg_string, None - class DropShorterLongHelpFormatter(argparse.HelpFormatter): """Shorten help for long options that differ only in extra hyphens. diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index 2a988149daf..eed59a2dce7 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1018,10 +1018,6 @@ def test_zipfile(self, pytester: Pytester) -> None: ) assert pytester.runpytest().ret == ExitCode.NO_TESTS_COLLECTED - @pytest.mark.skipif( - sys.version_info < (3, 9), - reason="importlib.resources.files was introduced in 3.9", - ) def test_load_resource_via_files_with_rewrite(self, pytester: Pytester) -> None: example = pytester.path.joinpath("demo") / "example" init = pytester.path.joinpath("demo") / "__init__.py" From 66fc31f05f02914c190fd9120653143f0bcb5105 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 10 Nov 2024 22:03:44 +0100 Subject: [PATCH 4/9] Fix 'typing.AbstractSet' is deprecated, use 'collections.abc.Set' --- src/_pytest/assertion/util.py | 2 +- src/_pytest/fixtures.py | 2 +- src/_pytest/logging.py | 2 +- src/_pytest/main.py | 2 +- src/_pytest/mark/__init__.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 49e977171b9..0db846ce204 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -8,9 +8,9 @@ from collections.abc import Iterable from collections.abc import Mapping from collections.abc import Sequence +from collections.abc import Set as AbstractSet import os import pprint -from typing import AbstractSet from typing import Any from typing import Literal from typing import Protocol diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 80c4ec962b8..01707418755 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -12,6 +12,7 @@ from collections.abc import Mapping from collections.abc import MutableMapping from collections.abc import Sequence +from collections.abc import Set as AbstractSet import dataclasses import functools import inspect @@ -19,7 +20,6 @@ from pathlib import Path import sys import types -from typing import AbstractSet from typing import Any from typing import cast from typing import Final diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 00645dae2da..ca5fbda6fcc 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -5,6 +5,7 @@ from collections.abc import Generator from collections.abc import Mapping +from collections.abc import Set as AbstractSet from contextlib import contextmanager from contextlib import nullcontext from datetime import datetime @@ -18,7 +19,6 @@ from pathlib import Path import re from types import TracebackType -from typing import AbstractSet from typing import final from typing import Generic from typing import Literal diff --git a/src/_pytest/main.py b/src/_pytest/main.py index ebd94c84c76..d7086537f39 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -7,6 +7,7 @@ from collections.abc import Iterable from collections.abc import Iterator from collections.abc import Sequence +from collections.abc import Set as AbstractSet import dataclasses import fnmatch import functools @@ -15,7 +16,6 @@ import os from pathlib import Path import sys -from typing import AbstractSet from typing import final from typing import Literal from typing import overload diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index c8c51d19aa0..efb966c09aa 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -5,8 +5,8 @@ import collections from collections.abc import Collection from collections.abc import Iterable +from collections.abc import Set as AbstractSet import dataclasses -from typing import AbstractSet from typing import Optional from typing import TYPE_CHECKING From e684e64dd04967c94d34b7cab651640512b67fa6 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 10 Nov 2024 22:04:32 +0100 Subject: [PATCH 5/9] Fix 'typing.Type' is deprecated, use 'type' instead --- src/_pytest/config/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index fb012d081e1..6160f780b1b 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -32,7 +32,6 @@ from typing import final from typing import IO from typing import TextIO -from typing import Type from typing import TYPE_CHECKING import warnings From a6ef97b65bea694f179ed026e988cf7535ba8d2e Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 10 Nov 2024 22:05:05 +0100 Subject: [PATCH 6/9] Fix 'typing.ContextManager' is deprecated, use 'contextlib.AbstractContextManager' --- src/_pytest/python_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index aae0bd50ce0..fb00f1dd749 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -6,6 +6,7 @@ from collections.abc import Mapping from collections.abc import Sequence from collections.abc import Sized +from contextlib import AbstractContextManager from decimal import Decimal import math from numbers import Complex @@ -15,7 +16,6 @@ from types import TracebackType from typing import Any from typing import cast -from typing import ContextManager from typing import final from typing import overload from typing import TYPE_CHECKING @@ -978,7 +978,7 @@ def raises( @final -class RaisesContext(ContextManager[_pytest._code.ExceptionInfo[E]]): +class RaisesContext(AbstractContextManager[_pytest._code.ExceptionInfo[E]]): def __init__( self, expected_exception: type[E] | tuple[type[E], ...], From 1bacc000779e46e55925533eeb97465e8c857254 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Wed, 20 Nov 2024 22:24:45 +0100 Subject: [PATCH 7/9] [typing] Use the re namespace in 're' typing everywhere --- src/_pytest/_code/code.py | 9 ++++----- src/_pytest/doctest.py | 5 ++--- src/_pytest/junitxml.py | 3 +-- src/_pytest/python.py | 4 ++-- src/_pytest/python_api.py | 7 +++---- src/_pytest/recwarn.py | 11 ++++++----- 6 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 14ac545490f..b98ce013b6e 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -14,7 +14,6 @@ import os from pathlib import Path import re -from re import Pattern import sys import traceback from traceback import format_exception_only @@ -722,7 +721,7 @@ def _stringify_exception(self, exc: BaseException) -> str: ] ) - def match(self, regexp: str | Pattern[str]) -> Literal[True]: + def match(self, regexp: str | re.Pattern[str]) -> Literal[True]: """Check whether the regular expression `regexp` matches the string representation of the exception using :func:`python:re.search`. @@ -741,7 +740,7 @@ def _group_contains( self, exc_group: BaseExceptionGroup[BaseException], expected_exception: EXCEPTION_OR_MORE, - match: str | Pattern[str] | None, + match: str | re.Pattern[str] | None, target_depth: int | None = None, current_depth: int = 1, ) -> bool: @@ -771,7 +770,7 @@ def group_contains( self, expected_exception: EXCEPTION_OR_MORE, *, - match: str | Pattern[str] | None = None, + match: str | re.Pattern[str] | None = None, depth: int | None = None, ) -> bool: """Check whether a captured exception group contains a matching exception. @@ -780,7 +779,7 @@ def group_contains( The expected exception type, or a tuple if one of multiple possible exception types are expected. - :param str | Pattern[str] | None match: + :param str | re.Pattern[str] | None match: If specified, a string containing a regular expression, or a regular expression object, that is tested against the string representation of the exception and its `PEP-678 ` `__notes__` diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index 94868d06106..598df84d70e 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -14,7 +14,7 @@ import os from pathlib import Path import platform -from re import Pattern +import re import sys import traceback import types @@ -593,7 +593,6 @@ def _from_module(self, module, object): def _init_checker_class() -> type[doctest.OutputChecker]: import doctest - import re class LiteralsOutputChecker(doctest.OutputChecker): # Based on doctest_nose_plugin.py from the nltk project @@ -636,7 +635,7 @@ def check_output(self, want: str, got: str, optionflags: int) -> bool: if not allow_unicode and not allow_bytes and not allow_number: return False - def remove_prefixes(regex: Pattern[str], txt: str) -> str: + def remove_prefixes(regex: re.Pattern[str], txt: str) -> str: return re.sub(regex, r"\1\2", txt) if allow_unicode: diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index af072f0d1a4..d129cd295e7 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -17,7 +17,6 @@ import os import platform import re -from re import Match import xml.etree.ElementTree as ET from _pytest import nodes @@ -48,7 +47,7 @@ def bin_xml_escape(arg: object) -> str: The idea is to escape visually for the user rather than for XML itself. """ - def repl(matchobj: Match[str]) -> str: + def repl(matchobj: re.Match[str]) -> str: i = ord(matchobj.group()) if i <= 0xFF: return f"#x{i:02X}" diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 3a42b43d0a1..f75bb5b432e 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -20,7 +20,7 @@ import itertools import os from pathlib import Path -from re import Pattern +import re import types from typing import Any from typing import final @@ -973,7 +973,7 @@ def _idval_from_value(self, val: object) -> str | None: return _ascii_escaped_by_config(val, self.config) elif val is None or isinstance(val, (float, int, bool, complex)): return str(val) - elif isinstance(val, Pattern): + elif isinstance(val, re.Pattern): return ascii_escaped(val.pattern) elif val is NOTSET: # Fallback to default. Note that NOTSET is an enum.Enum. diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index fb00f1dd749..af13c3dc981 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -12,7 +12,6 @@ from numbers import Complex import pprint import re -from re import Pattern from types import TracebackType from typing import Any from typing import cast @@ -780,7 +779,7 @@ def _as_numpy_array(obj: object) -> ndarray | None: def raises( expected_exception: type[E] | tuple[type[E], ...], *, - match: str | Pattern[str] | None = ..., + match: str | re.Pattern[str] | None = ..., ) -> RaisesContext[E]: ... @@ -955,7 +954,7 @@ def raises( message = f"DID NOT RAISE {expected_exception}" if not args: - match: str | Pattern[str] | None = kwargs.pop("match", None) + match: str | re.Pattern[str] | None = kwargs.pop("match", None) if kwargs: msg = "Unexpected keyword arguments passed to pytest.raises: " msg += ", ".join(sorted(kwargs)) @@ -983,7 +982,7 @@ def __init__( self, expected_exception: type[E] | tuple[type[E], ...], message: str, - match_expr: str | Pattern[str] | None = None, + match_expr: str | re.Pattern[str] | None = None, ) -> None: self.expected_exception = expected_exception self.message = message diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index b168bbe746d..440e3efac8a 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -8,7 +8,6 @@ from collections.abc import Iterator from pprint import pformat import re -from re import Pattern from types import TracebackType from typing import Any from typing import final @@ -44,7 +43,9 @@ def recwarn() -> Generator[WarningsRecorder]: @overload -def deprecated_call(*, match: str | Pattern[str] | None = ...) -> WarningsRecorder: ... +def deprecated_call( + *, match: str | re.Pattern[str] | None = ... +) -> WarningsRecorder: ... @overload @@ -89,7 +90,7 @@ def deprecated_call( def warns( expected_warning: type[Warning] | tuple[type[Warning], ...] = ..., *, - match: str | Pattern[str] | None = ..., + match: str | re.Pattern[str] | None = ..., ) -> WarningsChecker: ... @@ -105,7 +106,7 @@ def warns( def warns( expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning, *args: Any, - match: str | Pattern[str] | None = None, + match: str | re.Pattern[str] | None = None, **kwargs: Any, ) -> WarningsChecker | Any: r"""Assert that code raises a particular class of warning. @@ -258,7 +259,7 @@ class WarningsChecker(WarningsRecorder): def __init__( self, expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning, - match_expr: str | Pattern[str] | None = None, + match_expr: str | re.Pattern[str] | None = None, *, _ispytest: bool = False, ) -> None: From 58e25811b6d8a481c15004c2f0c097db6b24d5ad Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Wed, 20 Nov 2024 22:29:13 +0100 Subject: [PATCH 8/9] [black] Fix the target-version configuration --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6856e652829..c13da163259 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,9 +83,8 @@ scripts.pytest = "pytest:console_main" write_to = "src/_pytest/_version.py" [tool.black] -target-version = [ - 'py39', -] +# See https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#t-target-version +target-version = [ "py39", "py310", "py311", "py312", "py313" ] [tool.ruff] line-length = 88 From 10c0c6271604e339042bbf5dd4f271fe6bfd0f5b Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Thu, 28 Nov 2024 21:12:53 +0100 Subject: [PATCH 9/9] [ruff] Set the target version to python 3.9 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index c13da163259..dce6a0870e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,7 @@ write_to = "src/_pytest/_version.py" target-version = [ "py39", "py310", "py311", "py312", "py313" ] [tool.ruff] +target-version = "py39" line-length = 88 src = [ "src",