[Python-checkins] r68805 - in python/trunk: Lib/test/test_extcall.py Misc/NEWS Python/ceval.c

benjamin.peterson python-checkins at python.org
Tue Jan 20 15:21:17 CET 2009


Author: benjamin.peterson
Date: Tue Jan 20 15:21:16 2009
New Revision: 68805

Log:
allow unicode keyword arguments for the ** syntax #4978

Modified:
   python/trunk/Lib/test/test_extcall.py
   python/trunk/Misc/NEWS
   python/trunk/Python/ceval.c

Modified: python/trunk/Lib/test/test_extcall.py
==============================================================================
--- python/trunk/Lib/test/test_extcall.py	(original)
+++ python/trunk/Lib/test/test_extcall.py	Tue Jan 20 15:21:16 2009
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 """Doctest for method/function calls.
 
 We're going the use these types for extra testing
@@ -252,11 +253,30 @@
 
 """
 
+import unittest
 from test import test_support
 
+
+class UnicodeKeywordArgsTest(unittest.TestCase):
+
+    def test_unicode_keywords(self):
+        def f(a):
+            return a
+        self.assertEqual(f(**{u'a': 4}), 4)
+        self.assertRaises(TypeError, f, **{u'stören': 4})
+        self.assertRaises(TypeError, f, **{u'someLongString':2})
+        try:
+            f(a=4, **{u'a': 4})
+        except TypeError:
+            pass
+        else:
+            self.fail("duplicate arguments didn't raise")
+
+
 def test_main():
     from test import test_extcall # self import
     test_support.run_doctest(test_extcall, True)
+    test_support.run_unittest(UnicodeKeywordArgsTest)
 
 if __name__ == '__main__':
     test_main()

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Tue Jan 20 15:21:16 2009
@@ -12,6 +12,8 @@
 Core and Builtins
 -----------------
 
+- Issue #4978: Passing keyword arguments as unicode strings is now allowed.
+
 - os.ftruncate raises OSErrors instead of IOErrors for consistency with other os
   functions.
 

Modified: python/trunk/Python/ceval.c
==============================================================================
--- python/trunk/Python/ceval.c	(original)
+++ python/trunk/Python/ceval.c	Tue Jan 20 15:21:16 2009
@@ -127,6 +127,7 @@
 static void format_exc_check_arg(PyObject *, char *, PyObject *);
 static PyObject * string_concatenate(PyObject *, PyObject *,
 				    PyFrameObject *, unsigned char *);
+static PyObject * kwd_as_string(PyObject *);
 
 #define NAME_ERROR_MSG \
 	"name '%.200s' is not defined"
@@ -2932,7 +2933,8 @@
 			PyObject *keyword = kws[2*i];
 			PyObject *value = kws[2*i + 1];
 			int j;
-			if (keyword == NULL || !PyString_Check(keyword)) {
+			if (keyword == NULL || !(PyString_Check(keyword) ||
+						 PyUnicode_Check(keyword))) {
 				PyErr_Format(PyExc_TypeError,
 				    "%.200s() keywords must be strings",
 				    PyString_AsString(co->co_name));
@@ -2961,11 +2963,15 @@
 				goto fail;
 			if (j >= co->co_argcount) {
 				if (kwdict == NULL) {
-					PyErr_Format(PyExc_TypeError,
-					    "%.200s() got an unexpected "
-					    "keyword argument '%.400s'",
-					    PyString_AsString(co->co_name),
-					    PyString_AsString(keyword));
+					PyObject *kwd_str = kwd_as_string(keyword);
+					if (kwd_str) {
+						PyErr_Format(PyExc_TypeError,
+							     "%.200s() got an unexpected "
+							     "keyword argument '%.400s'",
+							     PyString_AsString(co->co_name),
+							     PyString_AsString(kwd_str));
+						Py_DECREF(kwd_str);
+					}
 					goto fail;
 				}
 				PyDict_SetItem(kwdict, keyword, value);
@@ -2973,12 +2979,16 @@
 			}
 kw_found:
 			if (GETLOCAL(j) != NULL) {
-				PyErr_Format(PyExc_TypeError,
-						"%.200s() got multiple "
-						"values for keyword "
-						"argument '%.400s'",
-						PyString_AsString(co->co_name),
-						PyString_AsString(keyword));
+				PyObject *kwd_str = kwd_as_string(keyword);
+				if (kwd_str) {
+					PyErr_Format(PyExc_TypeError,
+						     "%.200s() got multiple "
+						     "values for keyword "
+						     "argument '%.400s'",
+						     PyString_AsString(co->co_name),
+						     PyString_AsString(kwd_str));
+					Py_DECREF(kwd_str);
+				}
 				goto fail;
 			}
 			Py_INCREF(value);
@@ -3105,6 +3115,17 @@
 }
 
 
+static PyObject *
+kwd_as_string(PyObject *kwd) {
+	if (PyString_Check(kwd)) {
+		Py_INCREF(kwd);
+		return kwd;
+	}
+	else
+		return _PyUnicode_AsDefaultEncodedString(kwd, "replace");
+}
+
+
 /* Implementation notes for set_exc_info() and reset_exc_info():
 
 - Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and


More information about the Python-checkins mailing list