@@ -4771,6 +4771,7 @@ PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, voi
47714771 return NULL ;
47724772 }
47734773 }
4774+ ufunc -> dict = PyDict_New ();
47744775 /*
47754776 * TODO: I tried adding a default promoter here (either all object for
47764777 * some special cases, or all homogeneous). Those are reasonable
@@ -6411,6 +6412,15 @@ ufunc_get_doc(PyUFuncObject *ufunc, void *NPY_UNUSED(ignored))
64116412{
64126413 PyObject * doc ;
64136414
6415+ // If there is a __doc__ in the instance __dict__, use it.
6416+ int result = PyDict_GetItemRef (ufunc -> dict , npy_interned_str .__doc__ , & doc );
6417+ if (result == -1 ) {
6418+ return NULL ;
6419+ }
6420+ else if (result == 1 ) {
6421+ return doc ;
6422+ }
6423+
64146424 if (npy_cache_import_runtime (
64156425 "numpy._core._internal" , "_ufunc_doc_signature_formatter" ,
64166426 & npy_runtime_imports ._ufunc_doc_signature_formatter ) == -1 ) {
@@ -6434,6 +6444,24 @@ ufunc_get_doc(PyUFuncObject *ufunc, void *NPY_UNUSED(ignored))
64346444 return doc ;
64356445}
64366446
6447+ static int
6448+ ufunc_set_doc (PyUFuncObject * ufunc , PyObject * doc , void * NPY_UNUSED (ignored ))
6449+ {
6450+ if (doc == NULL ) {
6451+ int result = PyDict_Contains (ufunc -> dict , npy_interned_str .__doc__ );
6452+ if (result == -1 ) {
6453+ return NULL ;
6454+ }
6455+ else if (result == 1 ) {
6456+ return PyDict_DelItem (ufunc -> dict , npy_interned_str .__doc__ );
6457+ }
6458+ else {
6459+ return 0 ;
6460+ }
6461+ } else {
6462+ return PyDict_SetItem (ufunc -> dict , npy_interned_str .__doc__ , doc );
6463+ }
6464+ }
64376465
64386466static PyObject *
64396467ufunc_get_nin (PyUFuncObject * ufunc , void * NPY_UNUSED (ignored ))
@@ -6519,8 +6547,8 @@ ufunc_get_signature(PyUFuncObject *ufunc, void *NPY_UNUSED(ignored))
65196547
65206548static PyGetSetDef ufunc_getset [] = {
65216549 {"__doc__" ,
6522- (getter )ufunc_get_doc ,
6523- NULL , NULL , NULL },
6550+ (getter )ufunc_get_doc , ( setter ) ufunc_set_doc ,
6551+ NULL , NULL },
65246552 {"nin" ,
65256553 (getter )ufunc_get_nin ,
65266554 NULL , NULL , NULL },
@@ -6549,6 +6577,17 @@ static PyGetSetDef ufunc_getset[] = {
65496577};
65506578
65516579
6580+ /******************************************************************************
6581+ *** UFUNC MEMBERS ***
6582+ *****************************************************************************/
6583+
6584+ static PyMemberDef ufunc_members [] = {
6585+ {"__dict__" , T_OBJECT , offsetof(PyUFuncObject , dict ),
6586+ READONLY },
6587+ {NULL },
6588+ };
6589+
6590+
65526591/******************************************************************************
65536592 *** UFUNC TYPE OBJECT ***
65546593 *****************************************************************************/
@@ -6568,6 +6607,12 @@ NPY_NO_EXPORT PyTypeObject PyUFunc_Type = {
65686607 .tp_traverse = (traverseproc )ufunc_traverse ,
65696608 .tp_methods = ufunc_methods ,
65706609 .tp_getset = ufunc_getset ,
6610+ .tp_getattro = PyObject_GenericGetAttr ,
6611+ .tp_setattro = PyObject_GenericSetAttr ,
6612+ // TODO when Python 3.12 is the minimum supported version,
6613+ // use Py_TPFLAGS_MANAGED_DICT
6614+ .tp_members = ufunc_members ,
6615+ .tp_dictoffset = offsetof(PyUFuncObject , dict ),
65716616};
65726617
65736618/* End of code for ufunc objects */
0 commit comments