Skip to content

Commit 3bbb722

Browse files
committed
allow __dir__ to return any sequence
1 parent 703f7c4 commit 3bbb722

File tree

4 files changed

+29
-32
lines changed

4 files changed

+29
-32
lines changed

Doc/reference/datamodel.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,8 @@ access (use of, assignment to, or deletion of ``x.name``) for class instances.
13431343

13441344
.. method:: object.__dir__(self)
13451345

1346-
Called when :func:`dir` is called on the object. A list must be returned.
1346+
Called when :func:`dir` is called on the object. A sequence must be
1347+
returned. :func:`dir` converts the returned sequence to a list and sorts it.
13471348

13481349

13491350
.. _descriptors:

Lib/test/test_builtin.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,15 @@ def __dir__(self):
372372
f = Foo()
373373
self.assertTrue(dir(f) == ["ga", "kan", "roo"])
374374

375-
# dir(obj__dir__not_list)
375+
# dir(obj__dir__tuple)
376+
class Foo(object):
377+
def __dir__(self):
378+
return ("b", "c", "a")
379+
res = dir(Foo())
380+
self.assertIsInstance(res, list)
381+
self.assertTrue(res == ["a", "b", "c"])
382+
383+
# dir(obj__dir__not_sequence)
376384
class Foo(object):
377385
def __dir__(self):
378386
return 7

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+
- Loosen type restrictions on the __dir__ method. __dir__ can now return any
14+
sequence, which will be converted to a list and sorted by dir().
15+
1316
- Issue #12265: Make error messages produced by passing an invalid set of
1417
arguments to a function more informative.
1518

Objects/object.c

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,10 @@ _dir_locals(void)
12051205
Py_DECREF(names);
12061206
return NULL;
12071207
}
1208+
if (PyList_Sort(names)) {
1209+
Py_DECREF(names);
1210+
return NULL;
1211+
}
12081212
/* the locals don't need to be DECREF'd */
12091213
return names;
12101214
}
@@ -1213,7 +1217,7 @@ _dir_locals(void)
12131217
static PyObject *
12141218
_dir_object(PyObject *obj)
12151219
{
1216-
PyObject *result;
1220+
PyObject *result, *sorted;
12171221
static PyObject *dir_str = NULL;
12181222
PyObject *dirfunc = _PyObject_LookupSpecial(obj, "__dir__", &dir_str);
12191223

@@ -1228,18 +1232,16 @@ _dir_object(PyObject *obj)
12281232
Py_DECREF(dirfunc);
12291233
if (result == NULL)
12301234
return NULL;
1231-
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;
1235+
/* return sorted(result) */
1236+
sorted = PySequence_List(result);
1237+
Py_DECREF(result);
1238+
if (sorted == NULL)
1239+
return NULL;
1240+
if (PyList_Sort(sorted)) {
1241+
Py_DECREF(sorted);
1242+
return NULL;
12401243
}
1241-
1242-
return result;
1244+
return sorted;
12431245
}
12441246

12451247
/* Implementation of dir() -- if obj is NULL, returns the names in the current
@@ -1249,24 +1251,7 @@ _dir_object(PyObject *obj)
12491251
PyObject *
12501252
PyObject_Dir(PyObject *obj)
12511253
{
1252-
PyObject * result;
1253-
1254-
if (obj == NULL)
1255-
/* no object -- introspect the locals */
1256-
result = _dir_locals();
1257-
else
1258-
/* object -- introspect the object */
1259-
result = _dir_object(obj);
1260-
1261-
assert(result == NULL || PyList_Check(result));
1262-
1263-
if (result != NULL && PyList_Sort(result) != 0) {
1264-
/* sorting the list failed */
1265-
Py_DECREF(result);
1266-
result = NULL;
1267-
}
1268-
1269-
return result;
1254+
return (obj == NULL) ? _dir_locals() : _dir_object(obj);
12701255
}
12711256

12721257
/*

0 commit comments

Comments
 (0)