82
82
ParamSpecKwargsValue ,
83
83
ParameterTypeGuardExtension ,
84
84
SelfTVV ,
85
+ SequenceValue ,
85
86
TypeGuardExtension ,
86
87
TypedValue ,
87
88
SequenceIncompleteValue ,
@@ -344,14 +345,26 @@ def value_from_ast(
344
345
return val
345
346
346
347
347
- def _type_from_ast (node : ast .AST , ctx : Context , is_typeddict : bool = False ) -> Value :
348
+ def _type_from_ast (
349
+ node : ast .AST ,
350
+ ctx : Context ,
351
+ * ,
352
+ is_typeddict : bool = False ,
353
+ unpack_allowed : bool = False ,
354
+ ) -> Value :
348
355
val = value_from_ast (node , ctx )
349
- return _type_from_value (val , ctx , is_typeddict = is_typeddict )
356
+ return _type_from_value (
357
+ val , ctx , is_typeddict = is_typeddict , unpack_allowed = unpack_allowed
358
+ )
350
359
351
360
352
- def _type_from_runtime (val : Any , ctx : Context , is_typeddict : bool = False ) -> Value :
361
+ def _type_from_runtime (
362
+ val : Any , ctx : Context , * , is_typeddict : bool = False , unpack_allowed : bool = False
363
+ ) -> Value :
353
364
if isinstance (val , str ):
354
- return _eval_forward_ref (val , ctx , is_typeddict = is_typeddict )
365
+ return _eval_forward_ref (
366
+ val , ctx , is_typeddict = is_typeddict , unpack_allowed = unpack_allowed
367
+ )
355
368
elif isinstance (val , tuple ):
356
369
# This happens under some Python versions for types
357
370
# nested in tuples, e.g. on 3.6:
@@ -365,13 +378,17 @@ def _type_from_runtime(val: Any, ctx: Context, is_typeddict: bool = False) -> Va
365
378
args = (val [1 ],)
366
379
else :
367
380
args = val [1 :]
368
- return _value_of_origin_args (origin , args , val , ctx )
381
+ return _value_of_origin_args (
382
+ origin , args , val , ctx , unpack_allowed = unpack_allowed
383
+ )
369
384
elif GenericAlias is not None and isinstance (val , GenericAlias ):
370
385
origin = get_origin (val )
371
386
args = get_args (val )
372
387
if origin is tuple and not args :
373
388
return SequenceIncompleteValue (tuple , [])
374
- return _value_of_origin_args (origin , args , val , ctx )
389
+ return _value_of_origin_args (
390
+ origin , args , val , ctx , unpack_allowed = origin is tuple
391
+ )
375
392
elif typing_inspect .is_literal_type (val ):
376
393
args = typing_inspect .get_args (val )
377
394
if len (args ) == 0 :
@@ -393,7 +410,17 @@ def _type_from_runtime(val: Any, ctx: Context, is_typeddict: bool = False) -> Va
393
410
elif len (args ) == 1 and args [0 ] == ():
394
411
return SequenceIncompleteValue (tuple , []) # empty tuple
395
412
else :
396
- args_vals = [_type_from_runtime (arg , ctx ) for arg in args ]
413
+ args_vals = [
414
+ _type_from_runtime (arg , ctx , unpack_allowed = True ) for arg in args
415
+ ]
416
+ if any (isinstance (val , UnpackedValue ) for val in args_vals ):
417
+ members = []
418
+ for val in args_vals :
419
+ if isinstance (val , UnpackedValue ):
420
+ members += val .elements
421
+ else :
422
+ members .append ((False , val ))
423
+ return SequenceValue (tuple , members )
397
424
return SequenceIncompleteValue (tuple , args_vals )
398
425
elif is_instance_of_typing_name (val , "_TypedDictMeta" ):
399
426
required_keys = getattr (val , "__required_keys__" , None )
@@ -434,7 +461,14 @@ def _type_from_runtime(val: Any, ctx: Context, is_typeddict: bool = False) -> Va
434
461
args = typing_inspect .get_args (val )
435
462
if getattr (val , "_special" , False ):
436
463
args = [] # distinguish List from List[T] on 3.7 and 3.8
437
- return _value_of_origin_args (origin , args , val , ctx , is_typeddict = is_typeddict )
464
+ return _value_of_origin_args (
465
+ origin ,
466
+ args ,
467
+ val ,
468
+ ctx ,
469
+ is_typeddict = is_typeddict ,
470
+ unpack_allowed = unpack_allowed or origin is tuple or origin is Tuple ,
471
+ )
438
472
elif typing_inspect .is_callable_type (val ):
439
473
args = typing_inspect .get_args (val )
440
474
return _value_of_origin_args (Callable , args , val , ctx )
@@ -535,6 +569,13 @@ def _type_from_runtime(val: Any, ctx: Context, is_typeddict: bool = False) -> Va
535
569
cls = "Required" if required else "NotRequired"
536
570
ctx .show_error (f"{ cls } [] used in unsupported context" )
537
571
return AnyValue (AnySource .error )
572
+ # Also 3.6 only.
573
+ elif is_instance_of_typing_name (val , "_Unpack" ):
574
+ if unpack_allowed :
575
+ return _make_unpacked_value (_type_from_runtime (val .__type__ , ctx ), ctx )
576
+ else :
577
+ ctx .show_error ("Unpack[] used in unsupported context" )
578
+ return AnyValue (AnySource .error )
538
579
elif is_typing_name (val , "TypeAlias" ):
539
580
return AnyValue (AnySource .incomplete_annotation )
540
581
elif is_typing_name (val , "TypedDict" ):
@@ -638,28 +679,51 @@ def _get_typeddict_value(
638
679
return required , val
639
680
640
681
641
- def _eval_forward_ref (val : str , ctx : Context , is_typeddict : bool = False ) -> Value :
682
+ def _eval_forward_ref (
683
+ val : str , ctx : Context , * , is_typeddict : bool = False , unpack_allowed : bool = False
684
+ ) -> Value :
642
685
try :
643
686
tree = ast .parse (val , mode = "eval" )
644
687
except SyntaxError :
645
688
ctx .show_error (f"Syntax error in type annotation: { val } " )
646
689
return AnyValue (AnySource .error )
647
690
else :
648
- return _type_from_ast (tree .body , ctx , is_typeddict = is_typeddict )
691
+ return _type_from_ast (
692
+ tree .body , ctx , is_typeddict = is_typeddict , unpack_allowed = unpack_allowed
693
+ )
649
694
650
695
651
- def _type_from_value (value : Value , ctx : Context , is_typeddict : bool = False ) -> Value :
696
+ def _type_from_value (
697
+ value : Value ,
698
+ ctx : Context ,
699
+ * ,
700
+ is_typeddict : bool = False ,
701
+ unpack_allowed : bool = False ,
702
+ ) -> Value :
652
703
if isinstance (value , KnownValue ):
653
- return _type_from_runtime (value .val , ctx , is_typeddict = is_typeddict )
704
+ return _type_from_runtime (
705
+ value .val , ctx , is_typeddict = is_typeddict , unpack_allowed = unpack_allowed
706
+ )
654
707
elif isinstance (value , TypeVarValue ):
655
708
return value
656
709
elif isinstance (value , MultiValuedValue ):
657
- return unite_values (* [_type_from_value (val , ctx ) for val in value .vals ])
710
+ return unite_values (
711
+ * [
712
+ _type_from_value (
713
+ val , ctx , is_typeddict = is_typeddict , unpack_allowed = unpack_allowed
714
+ )
715
+ for val in value .vals
716
+ ]
717
+ )
658
718
elif isinstance (value , AnnotatedValue ):
659
719
return _type_from_value (value .value , ctx )
660
720
elif isinstance (value , _SubscriptedValue ):
661
721
return _type_from_subscripted_value (
662
- value .root , value .members , ctx , is_typeddict = is_typeddict
722
+ value .root ,
723
+ value .members ,
724
+ ctx ,
725
+ is_typeddict = is_typeddict ,
726
+ unpack_allowed = unpack_allowed ,
663
727
)
664
728
elif isinstance (value , AnyValue ):
665
729
return value
@@ -677,7 +741,9 @@ def _type_from_subscripted_value(
677
741
root : Optional [Value ],
678
742
members : Sequence [Value ],
679
743
ctx : Context ,
744
+ * ,
680
745
is_typeddict : bool = False ,
746
+ unpack_allowed : bool = False ,
681
747
) -> Value :
682
748
if isinstance (root , GenericValue ):
683
749
if len (root .args ) == len (members ):
@@ -690,7 +756,13 @@ def _type_from_subscripted_value(
690
756
elif isinstance (root , MultiValuedValue ):
691
757
return unite_values (
692
758
* [
693
- _type_from_subscripted_value (subval , members , ctx , is_typeddict )
759
+ _type_from_subscripted_value (
760
+ subval ,
761
+ members ,
762
+ ctx ,
763
+ is_typeddict = is_typeddict ,
764
+ unpack_allowed = unpack_allowed ,
765
+ )
694
766
for subval in root .vals
695
767
]
696
768
)
@@ -729,9 +801,16 @@ def _type_from_subscripted_value(
729
801
elif len (members ) == 1 and members [0 ] == KnownValue (()):
730
802
return SequenceIncompleteValue (tuple , [])
731
803
else :
732
- return SequenceIncompleteValue (
733
- tuple , [_type_from_value (arg , ctx ) for arg in members ]
734
- )
804
+ args = [_type_from_value (arg , ctx , unpack_allowed = True ) for arg in members ]
805
+ if any (isinstance (val , UnpackedValue ) for val in args ):
806
+ tuple_members = []
807
+ for val in args :
808
+ if isinstance (val , UnpackedValue ):
809
+ tuple_members += val .elements
810
+ else :
811
+ tuple_members .append ((False , val ))
812
+ return SequenceValue (tuple , tuple_members )
813
+ return SequenceIncompleteValue (tuple , args )
735
814
elif root is typing .Optional :
736
815
if len (members ) != 1 :
737
816
ctx .show_error ("Optional[] takes only one argument" )
@@ -769,6 +848,14 @@ def _type_from_subscripted_value(
769
848
ctx .show_error ("NotRequired[] requires a single argument" )
770
849
return AnyValue (AnySource .error )
771
850
return Pep655Value (False , _type_from_value (members [0 ], ctx ))
851
+ elif is_typing_name (root , "Unpack" ):
852
+ if not unpack_allowed :
853
+ ctx .show_error ("Unpack[] used in unsupported context" )
854
+ return AnyValue (AnySource .error )
855
+ if len (members ) != 1 :
856
+ ctx .show_error ("Unpack requires a single argument" )
857
+ return AnyValue (AnySource .error )
858
+ return _make_unpacked_value (_type_from_value (members [0 ], ctx ), ctx )
772
859
elif root is Callable or root is typing .Callable :
773
860
if len (members ) == 2 :
774
861
args , return_value = members
@@ -877,6 +964,11 @@ class Pep655Value(Value):
877
964
value : Value
878
965
879
966
967
+ @dataclass
968
+ class UnpackedValue (Value ):
969
+ elements : Sequence [Tuple [bool , Value ]]
970
+
971
+
880
972
class _Visitor (ast .NodeVisitor ):
881
973
def __init__ (self , ctx : Context ) -> None :
882
974
self .ctx = ctx
@@ -892,6 +984,12 @@ def visit_Subscript(self, node: ast.Subscript) -> Value:
892
984
index = self .visit (node .slice )
893
985
if isinstance (index , SequenceIncompleteValue ):
894
986
members = index .members
987
+ elif isinstance (index , SequenceValue ):
988
+ members = index .get_member_sequence ()
989
+ if members is None :
990
+ # TODO support unpacking here
991
+ return AnyValue (AnySource .inference )
992
+ members = tuple (members )
895
993
else :
896
994
members = (index ,)
897
995
return _SubscriptedValue (value , members )
@@ -1047,7 +1145,9 @@ def _value_of_origin_args(
1047
1145
args : Sequence [object ],
1048
1146
val : object ,
1049
1147
ctx : Context ,
1148
+ * ,
1050
1149
is_typeddict : bool = False ,
1150
+ unpack_allowed : bool = False ,
1051
1151
) -> Value :
1052
1152
if origin is typing .Type or origin is type :
1053
1153
if not args :
@@ -1061,7 +1161,9 @@ def _value_of_origin_args(
1061
1161
elif len (args ) == 1 and args [0 ] == ():
1062
1162
return SequenceIncompleteValue (tuple , [])
1063
1163
else :
1064
- args_vals = [_type_from_runtime (arg , ctx ) for arg in args ]
1164
+ args_vals = [
1165
+ _type_from_runtime (arg , ctx , unpack_allowed = True ) for arg in args
1166
+ ]
1065
1167
return SequenceIncompleteValue (tuple , args_vals )
1066
1168
elif origin is typing .Union :
1067
1169
return unite_values (* [_type_from_runtime (arg , ctx ) for arg in args ])
@@ -1126,6 +1228,14 @@ def _value_of_origin_args(
1126
1228
ctx .show_error ("NotRequired[] requires a single argument" )
1127
1229
return AnyValue (AnySource .error )
1128
1230
return Pep655Value (False , _type_from_runtime (args [0 ], ctx ))
1231
+ elif is_typing_name (origin , "Unpack" ):
1232
+ if not unpack_allowed :
1233
+ ctx .show_error ("Invalid usage of Unpack" )
1234
+ return AnyValue (AnySource .error )
1235
+ if len (args ) != 1 :
1236
+ ctx .show_error ("Unpack requires a single argument" )
1237
+ return AnyValue (AnySource .error )
1238
+ return _make_unpacked_value (_type_from_runtime (args [0 ], ctx ), ctx )
1129
1239
elif origin is None and isinstance (val , type ):
1130
1240
# This happens for SupportsInt in 3.7.
1131
1241
return _maybe_typed_value (val )
@@ -1144,6 +1254,19 @@ def _maybe_typed_value(val: Union[type, str]) -> Value:
1144
1254
return TypedValue (val )
1145
1255
1146
1256
1257
+ def _make_unpacked_value (val : Value , ctx : Context ) -> UnpackedValue :
1258
+ if isinstance (val , SequenceValue ) and val .typ is tuple :
1259
+ return UnpackedValue (val .members )
1260
+ elif isinstance (val , SequenceIncompleteValue ) and val .typ is tuple :
1261
+ return UnpackedValue ([(False , elt ) for elt in val .members ])
1262
+ elif isinstance (val , GenericValue ) and val .typ is tuple :
1263
+ return UnpackedValue ([(True , val .args [0 ])])
1264
+ elif isinstance (val , TypedValue ) and val .typ is tuple :
1265
+ return UnpackedValue ([(True , AnyValue (AnySource .generic_argument ))])
1266
+ ctx .show_error (f"Invalid argument for Unpack: { val } " )
1267
+ return UnpackedValue ([])
1268
+
1269
+
1147
1270
def _make_callable_from_value (
1148
1271
args : Value , return_value : Value , ctx : Context , is_asynq : bool = False
1149
1272
) -> Value :
0 commit comments