mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
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:
parent
e0af35eb69
commit
6f7993765a
17 changed files with 313 additions and 251 deletions
|
@ -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, ©);
|
||||
}
|
||||
}
|
||||
|
||||
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, ©, 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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue