Skip to content

Commit 706389d

Browse files
stubtest: hack for "<unrepresentable>" defaults (#16433)
See python/cpython#87233
1 parent e81309e commit 706389d

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

mypy/stubtest.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ def __repr__(self) -> str:
5555
T = TypeVar("T")
5656
MaybeMissing: typing_extensions.TypeAlias = Union[T, Missing]
5757

58+
59+
class Unrepresentable:
60+
"""Marker object for unrepresentable parameter defaults."""
61+
62+
def __repr__(self) -> str:
63+
return "<unrepresentable>"
64+
65+
66+
UNREPRESENTABLE: typing_extensions.Final = Unrepresentable()
67+
68+
5869
_formatter: typing_extensions.Final = FancyFormatter(sys.stdout, sys.stderr, False)
5970

6071

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

14841496
def safe_inspect_signature(runtime: Any) -> inspect.Signature | None:
14851497
try:
1486-
return inspect.signature(runtime)
1498+
try:
1499+
return inspect.signature(runtime)
1500+
except ValueError:
1501+
if (
1502+
hasattr(runtime, "__text_signature__")
1503+
and "<unrepresentable>" in runtime.__text_signature__
1504+
):
1505+
# Try to fix up the signature. Workaround for
1506+
# https://github.com/python/cpython/issues/87233
1507+
sig = runtime.__text_signature__.replace("<unrepresentable>", "...")
1508+
sig = inspect._signature_fromstr(inspect.Signature, runtime, sig) # type: ignore[attr-defined]
1509+
assert isinstance(sig, inspect.Signature)
1510+
new_params = [
1511+
parameter.replace(default=UNREPRESENTABLE)
1512+
if parameter.default is ...
1513+
else parameter
1514+
for parameter in sig.parameters.values()
1515+
]
1516+
return sig.replace(parameters=new_params)
1517+
else:
1518+
raise
14871519
except Exception:
14881520
# inspect.signature throws ValueError all the time
14891521
# catch RuntimeError because of https://bugs.python.org/issue39504

mypy/test/teststubtest.py

+18
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,16 @@ def test_default_value(self) -> Iterator[Case]:
428428
error=None,
429429
)
430430

431+
# Simulate "<unrepresentable>"
432+
yield Case(
433+
stub="def f11() -> None: ...",
434+
runtime="""
435+
def f11(text=None) -> None: pass
436+
f11.__text_signature__ = "(text=<unrepresentable>)"
437+
""",
438+
error="f11",
439+
)
440+
431441
@collect_cases
432442
def test_static_class_method(self) -> Iterator[Case]:
433443
yield Case(
@@ -2281,6 +2291,14 @@ def f(a: int, b: int, *, c: int, d: int = 0, **kwargs: Any) -> None:
22812291
== "def (a, b, *, c, d = ..., **kwargs)"
22822292
)
22832293

2294+
def test_builtin_signature_with_unrepresentable_default(self) -> None:
2295+
sig = mypy.stubtest.safe_inspect_signature(bytes.hex)
2296+
assert sig is not None
2297+
assert (
2298+
str(mypy.stubtest.Signature.from_inspect_signature(sig))
2299+
== "def (self, sep = ..., bytes_per_sep = ...)"
2300+
)
2301+
22842302
def test_config_file(self) -> None:
22852303
runtime = "temp = 5\n"
22862304
stub = "from decimal import Decimal\ntemp: Decimal\n"

0 commit comments

Comments
 (0)