Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 305b585

Browse files
committed
PyObject_Dir(): Merge in __members__ and __methods__ too (if they exist,
and are lists, and then just the string elements (if any)). There are good and bad reasons for this. The good reason is to support dir() "like before" on objects of extension types that haven't migrated to the class introspection API yet. The bad reason is that Python's own method objects are such a type, and this is the quickest way to get their im_self etc attrs to "show up" via dir(). It looks much messier to move them to the new scheme, as their current getattr implementation presents a view of their attrs that's a untion of their own attrs plus their im_func's attrs. In particular, methodobject.__dict__ actually returns methodobject.im_func.__dict__, and if that's important to preserve it doesn't seem to fit the class introspection model at all.
1 parent bc7e863 commit 305b585

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

Lib/test/test_descr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,22 +190,26 @@ def Cmethod(self): pass
190190

191191
cstuff = ['Cdata', 'Cmethod', '__doc__', '__module__']
192192
verify(dir(C) == cstuff)
193+
verify('im_self' in dir(C.Cmethod))
193194

194195
c = C() # c.__doc__ is an odd thing to see here; ditto c.__module__.
195196
verify(dir(c) == cstuff)
196197

197198
c.cdata = 2
198199
c.cmethod = lambda self: 0
199200
verify(dir(c) == cstuff + ['cdata', 'cmethod'])
201+
verify('im_self' in dir(c.Cmethod))
200202

201203
class A(C):
202204
Adata = 1
203205
def Amethod(self): pass
204206

205207
astuff = ['Adata', 'Amethod'] + cstuff
206208
verify(dir(A) == astuff)
209+
verify('im_self' in dir(A.Amethod))
207210
a = A()
208211
verify(dir(a) == astuff)
212+
verify('im_self' in dir(a.Amethod))
209213
a.adata = 42
210214
a.amethod = lambda self: 3
211215
verify(dir(a) == astuff + ['adata', 'amethod'])
@@ -224,22 +228,26 @@ def Cmethod(self): pass
224228

225229
c = C()
226230
verify(interesting(dir(c)) == cstuff)
231+
verify('im_self' in dir(C.Cmethod))
227232

228233
c.cdata = 2
229234
c.cmethod = lambda self: 0
230235
verify(interesting(dir(c)) == cstuff + ['cdata', 'cmethod'])
236+
verify('im_self' in dir(c.Cmethod))
231237

232238
class A(C):
233239
Adata = 1
234240
def Amethod(self): pass
235241

236242
astuff = ['Adata', 'Amethod'] + cstuff
237243
verify(interesting(dir(A)) == astuff)
244+
verify('im_self' in dir(A.Amethod))
238245
a = A()
239246
verify(interesting(dir(a)) == astuff)
240247
a.adata = 42
241248
a.amethod = lambda self: 3
242249
verify(interesting(dir(a)) == astuff + ['adata', 'amethod'])
250+
verify('im_self' in dir(a.Amethod))
243251

244252
# Try a module subclass.
245253
import sys

Objects/object.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,43 @@ merge_class_dict(PyObject* dict, PyObject* aclass)
14171417
return 0;
14181418
}
14191419

1420+
/* Helper for PyObject_Dir.
1421+
If obj has an attr named attrname that's a list, merge its string
1422+
elements into keys of dict.
1423+
Return 0 on success, -1 on error. Errors due to not finding the attr,
1424+
or the attr not being a list, are suppressed.
1425+
*/
1426+
1427+
static int
1428+
merge_list_attr(PyObject* dict, PyObject* obj, char *attrname)
1429+
{
1430+
PyObject *list;
1431+
int result = 0;
1432+
1433+
assert(PyDict_Check(dict));
1434+
assert(obj);
1435+
assert(attrname);
1436+
1437+
list = PyObject_GetAttrString(obj, attrname);
1438+
if (list == NULL)
1439+
PyErr_Clear();
1440+
1441+
else if (PyList_Check(list)) {
1442+
int i;
1443+
for (i = 0; i < PyList_GET_SIZE(list); ++i) {
1444+
PyObject *item = PyList_GET_ITEM(list, i);
1445+
if (PyString_Check(item)) {
1446+
result = PyDict_SetItem(dict, item, Py_None);
1447+
if (result < 0)
1448+
break;
1449+
}
1450+
}
1451+
}
1452+
1453+
Py_XDECREF(list);
1454+
return result;
1455+
}
1456+
14201457
/* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the
14211458
docstring, which should be kept in synch with this implementation. */
14221459

@@ -1484,6 +1521,14 @@ PyObject_Dir(PyObject *arg)
14841521
if (masterdict == NULL)
14851522
goto error;
14861523

1524+
/* Merge in __members__ and __methods__ (if any).
1525+
XXX Would like this to go away someday; for now, it's
1526+
XXX needed to get at im_self etc of method objects. */
1527+
if (merge_list_attr(masterdict, arg, "__members__") < 0)
1528+
goto error;
1529+
if (merge_list_attr(masterdict, arg, "__methods__") < 0)
1530+
goto error;
1531+
14871532
/* Merge in attrs reachable from its class.
14881533
CAUTION: Not all objects have a __class__ attr. */
14891534
itsclass = PyObject_GetAttrString(arg, "__class__");

0 commit comments

Comments
 (0)