[pypy-commit] pypy cpyext-ext: copy add_docstring from numpy, add test that passes with -A
mattip
pypy.commits at gmail.com
Sat Jan 9 18:13:03 EST 2016
Author: mattip <matti.picus at gmail.com>
Branch: cpyext-ext
Changeset: r81649:94e1a7e213d9
Date: 2016-01-10 01:10 +0200
http://bitbucket.org/pypy/pypy/changeset/94e1a7e213d9/
Log: copy add_docstring from numpy, add test that passes with -A
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -20,6 +20,7 @@
long long foo_longlong;
unsigned long long foo_ulonglong;
Py_ssize_t foo_ssizet;
+ PyObject * foo_docless;
} fooobject;
static PyTypeObject footype;
@@ -184,6 +185,7 @@
{"longlong_member", T_LONGLONG, offsetof(fooobject, foo_longlong), 0, NULL},
{"ulonglong_member", T_ULONGLONG, offsetof(fooobject, foo_ulonglong), 0, NULL},
{"ssizet_member", T_PYSSIZET, offsetof(fooobject, foo_ssizet), 0, NULL},
+ {"docless_member", T_OBJECT, offsetof(fooobject, foo_docless), READONLY, NULL},
{NULL} /* Sentinel */
};
@@ -623,12 +625,107 @@
(destructor)custom_dealloc, /*tp_dealloc*/
};
+static PyObject * add_docstring(PyObject * self, PyObject * args)
+{
+ PyObject *obj;
+ PyObject *str;
+ char *docstr;
+ static char *msg = "already has a docstring";
+ PyObject *tp_dict = footype.tp_dict;
+ PyObject *myobj;
+ static PyTypeObject *PyMemberDescr_TypePtr = NULL;
+ static PyTypeObject *PyGetSetDescr_TypePtr = NULL;
+ static PyTypeObject *PyMethodDescr_TypePtr = NULL;
+
+ /* Don't add docstrings */
+ if (Py_OptimizeFlag > 1) {
+ Py_RETURN_NONE;
+ }
+
+ if (PyGetSetDescr_TypePtr == NULL) {
+ /* Get "subdescr" */
+ myobj = PyDict_GetItemString(tp_dict, "name");
+ if (myobj != NULL) {
+ PyGetSetDescr_TypePtr = Py_TYPE(myobj);
+ }
+ }
+ if (PyMemberDescr_TypePtr == NULL) {
+ myobj = PyDict_GetItemString(tp_dict, "int_member");
+ if (myobj != NULL) {
+ PyMemberDescr_TypePtr = Py_TYPE(myobj);
+ }
+ }
+ if (PyMethodDescr_TypePtr == NULL) {
+ myobj = PyDict_GetItemString(tp_dict, "classmeth");
+ if (myobj != NULL) {
+ PyMethodDescr_TypePtr = Py_TYPE(myobj);
+ }
+ }
+
+ if (!PyArg_ParseTuple(args, "OO!", &obj, &PyString_Type, &str)) {
+ return NULL;
+ }
+ docstr = PyString_AS_STRING(str);
+#define _TESTDOC1(typebase) (Py_TYPE(obj) == &Py##typebase##_Type)
+#define _TESTDOC2(typebase) (Py_TYPE(obj) == Py##typebase##_TypePtr)
+#define _ADDDOC(typebase, doc, name) do { \
+ Py##typebase##Object *new = (Py##typebase##Object *)obj; \
+ if (!(doc)) { \
+ doc = docstr; \
+ } \
+ else { \
+ PyErr_Format(PyExc_RuntimeError, "%s method %s", name, msg); \
+ return NULL; \
+ } \
+ } while (0)
+
+ if (_TESTDOC1(CFunction)) {
+ _ADDDOC(CFunction, new->m_ml->ml_doc, new->m_ml->ml_name);
+ }
+ else if (_TESTDOC1(Type)) {
+ _ADDDOC(Type, new->tp_doc, new->tp_name);
+ }
+ else if (_TESTDOC2(MemberDescr)) {
+ _ADDDOC(MemberDescr, new->d_member->doc, new->d_member->name);
+ }
+ else if (_TESTDOC2(GetSetDescr)) {
+ _ADDDOC(GetSetDescr, new->d_getset->doc, new->d_getset->name);
+ }
+ else if (_TESTDOC2(MethodDescr)) {
+ _ADDDOC(MethodDescr, new->d_method->ml_doc, new->d_method->ml_name);
+ }
+ else {
+ PyObject *doc_attr;
+
+ doc_attr = PyObject_GetAttrString(obj, "__doc__");
+ if (doc_attr != NULL && doc_attr != Py_None) {
+ PyErr_Format(PyExc_RuntimeError, "object %s", msg);
+ return NULL;
+ }
+ Py_XDECREF(doc_attr);
+
+ if (PyObject_SetAttrString(obj, "__doc__", str) < 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "Cannot set a docstring for that object");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+ }
+
+#undef _TESTDOC1
+#undef _TESTDOC2
+#undef _ADDDOC
+
+ Py_INCREF(str);
+ Py_RETURN_NONE;
+}
/* List of functions exported by this module */
static PyMethodDef foo_functions[] = {
{"new", (PyCFunction)foo_new, METH_NOARGS, NULL},
{"newCustom", (PyCFunction)newCustom, METH_NOARGS, NULL},
+ {"add_docstring", (PyCFunction)add_docstring, METH_VARARGS, NULL},
{NULL, NULL} /* Sentinel */
};
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -55,6 +55,9 @@
raises(SystemError, "obj.broken_member = 42")
assert module.fooType.broken_member.__doc__ is None
assert module.fooType.object_member.__doc__ == "A Python object."
+ module.add_docstring(module.fooType.docless_member, "docstring for docless_member")
+ assert module.fooType.docless_member.__doc__ == "docstring for docless_member"
+ assert str(type(module.fooType.int_member)) == "<type 'member_descriptor'>"
def test_typeobject_object_member(self):
module = self.import_module(name='foo')
More information about the pypy-commit
mailing list