diff options
-rw-r--r-- | Lib/test/test_descr.py | 8 | ||||
-rw-r--r-- | Objects/object.c | 45 |
2 files changed, 53 insertions, 0 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 401489d6ed..dbfce0c28d 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -190,6 +190,7 @@ def test_dir(): cstuff = ['Cdata', 'Cmethod', '__doc__', '__module__'] verify(dir(C) == cstuff) + verify('im_self' in dir(C.Cmethod)) c = C() # c.__doc__ is an odd thing to see here; ditto c.__module__. verify(dir(c) == cstuff) @@ -197,6 +198,7 @@ def test_dir(): c.cdata = 2 c.cmethod = lambda self: 0 verify(dir(c) == cstuff + ['cdata', 'cmethod']) + verify('im_self' in dir(c.Cmethod)) class A(C): Adata = 1 @@ -204,8 +206,10 @@ def test_dir(): astuff = ['Adata', 'Amethod'] + cstuff verify(dir(A) == astuff) + verify('im_self' in dir(A.Amethod)) a = A() verify(dir(a) == astuff) + verify('im_self' in dir(a.Amethod)) a.adata = 42 a.amethod = lambda self: 3 verify(dir(a) == astuff + ['adata', 'amethod']) @@ -224,10 +228,12 @@ def test_dir(): c = C() verify(interesting(dir(c)) == cstuff) + verify('im_self' in dir(C.Cmethod)) c.cdata = 2 c.cmethod = lambda self: 0 verify(interesting(dir(c)) == cstuff + ['cdata', 'cmethod']) + verify('im_self' in dir(c.Cmethod)) class A(C): Adata = 1 @@ -235,11 +241,13 @@ def test_dir(): astuff = ['Adata', 'Amethod'] + cstuff verify(interesting(dir(A)) == astuff) + verify('im_self' in dir(A.Amethod)) a = A() verify(interesting(dir(a)) == astuff) a.adata = 42 a.amethod = lambda self: 3 verify(interesting(dir(a)) == astuff + ['adata', 'amethod']) + verify('im_self' in dir(a.Amethod)) # Try a module subclass. import sys diff --git a/Objects/object.c b/Objects/object.c index fd31e51c0e..c56c3be917 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1417,6 +1417,43 @@ merge_class_dict(PyObject* dict, PyObject* aclass) return 0; } +/* Helper for PyObject_Dir. + If obj has an attr named attrname that's a list, merge its string + elements into keys of dict. + Return 0 on success, -1 on error. Errors due to not finding the attr, + or the attr not being a list, are suppressed. +*/ + +static int +merge_list_attr(PyObject* dict, PyObject* obj, char *attrname) +{ + PyObject *list; + int result = 0; + + assert(PyDict_Check(dict)); + assert(obj); + assert(attrname); + + list = PyObject_GetAttrString(obj, attrname); + if (list == NULL) + PyErr_Clear(); + + else if (PyList_Check(list)) { + int i; + for (i = 0; i < PyList_GET_SIZE(list); ++i) { + PyObject *item = PyList_GET_ITEM(list, i); + if (PyString_Check(item)) { + result = PyDict_SetItem(dict, item, Py_None); + if (result < 0) + break; + } + } + } + + Py_XDECREF(list); + return result; +} + /* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the docstring, which should be kept in synch with this implementation. */ @@ -1484,6 +1521,14 @@ PyObject_Dir(PyObject *arg) if (masterdict == NULL) goto error; + /* Merge in __members__ and __methods__ (if any). + XXX Would like this to go away someday; for now, it's + XXX needed to get at im_self etc of method objects. */ + if (merge_list_attr(masterdict, arg, "__members__") < 0) + goto error; + if (merge_list_attr(masterdict, arg, "__methods__") < 0) + goto error; + /* Merge in attrs reachable from its class. CAUTION: Not all objects have a __class__ attr. */ itsclass = PyObject_GetAttrString(arg, "__class__"); |