5
5
from contextlib import contextmanager
6
6
7
7
from typing import (
8
- Dict , Set , List , cast , Tuple , TypeVar , Union , Optional , NamedTuple , Iterator
8
+ Dict , Set , List , cast , Tuple , TypeVar , Union , Optional , NamedTuple , Iterator , MutableMapping
9
9
)
10
10
11
11
from mypy .errors import Errors , report_internal_error
@@ -2588,6 +2588,20 @@ def or_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
2588
2588
return result
2589
2589
2590
2590
2591
+ def convert_to_types (m : MutableMapping [Expression , Type ]) -> None :
2592
+ for k in m :
2593
+ x = m [k ]
2594
+ if isinstance (x , UnionType ):
2595
+ m [k ] = UnionType ([TypeType (t ) for t in x .items ])
2596
+ elif isinstance (x , Instance ):
2597
+ m [k ] = TypeType (m [k ])
2598
+ else :
2599
+ # TODO: verify this is ok
2600
+ # unknown object, don't know how to convert
2601
+ m .clear ()
2602
+ return
2603
+
2604
+
2591
2605
def find_isinstance_check (node : Expression ,
2592
2606
type_map : Dict [Expression , Type ],
2593
2607
) -> Tuple [TypeMap , TypeMap ]:
@@ -2613,6 +2627,22 @@ def find_isinstance_check(node: Expression,
2613
2627
vartype = type_map [expr ]
2614
2628
type = get_isinstance_type (node .args [1 ], type_map )
2615
2629
return conditional_type_map (expr , vartype , type )
2630
+ elif refers_to_fullname (node .callee , 'builtins.issubclass' ):
2631
+ expr = node .args [0 ]
2632
+ if expr .literal == LITERAL_TYPE :
2633
+ vartype = type_map [expr ]
2634
+ type = get_issubclass_type (node .args [1 ], type_map )
2635
+ if isinstance (vartype , UnionType ):
2636
+ vartype = UnionType ([t .item for t in vartype .items ]) # type: ignore
2637
+ elif isinstance (vartype , TypeType ):
2638
+ vartype = vartype .item
2639
+ else :
2640
+ # TODO: verify this is ok
2641
+ return {}, {} # unknown type
2642
+ yes_map , no_map = conditional_type_map (expr , vartype , type )
2643
+ convert_to_types (yes_map )
2644
+ convert_to_types (no_map )
2645
+ return yes_map , no_map
2616
2646
elif refers_to_fullname (node .callee , 'builtins.callable' ):
2617
2647
expr = node .args [0 ]
2618
2648
if expr .literal == LITERAL_TYPE :
@@ -2716,6 +2746,30 @@ def get_isinstance_type(expr: Expression, type_map: Dict[Expression, Type]) -> T
2716
2746
return UnionType (types )
2717
2747
2718
2748
2749
+ def get_issubclass_type (expr : Expression , type_map : Dict [Expression , Type ]) -> Type :
2750
+ all_types = [type_map [e ] for e in flatten (expr )]
2751
+
2752
+ types = [] # type: List[Type]
2753
+
2754
+ for type in all_types :
2755
+ if isinstance (type , FunctionLike ):
2756
+ if type .is_type_obj ():
2757
+ # Type variables may be present -- erase them, which is the best
2758
+ # we can do (outside disallowing them here).
2759
+ type = erase_typevars (type .items ()[0 ].ret_type )
2760
+ types .append (type )
2761
+ elif isinstance (type , TypeType ):
2762
+ types .append (type .item )
2763
+ else : # we didn't see an actual type, but rather a variable whose value is unknown to us
2764
+ return None
2765
+
2766
+ assert len (types ) != 0
2767
+ if len (types ) == 1 :
2768
+ return types [0 ]
2769
+ else :
2770
+ return UnionType (types )
2771
+
2772
+
2719
2773
def expand_func (defn : FuncItem , map : Dict [TypeVarId , Type ]) -> FuncItem :
2720
2774
visitor = TypeTransformVisitor (map )
2721
2775
ret = defn .accept (visitor )
0 commit comments