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

Skip to content

Commit 82b00c1

Browse files
committed
move specialized dir implementations into __dir__ methods (closes #12166)
1 parent 9bcfacd commit 82b00c1

5 files changed

Lines changed: 178 additions & 178 deletions

File tree

Lib/test/test_descrtut.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ def merge(self, other):
170170
'__contains__',
171171
'__delattr__',
172172
'__delitem__',
173+
'__dir__',
173174
'__doc__',
174175
'__eq__',
175176
'__format__',

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #12166: Move implementations of dir() specialized for various types into
14+
the __dir__() methods of those types.
15+
1316
- Correct lookup of __dir__ on objects. Among other things, this causes errors
1417
besides AttributeError found on lookup to be propagated.
1518

Objects/moduleobject.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,34 @@ module_clear(PyModuleObject *m)
413413
return 0;
414414
}
415415

416+
static PyObject *
417+
module_dir(PyObject *self, PyObject *args)
418+
{
419+
PyObject *result = NULL;
420+
PyObject *dict = PyObject_GetAttrString(self, "__dict__");
421+
422+
if (dict != NULL) {
423+
if (PyDict_Check(dict))
424+
result = PyDict_Keys(dict);
425+
else {
426+
const char *name = PyModule_GetName(self);
427+
if (name)
428+
PyErr_Format(PyExc_TypeError,
429+
"%.200s.__dict__ is not a dictionary",
430+
name);
431+
}
432+
}
433+
434+
Py_XDECREF(dict);
435+
return result;
436+
}
437+
438+
static PyMethodDef module_methods[] = {
439+
{"__dir__", module_dir, METH_NOARGS,
440+
PyDoc_STR("__dir__() -> specialized dir() implementation")},
441+
{0}
442+
};
443+
416444

417445
PyDoc_STRVAR(module_doc,
418446
"module(name[, doc])\n\
@@ -449,7 +477,7 @@ PyTypeObject PyModule_Type = {
449477
0, /* tp_weaklistoffset */
450478
0, /* tp_iter */
451479
0, /* tp_iternext */
452-
0, /* tp_methods */
480+
module_methods, /* tp_methods */
453481
module_members, /* tp_members */
454482
0, /* tp_getset */
455483
0, /* tp_base */

Objects/object.c

Lines changed: 18 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,66 +1182,6 @@ PyCallable_Check(PyObject *x)
11821182
return x->ob_type->tp_call != NULL;
11831183
}
11841184

1185-
/* ------------------------- PyObject_Dir() helpers ------------------------- */
1186-
1187-
/* Helper for PyObject_Dir.
1188-
Merge the __dict__ of aclass into dict, and recursively also all
1189-
the __dict__s of aclass's base classes. The order of merging isn't
1190-
defined, as it's expected that only the final set of dict keys is
1191-
interesting.
1192-
Return 0 on success, -1 on error.
1193-
*/
1194-
1195-
static int
1196-
merge_class_dict(PyObject* dict, PyObject* aclass)
1197-
{
1198-
PyObject *classdict;
1199-
PyObject *bases;
1200-
1201-
assert(PyDict_Check(dict));
1202-
assert(aclass);
1203-
1204-
/* Merge in the type's dict (if any). */
1205-
classdict = PyObject_GetAttrString(aclass, "__dict__");
1206-
if (classdict == NULL)
1207-
PyErr_Clear();
1208-
else {
1209-
int status = PyDict_Update(dict, classdict);
1210-
Py_DECREF(classdict);
1211-
if (status < 0)
1212-
return -1;
1213-
}
1214-
1215-
/* Recursively merge in the base types' (if any) dicts. */
1216-
bases = PyObject_GetAttrString(aclass, "__bases__");
1217-
if (bases == NULL)
1218-
PyErr_Clear();
1219-
else {
1220-
/* We have no guarantee that bases is a real tuple */
1221-
Py_ssize_t i, n;
1222-
n = PySequence_Size(bases); /* This better be right */
1223-
if (n < 0)
1224-
PyErr_Clear();
1225-
else {
1226-
for (i = 0; i < n; i++) {
1227-
int status;
1228-
PyObject *base = PySequence_GetItem(bases, i);
1229-
if (base == NULL) {
1230-
Py_DECREF(bases);
1231-
return -1;
1232-
}
1233-
status = merge_class_dict(dict, base);
1234-
Py_DECREF(base);
1235-
if (status < 0) {
1236-
Py_DECREF(bases);
1237-
return -1;
1238-
}
1239-
}
1240-
}
1241-
Py_DECREF(bases);
1242-
}
1243-
return 0;
1244-
}
12451185

12461186
/* Helper for PyObject_Dir without arguments: returns the local scope. */
12471187
static PyObject *
@@ -1269,133 +1209,34 @@ _dir_locals(void)
12691209
return names;
12701210
}
12711211

