fix keyword arguments in function calls: must be unicode in Py3 and strings in Py2...
authorStefan Behnel <scoder@users.berlios.de>
Sun, 18 May 2008 06:59:16 +0000 (08:59 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 18 May 2008 06:59:16 +0000 (08:59 +0200)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
tests/run/kwonlyargscall.pyx [new file with mode: 0644]

index e8354575bab457e424af5943a0e5d92397b0daeb..c2ae18b43d4a55c5a9d896265a3e695a43256665 100644 (file)
@@ -736,6 +736,18 @@ class StringNode(ConstNode):
             return self.entry.cname
 
 
+class KeywordNameNode(ConstNode):
+    # A keyword in a Python function call: a string that behaves like
+    # an identifier
+    type = PyrexTypes.py_object_type
+
+    def analyse_types(self, env):
+        self.cname = env.intern_identifier(self.value)
+
+    def calculate_result_code(self):
+        return self.cname
+
+
 class LongNode(AtomicExprNode):
     #  Python long integer literal
     #
index bd99380fad6d2eca61643f73ab9c3fe473d86b3b..8d0f2e062b23a7f86f77963d628c6b8d6c0c3907 100644 (file)
@@ -4347,7 +4347,7 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
 static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
     while (t->p) {
         #if PY_MAJOR_VERSION < 3
-        if (t->is_unicode) {
+        if (t->is_unicode && (!t->is_identifier)) {
             *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
         } else if (t->intern) {
             *t->p = PyString_InternFromString(t->s);
index c52b19b9d239f0cfd07dab077a14d3c9901c8ffb..a2f9f38fe0da7c3f9d0796c3b2c3c70412439ba5 100644 (file)
@@ -284,8 +284,7 @@ def p_call(s, function):
                 s.error("Expected an identifier before '='",
                     pos = arg.pos)
             encoded_name = Utils.EncodedString(arg.name)
-            encoded_name.encoding = s.source_encoding
-            keyword = ExprNodes.StringNode(arg.pos, 
+            keyword = ExprNodes.KeywordNameNode(arg.pos, 
                 value = encoded_name)
             arg = p_simple_expr(s)
             keyword_args.append((keyword, arg))
diff --git a/tests/run/kwonlyargscall.pyx b/tests/run/kwonlyargscall.pyx
new file mode 100644 (file)
index 0000000..3f23dcd
--- /dev/null
@@ -0,0 +1,165 @@
+__doc__ = u"""
+    >>> call3(b)
+    >>> call4(b)
+    Traceback (most recent call last):
+    TypeError: function takes exactly 3 arguments (4 given)
+
+    >>> call2(c)
+    >>> call3(c)
+    >>> call4(c)
+    Traceback (most recent call last):
+    TypeError: function takes at most 3 arguments (4 given)
+
+    >>> call2(d)
+    >>> call2c(d)
+
+    >>> call3(d)
+    Traceback (most recent call last):
+    TypeError: function takes at most 2 positional arguments (3 given)
+    >>> call2d(d)
+    Traceback (most recent call last):
+    TypeError: 'd' is an invalid keyword argument for this function
+
+    >>> call2(e)
+    >>> call2c(e)
+    >>> call2d(e)
+    >>> call2cde(e)
+    >>> call3(e)
+    >>> call4(e)
+    Traceback (most recent call last):
+    TypeError: function takes at most 3 positional arguments (4 given)
+
+    >>> call2c(f)
+    >>> call2cd(f)
+
+    >>> call3(f)
+    Traceback (most recent call last):
+    TypeError: function takes at most 2 positional arguments (3 given)
+    >>> call2(f)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'c' is missing
+    >>> call2ce(f)
+    Traceback (most recent call last):
+    TypeError: 'e' is an invalid keyword argument for this function
+
+    >>> call2cf(g)
+    >>> call2cefd(g)
+    >>> call2cfex(g)
+
+    >>> call3(g)
+    Traceback (most recent call last):
+    TypeError: function takes at most 2 positional arguments (3 given)
+    >>> call2(g)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'c' is missing
+    >>> call2c(g)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'f' is missing
+
+    >>> call2cf(h)
+    >>> call2cfe(h)
+    >>> call6cf(h)
+    >>> call6cfexy(h)
+
+    >>> call3(h)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'c' is missing
+    >>> call3d(h)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'c' is missing
+
+    >>> call2cf(k)
+    >>> call2cfe(k)
+    >>> call6df(k)
+    >>> call6dfexy(k)
+
+    >>> call3(k)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'f' is missing
+    >>> call2d(k)
+    Traceback (most recent call last):
+    TypeError: required keyword argument 'f' is missing
+"""
+
+import sys, re
+if sys.version_info[0] >= 3:
+    __doc__ = re.sub(u"Error: (.*)exactly(.*)", u"Error: \\1at most\\2", __doc__)
+
+# the calls:
+
+def call2(f):
+    f(1,2)
+
+def call3(f):
+    f(1,2,3)
+
+def call4(f):
+    f(1,2,3,4)
+
+def call2c(f):
+    f(1,2, c=1)
+
+def call2d(f):
+    f(1,2, d=1)
+
+def call3d(f):
+    f(1,2,3, d=1)
+
+def call2cd(f):
+    f(1,2, c=1, d=2)
+
+def call2ce(f):
+    f(1,2, c=1, e=2)
+
+def call2cde(f):
+    f(1,2, c=1, d=2, e=3)
+
+def call2cf(f):
+    f(1,2, c=1, f=2)
+
+def call6cf(f):
+    f(1,2,3,4,5,6, c=1, f=2)
+
+def call6df(f):
+    f(1,2,3,4,5,6, d=1, f=2)
+
+def call2cfe(f):
+    f(1,2, c=1, f=2, e=3)
+
+def call2cefd(f):
+    f(1,2, c=1, e=0, f=2, d=11)
+
+def call2cfex(f):
+    f(1,2, c=1, f=2, e=0, x=25)
+
+def call6cfexy(f):
+    f(1,2,3,4,5,6, c=1, f=2, e=3, x=25, y=11)
+
+def call6dfexy(f):
+    f(1,2,3,4,5,6, d=1, f=2, e=3, x=25, y=11)
+
+# the called functions:
+
+def b(a, b, c):
+    pass
+
+def c(a, b, c=1):
+    pass
+
+def d(a, b, *, c = 88):
+    pass
+
+def e(a, b, c = 88, **kwds):
+    pass
+
+def f(a, b, *, c, d = 42):
+    pass
+
+def g(a, b, *, c, d = 42, e = 17, f, **kwds):
+    pass
+
+def h(a, b, *args, c, d = 42, e = 17, f, **kwds):
+    pass
+
+def k(a, b, c=1, *args, d = 42, e = 17, f, **kwds):
+    pass