tantale / deprecated

Python @deprecated decorator to deprecate old python classes, functions or methods.
MIT License
301 stars 32 forks source link

TypeError in deprecated class because of arguments given to __new__ #4

Closed MatthiasKohl closed 5 years ago

MatthiasKohl commented 5 years ago

Expected Behavior

No exception, returns class as expected.

# Paste a minimal example that causes the problem.
@deprecated('kwargs class')
class ClassKwargs(object):
    def __init__(self, a=5):
        super(ClassKwargs, self).__init__()
        self.state = a

    def method(self):
        return self.state

ClassKwargs(6)

Actual Behavior

Not complete traceback but most important part:

    ClassKwargs(6)
  File "/home/matt/miniconda3/envs/df/lib/python3.5/site-packages/deprecated/classic.py", line 104, in wrapped_cls
    return old_new1(*args, **kwargs)
TypeError: object() takes no parameters

Environment

MatthiasKohl commented 5 years ago

This bug comes from function wrapped_cls in ClassicAdapter.__call__

I'm not sure if the underlying problem comes from this library, so I'm not sure if this is really the best place to report this bug. On my system at least, I found a weird issue, where if you use a function like this:

def new_constructor(cls, *args, **kwargs):
  print(cls)
  print(args)
  print(kwargs)

SomeClass.__new__ = classmethod(new_constructor)

It seems to call the new_constructor with the class argument twice (in cls and args[0]). But doing this:

def new_constructor(*args, **kwargs):
  print(cls)
  print(args)
  print(kwargs)

SomeClass.__new__ = classmethod(new_constructor)

works as expected.

No idea why, this looks very strange... possibly an obscure issue with my system (?)

MatthiasKohl commented 5 years ago

I ended up working around this problem by using deprecated on the __init__ function only. Not sure what the underlying issue is, though.

tantale commented 5 years ago

I need to investigate this issue further.

tantale commented 5 years ago

This exception is raised when some parameters in passed to __init__ (in addition to self).

tantale commented 5 years ago

Here is a demonstration of the problem:

class Something(object):
    def __new__(cls, *args, **kwargs):
        return super(Something, cls).__new__(cls, *args, **kwargs)

    def __init__(self, a=5):
        self.a = a

Something(5)

You get:

Traceback (most recent call last):
  ...
TypeError: object() takes no parameters

Because object.__new__ has no extra parameters.