Skip to content

Commit

Permalink
Fixes for function binding for builtins and functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
GrahamDumpleton committed Oct 4, 2024
1 parent 68c45c9 commit 095323e
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 140 deletions.
12 changes: 6 additions & 6 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ Note that version 1.17.0 drops support for Python 3.6 and 3.7. Python version

**Bugs Fixed**

* When a normal function which had `wrapt.decorator` applied, was assigned as a
class attribute, and the function attribute called via the class or an
instance of the class, an additional argument was being passed, inserted as
the first argument, which was the class or instance. This was not the correct
behaviour and the class or instance should not have been passed as the first
argument.
* When a normal function or builtin function which had `wrapt.decorator` or a
function wrapper applied, was assigned as a class attribute, and the function
attribute called via the class or an instance of the class, an additional
argument was being passed, inserted as the first argument, which was the class
or instance. This was not the correct behaviour and the class or instance
should not have been passed as the first argument.

Version 1.16.0
--------------
Expand Down
113 changes: 84 additions & 29 deletions src/wrapt/_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2353,16 +2353,19 @@ static PyObject *WraptFunctionWrapperBase_call(
static PyObject *function_str = NULL;
static PyObject *callable_str = NULL;
static PyObject *classmethod_str = NULL;
static PyObject *instancemethod_str = NULL;

if (!function_str) {
#if PY_MAJOR_VERSION >= 3
function_str = PyUnicode_InternFromString("function");
callable_str = PyUnicode_InternFromString("callable");
classmethod_str = PyUnicode_InternFromString("classmethod");
instancemethod_str = PyUnicode_InternFromString("instancemethod");
#else
function_str = PyString_InternFromString("function");
callable_str = PyString_InternFromString("callable");
classmethod_str = PyString_InternFromString("classmethod");
instancemethod_str = PyString_InternFromString("instancemethod");
#endif
}

Expand Down Expand Up @@ -2394,6 +2397,8 @@ static PyObject *WraptFunctionWrapperBase_call(

if ((self->instance == Py_None) && (self->binding == function_str ||
PyObject_RichCompareBool(self->binding, function_str,
Py_EQ) == 1 || self->binding == instancemethod_str ||
PyObject_RichCompareBool(self->binding, instancemethod_str,
Py_EQ) == 1 || self->binding == callable_str ||
PyObject_RichCompareBool(self->binding, callable_str,
Py_EQ) == 1 || self->binding == classmethod_str ||
Expand Down Expand Up @@ -2439,6 +2444,9 @@ static PyObject *WraptFunctionWrapperBase_descr_get(
static PyObject *bound_type_str = NULL;
static PyObject *function_str = NULL;
static PyObject *callable_str = NULL;
static PyObject *builtin_str = NULL;
static PyObject *class_str = NULL;
static PyObject *instancemethod_str = NULL;

if (!bound_type_str) {
#if PY_MAJOR_VERSION >= 3
Expand All @@ -2454,27 +2462,30 @@ static PyObject *WraptFunctionWrapperBase_descr_get(
#if PY_MAJOR_VERSION >= 3
function_str = PyUnicode_InternFromString("function");
callable_str = PyUnicode_InternFromString("callable");
builtin_str = PyUnicode_InternFromString("builtin");
class_str = PyUnicode_InternFromString("class");
instancemethod_str = PyUnicode_InternFromString("instancemethod");
#else
function_str = PyString_InternFromString("function");
callable_str = PyString_InternFromString("callable");
builtin_str = PyString_InternFromString("builtin");
class_str = PyString_InternFromString("class");
instancemethod_str = PyString_InternFromString("instancemethod");
#endif
}

if (self->parent == Py_None) {
#if PY_MAJOR_VERSION < 3
if (PyObject_IsInstance(self->object_proxy.wrapped,
(PyObject *)&PyClass_Type) || PyObject_IsInstance(
self->object_proxy.wrapped, (PyObject *)&PyType_Type)) {
if (self->binding == builtin_str || PyObject_RichCompareBool(
self->binding, builtin_str, Py_EQ) == 1) {
Py_INCREF(self);
return (PyObject *)self;
}
#else
if (PyObject_IsInstance(self->object_proxy.wrapped,
(PyObject *)&PyType_Type)) {

if (self->binding == class_str || PyObject_RichCompareBool(
self->binding, class_str, Py_EQ) == 1) {
Py_INCREF(self);
return (PyObject *)self;
}
#endif

if (Py_TYPE(self->object_proxy.wrapped)->tp_descr_get == NULL) {
PyErr_Format(PyExc_AttributeError,
Expand Down Expand Up @@ -2513,6 +2524,8 @@ static PyObject *WraptFunctionWrapperBase_descr_get(

if (self->instance == Py_None && (self->binding == function_str ||
PyObject_RichCompareBool(self->binding, function_str,
Py_EQ) == 1 || self->binding == instancemethod_str ||
PyObject_RichCompareBool(self->binding, instancemethod_str,
Py_EQ) == 1 || self->binding == callable_str ||
PyObject_RichCompareBool(self->binding, callable_str,
Py_EQ) == 1)) {
Expand Down Expand Up @@ -3105,6 +3118,9 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self,
static PyObject *classmethod_str = NULL;
static PyObject *staticmethod_str = NULL;
static PyObject *callable_str = NULL;
static PyObject *builtin_str = NULL;
static PyObject *class_str = NULL;
static PyObject *instancemethod_str = NULL;

int result = 0;

Expand Down Expand Up @@ -3147,35 +3163,74 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self,
#endif
}

if (PyObject_IsInstance(wrapped, (PyObject *)&PyFunction_Type)) {
binding = function_str;
if (!builtin_str) {
#if PY_MAJOR_VERSION >= 3
builtin_str = PyUnicode_InternFromString("builtin");
#else
builtin_str = PyString_InternFromString("builtin");
#endif
}
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyClassMethod_Type)) {
binding = classmethod_str;

if (!class_str) {
#if PY_MAJOR_VERSION >= 3
class_str = PyUnicode_InternFromString("class");
#else
class_str = PyString_InternFromString("class");
#endif
}
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyStaticMethod_Type)) {
binding = staticmethod_str;

if (!instancemethod_str) {
#if PY_MAJOR_VERSION >= 3
instancemethod_str = PyUnicode_InternFromString("instancemethod");
#else
instancemethod_str = PyString_InternFromString("instancemethod");
#endif
}
else if ((instance = PyObject_GetAttrString(wrapped, "__self__")) != 0) {
#if PY_MAJOR_VERSION < 3
if (PyObject_IsInstance(instance, (PyObject *)&PyClass_Type) ||
PyObject_IsInstance(instance, (PyObject *)&PyType_Type)) {
binding = classmethod_str;

if (PyObject_IsInstance(wrapped, (PyObject *)&WraptFunctionWrapperBase_Type)) {
binding = PyObject_GetAttrString(wrapped, "_self_binding");
}

if (!binding) {
if (PyCFunction_Check(wrapped)) {
binding = builtin_str;
}
#else
if (PyObject_IsInstance(instance, (PyObject *)&PyType_Type)) {
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyFunction_Type)) {
binding = function_str;
}
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyClassMethod_Type)) {
binding = classmethod_str;
}
#endif
else
binding = callable_str;
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyType_Type)) {
binding = class_str;
}
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyStaticMethod_Type)) {
binding = staticmethod_str;
}
else if ((instance = PyObject_GetAttrString(wrapped, "__self__")) != 0) {
#if PY_MAJOR_VERSION < 3
if (PyObject_IsInstance(instance, (PyObject *)&PyClass_Type) ||
PyObject_IsInstance(instance, (PyObject *)&PyType_Type)) {
binding = classmethod_str;
}
#else
if (PyObject_IsInstance(instance, (PyObject *)&PyType_Type)) {
binding = classmethod_str;
}
#endif
else if (PyObject_IsInstance(wrapped, (PyObject *)&PyMethod_Type)) {
binding = instancemethod_str;
}
else
binding = callable_str;

Py_DECREF(instance);
}
else {
PyErr_Clear();
Py_DECREF(instance);
}
else {
PyErr_Clear();

binding = callable_str;
binding = callable_str;
}
}

result = WraptFunctionWrapperBase_raw_init(self, wrapped, Py_None,
Expand Down
Loading

0 comments on commit 095323e

Please sign in to comment.