Skip to content

Commit a2dee23

Browse files
committed
Move some functions from checkmember to typeops
1 parent 34e8c7c commit a2dee23

File tree

5 files changed

+110
-113
lines changed

5 files changed

+110
-113
lines changed

mypy/checker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
analyze_decorator_or_funcbase_access,
1818
analyze_descriptor_access,
1919
analyze_member_access,
20-
type_object_type,
2120
)
2221
from mypy.checkpattern import PatternChecker
2322
from mypy.constraints import SUPERTYPE_OF
@@ -168,6 +167,7 @@
168167
try_getting_str_literals,
169168
try_getting_str_literals_from_type,
170169
tuple_fallback,
170+
type_object_type,
171171
)
172172
from mypy.types import (
173173
ANY_STRATEGY,

mypy/checkexpr.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@
1515
import mypy.errorcodes as codes
1616
from mypy import applytype, erasetype, join, message_registry, nodes, operators, types
1717
from mypy.argmap import ArgTypeExpander, map_actuals_to_formals, map_formals_to_actuals
18-
from mypy.checkmember import (
19-
analyze_member_access,
20-
freeze_all_type_vars,
21-
type_object_type,
22-
typeddict_callable,
23-
)
18+
from mypy.checkmember import analyze_member_access, typeddict_callable
2419
from mypy.checkstrformat import StringFormatterChecker
2520
from mypy.erasetype import erase_type, remove_instance_last_known_values, replace_meta_vars
2621
from mypy.errors import ErrorWatcher, report_internal_error
@@ -138,6 +133,7 @@
138133
erase_to_union_or_bound,
139134
false_only,
140135
fixup_partial_type,
136+
freeze_all_type_vars,
141137
function_type,
142138
get_all_type_vars,
143139
get_type_vars,
@@ -148,6 +144,7 @@
148144
try_expanding_sum_type_to_union,
149145
try_getting_str_literals,
150146
tuple_fallback,
147+
type_object_type,
151148
)
152149
from mypy.types import (
153150
LITERAL_TYPE_NAMES,

mypy/checkmember.py

Lines changed: 2 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from mypy.nodes import (
1818
ARG_POS,
1919
ARG_STAR,
20-
ARG_STAR2,
2120
EXCLUDED_ENUM_ATTRIBUTES,
2221
SYMBOL_FUNCBASE_TYPES,
2322
ArgKind,
@@ -41,14 +40,14 @@
4140
from mypy.plugin import AttributeContext
4241
from mypy.typeops import (
4342
bind_self,
44-
class_callable,
4543
erase_to_bound,
44+
freeze_all_type_vars,
4645
function_type,
4746
get_type_vars,
4847
make_simplified_union,
4948
supported_self_type,
5049
tuple_fallback,
51-
type_object_type_from_function,
50+
type_object_type,
5251
)
5352
from mypy.types import (
5453
AnyType,
@@ -73,7 +72,6 @@
7372
UnionType,
7473
get_proper_type,
7574
)
76-
from mypy.typetraverser import TypeTraverserVisitor
7775

7876
if TYPE_CHECKING: # import for forward declaration only
7977
import mypy.checker
@@ -887,17 +885,6 @@ def expand_self_type_if_needed(
887885
return t
888886

889887

890-
def freeze_all_type_vars(member_type: Type) -> None:
891-
member_type.accept(FreezeTypeVarsVisitor())
892-
893-
894-
class FreezeTypeVarsVisitor(TypeTraverserVisitor):
895-
def visit_callable_type(self, t: CallableType) -> None:
896-
for v in t.variables:
897-
v.id.meta_level = 0
898-
super().visit_callable_type(t)
899-
900-
901888
def lookup_member_var_or_accessor(info: TypeInfo, name: str, is_lvalue: bool) -> SymbolNode | None:
902889
"""Find the attribute/accessor node that refers to a member of a type."""
903890
# TODO handle lvalues
@@ -1335,77 +1322,6 @@ def typeddict_callable(info: TypeInfo, named_type: Callable[[str], Instance]) ->
13351322
)
13361323

13371324

1338-
def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> ProperType:
1339-
"""Return the type of a type object.
1340-
1341-
For a generic type G with type variables T and S the type is generally of form
1342-
1343-
Callable[..., G[T, S]]
1344-
1345-
where ... are argument types for the __init__/__new__ method (without the self
1346-
argument). Also, the fallback type will be 'type' instead of 'function'.
1347-
"""
1348-
1349-
# We take the type from whichever of __init__ and __new__ is first
1350-
# in the MRO, preferring __init__ if there is a tie.
1351-
init_method = info.get("__init__")
1352-
new_method = info.get("__new__")
1353-
if not init_method or not is_valid_constructor(init_method.node):
1354-
# Must be an invalid class definition.
1355-
return AnyType(TypeOfAny.from_error)
1356-
# There *should* always be a __new__ method except the test stubs
1357-
# lack it, so just copy init_method in that situation
1358-
new_method = new_method or init_method
1359-
if not is_valid_constructor(new_method.node):
1360-
# Must be an invalid class definition.
1361-
return AnyType(TypeOfAny.from_error)
1362-
1363-
# The two is_valid_constructor() checks ensure this.
1364-
assert isinstance(new_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
1365-
assert isinstance(init_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
1366-
1367-
init_index = info.mro.index(init_method.node.info)
1368-
new_index = info.mro.index(new_method.node.info)
1369-
1370-
fallback = info.metaclass_type or named_type("builtins.type")
1371-
if init_index < new_index:
1372-
method: FuncBase | Decorator = init_method.node
1373-
is_new = False
1374-
elif init_index > new_index:
1375-
method = new_method.node
1376-
is_new = True
1377-
else:
1378-
if init_method.node.info.fullname == "builtins.object":
1379-
# Both are defined by object. But if we've got a bogus
1380-
# base class, we can't know for sure, so check for that.
1381-
if info.fallback_to_any:
1382-
# Construct a universal callable as the prototype.
1383-
any_type = AnyType(TypeOfAny.special_form)
1384-
sig = CallableType(
1385-
arg_types=[any_type, any_type],
1386-
arg_kinds=[ARG_STAR, ARG_STAR2],
1387-
arg_names=["_args", "_kwds"],
1388-
ret_type=any_type,
1389-
fallback=named_type("builtins.function"),
1390-
)
1391-
return class_callable(sig, info, fallback, None, is_new=False)
1392-
1393-
# Otherwise prefer __init__ in a tie. It isn't clear that this
1394-
# is the right thing, but __new__ caused problems with
1395-
# typeshed (#5647).
1396-
method = init_method.node
1397-
is_new = False
1398-
# Construct callable type based on signature of __init__. Adjust
1399-
# return type and insert type arguments.
1400-
if isinstance(method, FuncBase):
1401-
t = function_type(method, fallback)
1402-
else:
1403-
assert isinstance(method.type, ProperType)
1404-
assert isinstance(method.type, FunctionLike) # is_valid_constructor() ensures this
1405-
t = method.type
1406-
return type_object_type_from_function(t, info, method.info, fallback, is_new)
1407-
1408-
14091325
def analyze_decorator_or_funcbase_access(
14101326
defn: Decorator | FuncBase, itype: Instance, name: str, mx: MemberContext
14111327
) -> Type:
@@ -1419,16 +1335,3 @@ def analyze_decorator_or_funcbase_access(
14191335
return bind_self(
14201336
function_type(defn, mx.chk.named_type("builtins.function")), original_type=mx.self_type
14211337
)
1422-
1423-
1424-
def is_valid_constructor(n: SymbolNode | None) -> bool:
1425-
"""Does this node represents a valid constructor method?
1426-
1427-
This includes normal functions, overloaded functions, and decorators
1428-
that return a callable type.
1429-
"""
1430-
if isinstance(n, SYMBOL_FUNCBASE_TYPES):
1431-
return True
1432-
if isinstance(n, Decorator):
1433-
return isinstance(get_proper_type(n.type), FunctionLike)
1434-
return False

mypy/plugins/attrs.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@
5656
)
5757
from mypy.server.trigger import make_wildcard_trigger
5858
from mypy.state import state
59-
from mypy.typeops import get_type_vars, make_simplified_union, map_type_from_supertype
59+
from mypy.typeops import (
60+
get_type_vars,
61+
make_simplified_union,
62+
map_type_from_supertype,
63+
type_object_type,
64+
)
6065
from mypy.types import (
6166
AnyType,
6267
CallableType,
@@ -726,8 +731,6 @@ def _parse_converter(
726731
):
727732
converter_type = converter_expr.node.type
728733
elif isinstance(converter_expr.node, TypeInfo):
729-
from mypy.checkmember import type_object_type # To avoid import cycle.
730-
731734
converter_type = type_object_type(converter_expr.node, ctx.api.named_type)
732735
elif (
733736
isinstance(converter_expr, IndexExpr)
@@ -736,8 +739,6 @@ def _parse_converter(
736739
and isinstance(converter_expr.base.node, TypeInfo)
737740
):
738741
# The converter is a generic type.
739-
from mypy.checkmember import type_object_type # To avoid import cycle.
740-
741742
converter_type = type_object_type(converter_expr.base.node, ctx.api.named_type)
742743
if isinstance(converter_type, CallableType):
743744
converter_type = apply_generic_arguments(

mypy/typeops.py

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import itertools
1111
from collections.abc import Iterable, Sequence
12-
from typing import Any, TypeVar, cast
12+
from typing import Any, Callable, TypeVar, cast
1313

1414
from mypy.copytype import copy_type
1515
from mypy.expandtype import expand_type, expand_type_by_instance
@@ -27,6 +27,7 @@
2727
FuncItem,
2828
OverloadedFuncDef,
2929
StrExpr,
30+
SymbolNode,
3031
TypeInfo,
3132
Var,
3233
)
@@ -63,6 +64,7 @@
6364
get_proper_type,
6465
get_proper_types,
6566
)
67+
from mypy.typetraverser import TypeTraverserVisitor
6668
from mypy.typevars import fill_typevars
6769

6870

@@ -132,6 +134,90 @@ def get_self_type(func: CallableType, default_self: Instance | TupleType) -> Typ
132134
return None
133135

134136

137+
def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> ProperType:
138+
"""Return the type of a type object.
139+
140+
For a generic type G with type variables T and S the type is generally of form
141+
142+
Callable[..., G[T, S]]
143+
144+
where ... are argument types for the __init__/__new__ method (without the self
145+
argument). Also, the fallback type will be 'type' instead of 'function'.
146+
"""
147+
148+
# We take the type from whichever of __init__ and __new__ is first
149+
# in the MRO, preferring __init__ if there is a tie.
150+
init_method = info.get("__init__")
151+
new_method = info.get("__new__")
152+
if not init_method or not is_valid_constructor(init_method.node):
153+
# Must be an invalid class definition.
154+
return AnyType(TypeOfAny.from_error)
155+
# There *should* always be a __new__ method except the test stubs
156+
# lack it, so just copy init_method in that situation
157+
new_method = new_method or init_method
158+
if not is_valid_constructor(new_method.node):
159+
# Must be an invalid class definition.
160+
return AnyType(TypeOfAny.from_error)
161+
162+
# The two is_valid_constructor() checks ensure this.
163+
assert isinstance(new_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
164+
assert isinstance(init_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
165+
166+
init_index = info.mro.index(init_method.node.info)
167+
new_index = info.mro.index(new_method.node.info)
168+
169+
fallback = info.metaclass_type or named_type("builtins.type")
170+
if init_index < new_index:
171+
method: FuncBase | Decorator = init_method.node
172+
is_new = False
173+
elif init_index > new_index:
174+
method = new_method.node
175+
is_new = True
176+
else:
177+
if init_method.node.info.fullname == "builtins.object":
178+
# Both are defined by object. But if we've got a bogus
179+
# base class, we can't know for sure, so check for that.
180+
if info.fallback_to_any:
181+
# Construct a universal callable as the prototype.
182+
any_type = AnyType(TypeOfAny.special_form)
183+
sig = CallableType(
184+
arg_types=[any_type, any_type],
185+
arg_kinds=[ARG_STAR, ARG_STAR2],
186+
arg_names=["_args", "_kwds"],
187+
ret_type=any_type,
188+
fallback=named_type("builtins.function"),
189+
)
190+
return class_callable(sig, info, fallback, None, is_new=False)
191+
192+
# Otherwise prefer __init__ in a tie. It isn't clear that this
193+
# is the right thing, but __new__ caused problems with
194+
# typeshed (#5647).
195+
method = init_method.node
196+
is_new = False
197+
# Construct callable type based on signature of __init__. Adjust
198+
# return type and insert type arguments.
199+
if isinstance(method, FuncBase):
200+
t = function_type(method, fallback)
201+
else:
202+
assert isinstance(method.type, ProperType)
203+
assert isinstance(method.type, FunctionLike) # is_valid_constructor() ensures this
204+
t = method.type
205+
return type_object_type_from_function(t, info, method.info, fallback, is_new)
206+
207+
208+
def is_valid_constructor(n: SymbolNode | None) -> bool:
209+
"""Does this node represents a valid constructor method?
210+
211+
This includes normal functions, overloaded functions, and decorators
212+
that return a callable type.
213+
"""
214+
if isinstance(n, SYMBOL_FUNCBASE_TYPES):
215+
return True
216+
if isinstance(n, Decorator):
217+
return isinstance(get_proper_type(n.type), FunctionLike)
218+
return False
219+
220+
135221
def type_object_type_from_function(
136222
signature: FunctionLike, info: TypeInfo, def_info: TypeInfo, fallback: Instance, is_new: bool
137223
) -> FunctionLike:
@@ -1070,6 +1156,17 @@ def visit_type_var_tuple(self, t: TypeVarTupleType) -> list[TypeVarLikeType]:
10701156
return [t] if self.include_all else []
10711157

10721158

1159+
def freeze_all_type_vars(member_type: Type) -> None:
1160+
member_type.accept(FreezeTypeVarsVisitor())
1161+
1162+
1163+
class FreezeTypeVarsVisitor(TypeTraverserVisitor):
1164+
def visit_callable_type(self, t: CallableType) -> None:
1165+
for v in t.variables:
1166+
v.id.meta_level = 0
1167+
super().visit_callable_type(t)
1168+
1169+
10731170
def custom_special_method(typ: Type, name: str, check_all: bool = False) -> bool:
10741171
"""Does this type have a custom special method such as __format__() or __eq__()?
10751172
@@ -1152,7 +1249,6 @@ def get_protocol_member(
11521249
) -> Type | None:
11531250
if member == "__call__" and class_obj:
11541251
# Special case: class objects always have __call__ that is just the constructor.
1155-
from mypy.checkmember import type_object_type
11561252

11571253
def named_type(fullname: str) -> Instance:
11581254
return Instance(left.type.mro[-1], [])

0 commit comments

Comments
 (0)