Skip to content

Commit

Permalink
compat with new Pythons
Browse files Browse the repository at this point in the history
  • Loading branch information
Zac-HD committed May 22, 2024
1 parent a536684 commit d5fb615
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ jobs:
- check-py313-cover
- check-py313-nocover
- check-py313-niche
# - check-py314-cover
# - check-py314-nocover
# - check-py314-niche
- check-quality
## Skip all the (inactive/old) Rust and Ruby tests pending fixes
# - lint-ruby
Expand Down
4 changes: 4 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RELEASE_TYPE: patch

This patch fixes some introspection errors new in Python 3.11.9 and
3.13.0b1, for the Ghostwriter and :func:`~hypothesis.strategies.from_type`.
22 changes: 11 additions & 11 deletions hypothesis-python/src/hypothesis/extra/ghostwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,17 @@ def _guess_strategy_by_argname(name: str) -> st.SearchStrategy:

def _get_params(func: Callable) -> Dict[str, inspect.Parameter]:
"""Get non-vararg parameters of `func` as an ordered dict."""
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.
# Note that we use args named a, b, c... to match the `operator` module,
# rather than x1, x2, x3... like the Numpy docs. Because they're pos-only
# this doesn't make a runtime difference, and it's much nicer for use-cases
# like `equivalent(numpy.add, operator.add)`.
params = [
inspect.Parameter(name=name, kind=inspect.Parameter.POSITIONAL_ONLY)
for name in ascii_lowercase[: func.nin] # type: ignore
]
try:
params = list(get_signature(func).parameters.values())
except Exception:
Expand Down Expand Up @@ -485,17 +496,6 @@ def _get_params(func: Callable) -> Dict[str, inspect.Parameter]:
break # skip all subsequent params if this name is invalid
params.append(inspect.Parameter(name=arg, kind=kind))

elif _is_probably_ufunc(func):
# `inspect.signature` doesn't work on ufunc objects, but we can work out
# what the required parameters would look like if it did.
# Note that we use args named a, b, c... to match the `operator` module,
# rather than x1, x2, x3... like the Numpy docs. Because they're pos-only
# this doesn't make a runtime difference, and it's much nicer for use-cases
# like `equivalent(numpy.add, operator.add)`.
params = [
inspect.Parameter(name=name, kind=inspect.Parameter.POSITIONAL_ONLY)
for name in ascii_lowercase[: func.nin] # type: ignore
]
else:
# If we haven't managed to recover a signature through the tricks above,
# we're out of ideas and should just re-raise the exception.
Expand Down
16 changes: 13 additions & 3 deletions hypothesis-python/src/hypothesis/strategies/_internal/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,12 @@ def is_generic_type(type_):
)


def _try_import_forward_ref(thing, bound): # pragma: no cover
__EVAL_TYPE_TAKES_TYPE_PARAMS = (
"type_params" in inspect.signature(typing._eval_type).parameters # type: ignore
)


def _try_import_forward_ref(thing, bound, *, type_params): # pragma: no cover
"""
Tries to import a real bound type from ``TypeVar`` bound to a ``ForwardRef``.
Expand All @@ -397,7 +402,10 @@ def _try_import_forward_ref(thing, bound): # pragma: no cover
because we can only cover each path in a separate python version.
"""
try:
return typing._eval_type(bound, vars(sys.modules[thing.__module__]), None)
kw = {"globalns": vars(sys.modules[thing.__module__]), "localns": None}
if __EVAL_TYPE_TAKES_TYPE_PARAMS:
kw["type_params"] = type_params
return typing._eval_type(bound, **kw)
except (KeyError, AttributeError, NameError):
# We fallback to `ForwardRef` instance, you can register it as a type as well:
# >>> from typing import ForwardRef
Expand Down Expand Up @@ -1030,7 +1038,9 @@ def resolve_TypeVar(thing):
if getattr(thing, "__bound__", None) is not None:
bound = thing.__bound__
if isinstance(bound, typing.ForwardRef):
bound = _try_import_forward_ref(thing, bound)
# TODO: on Python 3.13 and later, we should work out what type_params
# could be part of this type, and pass them in here.
bound = _try_import_forward_ref(thing, bound, type_params=())
strat = unwrap_strategies(st.from_type(bound))
if not isinstance(strat, OneOfStrategy):
return strat
Expand Down
2 changes: 1 addition & 1 deletion requirements/coverage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ tomli==2.0.1
# black
# coverage
# pytest
typing-extensions==4.11.0
typing-extensions==4.12.0rc1
# via
# -r requirements/coverage.in
# black
Expand Down
2 changes: 1 addition & 1 deletion requirements/fuzzing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ tomli==2.0.1
# black
# coverage
# pytest
typing-extensions==4.11.0
typing-extensions==4.12.0rc1
# via
# -r requirements/coverage.in
# black
Expand Down
2 changes: 1 addition & 1 deletion requirements/tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ types-redis==4.6.0.20240425
# via -r requirements/tools.in
types-setuptools==69.5.0.20240518
# via types-cffi
typing-extensions==4.11.0
typing-extensions==4.12.0rc1
# via
# -r requirements/tools.in
# anyio
Expand Down

0 comments on commit d5fb615

Please sign in to comment.