Skip to content

Commit

Permalink
stubtest: hack for "<unrepresentable>" defaults (#16433)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed Nov 18, 2023
1 parent e81309e commit 706389d
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
34 changes: 33 additions & 1 deletion mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ def __repr__(self) -> str:
T = TypeVar("T")
MaybeMissing: typing_extensions.TypeAlias = Union[T, Missing]


class Unrepresentable:
"""Marker object for unrepresentable parameter defaults."""

def __repr__(self) -> str:
return "<unrepresentable>"


UNREPRESENTABLE: typing_extensions.Final = Unrepresentable()


_formatter: typing_extensions.Final = FancyFormatter(sys.stdout, sys.stderr, False)


Expand Down Expand Up @@ -681,6 +692,7 @@ def _verify_arg_default_value(
if (
stub_default is not UNKNOWN
and stub_default is not ...
and runtime_arg.default is not UNREPRESENTABLE
and (
stub_default != runtime_arg.default
# We want the types to match exactly, e.g. in case the stub has
Expand Down Expand Up @@ -1483,7 +1495,27 @@ def is_read_only_property(runtime: object) -> bool:

def safe_inspect_signature(runtime: Any) -> inspect.Signature | None:
try:
return inspect.signature(runtime)
try:
return inspect.signature(runtime)
except ValueError:
if (
hasattr(runtime, "__text_signature__")
and "<unrepresentable>" in runtime.__text_signature__
):
# Try to fix up the signature. Workaround for
# https://github.com/python/cpython/issues/87233
sig = runtime.__text_signature__.replace("<unrepresentable>", "...")
sig = inspect._signature_fromstr(inspect.Signature, runtime, sig) # type: ignore[attr-defined]
assert isinstance(sig, inspect.Signature)
new_params = [
parameter.replace(default=UNREPRESENTABLE)
if parameter.default is ...
else parameter
for parameter in sig.parameters.values()
]
return sig.replace(parameters=new_params)
else:
raise
except Exception:
# inspect.signature throws ValueError all the time
# catch RuntimeError because of https://bugs.python.org/issue39504
Expand Down
18 changes: 18 additions & 0 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ def test_default_value(self) -> Iterator[Case]:
error=None,
)

# Simulate "<unrepresentable>"
yield Case(
stub="def f11() -> None: ...",
runtime="""
def f11(text=None) -> None: pass
f11.__text_signature__ = "(text=<unrepresentable>)"
""",
error="f11",
)

@collect_cases
def test_static_class_method(self) -> Iterator[Case]:
yield Case(
Expand Down Expand Up @@ -2281,6 +2291,14 @@ def f(a: int, b: int, *, c: int, d: int = 0, **kwargs: Any) -> None:
== "def (a, b, *, c, d = ..., **kwargs)"
)

def test_builtin_signature_with_unrepresentable_default(self) -> None:
sig = mypy.stubtest.safe_inspect_signature(bytes.hex)
assert sig is not None
assert (
str(mypy.stubtest.Signature.from_inspect_signature(sig))
== "def (self, sep = ..., bytes_per_sep = ...)"
)

def test_config_file(self) -> None:
runtime = "temp = 5\n"
stub = "from decimal import Decimal\ntemp: Decimal\n"
Expand Down

0 comments on commit 706389d

Please sign in to comment.