Hello community, here is the log from the commit of package python-Cython for openSUSE:Factory checked in at 2020-06-21 18:49:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Cython (Old) and /work/SRC/openSUSE:Factory/.python-Cython.new.3606 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Cython" Sun Jun 21 18:49:14 2020 rev:56 rq:813397 version:0.29.20 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Cython/python-Cython.changes 2020-05-28 09:09:02.247982443 +0200 +++ /work/SRC/openSUSE:Factory/.python-Cython.new.3606/python-Cython.changes 2020-06-21 19:02:41.928278581 +0200 @@ -1,0 +2,19 @@ +Thu Jun 11 06:30:55 UTC 2020 - Paolo Stivanin <i...@paolostivanin.com> + +- Update to 0.29.20 + * Nested try-except statements with multiple return statements + could crash due to incorrect deletion of the except as target variable. + * The @classmethod decorator no longer rejects unknown input from other decorators. + * Fused types could leak into unrelated usages. Patch by David Woods. + * Now uses Py_SET_SIZE() and Py_SET_REFCNT() in Py3.9+ to avoid + low-level write access to these object field + * The built-in abs() function could lead to undefined behaviour when used on + the negative-most value of a signed C integer type + * Usages of sizeof() and typeid() on uninitialised variables no longer produce a warning + * The C++ typeid() function was allowed in C mode + * The error position reported for errors found in f-strings was misleading + * The new c_api_binop_methods directive was added for forward compatibility, + but can only be set to True (the current default value). It can be disabled in Cython 3.0 + + +------------------------------------------------------------------- Old: ---- Cython-0.29.19.tar.gz New: ---- Cython-0.29.20.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Cython.spec ++++++ --- /var/tmp/diff_new_pack.IJGxQP/_old 2020-06-21 19:02:42.348280000 +0200 +++ /var/tmp/diff_new_pack.IJGxQP/_new 2020-06-21 19:02:42.352280013 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define oldpython python Name: python-Cython -Version: 0.29.19 +Version: 0.29.20 Release: 0 Summary: The Cython compiler for writing C extensions for the Python language License: Apache-2.0 ++++++ Cython-0.29.19.tar.gz -> Cython-0.29.20.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/.gitrev new/Cython-0.29.20/.gitrev --- old/Cython-0.29.19/.gitrev 2020-05-20 21:19:28.000000000 +0200 +++ new/Cython-0.29.20/.gitrev 2020-06-10 15:13:39.000000000 +0200 @@ -1 +1 @@ -2c3a8c12b7c51f287a2a1475fb7d06eadde83baf +9bc3fc65e906c7b1f5e4e19c92cb726b0ef361bb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/CHANGES.rst new/Cython-0.29.20/CHANGES.rst --- old/Cython-0.29.19/CHANGES.rst 2020-05-20 21:19:13.000000000 +0200 +++ new/Cython-0.29.20/CHANGES.rst 2020-06-10 15:13:18.000000000 +0200 @@ -2,6 +2,44 @@ Cython Changelog ================ +0.29.20 (2020-06-10) +==================== + +Bugs fixed +---------- + +* Nested try-except statements with multiple ``return`` statements could crash + due to incorrect deletion of the ``except as`` target variable. + (Github issue #3666) + +* The ``@classmethod`` decorator no longer rejects unknown input from other decorators. + Patch by David Woods. (Github issue #3660) + +* Fused types could leak into unrelated usages. + Patch by David Woods. (Github issue #3642) + +* Now uses ``Py_SET_SIZE()`` and ``Py_SET_REFCNT()`` in Py3.9+ to avoid low-level + write access to these object fields. + Patch by Victor Stinner. (Github issue #3639) + +* The built-in ``abs()`` function could lead to undefined behaviour when used on + the negative-most value of a signed C integer type. + Patch by Serge Guelton. (Github issue #1911) + +* Usages of ``sizeof()`` and ``typeid()`` on uninitialised variables no longer + produce a warning. + Patch by Celelibi. (Github issue #3575) + +* The C++ ``typeid()`` function was allowed in C mode. + Patch by Celelibi. (Github issue #3637) + +* The error position reported for errors found in f-strings was misleading. + (Github issue #3674) + +* The new ``c_api_binop_methods`` directive was added for forward compatibility, but can + only be set to True (the current default value). It can be disabled in Cython 3.0. + + 0.29.19 (2020-05-20) ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/Code.py new/Cython-0.29.20/Cython/Compiler/Code.py --- old/Cython-0.29.19/Cython/Compiler/Code.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/Code.py 2020-06-10 15:13:18.000000000 +0200 @@ -543,7 +543,7 @@ impl = re.sub(r'PY(IDENT|UNICODE)\("([^"]+)"\)', externalise, impl) assert 'PYIDENT(' not in impl and 'PYUNICODE(' not in impl - return bool(replacements), impl + return True, impl def inject_unbound_methods(self, impl, output): """Replace 'UNBOUND_METHOD(type, "name")' by a constant Python identifier cname. @@ -551,7 +551,6 @@ if 'CALL_UNBOUND_METHOD(' not in impl: return False, impl - utility_code = set() def externalise(matchobj): type_cname, method_name, obj_cname, args = matchobj.groups() args = [arg.strip() for arg in args[1:].split(',')] if args else [] @@ -567,9 +566,7 @@ r'\)', externalise, impl) assert 'CALL_UNBOUND_METHOD(' not in impl - for helper in sorted(utility_code): - output.use_utility_code(UtilityCode.load_cached(helper, "ObjectHandling.c")) - return bool(utility_code), impl + return True, impl def wrap_c_strings(self, impl): """Replace CSTRING('''xyz''') by a C compatible string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/ExprNodes.py new/Cython-0.29.20/Cython/Compiler/ExprNodes.py --- old/Cython-0.29.19/Cython/Compiler/ExprNodes.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/ExprNodes.py 2020-06-10 15:13:18.000000000 +0200 @@ -5471,7 +5471,7 @@ func_type = self.function_type() if func_type.is_pyobject: self.gil_error() - elif not getattr(func_type, 'nogil', False): + elif not func_type.is_error and not getattr(func_type, 'nogil', False): self.gil_error() gil_message = "Calling gil-requiring function" @@ -5839,6 +5839,17 @@ if function.is_name or function.is_attribute: code.globalstate.use_entry_utility_code(function.entry) + abs_function_cnames = ('abs', 'labs', '__Pyx_abs_longlong') + is_signed_int = self.type.is_int and self.type.signed + if self.overflowcheck and is_signed_int and function.result() in abs_function_cnames: + code.globalstate.use_utility_code(UtilityCode.load_cached("Common", "Overflow.c")) + code.putln('if (unlikely(%s == __PYX_MIN(%s))) {\ + PyErr_SetString(PyExc_OverflowError,\ + "Trying to take the absolute value of the most negative integer is not defined."); %s; }' % ( + self.args[0].result(), + self.args[0].type.empty_declaration_code(), + code.error_goto(self.pos))) + if not function.type.is_pyobject or len(self.arg_tuple.args) > 1 or ( self.arg_tuple.args and self.arg_tuple.is_literal): super(SimpleCallNode, self).generate_evaluation_code(code) @@ -5941,13 +5952,7 @@ self.result() if self.type.is_pyobject else None, func_type.exception_value, self.nogil) else: - if (self.overflowcheck - and self.type.is_int - and self.type.signed - and self.function.result() in ('abs', 'labs', '__Pyx_abs_longlong')): - goto_error = 'if (unlikely(%s < 0)) { PyErr_SetString(PyExc_OverflowError, "value too large"); %s; }' % ( - self.result(), code.error_goto(self.pos)) - elif exc_checks: + if exc_checks: goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos) else: goto_error = "" @@ -10866,7 +10871,10 @@ typeinfo_entry = typeinfo_module.lookup('type_info') return PyrexTypes.CFakeReferenceType(PyrexTypes.c_const_type(typeinfo_entry.type)) + cpp_message = 'typeid operator' + def analyse_types(self, env): + self.cpp_check(env) type_info = self.get_type_info_type(env) if not type_info: self.error("The 'libcpp.typeinfo' module must be cimported to use the typeid() operator") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/FlowControl.py new/Cython-0.29.20/Cython/Compiler/FlowControl.py --- old/Cython-0.29.19/Cython/Compiler/FlowControl.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/FlowControl.py 2020-06-10 15:13:18.000000000 +0200 @@ -884,6 +884,12 @@ self.mark_position(node) return node + def visit_SizeofVarNode(self, node): + return node + + def visit_TypeidNode(self, node): + return node + def visit_IfStatNode(self, node): next_block = self.flow.newblock() parent = self.flow.block @@ -1192,8 +1198,6 @@ if self.flow.loops: self.flow.loops[-1].exceptions.append(descr) self.flow.block = body_block - ## XXX: Is it still required - body_block.add_child(entry_point) self.flow.nextblock() self._visit(node.body) self.flow.exceptions.pop() @@ -1227,11 +1231,18 @@ self.mark_position(node) self.visitchildren(node) - for exception in self.flow.exceptions[::-1]: - if exception.finally_enter: - self.flow.block.add_child(exception.finally_enter) - if exception.finally_exit: - exception.finally_exit.add_child(self.flow.exit_point) + outer_exception_handlers = iter(self.flow.exceptions[::-1]) + for handler in outer_exception_handlers: + if handler.finally_enter: + self.flow.block.add_child(handler.finally_enter) + if handler.finally_exit: + # 'return' goes to function exit, or to the next outer 'finally' clause + exit_point = self.flow.exit_point + for next_handler in outer_exception_handlers: + if next_handler.finally_enter: + exit_point = next_handler.finally_enter + break + handler.finally_exit.add_child(exit_point) break else: if self.flow.block: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/ModuleNode.py new/Cython-0.29.20/Cython/Compiler/ModuleNode.py --- old/Cython-0.29.19/Cython/Compiler/ModuleNode.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/ModuleNode.py 2020-06-10 15:13:18.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 +from .Code import UtilityCode, IncludeCode, TempitaUtilityCode from .StringEncoding import EncodedString from .Pythran import has_np_pythran @@ -1255,6 +1255,9 @@ 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) @@ -1554,9 +1557,11 @@ code.putln("{") code.putln("PyObject *etype, *eval, *etb;") code.putln("PyErr_Fetch(&etype, &eval, &etb);") - code.putln("++Py_REFCNT(o);") + # increase the refcount while we are calling into user code + # to prevent recursive deallocation + code.putln("__Pyx_SET_REFCNT(o, Py_REFCNT(o) + 1);") code.putln("%s(o);" % entry.func_cname) - code.putln("--Py_REFCNT(o);") + code.putln("__Pyx_SET_REFCNT(o, Py_REFCNT(o) - 1);") code.putln("PyErr_Restore(etype, eval, etb);") code.putln("}") @@ -1892,6 +1897,64 @@ 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. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/Nodes.py new/Cython-0.29.20/Cython/Compiler/Nodes.py --- old/Cython-0.29.19/Cython/Compiler/Nodes.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/Nodes.py 2020-06-10 15:13:18.000000000 +0200 @@ -1023,8 +1023,6 @@ if scope is None: # Maybe it's a cimport. scope = env.find_imported_module(self.module_path, self.pos) - if scope: - scope.fused_to_specific = env.fused_to_specific else: scope = env diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/Options.py new/Cython-0.29.20/Cython/Compiler/Options.py --- old/Cython-0.29.19/Cython/Compiler/Options.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/Options.py 2020-06-10 15:13:18.000000000 +0200 @@ -178,6 +178,7 @@ 'auto_pickle': None, 'cdivision': False, # was True before 0.12 'cdivision_warnings': False, + 'c_api_binop_methods': True, # Change for 3.0 'overflowcheck': False, 'overflowcheck.fold': True, 'always_allow_keywords': False, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/Parsing.pxd new/Cython-0.29.20/Cython/Compiler/Parsing.pxd --- old/Cython-0.29.19/Cython/Compiler/Parsing.pxd 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/Parsing.pxd 2020-06-10 15:13:18.000000000 +0200 @@ -69,7 +69,8 @@ @cython.locals(systr=unicode, is_python3_source=bint, is_raw=bint) cdef p_string_literal(PyrexScanner s, kind_override=*) cdef _append_escape_sequence(kind, builder, unicode escape_sequence, PyrexScanner s) -@cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4) +cdef tuple _f_string_error_pos(pos, string, Py_ssize_t i) +@cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4, next_start=Py_ssize_t) cdef list p_f_string(PyrexScanner s, unicode_value, pos, bint is_raw) @cython.locals(i=Py_ssize_t, size=Py_ssize_t, c=Py_UCS4, quote_char=Py_UCS4, NO_CHAR=Py_UCS4) cdef tuple p_f_string_expr(PyrexScanner s, unicode_value, pos, Py_ssize_t starting_index, bint is_raw) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/Parsing.py new/Cython-0.29.20/Cython/Compiler/Parsing.py --- old/Cython-0.29.19/Cython/Compiler/Parsing.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/Parsing.py 2020-06-10 15:13:18.000000000 +0200 @@ -882,6 +882,7 @@ pos = s.position() is_python3_source = s.context.language_level >= 3 has_non_ascii_literal_characters = False + string_start_pos = (pos[0], pos[1], pos[2] + len(s.systring)) kind_string = s.systring.rstrip('"\'').lower() if len(kind_string) > 1: if len(set(kind_string)) != len(kind_string): @@ -965,7 +966,7 @@ s.error("bytes can only contain ASCII literal characters.", pos=pos) bytes_value = None if kind == 'f': - unicode_value = p_f_string(s, unicode_value, pos, is_raw='r' in kind_string) + unicode_value = p_f_string(s, unicode_value, string_start_pos, is_raw='r' in kind_string) s.next() return (kind, bytes_value, unicode_value) @@ -1037,6 +1038,10 @@ for is_raw in (True, False)] +def _f_string_error_pos(pos, string, i): + return (pos[0], pos[1], pos[2] + i + 1) # FIXME: handle newlines in string + + def p_f_string(s, unicode_value, pos, is_raw): # Parses a PEP 498 f-string literal into a list of nodes. Nodes are either UnicodeNodes # or FormattedValueNodes. @@ -1044,15 +1049,13 @@ next_start = 0 size = len(unicode_value) builder = StringEncoding.UnicodeLiteralBuilder() - error_pos = list(pos) # [src, line, column] _parse_seq = _parse_escape_sequences_raw if is_raw else _parse_escape_sequences while next_start < size: end = next_start - error_pos[2] = pos[2] + end # FIXME: handle newlines in string match = _parse_seq(unicode_value, next_start) if match is None: - error(tuple(error_pos), "Invalid escape sequence") + error(_f_string_error_pos(pos, unicode_value, next_start), "Invalid escape sequence") next_start = match.end() part = match.group() @@ -1076,7 +1079,8 @@ if part == '}}': builder.append('}') else: - s.error("f-string: single '}' is not allowed", pos=tuple(error_pos)) + error(_f_string_error_pos(pos, unicode_value, end), + "f-string: single '}' is not allowed") else: builder.append(part) @@ -1097,16 +1101,20 @@ nested_depth = 0 quote_char = NO_CHAR in_triple_quotes = False + backslash_reported = False while True: if i >= size: - s.error("missing '}' in format string expression") + break # error will be reported below c = unicode_value[i] if quote_char != NO_CHAR: if c == '\\': - error_pos = (pos[0], pos[1] + i, pos[2]) # FIXME: handle newlines in string - error(error_pos, "backslashes not allowed in f-strings") + # avoid redundant error reports along '\' sequences + if not backslash_reported: + error(_f_string_error_pos(pos, unicode_value, i), + "backslashes not allowed in f-strings") + backslash_reported = True elif c == quote_char: if in_triple_quotes: if i + 2 < size and unicode_value[i + 1] == c and unicode_value[i + 2] == c: @@ -1125,7 +1133,8 @@ elif nested_depth != 0 and c in '}])': nested_depth -= 1 elif c == '#': - s.error("format string cannot include #") + error(_f_string_error_pos(pos, unicode_value, i), + "format string cannot include #") elif nested_depth == 0 and c in '!:}': # allow != as a special case if c == '!' and i + 1 < size and unicode_value[i + 1] == '=': @@ -1141,12 +1150,13 @@ expr_pos = (pos[0], pos[1], pos[2] + starting_index + 2) # TODO: find exact code position (concat, multi-line, ...) if not expr_str.strip(): - error(expr_pos, "empty expression not allowed in f-string") + error(_f_string_error_pos(pos, unicode_value, starting_index), + "empty expression not allowed in f-string") if terminal_char == '!': i += 1 if i + 2 > size: - error(expr_pos, "invalid conversion char at end of string") + pass # error will be reported below else: conversion_char = unicode_value[i] i += 1 @@ -1159,7 +1169,7 @@ start_format_spec = i + 1 while True: if i >= size: - s.error("missing '}' in format specifier", pos=expr_pos) + break # error will be reported below c = unicode_value[i] if not in_triple_quotes and not in_string: if c == '{': @@ -1181,7 +1191,9 @@ format_spec_str = unicode_value[start_format_spec:i] if terminal_char != '}': - s.error("missing '}' in format string expression', found '%s'" % terminal_char) + error(_f_string_error_pos(pos, unicode_value, i), + "missing '}' in format string expression" + ( + ", found '%s'" % terminal_char if terminal_char else "")) # parse the expression as if it was surrounded by parentheses buf = StringIO('(%s)' % expr_str) @@ -1190,7 +1202,7 @@ # validate the conversion char if conversion_char is not None and not ExprNodes.FormattedValueNode.find_conversion_func(conversion_char): - error(pos, "invalid conversion character '%s'" % conversion_char) + error(expr_pos, "invalid conversion character '%s'" % conversion_char) # the format spec is itself treated like an f-string if format_spec_str: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Compiler/TypeSlots.py new/Cython-0.29.20/Cython/Compiler/TypeSlots.py --- old/Cython-0.29.19/Cython/Compiler/TypeSlots.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Compiler/TypeSlots.py 2020-06-10 15:13:18.000000000 +0200 @@ -180,13 +180,14 @@ # 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): + py3=True, py2=True, ifdef=None, is_binop=False): 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 @@ -405,6 +406,17 @@ 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) @@ -728,23 +740,23 @@ PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" PyNumberMethods = ( - 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__"), + 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(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__"), - 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__"), + 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__"), EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"), @@ -767,8 +779,8 @@ # Added in release 2.2 # The following require the Py_TPFLAGS_HAVE_CLASS flag - MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), - MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"), + BinopSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), + BinopSlot(binaryfunc, "nb_true_divide", "__truediv__"), MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"), MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"), @@ -776,7 +788,7 @@ MethodSlot(unaryfunc, "nb_index", "__index__"), # Added in release 3.5 - MethodSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), + BinopSlot(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.19/Cython/Shadow.py new/Cython-0.29.20/Cython/Shadow.py --- old/Cython-0.29.19/Cython/Shadow.py 2020-05-20 21:19:13.000000000 +0200 +++ new/Cython-0.29.20/Cython/Shadow.py 2020-06-10 15:13:18.000000000 +0200 @@ -1,7 +1,7 @@ # cython.* namespace for pure mode. from __future__ import absolute_import -__version__ = "0.29.19" +__version__ = "0.29.20" try: from __builtin__ import basestring diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Utility/Builtins.c new/Cython-0.29.20/Cython/Utility/Builtins.c --- old/Cython-0.29.19/Cython/Utility/Builtins.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Utility/Builtins.c 2020-06-10 15:13:18.000000000 +0200 @@ -279,7 +279,8 @@ { PyObject *copy = _PyLong_Copy((PyLongObject*)n); if (likely(copy)) { - Py_SIZE(copy) = -(Py_SIZE(copy)); + // negate the size to swap the sign + __Pyx_SET_SIZE(copy, -Py_SIZE(copy)); } return copy; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Utility/CythonFunction.c new/Cython-0.29.20/Cython/Utility/CythonFunction.c --- old/Cython-0.29.19/Cython/Utility/CythonFunction.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Utility/CythonFunction.c 2020-06-10 15:13:18.000000000 +0200 @@ -1292,7 +1292,8 @@ // special C-API function only in Pyston and PyPy >= 5.9 if (PyMethodDescr_Check(method)) #else - // It appears that PyMethodDescr_Type is not exposed anywhere in the CPython C-API + #if PY_MAJOR_VERSION == 2 + // PyMethodDescr_Type is not exposed in the CPython C-API in Py2. static PyTypeObject *methoddescr_type = NULL; if (methoddescr_type == NULL) { PyObject *meth = PyObject_GetAttrString((PyObject*)&PyList_Type, "append"); @@ -1300,6 +1301,9 @@ methoddescr_type = Py_TYPE(meth); Py_DECREF(meth); } + #else + PyTypeObject *methoddescr_type = &PyMethodDescr_Type; + #endif if (__Pyx_TypeCheck(method, methoddescr_type)) #endif { @@ -1317,16 +1321,7 @@ // python classes return PyClassMethod_New(PyMethod_GET_FUNCTION(method)); } - else if (PyCFunction_Check(method)) { + else { return PyClassMethod_New(method); } -#ifdef __Pyx_CyFunction_USED - else if (__Pyx_CyFunction_Check(method)) { - return PyClassMethod_New(method); - } -#endif - PyErr_SetString(PyExc_TypeError, - "Class-level classmethod() can only be called on " - "a method_descriptor or instance method."); - return NULL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Utility/ExtensionTypes.c new/Cython-0.29.20/Cython/Utility/ExtensionTypes.c --- old/Cython-0.29.19/Cython/Utility/ExtensionTypes.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Utility/ExtensionTypes.c 2020-06-10 15:13:18.000000000 +0200 @@ -278,3 +278,56 @@ 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.19/Cython/Utility/ModuleSetupCode.c new/Cython-0.29.20/Cython/Utility/ModuleSetupCode.c --- old/Cython-0.29.19/Cython/Utility/ModuleSetupCode.c 2020-05-20 21:19:13.000000000 +0200 +++ new/Cython-0.29.20/Cython/Utility/ModuleSetupCode.c 2020-06-10 15:13:18.000000000 +0200 @@ -609,6 +609,15 @@ #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) #endif + +#if PY_VERSION_HEX >= 0x030900A4 + #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) +#else + #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) + #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) +#endif + #if CYTHON_ASSUME_SAFE_MACROS #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) #else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/Cython/Utility/Optimize.c new/Cython-0.29.20/Cython/Utility/Optimize.c --- old/Cython-0.29.19/Cython/Utility/Optimize.c 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/Cython/Utility/Optimize.c 2020-06-10 15:13:18.000000000 +0200 @@ -35,7 +35,7 @@ if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { Py_INCREF(x); PyList_SET_ITEM(list, len, x); - Py_SIZE(list) = len+1; + __Pyx_SET_SIZE(list, len + 1); return 0; } return PyList_Append(list, x); @@ -53,7 +53,7 @@ if (likely(L->allocated > len)) { Py_INCREF(x); PyList_SET_ITEM(list, len, x); - Py_SIZE(list) = len+1; + __Pyx_SET_SIZE(list, len + 1); return 0; } return PyList_Append(list, x); @@ -104,7 +104,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) { /* Check that both the size is positive and no reallocation shrinking needs to be done. */ if (likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) { - Py_SIZE(L) -= 1; + __Pyx_SET_SIZE(L, Py_SIZE(L) - 1); return PyList_GET_ITEM(L, PyList_GET_SIZE(L)); } return CALL_UNBOUND_METHOD(PyList_Type, "pop", L); @@ -167,7 +167,7 @@ } if (likely(__Pyx_is_valid_index(cix, size))) { PyObject* v = PyList_GET_ITEM(L, cix); - Py_SIZE(L) -= 1; + __Pyx_SET_SIZE(L, Py_SIZE(L) - 1); size -= 1; memmove(&PyList_GET_ITEM(L, cix), &PyList_GET_ITEM(L, cix+1), (size_t)(size-cix)*sizeof(PyObject*)); return v; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/PKG-INFO new/Cython-0.29.20/PKG-INFO --- old/Cython-0.29.19/PKG-INFO 2020-05-20 21:19:36.000000000 +0200 +++ new/Cython-0.29.20/PKG-INFO 2020-06-10 15:13:46.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: Cython -Version: 0.29.19 +Version: 0.29.20 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.19/runtests.py new/Cython-0.29.20/runtests.py --- old/Cython-0.29.19/runtests.py 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/runtests.py 2020-06-10 15:13:18.000000000 +0200 @@ -617,6 +617,7 @@ self.cleanup_failures = options.cleanup_failures self.with_pyregr = with_pyregr self.cython_only = options.cython_only + self.doctest_selector = re.compile(options.only_pattern).search if options.only_pattern else None self.languages = languages self.test_bugs = test_bugs self.fork = options.fork @@ -730,12 +731,14 @@ else: languages = self.languages - if skip_c(tags) and 'c' in languages: + if 'c' in languages and skip_c(tags): languages = list(languages) languages.remove('c') - elif 'no-cpp' in tags['tag'] and 'cpp' in self.languages: + if 'cpp' in languages and 'no-cpp' in tags['tag']: languages = list(languages) languages.remove('cpp') + if not languages: + return [] pythran_dir = self.pythran_dir if 'pythran' in tags['tag'] and not pythran_dir and 'cpp' in languages: @@ -772,6 +775,7 @@ cleanup_sharedlibs=self.cleanup_sharedlibs, cleanup_failures=self.cleanup_failures, cython_only=self.cython_only, + doctest_selector=self.doctest_selector, fork=self.fork, language_level=self.language_level, warning_errors=warning_errors, @@ -812,7 +816,7 @@ class CythonCompileTestCase(unittest.TestCase): def __init__(self, test_directory, workdir, module, tags, language='c', preparse='id', expect_errors=False, expect_warnings=False, annotate=False, cleanup_workdir=True, - cleanup_sharedlibs=True, cleanup_failures=True, cython_only=False, + cleanup_sharedlibs=True, cleanup_failures=True, cython_only=False, doctest_selector=None, fork=True, language_level=2, warning_errors=False, test_determinism=False, common_utility_dir=None, pythran_dir=None, stats=None): @@ -830,6 +834,7 @@ self.cleanup_sharedlibs = cleanup_sharedlibs self.cleanup_failures = cleanup_failures self.cython_only = cython_only + self.doctest_selector = doctest_selector self.fork = fork self.language_level = language_level self.warning_errors = warning_errors @@ -1276,6 +1281,8 @@ else: module = module_or_name tests = doctest.DocTestSuite(module) + if self.doctest_selector is not None: + tests._tests[:] = [test for test in tests._tests if self.doctest_selector(test.id())] with self.stats.time(self.name, self.language, 'run'): tests.run(result) run_forked_test(result, run_test, self.shortDescription(), self.fork) @@ -2058,6 +2065,8 @@ parser.add_option("-T", "--ticket", dest="tickets", action="append", help="a bug ticket number to run the respective test in 'tests/*'") + parser.add_option("-k", dest="only_pattern", + help="a regex pattern for selecting doctests and test functions in the test modules") parser.add_option("-3", dest="language_level", action="store_const", const=3, default=2, help="set language level to Python 3 (useful for running the CPython regression tests)'") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/errors/e_cpp_only_features.pyx new/Cython-0.29.20/tests/errors/e_cpp_only_features.pyx --- old/Cython-0.29.19/tests/errors/e_cpp_only_features.pyx 1970-01-01 01:00:00.000000000 +0100 +++ new/Cython-0.29.20/tests/errors/e_cpp_only_features.pyx 2020-06-10 15:13:18.000000000 +0200 @@ -0,0 +1,26 @@ +# mode: error +# tag: no-cpp, werror + +from cython.operator import typeid + +def use_typeid(): + cdef int i = 0 + print typeid(i) == typeid(i) + +cdef cppclass A: + pass + +def use_new(): + cdef A* x = new A() + +def use_del(): + cdef A a = A() + cdef A *p = &a + del p + +_ERRORS = """ +8:10: typeid operator only allowed in c++ +8:23: typeid operator only allowed in c++ +14:20: Operation only allowed in c++ +19:4: Operation only allowed in c++ +""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/errors/e_fstring.pyx new/Cython-0.29.20/tests/errors/e_fstring.pyx --- old/Cython-0.29.19/tests/errors/e_fstring.pyx 1970-01-01 01:00:00.000000000 +0100 +++ new/Cython-0.29.20/tests/errors/e_fstring.pyx 2020-06-10 15:13:18.000000000 +0200 @@ -0,0 +1,23 @@ +# mode: error +# tag: fstring + +def incorrect_fstrings(x): + return [ + f"{x}{'\\'}'{x+1}", + f"""{}""", + f"{}", + f"{x!}", + f"{", + f"{{}}}", + ] + + +_ERRORS = """ +6:16: backslashes not allowed in f-strings +7:14: empty expression not allowed in f-string +8:12: empty expression not allowed in f-string +9:14: missing '}' in format string expression, found '!' +10:12: empty expression not allowed in f-string +10:12: missing '}' in format string expression +11:15: f-string: single '}' is not allowed +""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/errors/w_uninitialized.pyx new/Cython-0.29.20/tests/errors/w_uninitialized.pyx --- old/Cython-0.29.19/tests/errors/w_uninitialized.pyx 2018-09-22 16:18:56.000000000 +0200 +++ new/Cython-0.29.20/tests/errors/w_uninitialized.pyx 2020-06-10 15:13:18.000000000 +0200 @@ -112,6 +112,10 @@ args = [] kwargs = {} +def uninitialized_in_sizeof(): + cdef int i + print sizeof(i) + _ERRORS = """ 6:10: local variable 'a' referenced before assignment 12:11: local variable 'a' might be referenced before assignment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/errors/w_uninitialized_cpp.pyx new/Cython-0.29.20/tests/errors/w_uninitialized_cpp.pyx --- old/Cython-0.29.19/tests/errors/w_uninitialized_cpp.pyx 1970-01-01 01:00:00.000000000 +0100 +++ new/Cython-0.29.20/tests/errors/w_uninitialized_cpp.pyx 2020-06-10 15:13:18.000000000 +0200 @@ -0,0 +1,12 @@ +# cython: warn.maybe_uninitialized=True +# mode: error +# tag: cpp, werror + +from cython.operator import typeid + +def uninitialized_in_typeid(): + cdef int i + print typeid(i) == typeid(i) + +_ERRORS = """ +""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/run/builtin_abs.pyx new/Cython-0.29.20/tests/run/builtin_abs.pyx --- old/Cython-0.29.19/tests/run/builtin_abs.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/tests/run/builtin_abs.pyx 2020-06-10 15:13:19.000000000 +0200 @@ -1,5 +1,6 @@ # mode: run # ticket: 698 +# distutils: extra_compile_args=-fwrapv cdef extern from *: int INT_MAX diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/run/classmethod.pyx new/Cython-0.29.20/tests/run/classmethod.pyx --- old/Cython-0.29.19/tests/run/classmethod.pyx 2016-12-10 16:41:15.000000000 +0100 +++ new/Cython-0.29.20/tests/run/classmethod.pyx 2020-06-10 15:13:19.000000000 +0200 @@ -9,6 +9,10 @@ class1 >>> class1().bview() class1 +>>> class1().cview() +class1 +>>> class1().cview("XX") +class1XX >>> class2.view() class2 @@ -35,6 +39,12 @@ def f_plus(cls, a): return cls.a + a +def second_decorator(f): + # note - a class, not a function (didn't pass Cython's test in __Pyx_Method_ClassMethod) + class C: + def __call__(self, *args): + return f(*args) + return C() class class1: a = 5 @@ -48,6 +58,11 @@ def bview(cls): print cls.__name__ + @classmethod + @second_decorator + def cview(cls, s=""): + print cls.__name__+s + class class2(object): a = 6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/run/cython3.pyx new/Cython-0.29.20/tests/run/cython3.pyx --- old/Cython-0.29.19/tests/run/cython3.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/tests/run/cython3.pyx 2020-06-10 15:13:19.000000000 +0200 @@ -258,6 +258,32 @@ yield 6 +def nested_except_gh3666(a=False, b=False): + """ + >>> print(nested_except_gh3666()) + A + >>> print(nested_except_gh3666(a=True)) + B-V + >>> print(nested_except_gh3666(a=True, b=True)) + B-V-T + """ + try: + if a: + raise ValueError + return "A" + except TypeError as exc: + return "A-T" + except ValueError as exc: + try: + if b: + raise TypeError + return "B-V" + except ValueError as exc: + return "B-V-V" + except TypeError as exc: + return "B-V-T" + + ### Py3 feature tests def print_function(*args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/run/fused_types.pyx new/Cython-0.29.20/tests/run/fused_types.pyx --- old/Cython-0.29.19/tests/run/fused_types.pyx 2020-05-19 10:45:14.000000000 +0200 +++ new/Cython-0.29.20/tests/run/fused_types.pyx 2020-06-10 15:13:19.000000000 +0200 @@ -400,3 +400,27 @@ return x else: return 2 * x + + +### see GH3642 - presence of cdef inside "unrelated" caused a type to be incorrectly inferred +cdef unrelated(cython.floating x): + cdef cython.floating t = 1 + return t + +cdef handle_float(float* x): return 'float' + +cdef handle_double(double* x): return 'double' + +def convert_to_ptr(cython.floating x): + """ + >>> convert_to_ptr(1.0) + 'double' + >>> convert_to_ptr['double'](1.0) + 'double' + >>> convert_to_ptr['float'](1.0) + 'float' + """ + if cython.floating is float: + return handle_float(&x) + elif cython.floating is double: + return handle_double(&x) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Cython-0.29.19/tests/run/verbatiminclude.pyx new/Cython-0.29.20/tests/run/verbatiminclude.pyx --- old/Cython-0.29.19/tests/run/verbatiminclude.pyx 2018-09-22 16:18:56.000000000 +0200 +++ new/Cython-0.29.20/tests/run/verbatiminclude.pyx 2020-06-10 15:13:19.000000000 +0200 @@ -25,9 +25,9 @@ cdef extern from "Python.h": """ - #define Py_SET_SIZE(obj, size) Py_SIZE((obj)) = (size) + #define my_SET_SIZE(obj, size) __Pyx_SET_SIZE(obj, size) """ - void Py_SET_SIZE(object, Py_ssize_t) + void my_SET_SIZE(object, Py_ssize_t) def test_square(x): @@ -59,4 +59,4 @@ def test_set_size(x, size): # This function manipulates Python objects in a bad way, so we # do not call it. The real test is that it compiles. - Py_SET_SIZE(x, size) + my_SET_SIZE(x, size)