summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.rst12
-rw-r--r--Cython/Compiler/Builtin.py47
-rw-r--r--Cython/Compiler/ExprNodes.py34
-rw-r--r--Cython/Compiler/ModuleNode.py4
-rw-r--r--Cython/Compiler/Nodes.py9
-rw-r--r--Cython/Utility/Builtins.c45
-rw-r--r--Cython/Utility/Exceptions.c3
-rw-r--r--Cython/Utility/ModuleSetupCode.c4
-rw-r--r--Cython/Utility/StringTools.c64
-rw-r--r--tests/run/richcmp_str_equals.py12
-rw-r--r--tests/run/set.pyx13
-rw-r--r--tests/run/string_comparison.pyx386
-rw-r--r--tests/run/tryfinally.pyx25
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: