Skip to content

Commit 2603d50

Browse files
authored
Merge branch 'main' into rlock-threading-locked-failed
2 parents 512ff69 + e1f8914 commit 2603d50

File tree

4 files changed

+98
-114
lines changed

4 files changed

+98
-114
lines changed

Doc/library/io.rst

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -528,14 +528,13 @@ I/O Base Classes
528528
It inherits from :class:`IOBase`.
529529

530530
The main difference with :class:`RawIOBase` is that methods :meth:`read`,
531-
:meth:`readinto` and :meth:`write` will try (respectively) to read as much
532-
input as requested or to consume all given output, at the expense of
533-
making perhaps more than one system call.
531+
:meth:`readinto` and :meth:`write` will try (respectively) to read
532+
as much input as requested or to emit all provided data.
534533

535-
In addition, those methods can raise :exc:`BlockingIOError` if the
536-
underlying raw stream is in non-blocking mode and cannot take or give
537-
enough data; unlike their :class:`RawIOBase` counterparts, they will
538-
never return ``None``.
534+
In addition, if the underlying raw stream is in non-blocking mode, when the
535+
system returns would block :meth:`write` will raise :exc:`BlockingIOError`
536+
with :attr:`BlockingIOError.characters_written` and :meth:`read` will return
537+
data read so far or ``None`` if no data is available.
539538

540539
Besides, the :meth:`read` method does not have a default
541540
implementation that defers to :meth:`readinto`.
@@ -568,29 +567,40 @@ I/O Base Classes
568567

569568
.. method:: read(size=-1, /)
570569

571-
Read and return up to *size* bytes. If the argument is omitted, ``None``,
572-
or negative, data is read and returned until EOF is reached. An empty
573-
:class:`bytes` object is returned if the stream is already at EOF.
570+
Read and return up to *size* bytes. If the argument is omitted, ``None``,
571+
or negative read as much as possible.
574572

575-
If the argument is positive, and the underlying raw stream is not
576-
interactive, multiple raw reads may be issued to satisfy the byte count
577-
(unless EOF is reached first). But for interactive raw streams, at most
578-
one raw read will be issued, and a short result does not imply that EOF is
579-
imminent.
573+
Fewer bytes may be returned than requested. An empty :class:`bytes` object
574+
is returned if the stream is already at EOF. More than one read may be
575+
made and calls may be retried if specific errors are encountered, see
576+
:meth:`os.read` and :pep:`475` for more details. Less than size bytes
577+
being returned does not imply that EOF is imminent.
580578

581-
A :exc:`BlockingIOError` is raised if the underlying raw stream is in
582-
non blocking-mode, and has no data available at the moment.
579+
When reading as much as possible the default implementation will use
580+
``raw.readall`` if available (which should implement
581+
:meth:`RawIOBase.readall`), otherwise will read in a loop until read
582+
returns ``None``, an empty :class:`bytes`, or a non-retryable error. For
583+
most streams this is to EOF, but for non-blocking streams more data may
584+
become available.
585+
586+
.. note::
587+
588+
When the underlying raw stream is non-blocking, implementations may
589+
either raise :exc:`BlockingIOError` or return ``None`` if no data is
590+
available. :mod:`io` implementations return ``None``.
583591

584592
.. method:: read1(size=-1, /)
585593

586-
Read and return up to *size* bytes, with at most one call to the
587-
underlying raw stream's :meth:`~RawIOBase.read` (or
588-
:meth:`~RawIOBase.readinto`) method. This can be useful if you are
589-
implementing your own buffering on top of a :class:`BufferedIOBase`
590-
object.
594+
Read and return up to *size* bytes, calling :meth:`~RawIOBase.readinto`
595+
which may retry if :py:const:`~errno.EINTR` is encountered per
596+
:pep:`475`. If *size* is ``-1`` or not provided, the implementation will
597+
choose an arbitrary value for *size*.
591598

592-
If *size* is ``-1`` (the default), an arbitrary number of bytes are
593-
returned (more than zero unless EOF is reached).
599+
.. note::
600+
601+
When the underlying raw stream is non-blocking, implementations may
602+
either raise :exc:`BlockingIOError` or return ``None`` if no data is
603+
available. :mod:`io` implementations return ``None``.
594604

595605
.. method:: readinto(b, /)
596606

@@ -767,34 +777,21 @@ than raw I/O does.
767777

768778
.. method:: peek(size=0, /)
769779

770-
Return bytes from the stream without advancing the position. At most one
771-
single read on the raw stream is done to satisfy the call. The number of
772-
bytes returned may be less or more than requested.
780+
Return bytes from the stream without advancing the position. The number of
781+
bytes returned may be less or more than requested. If the underlying raw
782+
stream is non-blocking and the operation would block, returns empty bytes.
773783

