1
1
from collections import OrderedDict
2
2
from typing import (
3
- TYPE_CHECKING , Any , Dict , Iterable , Iterator , List , Optional , Set , Union , cast ,
3
+ TYPE_CHECKING , Any , Dict , Iterable , Iterator , List , Optional , Set , Tuple , Union ,
4
4
)
5
5
6
6
from django .db .models .fields import Field
10
10
from mypy .checker import TypeChecker
11
11
from mypy .mro import calculate_mro
12
12
from mypy .nodes import (
13
- GDEF , MDEF , Block , ClassDef , Expression , MemberExpr , MypyFile , NameExpr , StrExpr , SymbolNode , SymbolTable ,
14
- SymbolTableNode , TypeInfo , Var ,
13
+ GDEF , MDEF , Argument , Block , ClassDef , Expression , FuncDef , MemberExpr , MypyFile , NameExpr , StrExpr , SymbolNode ,
14
+ SymbolTable , SymbolTableNode , TypeInfo , Var ,
15
15
)
16
16
from mypy .plugin import (
17
- AttributeContext , CheckerPluginInterface , FunctionContext , MethodContext ,
17
+ AttributeContext , CheckerPluginInterface , ClassDefContext , DynamicClassDefContext , FunctionContext , MethodContext ,
18
18
)
19
- from mypy .types import AnyType , Instance , NoneTyp , TupleType
19
+ from mypy .plugins .common import add_method
20
+ from mypy .semanal import SemanticAnalyzer
21
+ from mypy .types import AnyType , CallableType , Instance , NoneTyp , TupleType
20
22
from mypy .types import Type as MypyType
21
23
from mypy .types import TypedDictType , TypeOfAny , UnionType
22
24
@@ -55,7 +57,7 @@ def lookup_fully_qualified_generic(name: str, all_modules: Dict[str, MypyFile])
55
57
return sym .node
56
58
57
59
58
- def lookup_fully_qualified_typeinfo (api : TypeChecker , fullname : str ) -> Optional [TypeInfo ]:
60
+ def lookup_fully_qualified_typeinfo (api : Union [ TypeChecker , SemanticAnalyzer ] , fullname : str ) -> Optional [TypeInfo ]:
59
61
node = lookup_fully_qualified_generic (fullname , api .modules )
60
62
if not isinstance (node , TypeInfo ):
61
63
return None
@@ -173,8 +175,11 @@ def get_nested_meta_node_for_current_class(info: TypeInfo) -> Optional[TypeInfo]
173
175
return None
174
176
175
177
176
- def add_new_class_for_module (module : MypyFile , name : str , bases : List [Instance ],
177
- fields : 'OrderedDict[str, MypyType]' ) -> TypeInfo :
178
+ def add_new_class_for_module (module : MypyFile ,
179
+ name : str ,
180
+ bases : List [Instance ],
181
+ fields : Optional [Dict [str , MypyType ]] = None
182
+ ) -> TypeInfo :
178
183
new_class_unique_name = checker .gen_unique_name (name , module .names )
179
184
180
185
# make new class expression
@@ -188,11 +193,12 @@ def add_new_class_for_module(module: MypyFile, name: str, bases: List[Instance],
188
193
new_typeinfo .calculate_metaclass_type ()
189
194
190
195
# add fields
191
- for field_name , field_type in fields .items ():
192
- var = Var (field_name , type = field_type )
193
- var .info = new_typeinfo
194
- var ._fullname = new_typeinfo .fullname + '.' + field_name
195
- new_typeinfo .names [field_name ] = SymbolTableNode (MDEF , var , plugin_generated = True )
196
+ if fields :
197
+ for field_name , field_type in fields .items ():
198
+ var = Var (field_name , type = field_type )
199
+ var .info = new_typeinfo
200
+ var ._fullname = new_typeinfo .fullname + '.' + field_name
201
+ new_typeinfo .names [field_name ] = SymbolTableNode (MDEF , var , plugin_generated = True )
196
202
197
203
classdef .info = new_typeinfo
198
204
module .names [new_class_unique_name ] = SymbolTableNode (GDEF , new_typeinfo , plugin_generated = True )
@@ -269,10 +275,16 @@ def resolve_string_attribute_value(attr_expr: Expression, ctx: Union[FunctionCon
269
275
return None
270
276
271
277
278
+ def get_semanal_api (ctx : Union [ClassDefContext , DynamicClassDefContext ]) -> SemanticAnalyzer :
279
+ if not isinstance (ctx .api , SemanticAnalyzer ):
280
+ raise ValueError ('Not a SemanticAnalyzer' )
281
+ return ctx .api
282
+
283
+
272
284
def get_typechecker_api (ctx : Union [AttributeContext , MethodContext , FunctionContext ]) -> TypeChecker :
273
285
if not isinstance (ctx .api , TypeChecker ):
274
286
raise ValueError ('Not a TypeChecker' )
275
- return cast ( TypeChecker , ctx .api )
287
+ return ctx .api
276
288
277
289
278
290
def is_model_subclass_info (info : TypeInfo , django_context : 'DjangoContext' ) -> bool :
@@ -298,3 +310,28 @@ def add_new_sym_for_info(info: TypeInfo, *, name: str, sym_type: MypyType) -> No
298
310
var .is_inferred = True
299
311
info .names [name ] = SymbolTableNode (MDEF , var ,
300
312
plugin_generated = True )
313
+
314
+
315
+ def _prepare_new_method_arguments (node : FuncDef ) -> Tuple [List [Argument ], MypyType ]:
316
+ arguments = []
317
+ for argument in node .arguments [1 :]:
318
+ if argument .type_annotation is None :
319
+ argument .type_annotation = AnyType (TypeOfAny .unannotated )
320
+ arguments .append (argument )
321
+
322
+ if isinstance (node .type , CallableType ):
323
+ return_type = node .type .ret_type
324
+ else :
325
+ return_type = AnyType (TypeOfAny .unannotated )
326
+
327
+ return arguments , return_type
328
+
329
+
330
+ def copy_method_to_another_class (ctx : ClassDefContext , self_type : Instance ,
331
+ new_method_name : str , method_node : FuncDef ) -> None :
332
+ arguments , return_type = _prepare_new_method_arguments (method_node )
333
+ add_method (ctx ,
334
+ new_method_name ,
335
+ args = arguments ,
336
+ return_type = return_type ,
337
+ self_type = self_type )
0 commit comments