1272-
/* Helper for PyObject_Dir of type objects: returns __dict__ and __bases__.
1273-
We deliberately don't suck up its __class__, as methods belonging to the
1274-
metaclass would probably be more confusing than helpful.
1275-
*/
1276-
static PyObject *
1277-
_specialized_dir_type(PyObject *obj)
1278-
{
1279-
PyObject *result = NULL;
1280-
PyObject *dict = PyDict_New();
1281-
1282-
if (dict != NULL && merge_class_dict(dict, obj) == 0)
1283-
result = PyDict_Keys(dict);
1284-
1285-
Py_XDECREF(dict);
1286-
return result;
1287-
}
1288-
1289-
/* Helper for PyObject_Dir of module objects: returns the module's __dict__. */
1290-
static PyObject *
1291-
_specialized_dir_module(PyObject *obj)
1292-
{
1293-
PyObject *result = NULL;
1294-
PyObject *dict = PyObject_GetAttrString(obj, "__dict__");
1295-
1296-
if (dict != NULL) {
1297-
if (PyDict_Check(dict))
1298-
result = PyDict_Keys(dict);
1299-
else {
1300-
const char *name = PyModule_GetName(obj);
1301-
if (name)
1302-
PyErr_Format(PyExc_TypeError,
1303-
"%.200s.__dict__ is not a dictionary",
1304-
name);
1305-
}
1306-
}
1307-
1308-
Py_XDECREF(dict);
1309-
return result;
1310-
}
1311-
1312-
/* Helper for PyObject_Dir of generic objects: returns __dict__, __class__,
1313-
and recursively up the __class__.__bases__ chain.
1314-
*/
1315-
static PyObject *
1316-
_generic_dir(PyObject *obj)
1317-
{
1318-
PyObject *result = NULL;
1319-
PyObject *dict = NULL;
1320-
PyObject *itsclass = NULL;
1321-
1322-
/* Get __dict__ (which may or may not be a real dict...) */
1323-
dict = PyObject_GetAttrString(obj, "__dict__");
1324-
if (dict == NULL) {
1325-
PyErr_Clear();
1326-
dict = PyDict_New();
1327-
}
1328-
else if (!PyDict_Check(dict)) {
1329-
Py_DECREF(dict);
1330-
dict = PyDict_New();
1331-
}
1332-
else {
1333-
/* Copy __dict__ to avoid mutating it. */
1334-
PyObject *temp = PyDict_Copy(dict);
1335-
Py_DECREF(dict);
1336-
dict = temp;
1337-
}
1338-
1339-
if (dict == NULL)
1340-
goto error;
1341-
1342-
/* Merge in attrs reachable from its class. */
1343-
itsclass = PyObject_GetAttrString(obj, "__class__");
1344-
if (itsclass == NULL)
1345-
/* XXX(tomer): Perhaps fall back to obj->ob_type if no
1346-
__class__ exists? */
1347-
PyErr_Clear();
1348-
else {
1349-
if (merge_class_dict(dict, itsclass) != 0)
1350-
goto error;
1351-
}
1352-
1353-
result = PyDict_Keys(dict);
1354-
/* fall through */
1355-
error:
1356-
Py_XDECREF(itsclass);
1357-
Py_XDECREF(dict);
1358-
return result;
1359-
}
1360-
1361-
/* Helper for PyObject_Dir: object introspection.
1362-
This calls one of the above specialized versions if no __dir__ method
1363-
exists. */
1212+
/* Helper for PyObject_Dir: object introspection. */
13641213
static PyObject *
13651214
_dir_object(PyObject *obj)
13661215
{
1367-
PyObject *result = NULL;
1216+
PyObject *result;
13681217
static PyObject *dir_str = NULL;
13691218
PyObject *dirfunc = _PyObject_LookupSpecial(obj, "__dir__", &dir_str);
13701219

13711220
assert(obj);
13721221
if (dirfunc == NULL) {
1373-
if (PyErr_Occurred())
1374-
return NULL;
1375-
/* use default implementation */
1376-
if (PyModule_Check(obj))
1377-
result = _specialized_dir_module(obj);
1378-
else if (PyType_Check(obj))
1379-
result = _specialized_dir_type(obj);
1380-
else
1381-
result = _generic_dir(obj);
1222+
if (!PyErr_Occurred())
1223+
PyErr_SetString(PyExc_TypeError, "object does not provide __dir__");
1224+
return NULL;
13821225
}
1383-
else {
1384-
/* use __dir__ */
1385-
result = PyObject_CallFunctionObjArgs(dirfunc, NULL);
1386-
Py_DECREF(dirfunc);
1387-
if (result == NULL)
1388-
return NULL;
1226+
/* use __dir__ */
1227+
result = PyObject_CallFunctionObjArgs(dirfunc, NULL);
1228+
Py_DECREF(dirfunc);
1229+
if (result == NULL)
1230+
return NULL;
13891231

1390-
/* result must be a list */
1391-
/* XXX(gbrandl): could also check if all items are strings */
1392-
if (!PyList_Check(result)) {
1393-
PyErr_Format(PyExc_TypeError,
1394-
"__dir__() must return a list, not %.200s",
1395-
Py_TYPE(result)->tp_name);
1396-
Py_DECREF(result);
1397-
result = NULL;
1398-
}
1232+
/* result must be a list */
1233+
/* XXX(gbrandl): could also check if all items are strings */
1234+
if (!PyList_Check(result)) {
1235+
PyErr_Format(PyExc_TypeError,
1236+
"__dir__() must return a list, not %.200s",
1237+
Py_TYPE(result)->tp_name);
1238+
Py_DECREF(result);
1239+
result = NULL;
13991240
}
14001241

14011242
return result;

0 commit comments

Comments
 (0)