diff --git a/hypothesis-python/src/hypothesis/core.py b/hypothesis-python/src/hypothesis/core.py index cbf627aa17..9a1a19c1e2 100644 --- a/hypothesis-python/src/hypothesis/core.py +++ b/hypothesis-python/src/hypothesis/core.py @@ -24,6 +24,7 @@ import warnings import zlib from collections import defaultdict +from collections.abc import Coroutine, Hashable from functools import partial from random import Random from typing import ( @@ -31,12 +32,7 @@ Any, BinaryIO, Callable, - Coroutine, - Hashable, - List, Optional, - Tuple, - Type, TypeVar, Union, overload, @@ -179,7 +175,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: if not (args or kwargs): raise InvalidArgument("An example must provide at least one argument") - self.hypothesis_explicit_examples: List[Example] = [] + self.hypothesis_explicit_examples: list[Example] = [] self._this_example = Example(tuple(args), kwargs) def __call__(self, test: TestFunc) -> TestFunc: @@ -194,7 +190,7 @@ def xfail( *, reason: str = "", raises: Union[ - Type[BaseException], Tuple[Type[BaseException], ...] + type[BaseException], tuple[type[BaseException], ...] ] = BaseException, ) -> "example": """Mark this example as an expected failure, similarly to @@ -1825,7 +1821,7 @@ def find( ) specifier.validate() - last: List[Ex] = [] + last: list[Ex] = [] @settings @given(specifier) diff --git a/hypothesis-python/src/hypothesis/extra/ghostwriter.py b/hypothesis-python/src/hypothesis/extra/ghostwriter.py index 9fb8c89331..d1936894ff 100644 --- a/hypothesis-python/src/hypothesis/extra/ghostwriter.py +++ b/hypothesis-python/src/hypothesis/extra/ghostwriter.py @@ -82,6 +82,7 @@ import types import warnings from collections import OrderedDict, defaultdict +from collections.abc import Iterable, Mapping from itertools import permutations, zip_longest from keyword import iskeyword as _iskeyword from string import ascii_lowercase @@ -91,16 +92,9 @@ Any, Callable, DefaultDict, - Dict, ForwardRef, - Iterable, - List, - Mapping, NamedTuple, Optional, - Set, - Tuple, - Type, TypeVar, Union, get_args, @@ -156,8 +150,8 @@ def test_{test_kind}_{func_name}({arg_names}){return_annotation}: reject() """.strip() -Except = Union[Type[Exception], Tuple[Type[Exception], ...]] -ImportSet = Set[Union[str, Tuple[str, str]]] +Except = Union[type[Exception], tuple[type[Exception], ...]] +ImportSet = set[Union[str, tuple[str, str]]] _quietly_settings = settings( database=None, deadline=None, @@ -166,7 +160,7 @@ def test_{test_kind}_{func_name}({arg_names}){return_annotation}: ) -def _dedupe_exceptions(exc: Tuple[Type[Exception], ...]) -> Tuple[Type[Exception], ...]: +def _dedupe_exceptions(exc: tuple[type[Exception], ...]) -> tuple[type[Exception], ...]: # This is reminiscent of de-duplication logic I wrote for flake8-bugbear, # but with access to the actual objects we can just check for subclasses. # This lets us print e.g. `Exception` instead of `(Exception, OSError)`. @@ -177,7 +171,7 @@ def _dedupe_exceptions(exc: Tuple[Type[Exception], ...]) -> Tuple[Type[Exception return tuple(sorted(uniques, key=lambda e: e.__name__)) -def _check_except(except_: Except) -> Tuple[Type[Exception], ...]: +def _check_except(except_: Except) -> tuple[type[Exception], ...]: if isinstance(except_, tuple): for i, e in enumerate(except_): if not isinstance(e, type) or not issubclass(e, Exception): @@ -194,7 +188,7 @@ def _check_except(except_: Except) -> Tuple[Type[Exception], ...]: return (except_,) -def _exception_string(except_: Tuple[Type[Exception], ...]) -> Tuple[ImportSet, str]: +def _exception_string(except_: tuple[type[Exception], ...]) -> tuple[ImportSet, str]: if not except_: return set(), "" exceptions = [] @@ -215,7 +209,7 @@ def _check_style(style: str) -> None: raise InvalidArgument(f"Valid styles are 'pytest' or 'unittest', got {style!r}") -def _exceptions_from_docstring(doc: str) -> Tuple[Type[Exception], ...]: +def _exceptions_from_docstring(doc: str) -> tuple[type[Exception], ...]: """Return a tuple of exceptions that the docstring says may be raised. Note that we ignore non-builtin exception types for simplicity, as this is @@ -250,7 +244,7 @@ def _type_from_doc_fragment(token: str) -> Optional[type]: if elems is None and elem_token.endswith("s"): elems = _type_from_doc_fragment(elem_token[:-1]) if elems is not None and coll_token in ("list", "sequence", "collection"): - return List[elems] # type: ignore + return list[elems] # type: ignore # This might be e.g. "array-like of float"; arrays is better than nothing # even if we can't conveniently pass a generic type around. return _type_from_doc_fragment(coll_token) @@ -451,7 +445,7 @@ def _guess_strategy_by_argname(name: str) -> st.SearchStrategy: return st.nothing() -def _get_params_builtin_fn(func: Callable) -> List[inspect.Parameter]: +def _get_params_builtin_fn(func: Callable) -> list[inspect.Parameter]: if ( isinstance(func, (types.BuiltinFunctionType, types.BuiltinMethodType)) and hasattr(func, "__doc__") @@ -483,7 +477,7 @@ def _get_params_builtin_fn(func: Callable) -> List[inspect.Parameter]: return [] -def _get_params_ufunc(func: Callable) -> List[inspect.Parameter]: +def _get_params_ufunc(func: Callable) -> list[inspect.Parameter]: if _is_probably_ufunc(func): # `inspect.signature` results vary for ufunc objects, but we can work out # what the required parameters would look like if it was reliable. @@ -498,7 +492,7 @@ def _get_params_ufunc(func: Callable) -> List[inspect.Parameter]: return [] -def _get_params(func: Callable) -> Dict[str, inspect.Parameter]: +def _get_params(func: Callable) -> dict[str, inspect.Parameter]: """Get non-vararg parameters of `func` as an ordered dict.""" try: params = list(get_signature(func).parameters.values()) @@ -522,7 +516,7 @@ def _get_params(func: Callable) -> Dict[str, inspect.Parameter]: def _params_to_dict( params: Iterable[inspect.Parameter], -) -> Dict[str, inspect.Parameter]: +) -> dict[str, inspect.Parameter]: var_param_kinds = (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) return OrderedDict((p.name, p) for p in params if p.kind not in var_param_kinds) @@ -548,7 +542,7 @@ def _with_any_registered(): def _get_strategies( *funcs: Callable, pass_result_to_next_func: bool = False -) -> Dict[str, st.SearchStrategy]: +) -> dict[str, st.SearchStrategy]: """Return a dict of strategies for the union of arguments to `funcs`. If `pass_result_to_next_func` is True, assume that the result of each function @@ -558,7 +552,7 @@ def _get_strategies( This dict is used to construct our call to the `@given(...)` decorator. """ assert funcs, "Must pass at least one function" - given_strategies: Dict[str, st.SearchStrategy] = {} + given_strategies: dict[str, st.SearchStrategy] = {} for i, f in enumerate(funcs): params = _get_params(f) if pass_result_to_next_func and i >= 1: @@ -735,7 +729,7 @@ def _valid_syntax_repr(strategy): # When we ghostwrite for a module, we want to treat that as the __module__ for # each function, rather than whichever internal file it was actually defined in. -KNOWN_FUNCTION_LOCATIONS: Dict[object, str] = {} +KNOWN_FUNCTION_LOCATIONS: dict[object, str] = {} def _get_module_helper(obj): @@ -832,13 +826,13 @@ def _make_test_body( *funcs: Callable, ghost: str, test_body: str, - except_: Tuple[Type[Exception], ...], + except_: tuple[type[Exception], ...], assertions: str = "", style: str, given_strategies: Optional[Mapping[str, Union[str, st.SearchStrategy]]] = None, imports: Optional[ImportSet] = None, annotate: bool, -) -> Tuple[ImportSet, str]: +) -> tuple[ImportSet, str]: # A set of modules to import - we might add to this later. The import code # is written later, so we can have one import section for multiple magic() # test functions. @@ -899,7 +893,7 @@ def _make_test_body( def _annotate_args( argnames: Iterable[str], funcs: Iterable[Callable], imports: ImportSet ) -> Iterable[str]: - arg_parameters: DefaultDict[str, Set[Any]] = defaultdict(set) + arg_parameters: DefaultDict[str, set[Any]] = defaultdict(set) for func in funcs: try: params = tuple(get_signature(func, eval_str=True).parameters.values()) @@ -922,7 +916,7 @@ def _annotate_args( class _AnnotationData(NamedTuple): type_name: str - imports: Set[str] + imports: set[str] def _parameters_to_annotation_name( @@ -949,7 +943,7 @@ def _parameters_to_annotation_name( def _join_generics( - origin_type_data: Optional[Tuple[str, Set[str]]], + origin_type_data: Optional[tuple[str, set[str]]], annotations: Iterable[Optional[_AnnotationData]], ) -> Optional[_AnnotationData]: if origin_type_data is None: @@ -976,9 +970,9 @@ def _join_generics( def _join_argument_annotations( annotations: Iterable[Optional[_AnnotationData]], -) -> Optional[Tuple[List[str], Set[str]]]: - imports: Set[str] = set() - arg_types: List[str] = [] +) -> Optional[tuple[list[str], set[str]]]: + imports: set[str] = set() + arg_types: list[str] = [] for annotation in annotations: if annotation is None: @@ -1134,10 +1128,10 @@ def _is_probably_ufunc(obj): ) -def _get_testable_functions(thing: object) -> Dict[str, Callable]: +def _get_testable_functions(thing: object) -> dict[str, Callable]: by_name = {} if callable(thing): - funcs: List[Optional[Any]] = [thing] + funcs: list[Optional[Any]] = [thing] elif isinstance(thing, types.ModuleType): if hasattr(thing, "__all__"): funcs = [getattr(thing, name, None) for name in thing.__all__] @@ -1732,10 +1726,10 @@ def _make_binop_body( commutative: bool = True, identity: Union[X, EllipsisType, None] = ..., distributes_over: Optional[Callable[[X, X], X]] = None, - except_: Tuple[Type[Exception], ...], + except_: tuple[type[Exception], ...], style: str, annotate: bool, -) -> Tuple[ImportSet, str]: +) -> tuple[ImportSet, str]: strategies = _get_strategies(func) operands, b = (strategies.pop(p) for p in list(_get_params(func))[:2]) if repr(operands) != repr(b): diff --git a/hypothesis-python/src/hypothesis/internal/compat.py b/hypothesis-python/src/hypothesis/internal/compat.py index 6837f00684..baa9284bce 100644 --- a/hypothesis-python/src/hypothesis/internal/compat.py +++ b/hypothesis-python/src/hypothesis/internal/compat.py @@ -17,7 +17,7 @@ import sysconfig import typing from functools import partial -from typing import Any, ForwardRef, List, Optional, TypedDict as TypedDict, get_args +from typing import Any, ForwardRef, Optional, TypedDict as TypedDict, get_args try: BaseExceptionGroup = BaseExceptionGroup @@ -218,7 +218,7 @@ def ceil(x): return y -def extract_bits(x: int, /, width: Optional[int] = None) -> List[int]: +def extract_bits(x: int, /, width: Optional[int] = None) -> list[int]: assert x >= 0 result = [] while x: diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py index 7608e3682a..7013441358 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py @@ -13,6 +13,7 @@ import textwrap import time from collections import defaultdict +from collections.abc import Generator from contextlib import contextmanager, suppress from datetime import timedelta from enum import Enum @@ -20,16 +21,11 @@ from typing import ( Any, Callable, - Dict, Final, - FrozenSet, - Generator, List, Literal, NoReturn, Optional, - Set, - Tuple, Union, cast, overload, @@ -97,7 +93,7 @@ # (but make it monkeypatchable, for the rare users who need to keep on shrinking) MAX_SHRINKING_SECONDS: Final[int] = 300 -Ls: TypeAlias = List["Ls | int"] +Ls: TypeAlias = list["Ls | int"] @attr.s @@ -180,14 +176,14 @@ class CallStats(TypedDict): runtime: float drawtime: float gctime: float - events: List[str] + events: list[str] PhaseStatistics = TypedDict( "PhaseStatistics", { "duration-seconds": float, - "test-cases": List[CallStats], + "test-cases": list[CallStats], "distinct-failures": int, "shrinks-successful": int, }, @@ -199,7 +195,7 @@ class CallStats(TypedDict): "reuse-phase": NotRequired[PhaseStatistics], "shrink-phase": NotRequired[PhaseStatistics], "stopped-because": NotRequired[str], - "targets": NotRequired[Dict[str, float]], + "targets": NotRequired[dict[str, float]], "nodeid": NotRequired[str], }, ) @@ -230,16 +226,16 @@ def __init__( # which transfer to the global dict at the end of each phase. self._current_phase: str = "(not a phase)" self.statistics: StatisticsDict = {} - self.stats_per_test_case: List[CallStats] = [] + self.stats_per_test_case: list[CallStats] = [] # At runtime, the keys are only ever type `InterestingOrigin`, but can be `None` during tests. - self.interesting_examples: Dict[InterestingOrigin, ConjectureResult] = {} + self.interesting_examples: dict[InterestingOrigin, ConjectureResult] = {} # We use call_count because there may be few possible valid_examples. self.first_bug_found_at: Optional[int] = None self.last_bug_found_at: Optional[int] = None # At runtime, the keys are only ever type `InterestingOrigin`, but can be `None` during tests. - self.shrunk_examples: Set[Optional[InterestingOrigin]] = set() + self.shrunk_examples: set[Optional[InterestingOrigin]] = set() self.health_check_state: Optional[HealthCheckState] = None @@ -252,7 +248,7 @@ def __init__( self.best_observed_targets: "defaultdict[str, float]" = defaultdict( lambda: NO_SCORE ) - self.best_examples_of_observed_targets: Dict[str, ConjectureResult] = {} + self.best_examples_of_observed_targets: dict[str, ConjectureResult] = {} # We keep the pareto front in the example database if we have one. This # is only marginally useful at present, but speeds up local development @@ -334,9 +330,9 @@ def __stoppable_test_function(self, data: ConjectureData) -> None: def _cache_key_ir( self, *, - nodes: Optional[List[IRNode]] = None, + nodes: Optional[list[IRNode]] = None, data: Union[ConjectureData, ConjectureResult, None] = None, - ) -> Tuple[Tuple[Any, ...], ...]: + ) -> tuple[tuple[Any, ...], ...]: assert (nodes is not None) ^ (data is not None) if data is not None: nodes = data.examples.ir_tree_nodes @@ -377,7 +373,7 @@ def _cache(self, data: ConjectureData) -> None: self.__data_cache_ir[key] = result def cached_test_function_ir( - self, nodes: List[IRNode], *, error_on_discard: bool = False + self, nodes: list[IRNode], *, error_on_discard: bool = False ) -> Union[ConjectureResult, _Overrun]: key = self._cache_key_ir(nodes=nodes) try: @@ -742,7 +738,7 @@ def debug_data(self, data: Union[ConjectureData, ConjectureResult]) -> None: if not self.report_debug_info: return - stack: List[Ls] = [[]] + stack: list[Ls] = [[]] def go(ex: Example) -> None: if ex.length == 0: @@ -1257,7 +1253,7 @@ def _run(self) -> None: def new_conjecture_data_ir( self, - ir_tree_prefix: List[IRNode], + ir_tree_prefix: list[IRNode], *, observer: Optional[DataObserver] = None, max_length: Optional[int] = None, @@ -1486,7 +1482,7 @@ def check_result( self.__data_cache[buffer] = result return result - def passing_buffers(self, prefix: bytes = b"") -> FrozenSet[bytes]: + def passing_buffers(self, prefix: bytes = b"") -> frozenset[bytes]: """Return a collection of bytestrings which cause the test to pass. Optionally restrict this by a certain prefix, which is useful for explain mode. diff --git a/hypothesis-python/src/hypothesis/internal/observability.py b/hypothesis-python/src/hypothesis/internal/observability.py index 99b9e11f7f..2ad2d4dd5a 100644 --- a/hypothesis-python/src/hypothesis/internal/observability.py +++ b/hypothesis-python/src/hypothesis/internal/observability.py @@ -17,13 +17,13 @@ import warnings from datetime import date, timedelta from functools import lru_cache -from typing import Any, Callable, Dict, List, Optional +from typing import Any, Callable, Optional from hypothesis.configuration import storage_directory from hypothesis.errors import HypothesisWarning from hypothesis.internal.conjecture.data import ConjectureData, Status -TESTCASE_CALLBACKS: List[Callable[[dict], None]] = [] +TESTCASE_CALLBACKS: list[Callable[[dict], None]] = [] def deliver_json_blob(value: dict) -> None: @@ -39,10 +39,10 @@ def make_testcase( how_generated: str, string_repr: str = "", arguments: Optional[dict] = None, - timing: Dict[str, float], - coverage: Optional[Dict[str, List[int]]] = None, + timing: dict[str, float], + coverage: Optional[dict[str, list[int]]] = None, phase: Optional[str] = None, - backend_metadata: Optional[Dict[str, Any]] = None, + backend_metadata: Optional[dict[str, Any]] = None, ) -> dict: if data.interesting_origin: status_reason = str(data.interesting_origin) diff --git a/hypothesis-python/src/hypothesis/internal/reflection.py b/hypothesis-python/src/hypothesis/internal/reflection.py index 9f09efb9a0..dbc987e9c7 100644 --- a/hypothesis-python/src/hypothesis/internal/reflection.py +++ b/hypothesis-python/src/hypothesis/internal/reflection.py @@ -21,13 +21,14 @@ import textwrap import types import warnings +from collections.abc import MutableMapping from functools import partial, wraps from io import StringIO from keyword import iskeyword from random import _inst as global_random_instance from tokenize import COMMENT, detect_encoding, generate_tokens, untokenize from types import ModuleType -from typing import TYPE_CHECKING, Any, Callable, MutableMapping +from typing import TYPE_CHECKING, Any, Callable from unittest.mock import _patch as PatchType from weakref import WeakKeyDictionary diff --git a/hypothesis-python/src/hypothesis/internal/scrutineer.py b/hypothesis-python/src/hypothesis/internal/scrutineer.py index 30da35bead..5586e42808 100644 --- a/hypothesis-python/src/hypothesis/internal/scrutineer.py +++ b/hypothesis-python/src/hypothesis/internal/scrutineer.py @@ -15,10 +15,11 @@ import sys import types from collections import defaultdict +from collections.abc import Iterable from functools import lru_cache, reduce from os import sep from pathlib import Path -from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple +from typing import TYPE_CHECKING, Optional from hypothesis._settings import Phase, Verbosity from hypothesis.internal.compat import PYPY @@ -29,9 +30,9 @@ else: TypeAlias = object -Location: TypeAlias = Tuple[str, int] -Branch: TypeAlias = Tuple[Optional[Location], Location] -Trace: TypeAlias = Set[Branch] +Location: TypeAlias = tuple[str, int] +Branch: TypeAlias = tuple[Optional[Location], Location] +Trace: TypeAlias = set[Branch] @lru_cache(maxsize=None) @@ -250,7 +251,7 @@ def _get_git_repo_root() -> Path: return Path(where) -def tractable_coverage_report(trace: Trace) -> Dict[str, List[int]]: +def tractable_coverage_report(trace: Trace) -> dict[str, list[int]]: """Report a simple coverage map which is (probably most) of the user's code.""" coverage: dict = {} t = dict(trace) diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/core.py b/hypothesis-python/src/hypothesis/strategies/_internal/core.py index 8a52c74831..472eb9c055 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/core.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/core.py @@ -18,30 +18,21 @@ import sys import typing import warnings +from collections.abc import Collection, Hashable, Iterable, Sequence from contextvars import ContextVar from decimal import Context, Decimal, localcontext from fractions import Fraction from functools import reduce from inspect import Parameter, Signature, isabstract, isclass +from re import Pattern from types import FunctionType from typing import ( Any, AnyStr, Callable, - Collection, - Dict, - FrozenSet, - Hashable, - Iterable, - List, Literal, Optional, - Pattern, Protocol, - Sequence, - Set, - Tuple, - Type, TypeVar, Union, get_args, @@ -180,21 +171,21 @@ def sampled_from(elements: Sequence[T]) -> SearchStrategy[T]: # pragma: no cove @overload -def sampled_from(elements: Type[enum.Enum]) -> SearchStrategy[Any]: # pragma: no cover +def sampled_from(elements: type[enum.Enum]) -> SearchStrategy[Any]: # pragma: no cover # `SearchStrategy[Enum]` is unreliable due to metaclass issues. ... @overload def sampled_from( - elements: Union[Type[enum.Enum], Sequence[Any]] + elements: Union[type[enum.Enum], Sequence[Any]] ) -> SearchStrategy[Any]: # pragma: no cover ... @defines_strategy(try_non_lazy=True) def sampled_from( - elements: Union[Type[enum.Enum], Sequence[Any]] + elements: Union[type[enum.Enum], Sequence[Any]] ) -> SearchStrategy[Any]: """Returns a strategy which generates any value present in ``elements``. @@ -285,10 +276,10 @@ def lists( unique_by: Union[ None, Callable[[Ex], Hashable], - Tuple[Callable[[Ex], Hashable], ...], + tuple[Callable[[Ex], Hashable], ...], ] = None, unique: bool = False, -) -> SearchStrategy[List[Ex]]: +) -> SearchStrategy[list[Ex]]: """Returns a list containing values drawn from elements with length in the interval [min_size, max_size] (no bounds in that direction if these are None). If max_size is 0, only the empty list will be drawn. @@ -419,7 +410,7 @@ def sets( *, min_size: int = 0, max_size: Optional[int] = None, -) -> SearchStrategy[Set[Ex]]: +) -> SearchStrategy[set[Ex]]: """This has the same behaviour as lists, but returns sets instead. Note that Hypothesis cannot tell if values are drawn from elements @@ -441,7 +432,7 @@ def frozensets( *, min_size: int = 0, max_size: Optional[int] = None, -) -> SearchStrategy[FrozenSet[Ex]]: +) -> SearchStrategy[frozenset[Ex]]: """This is identical to the sets function but instead returns frozensets.""" return lists( @@ -473,7 +464,7 @@ def iterables( unique_by: Union[ None, Callable[[Ex], Hashable], - Tuple[Callable[[Ex], Hashable], ...], + tuple[Callable[[Ex], Hashable], ...], ] = None, unique: bool = False, ) -> SearchStrategy[Iterable[Ex]]: @@ -495,10 +486,10 @@ def iterables( @defines_strategy() def fixed_dictionaries( - mapping: Dict[T, SearchStrategy[Ex]], + mapping: dict[T, SearchStrategy[Ex]], *, - optional: Optional[Dict[T, SearchStrategy[Ex]]] = None, -) -> SearchStrategy[Dict[T, Ex]]: + optional: Optional[dict[T, SearchStrategy[Ex]]] = None, +) -> SearchStrategy[dict[T, Ex]]: """Generates a dictionary of the same type as mapping with a fixed set of keys mapping to strategies. ``mapping`` must be a dict subclass. @@ -542,7 +533,7 @@ def dictionaries( dict_class: type = dict, min_size: int = 0, max_size: Optional[int] = None, -) -> SearchStrategy[Dict[Ex, T]]: +) -> SearchStrategy[dict[Ex, T]]: # Describing the exact dict_class to Mypy drops the key and value types, # so we report Dict[K, V] instead of Mapping[Any, Any] for now. Sorry! """Generates dictionaries of type ``dict_class`` with keys drawn from the ``keys`` @@ -1139,7 +1130,7 @@ def builds( @cacheable @defines_strategy(never_lazy=True) -def from_type(thing: Type[Ex_Inv]) -> SearchStrategy[Ex_Inv]: +def from_type(thing: type[Ex_Inv]) -> SearchStrategy[Ex_Inv]: """Looks up the appropriate search strategy for the given type. ``from_type`` is used internally to fill in missing arguments to @@ -1199,7 +1190,7 @@ def everything_except(excluded_types): return _from_type_deferred(thing) -def _from_type_deferred(thing: Type[Ex]) -> SearchStrategy[Ex]: +def _from_type_deferred(thing: type[Ex]) -> SearchStrategy[Ex]: # This tricky little dance is because we want to show the repr of the actual # underlying strategy wherever possible, as a form of user education, but # would prefer to fall back to the default "from_type(...)" repr instead of @@ -1224,7 +1215,7 @@ def _from_type_deferred(thing: Type[Ex]) -> SearchStrategy[Ex]: _recurse_guard: ContextVar = ContextVar("recurse_guard") -def _from_type(thing: Type[Ex]) -> SearchStrategy[Ex]: +def _from_type(thing: type[Ex]) -> SearchStrategy[Ex]: # TODO: We would like to move this to the top level, but pending some major # refactoring it's hard to do without creating circular imports. from hypothesis.strategies._internal import types @@ -1703,7 +1694,7 @@ def fraction_to_decimal(val): strat = fractions(min_value, max_value).map(fraction_to_decimal) # Compose with sampled_from for infinities and NaNs as appropriate - special: List[Decimal] = [] + special: list[Decimal] = [] if allow_nan or (allow_nan is None and (None in (min_value, max_value))): special.extend(map(Decimal, ("NaN", "-NaN", "sNaN", "-sNaN"))) if allow_infinity or (allow_infinity is None and max_value is None): @@ -1761,7 +1752,7 @@ def do_draw(self, data): @defines_strategy() -def permutations(values: Sequence[T]) -> SearchStrategy[List[T]]: +def permutations(values: Sequence[T]) -> SearchStrategy[list[T]]: """Return a strategy which returns permutations of the ordered collection ``values``. @@ -2217,8 +2208,8 @@ def data() -> SearchStrategy[DataObject]: def register_type_strategy( - custom_type: Type[Ex], - strategy: Union[SearchStrategy[Ex], Callable[[Type[Ex]], SearchStrategy[Ex]]], + custom_type: type[Ex], + strategy: Union[SearchStrategy[Ex], Callable[[type[Ex]], SearchStrategy[Ex]]], ) -> None: """Add an entry to the global type-to-strategy lookup. diff --git a/hypothesis-python/tests/array_api/common.py b/hypothesis-python/tests/array_api/common.py index 89c612ef2e..84742787e6 100644 --- a/hypothesis-python/tests/array_api/common.py +++ b/hypothesis-python/tests/array_api/common.py @@ -9,7 +9,7 @@ # obtain one at https://mozilla.org/MPL/2.0/. from importlib.metadata import EntryPoint, entry_points # type: ignore -from typing import Dict, Literal +from typing import Literal import pytest @@ -34,7 +34,7 @@ assert MIN_VER_FOR_COMPLEX == RELEASED_VERSIONS[1] -def installed_array_modules() -> Dict[str, EntryPoint]: +def installed_array_modules() -> dict[str, EntryPoint]: """Returns a dictionary of array module names paired to their entry points A convenience wrapper for importlib.metadata.entry_points(). It has the diff --git a/hypothesis-python/tests/ghostwriter/test_expected_output.py b/hypothesis-python/tests/ghostwriter/test_expected_output.py index 07f35e8e03..34c453a50b 100644 --- a/hypothesis-python/tests/ghostwriter/test_expected_output.py +++ b/hypothesis-python/tests/ghostwriter/test_expected_output.py @@ -23,7 +23,8 @@ import re import subprocess import sys -from typing import Optional, Sequence, Union +from collections.abc import Sequence +from typing import Optional, Union import numpy import numpy.typing diff --git a/hypothesis-python/tests/test_annotated_types.py b/hypothesis-python/tests/test_annotated_types.py index 8a869f7d46..3fbde052ee 100644 --- a/hypothesis-python/tests/test_annotated_types.py +++ b/hypothesis-python/tests/test_annotated_types.py @@ -10,7 +10,7 @@ import re import sys -from typing import Annotated, List, Set +from typing import Annotated import pytest @@ -90,7 +90,7 @@ def func(_): class MyCollection: - def __init__(self, values: List[int]) -> None: + def __init__(self, values: list[int]) -> None: self._values = values def __len__(self) -> int: @@ -99,7 +99,7 @@ def __len__(self) -> int: @pytest.mark.parametrize("lo", [0, 1]) @pytest.mark.parametrize("hi", [None, 10]) -@pytest.mark.parametrize("type_", [List[int], Set[int], MyCollection]) +@pytest.mark.parametrize("type_", [list[int], set[int], MyCollection]) @given(data=st.data()) def test_collection_sizes(data, lo, hi, type_): print(f"{type_=} {lo=} {hi=}") diff --git a/tooling/src/hypothesistooling/__main__.py b/tooling/src/hypothesistooling/__main__.py index d5ea1ec45d..6c59dbac4d 100644 --- a/tooling/src/hypothesistooling/__main__.py +++ b/tooling/src/hypothesistooling/__main__.py @@ -209,6 +209,8 @@ def warn(msg): codespell("--write-changes", *files_to_format, *doc_files_to_format) pip_tool("ruff", "check", "--fix-only", ".") pip_tool("shed", *files_to_format, *doc_files_to_format) + # FIXME: work through the typing issues and enable py39 formatting + # pip_tool("shed", "--py39-plus", *files_to_format, *doc_files_to_format) VALID_STARTS = (HEADER.split()[0], "#!/usr/bin/env python")