From 371510f0db57b9728c64a98fee044ff9c9847327 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: May 13 2020 10:09:24 +0000 Subject: Backport classmethod fixes --- diff --git a/3106.patch b/3106.patch new file mode 100644 index 0000000..8a34233 --- /dev/null +++ b/3106.patch @@ -0,0 +1,151 @@ +From 9170a5ad4144e3e61889623c615f294fad373003 Mon Sep 17 00:00:00 2001 +From: Jeroen Demeyer +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 +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() diff --git a/Cython.spec b/Cython.spec index f91169c..e8b97f5 100644 --- a/Cython.spec +++ b/Cython.spec @@ -6,13 +6,18 @@ Name: Cython Version: 0.29.17 %global upver %{version_no_tilde %{nil}} -Release: 1%{?dist} +Release: 2%{?dist} Summary: Language for writing Python extension modules License: ASL 2.0 URL: http://www.cython.org Source: https://github.com/cython/cython/archive/%{upver}/%{srcname}-%{version}.tar.gz +# Always bind Cython functions. +# Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1788506 +# Backported from upstream: https://github.com/cython/cython/pull/3106 +Patch3106: 3106.patch + BuildRequires: gcc %if %{with tests} BuildRequires: gcc-c++ @@ -103,6 +108,10 @@ cp -p cython-mode-init.el cython-mode-init.elc %{buildroot}%{_emacs_sitestartdir %{_emacs_sitestartdir}/cython*.el* %changelog +* Wed May 13 2020 Petr Viktorin - 0.29.17-2 +- Backport classmethod fixes + Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1788506 + * Tue Apr 28 2020 Marcel Plch - 0.29.17-1 - Update to 0.29.17