Add optional docstrings to member descriptors. For backwards

compatibility, this required all places where an array of "struct
memberlist" structures was declared that is referenced from a type's
tp_members slot to change the type of the structure to PyMemberDef;
"struct memberlist" is now only used by old code that still calls
PyMember_Get/Set.  The code in PyObject_GenericGetAttr/SetAttr now
calls the new APIs PyMember_GetOne/SetOne, which take a PyMemberDef
argument.

As examples, I added actual docstrings to the attributes of a few
types: file, complex, instance method, super, and xxsubtype.spamlist.

Also converted the symtable to new style getattr.
This commit is contained in:
Guido van Rossum 2001-09-20 20:46:19 +00:00
parent e0af35eb69
commit 6f7993765a
17 changed files with 313 additions and 251 deletions

View file

@ -32,226 +32,237 @@ PyObject *
PyMember_Get(char *addr, struct memberlist *mlist, char *name)
{
struct memberlist *l;
if (strcmp(name, "__members__") == 0)
return listmembers(mlist);
for (l = mlist; l->name != NULL; l++) {
if (strcmp(l->name, name) == 0) {
PyObject *v;
if ((l->flags & READ_RESTRICTED) &&
PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"restricted attribute");
return NULL;
}
addr += l->offset;
switch (l->type) {
case T_BYTE:
v = PyInt_FromLong((long)
(((*(char*)addr & 0xff)
^ 0x80) - 0x80));
break;
case T_UBYTE:
v = PyInt_FromLong((long) *(char*)addr & 0xff);
break;
case T_SHORT:
v = PyInt_FromLong((long) *(short*)addr);
break;
case T_USHORT:
v = PyInt_FromLong((long)
*(unsigned short*)addr);
break;
case T_INT:
v = PyInt_FromLong((long) *(int*)addr);
break;
case T_UINT:
v = PyInt_FromLong((long)
*(unsigned int*)addr);
break;
case T_LONG:
v = PyInt_FromLong(*(long*)addr);
break;
case T_ULONG:
v = PyLong_FromDouble((double)
*(unsigned long*)addr);
break;
case T_FLOAT:
v = PyFloat_FromDouble((double)*(float*)addr);
break;
case T_DOUBLE:
v = PyFloat_FromDouble(*(double*)addr);
break;
case T_STRING:
if (*(char**)addr == NULL) {
Py_INCREF(Py_None);
v = Py_None;
}
else
v = PyString_FromString(*(char**)addr);
break;
case T_STRING_INPLACE:
v = PyString_FromString((char*)addr);
break;
#ifdef macintosh
case T_PSTRING:
if (*(char**)addr == NULL) {
Py_INCREF(Py_None);
v = Py_None;
}
else
v = PyString_FromStringAndSize(
(*(char**)addr)+1,
**(unsigned char**)addr);
break;
case T_PSTRING_INPLACE:
v = PyString_FromStringAndSize(
((char*)addr)+1,
*(unsigned char*)addr);
break;
#endif /* macintosh */
case T_CHAR:
v = PyString_FromStringAndSize((char*)addr, 1);
break;
case T_OBJECT:
v = *(PyObject **)addr;
if (v == NULL)
v = Py_None;
Py_INCREF(v);
break;
default:
PyErr_SetString(PyExc_SystemError,
"bad memberlist type");
v = NULL;
}
return v;
PyMemberDef copy;
copy.name = l->name;
copy.type = l->type;
copy.offset = l->offset;
copy.flags = l->flags;
copy.doc = NULL;
return PyMember_GetOne(addr, &copy);
}
}
PyErr_SetString(PyExc_AttributeError, name);
return NULL;
}
PyObject *
PyMember_GetOne(char *addr, PyMemberDef *l)
{
PyObject *v;
if ((l->flags & READ_RESTRICTED) &&
PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
return NULL;
}
addr += l->offset;
switch (l->type) {
case T_BYTE:
v = PyInt_FromLong(
(long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80));
break;
case T_UBYTE:
v = PyInt_FromLong((long) *(char*)addr & 0xff);
break;
case T_SHORT:
v = PyInt_FromLong((long) *(short*)addr);
break;
case T_USHORT:
v = PyInt_FromLong((long) *(unsigned short*)addr);
break;
case T_INT:
v = PyInt_FromLong((long) *(int*)addr);
break;
case T_UINT:
v = PyInt_FromLong((long) *(unsigned int*)addr);
break;
case T_LONG:
v = PyInt_FromLong(*(long*)addr);
break;
case T_ULONG:
v = PyLong_FromDouble((double) *(unsigned long*)addr);
break;
case T_FLOAT:
v = PyFloat_FromDouble((double)*(float*)addr);
break;
case T_DOUBLE:
v = PyFloat_FromDouble(*(double*)addr);
break;
case T_STRING:
if (*(char**)addr == NULL) {
Py_INCREF(Py_None);
v = Py_None;
}
else
v = PyString_FromString(*(char**)addr);
break;
case T_STRING_INPLACE:
v = PyString_FromString((char*)addr);
break;
#ifdef macintosh
case T_PSTRING:
if (*(char**)addr == NULL) {
Py_INCREF(Py_None);
v = Py_None;
}
else
v = PyString_FromStringAndSize(
(*(char**)addr)+1,
**(unsigned char**)addr);
break;
case T_PSTRING_INPLACE:
v = PyString_FromStringAndSize(
((char*)addr)+1,
*(unsigned char*)addr);
break;
#endif /* macintosh */
case T_CHAR:
v = PyString_FromStringAndSize((char*)addr, 1);
break;
case T_OBJECT:
v = *(PyObject **)addr;
if (v == NULL)
v = Py_None;
Py_INCREF(v);
break;
default:
PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
v = NULL;
}
return v;
}
int
PyMember_Set(char *addr, struct memberlist *mlist, char *name, PyObject *v)
{
struct memberlist *l;
PyObject *oldv;
for (l = mlist; l->name != NULL; l++) {
if (strcmp(l->name, name) == 0) {
if ((l->flags & READONLY) || l->type == T_STRING
#ifdef macintosh
|| l->type == T_PSTRING
#endif
)
{
PyErr_SetString(PyExc_TypeError,
"readonly attribute");
return -1;
}
if ((l->flags & WRITE_RESTRICTED) &&
PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"restricted attribute");
return -1;
}
if (v == NULL && l->type != T_OBJECT) {
PyErr_SetString(PyExc_TypeError,
"can't delete numeric/char attribute");
return -1;
}
addr += l->offset;
switch (l->type) {
case T_BYTE:
case T_UBYTE:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(char*)addr = (char) PyInt_AsLong(v);
break;
case T_SHORT:
case T_USHORT:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(short*)addr = (short) PyInt_AsLong(v);
break;
case T_UINT:
case T_INT:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(int*)addr = (int) PyInt_AsLong(v);
break;
case T_LONG:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(long*)addr = PyInt_AsLong(v);
break;
case T_ULONG:
if (PyInt_Check(v))
*(long*)addr = PyInt_AsLong(v);
else if (PyLong_Check(v))
*(long*)addr = PyLong_AsLong(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_FLOAT:
if (PyInt_Check(v))
*(float*)addr =
(float) PyInt_AsLong(v);
else if (PyFloat_Check(v))
*(float*)addr =
(float) PyFloat_AsDouble(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_DOUBLE:
if (PyInt_Check(v))
*(double*)addr =
(double) PyInt_AsLong(v);
else if (PyFloat_Check(v))
*(double*)addr = PyFloat_AsDouble(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_OBJECT:
Py_XINCREF(v);
oldv = *(PyObject **)addr;
*(PyObject **)addr = v;
Py_XDECREF(oldv);
break;
case T_CHAR:
if (PyString_Check(v) &&
PyString_Size(v) == 1) {
*(char*)addr =
PyString_AsString(v)[0];
}
else {
PyErr_BadArgument();
return -1;
}
break;
default:
PyErr_SetString(PyExc_SystemError,
"bad memberlist type");
return -1;
}
return 0;
PyMemberDef copy;
copy.name = l->name;
copy.type = l->type;
copy.offset = l->offset;
copy.flags = l->flags;
copy.doc = NULL;
return PyMember_SetOne(addr, &copy, v);
}
}
PyErr_SetString(PyExc_AttributeError, name);
return -1;
}
int
PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
{
PyObject *oldv;
if ((l->flags & READONLY) || l->type == T_STRING
#ifdef macintosh
|| l->type == T_PSTRING
#endif
)
{
PyErr_SetString(PyExc_TypeError, "readonly attribute");
return -1;
}
if ((l->flags & WRITE_RESTRICTED) && PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
return -1;
}
if (v == NULL && l->type != T_OBJECT) {
PyErr_SetString(PyExc_TypeError,
"can't delete numeric/char attribute");
return -1;
}
addr += l->offset;
switch (l->type) {
case T_BYTE:
case T_UBYTE:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(char*)addr = (char) PyInt_AsLong(v);
break;
case T_SHORT:
case T_USHORT:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(short*)addr = (short) PyInt_AsLong(v);
break;
case T_UINT:
case T_INT:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(int*)addr = (int) PyInt_AsLong(v);
break;
case T_LONG:
if (!PyInt_Check(v)) {
PyErr_BadArgument();
return -1;
}
*(long*)addr = PyInt_AsLong(v);
break;
case T_ULONG:
if (PyInt_Check(v))
*(long*)addr = PyInt_AsLong(v);
else if (PyLong_Check(v))
*(long*)addr = PyLong_AsLong(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_FLOAT:
if (PyInt_Check(v))
*(float*)addr =
(float) PyInt_AsLong(v);
else if (PyFloat_Check(v))
*(float*)addr =
(float) PyFloat_AsDouble(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_DOUBLE:
if (PyInt_Check(v))
*(double*)addr = (double) PyInt_AsLong(v);
else if (PyFloat_Check(v))
*(double*)addr = PyFloat_AsDouble(v);
else {
PyErr_BadArgument();
return -1;
}
break;
case T_OBJECT:
Py_XINCREF(v);
oldv = *(PyObject **)addr;
*(PyObject **)addr = v;
Py_XDECREF(oldv);
break;
case T_CHAR:
if (PyString_Check(v) && PyString_Size(v) == 1) {
*(char*)addr = PyString_AsString(v)[0];
}
else {
PyErr_BadArgument();
return -1;
}
break;
default:
PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
return -1;
}
return 0;
}