]> granicus.if.org Git - python/commitdiff
At Guido's suggestion, here's a new C API function, PyObject_Dir(), like
authorTim Peters <tim.peters@gmail.com>
Tue, 4 Sep 2001 22:08:56 +0000 (22:08 +0000)
committerTim Peters <tim.peters@gmail.com>
Tue, 4 Sep 2001 22:08:56 +0000 (22:08 +0000)
__builtin__.dir().  Moved the guts from bltinmodule.c to object.c.

Doc/api/api.tex
Include/object.h
Misc/NEWS
Objects/object.c
Python/bltinmodule.c

index 8836cdf57a2ff37412113f09446bb96aace6ce65..a185509898bc357cc2180a642c3ab3a08300e8b2 100644 (file)
@@ -1720,6 +1720,16 @@ must return an integer or long integer, which is returned as the file
 descriptor value.  Returns \code{-1} on failure.
 \end{cfuncdesc}
 
+\begin{cfuncdesc}{PyObject*}{PyObject_Dir}{PyObject *o}
+This is equivalent to the Python expression \samp{dir(\var{o})},
+returning a (possibly empty) list of strings appropriate for the
+object argument, or \NULL{} in case of error.
+If the argument is \NULL{}, this is like the Python \samp{dir()},
+returning the names of the current locals; in this case, if no
+execution frame is active then \NULL{} is returned but
+\cfunction{PyErr_Occurred()} will return false.
+\end{cfuncdesc}
+
 
 \section{Number Protocol \label{number}}
 
index 6cd20a6e61895b52dd84cd9717415214565ed68e..d9c35144b32bb6cf8fac087d156e3cd61107e370 100644 (file)
@@ -346,6 +346,14 @@ extern DL_IMPORT(int) PyNumber_CoerceEx(PyObject **, PyObject **);
 
 extern DL_IMPORT(void) (*PyObject_ClearWeakRefs)(PyObject *);
 
+/* PyObject_Dir(obj) acts like Python __builtin__.dir(obj), returning a
+   list of strings.  PyObject_Dir(NULL) is like __builtin__.dir(),
+   returning the names of the current locals.  In this case, if there are
+   no current locals, NULL is returned, and PyErr_Occurred() is false.
+*/
+extern DL_IMPORT(PyObject *) PyObject_Dir(PyObject *);
+
+
 /* Helpers for printing recursive container types */
 extern DL_IMPORT(int) Py_ReprEnter(PyObject *);
 extern DL_IMPORT(void) Py_ReprLeave(PyObject *);
index a8f05c7e82db3393dc268d061134a455be23f593..7d44a5930f420d6ba15f870f334387489ecf6b27 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -96,7 +96,9 @@ Tools
 
 Build
 
-API
+C API
+
+- New function PyObject_Dir(obj), like Python __builtin__.dir(obj).
 
 - Note that PyLong_AsDouble can fail!  This has always been true, but no
   callers checked for it.  It's more likely to fail now, because overflow
index 66b4eae2b2fc9ebfca76bebf4cede3b77224d4b9..365d1313f7966e3469caba99eba4b651581b2e60 100644 (file)
@@ -1357,6 +1357,151 @@ PyCallable_Check(PyObject *x)
        }
 }
 
