summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-09-04 22:08:56 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-09-04 22:08:56 (GMT)
commit7eea37e8317bda88d9f50b862f13642e837957ce (patch)
tree33b41620f6b0e2266d19d43aa8fad9743f3bb3d4
parent2f760c35e2372dc50102305f407e5eed7e7b5c0a (diff)
downloadcpython-7eea37e8317bda88d9f50b862f13642e837957ce.zip
cpython-7eea37e8317bda88d9f50b862f13642e837957ce.tar.gz
cpython-7eea37e8317bda88d9f50b862f13642e837957ce.tar.bz2
At Guido's suggestion, here's a new C API function, PyObject_Dir(), like
__builtin__.dir(). Moved the guts from bltinmodule.c to object.c.
-rw-r--r--Doc/api/api.tex10
-rw-r--r--Include/object.h8
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/object.c145
-rw-r--r--Python/bltinmodule.c138
5 files changed, 167 insertions, 138 deletions
diff --git a/Doc/api/api.tex b/Doc/api/api.tex
index 8836cdf..a185509 100644
--- a/Doc/api/api.tex
+++ b/Doc/api/api.tex
@@ -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}}
diff --git a/Include/object.h b/Include/object.h
index 6cd20a6..d9c3514 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -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 *);
diff --git a/Misc/NEWS b/Misc/NEWS
index a8f05c7..7d44a59 100644
--- 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
diff --git a/Objects/object.c b/Objects/object.c
index 66b4eae..365d131 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -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.
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index d3d32c9..8fff44c 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -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[] =