6767 "GEN_CREATED" ,
6868 "GEN_RUNNING" ,
6969 "GEN_SUSPENDED" ,
70+ "MultiSignature" ,
7071 "Parameter" ,
7172 "Signature" ,
7273 "TPFLAGS_IS_ABSTRACT" ,
134135 "istraceback" ,
135136 "markcoroutinefunction" ,
136137 "signature" ,
138+ "signatures" ,
137139 "stack" ,
138140 "trace" ,
139141 "unwrap" ,
@@ -2189,19 +2191,20 @@ def _signature_is_functionlike(obj):
21892191 (isinstance (annotations , (dict )) or annotations is None ) )
21902192
21912193
2192- def _signature_strip_non_python_syntax (signature ):
2194+ def _signature_split (signature ):
21932195 """
21942196 Private helper function. Takes a signature in Argument Clinic's
21952197 extended signature format.
21962198
2197- Returns a tuple of two things :
2199+ Yields pairs :
21982200 * that signature re-rendered in standard Python syntax, and
21992201 * the index of the "self" parameter (generally 0), or None if
22002202 the function does not have a "self" parameter.
22012203 """
22022204
22032205 if not signature :
2204- return signature , None
2206+ yield (signature , None )
2207+ return
22052208
22062209 self_parameter = None
22072210
@@ -2214,38 +2217,47 @@ def _signature_strip_non_python_syntax(signature):
22142217
22152218 current_parameter = 0
22162219 OP = token .OP
2217- ERRORTOKEN = token .ERRORTOKEN
2220+ NEWLINE = token .NEWLINE
2221+ NL = token .NL
22182222
22192223 # token stream always starts with ENCODING token, skip it
22202224 t = next (token_stream )
22212225 assert t .type == tokenize .ENCODING
22222226
22232227 for t in token_stream :
22242228 type , string = t .type , t .string
2225-
2226- if type == OP :
2229+ if type == NEWLINE :
2230+ yield ('' .join (text ), self_parameter )
2231+ text .clear ()
2232+ self_parameter = None
2233+ current_parameter = 0
2234+ continue
2235+ elif type == NL :
2236+ continue
2237+ elif type == OP :
22272238 if string == ',' :
22282239 current_parameter += 1
2229-
2230- if (type == OP ) and (string == '$' ):
2231- assert self_parameter is None
2232- self_parameter = current_parameter
2233- continue
2234-
2240+ string = ', '
2241+ elif string == '$' and self_parameter is None :
2242+ self_parameter = current_parameter
2243+ continue
22352244 add (string )
2236- if (string == ',' ):
2237- add (' ' )
2238- clean_signature = '' .join (text ).strip ().replace ("\n " , "" )
2239- return clean_signature , self_parameter
2240-
22412245
22422246def _signature_fromstr (cls , obj , s , skip_bound_arg = True ):
22432247 """Private helper to parse content of '__text_signature__'
22442248 and return a Signature based on it.
22452249 """
2246- Parameter = cls ._parameter_cls
2250+ signatures = [_signature_fromstr1 (cls , obj ,
2251+ clean_signature , self_parameter ,
2252+ skip_bound_arg )
2253+ for clean_signature , self_parameter in _signature_split (s )]
2254+ if len (signatures ) == 1 :
2255+ return signatures [0 ]
2256+ else :
2257+ return MultiSignature (signatures )
22472258
2248- clean_signature , self_parameter = _signature_strip_non_python_syntax (s )
2259+ def _signature_fromstr1 (cls , obj , clean_signature , self_parameter , skip_bound_arg ):
2260+ Parameter = cls ._parameter_cls
22492261
22502262 program = "def foo" + clean_signature + ": pass"
22512263
@@ -2830,6 +2842,8 @@ def replace(self, *, name=_void, kind=_void,
28302842
28312843 return type (self )(name , kind , default = default , annotation = annotation )
28322844
2845+ __replace__ = replace
2846+
28332847 def __str__ (self ):
28342848 kind = self .kind
28352849 formatted = self ._name
@@ -2852,8 +2866,6 @@ def __str__(self):
28522866
28532867 return formatted
28542868
2855- __replace__ = replace
2856-
28572869 def __repr__ (self ):
28582870 return '<{} "{}">' .format (self .__class__ .__name__ , self )
28592871
@@ -3133,7 +3145,7 @@ def __hash__(self):
31333145 def __eq__ (self , other ):
31343146 if self is other :
31353147 return True
3136- if not isinstance (other , Signature ):
3148+ if not isinstance (other , Signature ) or isinstance ( other , MultiSignature ) :
31373149 return NotImplemented
31383150 return self ._hash_basis () == other ._hash_basis ()
31393151
@@ -3355,11 +3367,106 @@ def format(self, *, max_width=None):
33553367 return rendered
33563368
33573369
3370+ class MultiSignature (Signature ):
3371+ __slots__ = ('_signatures' ,)
3372+
3373+ def __init__ (self , signatures ):
3374+ signatures = tuple (signatures )
3375+ if not signatures :
3376+ raise ValueError ('No signatures' )
3377+ self ._signatures = signatures
3378+
3379+ @staticmethod
3380+ def from_callable (obj , * ,
3381+ follow_wrapped = True , globals = None , locals = None , eval_str = False ):
3382+ """Constructs MultiSignature for the given callable object."""
3383+ signature = Signature .from_callable (obj , follow_wrapped = follow_wrapped ,
3384+ globals = globals , locals = locals ,
3385+ eval_str = eval_str )
3386+ if not isinstance (signature , MultiSignature ):
3387+ signature = MultiSignature ((signature ,))
3388+ return signature
3389+
3390+ @property
3391+ def parameters (self ):
3392+ try :
3393+ return self ._parameters
3394+ except AttributeError :
3395+ pass
3396+ params = {}
3397+ for s in self ._signatures :
3398+ params .update (s .parameters )
3399+ self ._parameters = types .MappingProxyType (params )
3400+ return self ._parameters
3401+
3402+ @property
3403+ def return_annotation (self ):
3404+ try :
3405+ return self ._return_annotation
3406+ except AttributeError :
3407+ pass
3408+ self ._return_annotation = types .UnionType (tuple (s .return_annotation
3409+ for s in self ._signatures
3410+ if s .return_annotation != _empty ))
3411+ return self ._return_annotation
3412+
3413+ def replace (self ):
3414+ raise NotImplementedError
3415+
3416+ __replace__ = replace
3417+
3418+ def __iter__ (self ):
3419+ return iter (self ._signatures )
3420+
3421+ def __hash__ (self ):
3422+ if len (self ._signatures ) == 1 :
3423+ return hash (self ._signatures [0 ])
3424+ return hash (self ._signatures )
3425+
3426+ def __eq__ (self , other ):
3427+ if self is other :
3428+ return True
3429+ if isinstance (other , MultiSignature ):
3430+ return self ._signatures == other ._signatures
3431+ if len (self ._signatures ) == 1 and isinstance (other , Signature ):
3432+ return self ._signatures [0 ] == other
3433+ return NotImplemented
3434+
3435+ def _bind (self , args , kwargs , * , partial = False ):
3436+ """Private method. Don't use directly."""
3437+ for i , s in enumerate (self ._signatures ):
3438+ try :
3439+ return s ._bind (args , kwargs , partial = partial )
3440+ except TypeError :
3441+ if i == len (self ._signatures ) - 1 :
3442+ raise
3443+
3444+ def __reduce__ (self ):
3445+ return type (self ), (self ._signatures ,)
3446+
3447+ def __repr__ (self ):
3448+ return '<%s %s>' % (self .__class__ .__name__ ,
3449+ '|' .join (map (str , self ._signatures )))
3450+
3451+ def __str__ (self ):
3452+ return '\n ' .join (map (str , self ._signatures ))
3453+
3454+ def format (self , * , max_width = None ):
3455+ return '\n ' .join (sig .format (max_width = max_width )
3456+ for sig in self ._signatures )
3457+
3458+
33583459def signature (obj , * , follow_wrapped = True , globals = None , locals = None , eval_str = False ):
33593460 """Get a signature object for the passed callable."""
33603461 return Signature .from_callable (obj , follow_wrapped = follow_wrapped ,
33613462 globals = globals , locals = locals , eval_str = eval_str )
33623463
3464+ def signatures (obj , * , follow_wrapped = True , globals = None , locals = None , eval_str = False ):
3465+ """Get a multi-signature object for the passed callable."""
3466+ return MultiSignature .from_callable (obj , follow_wrapped = follow_wrapped ,
3467+ globals = globals , locals = locals ,
3468+ eval_str = eval_str )
3469+
33633470
33643471class BufferFlags (enum .IntFlag ):
33653472 SIMPLE = 0x0
0 commit comments