774784
.. method:: read(size=-1, /)
775785

776-
Read and return *size* bytes, or if *size* is not given or negative, until
777-
EOF or if the read call would block in non-blocking mode.
778-
779-
.. note::
780-
781-
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
782-
may be raised if a read operation cannot be completed immediately.
786+
In :class:`BufferedReader` this is the same as :meth:`io.BufferedIOBase.read`
783787

784788
.. method:: read1(size=-1, /)
785789

786-
Read and return up to *size* bytes with only one call on the raw stream.
787-
If at least one byte is buffered, only buffered bytes are returned.
788-
Otherwise, one raw stream read call is made.
790+
In :class:`BufferedReader` this is the same as :meth:`io.BufferedIOBase.read1`
789791

790792
.. versionchanged:: 3.7
791793
The *size* argument is now optional.
792794

793-
.. note::
794-
795-
When the underlying raw stream is non-blocking, a :exc:`BlockingIOError`
796-
may be raised if a read operation cannot be completed immediately.
797-
798795
.. class:: BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)
799796

800797
A buffered binary stream providing higher-level access to a writeable, non
@@ -826,8 +823,8 @@ than raw I/O does.
826823

827824
Write the :term:`bytes-like object`, *b*, and return the
828825
number of bytes written. When in non-blocking mode, a
829-
:exc:`BlockingIOError` is raised if the buffer needs to be written out but
830-
the raw stream blocks.
826+
:exc:`BlockingIOError` with :attr:`BlockingIOError.characters_written` set
827+
is raised if the buffer needs to be written out but the raw stream blocks.
831828

832829

833830
.. class:: BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)

Lib/_pyio.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,6 @@ def write(self, b):
648648
self._unsupported("write")
649649

650650
io.RawIOBase.register(RawIOBase)
651-
from _io import FileIO
652-
RawIOBase.register(FileIO)
653651

654652

655653
class BufferedIOBase(IOBase):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove import of C implementation of :class:`io.FileIO` from Python
2+
implementation which has its own implementation

Modules/_zstd/_zstdmodule.c

Lines changed: 55 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,49 @@ get_zstd_state(PyObject *module)
172172
return (_zstd_state *)state;
173173
}
174174

175+
static Py_ssize_t
176+
calculate_samples_stats(PyBytesObject *samples_bytes, PyObject *samples_sizes,
177+
size_t **chunk_sizes)
178+
{
179+
Py_ssize_t chunks_number;
180+
Py_ssize_t sizes_sum;
181+
Py_ssize_t i;
182+
183+
chunks_number = Py_SIZE(samples_sizes);
184+
if ((size_t) chunks_number > UINT32_MAX) {
185+
PyErr_Format(PyExc_ValueError,
186+
"The number of samples should be <= %u.", UINT32_MAX);
187+
return -1;
188+
}
189+
190+
/* Prepare chunk_sizes */
191+
*chunk_sizes = PyMem_New(size_t, chunks_number);
192+
if (*chunk_sizes == NULL) {
193+
PyErr_NoMemory();
194+
return -1;
195+
}
196+
197+
sizes_sum = 0;
198+
for (i = 0; i < chunks_number; i++) {
199+
PyObject *size = PyTuple_GetItem(samples_sizes, i);
200+
(*chunk_sizes)[i] = PyLong_AsSize_t(size);
201+
if ((*chunk_sizes)[i] == (size_t)-1 && PyErr_Occurred()) {
202+
PyErr_Format(PyExc_ValueError,
203+
"Items in samples_sizes should be an int "
204+
"object, with a value between 0 and %u.", SIZE_MAX);
205+
return -1;
206+
}
207+
sizes_sum += (*chunk_sizes)[i];
208+
}
209+
210+
if (sizes_sum != Py_SIZE(samples_bytes)) {
211+
PyErr_SetString(PyExc_ValueError,
212+
"The samples size tuple doesn't match the concatenation's size.");
213+
return -1;
214+
}
215+
return chunks_number;
216+
}
217+
175218

