@@ -148,6 +148,29 @@ def meth_self_o(self, object, /): pass
148148def meth_type_noargs (type , / ): pass
149149def meth_type_o (type , object , / ): pass
150150
151+ # Decorator decorator that returns a simple wrapped function
152+ def identity_wrapper (func ):
153+ @functools .wraps (func )
154+ def wrapped (* args , ** kwargs ):
155+ return func (* args , ** kwargs )
156+ return wrapped
157+
158+ # Original signature of the simple wrapped function returned by
159+ # identity_wrapper().
160+ varargs_signature = (
161+ (('args' , ..., ..., 'var_positional' ),
162+ ('kwargs' , ..., ..., 'var_keyword' )),
163+ ...,
164+ )
165+
166+ # Decorator decorator that returns a simple descriptor
167+ class custom_descriptor :
168+ def __init__ (self , func ):
169+ self .func = func
170+
171+ def __get__ (self , instance , owner ):
172+ return self .func .__get__ (instance , owner )
173+
151174
152175class TestPredicates (IsTestBase ):
153176
@@ -4027,44 +4050,266 @@ def __init__(self, b):
40274050 ('bar' , 2 , ..., "keyword_only" )),
40284051 ...))
40294052
4030- def test_signature_on_class_with_decorated_new (self ):
4031- def identity (func ):
4032- @functools .wraps (func )
4033- def wrapped (* args , ** kwargs ):
4034- return func (* args , ** kwargs )
4035- return wrapped
4036-
4037- class Foo :
4038- @identity
4039- def __new__ (cls , a , b ):
4053+ def test_signature_on_class_with_wrapped_metaclass_call (self ):
4054+ class CM (type ):
4055+ @identity_wrapper
4056+ def __call__ (cls , a ):
4057+ pass
4058+ class C (metaclass = CM ):
4059+ def __init__ (self , b ):
40404060 pass
40414061
4042- self .assertEqual (self .signature (Foo ),
4043- ((('a' , ..., ..., "positional_or_keyword" ),
4044- ('b' , ..., ..., "positional_or_keyword" )),
4062+ self .assertEqual (self .signature (C ),
4063+ ((('a' , ..., ..., "positional_or_keyword" ),),
40454064 ...))
40464065
4047- self .assertEqual (self .signature (Foo .__new__ ),
4048- ((('cls' , ..., ..., "positional_or_keyword" ),
4049- ('a' , ..., ..., "positional_or_keyword" ),
4050- ('b' , ..., ..., "positional_or_keyword" )),
4051- ...))
4066+ with self .subTest ('classmethod' ):
4067+ class CM (type ):
4068+ @classmethod
4069+ @identity_wrapper
4070+ def __call__ (cls , a ):
4071+ return a
4072+ class C (metaclass = CM ):
4073+ def __init__ (self , b ):
4074+ pass
40524075
4053- class Bar :
4054- __new__ = identity (object .__new__ )
4076+ self .assertEqual (C (1 ), 1 )
4077+ self .assertEqual (self .signature (C ),
4078+ ((('a' , ..., ..., "positional_or_keyword" ),),
4079+ ...))
40554080
4056- varargs_signature = (
4057- (('args' , ..., ..., 'var_positional' ),
4058- ('kwargs' , ..., ..., 'var_keyword' )),
4059- ...,
4060- )
4081+ with self .subTest ('staticmethod' ):
4082+ class CM (type ):
4083+ @staticmethod
4084+ @identity_wrapper
4085+ def __call__ (a ):
4086+ return a
4087+ class C (metaclass = CM ):
4088+ def __init__ (self , b ):
4089+ pass
4090+
4091+ self .assertEqual (C (1 ), 1 )
4092+ self .assertEqual (self .signature (C ),
4093+ ((('a' , ..., ..., "positional_or_keyword" ),),
4094+ ...))
4095+
4096+ with self .subTest ('MethodType' ):
4097+ class A :
4098+ @identity_wrapper
4099+ def call (self , a ):
4100+ return a
4101+ class CM (type ):
4102+ __call__ = A ().call
4103+ class C (metaclass = CM ):
4104+ def __init__ (self , b ):
4105+ pass
4106+
4107+ self .assertEqual (C (1 ), 1 )
4108+ self .assertEqual (self .signature (C ),
4109+ ((('a' , ..., ..., "positional_or_keyword" ),),
4110+ ...))
4111+
4112+ with self .subTest ('descriptor' ):
4113+ class CM (type ):
4114+ @custom_descriptor
4115+ @identity_wrapper
4116+ def __call__ (self , a ):
4117+ return a
4118+ class C (metaclass = CM ):
4119+ def __init__ (self , b ):
4120+ pass
4121+
4122+ self .assertEqual (C (1 ), 1 )
4123+ self .assertEqual (self .signature (C ),
4124+ ((('a' , ..., ..., "positional_or_keyword" ),),
4125+ ...))
4126+ self .assertEqual (self .signature (C .__call__ ),
4127+ ((('a' , ..., ..., "positional_or_keyword" ),),
4128+ ...))
4129+
4130+ self .assertEqual (self .signature (C , follow_wrapped = False ),
4131+ varargs_signature )
4132+ self .assertEqual (self .signature (C .__call__ , follow_wrapped = False ),
4133+ varargs_signature )
4134+
4135+ def test_signature_on_class_with_wrapped_init (self ):
4136+ class C :
4137+ @identity_wrapper
4138+ def __init__ (self , b ):
4139+ pass
4140+
4141+ C (1 ) # does not raise
4142+ self .assertEqual (self .signature (C ),
4143+ ((('b' , ..., ..., "positional_or_keyword" ),),
4144+ ...))
4145+
4146+ with self .subTest ('classmethod' ):
4147+ class C :
4148+ @classmethod
4149+ @identity_wrapper
4150+ def __init__ (cls , b ):
4151+ pass
4152+
4153+ C (1 ) # does not raise
4154+ self .assertEqual (self .signature (C ),
4155+ ((('b' , ..., ..., "positional_or_keyword" ),),
4156+ ...))
4157+
4158+ with self .subTest ('staticmethod' ):
4159+ class C :
4160+ @staticmethod
4161+ @identity_wrapper
4162+ def __init__ (b ):
4163+ pass
4164+
4165+ C (1 ) # does not raise
4166+ self .assertEqual (self .signature (C ),
4167+ ((('b' , ..., ..., "positional_or_keyword" ),),
4168+ ...))
4169+
4170+ with self .subTest ('MethodType' ):
4171+ class A :
4172+ @identity_wrapper
4173+ def call (self , a ):
4174+ pass
4175+
4176+ class C :
4177+ __init__ = A ().call
4178+
4179+ C (1 ) # does not raise
4180+ self .assertEqual (self .signature (C ),
4181+ ((('a' , ..., ..., "positional_or_keyword" ),),
4182+ ...))
4183+
4184+ with self .subTest ('partial' ):
4185+ class C :
4186+ __init__ = functools .partial (identity_wrapper (lambda x , a , b : None ), 2 )
4187+
4188+ C (1 ) # does not raise
4189+ self .assertEqual (self .signature (C ),
4190+ ((('b' , ..., ..., "positional_or_keyword" ),),
4191+ ...))
4192+
4193+ with self .subTest ('partialmethod' ):
4194+ class C :
4195+ @identity_wrapper
4196+ def _init (self , x , a ):
4197+ self .a = (x , a )
4198+ __init__ = functools .partialmethod (_init , 2 )
4199+
4200+ self .assertEqual (C (1 ).a , (2 , 1 ))
4201+ self .assertEqual (self .signature (C ),
4202+ ((('a' , ..., ..., "positional_or_keyword" ),),
4203+ ...))
4204+
4205+ with self .subTest ('descriptor' ):
4206+ class C :
4207+ @custom_descriptor
4208+ @identity_wrapper
4209+ def __init__ (self , a ):
4210+ pass
4211+
4212+ C (1 ) # does not raise
4213+ self .assertEqual (self .signature (C ),
4214+ ((('a' , ..., ..., "positional_or_keyword" ),),
4215+ ...))
4216+ self .assertEqual (self .signature (C .__init__ ),
4217+ ((('self' , ..., ..., "positional_or_keyword" ),
4218+ ('a' , ..., ..., "positional_or_keyword" )),
4219+ ...))
4220+
4221+ self .assertEqual (self .signature (C , follow_wrapped = False ),
4222+ varargs_signature )
4223+ self .assertEqual (self .signature (C .__new__ , follow_wrapped = False ),
4224+ varargs_signature )
4225+
4226+ def test_signature_on_class_with_wrapped_new (self ):
4227+ with self .subTest ('FunctionType' ):
4228+ class C :
4229+ @identity_wrapper
4230+ def __new__ (cls , a ):
4231+ return a
4232+
4233+ self .assertEqual (C (1 ), 1 )
4234+ self .assertEqual (self .signature (C ),
4235+ ((('a' , ..., ..., "positional_or_keyword" ),),
4236+ ...))
4237+
4238+ with self .subTest ('classmethod' ):
4239+ class C :
4240+ @classmethod
4241+ @identity_wrapper
4242+ def __new__ (cls , cls2 , a ):
4243+ return a
4244+
4245+ self .assertEqual (C (1 ), 1 )
4246+ self .assertEqual (self .signature (C ),
4247+ ((('a' , ..., ..., "positional_or_keyword" ),),
4248+ ...))
4249+
4250+ with self .subTest ('staticmethod' ):
4251+ class C :
4252+ @staticmethod
4253+ @identity_wrapper
4254+ def __new__ (cls , a ):
4255+ return a
4256+
4257+ self .assertEqual (C (1 ), 1 )
4258+ self .assertEqual (self .signature (C ),
4259+ ((('a' , ..., ..., "positional_or_keyword" ),),
4260+ ...))
4261+
4262+ with self .subTest ('MethodType' ):
4263+ class A :
4264+ @identity_wrapper
4265+ def call (self , cls , a ):
4266+ return a
4267+ class C :
4268+ __new__ = A ().call
4269+
4270+ self .assertEqual (C (1 ), 1 )
4271+ self .assertEqual (self .signature (C ),
4272+ ((('a' , ..., ..., "positional_or_keyword" ),),
4273+ ...))
4274+
4275+ with self .subTest ('partial' ):
4276+ class C :
4277+ __new__ = functools .partial (identity_wrapper (lambda x , cls , a : (x , a )), 2 )
4278+
4279+ self .assertEqual (C (1 ), (2 , 1 ))
4280+ self .assertEqual (self .signature (C ),
4281+ ((('a' , ..., ..., "positional_or_keyword" ),),
4282+ ...))
4283+
4284+ with self .subTest ('partialmethod' ):
4285+ class C :
4286+ __new__ = functools .partialmethod (identity_wrapper (lambda cls , x , a : (x , a )), 2 )
4287+
4288+ self .assertEqual (C (1 ), (2 , 1 ))
4289+ self .assertEqual (self .signature (C ),
4290+ ((('a' , ..., ..., "positional_or_keyword" ),),
4291+ ...))
4292+
4293+ with self .subTest ('descriptor' ):
4294+ class C :
4295+ @custom_descriptor
4296+ @identity_wrapper
4297+ def __new__ (cls , a ):
4298+ return a
4299+
4300+ self .assertEqual (C (1 ), 1 )
4301+ self .assertEqual (self .signature (C ),
4302+ ((('a' , ..., ..., "positional_or_keyword" ),),
4303+ ...))
4304+ self .assertEqual (self .signature (C .__new__ ),
4305+ ((('cls' , ..., ..., "positional_or_keyword" ),
4306+ ('a' , ..., ..., "positional_or_keyword" )),
4307+ ...))
40614308
4062- self .assertEqual (self .signature (Bar ), ((), ...))
4063- self .assertEqual (self .signature (Bar .__new__ ), varargs_signature )
4064- self .assertEqual (self .signature (Bar , follow_wrapped = False ),
4065- varargs_signature )
4066- self .assertEqual (self .signature (Bar .__new__ , follow_wrapped = False ),
4067- varargs_signature )
4309+ self .assertEqual (self .signature (C , follow_wrapped = False ),
4310+ varargs_signature )
4311+ self .assertEqual (self .signature (C .__new__ , follow_wrapped = False ),
4312+ varargs_signature )
40684313
40694314 def test_signature_on_class_with_init (self ):
40704315 class C :
0 commit comments