Cython Changelog
================
+0.28.3 (2018-05-27)
+===================
+
+Bugs fixed
+----------
+
+* Set iteration was broken in non-CPython since 0.28.
+
+* ``UnicodeEncodeError`` in Py2 when ``%s`` formatting is optimised for
+ unicode strings. (Github issue #2276)
+
+* Work around a crash bug in g++ 4.4.x by disabling the size reduction setting
+ of the module init function in this version. (Github issue #2235)
+
+
0.28.2 (2018-04-13)
===================
``libcpp.string``. Patch by Alex Huszagh. (Github issue #2123)
* The C++11 methods ``reserve()`` and ``bucket_count()`` are declared for
- ``std::unordered_map``. Patch by Valentin Valls. (Github issue #2168)
+ ``libcpp.unordered_map``. Patch by Valentin Valls. (Github issue #2168)
Bugs fixed
----------
c_format_spec = None
find_conversion_func = {
- 's': 'PyObject_Str',
+ 's': 'PyObject_Unicode',
'r': 'PyObject_Repr',
'a': 'PyObject_ASCII', # NOTE: mapped to PyObject_Repr() in Py2
}.get
cpp_type = None
if type1.is_cpp_class or type1.is_ptr:
cpp_type = type1.find_cpp_operation_type(self.operator, type2)
- # FIXME: handle the reversed case?
- #if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
- # cpp_type = type2.find_cpp_operation_type(self.operator, type1)
+ if cpp_type is None and (type2.is_cpp_class or type2.is_ptr):
+ cpp_type = type2.find_cpp_operation_type(self.operator, type1)
# FIXME: do we need to handle other cases here?
return cpp_type
code.putln('static PyObject *%s = NULL;' % env.module_cname)
code.putln('static PyObject *%s;' % env.module_dict_cname)
code.putln('static PyObject *%s;' % Naming.builtins_cname)
- code.putln('static PyObject *%s;' % Naming.cython_runtime_cname)
+ code.putln('static PyObject *%s = NULL;' % Naming.cython_runtime_cname)
code.putln('static PyObject *%s;' % Naming.empty_tuple)
code.putln('static PyObject *%s;' % Naming.empty_bytes)
code.putln('static PyObject *%s;' % Naming.empty_unicode)
if res is not None:
return res
function = self.lookup("operator%s" % operator)
- if function is None:
+ function_alternatives = []
+ if function is not None:
+ function_alternatives = function.all_alternatives()
+
+ # look-up nonmember methods listed within a class
+ method_alternatives = []
+ if len(operands)==2: # binary operators only
+ for n in range(2):
+ if operands[n].type.is_cpp_class:
+ obj_type = operands[n].type
+ method = obj_type.scope.lookup("operator%s" % operator)
+ if method is not None:
+ method_alternatives += method.all_alternatives()
+
+ if (not method_alternatives) and (not function_alternatives):
return None
+
+ # select the unique alternatives
+ all_alternatives = list(set(method_alternatives + function_alternatives))
+
return PyrexTypes.best_match([arg.type for arg in operands],
- function.all_alternatives())
+ all_alternatives)
def lookup_operator_for_types(self, pos, operator, types):
from .Nodes import Node
# cython.* namespace for pure mode.
from __future__ import absolute_import
-__version__ = "0.28.2"
+__version__ = "0.28.3"
try:
from __builtin__ import basestring
#if CYTHON_COMPILING_IN_CPYTHON
PyObject **cython_runtime_dict;
#endif
+
+ if (unlikely(!${cython_runtime_cname})) {
+ // Very early error where the runtime module is not set up yet.
+ return c_line;
+ }
+
__Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback);
#if CYTHON_COMPILING_IN_CPYTHON
#define PyString_Type PyUnicode_Type
#define PyString_Check PyUnicode_Check
#define PyString_CheckExact PyUnicode_CheckExact
+ #define PyObject_Unicode PyObject_Str
#endif
#if PY_MAJOR_VERSION >= 3
#ifndef CYTHON_SMALL_CODE
#if defined(__clang__)
#define CYTHON_SMALL_CODE
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) && (!(defined(__cplusplus)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)))
+ // At least g++ 4.4.7 can generate crashing code with this option. (GH #2235)
#define CYTHON_SMALL_CODE __attribute__((optimize("Os")))
#else
#define CYTHON_SMALL_CODE
#if CYTHON_COMPILING_IN_CPYTHON
is_set = is_set || likely(PySet_CheckExact(iterable) || PyFrozenSet_CheckExact(iterable));
*p_source_is_set = is_set;
- if (unlikely(!is_set))
- return PyObject_GetIter(iterable);
- *p_orig_length = PySet_Size(iterable);
- Py_INCREF(iterable);
- return iterable;
+ if (likely(is_set)) {
+ *p_orig_length = PySet_Size(iterable);
+ Py_INCREF(iterable);
+ return iterable;
+ }
#else
(void)is_set;
*p_source_is_set = 0;
+#endif
*p_orig_length = 0;
return PyObject_GetIter(iterable);
-#endif
}
static CYTHON_INLINE int __Pyx_set_iter_next(
}
(void)orig_length;
(void)ppos;
- return 0;
+ return 1;
}
#if CYTHON_COMPILING_IN_CPYTHON
if (unlikely(PySet_GET_SIZE(iter_obj) != orig_length)) {
Py_INCREF(*value);
return 1;
}
- return 0;
}
#endif
+ return 0;
}
/////////////// py_set_discard_unhashable ///////////////
#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
-#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False))
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b);
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
return ival;
}
+
+static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) {
+ return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False);
+}
+
+
static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
return PyInt_FromSize_t(ival);
}
--- /dev/null
+Welcome, and thank you for your interest in contributing!
+=========================================================
+
+If you are looking for a good way to contribute to the Cython project, please
+- have a look at the [Cython Hacker Guide](https://github.com/cython/cython/wiki/HackerGuide)
+- look through the [issues that need help](https://github.com/cython/cython/issues?q=is%3Aissue+is%3Aopen+view+label%3A%22help+wanted%22)
+- look through the [issues that are a good entry point for beginners](https://github.com/cython/cython/issues?q=is%3Aissue+is%3Aopen+view+label%3A%22good+first+issue%22)
+
+If you have code that you want to contribute, please make sure that it
+- includes tests in the `tests/` directory (see the [Hacker Guide on Testing](https://github.com/cython/cython/wiki/HackerGuide#the-test-suite))
+- comes in form of a pull request
Foo operator-(Foo)
int operator*(Foo)
int operator/(int)
+ int operator*(int, Foo) # allows 1*Foo()
+ # nonmember operators can also be specified outside the class
+ double operator/(double, Foo)
+
cdef Foo foo = new Foo()
x = foo * foo2
x = foo / 1
+ x = foo[0] * foo2
+ x = foo[0] / 1
+ x = 1*foo[0]
+
+ cdef double y
+ y = 2.0/foo[0]
+
Note that if one has *pointers* to C++ objects, dereferencing must be done
to avoid doing pointer arithmetic rather than arithmetic on the objects
themselves::
--- /dev/null
+# tag: cpp
+
+from libcpp cimport bool
+
+cdef extern from "cpp_templates_helper.h":
+ cdef cppclass BinaryAnd[T1, T2]:
+ @staticmethod
+ T1 call(T1 x, T2 y)
+
+
+def test_compound_bool_return(bool x, bool y):
+ """
+ >>> test_compound_bool_return(True, False)
+ False
+ """
+ return BinaryAnd[bool, bool].call(x, y)
const_char* operator--(int)
const_char* operator+(int)
+ const_char* operator+(int,const TestOps&)
const_char* operator-(int)
+ const_char* operator-(int,const TestOps&)
const_char* operator*(int)
+ # deliberately omitted operator* to test case where only defined outside class
const_char* operator/(int)
+ const_char* operator/(int,const TestOps&)
const_char* operator%(int)
+ const_char* operator%(int,const TestOps&)
const_char* operator|(int)
+ const_char* operator|(int,const TestOps&)
const_char* operator&(int)
+ const_char* operator&(int,const TestOps&)
const_char* operator^(int)
+ const_char* operator^(int,const TestOps&)
const_char* operator,(int)
+ const_char* operator,(int,const TestOps&)
const_char* operator<<(int)
+ const_char* operator<<(int,const TestOps&)
const_char* operator>>(int)
+ const_char* operator>>(int,const TestOps&)
const_char* operator==(int)
const_char* operator!=(int)
const_char* operator[](int)
const_char* operator()(int)
+
+ # Defining the operator outside the class does work
+ # but doesn't help when importing from pxd files
+ # (they don't get imported)
+ const_char* operator+(float,const TestOps&)
+ # deliberately omitted operator- to test case where only defined in class
+ const_char* operator*(float,const TestOps&)
+ const_char* operator/(float,const TestOps&)
+ const_char* operator%(float,const TestOps&)
+
+ const_char* operator|(float,const TestOps&)
+ const_char* operator&(float,const TestOps&)
+ const_char* operator^(float,const TestOps&)
+ const_char* operator,(float,const TestOps&)
+
+ const_char* operator<<(float,const TestOps&)
+ const_char* operator>>(float,const TestOps&)
cdef cppclass TruthClass:
TruthClass()
out(x, typeof(x))
del t
+def test_nonmember_binop():
+ """
+ >>> test_nonmember_binop()
+ nonmember binary + [const_char *]
+ nonmember binary - [const_char *]
+ nonmember binary / [const_char *]
+ nonmember binary % [const_char *]
+ nonmember binary & [const_char *]
+ nonmember binary | [const_char *]
+ nonmember binary ^ [const_char *]
+ nonmember binary << [const_char *]
+ nonmember binary >> [const_char *]
+ nonmember binary COMMA [const_char *]
+ nonmember binary2 + [const_char *]
+ nonmember binary2 * [const_char *]
+ nonmember binary2 / [const_char *]
+ nonmember binary2 % [const_char *]
+ nonmember binary2 & [const_char *]
+ nonmember binary2 | [const_char *]
+ nonmember binary2 ^ [const_char *]
+ nonmember binary2 << [const_char *]
+ nonmember binary2 >> [const_char *]
+ nonmember binary2 COMMA [const_char *]
+ """
+
+ cdef TestOps* t = new TestOps()
+ out(1 + t[0], typeof(1 + t[0]))
+ out(1 - t[0], typeof(1 - t[0]))
+ # * deliberately omitted
+ out(1 / t[0], typeof(1 / t[0]))
+ out(1 % t[0], typeof(1 % t[0]))
+ out(1 & t[0], typeof(1 & t[0]))
+ out(1 | t[0], typeof(1 | t[0]))
+ out(1 ^ t[0], typeof(1 ^ t[0]))
+ out(1 << t[0], typeof(1 << t[0]))
+ out(1 >> t[0], typeof(1 >> t[0]))
+
+ x = cython.operator.comma(1, t[0])
+ out(x, typeof(x))
+
+ # now test float operators defined outside class
+ out(1. + t[0], typeof(1. + t[0]))
+ # operator - deliberately omitted
+ out(1. * t[0], typeof(1. * t[0]))
+ out(1. / t[0], typeof(1. / t[0]))
+ out(1. % t[0], typeof(1. % t[0]))
+ out(1. & t[0], typeof(1. & t[0]))
+ out(1. | t[0], typeof(1. | t[0]))
+ out(1. ^ t[0], typeof(1. ^ t[0]))
+ out(1. << t[0], typeof(1. << t[0]))
+ out(1. >> t[0], typeof(1. >> t[0]))
+
+ # for some reason we need a cdef here - not sure this is quite right
+ y = cython.operator.comma(1., t[0])
+ out(y, typeof(y))
+ del t
+
def test_cmp():
"""
>>> test_cmp()
#define UN_OP(op) const char* operator op () { return "unary "#op; }
#define POST_UN_OP(op) const char* operator op (int x) { x++; return "post "#op; }
#define BIN_OP(op) const char* operator op (int x) { x++; return "binary "#op; }
+#define NONMEMBER_BIN_OP(op) const char* operator op (int x, const TestOps&) { x++; return "nonmember binary "#op; }
+#define NONMEMBER_BIN_OP2(op) const char* operator op (double x, const TestOps&) { x++; return "nonmember binary2 "#op; }
#define COMMA ,
};
+NONMEMBER_BIN_OP(+)
+NONMEMBER_BIN_OP(-)
+NONMEMBER_BIN_OP(*)
+NONMEMBER_BIN_OP(/)
+NONMEMBER_BIN_OP(%)
+
+NONMEMBER_BIN_OP(<<)
+NONMEMBER_BIN_OP(>>)
+
+NONMEMBER_BIN_OP(|)
+NONMEMBER_BIN_OP(&)
+NONMEMBER_BIN_OP(^)
+NONMEMBER_BIN_OP(COMMA)
+
+NONMEMBER_BIN_OP2(+)
+NONMEMBER_BIN_OP2(-)
+NONMEMBER_BIN_OP2(*)
+NONMEMBER_BIN_OP2(/)
+NONMEMBER_BIN_OP2(%)
+
+NONMEMBER_BIN_OP2(<<)
+NONMEMBER_BIN_OP2(>>)
+
+NONMEMBER_BIN_OP2(|)
+NONMEMBER_BIN_OP2(&)
+NONMEMBER_BIN_OP2(^)
+NONMEMBER_BIN_OP2(COMMA)
+
class TruthClass {
public:
TruthClass() : value(false) {}
public:
static T half(T value) { return value / 2; }
};
+
+template <class T1, class T2>
+class BinaryAnd {
+public:
+ static T1 call(T1 x, T2 y) { return x & y; }
+};
u, u, u, u,
o, o, o, o,
)
+
+
+@cython.test_assert_path_exists(
+ "//FormattedValueNode",
+ "//JoinedStrNode",
+)
+def percent_s_unicode(u, int i):
+ u"""
+ >>> u = u'x\u0194z'
+ >>> print(percent_s_unicode(u, 12))
+ x\u0194z-12
+ """
+ return u"%s-%d" % (u, i)
cython.operator.preincrement(iter)
return lst
+
cdef double dmax = numeric_limits[double].max()
cdef double dmin = numeric_limits[double].min()
cdef double deps = numeric_limits[double].epsilon()
"""
cdef vector[int] x = I
-
+
+def complex_operators():
+ """
+ >>> complex_operators()
+ [-1.0, 0.0, 0.0, 2.0, 0.0, 2.0]
+ """
+ cdef libcpp.complex.complex[double] a = libcpp.complex.complex[double](0.0,1.0)
+ cdef libcpp.complex.complex[double] r1=a*a
+ cdef libcpp.complex.complex[double] r2=a*2.0
+ cdef libcpp.complex.complex[double] r3=2.0*a
+ return [r1.real(), r1.imag(), r2.real(), r2.imag(), r3.real(), r3.imag()]
+
+def pair_comparison():
+ """
+ >>> pair_comparison()
+ [False, True, False, True, False]
+ """
+ cdef pair[double, double] p1 = pair[double, double](1.0,2.0)
+ cdef pair[double, double] p2 = pair[double, double](2.0,2.0)
+ return [p1==p2,p1==p1,p1>p2,p1<p2,p2>p2]