Hello community, here is the log from the commit of package python-Cython for openSUSE:Factory checked in at 2020-07-15 12:03:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Cython (Old) and /work/SRC/openSUSE:Factory/.python-Cython.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Cython" Wed Jul 15 12:03:48 2020 rev:57 rq:819616 version:0.29.21 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Cython/python-Cython.changes 2020-06-21 19:02:41.928278581 +0200 +++ /work/SRC/openSUSE:Factory/.python-Cython.new.3060/python-Cython.changes 2020-07-15 12:04:43.468136133 +0200 @@ -1,0 +2,22 @@ +Wed Jul 8 22:36:13 UTC 2020 - Ondřej Súkup <mimi...@gmail.com> + +- Update TO 0.29.21 + * Fix a regression in 0.29.20 where __div__ failed to be found in extension types + * Fix a regression in 0.29.20 where a call inside of a finally clause could + fail to compile + * Zero-sized buffers could fail to validate as C/Fortran-contiguous. + * exec() did not allow recent Python syntax features in Py3.8+ + due to https://bugs.python.org/issue35975 + * Binding staticmethods of Cython functions were not behaving like + Python methods in Py3 + * Pythran calls to NumPy methods no longer generate useless method lookup code. + * The PyUnicode_GET_LENGTH() macro was missing from the cpython.* declarations + * The deprecated PyUnicode_*() C-API functions are no longer used, except + for Unicode strings that contain lone surrogates. Unicode strings that + contain non-BMP characters or surrogate pairs now generate different C + code on 16-bit Python 2.x Unicode deployments (such as MS-Windows). + Generating the C code on Python 3.x is recommended in this case + * Some template parameters were missing from the C++ std::unordered_map declaration + * Several internal code generation issues regarding temporary variables were resolved + +------------------------------------------------------------------- Old: ---- Cython-0.29.20.tar.gz New: ---- Cython-0.29.21.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Cython.spec ++++++ --- /var/tmp/diff_new_pack.fExevC/_old 2020-07-15 12:04:45.648138540 +0200 +++ /var/tmp/diff_new_pack.fExevC/_new 2020-07-15 12:04:45.652138545 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define oldpython python Name: python-Cython -Version: 0.29.20 +Version: 0.29.21 Release: 0 Summary: The Cython compiler for writing C extensions for the Python language License: Apache-2.0 ++++++ Cython-0.29.20.tar.gz -> Cython-0.29.21.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/.gitrev new/Cython-0.29.21/.gitrev --- old/Cython-0.29.20/.gitrev 2020-06-10 15:13:39.000000000 +0200 +++ new/Cython-0.29.21/.gitrev 2020-07-08 23:45:30.000000000 +0200 @@ -1 +1 @@ -9bc3fc65e906c7b1f5e4e19c92cb726b0ef361bb +976f5483c6df8570f34076ef25af7e7512dd9347 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/CHANGES.rst new/Cython-0.29.21/CHANGES.rst --- old/Cython-0.29.20/CHANGES.rst 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/CHANGES.rst 2020-07-08 23:44:39.000000000 +0200 @@ -2,6 +2,46 @@ Cython Changelog ================ +0.29.21 (2020-07-09) +==================== + +Bugs fixed +---------- + +* Fix a regression in 0.29.20 where ``__div__`` failed to be found in extension types. + (Github issue #3688) + +* Fix a regression in 0.29.20 where a call inside of a finally clause could fail to compile. + Patch by David Woods. (Github issue #3712) + +* Zero-sized buffers could fail to validate as C/Fortran-contiguous. + Patch by Clemens Hofreither. (Github issue #2093) + +* ``exec()`` did not allow recent Python syntax features in Py3.8+ due to + https://bugs.python.org/issue35975. + (Github issue #3695) + +* Binding staticmethods of Cython functions were not behaving like Python methods in Py3. + Patch by Jeroen Demeyer and Michał Górny. (Github issue #3106) + +* Pythran calls to NumPy methods no longer generate useless method lookup code. + +* The ``PyUnicode_GET_LENGTH()`` macro was missing from the ``cpython.*`` declarations. + Patch by Thomas Caswell. (Github issue #3692) + +* The deprecated ``PyUnicode_*()`` C-API functions are no longer used, except for Unicode + strings that contain lone surrogates. Unicode strings that contain non-BMP characters + or surrogate pairs now generate different C code on 16-bit Python 2.x Unicode deployments + (such as MS-Windows). Generating the C code on Python 3.x is recommended in this case. + Original patches by Inada Naoki and Victor Stinner. (Github issues #3677, #3721, #3697) + +* Some template parameters were missing from the C++ ``std::unordered_map`` declaration. + Patch by will. (Github issue #3685) + +* Several internal code generation issues regarding temporary variables were resolved. + (Github issue #3708) + + 0.29.20 (2020-06-10) ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/Code.py new/Cython-0.29.21/Cython/Compiler/Code.py --- old/Cython-0.29.20/Cython/Compiler/Code.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/Code.py 2020-07-08 23:44:39.000000000 +0200 @@ -718,9 +718,10 @@ self.can_trace = False self.gil_owned = True - self.temps_allocated = [] # of (name, type, manage_ref, static) - self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status - self.temps_used_type = {} # name -> (type, manage_ref) + self.temps_allocated = [] # of (name, type, manage_ref, static) + self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status + self.temps_used_type = {} # name -> (type, manage_ref) + self.zombie_temps = set() # temps that must not be reused after release self.temp_counter = 0 self.closure_temps = None @@ -735,6 +736,20 @@ self.should_declare_error_indicator = False self.uses_error_indicator = False + # safety checks + + def validate_exit(self): + # validate that all allocated temps have been freed + if self.temps_allocated: + leftovers = self.temps_in_use() + if leftovers: + msg = "TEMPGUARD: Temps left over at end of '%s': %s" % (self.scope.name, ', '.join([ + '%s [%s]' % (name, ctype) + for name, ctype, is_pytemp in sorted(leftovers)]), + ) + #print(msg) + raise RuntimeError(msg) + # labels def new_label(self, name=None): @@ -804,7 +819,7 @@ # temp handling - def allocate_temp(self, type, manage_ref, static=False): + def allocate_temp(self, type, manage_ref, static=False, reusable=True): """ Allocates a temporary (which may create a new one or get a previously allocated and released one of the same type). Type is simply registered @@ -823,6 +838,8 @@ This is only used when allocating backing store for a module-level C array literals. + if reusable=False, the temp will not be reused after release. + A C string referring to the variable is returned. """ if type.is_const and not type.is_reference: @@ -838,7 +855,7 @@ manage_ref = False freelist = self.temps_free.get((type, manage_ref)) - if freelist is not None and freelist[0]: + if reusable and freelist is not None and freelist[0]: result = freelist[0].pop() freelist[1].remove(result) else: @@ -847,9 +864,11 @@ result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter) if result not in self.names_taken: break self.temps_allocated.append((result, type, manage_ref, static)) + if not reusable: + self.zombie_temps.add(result) self.temps_used_type[result] = (type, manage_ref) if DebugFlags.debug_temp_code_comments: - self.owner.putln("/* %s allocated (%s) */" % (result, type)) + self.owner.putln("/* %s allocated (%s)%s */" % (result, type, "" if reusable else " - zombie")) if self.collect_temps_stack: self.collect_temps_stack[-1].add((result, type)) @@ -868,10 +887,12 @@ self.temps_free[(type, manage_ref)] = freelist if name in freelist[1]: raise RuntimeError("Temp %s freed twice!" % name) - freelist[0].append(name) + if name not in self.zombie_temps: + freelist[0].append(name) freelist[1].add(name) if DebugFlags.debug_temp_code_comments: - self.owner.putln("/* %s released */" % name) + self.owner.putln("/* %s released %s*/" % ( + name, " - zombie" if name in self.zombie_temps else "")) def temps_in_use(self): """Return a list of (cname,type,manage_ref) tuples of temp names and their type diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/ExprNodes.py new/Cython-0.29.21/Cython/Compiler/ExprNodes.py --- old/Cython-0.29.20/Cython/Compiler/ExprNodes.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/ExprNodes.py 2020-07-08 23:44:39.000000000 +0200 @@ -1623,17 +1623,23 @@ def generate_evaluation_code(self, code): if self.type.is_pyobject: - if self.contains_surrogates(): - # surrogates are not really portable and cannot be + # FIXME: this should go away entirely! + # Since string_contains_lone_surrogates() returns False for surrogate pairs in Py2/UCS2, + # Py2 can generate different code from Py3 here. Let's hope we get away with claiming that + # the processing of surrogate pairs in code was always ambiguous and lead to different results + # on P16/32bit Unicode platforms. + if StringEncoding.string_contains_lone_surrogates(self.value): + # lone (unpaired) surrogates are not really portable and cannot be # decoded by the UTF-8 codec in Py3.3 self.result_code = code.get_py_const(py_object_type, 'ustring') - data_cname = code.get_pyunicode_ptr_const(self.value) + data_cname = code.get_string_const( + StringEncoding.BytesLiteral(self.value.encode('unicode_escape'))) const_code = code.get_cached_constants_writer(self.result_code) if const_code is None: return # already initialised const_code.mark_pos(self.pos) const_code.putln( - "%s = PyUnicode_FromUnicode(%s, (sizeof(%s) / sizeof(Py_UNICODE))-1); %s" % ( + "%s = PyUnicode_DecodeUnicodeEscape(%s, sizeof(%s) - 1, NULL); %s" % ( self.result_code, data_cname, data_cname, @@ -4334,6 +4340,7 @@ pythran_indexing_code(self.indices), op, rhs.pythran_result())) + code.funcstate.release_temp(obj) return # Used from generate_assignment_code and InPlaceAssignmentNode @@ -4374,11 +4381,11 @@ code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code)) code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result()) - def free_temps(self, code): + def free_subexpr_temps(self, code): for temp in self.index_temps: code.funcstate.release_temp(temp) self.index_temps = () - super(BufferIndexNode, self).free_temps(code) + super(BufferIndexNode, self).free_subexpr_temps(code) class MemoryViewIndexNode(BufferIndexNode): @@ -4655,6 +4662,7 @@ self.dst.generate_evaluation_code(code) self._generate_assignment_code(rhs, code) self.dst.generate_disposal_code(code) + self.dst.free_temps(code) rhs.generate_disposal_code(code) rhs.free_temps(code) @@ -5558,7 +5566,7 @@ env.add_include_file(pythran_get_func_include_file(function)) return NumPyMethodCallNode.from_node( self, - function=function, + function_cname=pythran_functor(function), arg_tuple=self.arg_tuple, type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)), ) @@ -5963,13 +5971,13 @@ code.funcstate.release_temp(self.opt_arg_struct) -class NumPyMethodCallNode(SimpleCallNode): +class NumPyMethodCallNode(ExprNode): # Pythran call to a NumPy function or method. # - # function ExprNode the function/method to call - # arg_tuple TupleNode the arguments as an args tuple + # function_cname string the function/method to call + # arg_tuple TupleNode the arguments as an args tuple - subexprs = ['function', 'arg_tuple'] + subexprs = ['arg_tuple'] is_temp = True may_return_none = True @@ -5977,7 +5985,6 @@ code.mark_pos(self.pos) self.allocate_temp_result(code) - self.function.generate_evaluation_code(code) assert self.arg_tuple.mult_factor is None args = self.arg_tuple.args for arg in args: @@ -5988,7 +5995,7 @@ code.putln("new (&%s) decltype(%s){%s{}(%s)};" % ( self.result(), self.result(), - pythran_functor(self.function), + self.function_cname, ", ".join(a.pythran_result() for a in args))) @@ -7277,6 +7284,8 @@ self.member.upper(), self.obj.result_as(self.obj.type), rhs.result_as(self.ctype()))) + rhs.generate_disposal_code(code) + rhs.free_temps(code) else: select_code = self.result() if self.type.is_pyobject and self.use_managed_ref: @@ -8127,20 +8136,18 @@ return t def allocate_temp_result(self, code): - if self.type.is_array and self.in_module_scope: - self.temp_code = code.funcstate.allocate_temp( - self.type, manage_ref=False, static=True) - else: - SequenceNode.allocate_temp_result(self, code) - - def release_temp_result(self, env): if self.type.is_array: - # To be valid C++, we must allocate the memory on the stack - # manually and be sure not to reuse it for something else. - # Yes, this means that we leak a temp array variable. - pass + if self.in_module_scope: + self.temp_code = code.funcstate.allocate_temp( + self.type, manage_ref=False, static=True, reusable=False) + else: + # To be valid C++, we must allocate the memory on the stack + # manually and be sure not to reuse it for something else. + # Yes, this means that we leak a temp array variable. + self.temp_code = code.funcstate.allocate_temp( + self.type, manage_ref=False, reusable=False) else: - SequenceNode.release_temp_result(self, env) + SequenceNode.allocate_temp_result(self, code) def calculate_constant_result(self): if self.mult_factor: @@ -13076,9 +13083,18 @@ def generate_post_assignment_code(self, code): self.arg.generate_post_assignment_code(code) + def allocate_temp_result(self, code): + pass + + def release_temp_result(self, code): + pass + def free_temps(self, code): self.arg.free_temps(code) + def free_subexpr_temps(self, code): + self.arg.free_subexpr_temps(code) + class NoneCheckNode(CoercionNode): # This node is used to check that a Python object is not None and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/FlowControl.py new/Cython-0.29.21/Cython/Compiler/FlowControl.py --- old/Cython-0.29.20/Cython/Compiler/FlowControl.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/FlowControl.py 2020-07-08 23:44:39.000000000 +0200 @@ -1198,6 +1198,7 @@ if self.flow.loops: self.flow.loops[-1].exceptions.append(descr) self.flow.block = body_block + body_block.add_child(entry_point) self.flow.nextblock() self._visit(node.body) self.flow.exceptions.pop() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/FusedNode.py new/Cython-0.29.21/Cython/Compiler/FusedNode.py --- old/Cython-0.29.20/Cython/Compiler/FusedNode.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/FusedNode.py 2020-07-08 23:44:39.000000000 +0200 @@ -878,17 +878,23 @@ (self.resulting_fused_function.result(), self.__signatures__.result())) code.put_giveref(self.__signatures__.result()) + self.__signatures__.generate_post_assignment_code(code) + self.__signatures__.free_temps(code) self.fused_func_assignment.generate_execution_code(code) # Dispose of results self.resulting_fused_function.generate_disposal_code(code) + self.resulting_fused_function.free_temps(code) self.defaults_tuple.generate_disposal_code(code) + self.defaults_tuple.free_temps(code) self.code_object.generate_disposal_code(code) + self.code_object.free_temps(code) for default in self.defaults: if default is not None: default.generate_disposal_code(code) + default.free_temps(code) def annotate(self, code): for stat in self.stats: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/ModuleNode.py new/Cython-0.29.21/Cython/Compiler/ModuleNode.py --- old/Cython-0.29.20/Cython/Compiler/ModuleNode.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/ModuleNode.py 2020-07-08 23:44:39.000000000 +0200 @@ -29,7 +29,7 @@ from .Errors import error, warning from .PyrexTypes import py_object_type from ..Utils import open_new_file, replace_suffix, decode_filename, build_hex_version -from .Code import UtilityCode, IncludeCode, TempitaUtilityCode +from .Code import UtilityCode, IncludeCode from .StringEncoding import EncodedString from .Pythran import has_np_pythran @@ -1223,6 +1223,10 @@ type = entry.type scope = type.scope if scope: # could be None if there was an error + if not scope.directives['c_api_binop_methods']: + error(self.pos, + "The 'c_api_binop_methods' directive is only supported for forward compatibility" + " and must be True.") self.generate_exttype_vtable(scope, code) self.generate_new_function(scope, code, entry) self.generate_dealloc_function(scope, code) @@ -1255,9 +1259,6 @@ self.generate_dict_getter_function(scope, code) if scope.defines_any_special(TypeSlots.richcmp_special_methods): self.generate_richcmp_function(scope, code) - for slot in TypeSlots.PyNumberMethods: - if slot.is_binop and scope.defines_any_special(slot.user_methods): - self.generate_binop_function(scope, slot, code) self.generate_property_accessors(scope, code) self.generate_method_table(scope, code) self.generate_getset_table(scope, code) @@ -1897,64 +1898,6 @@ code.putln("}") # switch code.putln("}") - def generate_binop_function(self, scope, slot, code): - func_name = scope.mangle_internal(slot.slot_name) - if scope.directives['c_api_binop_methods']: - code.putln('#define %s %s' % (func_name, slot.left_slot.slot_code(scope))) - return - else: - error(self.pos, - "The 'c_api_binop_methods' directive is only supported for forward compatibility" - " and must be True.") - - code.putln() - preprocessor_guard = slot.preprocessor_guard_code() - if preprocessor_guard: - code.putln(preprocessor_guard) - - if slot.left_slot.signature == TypeSlots.binaryfunc: - slot_type = 'binaryfunc' - extra_arg = extra_arg_decl = '' - elif slot.left_slot.signature == TypeSlots.ternaryfunc: - slot_type = 'ternaryfunc' - extra_arg = ', extra_arg' - extra_arg_decl = ', PyObject* extra_arg' - else: - error(entry.pos, "Unexpected type lost signature: %s" % slot) - - def has_slot_method(method_name): - entry = scope.lookup(method_name) - return bool(entry and entry.is_special and entry.func_cname) - def call_slot_method(method_name, reverse): - entry = scope.lookup(method_name) - if entry and entry.is_special and entry.func_cname: - return "%s(%s%s)" % ( - entry.func_cname, - "right, left" if reverse else "left, right", - extra_arg) - else: - return '%s_maybe_call_slot(%s, left, right %s)' % ( - func_name, - 'Py_TYPE(right)->tp_base' if reverse else 'Py_TYPE(left)->tp_base', - extra_arg) - - code.putln( - TempitaUtilityCode.load_as_string( - "BinopSlot", "ExtensionTypes.c", - context={ - "func_name": func_name, - "slot_name": slot.slot_name, - "overloads_left": int(has_slot_method(slot.left_slot.method_name)), - "call_left": call_slot_method(slot.left_slot.method_name, reverse=False), - "call_right": call_slot_method(slot.right_slot.method_name, reverse=True), - "type_cname": scope.parent_type.typeptr_cname, - "slot_type": slot_type, - "extra_arg": extra_arg, - "extra_arg_decl": extra_arg_decl, - })[1]) - if preprocessor_guard: - code.putln("#endif") - def generate_getattro_function(self, scope, code): # First try to get the attribute using __getattribute__, if defined, or # PyObject_GenericGetAttr. @@ -2715,6 +2658,8 @@ code.putln('static void %s(CYTHON_UNUSED PyObject *self) {' % Naming.cleanup_cname) + code.enter_cfunc_scope(env) + if Options.generate_cleanup_code >= 2: code.putln("/*--- Global cleanup code ---*/") rev_entries = list(env.var_entries) @@ -3004,6 +2949,7 @@ module.qualified_name, temp, code.error_goto(self.pos))) + code.put_gotref(temp) for entry in entries: if env is module: cname = entry.cname @@ -3014,7 +2960,8 @@ 'if (__Pyx_ImportVoidPtr(%s, "%s", (void **)&%s, "%s") < 0) %s' % ( temp, entry.name, cname, signature, code.error_goto(self.pos))) - code.putln("Py_DECREF(%s); %s = 0;" % (temp, temp)) + code.put_decref_clear(temp, py_object_type) + code.funcstate.release_temp(temp) def generate_c_function_import_code_for_module(self, module, env, code): # Generate import code for all exported C functions in a cimported module. @@ -3032,6 +2979,7 @@ module.qualified_name, temp, code.error_goto(self.pos))) + code.put_gotref(temp) for entry in entries: code.putln( 'if (__Pyx_ImportFunction(%s, "%s", (void (**)(void))&%s, "%s") < 0) %s' % ( @@ -3040,7 +2988,8 @@ entry.cname, entry.type.signature_string(), code.error_goto(self.pos))) - code.putln("Py_DECREF(%s); %s = 0;" % (temp, temp)) + code.put_decref_clear(temp, py_object_type) + code.funcstate.release_temp(temp) def generate_type_init_code(self, env, code): # Generate type import code for extern extension types diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/Nodes.py new/Cython-0.29.21/Cython/Compiler/Nodes.py --- old/Cython-0.29.20/Cython/Compiler/Nodes.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/Nodes.py 2020-07-08 23:44:39.000000000 +0200 @@ -5866,6 +5866,7 @@ arg.generate_evaluation_code(code) code.putln("delete %s;" % arg.result()) arg.generate_disposal_code(code) + arg.free_temps(code) # else error reported earlier def annotate(self, code): @@ -6410,6 +6411,8 @@ # generate the switch statement, so shouldn't be bothered). code.putln("default: break;") code.putln("}") + self.test.generate_disposal_code(code) + self.test.free_temps(code) def generate_function_definitions(self, env, code): self.test.generate_function_definitions(env, code) @@ -7673,9 +7676,10 @@ if self.func_return_type.is_pyobject: code.putln("%s = 0;" % ret_temp) code.funcstate.release_temp(ret_temp) - ret_temp = None if self.in_generator: self.put_error_uncatcher(code, exc_vars) + for cname in exc_vars: + code.funcstate.release_temp(cname) if not self.finally_clause.is_terminator: code.put_goto(old_label) @@ -8772,6 +8776,11 @@ self.begin_of_parallel_control_block_point = None self.begin_of_parallel_control_block_point_after_decls = None + if self.num_threads is not None: + # FIXME: is it the right place? should not normally produce code. + self.num_threads.generate_disposal_code(code) + self.num_threads.free_temps(code) + # Firstly, always prefer errors over returning, continue or break if self.error_label_used: c.putln("const char *%s = NULL; int %s = 0, %s = 0;" % self.parallel_pos_info) @@ -9151,7 +9160,7 @@ # And finally, release our privates and write back any closure # variables - for temp in start_stop_step + (self.chunksize, self.num_threads): + for temp in start_stop_step + (self.chunksize,): if temp is not None: temp.generate_disposal_code(code) temp.free_temps(code) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/Options.py new/Cython-0.29.21/Cython/Compiler/Options.py --- old/Cython-0.29.20/Cython/Compiler/Options.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/Options.py 2020-07-08 23:44:39.000000000 +0200 @@ -178,7 +178,7 @@ 'auto_pickle': None, 'cdivision': False, # was True before 0.12 'cdivision_warnings': False, - 'c_api_binop_methods': True, # Change for 3.0 + 'c_api_binop_methods': True, 'overflowcheck': False, 'overflowcheck.fold': True, 'always_allow_keywords': False, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/StringEncoding.py new/Cython-0.29.21/Cython/Compiler/StringEncoding.py --- old/Cython-0.29.20/Cython/Compiler/StringEncoding.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/StringEncoding.py 2020-07-08 23:44:39.000000000 +0200 @@ -154,6 +154,34 @@ return False +def string_contains_lone_surrogates(ustring): + """ + Check if the unicode string contains lone surrogate code points + on a CPython platform with wide (UCS-4) or narrow (UTF-16) + Unicode, i.e. characters that would be spelled as two + separate code units on a narrow platform, but that do not form a pair. + """ + last_was_start = False + unicode_uses_surrogate_encoding = sys.maxunicode == 65535 + for c in map(ord, ustring): + # surrogates tend to be rare + if c < 0xD800 or c > 0xDFFF: + if last_was_start: + return True + elif not unicode_uses_surrogate_encoding: + # on 32bit Unicode platforms, there is never a pair + return True + elif c <= 0xDBFF: + if last_was_start: + return True # lone start + last_was_start = True + else: + if not last_was_start: + return True # lone end + last_was_start = False + return last_was_start + + class BytesLiteral(_bytes): # bytes subclass that is compatible with EncodedString encoding = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/Tests/TestStringEncoding.py new/Cython-0.29.21/Cython/Compiler/Tests/TestStringEncoding.py --- old/Cython-0.29.20/Cython/Compiler/Tests/TestStringEncoding.py 1970-01-01 01:00:00.000000000 +0100 +++ new/Cython-0.29.21/Cython/Compiler/Tests/TestStringEncoding.py 2020-07-08 23:44:39.000000000 +0200 @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +import sys +import unittest + +import Cython.Compiler.StringEncoding as StringEncoding + + +class StringEncodingTest(unittest.TestCase): + """ + Test the StringEncoding module. + """ + def test_string_contains_lone_surrogates(self): + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"abc")) + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"\uABCD")) + self.assertFalse(StringEncoding.string_contains_lone_surrogates(u"\N{SNOWMAN}")) + + # This behaves differently in Py2 when freshly parsed and read from a .pyc file, + # but it seems to be a marshalling bug in Py2, which doesn't hurt us in Cython. + if sys.version_info[0] != 2: + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800\uDFFF")) + + # In Py2 with 16bit Unicode, the following is indistinguishable from the 32bit character. + obfuscated_surrogate_pair = (u"\uDFFF" + "\uD800")[::-1] + if sys.version_info[0] == 2 and sys.maxunicode == 65565: + self.assertFalse(StringEncoding.string_contains_lone_surrogates(obfuscated_surrogate_pair)) + else: + self.assertTrue(StringEncoding.string_contains_lone_surrogates(obfuscated_surrogate_pair)) + + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uDFFF")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uDFFF\uD800")) + self.assertTrue(StringEncoding.string_contains_lone_surrogates(u"\uD800x\uDFFF")) + + def test_string_contains_surrogates(self): + self.assertFalse(StringEncoding.string_contains_surrogates(u"abc")) + self.assertFalse(StringEncoding.string_contains_surrogates(u"\uABCD")) + self.assertFalse(StringEncoding.string_contains_surrogates(u"\N{SNOWMAN}")) + + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uDFFF")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800\uDFFF")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uDFFF\uD800")) + self.assertTrue(StringEncoding.string_contains_surrogates(u"\uD800x\uDFFF")) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Compiler/TypeSlots.py new/Cython-0.29.21/Cython/Compiler/TypeSlots.py --- old/Cython-0.29.20/Cython/Compiler/TypeSlots.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Compiler/TypeSlots.py 2020-07-08 23:44:39.000000000 +0200 @@ -180,14 +180,13 @@ # ifdef Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.) def __init__(self, slot_name, dynamic=False, inherited=False, - py3=True, py2=True, ifdef=None, is_binop=False): + py3=True, py2=True, ifdef=None): self.slot_name = slot_name self.is_initialised_dynamically = dynamic self.is_inherited = inherited self.ifdef = ifdef self.py3 = py3 self.py2 = py2 - self.is_binop = is_binop def preprocessor_guard_code(self): ifdef = self.ifdef @@ -406,17 +405,6 @@ return self.default_value -class BinopSlot(SyntheticSlot): - def __init__(self, signature, slot_name, left_method, **kargs): - assert left_method.startswith('__') - right_method = '__r' + left_method[2:] - SyntheticSlot.__init__( - self, slot_name, [left_method, right_method], "0", is_binop=True, **kargs) - # MethodSlot causes special method registration. - self.left_slot = MethodSlot(signature, "", left_method) - self.right_slot = MethodSlot(signature, "", right_method) - - class RichcmpSlot(MethodSlot): def slot_code(self, scope): entry = scope.lookup_here(self.method_name) @@ -740,23 +728,23 @@ PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" PyNumberMethods = ( - BinopSlot(binaryfunc, "nb_add", "__add__"), - BinopSlot(binaryfunc, "nb_subtract", "__sub__"), - BinopSlot(binaryfunc, "nb_multiply", "__mul__"), - BinopSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), - BinopSlot(binaryfunc, "nb_remainder", "__mod__"), - BinopSlot(binaryfunc, "nb_divmod", "__divmod__"), - BinopSlot(ternaryfunc, "nb_power", "__pow__"), + MethodSlot(binaryfunc, "nb_add", "__add__"), + MethodSlot(binaryfunc, "nb_subtract", "__sub__"), + MethodSlot(binaryfunc, "nb_multiply", "__mul__"), + MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), + MethodSlot(binaryfunc, "nb_remainder", "__mod__"), + MethodSlot(binaryfunc, "nb_divmod", "__divmod__"), + MethodSlot(ternaryfunc, "nb_power", "__pow__"), MethodSlot(unaryfunc, "nb_negative", "__neg__"), MethodSlot(unaryfunc, "nb_positive", "__pos__"), MethodSlot(unaryfunc, "nb_absolute", "__abs__"), MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")), MethodSlot(unaryfunc, "nb_invert", "__invert__"), - BinopSlot(binaryfunc, "nb_lshift", "__lshift__"), - BinopSlot(binaryfunc, "nb_rshift", "__rshift__"), - BinopSlot(binaryfunc, "nb_and", "__and__"), - BinopSlot(binaryfunc, "nb_xor", "__xor__"), - BinopSlot(binaryfunc, "nb_or", "__or__"), + MethodSlot(binaryfunc, "nb_lshift", "__lshift__"), + MethodSlot(binaryfunc, "nb_rshift", "__rshift__"), + MethodSlot(binaryfunc, "nb_and", "__and__"), + MethodSlot(binaryfunc, "nb_xor", "__xor__"), + MethodSlot(binaryfunc, "nb_or", "__or__"), EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"), @@ -779,8 +767,8 @@ # Added in release 2.2 # The following require the Py_TPFLAGS_HAVE_CLASS flag - BinopSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), - BinopSlot(binaryfunc, "nb_true_divide", "__truediv__"), + MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), + MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"), MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"), MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"), @@ -788,7 +776,7 @@ MethodSlot(unaryfunc, "nb_index", "__index__"), # Added in release 3.5 - BinopSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), + MethodSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), MethodSlot(ibinaryfunc, "nb_inplace_matrix_multiply", "__imatmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Includes/cpython/unicode.pxd new/Cython-0.29.21/Cython/Includes/cpython/unicode.pxd --- old/Cython-0.29.20/Cython/Includes/cpython/unicode.pxd 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Includes/cpython/unicode.pxd 2020-07-08 23:44:39.000000000 +0200 @@ -10,8 +10,19 @@ # Return the size of the object. o has to be a PyUnicodeObject # (not checked). + # + # Deprecated since version 3.3, will be removed in version 3.10: + # Part of the old-style Unicode API, please migrate to using + # PyUnicode_GET_LENGTH(). Py_ssize_t PyUnicode_GET_SIZE(object o) + # Return the length of the Unicode string, in code points. o has + # to be a Unicode object in the “canonical” representation (not + # checked). + # + # New in version 3.3. + Py_ssize_t PyUnicode_GET_LENGTH(object o) + # Return the size of the object's internal buffer in bytes. o has # to be a PyUnicodeObject (not checked). Py_ssize_t PyUnicode_GET_DATA_SIZE(object o) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Includes/libcpp/unordered_map.pxd new/Cython-0.29.21/Cython/Includes/libcpp/unordered_map.pxd --- old/Cython-0.29.20/Cython/Includes/libcpp/unordered_map.pxd 2020-04-19 11:26:03.000000000 +0200 +++ new/Cython-0.29.21/Cython/Includes/libcpp/unordered_map.pxd 2020-07-08 23:44:39.000000000 +0200 @@ -1,7 +1,7 @@ from .utility cimport pair cdef extern from "<unordered_map>" namespace "std" nogil: - cdef cppclass unordered_map[T, U]: + cdef cppclass unordered_map[T, U, HASH=*, PRED=*, ALLOCATOR=*]: ctypedef T key_type ctypedef U mapped_type ctypedef pair[const T, U] value_type diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Shadow.py new/Cython-0.29.21/Cython/Shadow.py --- old/Cython-0.29.20/Cython/Shadow.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Shadow.py 2020-07-08 23:44:39.000000000 +0200 @@ -1,7 +1,7 @@ # cython.* namespace for pure mode. from __future__ import absolute_import -__version__ = "0.29.20" +__version__ = "0.29.21" try: from __builtin__ import basestring diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/Builtins.c new/Cython-0.29.21/Cython/Utility/Builtins.c --- old/Cython-0.29.20/Cython/Utility/Builtins.c 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/Builtins.c 2020-07-08 23:44:39.000000000 +0200 @@ -128,6 +128,9 @@ } else { PyCompilerFlags cf; cf.cf_flags = 0; +#if PY_VERSION_HEX >= 0x030800A3 + cf.cf_feature_version = PY_MINOR_VERSION; +#endif if (PyUnicode_Check(o)) { cf.cf_flags = PyCF_SOURCE_IS_UTF8; s = PyUnicode_AsUTF8String(o); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/CythonFunction.c new/Cython-0.29.21/Cython/Utility/CythonFunction.c --- old/Cython-0.29.20/Cython/Utility/CythonFunction.c 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/CythonFunction.c 2020-07-08 23:44:39.000000000 +0200 @@ -548,6 +548,7 @@ static PyObject *__Pyx_CyFunction_descr_get(PyObject *func, PyObject *obj, PyObject *type) { +#if PY_MAJOR_VERSION < 3 __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; if (m->flags & __Pyx_CYFUNCTION_STATICMETHOD) { @@ -563,6 +564,7 @@ if (obj == Py_None) obj = NULL; +#endif return __Pyx_PyMethod_New(func, obj, type); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/ExtensionTypes.c new/Cython-0.29.21/Cython/Utility/ExtensionTypes.c --- old/Cython-0.29.20/Cython/Utility/ExtensionTypes.c 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/ExtensionTypes.c 2020-07-08 23:44:39.000000000 +0200 @@ -278,56 +278,3 @@ Py_XDECREF(setstate_cython); return ret; } - -/////////////// BinopSlot /////////////// - -static CYTHON_INLINE PyObject *{{func_name}}_maybe_call_slot(PyTypeObject* type, PyObject *left, PyObject *right {{extra_arg_decl}}) { - {{slot_type}} slot; -#if CYTHON_USE_TYPE_SLOTS - slot = type->tp_as_number ? type->tp_as_number->{{slot_name}} : NULL; -#else - slot = ({{slot_type}}) PyType_GetSlot(type, Py_{{slot_name}}); -#endif - return slot ? slot(left, right {{extra_arg}}) : __Pyx_NewRef(Py_NotImplemented); -} - -static PyObject *{{func_name}}(PyObject *left, PyObject *right {{extra_arg_decl}}) { - PyObject *res; - int maybe_self_is_left, maybe_self_is_right = 0; - maybe_self_is_left = Py_TYPE(left) == Py_TYPE(right) -#if CYTHON_USE_TYPE_SLOTS - || (Py_TYPE(left)->tp_as_number && Py_TYPE(left)->tp_as_number->{{slot_name}} == &{{func_name}}) -#endif - || __Pyx_TypeCheck(left, {{type_cname}}); - // Optimize for the common case where the left operation is defined (and successful). - if (!{{overloads_left}}) { - maybe_self_is_right = Py_TYPE(left) == Py_TYPE(right) -#if CYTHON_USE_TYPE_SLOTS - || (Py_TYPE(right)->tp_as_number && Py_TYPE(right)->tp_as_number->{{slot_name}} == &{{func_name}}) -#endif - || __Pyx_TypeCheck(right, {{type_cname}}); - } - if (maybe_self_is_left) { - if (maybe_self_is_right && !{{overloads_left}}) { - res = {{call_right}}; - if (res != Py_NotImplemented) return res; - Py_DECREF(res); - // Don't bother calling it again. - maybe_self_is_right = 0; - } - res = {{call_left}}; - if (res != Py_NotImplemented) return res; - Py_DECREF(res); - } - if ({{overloads_left}}) { - maybe_self_is_right = Py_TYPE(left) == Py_TYPE(right) -#if CYTHON_USE_TYPE_SLOTS - || (Py_TYPE(right)->tp_as_number && Py_TYPE(right)->tp_as_number->{{slot_name}} == &{{func_name}}) -#endif - || PyType_IsSubtype(Py_TYPE(right), {{type_cname}}); - } - if (maybe_self_is_right) { - return {{call_right}}; - } - return __Pyx_NewRef(Py_NotImplemented); -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/ImportExport.c new/Cython-0.29.21/Cython/Utility/ImportExport.c --- old/Cython-0.29.20/Cython/Utility/ImportExport.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/ImportExport.c 2020-07-08 23:44:39.000000000 +0200 @@ -152,11 +152,12 @@ } if (skip_leading_underscores && #if PY_MAJOR_VERSION < 3 - PyString_Check(name) && + likely(PyString_Check(name)) && PyString_AS_STRING(name)[0] == '_') #else - PyUnicode_Check(name) && - PyUnicode_AS_UNICODE(name)[0] == '_') + likely(PyUnicode_Check(name)) && + likely(__Pyx_PyUnicode_GET_LENGTH(name)) && + __Pyx_PyUnicode_READ_CHAR(name, 0) == '_') #endif { Py_DECREF(name); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/MemoryView_C.c new/Cython-0.29.21/Cython/Utility/MemoryView_C.c --- old/Cython-0.29.20/Cython/Utility/MemoryView_C.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/MemoryView_C.c 2020-07-08 23:44:39.000000000 +0200 @@ -347,18 +347,22 @@ } /* Check axes */ - for (i = 0; i < ndim; i++) { - spec = axes_specs[i]; - if (unlikely(!__pyx_check_strides(buf, i, ndim, spec))) - goto fail; - if (unlikely(!__pyx_check_suboffsets(buf, i, ndim, spec))) + if (buf->len > 0) { + // 0-sized arrays do not undergo these checks since their strides are + // irrelevant and they are always both C- and F-contiguous. + for (i = 0; i < ndim; i++) { + spec = axes_specs[i]; + if (unlikely(!__pyx_check_strides(buf, i, ndim, spec))) + goto fail; + if (unlikely(!__pyx_check_suboffsets(buf, i, ndim, spec))) + goto fail; + } + + /* Check contiguity */ + if (unlikely(buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))) goto fail; } - /* Check contiguity */ - if (unlikely(buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))) - goto fail; - /* Initialize */ if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice, new_memview != NULL) == -1)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/ModuleSetupCode.c new/Cython-0.29.21/Cython/Utility/ModuleSetupCode.c --- old/Cython-0.29.20/Cython/Utility/ModuleSetupCode.c 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/ModuleSetupCode.c 2020-07-08 23:44:39.000000000 +0200 @@ -532,7 +532,11 @@ #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) + #else + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) + #endif #else #define CYTHON_PEP393_ENABLED 0 #define PyUnicode_1BYTE_KIND 1 @@ -663,7 +667,7 @@ #endif #if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func)) + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) #else #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/Cython/Utility/StringTools.c new/Cython-0.29.21/Cython/Utility/StringTools.c --- old/Cython-0.29.20/Cython/Utility/StringTools.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/Cython/Utility/StringTools.c 2020-07-08 23:44:39.000000000 +0200 @@ -66,6 +66,8 @@ //////////////////// PyUCS4InUnicode //////////////////// +#if PY_VERSION_HEX < 0x03090000 +#if Py_UNICODE_SIZE == 2 static int __Pyx_PyUnicodeBufferContainsUCS4_SP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) { /* handle surrogate pairs for Py_UNICODE buffers in 16bit Unicode builds */ Py_UNICODE high_val, low_val; @@ -77,6 +79,7 @@ } return 0; } +#endif static int __Pyx_PyUnicodeBufferContainsUCS4_BMP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) { Py_UNICODE uchar; @@ -87,6 +90,7 @@ } return 0; } +#endif static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) { #if CYTHON_PEP393_ENABLED @@ -100,19 +104,26 @@ } return 0; } +#elif PY_VERSION_HEX >= 0x03090000 + #error Cannot use "UChar in Unicode" in Python 3.9 without PEP-393 unicode strings. #endif - if (Py_UNICODE_SIZE == 2 && unlikely(character > 65535)) { +#if PY_VERSION_HEX < 0x03090000 +#if Py_UNICODE_SIZE == 2 + if (unlikely(character > 65535)) { return __Pyx_PyUnicodeBufferContainsUCS4_SP( PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), character); - } else { + } else +#endif + { return __Pyx_PyUnicodeBufferContainsUCS4_BMP( PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), character); } +#endif } @@ -443,6 +454,7 @@ /////////////// decode_c_string /////////////// //@requires: IncludeStringH //@requires: decode_c_string_utf16 +//@substitute: naming /* duplicate code to avoid calling strlen() if start >= 0 and stop >= 0 */ static CYTHON_INLINE PyObject* __Pyx_decode_c_string( @@ -467,7 +479,7 @@ stop += length; } if (unlikely(stop <= start)) - return PyUnicode_FromUnicode(NULL, 0); + return __Pyx_NewRef($empty_unicode); length = stop - start; cstring += start; if (decode_func) { @@ -486,6 +498,7 @@ /////////////// decode_c_bytes /////////////// //@requires: decode_c_string_utf16 +//@substitute: naming static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes( const char* cstring, Py_ssize_t length, Py_ssize_t start, Py_ssize_t stop, @@ -503,7 +516,7 @@ if (stop > length) stop = length; if (unlikely(stop <= start)) - return PyUnicode_FromUnicode(NULL, 0); + return __Pyx_NewRef($empty_unicode); length = stop - start; cstring += start; if (decode_func) { @@ -543,6 +556,7 @@ PyObject* text, Py_ssize_t start, Py_ssize_t stop); /////////////// PyUnicode_Substring /////////////// +//@substitute: naming static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( PyObject* text, Py_ssize_t start, Py_ssize_t stop) { @@ -559,7 +573,7 @@ else if (stop > length) stop = length; if (stop <= start) - return PyUnicode_FromUnicode(NULL, 0); + return __Pyx_NewRef($empty_unicode); #if CYTHON_PEP393_ENABLED return PyUnicode_FromKindAndData(PyUnicode_KIND(text), PyUnicode_1BYTE_DATA(text) + start*PyUnicode_KIND(text), stop-start); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/PKG-INFO new/Cython-0.29.21/PKG-INFO --- old/Cython-0.29.20/PKG-INFO 2020-06-10 15:13:46.000000000 +0200 +++ new/Cython-0.29.21/PKG-INFO 2020-07-08 23:45:37.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: Cython -Version: 0.29.20 +Version: 0.29.21 Summary: The Cython compiler for writing C extensions for the Python language. Home-page: http://cython.org/ Author: Robert Bradshaw, Stefan Behnel, Dag Seljebotn, Greg Ewing, et al. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/runtests.py new/Cython-0.29.21/runtests.py --- old/Cython-0.29.20/runtests.py 2020-06-10 15:13:18.000000000 +0200 +++ new/Cython-0.29.21/runtests.py 2020-07-08 23:44:39.000000000 +0200 @@ -1747,6 +1747,8 @@ out.append(_out) err.append(_err) res = p.returncode + if res == 0 and b'REFNANNY: ' in _out: + res = -1 if res != 0: for c, o, e in zip(cmd, out, err): sys.stderr.write("%s\n%s\n%s\n\n" % ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/compile/buildenv.pyx new/Cython-0.29.21/tests/compile/buildenv.pyx --- old/Cython-0.29.20/tests/compile/buildenv.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/tests/compile/buildenv.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -121,4 +121,12 @@ CFLAGS (env) = {get_env('CFLAGS', '')} LINKCC (distutils) = {config_var('LINKCC')} LINKCC (env) = {get_env('LINKCC', '')} + +Encodings: +sys maxunicode = {sys.maxunicode} +LANG (env) = {get_env('LANG', '')} +PYTHONIOENCODING (env) = {get_env('PYTHONIOENCODING', '')} +sys stdout encoding = {sys.stdout.encoding} +sys default encoding = {sys.getdefaultencoding()} +sys FS encoding = {sys.getfilesystemencoding()} """) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/compile/tryfinally.pyx new/Cython-0.29.21/tests/compile/tryfinally.pyx --- old/Cython-0.29.20/tests/compile/tryfinally.pyx 2015-06-22 14:53:11.000000000 +0200 +++ new/Cython-0.29.21/tests/compile/tryfinally.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -18,4 +18,11 @@ finally: i = 42 +def use_name_in_finally(name): + # GH3712 + try: + [] + finally: + name() + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/memoryview/relaxed_strides.pyx new/Cython-0.29.21/tests/memoryview/relaxed_strides.pyx --- old/Cython-0.29.20/tests/memoryview/relaxed_strides.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/tests/memoryview/relaxed_strides.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -37,6 +37,13 @@ np.ones((10, 1), order="C").flags.f_contiguous) +def not_py26(f): + import sys + if sys.version_info < (2, 7): + return lambda a: None + return f + + def test_one_sized(array): """ >>> contig = np.ascontiguousarray(np.arange(10, dtype=np.double)[::100]) @@ -62,3 +69,26 @@ """ cdef double[::1] a = array return a + +def test_zero_sized_multidim_ccontig(array): + """ + >>> contig = np.ascontiguousarray(np.zeros((4,4,4))[::2, 2:2, ::2]) + >>> _ = test_zero_sized_multidim_ccontig(contig) + + >>> a = np.zeros((4,4,4))[::2, 2:2, ::2] + >>> if NUMPY_HAS_RELAXED_STRIDES: _ = test_zero_sized_multidim_ccontig(a) + """ + cdef double[:, :, ::1] a = array + return a + +@not_py26 +def test_zero_sized_multidim_fcontig(array): + """ + >>> contig = np.ascontiguousarray(np.zeros((4,4,4))[::2, 2:2, ::2]) + >>> _ = test_zero_sized_multidim_fcontig(contig) + + >>> a = np.zeros((4,4,4))[::2, 2:2, ::2] + >>> if NUMPY_HAS_RELAXED_STRIDES: _ = test_zero_sized_multidim_fcontig(a) + """ + cdef double[::1, :, :] a = array + return a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/run/cpp_classes.pyx new/Cython-0.29.21/tests/run/cpp_classes.pyx --- old/Cython-0.29.20/tests/run/cpp_classes.pyx 2018-09-22 16:18:56.000000000 +0200 +++ new/Cython-0.29.21/tests/run/cpp_classes.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -212,6 +212,7 @@ cdef int f(int x): return x + def test_nested_del(): """ >>> test_nested_del() @@ -220,3 +221,15 @@ v.push_back(new vector[int]()) del v[0] del create_to_delete()[f(f(0))] + + +def test_nested_del_repeat(): + """ + >>> test_nested_del_repeat() + """ + cdef vector[vector_int_ptr] v + v.push_back(new vector[int]()) + del v[0] + del create_to_delete()[f(f(0))] + del create_to_delete()[f(f(0))] + del create_to_delete()[f(f(0))] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/run/cpp_stl_cpp11.pyx new/Cython-0.29.21/tests/run/cpp_stl_cpp11.pyx --- old/Cython-0.29.20/tests/run/cpp_stl_cpp11.pyx 2020-04-19 11:26:03.000000000 +0200 +++ new/Cython-0.29.21/tests/run/cpp_stl_cpp11.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -140,6 +140,11 @@ return "pass" +cdef extern from "cpp_unordered_map_helper.h": + cdef cppclass IntVectorHash: + pass + + def test_unordered_map_functionality(): """ >>> test_unordered_map_functionality() @@ -153,6 +158,8 @@ unordered_map[int, int] int_map2 unordered_map[int, int*] intptr_map const int* intptr + unordered_map[vector[int], int, IntVectorHash] int_vector_map + vector[int] intvec assert int_map[1] == 2 assert int_map.size() == 1 assert int_map.erase(1) == 1 # returns number of elements erased @@ -183,4 +190,12 @@ intptr_map[0] = NULL intptr = intptr_map.const_at(0) + + intvec = [1, 2] + int_vector_map[intvec] = 3 + intvec = [4, 5] + int_vector_map[intvec] = 6 + assert int_vector_map[intvec] == 6 + intvec = [1, 2] + assert int_vector_map[intvec] == 3 return "pass" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/run/cpp_unordered_map_helper.h new/Cython-0.29.21/tests/run/cpp_unordered_map_helper.h --- old/Cython-0.29.20/tests/run/cpp_unordered_map_helper.h 1970-01-01 01:00:00.000000000 +0100 +++ new/Cython-0.29.21/tests/run/cpp_unordered_map_helper.h 2020-07-08 23:44:39.000000000 +0200 @@ -0,0 +1,13 @@ +#include <functional> +#include <vector> + +struct IntVectorHash { + size_t operator()(const std::vector<int>& v) const { + std::hash<int> hasher; + size_t seed = 0; + for (int i : v) { + seed ^= hasher(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/run/exectest.pyx new/Cython-0.29.21/tests/run/exectest.pyx --- old/Cython-0.29.20/tests/run/exectest.pyx 2015-06-22 14:53:11.000000000 +0200 +++ new/Cython-0.29.21/tests/run/exectest.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -145,3 +145,18 @@ TypeError: exec: arg 1 must be string, bytes or code object, got int """ exec x in {} + + +def exec_with_new_features(s, d): + """ + >>> import sys + >>> pyversion = sys.version_info[:2] + + >>> d = {} + >>> exec_with_new_features('print(123)', d) + 123 + >>> if pyversion == (2, 7): exec_with_new_features('exec "123"', d) + >>> if pyversion >= (3, 6): exec_with_new_features('f = f"abc"', d) + >>> if pyversion >= (3, 8): exec_with_new_features('a = (b := 1)', d) + """ + exec s in d diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.20/tests/run/unicodeliterals.pyx new/Cython-0.29.21/tests/run/unicodeliterals.pyx --- old/Cython-0.29.20/tests/run/unicodeliterals.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.21/tests/run/unicodeliterals.pyx 2020-07-08 23:44:39.000000000 +0200 @@ -21,6 +21,13 @@ u'\udc00' >>> h u'\ud800' + >>> q + u'\udc00\ud800' + + # The output of surrogate pairs differs between 16/32bit Unicode runtimes. + #>>> p + #u'\ud800\udc00' + >>> add u'S\xf8k ik\xfc\xd6\xe4abc' >>> null @@ -44,6 +51,10 @@ 1 >>> len(h) 1 + >>> len(q) + 2 + >>> len(q) + 2 >>> len(add) 12 >>> len(null) @@ -75,11 +86,15 @@ True >>> h == u'\\ud800' # unescaped by Python (required by doctest) True - >>> k == u'\\N{SNOWMAN}' == u'\\u2603' + >>> p == (u'\\ud800\\udc00' if sys.maxunicode == 1114111 else u'\\U00010000') or p # unescaped by Python (required by doctest) + True + >>> q == u'\\udc00\\ud800' or q # unescaped by Python (required by doctest) + True + >>> k == u'\\N{SNOWMAN}' == u'\\u2603' or k True - >>> m == u'abc\\\\xf8\\\\t\\u00f8\\U000000f8' # unescaped by Python (required by doctest) + >>> m == u'abc\\\\xf8\\\\t\\u00f8\\U000000f8' or m # unescaped by Python (required by doctest) True - >>> add == u'Søk ik' + u'üÖä' + 'abc' + >>> add == u'Søk ik' + u'üÖä' + 'abc' or add True >>> null == u'\\x00' # unescaped by Python (required by doctest) True @@ -115,6 +130,8 @@ h = u'\ud800' # lone lead surrogate k = u'\N{SNOWMAN}' m = ur'abc\xf8\t\u00f8\U000000f8' +p = u'\ud800\udc00' # surrogate pair +q = u'\udc00\ud800' # reversed surrogate pair add = u'Søk ik' + u'üÖä' + u'abc' null = u'\x00'