Skip to content

Commit

Permalink
Add PyMethod_SetSelf API to let extensions can change method's im_self
Browse files Browse the repository at this point in the history
field

Some extensions, like Zope2.ExtensionClass(PyECMethod_New_ function),
will change instance method's im_self field in some situation. They do
it by access the field of PyMethodObject directly. We can't do it, so
provide a new API to do it.
  • Loading branch information
Daetalus committed Nov 18, 2016
1 parent 93df6ef commit 711f193
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
3 changes: 3 additions & 0 deletions from_cpython/Include/classobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject *) PyMethod_Class(PyObject *) PYSTON_NOEXCEPT;

// Pyston change: add help API to allow extensions to set the fields of PyMethodObject
PyAPI_FUNC(int) PyMethod_SetSelf(PyObject *, PyObject*) PYSTON_NOEXCEPT;

/* Look up attribute with name (a string) on instance object pinst, using
* only the instance and base class dicts. If a descriptor is found in
* a class dict, the descriptor is returned without calling it.
Expand Down
13 changes: 13 additions & 0 deletions src/runtime/classobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1927,6 +1927,19 @@ extern "C" PyObject* PyMethod_Self(PyObject* im) noexcept {
return ((BoxedInstanceMethod*)im)->obj;
}

extern "C" int PyMethod_SetSelf(PyObject* im, PyObject* instance) noexcept {
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return -1;
}

Box* old = ((BoxedInstanceMethod*)im)->obj;
Py_INCREF(instance);
((BoxedInstanceMethod*)im)->obj = instance;
Py_XDECREF(old);
return 1;
}

extern "C" PyObject* PyMethod_Class(PyObject* im) noexcept {
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
Expand Down
18 changes: 18 additions & 0 deletions test/test_extension/api_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,27 @@ test_attrwrapper_parse(PyObject *self, PyObject* args) {
Py_RETURN_NONE;
}

static PyObject*
change_self(PyObject* self, PyObject* args) {
PyObject *im, *inst;
if (!PyArg_ParseTuple(args, "OO", &im, &inst))
return NULL;

#if defined(PYSTON_VERSION)
PyMethod_SetSelf(im, inst);
#else
Py_XDECREF(((PyMethodObject*)im)->im_self);
Py_INCREF(inst);
((PyMethodObject*)im)->im_self = inst;
#endif
Py_RETURN_NONE;
}

static PyMethodDef TestMethods[] = {
{"set_size", set_size, METH_O, "Get set size by PySet_Size." },
{"test_attrwrapper_parse", test_attrwrapper_parse, METH_VARARGS, "Test PyArg_ParseTuple for attrwrappers." },
{"change_self", change_self, METH_VARARGS,
"A function which the self point to its base class."},
{NULL, NULL, 0, NULL} /* Sentinel */
};

Expand Down

0 comments on commit 711f193

Please sign in to comment.