+/* Helper for PyObject_Dir.
+   Merge the __dict__ of aclass into dict, and recursively also all
+   the __dict__s of aclass's base classes.  The order of merging isn't
+   defined, as it's expected that only the final set of dict keys is
+   interesting.
+   Return 0 on success, -1 on error.
+*/
+
+static int
+merge_class_dict(PyObject* dict, PyObject* aclass)
+{
+       PyObject *classdict;
+       PyObject *bases;
+
+       assert(PyDict_Check(dict));
+       assert(aclass);
+
+       /* Merge in the type's dict (if any). */
+       classdict = PyObject_GetAttrString(aclass, "__dict__");
+       if (classdict == NULL)
+               PyErr_Clear();
+       else {
+               int status = PyDict_Update(dict, classdict);
+               Py_DECREF(classdict);
+               if (status < 0)
+                       return -1;
+       }
+
+       /* Recursively merge in the base types' (if any) dicts. */
+       bases = PyObject_GetAttrString(aclass, "__bases__");
+       if (bases != NULL) {
+               int i, n;
+               assert(PyTuple_Check(bases));
+               n = PyTuple_GET_SIZE(bases);
+               for (i = 0; i < n; i++) {
+                       PyObject *base = PyTuple_GET_ITEM(bases, i);
+                       if (merge_class_dict(dict, base) < 0) {
+                               Py_DECREF(bases);
+                               return -1;
+                       }
+               }
+               Py_DECREF(bases);
+       }
+       return 0;
+}
+
+/* Like __builtin__.dir(arg).  See bltinmodule.c's builtin_dir for the
+   docstring, which should be kept in synch with this implementation. */
+
+PyObject *
+PyObject_Dir(PyObject *arg)
+{
+       /* Set exactly one of these non-NULL before the end. */
+       PyObject *result = NULL;        /* result list */
+       PyObject *masterdict = NULL;    /* result is masterdict.keys() */
+
+       /* If NULL arg, return the locals. */
+       if (arg == NULL) {
+               PyObject *locals = PyEval_GetLocals();
+               if (locals == NULL)
+                       goto error;
+               result = PyDict_Keys(locals);
+               if (result == NULL)
+                       goto error;
+       }
+
+       /* Elif this is some form of module, we only want its dict. */
+       else if (PyObject_TypeCheck(arg, &PyModule_Type)) {
+               masterdict = PyObject_GetAttrString(arg, "__dict__");
+               if (masterdict == NULL)
+                       goto error;
+               assert(PyDict_Check(masterdict));
+       }
+
+       /* Elif some form of type or class, grab its dict and its bases.
+          We deliberately don't suck up its __class__, as methods belonging
+          to the metaclass would probably be more confusing than helpful. */
+       else if (PyType_Check(arg) || PyClass_Check(arg)) {
+               masterdict = PyDict_New();
+               if (masterdict == NULL)
+                       goto error;
+               if (merge_class_dict(masterdict, arg) < 0)
+                       goto error;
+       }
+
+       /* Else look at its dict, and the attrs reachable from its class. */
+       else {
+               PyObject *itsclass;
+               /* Create a dict to start with.  CAUTION:  Not everything
+                  responding to __dict__ returns a dict! */
+               masterdict = PyObject_GetAttrString(arg, "__dict__");
+               if (masterdict == NULL) {
+                       PyErr_Clear();
+                       masterdict = PyDict_New();
+               }
+               else if (!PyDict_Check(masterdict)) {
+                       Py_DECREF(masterdict);
+                       masterdict = PyDict_New();
+               }
+               else {
+                       /* The object may have returned a reference to its
+                          dict, so copy it to avoid mutating it. */
+                       PyObject *temp = PyDict_Copy(masterdict);
+                       Py_DECREF(masterdict);
+                       masterdict = temp;
+               }
+               if (masterdict == NULL)
+                       goto error;
+
+               /* Merge in attrs reachable from its class.
+                  CAUTION:  Not all objects have a __class__ attr. */
+               itsclass = PyObject_GetAttrString(arg, "__class__");
+               if (itsclass == NULL)
+                       PyErr_Clear();
+               else {
+                       int status = merge_class_dict(masterdict, itsclass);
+                       Py_DECREF(itsclass);
+                       if (status < 0)
+                               goto error;
+               }
+       }
+
+       assert((result == NULL) ^ (masterdict == NULL));
+       if (masterdict != NULL) {
+               /* The result comes from its keys. */
+               assert(result == NULL);
+               result = PyDict_Keys(masterdict);
+               if (result == NULL)
+                       goto error;
+       }
+
+       assert(result);
+       if (PyList_Sort(result) != 0)
+               goto error;
+       else
+               goto normal_return;
+
+  error:
+       Py_XDECREF(result);
+       result = NULL;
+       /* fall through */
+  normal_return:
+       Py_XDECREF(masterdict);
+       return result;
+}
 
 /*
 NoObject is usable as a non-NULL undefined value, used by the macro None.
index d3d32c9ff566fb8cb5a1ffd4a8eaab97fd77e8db..8fff44c279abd9e87dde5e76ed4c048cfc148624 100644 (file)
@@ -426,150 +426,14 @@ the effects of any future statements in effect in the code calling\n\
 compile; if absent or zero these statements do influence the compilation,\n\
 in addition to any features explicitly specified.";
 
-/* Merge the __dict__ of aclass into dict, and recursively also all
-   the __dict__s of aclass's base classes.  The order of merging isn't
-   defined, as it's expected that only the final set of dict keys is
-   interesting.
-   Return 0 on success, -1 on error.
-*/
-
-static int
-merge_class_dict(PyObject* dict, PyObject* aclass)
-{
-       PyObject *classdict;
-       PyObject *bases;
-
-       assert(PyDict_Check(dict));
-       assert(aclass);
-
-       /* Merge in the type's dict (if any). */
-       classdict = PyObject_GetAttrString(aclass, "__dict__");
-       if (classdict == NULL)
-               PyErr_Clear();
-       else {
-               int status = PyDict_Update(dict, classdict);
-               Py_DECREF(classdict);
-               if (status < 0)
-                       return -1;
-       }
-
-       /* Recursively merge in the base types' (if any) dicts. */
-       bases = PyObject_GetAttrString(aclass, "__bases__");
-       if (bases != NULL) {
-               int i, n;
-               assert(PyTuple_Check(bases));
-               n = PyTuple_GET_SIZE(bases);
-               for (i = 0; i < n; i++) {
-                       PyObject *base = PyTuple_GET_ITEM(bases, i);
-                       if (merge_class_dict(dict, base) < 0) {
-                               Py_DECREF(bases);
-                               return -1;
-                       }
-               }
-               Py_DECREF(bases);
-       }
-       return 0;
-}
-
 static PyObject *
 builtin_dir(PyObject *self, PyObject *args)
 {
        PyObject *arg = NULL;
-       /* Set exactly one of these non-NULL before the end. */
-       PyObject *result = NULL;        /* result list */
-       PyObject *masterdict = NULL;    /* result is masterdict.keys() */
 
        if (!PyArg_ParseTuple(args, "|O:dir", &arg))
                return NULL;
-
-       /* If no arg, return the locals. */
-       if (arg == NULL) {
-               PyObject *locals = PyEval_GetLocals();
-               if (locals == NULL)
-                       goto error;
-               result = PyDict_Keys(locals);
-               if (result == NULL)
-                       goto error;
-       }
-
-       /* Elif this is some form of module, we only want its dict. */
-       else if (PyObject_TypeCheck(arg, &PyModule_Type)) {
-               masterdict = PyObject_GetAttrString(arg, "__dict__");
-               if (masterdict == NULL)
-                       goto error;
-               assert(PyDict_Check(masterdict));
-       }
-
-       /* Elif some form of type or class, grab its dict and its bases.
-          We deliberately don't suck up its __class__, as methods belonging
-          to the metaclass would probably be more confusing than helpful. */
-       else if (PyType_Check(arg) || PyClass_Check(arg)) {
-               masterdict = PyDict_New();
-               if (masterdict == NULL)
-                       goto error;
-               if (merge_class_dict(masterdict, arg) < 0)
-                       goto error;
-       }
-
-       /* Else look at its dict, and the attrs reachable from its class. */
-       else {
-               PyObject *itsclass;
-               /* Create a dict to start with.  CAUTION:  Not everything
-                  responding to __dict__ returns a dict! */
-               masterdict = PyObject_GetAttrString(arg, "__dict__");
-               if (masterdict == NULL) {
-                       PyErr_Clear();
-                       masterdict = PyDict_New();
-               }
-               else if (!PyDict_Check(masterdict)) {
-                       Py_DECREF(masterdict);
-                       masterdict = PyDict_New();
-               }
-               else {
-                       /* The object may have returned a reference to its
-                          dict, so copy it to avoid mutating it. */
-                       PyObject *temp = PyDict_Copy(masterdict);
-                       Py_DECREF(masterdict);
-                       masterdict = temp;
-               }
-               if (masterdict == NULL)
-                       goto error;
-
-               /* Merge in attrs reachable from its class.
-                  CAUTION:  Not all objects have a __class__ attr. */
-               itsclass = PyObject_GetAttrString(arg, "__class__");
-               if (itsclass == NULL)
-                       PyErr_Clear();
-               else {
-                       int status = merge_class_dict(masterdict, itsclass);
-                       Py_DECREF(itsclass);
-                       if (status < 0)
-                               goto error;
-               }
-       }
-
-       assert((result == NULL) ^ (masterdict == NULL));
-       if (masterdict != NULL) {
-               /* The result comes from its keys. */
-               assert(result == NULL);
-               result = PyDict_Keys(masterdict);
-               if (result == NULL)
-                       goto error;
-       }
-
-       assert(result);
-       if (PyList_Sort(result) != 0)
-               goto error;
-       else
-               goto normal_return;
-
-  error:
-       Py_XDECREF(result);
-       result = NULL;
-       /* fall through */
-  normal_return:
-       Py_XDECREF(masterdict);
-       return result;
+       return PyObject_Dir(arg);
 }
 
 static char dir_doc[] =