Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Address review, add @classmethod support
  • Loading branch information
sobolevn committed Feb 2, 2022
commit 964dc69416b729505441b923890d84ae324e4d8e
10 changes: 10 additions & 0 deletions Lib/test/ann_module8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Test `@no_type_check`,
# see https://bugs.python.org/issue46571

class NoTypeCheck_Outer:
class Inner:
x: int


def NoTypeCheck_function(arg: int) -> int:
...
37 changes: 37 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2669,6 +2669,18 @@ def test_errors(self):
cast('hello', 42)


# We need this to make sure that `@no_type_check` respects `__module__` attr:
from test import ann_module8

@no_type_check
class NoTypeCheck_Outer:
Inner = ann_module8.NoTypeCheck_Outer.Inner

@no_type_check
class NoTypeCheck_WithFunction:
NoTypeCheck_function = ann_module8.NoTypeCheck_function


class ForwardRefTests(BaseTestCase):

def test_basics(self):
Expand Down Expand Up @@ -3004,6 +3016,30 @@ class D:
not_modified.__no_type_check__
self.assertNotEqual(get_type_hints(not_modified), {})

def test_no_type_check_class_and_static_methods(self):
@no_type_check
class Some:
@staticmethod
def st(x: int) -> int: ...
@classmethod
def cl(cls, y: int) -> int: ...

self.assertTrue(Some.st.__no_type_check__)
self.assertEqual(get_type_hints(Some.st), {})
self.assertTrue(Some.cl.__no_type_check__)
self.assertEqual(get_type_hints(Some.cl), {})

def test_no_type_check_other_module(self):
self.assertTrue(NoTypeCheck_Outer.__no_type_check__)
with self.assertRaises(AttributeError):
ann_module8.NoTypeCheck_Outer.__no_type_check__
with self.assertRaises(AttributeError):
ann_module8.NoTypeCheck_Outer.Inner.__no_type_check__

self.assertTrue(NoTypeCheck_WithFunction.__no_type_check__)
with self.assertRaises(AttributeError):
ann_module8.NoTypeCheck_function.__no_type_check__

def test_no_type_check_foreign_functions(self):
# We should not modify this function:
def some(*args: int) -> int:
Expand All @@ -3017,6 +3053,7 @@ class A:

with self.assertRaises(AttributeError):
some.__no_type_check__
Comment thread
sobolevn marked this conversation as resolved.
self.assertEqual(get_type_hints(some), {'args': int, 'return': int})

def test_no_type_check_lambda(self):
@no_type_check
Expand Down
14 changes: 11 additions & 3 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1959,15 +1959,23 @@ def no_type_check(arg):
This mutates the function(s) or class(es) in place.
"""
if isinstance(arg, type):
for obj in arg.__dict__.values():
if (hasattr(obj, '__qualname__')
and obj.__qualname__ != f'{arg.__qualname__}.{obj.__name__}'):
for key in dir(arg):
obj = getattr(arg, key)
if (
not hasattr(obj, '__qualname__')
or obj.__qualname__ != f'{arg.__qualname__}.{obj.__name__}'
or getattr(obj, '__module__', None) != arg.__module__
):
# We only modify objects that are defined in this type directly.
# If classes / methods are nested in multiple layers,
# we will modify them when processing their direct holders.
continue
# Instance, class, and static methods:
if isinstance(obj, types.FunctionType):
obj.__no_type_check__ = True
if isinstance(obj, types.MethodType):
obj.__func__.__no_type_check__ = True
# Nested types:
if isinstance(obj, type):
no_type_check(obj)
try:
Expand Down