Commit a8f70e22 authored by Stefan Behnel's avatar Stefan Behnel

refactoring and rewrite of optional kw arguments parsing helper function to...

refactoring and rewrite of optional kw arguments parsing helper function to support Unicode keyword arguments in Py2 (CPython supports them in Py2.6+)
parent d396000b
......@@ -99,7 +99,7 @@ static void __Pyx_RaiseDoubleKeywordsError(
"%s() got multiple values for keyword argument '%U'", func_name, kw_name);
#else
"%s() got multiple values for keyword argument '%s'", func_name,
PyString_AS_STRING(kw_name));
PyString_AsString(kw_name));
#endif
}
......@@ -196,49 +196,78 @@ static int __Pyx_ParseOptionalKeywords(
while (*name && (**name != key)) name++;
if (*name) {
values[name-argnames] = value;
} else {
#if PY_MAJOR_VERSION < 3
if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) {
#else
if (unlikely(!PyUnicode_Check(key))) {
#endif
goto invalid_keyword_type;
} else {
for (name = first_kw_arg; *name; name++) {
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
PyUnicode_Compare(**name, key) == 0) break;
#else
if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
_PyString_Eq(**name, key)) break;
#endif
}
if (*name) {
continue;
}
name = first_kw_arg;
#if PY_MAJOR_VERSION < 3
if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) {
while (*name) {
if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key))
&& _PyString_Eq(**name, key)) {
values[name-argnames] = value;
} else {
/* unexpected keyword found */
for (name=argnames; name != first_kw_arg; name++) {
if (**name == key) goto arg_passed_twice;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) &&
PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice;
#else
if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) &&
_PyString_Eq(**name, key)) goto arg_passed_twice;
#endif
}
if (kwds2) {
if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
} else {
goto invalid_keyword;
break;
}
name++;
}
if (*name) continue;
else {
// not found after positional args, check for duplicate
PyObject*** argname = argnames;
while (argname != first_kw_arg) {
if ((**argname == key) || (
(CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key))
&& _PyString_Eq(**argname, key))) {
goto arg_passed_twice;
}
argname++;
}
}
} else
#endif
if (likely(PyUnicode_Check(key))) {
while (*name) {
int cmp = (**name == key) ? 0 :
#if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
(PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#endif
// need to convert argument name from bytes to unicode for comparison
PyUnicode_Compare(**name, key);
if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad;
if (cmp == 0) {
values[name-argnames] = value;
break;
}
name++;
}
if (*name) continue;
else {
// not found after positional args, check for duplicate
PyObject*** argname = argnames;
while (argname != first_kw_arg) {
int cmp = (**argname == key) ? 0 :
#if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
(PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#endif
// need to convert argument name from bytes to unicode for comparison
PyUnicode_Compare(**argname, key);
if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad;
if (cmp == 0) goto arg_passed_twice;
argname++;
}
}
} else
goto invalid_keyword_type;
if (kwds2) {
if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad;
} else {
goto invalid_keyword;
}
}
return 0;
arg_passed_twice:
__Pyx_RaiseDoubleKeywordsError(function_name, **name);
__Pyx_RaiseDoubleKeywordsError(function_name, key);
goto bad;
invalid_keyword_type:
PyErr_Format(PyExc_TypeError,
......
# -*- coding: utf8 -*-
try:
import platform
IS_PYPY = platform.python_implementation() == 'PyPy'
except (ImportError, AttributeError):
IS_PYPY = False
ustring_a = u'a'
ustring_ascii = u'abc'
ustring_nonascii = u'àöé\u0888'
def accept_kwargs(a, b, c=1, **kwargs):
"""
>>> accept_kwargs(1, 2, 3)
(1, 2, 3, {})
>>> accept_kwargs(1, 2, 3, d=5)
(1, 2, 3, {'d': 5})
>>> accept_kwargs(1, 2, 3, **{ustring_a: 5})
Traceback (most recent call last):
TypeError: accept_kwargs() got multiple values for keyword argument 'a'
>>> if not IS_PYPY: a, b, c, kwargs = accept_kwargs(1, 2, 3, **{ustring_ascii: 5})
>>> IS_PYPY and (1,2,3,1) or (a,b,c,len(kwargs))
(1, 2, 3, 1)
>>> IS_PYPY and 5 or kwargs[ustring_ascii]
5
>>> if not IS_PYPY: a, b, c, kwargs = accept_kwargs(1, 2, 3, **{ustring_nonascii: 5})
>>> IS_PYPY and (1,2,3,1) or (a,b,c,len(kwargs))
(1, 2, 3, 1)
>>> IS_PYPY and 5 or kwargs[ustring_nonascii]
5
>>> if not IS_PYPY: a, b, c, kwargs = accept_kwargs(1, 2, 3, **{ustring_nonascii: 5, ustring_ascii: 6})
>>> IS_PYPY and (1,2,3,2) or (a,b,c,len(kwargs))
(1, 2, 3, 2)
>>> IS_PYPY and 5 or kwargs[ustring_nonascii]
5
>>> IS_PYPY and 6 or kwargs[ustring_ascii]
6
"""
return a, b, c, kwargs
def unexpected_kwarg(a, b, c=1):
"""
>>> unexpected_kwarg(1, b=2)
(1, 2, 1)
>>> unexpected_kwarg(1, 2, **{ustring_ascii: 5})
Traceback (most recent call last):
TypeError: unexpected_kwarg() got an unexpected keyword argument 'abc'
>>> unexpected_kwarg(1, 2, 3, d=5)
Traceback (most recent call last):
TypeError: unexpected_kwarg() got an unexpected keyword argument 'd'
"""
return a, b, c
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment