Skip to content

Commit 3b90486

Browse files
committed
stubgen: handle PEP 604 unions in inspection mode
InspectionStubGenerator.get_type_fullname() did getattr(typ, '__qualname__', typ.__name__), which raised AttributeError for a types.UnionType (PEP 604 'X | Y'), crashing 'stubgen --inspect-mode' on any function whose signature uses the new union syntax. Render a UnionType by joining its members, mapping NoneType to None. Fixes #21689.
1 parent 7a45d25 commit 3b90486

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

mypy/stubgenc.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import keyword
1414
import os.path
1515
from collections.abc import Callable, Mapping
16-
from types import FunctionType, ModuleType
16+
from types import FunctionType, ModuleType, UnionType
1717
from typing import Any
1818

1919
from mypy.fastparse import parse_type_comment
@@ -768,10 +768,16 @@ def generate_property_stub(
768768

769769
rw_properties.append(f"{self._indent}{name}: {inferred_type}")
770770

771-
def get_type_fullname(self, typ: type) -> str:
771+
def get_type_fullname(self, typ: type | UnionType) -> str:
772772
"""Given a type, return a string representation"""
773773
if typ is Any:
774774
return "Any"
775+
if isinstance(typ, UnionType):
776+
# PEP 604 unions (``X | Y``) have no ``__name__`` / ``__qualname__``.
777+
return " | ".join(
778+
"None" if arg is type(None) else self.get_type_fullname(arg)
779+
for arg in typ.__args__
780+
)
775781
typename = getattr(typ, "__qualname__", typ.__name__)
776782
module_name = self.get_obj_module(typ)
777783
if module_name is None:

test-data/unit/stubgen.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ def f(x='foo'): ...
5555
[out]
5656
def f(x: str = ...): ...
5757

58+
[case testInspectUnionType_inspect]
59+
def f(x: int | str) -> float | None: ...
60+
[out]
61+
def f(x: int | str) -> float | None: ...
62+
5863
[case testDefaultArgBytes]
5964
def f(x=b'foo',y=b"what's up",z=b'\xc3\xa0 la une'): ...
6065
[out]

0 commit comments

Comments
 (0)