From be65922fd388dba800228d14df0c8afff7213f98 Mon Sep 17 00:00:00 2001 From: Stefan Behnel <stefan_ml@behnel.de> Date: Mon, 16 Dec 2013 21:54:06 +0100 Subject: [PATCH] implement Python corner case of passing a tuple as assert message --- Cython/Compiler/ExprNodes.py | 3 +- Cython/Compiler/Nodes.py | 8 +++++- tests/run/assert.pyx | 55 ++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index a9700d06f..44d42d4fb 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -5673,6 +5673,7 @@ class SequenceNode(ExprNode): is_sequence_constructor = 1 unpacked_items = None mult_factor = None + slow = False # trade speed for code size (e.g. use PyTuple_Pack()) def compile_time_value_list(self, denv): return [arg.compile_time_value(denv) for arg in self.args] @@ -5754,7 +5755,7 @@ class SequenceNode(ExprNode): else: size_factor = ' * ((%s<0) ? 0:%s)' % (c_mult, c_mult) - if self.type is Builtin.tuple_type and self.is_literal and not c_mult: + if self.type is Builtin.tuple_type and (self.is_literal or self.slow) and not c_mult: # use PyTuple_Pack() to avoid generating huge amounts of one-time code code.putln('%s = PyTuple_Pack(%d, %s); %s' % ( target, diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index f7ff83422..897285b8a 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -5222,7 +5222,13 @@ class AssertStatNode(StatNode): self.cond = self.cond.analyse_boolean_expression(env) if self.value: value = self.value.analyse_types(env) - self.value = value.coerce_to_pyobject(env) + if value.type is Builtin.tuple_type or not value.type.is_builtin_type: + # prevent tuple values from being interpreted as argument value tuples + from ExprNodes import TupleNode + value = TupleNode(value.pos, args=[value], slow=True) + self.value = value.analyse_types(env, skip_children=True) + else: + self.value = value.coerce_to_pyobject(env) return self nogil_check = Node.gil_error diff --git a/tests/run/assert.pyx b/tests/run/assert.pyx index b431001d9..1e6cc17be 100644 --- a/tests/run/assert.pyx +++ b/tests/run/assert.pyx @@ -1,3 +1,7 @@ +# mode: run + +cimport cython + def f(a, b, int i): """ >>> f(1, 2, 1) @@ -15,11 +19,62 @@ def f(a, b, int i): assert a+b assert i + +@cython.test_assert_path_exists( + '//AssertStatNode', + '//AssertStatNode//TupleNode') def g(a, b): """ >>> g(1, "works") >>> g(0, "fails") Traceback (most recent call last): AssertionError: fails + >>> g(0, (1, 2)) + Traceback (most recent call last): + AssertionError: (1, 2) """ assert a, b + + +@cython.test_assert_path_exists( + '//AssertStatNode', + '//AssertStatNode//TupleNode') +def g(a, b): + """ + >>> g(1, "works") + >>> g(0, "fails") + Traceback (most recent call last): + AssertionError: fails + >>> g(0, (1, 2)) + Traceback (most recent call last): + AssertionError: (1, 2) + """ + assert a, b + + +@cython.test_assert_path_exists( + '//AssertStatNode', + '//AssertStatNode//TupleNode', + '//AssertStatNode//TupleNode//TupleNode') +def assert_with_tuple_arg(a): + """ + >>> assert_with_tuple_arg(True) + >>> assert_with_tuple_arg(False) + Traceback (most recent call last): + AssertionError: (1, 2) + """ + assert a, (1, 2) + + +@cython.test_assert_path_exists( + '//AssertStatNode') +@cython.test_fail_if_path_exists( + '//AssertStatNode//TupleNode') +def assert_with_str_arg(a): + """ + >>> assert_with_str_arg(True) + >>> assert_with_str_arg(False) + Traceback (most recent call last): + AssertionError: abc + """ + assert a, 'abc' -- 2.30.9