Skip to content

Commit c5ff475

Browse files
Michael0x2agvanrossum
authored andcommitted
Make type function return Type[T] (#1787)
1 parent e7e9c4a commit c5ff475

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

mypy/checkexpr.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ def check_call(self, callee: Type, args: List[Node],
251251
self.check_argument_types(arg_types, arg_kinds, callee,
252252
formal_to_actual, context,
253253
messages=arg_messages)
254+
255+
if (callee.is_type_obj() and (len(arg_types) == 1)
256+
and is_equivalent(callee.ret_type, self.named_type('builtins.type'))):
257+
callee = callee.copy_modified(ret_type=TypeType(arg_types[0]))
258+
254259
if callable_node:
255260
# Store the inferred callable type.
256261
self.chk.store_type(callable_node, callee)

test-data/unit/check-classes.test

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,8 +1818,10 @@ def f(a: Type[User]) -> None: pass
18181818
@overload
18191819
def f(a: int) -> None: pass
18201820

1821+
def mock() -> type: return User
1822+
18211823
f(User)
1822-
f(type(User)) # E: No overload variant of "f" matches argument types [builtins.type]
1824+
f(mock()) # E: No overload variant of "f" matches argument types [builtins.type]
18231825
[builtins fixtures/classmethod.py]
18241826
[out]
18251827

@@ -1948,3 +1950,59 @@ def f(a: object) -> str: pass
19481950
[builtins fixtures/classmethod.py]
19491951
[out]
19501952

1953+
[case testTypeConstructorReturnsTypeType]
1954+
class User:
1955+
@classmethod
1956+
def test_class_method(cls) -> int: pass
1957+
@staticmethod
1958+
def test_static_method() -> str: pass
1959+
def test_instance_method(self) -> None: pass
1960+
1961+
u = User()
1962+
1963+
reveal_type(type(u)) # E: Revealed type is 'Type[__main__.User]'
1964+
reveal_type(type(u).test_class_method()) # E: Revealed type is 'builtins.int'
1965+
reveal_type(type(u).test_static_method()) # E: Revealed type is 'builtins.str'
1966+
type(u).test_instance_method() # E: Too few arguments for "test_instance_method" of "User"
1967+
[builtins fixtures/classmethod.py]
1968+
[out]
1969+
1970+
[case testObfuscatedTypeConstructorReturnsTypeType]
1971+
from typing import TypeVar
1972+
class User: pass
1973+
1974+
f1 = type
1975+
1976+
A = TypeVar('A')
1977+
def f2(func: A) -> A:
1978+
return func
1979+
1980+
u = User()
1981+
1982+
reveal_type(f1(u)) # E: Revealed type is 'Type[__main__.User]'
1983+
reveal_type(f2(type)(u)) # E: Revealed type is 'Type[__main__.User]'
1984+
[builtins fixtures/classmethod.py]
1985+
[out]
1986+
1987+
[case testTypeConstructorLookalikeFails]
1988+
class User: pass
1989+
1990+
def fake1(a: object) -> type:
1991+
return User
1992+
def fake2(a: int) -> type:
1993+
return User
1994+
1995+
reveal_type(type(User())) # E: Revealed type is 'Type[__main__.User]'
1996+
reveal_type(fake1(User())) # E: Revealed type is 'builtins.type'
1997+
reveal_type(fake2(3)) # E: Revealed type is 'builtins.type'
1998+
[builtins fixtures/classmethod.py]
1999+
[out]
2000+
2001+
[case testOtherTypeConstructorsSucceed]
2002+
def foo(self) -> int: return self.attr
2003+
2004+
User = type('User', (object,), {'foo': foo, 'attr': 3})
2005+
reveal_type(User) # E: Revealed type is 'builtins.type'
2006+
[builtins fixtures/args.py]
2007+
[out]
2008+

test-data/unit/fixtures/args.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Builtins stub used to support *args, **kwargs.
22

3-
from typing import TypeVar, Generic, Iterable
3+
from typing import TypeVar, Generic, Iterable, Tuple, Dict, Any, overload
44

55
Tco = TypeVar('Tco', covariant=True)
66
T = TypeVar('T')
@@ -9,7 +9,12 @@
99
class object:
1010
def __init__(self) -> None: pass
1111

12-
class type: pass
12+
class type:
13+
@overload
14+
def __init__(self, o: object) -> None: pass
15+
@overload
16+
def __init__(self, name: str, bases: Tuple[type, ...], dict: Dict[str, Any]) -> None: pass
17+
1318
class tuple(Iterable[Tco], Generic[Tco]): pass
1419
class dict(Generic[T, S]): pass
1520

test-data/unit/fixtures/classmethod.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ def mro(self) -> typing.Any: pass
99

1010
class function: pass
1111

12-
classmethod = object() # Dummy definition.
12+
# Dummy definitions.
13+
classmethod = object()
14+
staticmethod = object()
1315

1416
class int:
1517
@classmethod

0 commit comments

Comments
 (0)