@@ -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
@@ -4068,44 +4091,266 @@ def __init__(self, b):
40684091 ('bar', 2, ..., "keyword_only")),
40694092 ...))
40704093
4071- def test_signature_on_class_with_decorated_new(self):
4072- def identity(func):
4073- @functools.wraps(func)
4074- def wrapped(*args, **kwargs):
4075- return func(*args, **kwargs)
4076- return wrapped
4077-
4078- class Foo:
4079- @identity
4080- def __new__(cls, a, b):
4094+ def test_signature_on_class_with_wrapped_metaclass_call(self):
4095+ class CM(type):
4096+ @identity_wrapper
4097+ def __call__(cls, a):
4098+ pass
4099+ class C(metaclass=CM):
4100+ def __init__(self, b):
40814101 pass
40824102
4083- self.assertEqual(self.signature(Foo),
4084- ((('a', ..., ..., "positional_or_keyword"),
4085- ('b', ..., ..., "positional_or_keyword")),
4103+ self.assertEqual(self.signature(C),
4104+ ((('a', ..., ..., "positional_or_keyword"),),
40864105 ...))
40874106
4088- self.assertEqual(self.signature(Foo.__new__),
4089- ((('cls', ..., ..., "positional_or_keyword"),
4090- ('a', ..., ..., "positional_or_keyword"),
4091- ('b', ..., ..., "positional_or_keyword")),
4092- ...))
4107+ with self.subTest('classmethod'):
4108+ class CM(type):
4109+ @classmethod
4110+ @identity_wrapper
4111+ def __call__(cls, a):
4112+ return a
4113+ class C(metaclass=CM):
4114+ def __init__(self, b):
4115+ pass
40934116
4094- class Bar:
4095- __new__ = identity(object.__new__)
4117+ self.assertEqual(C(1), 1)
4118+ self.assertEqual(self.signature(C),
4119+ ((('a', ..., ..., "positional_or_keyword"),),
4120+ ...))
40964121
4097- varargs_signature = (
4098- (('args', ..., ..., 'var_positional'),
4099- ('kwargs', ..., ..., 'var_keyword')),
4100- ...,
4101- )
4122+ with self.subTest('staticmethod'):
4123+ class CM(type):
4124+ @staticmethod
4125+ @identity_wrapper
4126+ def __call__(a):
4127+ return a
4128+ class C(metaclass=CM):
4129+ def __init__(self, b):
4130+ pass
4131+
4132+ self.assertEqual(C(1), 1)
4133+ self.assertEqual(self.signature(C),
4134+ ((('a', ..., ..., "positional_or_keyword"),),
4135+ ...))
4136+
4137+ with self.subTest('MethodType'):
4138+ class A:
4139+ @identity_wrapper
4140+ def call(self, a):
4141+ return a
4142+ class CM(type):
4143+ __call__ = A().call
4144+ class C(metaclass=CM):
4145+ def __init__(self, b):
4146+ pass
4147+
4148+ self.assertEqual(C(1), 1)
4149+ self.assertEqual(self.signature(C),
4150+ ((('a', ..., ..., "positional_or_keyword"),),
4151+ ...))
4152+
4153+ with self.subTest('descriptor'):
4154+ class CM(type):
4155+ @custom_descriptor
4156+ @identity_wrapper
4157+ def __call__(self, a):
4158+ return a
4159+ class C(metaclass=CM):
4160+ def __init__(self, b):
4161+ pass
4162+
4163+ self.assertEqual(C(1), 1)
4164+ self.assertEqual(self.signature(C),
4165+ ((('a', ..., ..., "positional_or_keyword"),),
4166+ ...))
4167+ self.assertEqual(self.signature(C.__call__),
4168+ ((('a', ..., ..., "positional_or_keyword"),),
4169+ ...))
4170+
4171+ self.assertEqual(self.signature(C, follow_wrapped=False),
4172+ varargs_signature)
4173+ self.assertEqual(self.signature(C.__call__, follow_wrapped=False),
4174+ varargs_signature)
4175+
4176+ def test_signature_on_class_with_wrapped_init(self):
4177+ class C:
4178+ @identity_wrapper
4179+ def __init__(self, b):
4180+ pass
4181+
4182+ C(1) # does not raise
4183+ self.assertEqual(self.signature(C),
4184+ ((('b', ..., ..., "positional_or_keyword"),),
4185+ ...))
4186+
4187+ with self.subTest('classmethod'):
4188+ class C:
4189+ @classmethod
4190+ @identity_wrapper
4191+ def __init__(cls, b):
4192+ pass
4193+
4194+ C(1) # does not raise
4195+ self.assertEqual(self.signature(C),
4196+ ((('b', ..., ..., "positional_or_keyword"),),
4197+ ...))
4198+
4199+ with self.subTest('staticmethod'):
4200+ class C:
4201+ @staticmethod
4202+ @identity_wrapper
4203+ def __init__(b):
4204+ pass
4205+
4206+ C(1) # does not raise
4207+ self.assertEqual(self.signature(C),
4208+ ((('b', ..., ..., "positional_or_keyword"),),
4209+ ...))
4210+
4211+ with self.subTest('MethodType'):
4212+ class A:
4213+ @identity_wrapper
4214+ def call(self, a):
4215+ pass
4216+
4217+ class C:
4218+ __init__ = A().call
4219+
4220+ C(1) # does not raise
4221+ self.assertEqual(self.signature(C),
4222+ ((('a', ..., ..., "positional_or_keyword"),),
4223+ ...))
4224+
4225+ with self.subTest('partial'):
4226+ class C:
4227+ __init__ = functools.partial(identity_wrapper(lambda x, a, b: None), 2)
4228+
4229+ C(1) # does not raise
4230+ self.assertEqual(self.signature(C),
4231+ ((('b', ..., ..., "positional_or_keyword"),),
4232+ ...))
4233+
4234+ with self.subTest('partialmethod'):
4235+ class C:
4236+ @identity_wrapper
4237+ def _init(self, x, a):
4238+ self.a = (x, a)
4239+ __init__ = functools.partialmethod(_init, 2)
4240+
4241+ self.assertEqual(C(1).a, (2, 1))
4242+ self.assertEqual(self.signature(C),
4243+ ((('a', ..., ..., "positional_or_keyword"),),
4244+ ...))
4245+
4246+ with self.subTest('descriptor'):
4247+ class C:
4248+ @custom_descriptor
4249+ @identity_wrapper
4250+ def __init__(self, a):
4251+ pass
4252+
4253+ C(1) # does not raise
4254+ self.assertEqual(self.signature(C),
4255+ ((('a', ..., ..., "positional_or_keyword"),),
4256+ ...))
4257+ self.assertEqual(self.signature(C.__init__),
4258+ ((('self', ..., ..., "positional_or_keyword"),
4259+ ('a', ..., ..., "positional_or_keyword")),
4260+ ...))
4261+
4262+ self.assertEqual(self.signature(C, follow_wrapped=False),
4263+ varargs_signature)
4264+ self.assertEqual(self.signature(C.__new__, follow_wrapped=False),
4265+ varargs_signature)
4266+
4267+ def test_signature_on_class_with_wrapped_new(self):
4268+ with self.subTest('FunctionType'):
4269+ class C:
4270+ @identity_wrapper
4271+ def __new__(cls, a):
4272+ return a
4273+
4274+ self.assertEqual(C(1), 1)
4275+ self.assertEqual(self.signature(C),
4276+ ((('a', ..., ..., "positional_or_keyword"),),
4277+ ...))
4278+
4279+ with self.subTest('classmethod'):
4280+ class C:
4281+ @classmethod
4282+ @identity_wrapper
4283+ def __new__(cls, cls2, a):
4284+ return a
4285+
4286+ self.assertEqual(C(1), 1)
4287+ self.assertEqual(self.signature(C),
4288+ ((('a', ..., ..., "positional_or_keyword"),),
4289+ ...))
4290+
4291+ with self.subTest('staticmethod'):
4292+ class C:
4293+ @staticmethod
4294+ @identity_wrapper
4295+ def __new__(cls, a):
4296+ return a
4297+
4298+ self.assertEqual(C(1), 1)
4299+ self.assertEqual(self.signature(C),
4300+ ((('a', ..., ..., "positional_or_keyword"),),
4301+ ...))
4302+
4303+ with self.subTest('MethodType'):
4304+ class A:
4305+ @identity_wrapper
4306+ def call(self, cls, a):
4307+ return a
4308+ class C:
4309+ __new__ = A().call
4310+
4311+ self.assertEqual(C(1), 1)
4312+ self.assertEqual(self.signature(C),
4313+ ((('a', ..., ..., "positional_or_keyword"),),
4314+ ...))
4315+
4316+ with self.subTest('partial'):
4317+ class C:
4318+ __new__ = functools.partial(identity_wrapper(lambda x, cls, a: (x, a)), 2)
4319+
4320+ self.assertEqual(C(1), (2, 1))
4321+ self.assertEqual(self.signature(C),
4322+ ((('a', ..., ..., "positional_or_keyword"),),
4323+ ...))
4324+
4325+ with self.subTest('partialmethod'):
4326+ class C:
4327+ __new__ = functools.partialmethod(identity_wrapper(lambda cls, x, a: (x, a)), 2)
4328+
4329+ self.assertEqual(C(1), (2, 1))
4330+ self.assertEqual(self.signature(C),
4331+ ((('a', ..., ..., "positional_or_keyword"),),
4332+ ...))
4333+
4334+ with self.subTest('descriptor'):
4335+ class C:
4336+ @custom_descriptor
4337+ @identity_wrapper
4338+ def __new__(cls, a):
4339+ return a
4340+
4341+ self.assertEqual(C(1), 1)
4342+ self.assertEqual(self.signature(C),
4343+ ((('a', ..., ..., "positional_or_keyword"),),
4344+ ...))
4345+ self.assertEqual(self.signature(C.__new__),
4346+ ((('cls', ..., ..., "positional_or_keyword"),
4347+ ('a', ..., ..., "positional_or_keyword")),
4348+ ...))
41024349
4103- self.assertEqual(self.signature(Bar), ((), ...))
4104- self.assertEqual(self.signature(Bar.__new__), varargs_signature)
4105- self.assertEqual(self.signature(Bar, follow_wrapped=False),
4106- varargs_signature)
4107- self.assertEqual(self.signature(Bar.__new__, follow_wrapped=False),
4108- varargs_signature)
4350+ self.assertEqual(self.signature(C, follow_wrapped=False),
4351+ varargs_signature)
4352+ self.assertEqual(self.signature(C.__new__, follow_wrapped=False),
4353+ varargs_signature)
41094354
41104355 def test_signature_on_class_with_init(self):
41114356 class C:
0 commit comments