Skip to content

Commit 04ab0ae

Browse files
author
benjamin.peterson
committed
allow unicode keyword arguments for the ** syntax #4978
git-svn-id: http://svn.python.org/projects/python/trunk@68805 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent ff1e04b commit 04ab0ae

3 files changed

Lines changed: 55 additions & 12 deletions

File tree

Lib/test/test_extcall.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
"""Doctest for method/function calls.
23
34
We're going the use these types for extra testing
@@ -252,11 +253,30 @@
252253
253254
"""
254255

256+
import unittest
255257
from test import test_support
256258

259+
260+
class UnicodeKeywordArgsTest(unittest.TestCase):
261+
262+
def test_unicode_keywords(self):
263+
def f(a):
264+
return a
265+
self.assertEqual(f(**{u'a': 4}), 4)
266+
self.assertRaises(TypeError, f, **{u'stören': 4})
267+
self.assertRaises(TypeError, f, **{u'someLongString':2})
268+
try:
269+
f(a=4, **{u'a': 4})
270+
except TypeError:
271+
pass
272+
else:
273+
self.fail("duplicate arguments didn't raise")
274+
275+
257276
def test_main():
258277
from test import test_extcall # self import
259278
test_support.run_doctest(test_extcall, True)
279+
test_support.run_unittest(UnicodeKeywordArgsTest)
260280

261281
if __name__ == '__main__':
262282
test_main()

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ What's New in Python 2.7 alpha 1
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #4978: Passing keyword arguments as unicode strings is now allowed.
16+
1517
- os.ftruncate raises OSErrors instead of IOErrors for consistency with other os
1618
functions.
1719

Python/ceval.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ static void reset_exc_info(PyThreadState *);
127127
static void format_exc_check_arg(PyObject *, char *, PyObject *);
128128
static PyObject * string_concatenate(PyObject *, PyObject *,
129129
PyFrameObject *, unsigned char *);
130+
static PyObject * kwd_as_string(PyObject *);
130131

131132
#define NAME_ERROR_MSG \
132133
"name '%.200s' is not defined"
@@ -2932,7 +2933,8 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
29322933
PyObject *keyword = kws[2*i];
29332934
PyObject *value = kws[2*i + 1];
29342935
int j;
2935-
if (keyword == NULL || !PyString_Check(keyword)) {
2936+
if (keyword == NULL || !(PyString_Check(keyword) ||
2937+
PyUnicode_Check(keyword))) {
29362938
PyErr_Format(PyExc_TypeError,
29372939
"%.200s() keywords must be strings",
29382940
PyString_AsString(co->co_name));
@@ -2961,24 +2963,32 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
29612963
goto fail;
29622964
if (j >= co->co_argcount) {
29632965
if (kwdict == NULL) {
2964-
PyErr_Format(PyExc_TypeError,
2965-
"%.200s() got an unexpected "
2966-
"keyword argument '%.400s'",
2967-
PyString_AsString(co->co_name),
2968-
PyString_AsString(keyword));
2966+
PyObject *kwd_str = kwd_as_string(keyword);
2967+
if (kwd_str) {
2968+
PyErr_Format(PyExc_TypeError,
2969+
"%.200s() got an unexpected "
2970+
"keyword argument '%.400s'",
2971+
PyString_AsString(co->co_name),
2972+
PyString_AsString(kwd_str));
2973+
Py_DECREF(kwd_str);
2974+
}
29692975
goto fail;
29702976
}
29712977
PyDict_SetItem(kwdict, keyword, value);
29722978
continue;
29732979
}
29742980
kw_found:
29752981
if (GETLOCAL(j) != NULL) {
2976-
PyErr_Format(PyExc_TypeError,
2977-
"%.200s() got multiple "
2978-
"values for keyword "
2979-
"argument '%.400s'",
2980-
PyString_AsString(co->co_name),
2981-
PyString_AsString(keyword));
2982+
PyObject *kwd_str = kwd_as_string(keyword);
2983+
if (kwd_str) {
2984+
PyErr_Format(PyExc_TypeError,
2985+
"%.200s() got multiple "
2986+
"values for keyword "
2987+
"argument '%.400s'",
2988+
PyString_AsString(co->co_name),
2989+
PyString_AsString(kwd_str));
2990+
Py_DECREF(kwd_str);
2991+
}
29822992
goto fail;
29832993
}
29842994
Py_INCREF(value);
@@ -3105,6 +3115,17 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
31053115
}
31063116

31073117

3118+
static PyObject *
3119+
kwd_as_string(PyObject *kwd) {
3120+
if (PyString_Check(kwd)) {
3121+
Py_INCREF(kwd);
3122+
return kwd;
3123+
}
3124+
else
3125+
return _PyUnicode_AsDefaultEncodedString(kwd, "replace");
3126+
}
3127+
3128+
31083129
/* Implementation notes for set_exc_info() and reset_exc_info():
31093130
31103131
- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and

0 commit comments

Comments
 (0)