]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
allow __dir__ to return any sequence
authorBenjamin Peterson <benjamin@python.org>
Sat, 11 Jun 2011 21:12:08 +0000 (16:12 -0500)
committerBenjamin Peterson <benjamin@python.org>
Sat, 11 Jun 2011 21:12:08 +0000 (16:12 -0500)
Doc/reference/datamodel.rst
Lib/test/test_builtin.py
Misc/NEWS
Objects/object.c

index 129f987a449932041ce7a572fb4c9f86a331c701..e628a02876bda6fd19b26c6041ddb544111d5d33 100644 (file)
@@ -1343,7 +1343,8 @@ access (use of, assignment to, or deletion of ``x.name``) for class instances.
 
 .. method:: object.__dir__(self)
 
-   Called when :func:`dir` is called on the object.  A list must be returned.
+   Called when :func:`dir` is called on the object. A sequence must be
+   returned. :func:`dir` converts the returned sequence to a list and sorts it.
 
 
 .. _descriptors:
index 97619cf9ef4119bae4aa6169ac9df4000837a10e..ce1586f98d8647cd31f6015b826c990973c0b661 100644 (file)
@@ -372,7 +372,15 @@ class BuiltinTest(unittest.TestCase):
         f = Foo()
         self.assertTrue(dir(f) == ["ga", "kan", "roo"])
 
-        # dir(obj__dir__not_list)
+        # dir(obj__dir__tuple)
+        class Foo(object):
+            def __dir__(self):
+                return ("b", "c", "a")
+        res = dir(Foo())
+        self.assertIsInstance(res, list)
+        self.assertTrue(res == ["a", "b", "c"])
+
+        # dir(obj__dir__not_sequence)
         class Foo(object):
             def __dir__(self):
                 return 7
index e2538fcd7b4f3122a653185d4a2ead19834fff9c..e13f72c7a5a3982df15c30705c99a254dea83a3e 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
 Core and Builtins
 -----------------
 
+- Loosen type restrictions on the __dir__ method. __dir__ can now return any
+  sequence, which will be converted to a list and sorted by dir().
+
 - Issue #12265: Make error messages produced by passing an invalid set of
   arguments to a function more informative.
 
index e42c1d9b06dbbe78e19cefadb35450fd28e522a9..80ffddbdb51d5e33b44b8303e5b375aa453d078f 100644 (file)
@@ -1205,6 +1205,10 @@ _dir_locals(void)
         Py_DECREF(names);
         return NULL;
     }
+    if (PyList_Sort(names)) {
+        Py_DECREF(names);
+        return NULL;
+    }
     /* the locals don't need to be DECREF'd */
     return names;
 }
@@ -1213,7 +1217,7 @@ _dir_locals(void)
 static PyObject *
 _dir_object(PyObject *obj)
 {
-    PyObject *result;
+    PyObject *result, *sorted;
     static PyObject *dir_str = NULL;
     PyObject *dirfunc = _PyObject_LookupSpecial(obj, "__dir__", &dir_str);
 
@@ -1228,18 +1232,16 @@ _dir_object(PyObject *obj)
     Py_DECREF(dirfunc);
     if (result == NULL)
         return NULL;
-
-    /* result must be a list */
-    /* XXX(gbrandl): could also check if all items are strings */
-    if (!PyList_Check(result)) {
-        PyErr_Format(PyExc_TypeError,
-                     "__dir__() must return a list, not %.200s",
-                     Py_TYPE(result)->tp_name);
-        Py_DECREF(result);
-        result = NULL;
+    /* return sorted(result) */
+    sorted = PySequence_List(result);
+    Py_DECREF(result);
+    if (sorted == NULL)
+        return NULL;
+    if (PyList_Sort(sorted)) {
+        Py_DECREF(sorted);
+        return NULL;
     }
-
-    return result;
+    return sorted;
 }
 
 /* Implementation of dir() -- if obj is NULL, returns the names in the current
@@ -1249,24 +1251,7 @@ _dir_object(PyObject *obj)
 PyObject *
 PyObject_Dir(PyObject *obj)
 {
-    PyObject * result;
-
-    if (obj == NULL)
-        /* no object -- introspect the locals */
-        result = _dir_locals();
-    else
-        /* object -- introspect the object */
-        result = _dir_object(obj);
-
-    assert(result == NULL || PyList_Check(result));
-
-    if (result != NULL && PyList_Sort(result) != 0) {
-        /* sorting the list failed */
-        Py_DECREF(result);
-        result = NULL;
-    }
-
-    return result;
+    return (obj == NULL) ? _dir_locals() : _dir_object(obj);
 }
 
 /*