diff options
author | Erlend E. Aasland <erlend@python.org> | 2024-04-11 13:55:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-11 13:55:37 (GMT) |
commit | 044dc496e06843cd3eb30a32f34d9d080635875a (patch) | |
tree | 62aeff8e7c8ccca88e2c5cd8dcb7a3b18f611791 | |
parent | 671cb22094df5b645f65c383213bfda17c8003c5 (diff) | |
download | cpython-044dc496e06843cd3eb30a32f34d9d080635875a.zip cpython-044dc496e06843cd3eb30a32f34d9d080635875a.tar.gz cpython-044dc496e06843cd3eb30a32f34d9d080635875a.tar.bz2 |
gh-117709: Add vectorcall support for str() with positional-only arguments (#117746)
Fall back to tp_call() for cases when arguments are passed by name.
Co-authored-by: Donghee Na <donghee.na@python.org>
Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r-- | Lib/test/test_str.py | 18 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2024-04-10-22-16-18.gh-issue-117709.-_1YL0.rst | 3 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 51 |
3 files changed, 72 insertions, 0 deletions
diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py index b492711..ea37eb5 100644 --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -2651,6 +2651,24 @@ class StrTest(string_tests.StringLikeTest, proc = assert_python_failure('-X', 'dev', '-c', code) self.assertEqual(proc.rc, 10, proc) + def test_str_invalid_call(self): + check = lambda *a, **kw: self.assertRaises(TypeError, str, *a, **kw) + + # too many args + check(1, "", "", 1) + + # no such kw arg + check(test=1) + + # 'encoding' must be str + check(1, encoding=1) + check(1, 1) + + # 'errors' must be str + check(1, errors=1) + check(1, "", errors=1) + check(1, 1, 1) + class StringModuleTest(unittest.TestCase): def test_formatter_parser(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-10-22-16-18.gh-issue-117709.-_1YL0.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-10-22-16-18.gh-issue-117709.-_1YL0.rst new file mode 100644 index 0000000..2216b53 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-10-22-16-18.gh-issue-117709.-_1YL0.rst @@ -0,0 +1,3 @@ +Speed up calls to :func:`str` with positional-only argument, +by using the :pep:`590` ``vectorcall`` calling convention. +Patch by Erlend Aasland. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 5f15071..2c259b7 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14617,6 +14617,56 @@ unicode_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return unicode; } +static const char * +arg_as_utf8(PyObject *obj, const char *name) +{ + if (!PyUnicode_Check(obj)) { + PyErr_Format(PyExc_TypeError, + "str() argument '%s' must be str, not %T", + name, obj); + return NULL; + } + return _PyUnicode_AsUTF8NoNUL(obj); +} + +static PyObject * +unicode_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + assert(Py_Is(_PyType_CAST(type), &PyUnicode_Type)); + + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) != 0) { + // Fallback to unicode_new() + PyObject *tuple = _PyTuple_FromArray(args, nargs); + if (tuple == NULL) { + return NULL; + } + PyObject *dict = _PyStack_AsDict(args + nargs, kwnames); + if (dict == NULL) { + Py_DECREF(tuple); + return NULL; + } + PyObject *ret = unicode_new(_PyType_CAST(type), tuple, dict); + Py_DECREF(tuple); + Py_DECREF(dict); + return ret; + } + if (!_PyArg_CheckPositional("str", nargs, 0, 3)) { + return NULL; + } + if (nargs == 0) { + return unicode_get_empty(); + } + PyObject *object = args[0]; + if (nargs == 1) { + return PyObject_Str(object); + } + const char *encoding = arg_as_utf8(args[1], "encoding"); + const char *errors = (nargs == 3) ? arg_as_utf8(args[2], "errors") : NULL; + return PyUnicode_FromEncodedObject(object, encoding, errors); +} + static PyObject * unicode_subtype_new(PyTypeObject *type, PyObject *unicode) { @@ -14758,6 +14808,7 @@ PyTypeObject PyUnicode_Type = { 0, /* tp_alloc */ unicode_new, /* tp_new */ PyObject_Del, /* tp_free */ + .tp_vectorcall = unicode_vectorcall, }; /* Initialize the Unicode implementation */ |