Skip to content

Commit cd422e0

Browse files
ilevkivskyihauntsaninjapre-commit-ci[bot]
authored
Move some functions from checkmember to typeops (#18820)
There is no reason for these functions to be there. This actually allows removing some function-level imports. This is a pure refactoring so I am not waiting for a review. --------- Co-authored-by: Shantanu <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 60f00f3 commit cd422e0

File tree

5 files changed

+110
-114
lines changed

5 files changed

+110
-114
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 & 100 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,
@@ -29,7 +28,6 @@
2928
MypyFile,
3029
NameExpr,
3130
OverloadedFuncDef,
32-
SymbolNode,
3331
SymbolTable,
3432
TempNode,
3533
TypeAlias,
@@ -41,14 +39,14 @@
4139
from mypy.plugin import AttributeContext
4240
from mypy.typeops import (
4341
bind_self,
44-
class_callable,
4542
erase_to_bound,
43+
freeze_all_type_vars,
4644
function_type,
4745
get_type_vars,
4846
make_simplified_union,
4947
supported_self_type,
5048
tuple_fallback,
51-
type_object_type_from_function,
49+
type_object_type,
5250
)
5351
from mypy.types import (
5452
AnyType,
@@ -73,7 +71,6 @@
7371
UnionType,
7472
get_proper_type,
7573
)
76-
from mypy.typetraverser import TypeTraverserVisitor
7774

7875
if TYPE_CHECKING: # import for forward declaration only
7976
import mypy.checker
@@ -881,17 +878,6 @@ def expand_self_type_if_needed(
881878
return t
882879

883880

884-
def freeze_all_type_vars(member_type: Type) -> None:
885-
member_type.accept(FreezeTypeVarsVisitor())
886-
887-
888-
class FreezeTypeVarsVisitor(TypeTraverserVisitor):
889-
def visit_callable_type(self, t: CallableType) -> None:
890-
for v in t.variables:
891-
v.id.meta_level = 0
892-
super().visit_callable_type(t)
893-
894-
895881
def check_self_arg(
896882
functype: FunctionLike,
897883
dispatched_arg_type: Type,
@@ -1319,77 +1305,6 @@ def typeddict_callable(info: TypeInfo, named_type: Callable[[str], Instance]) ->
13191305
)
13201306

13211307

1322-
def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> ProperType:
1323-
"""Return the type of a type object.
1324-
1325-
For a generic type G with type variables T and S the type is generally of form
1326-
1327-
Callable[..., G[T, S]]
1328-
1329-
where ... are argument types for the __init__/__new__ method (without the self
1330-
argument). Also, the fallback type will be 'type' instead of 'function'.
1331-
"""
1332-
1333-
# We take the type from whichever of __init__ and __new__ is first
1334-
# in the MRO, preferring __init__ if there is a tie.
1335-
init_method = info.get("__init__")
1336-
new_method = info.get("__new__")
1337-
if not init_method or not is_valid_constructor(init_method.node):
1338-
# Must be an invalid class definition.
1339-
return AnyType(TypeOfAny.from_error)
1340-
# There *should* always be a __new__ method except the test stubs
1341-
# lack it, so just copy init_method in that situation
1342-
new_method = new_method or init_method
1343-
if not is_valid_constructor(new_method.node):
1344-
# Must be an invalid class definition.
1345-
return AnyType(TypeOfAny.from_error)
1346-
1347-
# The two is_valid_constructor() checks ensure this.
1348-
assert isinstance(new_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
1349-
assert isinstance(init_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
1350-
1351-
init_index = info.mro.index(init_method.node.info)
1352-
new_index = info.mro.index(new_method.node.info)
1353-
1354-
fallback = info.metaclass_type or named_type("builtins.type")
1355-
if init_index < new_index:
1356-
method: FuncBase | Decorator = init_method.node
1357-
is_new = False
1358-
elif init_index > new_index:
1359-
method = new_method.node
1360-
is_new = True
1361-
else:
1362-
if init_method.node.info.fullname == "builtins.object":
1363-
# Both are defined by object. But if we've got a bogus
1364-
# base class, we can't know for sure, so check for that.
1365-
if info.fallback_to_any:
1366-
# Construct a universal callable as the prototype.
1367-
any_type = AnyType(TypeOfAny.special_form)
1368-
sig = CallableType(
1369-
arg_types=[any_type, any_type],
1370-
arg_kinds=[ARG_STAR, ARG_STAR2],
1371-
arg_names=["_args", "_kwds"],
1372-
ret_type=any_type,
1373-
fallback=named_type("builtins.function"),
1374-
)
1375-
return class_callable(sig, info, fallback, None, is_new=False)
1376-
1377-
# Otherwise prefer __init__ in a tie. It isn't clear that this
1378-
# is the right thing, but __new__ caused problems with
1379-
# typeshed (#5647).
1380-
method = init_method.node
1381-
is_new = False
1382-
# Construct callable type based on signature of __init__. Adjust
1383-
# return type and insert type arguments.
1384-
if isinstance(method, FuncBase):
1385-
t = function_type(method, fallback)
1386-
else:
1387-
assert isinstance(method.type, ProperType)
1388-
assert isinstance(method.type, FunctionLike) # is_valid_constructor() ensures this
1389-
t = method.type
1390-
return type_object_type_from_function(t, info, method.info, fallback, is_new)
1391-
1392-
13931308
def analyze_decorator_or_funcbase_access(
13941309
defn: Decorator | FuncBase, itype: Instance, name: str, mx: MemberContext
13951310
) -> Type:
@@ -1403,16 +1318,3 @@ def analyze_decorator_or_funcbase_access(
14031318
return bind_self(
14041319
function_type(defn, mx.chk.named_type("builtins.function")), original_type=mx.self_type
14051320
)
1406-
1407-
1408-
def is_valid_constructor(n: SymbolNode | None) -> bool:
1409-
"""Does this node represents a valid constructor method?
1410-
1411-
This includes normal functions, overloaded functions, and decorators
1412-
that return a callable type.
1413-
"""
1414-
if isinstance(n, SYMBOL_FUNCBASE_TYPES):
1415-
return True
1416-
if isinstance(n, Decorator):
1417-
return isinstance(get_proper_type(n.type), FunctionLike)
1418-
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)