sergesanspaille / rpms / Cython

Forked from rpms/Cython 4 years ago
Clone
Blob Blame History Raw
From 9170a5ad4144e3e61889623c615f294fad373003 Mon Sep 17 00:00:00 2001
From: Jeroen Demeyer <jeroen.k.demeyer@gmail.com>
Date: Tue, 27 Aug 2019 19:23:32 +0200
Subject: [PATCH 1/2] Special-case setting __new__ in class

---
 Cython/Compiler/ExprNodes.py    |  6 ++++--
 Cython/Utility/ObjectHandling.c | 24 ++++++++++++++++++++++++
 tests/run/set_new.py            | 21 +++++++++++++++++++++
 3 files changed, 49 insertions(+), 2 deletions(-)
 create mode 100644 tests/run/set_new.py

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 710dbaba2e..24e95f75c6 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -2295,8 +2295,10 @@ def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
                 setter = 'PyDict_SetItem'
                 namespace = Naming.moddict_cname
             elif entry.is_pyclass_attr:
-                code.globalstate.use_utility_code(UtilityCode.load_cached("SetNameInClass", "ObjectHandling.c"))
-                setter = '__Pyx_SetNameInClass'
+                # Special-case setting __new__
+                n = "SetNewInClass" if self.name == "__new__" else "SetNameInClass"
+                code.globalstate.use_utility_code(UtilityCode.load_cached(n, "ObjectHandling.c"))
+                setter = '__Pyx_' + n
             else:
                 assert False, repr(entry)
             code.put_error_if_neg(
diff --git a/Cython/Utility/ObjectHandling.c b/Cython/Utility/ObjectHandling.c
index 56d7c7ae9a..c6856a9c76 100644
--- a/Cython/Utility/ObjectHandling.c
+++ b/Cython/Utility/ObjectHandling.c
@@ -1209,6 +1209,30 @@ static PyObject *__Pyx__GetNameInClass(PyObject *nmspace, PyObject *name) {
 #define __Pyx_SetNameInClass(ns, name, value)  PyObject_SetItem(ns, name, value)
 #endif
 
+/////////////// SetNewInClass.proto ///////////////
+
+static int __Pyx_SetNewInClass(PyObject *ns, PyObject *name, PyObject *value);
+
+/////////////// SetNewInClass ///////////////
+//@requires: SetNameInClass
+
+// Special-case setting __new__: if it's a Cython function, wrap it in a
+// staticmethod. This is similar to what Python does for a Python function
+// called __new__.
+static int __Pyx_SetNewInClass(PyObject *ns, PyObject *name, PyObject *value) {
+#ifdef __Pyx_CyFunction_USED
+    int ret;
+    if (__Pyx_CyFunction_Check(value)) {
+        PyObject *staticnew = PyStaticMethod_New(value);
+        if (unlikely(!staticnew)) return -1;
+        ret = __Pyx_SetNameInClass(ns, name, staticnew);
+        Py_DECREF(staticnew);
+        return ret;
+    }
+#endif
+    return __Pyx_SetNameInClass(ns, name, value);
+}
+
 
 /////////////// GetModuleGlobalName.proto ///////////////
 //@requires: PyDictVersioning
diff --git a/tests/run/set_new.py b/tests/run/set_new.py
new file mode 100644
index 0000000000..d1c2c4acbd
--- /dev/null
+++ b/tests/run/set_new.py
@@ -0,0 +1,21 @@
+"""
+>>> X = make_class_with_new(cynew)
+>>> X.__new__ is cynew
+True
+>>> X().__new__ is cynew
+True
+>>> def pynew(cls): return object.__new__(cls)
+>>> X = make_class_with_new(pynew)
+>>> X.__new__ is pynew
+True
+>>> X().__new__ is pynew
+True
+"""
+
+def make_class_with_new(n):
+    class X(object):
+        __new__ = n
+    return X
+
+def cynew(cls):
+    return object.__new__(cls)

From 1bb26b964060392ecb08c3b6c8ca4626e5c1eec7 Mon Sep 17 00:00:00 2001
From: Jeroen Demeyer <jeroen.k.demeyer@gmail.com>
Date: Wed, 28 Aug 2019 10:56:28 +0200
Subject: [PATCH 2/2] Always bind Cython functions

---
 Cython/Utility/CythonFunction.c | 15 ---------------
 tests/run/cyfunction.pyx        | 12 ++++++++++++
 2 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c
index 01ff1e0dd4..0758548cb3 100644
--- a/Cython/Utility/CythonFunction.c
+++ b/Cython/Utility/CythonFunction.c
@@ -552,21 +552,6 @@ static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit,
 
 static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type)
 {
-    __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func;
-
-    if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) {
-        Py_INCREF(func);
-        return func;
-    }
-
-    if (m->flags & __Pyx_CYFUNCTION_CLASSMETHOD) {
-        if (type == NULL)
-            type = (PyObject *)(Py_TYPE(obj));
-        return __Pyx_PyMethod_New(func, type, (PyObject *)(Py_TYPE(type)));
-    }
-
-    if (obj == Py_None)
-        obj = NULL;
     return __Pyx_PyMethod_New(func, obj, type);
 }
 
diff --git a/tests/run/cyfunction.pyx b/tests/run/cyfunction.pyx
index cbce48bcfc..bbd2cefb83 100644
--- a/tests/run/cyfunction.pyx
+++ b/tests/run/cyfunction.pyx
@@ -376,6 +376,18 @@ class TestUnboundMethod:
     def meth(self): pass
 
 
+class TestStaticmethod(object):
+    """
+    >>> x = TestStaticmethod()
+    >>> x.staticmeth(42)
+    42
+    >>> x.staticmeth.__get__(42)()
+    42
+    """
+    @staticmethod
+    def staticmeth(arg): return arg
+
+
 cdef class TestOptimisedBuiltinMethod:
     """
     >>> obj = TestOptimisedBuiltinMethod()