176219
/*[clinic input]
177220
_zstd.train_dict
@@ -192,54 +235,25 @@ _zstd_train_dict_impl(PyObject *module, PyBytesObject *samples_bytes,
192235
PyObject *samples_sizes, Py_ssize_t dict_size)
193236
/*[clinic end generated code: output=8e87fe43935e8f77 input=d20dedb21c72cb62]*/
194237
{
195-
// TODO(emmatyping): The preamble and suffix to this function and _finalize_dict
196-
// are pretty similar. We should see if we can refactor them to share that code.
197-
Py_ssize_t chunks_number;
198-
size_t *chunk_sizes = NULL;
199238
PyObject *dst_dict_bytes = NULL;
239+
size_t *chunk_sizes = NULL;
240+
Py_ssize_t chunks_number;
200241
size_t zstd_ret;
201-
Py_ssize_t sizes_sum;
202-
Py_ssize_t i;
203242

204243
/* Check arguments */
205244
if (dict_size <= 0) {
206245
PyErr_SetString(PyExc_ValueError, "dict_size argument should be positive number.");
207246
return NULL;
208247
}
209248

210-
chunks_number = Py_SIZE(samples_sizes);
211-
if ((size_t) chunks_number > UINT32_MAX) {
212-
PyErr_Format(PyExc_ValueError,
213-
"The number of samples should be <= %u.", UINT32_MAX);
249+
/* Check that the samples are valid and get their sizes */
250+
chunks_number = calculate_samples_stats(samples_bytes, samples_sizes,
251+
&chunk_sizes);
252+
if (chunks_number < 0)
253+
{
214254
return NULL;
215255
}
216256

217-
/* Prepare chunk_sizes */
218-
chunk_sizes = PyMem_New(size_t, chunks_number);
219-
if (chunk_sizes == NULL) {
220-
PyErr_NoMemory();
221-
goto error;
222-
}
223-
224-
sizes_sum = 0;
225-
for (i = 0; i < chunks_number; i++) {
226-
PyObject *size = PyTuple_GetItem(samples_sizes, i);
227-
chunk_sizes[i] = PyLong_AsSize_t(size);
228-
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
229-
PyErr_Format(PyExc_ValueError,
230-
"Items in samples_sizes should be an int "
231-
"object, with a value between 0 and %u.", SIZE_MAX);
232-
goto error;
233-
}
234-
sizes_sum += chunk_sizes[i];
235-
}
236-
237-
if (sizes_sum != Py_SIZE(samples_bytes)) {
238-
PyErr_SetString(PyExc_ValueError,
239-
"The samples size tuple doesn't match the concatenation's size.");
240-
goto error;
241-
}
242-
243257
/* Allocate dict buffer */
244258
dst_dict_bytes = PyBytes_FromStringAndSize(NULL, dict_size);
245259
if (dst_dict_bytes == NULL) {
@@ -307,48 +321,21 @@ _zstd_finalize_dict_impl(PyObject *module, PyBytesObject *custom_dict_bytes,
307321
PyObject *dst_dict_bytes = NULL;
308322
size_t zstd_ret;
309323
ZDICT_params_t params;
310-
Py_ssize_t sizes_sum;
311-
Py_ssize_t i;
312324

313325
/* Check arguments */
314326
if (dict_size <= 0) {
315327
PyErr_SetString(PyExc_ValueError, "dict_size argument should be positive number.");
316328
return NULL;
317329
}
318330

319-
chunks_number = Py_SIZE(samples_sizes);
320-
if ((size_t) chunks_number > UINT32_MAX) {
321-
PyErr_Format(PyExc_ValueError,
322-
"The number of samples should be <= %u.", UINT32_MAX);
331+
/* Check that the samples are valid and get their sizes */
332+
chunks_number = calculate_samples_stats(samples_bytes, samples_sizes,
333+
&chunk_sizes);
334+
if (chunks_number < 0)
335+
{
323336
return NULL;
324337
}
325338

326-
/* Prepare chunk_sizes */
327-
chunk_sizes = PyMem_New(size_t, chunks_number);
328-
if (chunk_sizes == NULL) {
329-
PyErr_NoMemory();
330-
goto error;
331-
}
332-
333-
sizes_sum = 0;
334-
for (i = 0; i < chunks_number; i++) {
335-
PyObject *size = PyTuple_GetItem(samples_sizes, i);
336-
chunk_sizes[i] = PyLong_AsSize_t(size);
337-
if (chunk_sizes[i] == (size_t)-1 && PyErr_Occurred()) {
338-
PyErr_Format(PyExc_ValueError,
339-
"Items in samples_sizes should be an int "
340-
"object, with a value between 0 and %u.", SIZE_MAX);
341-
goto error;
342-
}
343-
sizes_sum += chunk_sizes[i];
344-
}
345-
346-
if (sizes_sum != Py_SIZE(samples_bytes)) {
347-
PyErr_SetString(PyExc_ValueError,
348-
"The samples size tuple doesn't match the concatenation's size.");
349-
goto error;
350-
}
351-
352339
/* Allocate dict buffer */
353340
dst_dict_bytes = PyBytes_FromStringAndSize(NULL, dict_size);
354341
if (dst_dict_bytes == NULL) {

0 commit comments

Comments
 (0)