Skip to content

Commit efdbad3

Browse files
authored
Merge branch 'main' into iterator_freelists
2 parents a3aed1c + e08b282 commit efdbad3

File tree

9 files changed

+112
-79
lines changed

9 files changed

+112
-79
lines changed

Doc/library/json.rst

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -258,64 +258,89 @@ Basic Usage
258258
the original one. That is, ``loads(dumps(x)) != x`` if x has non-string
259259
keys.
260260

261-
.. function:: load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
261+
.. function:: load(fp, *, cls=None, object_hook=None, parse_float=None, \
262+
parse_int=None, parse_constant=None, \
263+
object_pairs_hook=None, **kw)
262264
263-
Deserialize *fp* (a ``.read()``-supporting :term:`text file` or
264-
:term:`binary file` containing a JSON document) to a Python object using
265-
this :ref:`conversion table <json-to-py-table>`.
265+
Deserialize *fp* to a Python object
266+
using the :ref:`JSON-to-Python conversion table <json-to-py-table>`.
266267

267-
*object_hook* is an optional function that will be called with the result of
268-
any object literal decoded (a :class:`dict`). The return value of
269-
*object_hook* will be used instead of the :class:`dict`. This feature can
270-
be used to implement custom decoders (e.g. `JSON-RPC
271-
<https://www.jsonrpc.org>`_ class hinting).
268+
:param fp:
269+
A ``.read()``-supporting :term:`text file` or :term:`binary file`
270+
containing the JSON document to be deserialized.
271+
:type fp: :term:`file-like object`
272272

273-
*object_pairs_hook* is an optional function that will be called with the
274-
result of any object literal decoded with an ordered list of pairs. The
275-
return value of *object_pairs_hook* will be used instead of the
276-
:class:`dict`. This feature can be used to implement custom decoders. If
277-
*object_hook* is also defined, the *object_pairs_hook* takes priority.
273+
:param cls:
274+
If set, a custom JSON decoder.
275+
Additional keyword arguments to :func:`!load`
276+
will be passed to the constructor of *cls*.
277+
If ``None`` (the default), :class:`!JSONDecoder` is used.
278+
:type cls: a :class:`JSONDecoder` subclass
279+
280+
:param object_hook:
281+
If set, a function that is called with the result of
282+
any object literal decoded (a :class:`dict`).
283+
The return value of this function will be used
284+
instead of the :class:`dict`.
285+
This feature can be used to implement custom decoders,
286+
for example `JSON-RPC <https://www.jsonrpc.org>`_ class hinting.
287+
Default ``None``.
288+
:type object_hook: :term:`callable` | None
289+
290+
:param object_pairs_hook:
291+
If set, a function that is called with the result of
292+
any object literal decoded with an ordered list of pairs.
293+
The return value of this function will be used
294+
instead of the :class:`dict`.
295+
This feature can be used to implement custom decoders.
296+
If *object_hook* is also set, *object_pairs_hook* takes priority.
297+
Default ``None``.
298+
:type object_pairs_hook: :term:`callable` | None
299+
300+
:param parse_float:
301+
If set, a function that is called with
302+
the string of every JSON float to be decoded.
303+
If ``None`` (the default), it is equivalent to ``float(num_str)``.
304+
This can be used to parse JSON floats into custom datatypes,
305+
for example :class:`decimal.Decimal`.
306+
:type parse_float: :term:`callable` | None
307+
308+
:param parse_int:
309+
If set, a function that is called with
310+
the string of every JSON int to be decoded.
311+
If ``None`` (the default), it is equivalent to ``int(num_str)``.
312+
This can be used to parse JSON integers into custom datatypes,
313+
for example :class:`float`.
314+
:type parse_int: :term:`callable` | None
315+
316+
:param parse_constant:
317+
If set, a function that is called with one of the following strings:
318+
``'-Infinity'``, ``'Infinity'``, or ``'NaN'``.
319+
This can be used to raise an exception
320+
if invalid JSON numbers are encountered.
321+
Default ``None``.
322+
:type parse_constant: :term:`callable` | None
323+
324+
:raises JSONDecodeError:
325+
When the data being deserialized is not a valid JSON document.
278326

279327
.. versionchanged:: 3.1
280-
Added support for *object_pairs_hook*.
281328

282-
*parse_float* is an optional function that will be called with the string of
283-
every JSON float to be decoded. By default, this is equivalent to
284-
``float(num_str)``. This can be used to use another datatype or parser for
285-
JSON floats (e.g. :class:`decimal.Decimal`).
329+
* Added the optional *object_pairs_hook* parameter.
330+
* *parse_constant* doesn't get called on 'null', 'true', 'false' anymore.
286331

287-
*parse_int* is an optional function that will be called with the string of
288-
every JSON int to be decoded. By default, this is equivalent to
289-
``int(num_str)``. This can be used to use another datatype or parser for
290-
JSON integers (e.g. :class:`float`).
332+
.. versionchanged:: 3.6
333+
334+
* All optional parameters are now :ref:`keyword-only <keyword-only_parameter>`.
335+
* *fp* can now be a :term:`binary file`.
336+
The input encoding should be UTF-8, UTF-16 or UTF-32.
291337

