@@ -2857,6 +2857,18 @@ def _check_generic(cls, parameters, elen):
2857
2857
typing ._check_generic = _check_generic
2858
2858
2859
2859
2860
+ def _has_generic_or_protocol_as_origin () -> bool :
2861
+ try :
2862
+ frame = sys ._getframe (2 )
2863
+ # not all platforms have sys._getframe()
2864
+ except AttributeError :
2865
+ return False # err on the side of leniency
2866
+ else :
2867
+ return frame .f_locals .get ("origin" ) in {
2868
+ typing .Generic , Protocol , typing .Protocol
2869
+ }
2870
+
2871
+
2860
2872
_TYPEVARTUPLE_TYPES = {TypeVarTuple , getattr (typing , "TypeVarTuple" , None )}
2861
2873
2862
2874
@@ -2882,23 +2894,29 @@ def _collect_type_vars(types, typevar_types=None):
2882
2894
if typevar_types is None :
2883
2895
typevar_types = typing .TypeVar
2884
2896
tvars = []
2885
- # required TypeVarLike cannot appear after TypeVarLike with default
2897
+
2898
+ # A required TypeVarLike cannot appear after a TypeVarLike with a default
2899
+ # if it was a direct call to `Generic[]` or `Protocol[]`
2900
+ enforce_default_ordering = _has_generic_or_protocol_as_origin ()
2886
2901
default_encountered = False
2887
- # or after TypeVarTuple
2902
+
2903
+ # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
2888
2904
type_var_tuple_encountered = False
2905
+
2889
2906
for t in types :
2890
2907
if _is_unpacked_typevartuple (t ):
2891
2908
type_var_tuple_encountered = True
2892
2909
elif isinstance (t , typevar_types ) and t not in tvars :
2893
- has_default = getattr (t , '__default__' , NoDefault ) is not NoDefault
2894
- if has_default :
2895
- if type_var_tuple_encountered :
2896
- raise TypeError ('Type parameter with a default'
2897
- ' follows TypeVarTuple' )
2898
- default_encountered = True
2899
- elif default_encountered :
2900
- raise TypeError (f'Type parameter { t !r} without a default'
2901
- ' follows type parameter with a default' )
2910
+ if enforce_default_ordering :
2911
+ has_default = getattr (t , '__default__' , NoDefault ) is not NoDefault
2912
+ if has_default :
2913
+ if type_var_tuple_encountered :
2914
+ raise TypeError ('Type parameter with a default'
2915
+ ' follows TypeVarTuple' )
2916
+ default_encountered = True
2917
+ elif default_encountered :
2918
+ raise TypeError (f'Type parameter { t !r} without a default'
2919
+ ' follows type parameter with a default' )
2902
2920
2903
2921
tvars .append (t )
2904
2922
if _should_collect_from_parameters (t ):
@@ -2916,10 +2934,15 @@ def _collect_parameters(args):
2916
2934
assert _collect_parameters((T, Callable[P, T])) == (T, P)
2917
2935
"""
2918
2936
parameters = []
2919
- # required TypeVarLike cannot appear after TypeVarLike with default
2937
+
2938
+ # A required TypeVarLike cannot appear after a TypeVarLike with default
2939
+ # if it was a direct call to `Generic[]` or `Protocol[]`
2940
+ enforce_default_ordering = _has_generic_or_protocol_as_origin ()
2920
2941
default_encountered = False
2921
- # or after TypeVarTuple
2942
+
2943
+ # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
2922
2944
type_var_tuple_encountered = False
2945
+
2923
2946
for t in args :
2924
2947
if isinstance (t , type ):
2925
2948
# We don't want __parameters__ descriptor of a bare Python class.
@@ -2933,17 +2956,20 @@ def _collect_parameters(args):
2933
2956
parameters .append (collected )
2934
2957
elif hasattr (t , '__typing_subst__' ):
2935
2958
if t not in parameters :
2936
- has_default = getattr (t , '__default__' , NoDefault ) is not NoDefault
2959
+ if enforce_default_ordering :
2960
+ has_default = (
2961
+ getattr (t , '__default__' , NoDefault ) is not NoDefault
2962
+ )
2937
2963
2938
- if type_var_tuple_encountered and has_default :
2939
- raise TypeError ('Type parameter with a default'
2940
- ' follows TypeVarTuple' )
2964
+ if type_var_tuple_encountered and has_default :
2965
+ raise TypeError ('Type parameter with a default'
2966
+ ' follows TypeVarTuple' )
2941
2967
2942
- if has_default :
2943
- default_encountered = True
2944
- elif default_encountered :
2945
- raise TypeError (f'Type parameter { t !r} without a default'
2946
- ' follows type parameter with a default' )
2968
+ if has_default :
2969
+ default_encountered = True
2970
+ elif default_encountered :
2971
+ raise TypeError (f'Type parameter { t !r} without a default'
2972
+ ' follows type parameter with a default' )
2947
2973
2948
2974
parameters .append (t )
2949
2975
else :
0 commit comments