cpython: 8f403199f999 (original) (raw)
Mercurial > cpython
changeset 70331:8f403199f999
move specialized dir implementations into __dir__ methods (closes #12166) [#12166]
Benjamin Peterson benjamin@python.org | |
---|---|
date | Tue, 24 May 2011 11:09:06 -0500 |
parents | 28c1f8480090 |
children | 0e56d79fa2ab |
files | Lib/test/test_descrtut.py Misc/NEWS Objects/moduleobject.c Objects/object.c Objects/typeobject.c |
diffstat | 5 files changed, 178 insertions(+), 178 deletions(-)[+] [-] Lib/test/test_descrtut.py 1 Misc/NEWS 3 Objects/moduleobject.c 30 Objects/object.c 195 Objects/typeobject.c 127 |
line wrap: on
line diff
--- a/Lib/test/test_descrtut.py +++ b/Lib/test/test_descrtut.py @@ -170,6 +170,7 @@ You can get the information from the lis 'contains', 'delattr', 'delitem',
'__dir__',[](#l1.7) '__doc__',[](#l1.8) '__eq__',[](#l1.9) '__format__',[](#l1.10)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1? Core and Builtins ----------------- +- Issue #12166: Move implementations of dir() specialized for various types into
- Correct lookup of dir on objects. Among other things, this causes errors besides AttributeError found on lookup to be propagated.
--- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -413,6 +413,34 @@ module_clear(PyModuleObject *m) return 0; } +static PyObject * +module_dir(PyObject *self, PyObject *args) +{
- if (dict != NULL) {
if (PyDict_Check(dict))[](#l3.14)
result = PyDict_Keys(dict);[](#l3.15)
else {[](#l3.16)
const char *name = PyModule_GetName(self);[](#l3.17)
if (name)[](#l3.18)
PyErr_Format(PyExc_TypeError,[](#l3.19)
"%.200s.__dict__ is not a dictionary",[](#l3.20)
name);[](#l3.21)
}[](#l3.22)
- }
+} + +static PyMethodDef module_methods[] = {
- {"dir", module_dir, METH_NOARGS,
PyDoc_STR("__dir__() -> specialized dir() implementation")},[](#l3.31)
- {0}
+}; + PyDoc_STRVAR(module_doc, "module(name[, doc])\n[](#l3.37) @@ -449,7 +477,7 @@ PyTypeObject PyModule_Type = { 0, /* tp_weaklistoffset / 0, / tp_iter / 0, / tp_iternext */
--- a/Objects/object.c +++ b/Objects/object.c @@ -1182,66 +1182,6 @@ PyCallable_Check(PyObject x) return x->ob_type->tp_call != NULL; } -/ ------------------------- PyObject_Dir() helpers ------------------------- / - -/ 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) -{
- /* Merge in the type's dict (if any). */
- classdict = PyObject_GetAttrString(aclass, "dict");
- if (classdict == NULL)
PyErr_Clear();[](#l4.29)
- else {
int status = PyDict_Update(dict, classdict);[](#l4.31)
Py_DECREF(classdict);[](#l4.32)
if (status < 0)[](#l4.33)
return -1;[](#l4.34)
- }
- /* Recursively merge in the base types' (if any) dicts. */
- bases = PyObject_GetAttrString(aclass, "bases");
- if (bases == NULL)
PyErr_Clear();[](#l4.40)
- else {
/* We have no guarantee that bases is a real tuple */[](#l4.42)
Py_ssize_t i, n;[](#l4.43)
n = PySequence_Size(bases); /* This better be right */[](#l4.44)
if (n < 0)[](#l4.45)
PyErr_Clear();[](#l4.46)
else {[](#l4.47)
for (i = 0; i < n; i++) {[](#l4.48)
int status;[](#l4.49)
PyObject *base = PySequence_GetItem(bases, i);[](#l4.50)
if (base == NULL) {[](#l4.51)
Py_DECREF(bases);[](#l4.52)
return -1;[](#l4.53)
}[](#l4.54)
status = merge_class_dict(dict, base);[](#l4.55)
Py_DECREF(base);[](#l4.56)
if (status < 0) {[](#l4.57)
Py_DECREF(bases);[](#l4.58)
return -1;[](#l4.59)
}[](#l4.60)
}[](#l4.61)
}[](#l4.62)
Py_DECREF(bases);[](#l4.63)
- }
- return 0;
-} /* Helper for PyObject_Dir without arguments: returns the local scope. */ static PyObject * @@ -1269,133 +1209,34 @@ static PyObject return names; } -/ Helper for PyObject_Dir of type objects: returns dict and bases.
- We deliberately don't suck up its class, as methods belonging to the
- metaclass would probably be more confusing than helpful. -*/ -static PyObject * -_specialized_dir_type(PyObject *obj) -{
- PyObject *result = NULL;
- PyObject *dict = PyDict_New();
-} - -/* Helper for PyObject_Dir of module objects: returns the module's dict. */ -static PyObject * -_specialized_dir_module(PyObject *obj) -{
- if (dict != NULL) {
if (PyDict_Check(dict))[](#l4.99)
result = PyDict_Keys(dict);[](#l4.100)
else {[](#l4.101)
const char *name = PyModule_GetName(obj);[](#l4.102)
if (name)[](#l4.103)
PyErr_Format(PyExc_TypeError,[](#l4.104)
"%.200s.__dict__ is not a dictionary",[](#l4.105)
name);[](#l4.106)
}[](#l4.107)
- }
-} - -/* Helper for PyObject_Dir of generic objects: returns dict, class,
- and recursively up the class.bases chain. -*/ -static PyObject * -_generic_dir(PyObject *obj) -{
- PyObject *result = NULL;
- PyObject *dict = NULL;
- PyObject *itsclass = NULL;
- /* Get dict (which may or may not be a real dict...) */
- dict = PyObject_GetAttrString(obj, "dict");
- if (dict == NULL) {
PyErr_Clear();[](#l4.127)
dict = PyDict_New();[](#l4.128)
- }
- else if (!PyDict_Check(dict)) {
Py_DECREF(dict);[](#l4.131)
dict = PyDict_New();[](#l4.132)
- }
- else {
/* Copy __dict__ to avoid mutating it. */[](#l4.135)
PyObject *temp = PyDict_Copy(dict);[](#l4.136)
Py_DECREF(dict);[](#l4.137)
dict = temp;[](#l4.138)
- }
- /* Merge in attrs reachable from its class. */
- itsclass = PyObject_GetAttrString(obj, "class");
- if (itsclass == NULL)
/* XXX(tomer): Perhaps fall back to obj->ob_type if no[](#l4.147)
__class__ exists? */[](#l4.148)
PyErr_Clear();[](#l4.149)
- else {
if (merge_class_dict(dict, itsclass) != 0)[](#l4.151)
goto error;[](#l4.152)
- }
-} - -/* Helper for PyObject_Dir: object introspection.
- This calls one of the above specialized versions if no dir method
- exists. / +/ Helper for PyObject_Dir: object introspection. */ static PyObject * _dir_object(PyObject *obj) {
- PyObject *result = NULL;
- PyObject *result; static PyObject *dir_str = NULL; PyObject *dirfunc = _PyObject_LookupSpecial(obj, "dir", &dir_str); assert(obj); if (dirfunc == NULL) {
if (PyErr_Occurred())[](#l4.177)
return NULL;[](#l4.178)
/* use default implementation */[](#l4.179)
if (PyModule_Check(obj))[](#l4.180)
result = _specialized_dir_module(obj);[](#l4.181)
else if (PyType_Check(obj))[](#l4.182)
result = _specialized_dir_type(obj);[](#l4.183)
else[](#l4.184)
result = _generic_dir(obj);[](#l4.185)
if (!PyErr_Occurred())[](#l4.186)
PyErr_SetString(PyExc_TypeError, "object does not provide __dir__");[](#l4.187)
}return NULL;[](#l4.188)
- else {
/* use __dir__ */[](#l4.191)
result = PyObject_CallFunctionObjArgs(dirfunc, NULL);[](#l4.192)
Py_DECREF(dirfunc);[](#l4.193)
if (result == NULL)[](#l4.194)
return NULL;[](#l4.195)
- /* use dir */
- result = PyObject_CallFunctionObjArgs(dirfunc, NULL);
- Py_DECREF(dirfunc);
- if (result == NULL)
return NULL;[](#l4.200)
/* result must be a list */[](#l4.202)
/* XXX(gbrandl): could also check if all items are strings */[](#l4.203)
if (!PyList_Check(result)) {[](#l4.204)
PyErr_Format(PyExc_TypeError,[](#l4.205)
"__dir__() must return a list, not %.200s",[](#l4.206)
Py_TYPE(result)->tp_name);[](#l4.207)
Py_DECREF(result);[](#l4.208)
result = NULL;[](#l4.209)
}[](#l4.210)
- /* result must be a list */
- /* XXX(gbrandl): could also check if all items are strings */
- if (!PyList_Check(result)) {
PyErr_Format(PyExc_TypeError,[](#l4.214)
"__dir__() must return a list, not %.200s",[](#l4.215)
Py_TYPE(result)->tp_name);[](#l4.216)
Py_DECREF(result);[](#l4.217)
} return result;result = NULL;[](#l4.218)
--- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2572,6 +2572,82 @@ type_prepare(PyObject *self, PyObject a return PyDict_New(); } +/
- 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) +{
- /* Merge in the type's dict (if any). */
- classdict = PyObject_GetAttrString(aclass, "dict");
- if (classdict == NULL)
PyErr_Clear();[](#l5.27)
- else {
int status = PyDict_Update(dict, classdict);[](#l5.29)
Py_DECREF(classdict);[](#l5.30)
if (status < 0)[](#l5.31)
return -1;[](#l5.32)
- }
- /* Recursively merge in the base types' (if any) dicts. */
- bases = PyObject_GetAttrString(aclass, "bases");
- if (bases == NULL)
PyErr_Clear();[](#l5.38)
- else {
/* We have no guarantee that bases is a real tuple */[](#l5.40)
Py_ssize_t i, n;[](#l5.41)
n = PySequence_Size(bases); /* This better be right */[](#l5.42)
if (n < 0)[](#l5.43)
PyErr_Clear();[](#l5.44)
else {[](#l5.45)
for (i = 0; i < n; i++) {[](#l5.46)
int status;[](#l5.47)
PyObject *base = PySequence_GetItem(bases, i);[](#l5.48)
if (base == NULL) {[](#l5.49)
Py_DECREF(bases);[](#l5.50)
return -1;[](#l5.51)
}[](#l5.52)
status = merge_class_dict(dict, base);[](#l5.53)
Py_DECREF(base);[](#l5.54)
if (status < 0) {[](#l5.55)
Py_DECREF(bases);[](#l5.56)
return -1;[](#l5.57)
}[](#l5.58)
}[](#l5.59)
}[](#l5.60)
Py_DECREF(bases);[](#l5.61)
- }
- return 0;
+} + +/* dir for type objects: returns dict and bases.
- We deliberately don't suck up its class, as methods belonging to the
- metaclass would probably be more confusing than helpful. +*/ +static PyObject * +type_dir(PyObject *self, PyObject *args) +{
- PyObject *result = NULL;
- PyObject *dict = PyDict_New();
+} + static PyMethodDef type_methods[] = { {"mro", (PyCFunction)mro_external, METH_NOARGS, PyDoc_STR("mro() -> list\nreturn a type's method resolution order")}, @@ -2585,6 +2661,8 @@ static PyMethodDef type_methods[] = { PyDoc_STR("instancecheck() -> check if an object is an instance")}, {"subclasscheck", type___subclasscheck__, METH_O, PyDoc_STR("subclasscheck() -> check if a class is a subclass")},
- {"dir", type_dir, METH_NOARGS,
{0} }; @@ -3438,6 +3516,53 @@ object_sizeof(PyObject *self, PyObject return PyLong_FromSsize_t(res); } +/ dir for generic objects: returns dict, class,PyDoc_STR("__dir__() -> specialized __dir__ implementation for types")},[](#l5.91)
- and recursively up the class.bases chain. +*/ +static PyObject * +object_dir(PyObject *self, PyObject *args) +{
- PyObject *result = NULL;
- PyObject *dict = NULL;
- PyObject *itsclass = NULL;
- /* Get dict (which may or may not be a real dict...) */
- dict = PyObject_GetAttrString(self, "dict");
- if (dict == NULL) {
PyErr_Clear();[](#l5.112)
dict = PyDict_New();[](#l5.113)
- }
- else if (!PyDict_Check(dict)) {
Py_DECREF(dict);[](#l5.116)
dict = PyDict_New();[](#l5.117)
- }
- else {
/* Copy __dict__ to avoid mutating it. */[](#l5.120)
PyObject *temp = PyDict_Copy(dict);[](#l5.121)
Py_DECREF(dict);[](#l5.122)
dict = temp;[](#l5.123)
- }
- /* Merge in attrs reachable from its class. */
- itsclass = PyObject_GetAttrString(self, "class");
- if (itsclass == NULL)
/* XXX(tomer): Perhaps fall back to obj->ob_type if no[](#l5.132)
__class__ exists? */[](#l5.133)
PyErr_Clear();[](#l5.134)
- else if (merge_class_dict(dict, itsclass) != 0)
goto error;[](#l5.136)
+} + static PyMethodDef object_methods[] = { {"reduce_ex", object_reduce_ex, METH_VARARGS, PyDoc_STR("helper for pickle")}, @@ -3449,6 +3574,8 @@ static PyMethodDef object_methods[] = { PyDoc_STR("default object formatter")}, {"sizeof", object_sizeof, METH_NOARGS, PyDoc_STR("sizeof() -> size of object in memory, in bytes")},