292338
.. versionchanged:: 3.11
293339
The default *parse_int* of :func:`int` now limits the maximum length of
294340
the integer string via the interpreter's :ref:`integer string
295341
conversion length limitation <int_max_str_digits>` to help avoid denial
296342
of service attacks.
297343

298-
*parse_constant* is an optional function that will be called with one of the
299-
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be
300-
used to raise an exception if invalid JSON numbers are encountered.
301-
302-
.. versionchanged:: 3.1
303-
*parse_constant* doesn't get called on 'null', 'true', 'false' anymore.
304-
305-
To use a custom :class:`JSONDecoder` subclass, specify it with the ``cls``
306-
kwarg; otherwise :class:`JSONDecoder` is used. Additional keyword arguments
307-
will be passed to the constructor of the class.
308-
309-
If the data being deserialized is not a valid JSON document, a
310-
:exc:`JSONDecodeError` will be raised.
311-
312-
.. versionchanged:: 3.6
313-
All optional parameters are now :ref:`keyword-only <keyword-only_parameter>`.
314-
315-
.. versionchanged:: 3.6
316-
*fp* can now be a :term:`binary file`. The input encoding should be
317-
UTF-8, UTF-16 or UTF-32.
318-
319344
.. function:: loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
320345

321346
Deserialize *s* (a :class:`str`, :class:`bytes` or :class:`bytearray`

Lib/test/test_capi/test_file.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
_testcapi = import_helper.import_module('_testcapi')
77

8+
NULL = None
9+
810

911
class CAPIFileTest(unittest.TestCase):
1012
def test_py_fopen(self):
@@ -25,15 +27,22 @@ def test_py_fopen(self):
2527
os_helper.TESTFN,
2628
os.fsencode(os_helper.TESTFN),
2729
]
28-
# TESTFN_UNDECODABLE cannot be used to create a file on macOS/WASI.
30+
if os_helper.TESTFN_UNDECODABLE is not None:
31+
filenames.append(os_helper.TESTFN_UNDECODABLE)
32+
filenames.append(os.fsdecode(os_helper.TESTFN_UNDECODABLE))
2933
if os_helper.TESTFN_UNENCODABLE is not None:
3034
filenames.append(os_helper.TESTFN_UNENCODABLE)
3135
for filename in filenames:
3236
with self.subTest(filename=filename):
3337
try:
3438
with open(filename, "wb") as fp:
3539
fp.write(source)
36-
40+
except OSError:
41+
# TESTFN_UNDECODABLE cannot be used to create a file
42+
# on macOS/WASI.
43+
filename = None
44+
continue
45+
try:
3746
data = _testcapi.py_fopen(filename, "rb")
3847
self.assertEqual(data, source[:256])
3948
finally:
@@ -47,7 +56,14 @@ def test_py_fopen(self):
4756

4857
# non-ASCII mode failing with "Invalid argument"
4958
with self.assertRaises(OSError):
50-
_testcapi.py_fopen(__file__, "\xe9")
59+
_testcapi.py_fopen(__file__, b"\xc2\x80")
60+
with self.assertRaises(OSError):
61+
# \x98 is invalid in cp1250, cp1251, cp1257
62+
# \x9d is invalid in cp1252-cp1255, cp1258
63+
_testcapi.py_fopen(__file__, b"\xc2\x98\xc2\x9d")
64+
# UnicodeDecodeError can come from the audit hook code
65+
with self.assertRaises((UnicodeDecodeError, OSError)):
66+
_testcapi.py_fopen(__file__, b"\x98\x9d")
5167

5268
# invalid filename type
5369
for invalid_type in (123, object()):
@@ -60,7 +76,8 @@ def test_py_fopen(self):
6076
# On Windows, the file mode is limited to 10 characters
6177
_testcapi.py_fopen(__file__, "rt+, ccs=UTF-8")
6278

63-
# CRASHES py_fopen(__file__, None)
79+
# CRASHES _testcapi.py_fopen(NULL, 'rb')
80+
# CRASHES _testcapi.py_fopen(__file__, NULL)
6481

6582

6683
if __name__ == "__main__":

Modules/_testcapi/clinic/file.c.h

Lines changed: 7 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_testcapi/file.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ module _testcapi
1414
_testcapi.py_fopen
1515
1616
path: object
17-
mode: str
17+
mode: str(zeroes=True, accept={robuffer, str, NoneType})
1818
/
1919
2020
Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes.
2121
[clinic start generated code]*/
2222

2323
static PyObject *
24-
_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode)
25-
/*[clinic end generated code: output=5a900af000f759de input=d7e7b8f0fd151953]*/
24+
_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode,
25+
Py_ssize_t mode_length)
26+
/*[clinic end generated code: output=69840d0cfd8b7fbb input=f3a579dd7eb60926]*/
2627
{
28+
NULLABLE(path);
2729
FILE *fp = Py_fopen(path, mode);
2830
if (fp == NULL) {
2931
return NULL;

Modules/clinic/posixmodule.c.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3347,7 +3347,7 @@ os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd,
33473347
#endif
33483348

33493349

3350-
#ifdef HAVE_TTYNAME
3350+
#ifdef HAVE_TTYNAME_R
33513351
/*[clinic input]
33523352
os.ttyname
33533353

configure

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5152,7 +5152,7 @@ AC_CHECK_FUNCS([ \
51525152
sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \
51535153
sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \
51545154
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
5155-
tmpnam tmpnam_r truncate ttyname umask uname unlinkat unlockpt utimensat utimes vfork \
5155+
tmpnam tmpnam_r truncate ttyname_r umask uname unlinkat unlockpt utimensat utimes vfork \
51565156
wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \
51575157
])
51585158

pyconfig.h.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,8 +1506,8 @@
15061506
/* Define to 1 if you have the 'truncate' function. */
15071507
#undef HAVE_TRUNCATE
15081508

1509-
/* Define to 1 if you have the 'ttyname' function. */
1510-
#undef HAVE_TTYNAME
1509+
/* Define to 1 if you have the 'ttyname_r' function. */
1510+
#undef HAVE_TTYNAME_R
15111511

15121512
/* Define to 1 if you don't have 'tm_zone' but do have the external array
15131513
'tzname'. */

0 commit comments

Comments
 (0)