GrahamDumpleton / wrapt

A Python module for decorators, wrappers and monkey patching.
BSD 2-Clause "Simplified" License
2.06k stars 231 forks source link

Issues when using python2 and future's super with no arguments #131

Open aayla-secura opened 5 years ago

aayla-secura commented 5 years ago

I'm using the new super (future.builtins.newsuper.newsuper) with Python 2.7.16 (and future 0.17.1) and I am getting an exception when not passing arguments to super. Using future.builtins's super with no arguments works with any other class I've tried.

# wrapt_test.py
from builtins import super
from future import standard_library
standard_library.install_aliases()
from wrapt import ObjectProxy

class Foo(ObjectProxy):
    def __init__(self):
        super().__init__(1) # this works only in python3
        # super(Foo, self).__init__(1) # this always works

p = Foo()
$ python2 wrapt_test.py
Traceback (most recent call last):
  File "foo.py", line 10, in <module>
    p = Foo()
  File "foo.py", line 8, in __init__
    super().__init__(1)
  File "/usr/local/lib/python2.7/site-packages/future/builtins/newsuper.py", line 64, in newsuper
    mro = type_or_obj.__mro__
ValueError: wrapper has not been initialized
GrahamDumpleton commented 5 years ago

Most likely because internally to the Python object model, __mro__ access is trying to in turn access __class__, with that causing the exception since wrapper hasn't been initialised.

What happens if you run the same test with the environment variable WRAPT_DISABLE_EXTENSIONS set to 1? This will use the pure Python implementation of ObjectProxy instead of the C extension.

The whole search order for super() may well be screwed up anyway given that __class__ is being overridden to return the class type for what is wrapped.

aayla-secura commented 5 years ago

Setting the environment variable WRAPT_DISABLE_EXTENSIONS to 1 makes no difference: same exception is raised. Do you mean I simply shouldn't be using argument-less super with ObjectProxy?

GrahamDumpleton commented 5 years ago

If trying to use the no argument super() back port for 2.7, then yes at this point it doesn't look like it will work. Would need to dig into how that back port implementation works. I suspect the way it goes about things isn't going to work with anything that overrides __class__() method. It possibly should be using type() on the object it has instead, but this is just a wild guess since haven't looked at the code for it.