From 25bd72d6833765a5d37c10acc7ae7c7cb69c8ab4 Mon Sep 17 00:00:00 2001 From: Yoonho Hann Date: Thu, 30 Oct 2025 18:42:09 +0900 Subject: [PATCH] gh-137821: Convert _json module to use Argument Clinic (gh-140778) --- ...-10-30-15-33-07.gh-issue-137821.8_Iavt.rst | 1 + Modules/_json.c | 89 ++++++++++--------- Modules/clinic/_json.c.h | 84 +++++++++++++++++ 3 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-10-30-15-33-07.gh-issue-137821.8_Iavt.rst create mode 100644 Modules/clinic/_json.c.h diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-30-15-33-07.gh-issue-137821.8_Iavt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-30-15-33-07.gh-issue-137821.8_Iavt.rst new file mode 100644 index 000000000000..124ea3f99938 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-30-15-33-07.gh-issue-137821.8_Iavt.rst @@ -0,0 +1 @@ +Convert ``_json`` module to use Argument Clinic diff --git a/Modules/_json.c b/Modules/_json.c index 9a1fc3aba361..6a84661a243e 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -18,6 +18,12 @@ #include // bool +#include "clinic/_json.c.h" + +/*[clinic input] +module _json +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=549fa53592c925b2]*/ typedef struct _PyScannerObject { PyObject_HEAD @@ -637,30 +643,31 @@ bail: return NULL; } -PyDoc_STRVAR(pydoc_scanstring, - "scanstring(string, end, strict=True) -> (string, end)\n" - "\n" - "Scan the string s for a JSON string. End is the index of the\n" - "character in s after the quote that started the JSON string.\n" - "Unescapes all valid JSON string escape sequences and raises ValueError\n" - "on attempt to decode an invalid string. If strict is False then literal\n" - "control characters are allowed in the string.\n" - "\n" - "Returns a tuple of the decoded string and the index of the character in s\n" - "after the end quote." -); +/*[clinic input] +_json.scanstring as py_scanstring + pystr: object + end: Py_ssize_t + strict: bool = True + / + +Scan the string s for a JSON string. + +End is the index of the character in s after the quote that started the +JSON string. Unescapes all valid JSON string escape sequences and raises +ValueError on attempt to decode an invalid string. If strict is False +then literal control characters are allowed in the string. + +Returns a tuple of the decoded string and the index of the character in s +after the end quote. +[clinic start generated code]*/ static PyObject * -py_scanstring(PyObject* Py_UNUSED(self), PyObject *args) +py_scanstring_impl(PyObject *module, PyObject *pystr, Py_ssize_t end, + int strict) +/*[clinic end generated code: output=961740cfae07cdb3 input=9d46d7df7ac749b0]*/ { - PyObject *pystr; PyObject *rval; - Py_ssize_t end; Py_ssize_t next_end = -1; - int strict = 1; - if (!PyArg_ParseTuple(args, "On|p:scanstring", &pystr, &end, &strict)) { - return NULL; - } if (PyUnicode_Check(pystr)) { rval = scanstring_unicode(pystr, end, strict, &next_end); } @@ -673,14 +680,17 @@ py_scanstring(PyObject* Py_UNUSED(self), PyObject *args) return _build_rval_index_tuple(rval, next_end); } -PyDoc_STRVAR(pydoc_encode_basestring_ascii, - "encode_basestring_ascii(string) -> string\n" - "\n" - "Return an ASCII-only JSON representation of a Python string" -); +/*[clinic input] +_json.encode_basestring_ascii as py_encode_basestring_ascii + pystr: object + / + +Return an ASCII-only JSON representation of a Python string +[clinic start generated code]*/ static PyObject * -py_encode_basestring_ascii(PyObject* Py_UNUSED(self), PyObject *pystr) +py_encode_basestring_ascii(PyObject *module, PyObject *pystr) +/*[clinic end generated code: output=a8afcd88eba0b572 input=f4085ccd5928ea55]*/ { PyObject *rval; /* Return an ASCII-only JSON representation of a Python string */ @@ -697,15 +707,17 @@ py_encode_basestring_ascii(PyObject* Py_UNUSED(self), PyObject *pystr) return rval; } +/*[clinic input] +_json.encode_basestring as py_encode_basestring + pystr: object + / -PyDoc_STRVAR(pydoc_encode_basestring, - "encode_basestring(string) -> string\n" - "\n" - "Return a JSON representation of a Python string" -); +Return a JSON representation of a Python string +[clinic start generated code]*/ static PyObject * -py_encode_basestring(PyObject* Py_UNUSED(self), PyObject *pystr) +py_encode_basestring(PyObject *module, PyObject *pystr) +/*[clinic end generated code: output=c87752300776d3b1 input=c3c7ef6e72624f6e]*/ { PyObject *rval; /* Return a JSON representation of a Python string */ @@ -2080,18 +2092,9 @@ static PyType_Spec PyEncoderType_spec = { }; static PyMethodDef speedups_methods[] = { - {"encode_basestring_ascii", - py_encode_basestring_ascii, - METH_O, - pydoc_encode_basestring_ascii}, - {"encode_basestring", - py_encode_basestring, - METH_O, - pydoc_encode_basestring}, - {"scanstring", - py_scanstring, - METH_VARARGS, - pydoc_scanstring}, + PY_ENCODE_BASESTRING_ASCII_METHODDEF + PY_ENCODE_BASESTRING_METHODDEF + PY_SCANSTRING_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/clinic/_json.c.h b/Modules/clinic/_json.c.h new file mode 100644 index 000000000000..b80e72ad00a6 --- /dev/null +++ b/Modules/clinic/_json.c.h @@ -0,0 +1,84 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(py_scanstring__doc__, +"scanstring($module, pystr, end, strict=True, /)\n" +"--\n" +"\n" +"Scan the string s for a JSON string.\n" +"\n" +"End is the index of the character in s after the quote that started the\n" +"JSON string. Unescapes all valid JSON string escape sequences and raises\n" +"ValueError on attempt to decode an invalid string. If strict is False\n" +"then literal control characters are allowed in the string.\n" +"\n" +"Returns a tuple of the decoded string and the index of the character in s\n" +"after the end quote."); + +#define PY_SCANSTRING_METHODDEF \ + {"scanstring", _PyCFunction_CAST(py_scanstring), METH_FASTCALL, py_scanstring__doc__}, + +static PyObject * +py_scanstring_impl(PyObject *module, PyObject *pystr, Py_ssize_t end, + int strict); + +static PyObject * +py_scanstring(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *pystr; + Py_ssize_t end; + int strict = 1; + + if (!_PyArg_CheckPositional("scanstring", nargs, 2, 3)) { + goto exit; + } + pystr = args[0]; + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + end = ival; + } + if (nargs < 3) { + goto skip_optional; + } + strict = PyObject_IsTrue(args[2]); + if (strict < 0) { + goto exit; + } +skip_optional: + return_value = py_scanstring_impl(module, pystr, end, strict); + +exit: + return return_value; +} + +PyDoc_STRVAR(py_encode_basestring_ascii__doc__, +"encode_basestring_ascii($module, pystr, /)\n" +"--\n" +"\n" +"Return an ASCII-only JSON representation of a Python string"); + +#define PY_ENCODE_BASESTRING_ASCII_METHODDEF \ + {"encode_basestring_ascii", (PyCFunction)py_encode_basestring_ascii, METH_O, py_encode_basestring_ascii__doc__}, + +PyDoc_STRVAR(py_encode_basestring__doc__, +"encode_basestring($module, pystr, /)\n" +"--\n" +"\n" +"Return a JSON representation of a Python string"); + +#define PY_ENCODE_BASESTRING_METHODDEF \ + {"encode_basestring", (PyCFunction)py_encode_basestring, METH_O, py_encode_basestring__doc__}, +/*[clinic end generated code: output=d3aa505efc0acb3f input=a9049054013a1b77]*/ -- 2.47.3