py3.3: dir(None) gives TypeError
Created originally on Bitbucket by numerodix (Martin Matusiak)
As seen here (even though the cause is not obvious from the output): http://buildbot.pypy.org/summary/longrepr?testname=unmodified&builder=pypy-c-app-level-linux-x86-64&build=2379&mod=lib-python.3.test.test_unittest
First, a couple of checks:
#!python
>>>> isinstance(None, object)
True
>>>> None.__dir__()
['__str__', '__getattribute__', '__lt__', '__init__', '__setattr__', '__reduce_ex__', '__new__', '__format__', '__class__', '__doc__', '__ne__', '__reduce__', '__subclasshook__', '__gt__', '__bool__', '__eq__', '__dir__', '__delattr__', '__le__', '__repr__', '__hash__', '__ge__']
>>>> object.__dir__()
Traceback (application-level):
File "<inline>", line 1 in <module>
object.__dir__()
TypeError: __dir__() takes exactly 1 argument (0 given)
>>>> dir(None)
Traceback (application-level):
File "<inline>", line 1 in <module>
dir(None)
TypeError: __dir__() takes exactly 1 argument (0 given)
Ok, so calling dir directly on None works, but when called through dir() it has the effect of calling object.dir without arguments.
The incantation looks like this:
#!python
dir_meth = lookup_special(obj, "__dir__")
if dir_meth is not None:
result = dir_meth()
# object: <bound method type.__dir__ of <class 'object'>>
# None: <function __dir__ at 0xb61a9aec>
When called on object, dir_meth is a bound method. When called on None, it's just a function, why is that?
lookup_special:
#!python
w_descr = space.lookup(w_obj, meth)
if w_descr is None:
return space.w_None
return space.get(w_descr, w_obj)
So: use the wrapped object to find the descriptor, then use the descriptor to get a method.