diff options
-rw-r--r-- | CHANGES.rst | 12 | ||||
-rw-r--r-- | Cython/Compiler/Builtin.py | 47 | ||||
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 34 | ||||
-rw-r--r-- | Cython/Compiler/ModuleNode.py | 4 | ||||
-rw-r--r-- | Cython/Compiler/Nodes.py | 9 | ||||
-rw-r--r-- | Cython/Utility/Builtins.c | 45 | ||||
-rw-r--r-- | Cython/Utility/Exceptions.c | 3 | ||||
-rw-r--r-- | Cython/Utility/ModuleSetupCode.c | 4 | ||||
-rw-r--r-- | Cython/Utility/StringTools.c | 64 | ||||
-rw-r--r-- | tests/run/richcmp_str_equals.py | 12 | ||||
-rw-r--r-- | tests/run/set.pyx | 13 | ||||
-rw-r--r-- | tests/run/string_comparison.pyx | 386 | ||||
-rw-r--r-- | tests/run/tryfinally.pyx | 25 |
13 files changed, 582 insertions, 76 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 0d75ff977..3c7370623 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,6 +23,9 @@ Features added * Constant Python float values are cached. +* String equality comparisons can use faster type specific code in + more cases than before. + * String/Unicode formatting using the '%' operator uses a faster C-API call. @@ -73,9 +76,18 @@ Features added Bugs fixed ---------- +* Abstract Python classes that subtyped a Cython extension type + failed to raise an exception on instantiation, and thus ended + up being instantiated. + +* ``set.add(a_tuple)`` and ``set.discard(a_tuple)`` failed with a + TypeError in Py2.4. + * The PEP 3155 ``__qualname__`` was incorrect for nested classes and inner classes/functions declared as ``global``. +* Several corner cases in the try-finally statement were fixed. + * The metaclass of a Python class was not inherited from its parent class(es). It is now extracted from the list of base classes if not provided explicitly using the Py3 ``metaclass`` keyword argument. diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index e086a5a7e..81eaa0f7e 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -18,52 +18,7 @@ pyexec_utility_code = UtilityCode.load("PyExec", "Builtins.c") pyexec_globals_utility_code = UtilityCode.load("PyExecGlobals", "Builtins.c") globals_utility_code = UtilityCode.load("Globals", "Builtins.c") -py_set_utility_code = UtilityCode( -proto = """ -#if PY_VERSION_HEX < 0x02050000 -#ifndef PyAnySet_CheckExact - -#define PyAnySet_CheckExact(ob) \\ - ((ob)->ob_type == &PySet_Type || \\ - (ob)->ob_type == &PyFrozenSet_Type) - -#define PySet_New(iterable) \\ - PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL) - -#define Pyx_PyFrozenSet_New(iterable) \\ - PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL) - -#define PySet_Size(anyset) \\ - PyObject_Size((anyset)) - -#define PySet_Contains(anyset, key) \\ - PySequence_Contains((anyset), (key)) - -#define PySet_Pop(set) \\ - PyObject_CallMethod(set, (char *)"pop", NULL) - -static CYTHON_INLINE int PySet_Clear(PyObject *set) { - PyObject *ret = PyObject_CallMethod(set, (char *)"clear", NULL); - if (!ret) return -1; - Py_DECREF(ret); return 0; -} - -static CYTHON_INLINE int PySet_Discard(PyObject *set, PyObject *key) { - PyObject *ret = PyObject_CallMethod(set, (char *)"discard", (char *)"O", key); - if (!ret) return -1; - Py_DECREF(ret); return 0; -} - -static CYTHON_INLINE int PySet_Add(PyObject *set, PyObject *key) { - PyObject *ret = PyObject_CallMethod(set, (char *)"add", (char *)"O", key); - if (!ret) return -1; - Py_DECREF(ret); return 0; -} - -#endif /* PyAnySet_CheckExact (<= Py2.4) */ -#endif /* < Py2.5 */ -""", -) +py_set_utility_code = UtilityCode.load("pyset_compat", "Builtins.c") builtin_utility_code = { 'set' : py_set_utility_code, diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index e474d48c8..e0155d183 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -9930,11 +9930,11 @@ class CmpNode(object): return (container_type.is_ptr or container_type.is_array) \ and not container_type.is_string - def find_special_bool_compare_function(self, env, operand1): + def find_special_bool_compare_function(self, env, operand1, result_is_bool=False): # note: currently operand1 must get coerced to a Python object if we succeed here! if self.operator in ('==', '!='): type1, type2 = operand1.type, self.operand2.type - if type1.is_builtin_type and type2.is_builtin_type: + if result_is_bool or (type1.is_builtin_type and type2.is_builtin_type): if type1 is Builtin.unicode_type or type2 is Builtin.unicode_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals" @@ -9943,6 +9943,10 @@ class CmpNode(object): self.special_bool_cmp_utility_code = UtilityCode.load_cached("BytesEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyBytes_Equals" return True + elif type1 is Builtin.basestring_type or type2 is Builtin.basestring_type: + self.special_bool_cmp_utility_code = UtilityCode.load_cached("UnicodeEquals", "StringTools.c") + self.special_bool_cmp_function = "__Pyx_PyUnicode_Equals" + return True elif type1 is Builtin.str_type or type2 is Builtin.str_type: self.special_bool_cmp_utility_code = UtilityCode.load_cached("StrEquals", "StringTools.c") self.special_bool_cmp_function = "__Pyx_PyString_Equals" @@ -10180,6 +10184,7 @@ class PrimaryCmpNode(ExprNode, CmpNode): else: self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env) self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env) + self.is_pycmp = False self.type = func_type.return_type def analyse_memoryviewslice_comparison(self, env): @@ -10195,6 +10200,23 @@ class PrimaryCmpNode(ExprNode, CmpNode): return False + def coerce_to_boolean(self, env): + if self.is_pycmp: + # coercing to bool => may allow for more efficient comparison code + if self.find_special_bool_compare_function( + env, self.operand1, result_is_bool=True): + self.is_pycmp = False + self.type = PyrexTypes.c_bint_type + self.is_temp = 1 + if self.cascade: + operand2 = self.cascade.optimise_comparison( + self.operand2, env, result_is_bool=True) + if operand2 is not self.operand2: + self.coerced_operand2 = operand2 + return self + # TODO: check if we can optimise parts of the cascade here + return ExprNode.coerce_to_boolean(self, env) + def has_python_operands(self): return (self.operand1.type.is_pyobject or self.operand2.type.is_pyobject) @@ -10316,12 +10338,14 @@ class CascadedCmpNode(Node, CmpNode): def has_python_operands(self): return self.operand2.type.is_pyobject - def optimise_comparison(self, operand1, env): - if self.find_special_bool_compare_function(env, operand1): + def optimise_comparison(self, operand1, env, result_is_bool=False): + if self.find_special_bool_compare_function(env, operand1, result_is_bool): + self.is_pycmp = False + self.type = PyrexTypes.c_bint_type if not operand1.type.is_pyobject: operand1 = operand1.coerce_to_pyobject(env) if self.cascade: - operand2 = self.cascade.optimise_comparison(self.operand2, env) + operand2 = self.cascade.optimise_comparison(self.operand2, env, result_is_bool) if operand2 is not self.operand2: self.coerced_operand2 = operand2 return operand1 diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index e38d9344e..13d626b03 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -1125,7 +1125,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.globalstate.use_utility_code( UtilityCode.load_cached("IncludeStringH", "StringTools.c")) obj_struct = type.declaration_code("", deref=True) - code.putln("if (likely((%s > 0) & (t->tp_basicsize == sizeof(%s)))) {" % ( + code.putln("if (likely((%s > 0) & (t->tp_basicsize == sizeof(%s)) & ((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0))) {" % ( freecount_name, obj_struct)) code.putln("o = (PyObject*)%s[--%s];" % ( freelist_name, freecount_name)) @@ -1134,7 +1134,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): if scope.needs_gc(): code.putln("PyObject_GC_Track(o);") code.putln("} else {") - code.putln("o = (*t->tp_alloc)(t, 0);") + code.putln("o = (PyObject *) PyBaseObject_Type.tp_new(t, %s, 0);" % Naming.empty_tuple) code.putln("if (unlikely(!o)) return 0;") if freelist_size and not base_type: code.putln('}') diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index ec056cdce..2a17c18d0 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -5275,8 +5275,10 @@ class ReraiseStatNode(StatNode): vars = code.funcstate.exc_vars if vars: code.globalstate.use_utility_code(restore_exception_utility_code) - for varname in vars: - code.put_giveref(varname) + code.put_giveref(vars[0]) + code.put_giveref(vars[1]) + # fresh exceptions may not have a traceback yet (-> finally!) + code.put_xgiveref(vars[2]) code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars)) for varname in vars: code.put("%s = 0; " % varname) @@ -6506,7 +6508,10 @@ class TryFinallyStatNode(StatNode): finally_old_labels = code.all_new_labels() code.putln('{') + old_exc_vars = code.funcstate.exc_vars + code.funcstate.exc_vars = exc_vars[:3] fresh_finally_clause().generate_execution_code(code) + code.funcstate.exc_vars = old_exc_vars code.putln('}') if needs_success_cleanup: diff --git a/Cython/Utility/Builtins.c b/Cython/Utility/Builtins.c index 92dc753c6..7c966d813 100644 --- a/Cython/Utility/Builtins.c +++ b/Cython/Utility/Builtins.c @@ -369,3 +369,48 @@ static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewItems(PyObject* d); /*proto*/ static CYTHON_INLINE PyObject* __Pyx_PyDict_ViewItems(PyObject* d) { return __Pyx_PyObject_CallMethod0(d, (PY_MAJOR_VERSION >= 3) ? PYIDENT("items") : PYIDENT("viewitems")); } + +//////////////////// pyset_compat.proto //////////////////// + +#if PY_VERSION_HEX < 0x02050000 +#ifndef PyAnySet_CheckExact + +#define PyAnySet_CheckExact(ob) \ + ((ob)->ob_type == &PySet_Type || \ + (ob)->ob_type == &PyFrozenSet_Type) + +#define PySet_New(iterable) \ + PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL) + +#define Pyx_PyFrozenSet_New(iterable) \ + PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL) + +#define PySet_Size(anyset) \ + PyObject_Size((anyset)) + +#define PySet_Contains(anyset, key) \ + PySequence_Contains((anyset), (key)) + +#define PySet_Pop(set) \ + PyObject_CallMethod((set), (char*)"pop", NULL) + +static CYTHON_INLINE int PySet_Clear(PyObject *set) { + PyObject *ret = PyObject_CallMethod(set, (char*)"clear", NULL); + if (!ret) return -1; + Py_DECREF(ret); return 0; +} + +static CYTHON_INLINE int PySet_Discard(PyObject *set, PyObject *key) { + PyObject *ret = PyObject_CallMethod(set, (char*)"discard", (char*)"(O)", key); + if (!ret) return -1; + Py_DECREF(ret); return 0; +} + +static CYTHON_INLINE int PySet_Add(PyObject *set, PyObject *key) { + PyObject *ret = PyObject_CallMethod(set, (char*)"add", (char*)"(O)", key); + if (!ret) return -1; + Py_DECREF(ret); return 0; +} + +#endif /* PyAnySet_CheckExact (<= Py2.4) */ +#endif /* < Py2.5 */ diff --git a/Cython/Utility/Exceptions.c b/Cython/Utility/Exceptions.c index 916d6f221..4bfd19777 100644 --- a/Cython/Utility/Exceptions.c +++ b/Cython/Utility/Exceptions.c @@ -430,6 +430,9 @@ static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno, PyObject *ctx; __Pyx_ErrFetch(&old_exc, &old_val, &old_tb); if (full_traceback) { + Py_XINCREF(old_exc); + Py_XINCREF(old_val); + Py_XINCREF(old_tb); __Pyx_ErrRestore(old_exc, old_val, old_tb); PyErr_PrintEx(1); } diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c index e3a84ee47..88a134ea9 100644 --- a/Cython/Utility/ModuleSetupCode.c +++ b/Cython/Utility/ModuleSetupCode.c @@ -133,7 +133,9 @@ #if PY_VERSION_HEX < 0x02060000 #define Py_TPFLAGS_HAVE_VERSION_TAG 0 #endif - +#if PY_VERSION_HEX < 0x02060000 && !defined(Py_TPFLAGS_IS_ABSTRACT) + #define Py_TPFLAGS_IS_ABSTRACT 0 +#endif #if PY_VERSION_HEX < 0x030400a1 && !defined(Py_TPFLAGS_HAVE_FINALIZE) #define Py_TPFLAGS_HAVE_FINALIZE 0 #endif diff --git a/Cython/Utility/StringTools.c b/Cython/Utility/StringTools.c index 7b4b15c22..9af45aaa8 100644 --- a/Cython/Utility/StringTools.c +++ b/Cython/Utility/StringTools.c @@ -133,15 +133,40 @@ static CYTHON_INLINE int __Pyx_PyUnicode_Contains(PyObject* substring, PyObject* static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); /*proto*/ //////////////////// UnicodeEquals //////////////////// +//@requires: BytesEquals static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { #if CYTHON_COMPILING_IN_PYPY return PyObject_RichCompareBool(s1, s2, equals); #else +#if PY_MAJOR_VERSION < 3 + PyObject* owned_ref = NULL; +#endif + int s1_is_unicode, s2_is_unicode; if (s1 == s2) { /* as done by PyObject_RichCompareBool(); also catches the (interned) empty string */ - return (equals == Py_EQ); - } else if (PyUnicode_CheckExact(s1) & PyUnicode_CheckExact(s2)) { + goto return_eq; + } + s1_is_unicode = PyUnicode_CheckExact(s1); + s2_is_unicode = PyUnicode_CheckExact(s2); +#if PY_MAJOR_VERSION < 3 + if ((s1_is_unicode & (!s2_is_unicode)) && PyString_CheckExact(s2)) { + owned_ref = PyUnicode_FromObject(s2); + if (unlikely(!owned_ref)) + return -1; + s2 = owned_ref; + s2_is_unicode = 1; + } else if ((s2_is_unicode & (!s1_is_unicode)) && PyString_CheckExact(s1)) { + owned_ref = PyUnicode_FromObject(s1); + if (unlikely(!owned_ref)) + return -1; + s1 = owned_ref; + s1_is_unicode = 1; + } else if (((!s2_is_unicode) & (!s1_is_unicode))) { + return __Pyx_PyBytes_Equals(s1, s2, equals); + } +#endif + if (s1_is_unicode & s2_is_unicode) { Py_ssize_t length; int kind; void *data1, *data2; @@ -150,26 +175,31 @@ static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int return -1; #endif length = __Pyx_PyUnicode_GET_LENGTH(s1); - if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) - return (equals == Py_NE); + if (length != __Pyx_PyUnicode_GET_LENGTH(s2)) { + goto return_ne; + } // len(s1) == len(s2) >= 1 (empty string is interned, and "s1 is not s2") kind = __Pyx_PyUnicode_KIND(s1); - if (kind != __Pyx_PyUnicode_KIND(s2)) - return (equals == Py_NE); + if (kind != __Pyx_PyUnicode_KIND(s2)) { + goto return_ne; + } data1 = __Pyx_PyUnicode_DATA(s1); data2 = __Pyx_PyUnicode_DATA(s2); if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { - return (equals == Py_NE); + goto return_ne; } else if (length == 1) { - return (equals == Py_EQ); + goto return_eq; } else { int result = memcmp(data1, data2, length * kind); + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif return (equals == Py_EQ) ? (result == 0) : (result != 0); } - } else if ((s1 == Py_None) & PyUnicode_CheckExact(s2)) { - return (equals == Py_NE); - } else if ((s2 == Py_None) & PyUnicode_CheckExact(s1)) { - return (equals == Py_NE); + } else if ((s1 == Py_None) & s2_is_unicode) { + goto return_ne; + } else if ((s2 == Py_None) & s1_is_unicode) { + goto return_ne; } else { int result; PyObject* py_result = PyObject_RichCompare(s1, s2, equals); @@ -179,6 +209,16 @@ static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int Py_DECREF(py_result); return result; } +return_eq: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_EQ); +return_ne: + #if PY_MAJOR_VERSION < 3 + Py_XDECREF(owned_ref); + #endif + return (equals == Py_NE); #endif } diff --git a/tests/run/richcmp_str_equals.py b/tests/run/richcmp_str_equals.py index 2ac59859a..f6539f4a8 100644 --- a/tests/run/richcmp_str_equals.py +++ b/tests/run/richcmp_str_equals.py @@ -11,12 +11,16 @@ class testobj(object): def __eq__(self, other): return plop() -def test_equals(): +def test_equals(x): """ - >>> result = test_equals() + >>> x = testobj() + >>> result = test_equals(x) >>> isinstance(result, plop) True + >>> test_equals('hihi') + False + >>> test_equals('coucou') + True """ - blah = testobj() - eq = blah == 'coucou' # not every str equals returns a bool ... + eq = x == 'coucou' # not every str equals returns a bool ... return eq diff --git a/tests/run/set.pyx b/tests/run/set.pyx index 715a481ad..f4d6868dc 100644 --- a/tests/run/set.pyx +++ b/tests/run/set.pyx @@ -35,13 +35,14 @@ def test_set_add(): >>> type(test_set_add()) is _set True >>> sorted(test_set_add()) - ['a', 1] + ['a', 1, (1, 2)] """ cdef set s1 - s1 = set([1]) + s1 = set([1, (1, 2)]) s1.add(1) s1.add('a') s1.add(1) + s1.add((1,2)) return s1 def test_set_clear(): @@ -159,14 +160,18 @@ def test_set_of_tuple(): return set((1, 2, 3)) def sorted(it): - # Py3 can't compare strings to ints + # Py3 can't compare different types chars = [] nums = [] + tuples = [] for item in it: if type(item) is int: nums.append(item) + elif type(item) is tuple: + tuples.append(item) else: chars.append(item) nums.sort() chars.sort() - return chars+nums + tuples.sort() + return chars+nums+tuples diff --git a/tests/run/string_comparison.pyx b/tests/run/string_comparison.pyx index 193f100d0..7e19830d7 100644 --- a/tests/run/string_comparison.pyx +++ b/tests/run/string_comparison.pyx @@ -15,6 +15,10 @@ ustring2 = u"1234567" # unicode +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def unicode_eq(unicode s1, unicode s2): """ >>> unicode_eq(ustring1, ustring1) @@ -26,6 +30,10 @@ def unicode_eq(unicode s1, unicode s2): """ return s1 == s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def unicode_neq(unicode s1, unicode s2): """ >>> unicode_neq(ustring1, ustring1) @@ -37,6 +45,10 @@ def unicode_neq(unicode s1, unicode s2): """ return s1 != s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def unicode_literal_eq(unicode s): """ >>> unicode_literal_eq(ustring1) @@ -48,6 +60,10 @@ def unicode_literal_eq(unicode s): """ return s == u"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def unicode_literal_neq(unicode s): """ >>> unicode_literal_neq(ustring1) @@ -59,6 +75,15 @@ def unicode_literal_neq(unicode s): """ return s != u"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", + "//CascadedCmpNode" +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) def unicode_cascade(unicode s1, unicode s2): """ >>> unicode_cascade(ustring1, ustring1) @@ -70,6 +95,10 @@ def unicode_cascade(unicode s1, unicode s2): """ return s1 == s2 == u"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def unicode_cascade_untyped_end(unicode s1, unicode s2): """ >>> unicode_cascade_untyped_end(ustring1, ustring1) @@ -81,8 +110,31 @@ def unicode_cascade_untyped_end(unicode s1, unicode s2): """ return s1 == s2 == u"abcdefg" == (<object>ustring1) == ustring1 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def unicode_cascade_untyped_end_bool(unicode s1, unicode s2): + """ + >>> unicode_cascade_untyped_end_bool(ustring1, ustring1) + True + >>> unicode_cascade_untyped_end_bool(ustring1, (ustring1+ustring2)[:len(ustring1)]) + True + >>> unicode_cascade_untyped_end_bool(ustring1, ustring2) + False + """ + if s1 == s2 == u"abcdefg" == (<object>ustring1) == ustring1: + return True + else: + return False + + # str +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def str_eq(str s1, str s2): """ >>> str_eq(string1, string1) @@ -94,6 +146,10 @@ def str_eq(str s1, str s2): """ return s1 == s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def str_neq(str s1, str s2): """ >>> str_neq(string1, string1) @@ -105,6 +161,10 @@ def str_neq(str s1, str s2): """ return s1 != s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def str_literal_eq(str s): """ >>> str_literal_eq(string1) @@ -116,6 +176,10 @@ def str_literal_eq(str s): """ return s == "abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def str_literal_neq(str s): """ >>> str_literal_neq(string1) @@ -127,6 +191,14 @@ def str_literal_neq(str s): """ return s != "abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) def str_cascade(str s1, str s2): """ >>> str_cascade(string1, string1) @@ -138,6 +210,10 @@ def str_cascade(str s1, str s2): """ return s1 == s2 == "abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def str_cascade_untyped_end(str s1, str s2): """ >>> str_cascade_untyped_end(string1, string1) @@ -151,6 +227,10 @@ def str_cascade_untyped_end(str s1, str s2): # bytes +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def bytes_eq(bytes s1, bytes s2): """ >>> bytes_eq(bstring1, bstring1) @@ -162,6 +242,10 @@ def bytes_eq(bytes s1, bytes s2): """ return s1 == s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def bytes_neq(bytes s1, bytes s2): """ >>> bytes_neq(bstring1, bstring1) @@ -173,6 +257,10 @@ def bytes_neq(bytes s1, bytes s2): """ return s1 != s2 +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def bytes_literal_eq(bytes s): """ >>> bytes_literal_eq(bstring1) @@ -184,6 +272,10 @@ def bytes_literal_eq(bytes s): """ return s == b"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def bytes_literal_neq(bytes s): """ >>> bytes_literal_neq(bstring1) @@ -195,6 +287,14 @@ def bytes_literal_neq(bytes s): """ return s != b"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) def bytes_cascade(bytes s1, bytes s2): """ >>> bytes_cascade(bstring1, bstring1) @@ -206,6 +306,10 @@ def bytes_cascade(bytes s1, bytes s2): """ return s1 == s2 == b"abcdefg" +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) def bytes_cascade_untyped_end(bytes s1, bytes s2): """ >>> bytes_cascade_untyped_end(bstring1, bstring1) @@ -218,6 +322,288 @@ def bytes_cascade_untyped_end(bytes s1, bytes s2): return s1 == s2 == b"abcdefg" == (<object>bstring1) == bstring1 +# basestring + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_eq(basestring s1, basestring s2): + """ + >>> basestring_eq(string1, string1) + True + >>> basestring_eq(string1, ustring1) + True + >>> basestring_eq(string1+string2, string1+string2) + True + >>> basestring_eq(string1+ustring2, ustring1+string2) + True + >>> basestring_eq(string1, string2) + False + >>> basestring_eq(string1, ustring2) + False + >>> basestring_eq(ustring1, string2) + False + """ + return s1 == s2 + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_neq(basestring s1, basestring s2): + """ + >>> basestring_neq(string1, string1) + False + >>> basestring_neq(string1+string2, string1+string2) + False + >>> basestring_neq(string1+ustring2, ustring1+string2) + False + >>> basestring_neq(string1, string2) + True + >>> basestring_neq(string1, ustring2) + True + >>> basestring_neq(ustring1, string2) + True + """ + return s1 != s2 + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_str_literal_eq(basestring s): + """ + >>> basestring_str_literal_eq(string1) + True + >>> basestring_str_literal_eq((string1+string2)[:len(string1)]) + True + >>> basestring_str_literal_eq(string2) + False + """ + return s == "abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_unicode_literal_eq(basestring s): + """ + >>> basestring_unicode_literal_eq(string1) + True + >>> basestring_unicode_literal_eq((string1+string2)[:len(string1)]) + True + >>> basestring_unicode_literal_eq(string2) + False + """ + return s == u"abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_str_literal_neq(basestring s): + """ + >>> basestring_str_literal_neq(string1) + False + >>> basestring_str_literal_neq((string1+string2)[:len(string1)]) + False + >>> basestring_str_literal_neq(string2) + True + """ + return s != "abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_unicode_literal_neq(basestring s): + """ + >>> basestring_unicode_literal_neq(string1) + False + >>> basestring_unicode_literal_neq((string1+string2)[:len(string1)]) + False + >>> basestring_unicode_literal_neq(string2) + True + """ + return s != u"abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", + "//CascadedCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) +def basestring_cascade_str(basestring s1, basestring s2): + """ + >>> basestring_cascade_str(string1, string1) + True + >>> basestring_cascade_str(string1, (string1+string2)[:len(string1)]) + True + >>> basestring_cascade_str(string1, string2) + False + """ + return s1 == s2 == "abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", + "//CascadedCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) +def basestring_cascade_unicode(basestring s1, basestring s2): + """ + >>> basestring_cascade_unicode(string1, string1) + True + >>> basestring_cascade_unicode(ustring1, string1) + True + >>> basestring_cascade_unicode(string1, ustring1) + True + >>> basestring_cascade_unicode(string1, (string1+string2)[:len(string1)]) + True + >>> basestring_cascade_unicode(string1, string2) + False + >>> basestring_cascade_unicode(ustring1, string2) + False + >>> basestring_cascade_unicode(string1, ustring2) + False + """ + return s1 == s2 == u"abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def basestring_cascade_untyped_end(basestring s1, basestring s2): + """ + >>> basestring_cascade_untyped_end(string1, string1) + True + >>> basestring_cascade_untyped_end(string1, (string1+string2)[:len(string1)]) + True + >>> basestring_cascade_untyped_end(string1, string2) + False + """ + return s1 == s2 == "abcdefg" == (<object>string1) == string1 + + +# untyped/literal comparison + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def untyped_unicode_literal_eq_bool(s): + """ + >>> untyped_unicode_literal_eq_bool(string1) + True + >>> untyped_unicode_literal_eq_bool(ustring1) + True + >>> untyped_unicode_literal_eq_bool((string1+string2)[:len(string1)]) + True + >>> untyped_unicode_literal_eq_bool(string2) + False + >>> untyped_unicode_literal_eq_bool(ustring2) + False + """ + return True if s == u"abcdefg" else False + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def untyped_str_literal_eq_bool(s): + """ + >>> untyped_str_literal_eq_bool(string1) + True + >>> untyped_str_literal_eq_bool(ustring1) + True + >>> untyped_str_literal_eq_bool((string1+string2)[:len(string1)]) + True + >>> untyped_str_literal_eq_bool(string2) + False + >>> untyped_str_literal_eq_bool(ustring2) + False + """ + return True if s == "abcdefg" else False + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = True]", + "//CascadedCmpNode", + "//CascadedCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def untyped_unicode_cascade(s1, unicode s2): + """ + >>> untyped_unicode_cascade(ustring1, ustring1) + True + >>> untyped_unicode_cascade(ustring1, (ustring1+ustring2)[:len(ustring1)]) + True + >>> untyped_unicode_cascade(ustring1, ustring2) + False + """ + return s1 == s2 == u"abcdefg" + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = False]", + "//CascadedCmpNode", + "//CascadedCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = True]", +) +def untyped_unicode_cascade_bool(s1, unicode s2): + """ + >>> untyped_unicode_cascade_bool(ustring1, ustring1) + True + >>> untyped_unicode_cascade_bool(ustring1, (ustring1+ustring2)[:len(ustring1)]) + True + >>> untyped_unicode_cascade_bool(ustring1, ustring2) + False + """ + return True if s1 == s2 == u"abcdefg" else False + +@cython.test_assert_path_exists( + "//PrimaryCmpNode", + "//PrimaryCmpNode[@is_pycmp = True]", + "//CascadedCmpNode", +# "//CascadedCmpNode[@is_pycmp = False]", +) +@cython.test_fail_if_path_exists( + "//CascadedCmpNode[@is_pycmp = True]", + "//PrimaryCmpNode[@is_pycmp = False]", +) +def untyped_untyped_unicode_cascade_bool(s1, s2): + """ + >>> untyped_untyped_unicode_cascade_bool(ustring1, ustring1) + True + >>> untyped_untyped_unicode_cascade_bool(ustring1, (ustring1+ustring2)[:len(ustring1)]) + True + >>> untyped_untyped_unicode_cascade_bool(ustring1, ustring2) + False + >>> untyped_untyped_unicode_cascade_bool(string1, string2) + False + >>> untyped_untyped_unicode_cascade_bool(1, 2) + False + >>> untyped_untyped_unicode_cascade_bool(1, 1) + False + """ + return True if s1 == s2 == u"abcdefg" else False + + +# bytes/str comparison + @cython.test_assert_path_exists( '//CondExprNode', '//CondExprNode//PrimaryCmpNode', diff --git a/tests/run/tryfinally.pyx b/tests/run/tryfinally.pyx index a0e3fdb5a..a878df3a3 100644 --- a/tests/run/tryfinally.pyx +++ b/tests/run/tryfinally.pyx @@ -73,6 +73,31 @@ def except_finally_reraise(): raise +def except_finally_reraise_new(): + """ + >>> def py_check(): + ... try: raise ValueError + ... except ValueError: + ... try: raise TypeError + ... finally: + ... raise + >>> try: py_check() + ... except ValueError: assert not IS_PY3 + ... except TypeError: assert IS_PY3 + ... else: assert False + >>> try: except_finally_reraise_new() + ... except TypeError: pass # currently only Py3 semantics implemented + ... else: assert False + """ + try: + raise ValueError + except ValueError: + try: + raise TypeError + finally: + raise + + def finally_exception_check_return(): """ >>> if not IS_PY3: |