Skip to content

Commit e8147f2

Browse files
[stubtest] Allow runtime-existing aliases of types marked as @type_check_only (#19568)
In typeshed, there's a few cases of stubs like this: ```python class _DoesNotExist: ... # does not exist at runtime if sys.version_info >= (3, X): Exists = _DoesNotExist ``` Ideally, it would be nice to mark `_DoesNotExit` as `@type_check_only` to make it clear that this type isn't available at runtime. However, this currently can't be done, because doing so will make stubtest think that `Exists` is also `@type_check_only`, which sets off alarm bells due to `Exists` being available at runtime. This PR makes it so stubtest doesn't consider `@type_check_only`-status when checking type alias targets, making it possible to mark types like the above as `@type_check_only`.
1 parent c5a4efe commit e8147f2

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

mypy/stubtest.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,13 @@ def _verify_metaclass(
506506

507507
@verify.register(nodes.TypeInfo)
508508
def verify_typeinfo(
509-
stub: nodes.TypeInfo, runtime: MaybeMissing[type[Any]], object_path: list[str]
509+
stub: nodes.TypeInfo,
510+
runtime: MaybeMissing[type[Any]],
511+
object_path: list[str],
512+
*,
513+
is_alias_target: bool = False,
510514
) -> Iterator[Error]:
511-
if stub.is_type_check_only:
515+
if stub.is_type_check_only and not is_alias_target:
512516
# This type only exists in stubs, we only check that the runtime part
513517
# is missing. Other checks are not required.
514518
if not isinstance(runtime, Missing):
@@ -1449,7 +1453,7 @@ def verify_typealias(
14491453
# Okay, either we couldn't construct a fullname
14501454
# or the fullname of the stub didn't match the fullname of the runtime.
14511455
# Fallback to a full structural check of the runtime vis-a-vis the stub.
1452-
yield from verify(stub_origin, runtime_origin, object_path)
1456+
yield from verify_typeinfo(stub_origin, runtime_origin, object_path, is_alias_target=True)
14531457
return
14541458
if isinstance(stub_target, mypy.types.UnionType):
14551459
# complain if runtime is not a Union or UnionType

mypy/test/teststubtest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,6 +2472,17 @@ def func2() -> None: ...
24722472
runtime="def func2() -> None: ...",
24732473
error="func2",
24742474
)
2475+
# A type that exists at runtime is allowed to alias a type marked
2476+
# as '@type_check_only' in the stubs.
2477+
yield Case(
2478+
stub="""
2479+
@type_check_only
2480+
class _X1: ...
2481+
X2 = _X1
2482+
""",
2483+
runtime="class X2: ...",
2484+
error=None,
2485+
)
24752486

24762487

24772488
def remove_color_code(s: str) -> str:

0 commit comments

Comments
 (0)