omlish 0.0.0.dev103__py3-none-any.whl → 0.0.0.dev104__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
omlish/io/pyio.py ADDED
@@ -0,0 +1,2757 @@
1
+ # type: ignore
2
+ # ruff: noqa
3
+ # flake8: ignore
4
+ """
5
+ Python implementation of the io module.
6
+
7
+ https://github.com/python/cpython/blob/8fa4dc4ba8646c59f945f2451c53e2919f066065/Lib/_pyio.py
8
+ """
9
+ # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
10
+ # --------------------------------------------
11
+ #
12
+ # 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization
13
+ # ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated
14
+ # documentation.
15
+ #
16
+ # 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive,
17
+ # royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative
18
+ # works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License
19
+ # Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001-2024 Python Software Foundation; All Rights
20
+ # Reserved" are retained in Python alone or in any derivative version prepared by Licensee.
21
+ #
22
+ # 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and
23
+ # wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in
24
+ # any such work a brief summary of the changes made to Python.
25
+ #
26
+ # 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES,
27
+ # EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY
28
+ # OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY
29
+ # RIGHTS.
30
+ #
31
+ # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
32
+ # DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF
33
+ # ADVISED OF THE POSSIBILITY THEREOF.
34
+ #
35
+ # 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
36
+ #
37
+ # 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint
38
+ # venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade
39
+ # name in a trademark sense to endorse or promote products or services of Licensee, or any third party.
40
+ #
41
+ # 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this
42
+ # License Agreement.
43
+ import abc
44
+ import codecs
45
+ import errno
46
+ import io
47
+ import locale
48
+ import os
49
+ import stat
50
+ import sys
51
+ import threading
52
+ import warnings
53
+
54
+
55
+ valid_seek_flags = {0, 1, 2} # Hardwired values
56
+ if hasattr(os, 'SEEK_HOLE'):
57
+ valid_seek_flags.add(os.SEEK_HOLE)
58
+ valid_seek_flags.add(os.SEEK_DATA)
59
+
60
+ # open() uses st_blksize whenever we can
61
+ DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes
62
+
63
+ # NOTE: Base classes defined here are registered with the "official" ABCs defined in io.py. We don't use real
64
+ # inheritance though, because we don't want to inherit the C implementations.
65
+
66
+ # Does open() check its 'errors' argument?
67
+ _CHECK_ERRORS = hasattr(sys, 'gettotalrefcount') or sys.flags.dev_mode
68
+
69
+
70
+ def text_encoding(encoding, stacklevel=2):
71
+ """
72
+ A helper function to choose the text encoding.
73
+
74
+ When encoding is not None, this function returns it. Otherwise, this function returns the default text encoding
75
+ (i.e. "locale" or "utf-8" depends on UTF-8 mode).
76
+
77
+ This function emits an EncodingWarning if *encoding* is None and sys.flags.warn_default_encoding is true.
78
+
79
+ This can be used in APIs with an encoding=None parameter that pass it to TextIOWrapper or open. However, please
80
+ consider using encoding="utf-8" for new APIs.
81
+ """
82
+
83
+ if encoding is None:
84
+ if sys.flags.utf8_mode:
85
+ encoding = 'utf-8'
86
+ else:
87
+ encoding = 'locale'
88
+
89
+ if sys.flags.warn_default_encoding:
90
+ warnings.warn("'encoding' argument not specified.", EncodingWarning, stacklevel + 1)
91
+
92
+ return encoding
93
+
94
+
95
+ # Wrapper for builtins.open
96
+ #
97
+ # Trick so that open() won't become a bound method when stored as a class variable (as dbm.dumb does).
98
+ #
99
+ # See init_set_builtins_open() in Python/pylifecycle.c.
100
+ def open(
101
+ file,
102
+ mode='r',
103
+ buffering=-1,
104
+ encoding=None,
105
+ errors=None,
106
+ newline=None,
107
+ closefd=True,
108
+ opener=None,
109
+ ):
110
+ r"""
111
+ Open file and return a stream. Raise OSError upon failure.
112
+
113
+ file is either a text or byte string giving the name (and the path if the file isn't in the current working
114
+ directory) of the file to be opened or an integer file descriptor of the file to be wrapped. (If a file descriptor
115
+ is given, it is closed when the returned I/O object is closed, unless closefd is set to False.)
116
+
117
+ mode is an optional string that specifies the mode in which the file is opened. It defaults to 'r' which means open
118
+ for reading in text mode. Other common values are 'w' for writing (truncating the file if it already exists), 'x'
119
+ for exclusive creation of a new file, and 'a' for appending (which on some Unix systems, means that all writes
120
+ append to the end of the file regardless of the current seek position). In text mode, if encoding is not specified
121
+ the encoding used is platform dependent. (For reading and writing raw bytes use binary mode and leave encoding
122
+ unspecified.) The available modes are:
123
+
124
+ ========= ===============================================================
125
+ Character Meaning
126
+ --------- ---------------------------------------------------------------
127
+ 'r' open for reading (default)
128
+ 'w' open for writing, truncating the file first
129
+ 'x' create a new file and open it for writing
130
+ 'a' open for writing, appending to the end of the file if it exists
131
+ 'b' binary mode
132
+ 't' text mode (default)
133
+ '+' open a disk file for updating (reading and writing)
134
+ ========= ===============================================================
135
+
136
+ The default mode is 'rt' (open for reading text). For binary random access, the mode 'w+b' opens and truncates the
137
+ file to 0 bytes, while 'r+b' opens the file without truncation. The 'x' mode implies 'w' and raises an
138
+ `FileExistsError` if the file already exists.
139
+
140
+ Python distinguishes between files opened in binary and text modes, even when the underlying operating system
141
+ doesn't. Files opened in binary mode (appending 'b' to the mode argument) return contents as bytes objects without
142
+ any decoding. In text mode (the default, or when 't' is appended to the mode argument), the contents of the file are
143
+ returned as strings, the bytes having been first decoded using a platform-dependent encoding or using the specified
144
+ encoding if given.
145
+
146
+ buffering is an optional integer used to set the buffering policy. Pass 0 to switch buffering off (only allowed in
147
+ binary mode), 1 to select line buffering (only usable in text mode), and an integer > 1 to indicate the size of a
148
+ fixed-size chunk buffer. When no buffering argument is given, the default buffering policy works as follows:
149
+
150
+ * Binary files are buffered in fixed-size chunks; the size of the buffer is chosen using a heuristic trying to
151
+ determine the underlying device's "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`. On many systems, the
152
+ buffer will typically be 4096 or 8192 bytes long.
153
+
154
+ * "Interactive" text files (files for which isatty() returns True) use line buffering. Other text files use the
155
+ policy described above for binary files.
156
+
157
+ encoding is the str name of the encoding used to decode or encode the file. This should only be used in text mode.
158
+ The default encoding is platform dependent, but any encoding supported by Python can be passed. See the codecs
159
+ module for the list of supported encodings.
160
+
161
+ errors is an optional string that specifies how encoding errors are to be handled---this argument should not be used
162
+ in binary mode. Pass 'strict' to raise a ValueError exception if there is an encoding error (the default of None has
163
+ the same effect), or pass 'ignore' to ignore errors. (Note that ignoring encoding errors can lead to data loss.) See
164
+ the documentation for codecs.register for a list of the permitted encoding error strings.
165
+
166
+ newline is a string controlling how universal newlines works (it only applies to text mode). It can be None, '',
167
+ '\n', '\r', and '\r\n'. It works as follows:
168
+
169
+ * On input, if newline is None, universal newlines mode is enabled. Lines in the input can end in '\n', '\r', or
170
+ '\r\n', and these are translated into '\n' before being returned to the caller. If it is '', universal newline
171
+ mode is enabled, but line endings are returned to the caller untranslated. If it has any of the other legal
172
+ values, input lines are only terminated by the given string, and the line ending is returned to the caller
173
+ untranslated.
174
+
175
+ * On output, if newline is None, any '\n' characters written are translated to the system default line separator,
176
+ os.linesep. If newline is '', no translation takes place. If newline is any of the other legal values, any '\n'
177
+ characters written are translated to the given string.
178
+
179
+ closedfd is a bool. If closefd is False, the underlying file descriptor will be kept open when the file is closed.
180
+ This does not work when a file name is given and must be True in that case.
181
+
182
+ The newly created file is non-inheritable.
183
+
184
+ A custom opener can be used by passing a callable as *opener*. The underlying file descriptor for the file object is
185
+ then obtained by calling *opener* with (*file*, *flags*). *opener* must return an open file descriptor (passing
186
+ os.open as *opener* results in functionality similar to passing None).
187
+
188
+ open() returns a file object whose type depends on the mode, and through which the standard file operations such as
189
+ reading and writing are performed. When open() is used to open a file in a text mode ('w', 'r', 'wt', 'rt', etc.),
190
+ it returns a TextIOWrapper. When used to open a file in a binary mode, the returned class varies: in read binary
191
+ mode, it returns a BufferedReader; in write binary and append binary modes, it returns a BufferedWriter, and in
192
+ read/write mode, it returns a BufferedRandom.
193
+
194
+ It is also possible to use a string or bytearray as a file for both reading and writing. For strings StringIO can be
195
+ used like a file opened in a text mode, and for bytes a BytesIO can be used like a file opened in a binary mode.
196
+ """
197
+
198
+ if not isinstance(file, int):
199
+ file = os.fspath(file)
200
+ if not isinstance(file, (str, bytes, int)):
201
+ raise TypeError('invalid file: %r' % file)
202
+ if not isinstance(mode, str):
203
+ raise TypeError('invalid mode: %r' % mode)
204
+ if not isinstance(buffering, int):
205
+ raise TypeError('invalid buffering: %r' % buffering)
206
+ if encoding is not None and not isinstance(encoding, str):
207
+ raise TypeError('invalid encoding: %r' % encoding)
208
+ if errors is not None and not isinstance(errors, str):
209
+ raise TypeError('invalid errors: %r' % errors)
210
+
211
+ modes = set(mode)
212
+ if modes - set('axrwb+t') or len(mode) > len(modes):
213
+ raise ValueError('invalid mode: %r' % mode)
214
+ creating = 'x' in modes
215
+ reading = 'r' in modes
216
+ writing = 'w' in modes
217
+ appending = 'a' in modes
218
+ updating = '+' in modes
219
+ text = 't' in modes
220
+ binary = 'b' in modes
221
+ if text and binary:
222
+ raise ValueError("can't have text and binary mode at once")
223
+ if creating + reading + writing + appending > 1:
224
+ raise ValueError("can't have read/write/append mode at once")
225
+ if not (creating or reading or writing or appending):
226
+ raise ValueError('must have exactly one of read/write/append mode')
227
+ if binary and encoding is not None:
228
+ raise ValueError("binary mode doesn't take an encoding argument")
229
+ if binary and errors is not None:
230
+ raise ValueError("binary mode doesn't take an errors argument")
231
+ if binary and newline is not None:
232
+ raise ValueError("binary mode doesn't take a newline argument")
233
+ if binary and buffering == 1:
234
+ warnings.warn(
235
+ "line buffering (buffering=1) isn't supported in binary "
236
+ "mode, the default buffer size will be used",
237
+ RuntimeWarning,
238
+ 2,
239
+ )
240
+
241
+ raw = FileIO(
242
+ file,
243
+ (creating and 'x' or '')
244
+ + (reading and 'r' or '')
245
+ + (writing and 'w' or '')
246
+ + (appending and 'a' or '')
247
+ + (updating and '+' or ''),
248
+ closefd,
249
+ opener=opener,
250
+ )
251
+
252
+ result = raw
253
+ try:
254
+ line_buffering = False
255
+ if buffering == 1 or buffering < 0 and raw._isatty_open_only():
256
+ buffering = -1
257
+ line_buffering = True
258
+ if buffering < 0:
259
+ buffering = raw._blksize
260
+ if buffering < 0:
261
+ raise ValueError('invalid buffering size')
262
+ if buffering == 0:
263
+ if binary:
264
+ return result
265
+ raise ValueError("can't have unbuffered text I/O")
266
+
267
+ if updating:
268
+ buffer = BufferedRandom(raw, buffering)
269
+ elif creating or writing or appending:
270
+ buffer = BufferedWriter(raw, buffering)
271
+ elif reading:
272
+ buffer = BufferedReader(raw, buffering)
273
+ else:
274
+ raise ValueError('unknown mode: %r' % mode)
275
+
276
+ result = buffer
277
+ if binary:
278
+ return result
279
+
280
+ encoding = text_encoding(encoding)
281
+ text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering)
282
+ result = text
283
+ text.mode = mode
284
+ return result
285
+
286
+ except: # noqa
287
+ result.close()
288
+ raise
289
+
290
+
291
+ # Define a default pure-Python implementation for open_code() that does not allow hooks. Warn on first use. Defined for
292
+ # tests.
293
+ def _open_code_with_warning(path):
294
+ """
295
+ Opens the provided file with mode ``'rb'``. This function should be used when the intent is to treat the contents as
296
+ executable code.
297
+
298
+ ``path`` should be an absolute path.
299
+
300
+ When supported by the runtime, this function can be hooked in order to allow embedders more control over code files.
301
+ This functionality is not supported on the current runtime.
302
+ """
303
+
304
+ warnings.warn('_pyio.open_code() may not be using hooks', RuntimeWarning, 2)
305
+ return open(path, 'rb')
306
+
307
+
308
+ try:
309
+ open_code = io.open_code
310
+ except AttributeError:
311
+ open_code = _open_code_with_warning
312
+
313
+
314
+ # In normal operation, both `UnsupportedOperation`s should be bound to the same object.
315
+ UnsupportedOperation = io.UnsupportedOperation
316
+
317
+
318
+ @io.IOBase.register
319
+ class IOBase(metaclass=abc.ABCMeta):
320
+ """
321
+ The abstract base class for all I/O classes.
322
+
323
+ This class provides dummy implementations for many methods that derived classes can override selectively; the
324
+ default implementations represent a file that cannot be read, written or seeked.
325
+
326
+ Even though IOBase does not declare read or write because their signatures will vary, implementations and clients
327
+ should consider those methods part of the interface. Also, implementations may raise UnsupportedOperation when
328
+ operations they do not support are called.
329
+
330
+ The basic type used for binary data read from or written to a file is bytes. Other bytes-like objects are accepted
331
+ as method arguments too. Text I/O classes work with str data.
332
+
333
+ Note that calling any method (even inquiries) on a closed stream is undefined. Implementations may raise OSError in
334
+ this case.
335
+
336
+ IOBase (and its subclasses) support the iterator protocol, meaning that an IOBase object can be iterated over
337
+ yielding the lines in a stream.
338
+
339
+ IOBase also supports the :keyword:`with` statement. In this example, fp is closed after the suite of the with
340
+ statement is complete:
341
+
342
+ with open('spam.txt', 'r') as fp:
343
+ fp.write('Spam and eggs!')
344
+ """
345
+
346
+ # Internal
347
+
348
+ def _unsupported(self, name):
349
+ """Internal: raise an OSError exception for unsupported operations."""
350
+
351
+ raise UnsupportedOperation('%s.%s() not supported' % (self.__class__.__name__, name))
352
+
353
+ # Positioning
354
+
355
+ def seek(self, pos, whence=0):
356
+ """
357
+ Change stream position.
358
+
359
+ Change the stream position to byte offset pos. Argument pos is interpreted relative to the position indicated by
360
+ whence. Values for whence are ints:
361
+
362
+ * 0 -- start of stream (the default); offset should be zero or positive
363
+ * 1 -- current stream position; offset may be negative
364
+ * 2 -- end of stream; offset is usually negative
365
+ Some operating systems / file systems could provide additional values.
366
+
367
+ Return an int indicating the new absolute position.
368
+ """
369
+
370
+ self._unsupported('seek')
371
+
372
+ def tell(self):
373
+ """Return an int indicating the current stream position."""
374
+
375
+ return self.seek(0, 1)
376
+
377
+ def truncate(self, pos=None):
378
+ """
379
+ Truncate file to size bytes.
380
+
381
+ Size defaults to the current IO position as reported by tell(). Return the new size.
382
+ """
383
+
384
+ self._unsupported('truncate')
385
+
386
+ # Flush and close
387
+
388
+ def flush(self):
389
+ """
390
+ Flush write buffers, if applicable.
391
+
392
+ This is not implemented for read-only and non-blocking streams.
393
+ """
394
+
395
+ self._checkClosed()
396
+ # XXX Should this return the number of bytes written???
397
+
398
+ __closed = False
399
+
400
+ def close(self):
401
+ """
402
+ Flush and close the IO object.
403
+
404
+ This method has no effect if the file is already closed.
405
+ """
406
+
407
+ if not self.__closed:
408
+ try:
409
+ self.flush()
410
+ finally:
411
+ self.__closed = True
412
+
413
+ def __del__(self):
414
+ """Destructor. Calls close()."""
415
+
416
+ try:
417
+ closed = self.closed
418
+ except AttributeError:
419
+ # If getting closed fails, then the object is probably in an unusable state, so ignore.
420
+ return
421
+
422
+ if closed:
423
+ return
424
+
425
+ # If close() fails, the caller logs the exception with sys.unraisablehook. close() must be called at the end at
426
+ # __del__().
427
+ self.close()
428
+
429
+ # Inquiries
430
+
431
+ def seekable(self):
432
+ """
433
+ Return a bool indicating whether object supports random access.
434
+
435
+ If False, seek(), tell() and truncate() will raise OSError.
436
+ This method may need to do a test seek().
437
+ """
438
+
439
+ return False
440
+
441
+ def _checkSeekable(self, msg=None):
442
+ """Internal: raise UnsupportedOperation if file is not seekable"""
443
+
444
+ if not self.seekable():
445
+ raise UnsupportedOperation('File or stream is not seekable.' if msg is None else msg)
446
+
447
+ def readable(self):
448
+ """
449
+ Return a bool indicating whether object was opened for reading.
450
+
451
+ If False, read() will raise OSError.
452
+ """
453
+
454
+ return False
455
+
456
+ def _checkReadable(self, msg=None):
457
+ """Internal: raise UnsupportedOperation if file is not readable"""
458
+
459
+ if not self.readable():
460
+ raise UnsupportedOperation('File or stream is not readable.' if msg is None else msg)
461
+
462
+ def writable(self):
463
+ """
464
+ Return a bool indicating whether object was opened for writing.
465
+
466
+ If False, write() and truncate() will raise OSError.
467
+ """
468
+
469
+ return False
470
+
471
+ def _checkWritable(self, msg=None):
472
+ """Internal: raise UnsupportedOperation if file is not writable"""
473
+
474
+ if not self.writable():
475
+ raise UnsupportedOperation('File or stream is not writable.' if msg is None else msg)
476
+
477
+ @property
478
+ def closed(self):
479
+ """
480
+ closed: bool. True iff the file has been closed.
481
+
482
+ For backwards compatibility, this is a property, not a predicate.
483
+ """
484
+
485
+ return self.__closed
486
+
487
+ def _checkClosed(self, msg=None):
488
+ """Internal: raise a ValueError if file is closed"""
489
+
490
+ if self.closed:
491
+ raise ValueError('I/O operation on closed file.' if msg is None else msg)
492
+
493
+ # Context manager
494
+
495
+ def __enter__(self): # That's a forward reference
496
+ """Context management protocol. Returns self (an instance of IOBase)."""
497
+
498
+ self._checkClosed()
499
+ return self
500
+
501
+ def __exit__(self, *args):
502
+ """Context management protocol. Calls close()"""
503
+
504
+ self.close()
505
+
506
+ # Lower-level APIs
507
+
508
+ # XXX Should these be present even if unimplemented?
509
+
510
+ def fileno(self):
511
+ """
512
+ Returns underlying file descriptor (an int) if one exists.
513
+
514
+ An OSError is raised if the IO object does not use a file descriptor.
515
+ """
516
+
517
+ self._unsupported('fileno')
518
+
519
+ def isatty(self):
520
+ """
521
+ Return a bool indicating whether this is an 'interactive' stream.
522
+
523
+ Return False if it can't be determined.
524
+ """
525
+
526
+ self._checkClosed()
527
+ return False
528
+
529
+ # Readline[s] and writelines
530
+
531
+ def readline(self, size=-1):
532
+ r"""
533
+ Read and return a line of bytes from the stream.
534
+
535
+ If size is specified, at most size bytes will be read. Size should be an int.
536
+
537
+ The line terminator is always b'\n' for binary files; for text files, the newlines argument to open can be used
538
+ to select the line terminator(s) recognized.
539
+ """
540
+
541
+ # For backwards compatibility, a (slowish) readline().
542
+ if hasattr(self, 'peek'):
543
+ def nreadahead():
544
+ readahead = self.peek(1)
545
+ if not readahead:
546
+ return 1
547
+ n = (readahead.find(b'\n') + 1) or len(readahead)
548
+ if size >= 0:
549
+ n = min(n, size)
550
+ return n
551
+
552
+ else:
553
+ def nreadahead():
554
+ return 1
555
+
556
+ if size is None:
557
+ size = -1
558
+ else:
559
+ try:
560
+ size_index = size.__index__
561
+ except AttributeError:
562
+ raise TypeError(f'{size!r} is not an integer')
563
+ else:
564
+ size = size_index()
565
+
566
+ res = bytearray()
567
+ while size < 0 or len(res) < size:
568
+ b = self.read(nreadahead())
569
+ if not b:
570
+ break
571
+ res += b
572
+ if res.endswith(b'\n'):
573
+ break
574
+
575
+ return bytes(res)
576
+
577
+ def __iter__(self):
578
+ self._checkClosed()
579
+ return self
580
+
581
+ def __next__(self):
582
+ line = self.readline()
583
+ if not line:
584
+ raise StopIteration
585
+ return line
586
+
587
+ def readlines(self, hint=None):
588
+ """
589
+ Return a list of lines from the stream.
590
+
591
+ hint can be specified to control the number of lines read: no more lines will be read if the total size (in
592
+ bytes/characters) of all lines so far exceeds hint.
593
+ """
594
+
595
+ if hint is None or hint <= 0:
596
+ return list(self)
597
+ n = 0
598
+ lines = []
599
+ for line in self:
600
+ lines.append(line)
601
+ n += len(line)
602
+ if n >= hint:
603
+ break
604
+ return lines
605
+
606
+ def writelines(self, lines):
607
+ """
608
+ Write a list of lines to the stream.
609
+
610
+ Line separators are not added, so it is usual for each of the lines provided to have a line separator at the
611
+ end.
612
+ """
613
+
614
+ self._checkClosed()
615
+ for line in lines:
616
+ self.write(line)
617
+
618
+
619
+ @io.RawIOBase.register
620
+ class RawIOBase(IOBase):
621
+ """Base class for raw binary I/O."""
622
+
623
+ # The read() method is implemented by calling readinto(); derived classes that want to support read() only need to
624
+ # implement readinto() as a primitive operation. In general, readinto() can be more efficient than read().
625
+
626
+ # (It would be tempting to also provide an implementation of readinto() in terms of read(), in case the latter is a
627
+ # more suitable primitive operation, but that would lead to nasty recursion in case a subclass doesn't implement
628
+ # either.)
629
+
630
+ def read(self, size=-1):
631
+ """
632
+ Read and return up to size bytes, where size is an int.
633
+
634
+ Returns an empty bytes object on EOF, or None if the object is set not to block and has no data to read.
635
+ """
636
+
637
+ if size is None:
638
+ size = -1
639
+ if size < 0:
640
+ return self.readall()
641
+ b = bytearray(size.__index__())
642
+ n = self.readinto(b)
643
+ if n is None:
644
+ return None
645
+ del b[n:]
646
+ return bytes(b)
647
+
648
+ def readall(self):
649
+ """Read until EOF, using multiple read() call."""
650
+
651
+ res = bytearray()
652
+ while data := self.read(DEFAULT_BUFFER_SIZE):
653
+ res += data
654
+ if res:
655
+ return bytes(res)
656
+ else:
657
+ # b'' or None
658
+ return data
659
+
660
+ def readinto(self, b):
661
+ """
662
+ Read bytes into a pre-allocated bytes-like object b.
663
+
664
+ Returns an int representing the number of bytes read (0 for EOF), or None if the object is set not to block and
665
+ has no data to read.
666
+ """
667
+
668
+ self._unsupported('readinto')
669
+
670
+ def write(self, b):
671
+ """
672
+ Write the given buffer to the IO stream.
673
+
674
+ Returns the number of bytes written, which may be less than the length of b in bytes.
675
+ """
676
+
677
+ self._unsupported('write')
678
+
679
+
680
+ @io.BufferedIOBase.register
681
+ class BufferedIOBase(IOBase):
682
+ """
683
+ Base class for buffered IO objects.
684
+
685
+ The main difference with RawIOBase is that the read() method supports omitting the size argument, and does not have
686
+ a default implementation that defers to readinto().
687
+
688
+ In addition, read(), readinto() and write() may raise BlockingIOError if the underlying raw stream is in
689
+ non-blocking mode and not ready; unlike their raw counterparts, they will never return None.
690
+
691
+ A typical implementation should not inherit from a RawIOBase implementation, but wrap one.
692
+ """
693
+
694
+ def read(self, size=-1):
695
+ """
696
+ Read and return up to size bytes, where size is an int.
697
+
698
+ If the argument is omitted, None, or negative, reads and returns all data until EOF.
699
+
700
+ If the argument is positive, and the underlying raw stream is not 'interactive', multiple raw reads may be
701
+ issued to satisfy the byte count (unless EOF is reached first). But for interactive raw streams (XXX and for
702
+ pipes?), at most one raw read will be issued, and a short result does not imply that EOF is imminent.
703
+
704
+ Returns an empty bytes array on EOF.
705
+
706
+ Raises BlockingIOError if the underlying raw stream has no data at the moment.
707
+ """
708
+
709
+ self._unsupported('read')
710
+
711
+ def read1(self, size=-1):
712
+ """Read up to size bytes with at most one read() system call, where size is an int."""
713
+
714
+ self._unsupported('read1')
715
+
716
+ def readinto(self, b):
717
+ """
718
+ Read bytes into a pre-allocated bytes-like object b.
719
+
720
+ Like read(), this may issue multiple reads to the underlying raw stream, unless the latter is 'interactive'.
721
+
722
+ Returns an int representing the number of bytes read (0 for EOF).
723
+
724
+ Raises BlockingIOError if the underlying raw stream has no data at the moment.
725
+ """
726
+
727
+ return self._readinto(b, read1=False)
728
+
729
+ def readinto1(self, b):
730
+ """
731
+ Read bytes into buffer *b*, using at most one system call
732
+
733
+ Returns an int representing the number of bytes read (0 for EOF).
734
+
735
+ Raises BlockingIOError if the underlying raw stream has no data at the moment.
736
+ """
737
+
738
+ return self._readinto(b, read1=True)
739
+
740
+ def _readinto(self, b, read1):
741
+ if not isinstance(b, memoryview):
742
+ b = memoryview(b)
743
+ b = b.cast('B')
744
+
745
+ if read1:
746
+ data = self.read1(len(b))
747
+ else:
748
+ data = self.read(len(b))
749
+ n = len(data)
750
+
751
+ b[:n] = data
752
+
753
+ return n
754
+
755
+ def write(self, b):
756
+ """
757
+ Write the given bytes buffer to the IO stream.
758
+
759
+ Return the number of bytes written, which is always the length of b in bytes.
760
+
761
+ Raises BlockingIOError if the buffer is full and the underlying raw stream cannot accept more data at the
762
+ moment.
763
+ """
764
+
765
+ self._unsupported('write')
766
+
767
+ def detach(self):
768
+ """
769
+ Separate the underlying raw stream from the buffer and return it.
770
+
771
+ After the raw stream has been detached, the buffer is in an unusable state.
772
+ """
773
+
774
+ self._unsupported('detach')
775
+
776
+
777
+ class _BufferedIOMixin(BufferedIOBase):
778
+ """
779
+ A mixin implementation of BufferedIOBase with an underlying raw stream.
780
+
781
+ This passes most requests on to the underlying raw stream. It does *not* provide implementations of read(),
782
+ readinto() or write().
783
+ """
784
+
785
+ def __init__(self, raw):
786
+ self._raw = raw
787
+
788
+ # Positioning
789
+
790
+ def seek(self, pos, whence=0):
791
+ new_position = self.raw.seek(pos, whence)
792
+ if new_position < 0:
793
+ raise OSError('seek() returned an invalid position')
794
+ return new_position
795
+
796
+ def tell(self):
797
+ pos = self.raw.tell()
798
+ if pos < 0:
799
+ raise OSError('tell() returned an invalid position')
800
+ return pos
801
+
802
+ def truncate(self, pos=None):
803
+ self._checkClosed()
804
+ self._checkWritable()
805
+
806
+ # Flush the stream. We're mixing buffered I/O with lower-level I/O, and a flush may be necessary to synch both
807
+ # views of the current file state.
808
+ self.flush()
809
+
810
+ if pos is None:
811
+ pos = self.tell()
812
+
813
+ # XXX: Should seek() be used, instead of passing the position directly to truncate?
814
+ return self.raw.truncate(pos)
815
+
816
+ # Flush and close
817
+
818
+ def flush(self):
819
+ if self.closed:
820
+ raise ValueError('flush on closed file')
821
+ self.raw.flush()
822
+
823
+ def close(self):
824
+ if self.raw is not None and not self.closed:
825
+ try:
826
+ # may raise BlockingIOError or BrokenPipeError etc
827
+ self.flush()
828
+ finally:
829
+ self.raw.close()
830
+
831
+ def detach(self):
832
+ if self.raw is None:
833
+ raise ValueError('raw stream already detached')
834
+ self.flush()
835
+ raw = self._raw
836
+ self._raw = None
837
+ return raw
838
+
839
+ # Inquiries
840
+
841
+ def seekable(self):
842
+ return self.raw.seekable()
843
+
844
+ @property
845
+ def raw(self):
846
+ return self._raw
847
+
848
+ @property
849
+ def closed(self):
850
+ return self.raw.closed
851
+
852
+ @property
853
+ def name(self):
854
+ return self.raw.name
855
+
856
+ @property
857
+ def mode(self):
858
+ return self.raw.mode
859
+
860
+ def __getstate__(self):
861
+ raise TypeError(f'cannot pickle {self.__class__.__name__!r} object')
862
+
863
+ def __repr__(self):
864
+ modname = self.__class__.__module__
865
+ clsname = self.__class__.__qualname__
866
+ try:
867
+ name = self.name
868
+ except AttributeError:
869
+ return f'<{modname}.{clsname}>'
870
+ else:
871
+ return f'<{modname}.{clsname} name={name!r}>'
872
+
873
+ # Lower-level APIs
874
+
875
+ def fileno(self):
876
+ return self.raw.fileno()
877
+
878
+ def isatty(self):
879
+ return self.raw.isatty()
880
+
881
+
882
+ class BytesIO(BufferedIOBase):
883
+ """Buffered I/O implementation using an in-memory bytes buffer."""
884
+
885
+ # Initialize _buffer as soon as possible since it's used by __del__() which calls close()
886
+ _buffer = None
887
+
888
+ def __init__(self, initial_bytes=None):
889
+ buf = bytearray()
890
+ if initial_bytes is not None:
891
+ buf += initial_bytes
892
+ self._buffer = buf
893
+ self._pos = 0
894
+
895
+ def __getstate__(self):
896
+ if self.closed:
897
+ raise ValueError('__getstate__ on closed file')
898
+ return self.__dict__.copy()
899
+
900
+ def getvalue(self):
901
+ """Return the bytes value (contents) of the buffer"""
902
+
903
+ if self.closed:
904
+ raise ValueError('getvalue on closed file')
905
+ return bytes(self._buffer)
906
+
907
+ def getbuffer(self):
908
+ """Return a readable and writable view of the buffer."""
909
+
910
+ if self.closed:
911
+ raise ValueError('getbuffer on closed file')
912
+ return memoryview(self._buffer)
913
+
914
+ def close(self):
915
+ if self._buffer is not None:
916
+ self._buffer.clear()
917
+ super().close()
918
+
919
+ def read(self, size=-1):
920
+ if self.closed:
921
+ raise ValueError('read from closed file')
922
+ if size is None:
923
+ size = -1
924
+ else:
925
+ try:
926
+ size_index = size.__index__
927
+ except AttributeError:
928
+ raise TypeError(f'{size!r} is not an integer')
929
+ else:
930
+ size = size_index()
931
+ if size < 0:
932
+ size = len(self._buffer)
933
+ if len(self._buffer) <= self._pos:
934
+ return b''
935
+ newpos = min(len(self._buffer), self._pos + size)
936
+ b = self._buffer[self._pos:newpos]
937
+ self._pos = newpos
938
+ return bytes(b)
939
+
940
+ def read1(self, size=-1):
941
+ """This is the same as read."""
942
+
943
+ return self.read(size)
944
+
945
+ def write(self, b):
946
+ if self.closed:
947
+ raise ValueError('write to closed file')
948
+ if isinstance(b, str):
949
+ raise TypeError("can't write str to binary stream")
950
+ with memoryview(b) as view:
951
+ n = view.nbytes # Size of any bytes-like object
952
+ if n == 0:
953
+ return 0
954
+ pos = self._pos
955
+ if pos > len(self._buffer):
956
+ # Inserts null bytes between the current end of the file and the new write position.
957
+ padding = b'\x00' * (pos - len(self._buffer))
958
+ self._buffer += padding
959
+ self._buffer[pos:pos + n] = b
960
+ self._pos += n
961
+ return n
962
+
963
+ def seek(self, pos, whence=0):
964
+ if self.closed:
965
+ raise ValueError('seek on closed file')
966
+ try:
967
+ pos_index = pos.__index__
968
+ except AttributeError:
969
+ raise TypeError(f'{pos!r} is not an integer')
970
+ else:
971
+ pos = pos_index()
972
+ if whence == 0:
973
+ if pos < 0:
974
+ raise ValueError('negative seek position %r' % (pos,))
975
+ self._pos = pos
976
+ elif whence == 1:
977
+ self._pos = max(0, self._pos + pos)
978
+ elif whence == 2:
979
+ self._pos = max(0, len(self._buffer) + pos)
980
+ else:
981
+ raise ValueError('unsupported whence value')
982
+ return self._pos
983
+
984
+ def tell(self):
985
+ if self.closed:
986
+ raise ValueError('tell on closed file')
987
+ return self._pos
988
+
989
+ def truncate(self, pos=None):
990
+ if self.closed:
991
+ raise ValueError('truncate on closed file')
992
+ if pos is None:
993
+ pos = self._pos
994
+ else:
995
+ try:
996
+ pos_index = pos.__index__
997
+ except AttributeError:
998
+ raise TypeError(f'{pos!r} is not an integer')
999
+ else:
1000
+ pos = pos_index()
1001
+ if pos < 0:
1002
+ raise ValueError('negative truncate position %r' % (pos,))
1003
+ del self._buffer[pos:]
1004
+ return pos
1005
+
1006
+ def readable(self):
1007
+ if self.closed:
1008
+ raise ValueError('I/O operation on closed file.')
1009
+ return True
1010
+
1011
+ def writable(self):
1012
+ if self.closed:
1013
+ raise ValueError('I/O operation on closed file.')
1014
+ return True
1015
+
1016
+ def seekable(self):
1017
+ if self.closed:
1018
+ raise ValueError('I/O operation on closed file.')
1019
+ return True
1020
+
1021
+
1022
+ class BufferedReader(_BufferedIOMixin):
1023
+ """
1024
+ BufferedReader(raw[, buffer_size])
1025
+
1026
+ A buffer for a readable, sequential BaseRawIO object.
1027
+
1028
+ The constructor creates a BufferedReader for the given readable raw stream and buffer_size. If buffer_size is
1029
+ omitted, DEFAULT_BUFFER_SIZE is used.
1030
+ """
1031
+
1032
+ def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
1033
+ """Create a new buffered reader using the given readable raw IO object."""
1034
+
1035
+ if not raw.readable():
1036
+ raise OSError('"raw" argument must be readable.')
1037
+
1038
+ _BufferedIOMixin.__init__(self, raw)
1039
+ if buffer_size <= 0:
1040
+ raise ValueError('invalid buffer size')
1041
+ self.buffer_size = buffer_size
1042
+ self._reset_read_buf()
1043
+ self._read_lock = threading.Lock()
1044
+
1045
+ def readable(self):
1046
+ return self.raw.readable()
1047
+
1048
+ def _reset_read_buf(self):
1049
+ self._read_buf = b''
1050
+ self._read_pos = 0
1051
+
1052
+ def read(self, size=None):
1053
+ """
1054
+ Read size bytes.
1055
+
1056
+ Returns exactly size bytes of data unless the underlying raw IO stream reaches EOF or if the call would block in
1057
+ non-blocking mode. If size is negative, read until EOF or until read() would block.
1058
+ """
1059
+
1060
+ if size is not None and size < -1:
1061
+ raise ValueError('invalid number of bytes to read')
1062
+ with self._read_lock:
1063
+ return self._read_unlocked(size)
1064
+
1065
+ def _read_unlocked(self, n=None):
1066
+ nodata_val = b''
1067
+ empty_values = (b'', None)
1068
+ buf = self._read_buf
1069
+ pos = self._read_pos
1070
+
1071
+ # Special case for when the number of bytes to read is unspecified.
1072
+ if n is None or n == -1:
1073
+ self._reset_read_buf()
1074
+ if hasattr(self.raw, 'readall'):
1075
+ chunk = self.raw.readall()
1076
+ if chunk is None:
1077
+ return buf[pos:] or None
1078
+ else:
1079
+ return buf[pos:] + chunk
1080
+
1081
+ chunks = [buf[pos:]] # Strip the consumed bytes.
1082
+ current_size = 0
1083
+ while True:
1084
+ # Read until EOF or until read() would block.
1085
+ chunk = self.raw.read()
1086
+ if chunk in empty_values:
1087
+ nodata_val = chunk
1088
+ break
1089
+ current_size += len(chunk)
1090
+ chunks.append(chunk)
1091
+ return b''.join(chunks) or nodata_val
1092
+
1093
+ # The number of bytes to read is specified, return at most n bytes.
1094
+ avail = len(buf) - pos # Length of the available buffered data.
1095
+ if n <= avail:
1096
+ # Fast path: the data to read is fully buffered.
1097
+ self._read_pos += n
1098
+ return buf[pos:pos + n]
1099
+
1100
+ # Slow path: read from the stream until enough bytes are read, or until an EOF occurs or until read() would
1101
+ # block.
1102
+ chunks = [buf[pos:]]
1103
+ wanted = max(self.buffer_size, n)
1104
+ while avail < n:
1105
+ chunk = self.raw.read(wanted)
1106
+ if chunk in empty_values:
1107
+ nodata_val = chunk
1108
+ break
1109
+ avail += len(chunk)
1110
+ chunks.append(chunk)
1111
+
1112
+ # n is more than avail only when an EOF occurred or when read() would have blocked.
1113
+ n = min(n, avail)
1114
+ out = b''.join(chunks)
1115
+ self._read_buf = out[n:] # Save the extra data in the buffer.
1116
+ self._read_pos = 0
1117
+ return out[:n] if out else nodata_val
1118
+
1119
+ def peek(self, size=0):
1120
+ """
1121
+ Returns buffered bytes without advancing the position.
1122
+
1123
+ The argument indicates a desired minimal number of bytes; we do at most one raw read to satisfy it. We never
1124
+ return more than self.buffer_size.
1125
+ """
1126
+
1127
+ self._checkClosed('peek of closed file')
1128
+ with self._read_lock:
1129
+ return self._peek_unlocked(size)
1130
+
1131
+ def _peek_unlocked(self, n=0):
1132
+ want = min(n, self.buffer_size)
1133
+ have = len(self._read_buf) - self._read_pos
1134
+ if have < want or have <= 0:
1135
+ to_read = self.buffer_size - have
1136
+ current = self.raw.read(to_read)
1137
+ if current:
1138
+ self._read_buf = self._read_buf[self._read_pos:] + current
1139
+ self._read_pos = 0
1140
+ return self._read_buf[self._read_pos:]
1141
+
1142
+ def read1(self, size=-1):
1143
+ """Reads up to size bytes, with at most one read() system call."""
1144
+
1145
+ # Returns up to size bytes. If at least one byte is buffered, we only return buffered bytes. Otherwise, we do
1146
+ # one raw read.
1147
+ self._checkClosed('read of closed file')
1148
+ if size < 0:
1149
+ size = self.buffer_size
1150
+ if size == 0:
1151
+ return b''
1152
+ with self._read_lock:
1153
+ self._peek_unlocked(1)
1154
+ return self._read_unlocked(min(size, len(self._read_buf) - self._read_pos))
1155
+
1156
+ # Implementing readinto() and readinto1() is not strictly necessary (we could rely on the base class that provides
1157
+ # an implementation in terms of read() and read1()). We do it anyway to keep the _pyio implementation similar to the
1158
+ # io implementation (which implements the methods for performance reasons).
1159
+ def _readinto(self, buf, read1):
1160
+ """Read data into *buf* with at most one system call."""
1161
+
1162
+ self._checkClosed('readinto of closed file')
1163
+
1164
+ # Need to create a memoryview object of type 'b', otherwise we may not be able to assign bytes to it, and
1165
+ # slicing it would create a new object.
1166
+ if not isinstance(buf, memoryview):
1167
+ buf = memoryview(buf)
1168
+ if buf.nbytes == 0:
1169
+ return 0
1170
+ buf = buf.cast('B')
1171
+
1172
+ written = 0
1173
+ with self._read_lock:
1174
+ while written < len(buf):
1175
+ # First try to read from internal buffer
1176
+ avail = min(len(self._read_buf) - self._read_pos, len(buf))
1177
+ if avail:
1178
+ buf[written: written + avail] = self._read_buf[self._read_pos: self._read_pos + avail]
1179
+ self._read_pos += avail
1180
+ written += avail
1181
+ if written == len(buf):
1182
+ break
1183
+
1184
+ # If remaining space in callers buffer is larger than internal buffer, read directly into callers buffer
1185
+ if len(buf) - written > self.buffer_size:
1186
+ n = self.raw.readinto(buf[written:])
1187
+ if not n:
1188
+ break # eof
1189
+ written += n
1190
+
1191
+ # Otherwise refill internal buffer - unless we're in read1 mode and already got some data
1192
+ elif not (read1 and written):
1193
+ if not self._peek_unlocked(1):
1194
+ break # eof
1195
+
1196
+ # In readinto1 mode, return as soon as we have some data
1197
+ if read1 and written:
1198
+ break
1199
+
1200
+ return written
1201
+
1202
+ def tell(self):
1203
+ # GH-95782: Keep return value non-negative
1204
+ return max(_BufferedIOMixin.tell(self) - len(self._read_buf) + self._read_pos, 0)
1205
+
1206
+ def seek(self, pos, whence=0):
1207
+ if whence not in valid_seek_flags:
1208
+ raise ValueError('invalid whence value')
1209
+ self._checkClosed('seek of closed file')
1210
+ with self._read_lock:
1211
+ if whence == 1:
1212
+ pos -= len(self._read_buf) - self._read_pos
1213
+ pos = _BufferedIOMixin.seek(self, pos, whence)
1214
+ self._reset_read_buf()
1215
+ return pos
1216
+
1217
+
1218
+ class BufferedWriter(_BufferedIOMixin):
1219
+ """
1220
+ A buffer for a writeable sequential RawIO object.
1221
+
1222
+ The constructor creates a BufferedWriter for the given writeable raw stream. If the buffer_size is not given, it
1223
+ defaults to DEFAULT_BUFFER_SIZE.
1224
+ """
1225
+
1226
+ def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
1227
+ if not raw.writable():
1228
+ raise OSError('"raw" argument must be writable.')
1229
+
1230
+ _BufferedIOMixin.__init__(self, raw)
1231
+ if buffer_size <= 0:
1232
+ raise ValueError('invalid buffer size')
1233
+ self.buffer_size = buffer_size
1234
+ self._write_buf = bytearray()
1235
+ self._write_lock = threading.Lock()
1236
+
1237
+ def writable(self):
1238
+ return self.raw.writable()
1239
+
1240
+ def write(self, b):
1241
+ if isinstance(b, str):
1242
+ raise TypeError("can't write str to binary stream")
1243
+ with self._write_lock:
1244
+ if self.closed:
1245
+ raise ValueError('write to closed file')
1246
+ # XXX we can implement some more tricks to try and avoid partial writes
1247
+ if len(self._write_buf) > self.buffer_size:
1248
+ # We're full, so let's pre-flush the buffer. (This may raise BlockingIOError with characters_written ==
1249
+ # 0.)
1250
+ self._flush_unlocked()
1251
+ before = len(self._write_buf)
1252
+ self._write_buf.extend(b)
1253
+ written = len(self._write_buf) - before
1254
+ if len(self._write_buf) > self.buffer_size:
1255
+ try:
1256
+ self._flush_unlocked()
1257
+ except BlockingIOError as e:
1258
+ if len(self._write_buf) > self.buffer_size:
1259
+ # We've hit the buffer_size. We have to accept a partial write and cut back our buffer.
1260
+ overage = len(self._write_buf) - self.buffer_size
1261
+ written -= overage
1262
+ self._write_buf = self._write_buf[: self.buffer_size]
1263
+ raise BlockingIOError(e.errno, e.strerror, written)
1264
+ return written
1265
+
1266
+ def truncate(self, pos=None):
1267
+ with self._write_lock:
1268
+ self._flush_unlocked()
1269
+ if pos is None:
1270
+ pos = self.raw.tell()
1271
+ return self.raw.truncate(pos)
1272
+
1273
+ def flush(self):
1274
+ with self._write_lock:
1275
+ self._flush_unlocked()
1276
+
1277
+ def _flush_unlocked(self):
1278
+ if self.closed:
1279
+ raise ValueError('flush on closed file')
1280
+ while self._write_buf:
1281
+ try:
1282
+ n = self.raw.write(self._write_buf)
1283
+ except BlockingIOError:
1284
+ raise RuntimeError('self.raw should implement RawIOBase: it should not raise BlockingIOError')
1285
+ if n is None:
1286
+ raise BlockingIOError(errno.EAGAIN, 'write could not complete without blocking', 0)
1287
+ if n > len(self._write_buf) or n < 0:
1288
+ raise OSError('write() returned incorrect number of bytes')
1289
+ del self._write_buf[:n]
1290
+
1291
+ def tell(self):
1292
+ return _BufferedIOMixin.tell(self) + len(self._write_buf)
1293
+
1294
+ def seek(self, pos, whence=0):
1295
+ if whence not in valid_seek_flags:
1296
+ raise ValueError('invalid whence value')
1297
+ with self._write_lock:
1298
+ self._flush_unlocked()
1299
+ return _BufferedIOMixin.seek(self, pos, whence)
1300
+
1301
+ def close(self):
1302
+ with self._write_lock:
1303
+ if self.raw is None or self.closed:
1304
+ return
1305
+ # We have to release the lock and call self.flush() (which will probably just re-take the lock) in case flush
1306
+ # has been overridden in a subclass or the user set self.flush to something. This is the same behavior as the C
1307
+ # implementation.
1308
+ try:
1309
+ # may raise BlockingIOError or BrokenPipeError etc
1310
+ self.flush()
1311
+ finally:
1312
+ with self._write_lock:
1313
+ self.raw.close()
1314
+
1315
+
1316
+ class BufferedRWPair(BufferedIOBase):
1317
+ """
1318
+ A buffered reader and writer object together.
1319
+
1320
+ A buffered reader object and buffered writer object put together to form a sequential IO object that can read and
1321
+ write. This is typically used with a socket or two-way pipe.
1322
+
1323
+ reader and writer are RawIOBase objects that are readable and writeable respectively. If the buffer_size is omitted
1324
+ it defaults to DEFAULT_BUFFER_SIZE.
1325
+ """
1326
+
1327
+ # XXX The usefulness of this (compared to having two separate IO objects) is questionable.
1328
+
1329
+ def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE):
1330
+ """
1331
+ Constructor.
1332
+
1333
+ The arguments are two RawIO instances.
1334
+ """
1335
+
1336
+ if not reader.readable():
1337
+ raise OSError('"reader" argument must be readable.')
1338
+
1339
+ if not writer.writable():
1340
+ raise OSError('"writer" argument must be writable.')
1341
+
1342
+ self.reader = BufferedReader(reader, buffer_size)
1343
+ self.writer = BufferedWriter(writer, buffer_size)
1344
+
1345
+ def read(self, size=-1):
1346
+ if size is None:
1347
+ size = -1
1348
+ return self.reader.read(size)
1349
+
1350
+ def readinto(self, b):
1351
+ return self.reader.readinto(b)
1352
+
1353
+ def write(self, b):
1354
+ return self.writer.write(b)
1355
+
1356
+ def peek(self, size=0):
1357
+ return self.reader.peek(size)
1358
+
1359
+ def read1(self, size=-1):
1360
+ return self.reader.read1(size)
1361
+
1362
+ def readinto1(self, b):
1363
+ return self.reader.readinto1(b)
1364
+
1365
+ def readable(self):
1366
+ return self.reader.readable()
1367
+
1368
+ def writable(self):
1369
+ return self.writer.writable()
1370
+
1371
+ def flush(self):
1372
+ return self.writer.flush()
1373
+
1374
+ def close(self):
1375
+ try:
1376
+ self.writer.close()
1377
+ finally:
1378
+ self.reader.close()
1379
+
1380
+ def isatty(self):
1381
+ return self.reader.isatty() or self.writer.isatty()
1382
+
1383
+ @property
1384
+ def closed(self):
1385
+ return self.writer.closed
1386
+
1387
+
1388
+ class BufferedRandom(BufferedWriter, BufferedReader):
1389
+ """
1390
+ A buffered interface to random access streams.
1391
+
1392
+ The constructor creates a reader and writer for a seekable stream, raw, given in the first argument. If the
1393
+ buffer_size is omitted it defaults to DEFAULT_BUFFER_SIZE.
1394
+ """
1395
+
1396
+ def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE):
1397
+ raw._checkSeekable()
1398
+ BufferedReader.__init__(self, raw, buffer_size)
1399
+ BufferedWriter.__init__(self, raw, buffer_size)
1400
+
1401
+ def seek(self, pos, whence=0):
1402
+ if whence not in valid_seek_flags:
1403
+ raise ValueError('invalid whence value')
1404
+ self.flush()
1405
+ if self._read_buf:
1406
+ # Undo read ahead.
1407
+ with self._read_lock:
1408
+ self.raw.seek(self._read_pos - len(self._read_buf), 1)
1409
+ # First do the raw seek, then empty the read buffer, so that if the raw seek fails, we don't lose buffered data
1410
+ # forever.
1411
+ pos = self.raw.seek(pos, whence)
1412
+ with self._read_lock:
1413
+ self._reset_read_buf()
1414
+ if pos < 0:
1415
+ raise OSError('seek() returned invalid position')
1416
+ return pos
1417
+
1418
+ def tell(self):
1419
+ if self._write_buf:
1420
+ return BufferedWriter.tell(self)
1421
+ else:
1422
+ return BufferedReader.tell(self)
1423
+
1424
+ def truncate(self, pos=None):
1425
+ if pos is None:
1426
+ pos = self.tell()
1427
+ # Use seek to flush the read buffer.
1428
+ return BufferedWriter.truncate(self, pos)
1429
+
1430
+ def read(self, size=None):
1431
+ if size is None:
1432
+ size = -1
1433
+ self.flush()
1434
+ return BufferedReader.read(self, size)
1435
+
1436
+ def readinto(self, b):
1437
+ self.flush()
1438
+ return BufferedReader.readinto(self, b)
1439
+
1440
+ def peek(self, size=0):
1441
+ self.flush()
1442
+ return BufferedReader.peek(self, size)
1443
+
1444
+ def read1(self, size=-1):
1445
+ self.flush()
1446
+ return BufferedReader.read1(self, size)
1447
+
1448
+ def readinto1(self, b):
1449
+ self.flush()
1450
+ return BufferedReader.readinto1(self, b)
1451
+
1452
+ def write(self, b):
1453
+ if self._read_buf:
1454
+ # Undo readahead
1455
+ with self._read_lock:
1456
+ self.raw.seek(self._read_pos - len(self._read_buf), 1)
1457
+ self._reset_read_buf()
1458
+ return BufferedWriter.write(self, b)
1459
+
1460
+
1461
+ class FileIO(RawIOBase):
1462
+ _fd = -1
1463
+ _created = False
1464
+ _readable = False
1465
+ _writable = False
1466
+ _appending = False
1467
+ _seekable = None
1468
+ _closefd = True
1469
+
1470
+ def __init__(self, file, mode='r', closefd=True, opener=None):
1471
+ """
1472
+ Open a file. The mode can be 'r' (default), 'w', 'x' or 'a' for reading, writing, exclusive creation or
1473
+ appending. The file will be created if it doesn't exist when opened for writing or appending; it will be
1474
+ truncated when opened for writing. A FileExistsError will be raised if it already exists when opened for
1475
+ creating. Opening a file for creating implies writing so this mode behaves in a similar way to 'w'. Add a '+' to
1476
+ the mode to allow simultaneous reading and writing. A custom opener can be used by passing a callable as
1477
+ *opener*. The underlying file descriptor for the file object is then obtained by calling opener with (*name*,
1478
+ *flags*). *opener* must return an open file descriptor (passing os.open as *opener* results in functionality
1479
+ similar to passing None).
1480
+ """
1481
+
1482
+ if self._fd >= 0:
1483
+ # Have to close the existing file first.
1484
+ self._stat_atopen = None
1485
+ try:
1486
+ if self._closefd:
1487
+ os.close(self._fd)
1488
+ finally:
1489
+ self._fd = -1
1490
+
1491
+ if isinstance(file, float):
1492
+ raise TypeError('integer argument expected, got float')
1493
+ if isinstance(file, int):
1494
+ if isinstance(file, bool):
1495
+ warnings.warn('bool is used as a file descriptor', RuntimeWarning, stacklevel=2)
1496
+ file = int(file)
1497
+ fd = file
1498
+ if fd < 0:
1499
+ raise ValueError('negative file descriptor')
1500
+ else:
1501
+ fd = -1
1502
+
1503
+ if not isinstance(mode, str):
1504
+ raise TypeError('invalid mode: %s' % (mode,))
1505
+ if not set(mode) <= set('xrwab+'):
1506
+ raise ValueError('invalid mode: %s' % (mode,))
1507
+ if sum(c in 'rwax' for c in mode) != 1 or mode.count('+') > 1:
1508
+ raise ValueError('Must have exactly one of create/read/write/append mode and at most one plus')
1509
+
1510
+ if 'x' in mode:
1511
+ self._created = True
1512
+ self._writable = True
1513
+ flags = os.O_EXCL | os.O_CREAT
1514
+ elif 'r' in mode:
1515
+ self._readable = True
1516
+ flags = 0
1517
+ elif 'w' in mode:
1518
+ self._writable = True
1519
+ flags = os.O_CREAT | os.O_TRUNC
1520
+ elif 'a' in mode:
1521
+ self._writable = True
1522
+ self._appending = True
1523
+ flags = os.O_APPEND | os.O_CREAT
1524
+
1525
+ if '+' in mode:
1526
+ self._readable = True
1527
+ self._writable = True
1528
+
1529
+ if self._readable and self._writable:
1530
+ flags |= os.O_RDWR
1531
+ elif self._readable:
1532
+ flags |= os.O_RDONLY
1533
+ else:
1534
+ flags |= os.O_WRONLY
1535
+
1536
+ flags |= getattr(os, 'O_BINARY', 0)
1537
+
1538
+ noinherit_flag = getattr(os, 'O_NOINHERIT', 0) or getattr(os, 'O_CLOEXEC', 0)
1539
+ flags |= noinherit_flag
1540
+
1541
+ owned_fd = None
1542
+ try:
1543
+ if fd < 0:
1544
+ if not closefd:
1545
+ raise ValueError('Cannot use closefd=False with file name')
1546
+ if opener is None:
1547
+ fd = os.open(file, flags, 0o666)
1548
+ else:
1549
+ fd = opener(file, flags)
1550
+ if not isinstance(fd, int):
1551
+ raise TypeError('expected integer from opener')
1552
+ if fd < 0:
1553
+ raise OSError('Negative file descriptor')
1554
+ owned_fd = fd
1555
+ if not noinherit_flag:
1556
+ os.set_inheritable(fd, False)
1557
+
1558
+ self._closefd = closefd
1559
+ self._stat_atopen = os.fstat(fd)
1560
+ try:
1561
+ if stat.S_ISDIR(self._stat_atopen.st_mode):
1562
+ raise IsADirectoryError(
1563
+ errno.EISDIR, os.strerror(errno.EISDIR), file,
1564
+ )
1565
+ except AttributeError:
1566
+ # Ignore the AttributeError if stat.S_ISDIR or errno.EISDIR don't exist.
1567
+ pass
1568
+
1569
+ self.name = file
1570
+ if self._appending:
1571
+ # For consistent behaviour, we explicitly seek to the end of file (otherwise, it might be done only on
1572
+ # the first write()).
1573
+ try:
1574
+ os.lseek(fd, 0, io.SEEK_END)
1575
+ except OSError as e:
1576
+ if e.errno != errno.ESPIPE:
1577
+ raise
1578
+ except: # noqa
1579
+ self._stat_atopen = None
1580
+ if owned_fd is not None:
1581
+ os.close(owned_fd)
1582
+ raise
1583
+ self._fd = fd
1584
+
1585
+ def __del__(self):
1586
+ if self._fd >= 0 and self._closefd and not self.closed:
1587
+ warnings.warn('unclosed file %r' % (self,), ResourceWarning, stacklevel=2, source=self)
1588
+ self.close()
1589
+
1590
+ def __getstate__(self):
1591
+ raise TypeError(f'cannot pickle {self.__class__.__name__!r} object')
1592
+
1593
+ def __repr__(self):
1594
+ class_name = '%s.%s' % (self.__class__.__module__, self.__class__.__qualname__)
1595
+ if self.closed:
1596
+ return '<%s [closed]>' % class_name
1597
+ try:
1598
+ name = self.name
1599
+ except AttributeError:
1600
+ return '<%s fd=%d mode=%r closefd=%r>' % (
1601
+ class_name,
1602
+ self._fd,
1603
+ self.mode,
1604
+ self._closefd,
1605
+ )
1606
+ else:
1607
+ return '<%s name=%r mode=%r closefd=%r>' % (
1608
+ class_name,
1609
+ name,
1610
+ self.mode,
1611
+ self._closefd,
1612
+ )
1613
+
1614
+ @property
1615
+ def _blksize(self):
1616
+ if self._stat_atopen is None:
1617
+ return DEFAULT_BUFFER_SIZE
1618
+
1619
+ blksize = getattr(self._stat_atopen, 'st_blksize', 0)
1620
+ # WASI sets blsize to 0
1621
+ if not blksize:
1622
+ return DEFAULT_BUFFER_SIZE
1623
+ return blksize
1624
+
1625
+ def _checkReadable(self):
1626
+ if not self._readable:
1627
+ raise UnsupportedOperation('File not open for reading')
1628
+
1629
+ def _checkWritable(self, msg=None):
1630
+ if not self._writable:
1631
+ raise UnsupportedOperation('File not open for writing')
1632
+
1633
+ def read(self, size=None):
1634
+ """
1635
+ Read at most size bytes, returned as bytes.
1636
+
1637
+ Only makes one system call, so less data may be returned than requested In non-blocking mode, returns None if no
1638
+ data is available. Return an empty bytes object at EOF.
1639
+ """
1640
+
1641
+ self._checkClosed()
1642
+ self._checkReadable()
1643
+ if size is None or size < 0:
1644
+ return self.readall()
1645
+ try:
1646
+ return os.read(self._fd, size)
1647
+ except BlockingIOError:
1648
+ return None
1649
+
1650
+ def readall(self):
1651
+ """
1652
+ Read all data from the file, returned as bytes.
1653
+
1654
+ In non-blocking mode, returns as much as is immediately available, or None if no data is available. Return an
1655
+ empty bytes object at EOF.
1656
+ """
1657
+
1658
+ self._checkClosed()
1659
+ self._checkReadable()
1660
+ if self._stat_atopen is None or self._stat_atopen.st_size <= 0:
1661
+ bufsize = DEFAULT_BUFFER_SIZE
1662
+ else:
1663
+ # In order to detect end of file, need a read() of at least 1 byte which returns size 0. Oversize the buffer
1664
+ # by 1 byte so the I/O can be completed with two read() calls (one for all data, one for EOF) without
1665
+ # needing to resize the buffer.
1666
+ bufsize = self._stat_atopen.st_size + 1
1667
+
1668
+ if self._stat_atopen.st_size > 65536:
1669
+ try:
1670
+ pos = os.lseek(self._fd, 0, io.SEEK_CUR)
1671
+ if self._stat_atopen.st_size >= pos:
1672
+ bufsize = self._stat_atopen.st_size - pos + 1
1673
+ except OSError:
1674
+ pass
1675
+
1676
+ result = bytearray()
1677
+ while True:
1678
+ if len(result) >= bufsize:
1679
+ bufsize = len(result)
1680
+ bufsize += max(bufsize, DEFAULT_BUFFER_SIZE)
1681
+ n = bufsize - len(result)
1682
+ try:
1683
+ chunk = os.read(self._fd, n)
1684
+ except BlockingIOError:
1685
+ if result:
1686
+ break
1687
+ return None
1688
+ if not chunk: # reached the end of the file
1689
+ break
1690
+ result += chunk
1691
+
1692
+ return bytes(result)
1693
+
1694
+ def readinto(self, b):
1695
+ """Same as RawIOBase.readinto()."""
1696
+
1697
+ m = memoryview(b).cast('B')
1698
+ data = self.read(len(m))
1699
+ n = len(data)
1700
+ m[:n] = data
1701
+ return n
1702
+
1703
+ def write(self, b):
1704
+ """
1705
+ Write bytes b to file, return number written.
1706
+
1707
+ Only makes one system call, so not all of the data may be written. The number of bytes actually written is
1708
+ returned. In non-blocking mode, returns None if the write would block.
1709
+ """
1710
+ self._checkClosed()
1711
+ self._checkWritable()
1712
+ try:
1713
+ return os.write(self._fd, b)
1714
+ except BlockingIOError:
1715
+ return None
1716
+
1717
+ def seek(self, pos, whence=io.SEEK_SET):
1718
+ """
1719
+ Move to new file position.
1720
+
1721
+ Argument offset is a byte count. Optional argument whence defaults to SEEK_SET or 0 (offset from start of file,
1722
+ offset should be >= 0); other values are SEEK_CUR or 1 (move relative to current position, positive or
1723
+ negative), and SEEK_END or 2 (move relative to end of file, usually negative, although many platforms allow
1724
+ seeking beyond the end of a file).
1725
+
1726
+ Note that not all file objects are seekable.
1727
+ """
1728
+
1729
+ if isinstance(pos, float):
1730
+ raise TypeError('an integer is required')
1731
+ self._checkClosed()
1732
+ return os.lseek(self._fd, pos, whence)
1733
+
1734
+ def tell(self):
1735
+ """
1736
+ tell() -> int. Current file position.
1737
+
1738
+ Can raise OSError for non seekable files."""
1739
+
1740
+ self._checkClosed()
1741
+ return os.lseek(self._fd, 0, io.SEEK_CUR)
1742
+
1743
+ def truncate(self, size=None):
1744
+ """
1745
+ Truncate the file to at most size bytes.
1746
+
1747
+ Size defaults to the current file position, as returned by tell(). The current file position is changed to the
1748
+ value of size.
1749
+ """
1750
+
1751
+ self._checkClosed()
1752
+ self._checkWritable()
1753
+ if size is None:
1754
+ size = self.tell()
1755
+ os.ftruncate(self._fd, size)
1756
+ self._stat_atopen = None
1757
+ return size
1758
+
1759
+ def close(self):
1760
+ """
1761
+ Close the file.
1762
+
1763
+ A closed file cannot be used for further I/O operations. close() may be called more than once without error.
1764
+ """
1765
+
1766
+ if not self.closed:
1767
+ self._stat_atopen = None
1768
+ try:
1769
+ if self._closefd:
1770
+ os.close(self._fd)
1771
+ finally:
1772
+ super().close()
1773
+
1774
+ def seekable(self):
1775
+ """True if file supports random-access."""
1776
+
1777
+ self._checkClosed()
1778
+ if self._seekable is None:
1779
+ try:
1780
+ self.tell()
1781
+ except OSError:
1782
+ self._seekable = False
1783
+ else:
1784
+ self._seekable = True
1785
+ return self._seekable
1786
+
1787
+ def readable(self):
1788
+ """True if file was opened in a read mode."""
1789
+
1790
+ self._checkClosed()
1791
+ return self._readable
1792
+
1793
+ def writable(self):
1794
+ """True if file was opened in a write mode."""
1795
+
1796
+ self._checkClosed()
1797
+ return self._writable
1798
+
1799
+ def fileno(self):
1800
+ """Return the underlying file descriptor (an integer)."""
1801
+
1802
+ self._checkClosed()
1803
+ return self._fd
1804
+
1805
+ def isatty(self):
1806
+ """True if the file is connected to a TTY device."""
1807
+
1808
+ self._checkClosed()
1809
+ return os.isatty(self._fd)
1810
+
1811
+ def _isatty_open_only(self):
1812
+ """
1813
+ Checks whether the file is a TTY using an open-only optimization.
1814
+
1815
+ TTYs are always character devices. If the interpreter knows a file is not a character device when it would call
1816
+ ``isatty``, can skip that call. Inside ``open()`` there is a fresh stat result that contains that information.
1817
+ Use the stat result to skip a system call. Outside of that context TOCTOU issues (the fd could be arbitrarily
1818
+ modified by surrounding code).
1819
+ """
1820
+
1821
+ if self._stat_atopen is not None and not stat.S_ISCHR(self._stat_atopen.st_mode):
1822
+ return False
1823
+ return os.isatty(self._fd)
1824
+
1825
+ @property
1826
+ def closefd(self):
1827
+ """True if the file descriptor will be closed by close()."""
1828
+
1829
+ return self._closefd
1830
+
1831
+ @property
1832
+ def mode(self):
1833
+ """String giving the file mode"""
1834
+
1835
+ if self._created:
1836
+ if self._readable:
1837
+ return 'xb+'
1838
+ else:
1839
+ return 'xb'
1840
+ elif self._appending:
1841
+ if self._readable:
1842
+ return 'ab+'
1843
+ else:
1844
+ return 'ab'
1845
+ elif self._readable:
1846
+ if self._writable:
1847
+ return 'rb+'
1848
+ else:
1849
+ return 'rb'
1850
+ else:
1851
+ return 'wb'
1852
+
1853
+
1854
+ @io.TextIOBase.register
1855
+ class TextIOBase(IOBase):
1856
+ """
1857
+ Base class for text I/O.
1858
+
1859
+ This class provides a character and line based interface to stream I/O.
1860
+ """
1861
+
1862
+ def read(self, size=-1):
1863
+ """
1864
+ Read at most size characters from stream, where size is an int.
1865
+
1866
+ Read from underlying buffer until we have size characters or we hit EOF. If size is negative or omitted, read
1867
+ until EOF.
1868
+
1869
+ Returns a string.
1870
+ """
1871
+
1872
+ self._unsupported('read')
1873
+
1874
+ def write(self, s):
1875
+ """Write string s to stream and returning an int."""
1876
+
1877
+ self._unsupported('write')
1878
+
1879
+ def truncate(self, pos=None):
1880
+ """Truncate size to pos, where pos is an int."""
1881
+
1882
+ self._unsupported('truncate')
1883
+
1884
+ def readline(self):
1885
+ """
1886
+ Read until newline or EOF.
1887
+
1888
+ Returns an empty string if EOF is hit immediately.
1889
+ """
1890
+
1891
+ self._unsupported('readline')
1892
+
1893
+ def detach(self):
1894
+ """
1895
+ Separate the underlying buffer from the TextIOBase and return it.
1896
+
1897
+ After the underlying buffer has been detached, the TextIO is in an unusable state.
1898
+ """
1899
+
1900
+ self._unsupported('detach')
1901
+
1902
+ @property
1903
+ def encoding(self):
1904
+ """Subclasses should override."""
1905
+
1906
+ return None
1907
+
1908
+ @property
1909
+ def newlines(self):
1910
+ """
1911
+ Line endings translated so far.
1912
+
1913
+ Only line endings translated during reading are considered.
1914
+
1915
+ Subclasses should override.
1916
+ """
1917
+
1918
+ return None
1919
+
1920
+ @property
1921
+ def errors(self):
1922
+ """
1923
+ Error setting of the decoder or encoder.
1924
+
1925
+ Subclasses should override.
1926
+ """
1927
+
1928
+ return None
1929
+
1930
+
1931
+ class IncrementalNewlineDecoder(codecs.IncrementalDecoder):
1932
+ r"""
1933
+ Codec used when reading a file in universal newlines mode. It wraps another incremental decoder, translating \r\n
1934
+ and \r into \n. It also records the types of newlines encountered. When used with translate=False, it ensures that
1935
+ the newline sequence is returned in one piece.
1936
+ """
1937
+
1938
+ def __init__(self, decoder, translate, errors='strict'):
1939
+ codecs.IncrementalDecoder.__init__(self, errors=errors)
1940
+ self.translate = translate
1941
+ self.decoder = decoder
1942
+ self.seennl = 0
1943
+ self.pendingcr = False
1944
+
1945
+ def decode(self, input, final=False):
1946
+ # decode input (with the eventual \r from a previous pass)
1947
+ if self.decoder is None:
1948
+ output = input
1949
+ else:
1950
+ output = self.decoder.decode(input, final=final)
1951
+ if self.pendingcr and (output or final):
1952
+ output = '\r' + output
1953
+ self.pendingcr = False
1954
+
1955
+ # retain last \r even when not translating data: then readline() is sure to get \r\n in one pass
1956
+ if output.endswith('\r') and not final:
1957
+ output = output[:-1]
1958
+ self.pendingcr = True
1959
+
1960
+ # Record which newlines are read
1961
+ crlf = output.count('\r\n')
1962
+ cr = output.count('\r') - crlf
1963
+ lf = output.count('\n') - crlf
1964
+ self.seennl |= (lf and self._LF) | (cr and self._CR) | (crlf and self._CRLF)
1965
+
1966
+ if self.translate:
1967
+ if crlf:
1968
+ output = output.replace('\r\n', '\n')
1969
+ if cr:
1970
+ output = output.replace('\r', '\n')
1971
+
1972
+ return output
1973
+
1974
+ def getstate(self):
1975
+ if self.decoder is None:
1976
+ buf = b''
1977
+ flag = 0
1978
+ else:
1979
+ buf, flag = self.decoder.getstate()
1980
+ flag <<= 1
1981
+ if self.pendingcr:
1982
+ flag |= 1
1983
+ return buf, flag
1984
+
1985
+ def setstate(self, state):
1986
+ buf, flag = state
1987
+ self.pendingcr = bool(flag & 1)
1988
+ if self.decoder is not None:
1989
+ self.decoder.setstate((buf, flag >> 1))
1990
+
1991
+ def reset(self):
1992
+ self.seennl = 0
1993
+ self.pendingcr = False
1994
+ if self.decoder is not None:
1995
+ self.decoder.reset()
1996
+
1997
+ _LF = 1
1998
+ _CR = 2
1999
+ _CRLF = 4
2000
+
2001
+ @property
2002
+ def newlines(self):
2003
+ return (
2004
+ None,
2005
+ '\n',
2006
+ '\r',
2007
+ ('\r', '\n'),
2008
+ '\r\n',
2009
+ ('\n', '\r\n'),
2010
+ ('\r', '\r\n'),
2011
+ ('\r', '\n', '\r\n'),
2012
+ )[self.seennl]
2013
+
2014
+
2015
+ class TextIOWrapper(TextIOBase):
2016
+ r"""
2017
+ Character and line based layer over a BufferedIOBase object, buffer.
2018
+
2019
+ encoding gives the name of the encoding that the stream will be decoded or encoded with. It defaults to
2020
+ locale.getencoding().
2021
+
2022
+ errors determines the strictness of encoding and decoding (see the codecs.register) and defaults to "strict".
2023
+
2024
+ newline can be None, '', '\n', '\r', or '\r\n'. It controls the handling of line endings. If it is None, universal
2025
+ newlines is enabled. With this enabled, on input, the lines endings '\n', '\r', or '\r\n' are translated to '\n'
2026
+ before being returned to the caller. Conversely, on output, '\n' is translated to the system default line separator,
2027
+ os.linesep. If newline is any other of its legal values, that newline becomes the newline when the file is read and
2028
+ it is returned untranslated. On output, '\n' is converted to the newline.
2029
+
2030
+ If line_buffering is True, a call to flush is implied when a call to write contains a newline character.
2031
+ """
2032
+
2033
+ _CHUNK_SIZE = 2048
2034
+
2035
+ # Initialize _buffer as soon as possible since it's used by __del__() which calls close()
2036
+ _buffer = None
2037
+
2038
+ # The write_through argument has no effect here since this implementation always writes through. The argument is
2039
+ # present only so that the signature can match the signature of the C version.
2040
+ def __init__(
2041
+ self,
2042
+ buffer,
2043
+ encoding=None,
2044
+ errors=None,
2045
+ newline=None,
2046
+ line_buffering=False,
2047
+ write_through=False,
2048
+ ):
2049
+ self._check_newline(newline)
2050
+ encoding = text_encoding(encoding)
2051
+
2052
+ if encoding == 'locale':
2053
+ encoding = self._get_locale_encoding()
2054
+
2055
+ if not isinstance(encoding, str):
2056
+ raise ValueError('invalid encoding: %r' % encoding)
2057
+
2058
+ if not codecs.lookup(encoding)._is_text_encoding:
2059
+ msg = (
2060
+ '%r is not a text encoding; '
2061
+ 'use codecs.open() to handle arbitrary codecs'
2062
+ )
2063
+ raise LookupError(msg % encoding)
2064
+
2065
+ if errors is None:
2066
+ errors = 'strict'
2067
+ else:
2068
+ if not isinstance(errors, str):
2069
+ raise ValueError('invalid errors: %r' % errors)
2070
+ if _CHECK_ERRORS:
2071
+ codecs.lookup_error(errors)
2072
+
2073
+ self._buffer = buffer
2074
+ self._decoded_chars = '' # buffer for text returned from decoder
2075
+ self._decoded_chars_used = 0 # offset into _decoded_chars for read()
2076
+ self._snapshot = None # info for reconstructing decoder state
2077
+ self._seekable = self._telling = self.buffer.seekable()
2078
+ self._has_read1 = hasattr(self.buffer, 'read1')
2079
+ self._configure(encoding, errors, newline, line_buffering, write_through)
2080
+
2081
+ def _check_newline(self, newline):
2082
+ if newline is not None and not isinstance(newline, str):
2083
+ raise TypeError('illegal newline type: %r' % (type(newline),))
2084
+ if newline not in (None, '', '\n', '\r', '\r\n'):
2085
+ raise ValueError('illegal newline value: %r' % (newline,))
2086
+
2087
+ def _configure(
2088
+ self,
2089
+ encoding=None,
2090
+ errors=None,
2091
+ newline=None,
2092
+ line_buffering=False,
2093
+ write_through=False,
2094
+ ):
2095
+ self._encoding = encoding
2096
+ self._errors = errors
2097
+ self._encoder = None
2098
+ self._decoder = None
2099
+ self._b2cratio = 0.0
2100
+
2101
+ self._readuniversal = not newline
2102
+ self._readtranslate = newline is None
2103
+ self._readnl = newline
2104
+ self._writetranslate = newline != ''
2105
+ self._writenl = newline or os.linesep
2106
+
2107
+ self._line_buffering = line_buffering
2108
+ self._write_through = write_through
2109
+
2110
+ # don't write a BOM in the middle of a file
2111
+ if self._seekable and self.writable():
2112
+ position = self.buffer.tell()
2113
+ if position != 0:
2114
+ try:
2115
+ self._get_encoder().setstate(0)
2116
+ except LookupError:
2117
+ # Sometimes the encoder doesn't exist
2118
+ pass
2119
+
2120
+ # self._snapshot is either None, or a tuple (dec_flags, next_input) where dec_flags is the second (integer) item of
2121
+ # the decoder state and next_input is the chunk of input bytes that comes next after the snapshot point. We use
2122
+ # this to reconstruct decoder states in tell().
2123
+
2124
+ # Naming convention:
2125
+ # - "bytes_..." for integer variables that count input bytes
2126
+ # - "chars_..." for integer variables that count decoded characters
2127
+
2128
+ def __repr__(self):
2129
+ result = f'<{self.__class__.__module__}.{self.__class__.__qualname__}'
2130
+ try:
2131
+ name = self.name
2132
+ except AttributeError:
2133
+ pass
2134
+ else:
2135
+ result += f' name={name!r}'
2136
+ try:
2137
+ mode = self.mode
2138
+ except AttributeError:
2139
+ pass
2140
+ else:
2141
+ result += f' mode={mode!r}'
2142
+ return result + f' encoding={self.encoding!r}>'
2143
+
2144
+ @property
2145
+ def encoding(self):
2146
+ return self._encoding
2147
+
2148
+ @property
2149
+ def errors(self):
2150
+ return self._errors
2151
+
2152
+ @property
2153
+ def line_buffering(self):
2154
+ return self._line_buffering
2155
+
2156
+ @property
2157
+ def write_through(self):
2158
+ return self._write_through
2159
+
2160
+ @property
2161
+ def buffer(self):
2162
+ return self._buffer
2163
+
2164
+ def reconfigure(
2165
+ self,
2166
+ *,
2167
+ encoding=None,
2168
+ errors=None,
2169
+ newline=Ellipsis,
2170
+ line_buffering=None,
2171
+ write_through=None,
2172
+ ):
2173
+ """
2174
+ Reconfigure the text stream with new parameters.
2175
+
2176
+ This also flushes the stream.
2177
+ """
2178
+
2179
+ if self._decoder is not None and (
2180
+ encoding is not None or errors is not None or newline is not Ellipsis
2181
+ ):
2182
+ raise UnsupportedOperation(
2183
+ 'It is not possible to set the encoding or newline of stream after the first read',
2184
+ )
2185
+
2186
+ if errors is None:
2187
+ if encoding is None:
2188
+ errors = self._errors
2189
+ else:
2190
+ errors = 'strict'
2191
+ elif not isinstance(errors, str):
2192
+ raise TypeError('invalid errors: %r' % errors)
2193
+
2194
+ if encoding is None:
2195
+ encoding = self._encoding
2196
+ else:
2197
+ if not isinstance(encoding, str):
2198
+ raise TypeError('invalid encoding: %r' % encoding)
2199
+ if encoding == 'locale':
2200
+ encoding = self._get_locale_encoding()
2201
+
2202
+ if newline is Ellipsis:
2203
+ newline = self._readnl
2204
+ self._check_newline(newline)
2205
+
2206
+ if line_buffering is None:
2207
+ line_buffering = self.line_buffering
2208
+ if write_through is None:
2209
+ write_through = self.write_through
2210
+
2211
+ self.flush()
2212
+ self._configure(encoding, errors, newline, line_buffering, write_through)
2213
+
2214
+ def seekable(self):
2215
+ if self.closed:
2216
+ raise ValueError('I/O operation on closed file.')
2217
+ return self._seekable
2218
+
2219
+ def readable(self):
2220
+ return self.buffer.readable()
2221
+
2222
+ def writable(self):
2223
+ return self.buffer.writable()
2224
+
2225
+ def flush(self):
2226
+ self.buffer.flush()
2227
+ self._telling = self._seekable
2228
+
2229
+ def close(self):
2230
+ if self.buffer is not None and not self.closed:
2231
+ try:
2232
+ self.flush()
2233
+ finally:
2234
+ self.buffer.close()
2235
+
2236
+ @property
2237
+ def closed(self):
2238
+ return self.buffer.closed
2239
+
2240
+ @property
2241
+ def name(self):
2242
+ return self.buffer.name
2243
+
2244
+ def fileno(self):
2245
+ return self.buffer.fileno()
2246
+
2247
+ def isatty(self):
2248
+ return self.buffer.isatty()
2249
+
2250
+ def write(self, s):
2251
+ """Write data, where s is a str"""
2252
+
2253
+ if self.closed:
2254
+ raise ValueError('write to closed file')
2255
+ if not isinstance(s, str):
2256
+ raise TypeError("can't write %s to text stream" % s.__class__.__name__)
2257
+ length = len(s)
2258
+ haslf = (self._writetranslate or self._line_buffering) and '\n' in s
2259
+ if haslf and self._writetranslate and self._writenl != '\n':
2260
+ s = s.replace('\n', self._writenl)
2261
+ encoder = self._encoder or self._get_encoder()
2262
+ # XXX What if we were just reading?
2263
+ b = encoder.encode(s)
2264
+ self.buffer.write(b)
2265
+ if self._line_buffering and (haslf or '\r' in s):
2266
+ self.flush()
2267
+ if self._snapshot is not None:
2268
+ self._set_decoded_chars('')
2269
+ self._snapshot = None
2270
+ if self._decoder:
2271
+ self._decoder.reset()
2272
+ return length
2273
+
2274
+ def _get_encoder(self):
2275
+ make_encoder = codecs.getincrementalencoder(self._encoding)
2276
+ self._encoder = make_encoder(self._errors)
2277
+ return self._encoder
2278
+
2279
+ def _get_decoder(self):
2280
+ make_decoder = codecs.getincrementaldecoder(self._encoding)
2281
+ decoder = make_decoder(self._errors)
2282
+ if self._readuniversal:
2283
+ decoder = IncrementalNewlineDecoder(decoder, self._readtranslate)
2284
+ self._decoder = decoder
2285
+ return decoder
2286
+
2287
+ # The following three methods implement an ADT for _decoded_chars. Text returned from the decoder is buffered here
2288
+ # until the client requests it by calling our read() or readline() method.
2289
+ def _set_decoded_chars(self, chars):
2290
+ """Set the _decoded_chars buffer."""
2291
+
2292
+ self._decoded_chars = chars
2293
+ self._decoded_chars_used = 0
2294
+
2295
+ def _get_decoded_chars(self, n=None):
2296
+ """Advance into the _decoded_chars buffer."""
2297
+
2298
+ offset = self._decoded_chars_used
2299
+ if n is None:
2300
+ chars = self._decoded_chars[offset:]
2301
+ else:
2302
+ chars = self._decoded_chars[offset: offset + n]
2303
+ self._decoded_chars_used += len(chars)
2304
+ return chars
2305
+
2306
+ def _get_locale_encoding(self):
2307
+ return locale.getencoding()
2308
+
2309
+ def _rewind_decoded_chars(self, n):
2310
+ """Rewind the _decoded_chars buffer."""
2311
+
2312
+ if self._decoded_chars_used < n:
2313
+ raise AssertionError('rewind decoded_chars out of bounds')
2314
+ self._decoded_chars_used -= n
2315
+
2316
+ def _read_chunk(self):
2317
+ """Read and decode the next chunk of data from the BufferedReader."""
2318
+
2319
+ # The return value is True unless EOF was reached. The decoded string is placed in self._decoded_chars
2320
+ # (replacing its previous value). The entire input chunk is sent to the decoder, though some of it may remain
2321
+ # buffered in the decoder, yet to be converted.
2322
+
2323
+ if self._decoder is None:
2324
+ raise ValueError('no decoder')
2325
+
2326
+ if self._telling:
2327
+ # To prepare for tell(), we need to snapshot a point in the file where the decoder's input buffer is empty.
2328
+
2329
+ dec_buffer, dec_flags = self._decoder.getstate()
2330
+
2331
+ # Given this, we know there was a valid snapshot point len(dec_buffer) bytes ago with decoder state (b'',
2332
+ # dec_flags).
2333
+
2334
+ # Read a chunk, decode it, and put the result in self._decoded_chars.
2335
+ if self._has_read1:
2336
+ input_chunk = self.buffer.read1(self._CHUNK_SIZE)
2337
+ else:
2338
+ input_chunk = self.buffer.read(self._CHUNK_SIZE)
2339
+ eof = not input_chunk
2340
+ decoded_chars = self._decoder.decode(input_chunk, eof)
2341
+ self._set_decoded_chars(decoded_chars)
2342
+ if decoded_chars:
2343
+ self._b2cratio = len(input_chunk) / len(self._decoded_chars)
2344
+ else:
2345
+ self._b2cratio = 0.0
2346
+
2347
+ if self._telling:
2348
+ # At the snapshot point, len(dec_buffer) bytes before the read, the next input to be decoded is dec_buffer +
2349
+ # input_chunk.
2350
+ self._snapshot = (dec_flags, dec_buffer + input_chunk)
2351
+
2352
+ return not eof
2353
+
2354
+ def _pack_cookie(
2355
+ self,
2356
+ position,
2357
+ dec_flags=0,
2358
+ bytes_to_feed=0,
2359
+ need_eof=False,
2360
+ chars_to_skip=0,
2361
+ ):
2362
+ # The meaning of a tell() cookie is: seek to position, set the decoder flags to dec_flags, read bytes_to_feed
2363
+ # bytes, feed them into the decoder with need_eof as the EOF flag, then skip chars_to_skip characters of the
2364
+ # decoded result. For most simple decoders, tell() will often just give a byte offset in the file.
2365
+ return (
2366
+ position
2367
+ | (dec_flags << 64)
2368
+ | (bytes_to_feed << 128)
2369
+ | (chars_to_skip << 192)
2370
+ | bool(need_eof) << 256
2371
+ )
2372
+
2373
+ def _unpack_cookie(self, bigint):
2374
+ rest, position = divmod(bigint, 1 << 64)
2375
+ rest, dec_flags = divmod(rest, 1 << 64)
2376
+ rest, bytes_to_feed = divmod(rest, 1 << 64)
2377
+ need_eof, chars_to_skip = divmod(rest, 1 << 64)
2378
+ return position, dec_flags, bytes_to_feed, bool(need_eof), chars_to_skip
2379
+
2380
+ def tell(self):
2381
+ if not self._seekable:
2382
+ raise UnsupportedOperation('underlying stream is not seekable')
2383
+ if not self._telling:
2384
+ raise OSError('telling position disabled by next() call')
2385
+ self.flush()
2386
+ position = self.buffer.tell()
2387
+ decoder = self._decoder
2388
+ if decoder is None or self._snapshot is None:
2389
+ if self._decoded_chars:
2390
+ # This should never happen.
2391
+ raise AssertionError('pending decoded text')
2392
+ return position
2393
+
2394
+ # Skip backward to the snapshot point (see _read_chunk).
2395
+ dec_flags, next_input = self._snapshot
2396
+ position -= len(next_input)
2397
+
2398
+ # How many decoded characters have been used up since the snapshot?
2399
+ chars_to_skip = self._decoded_chars_used
2400
+ if chars_to_skip == 0:
2401
+ # We haven't moved from the snapshot point.
2402
+ return self._pack_cookie(position, dec_flags)
2403
+
2404
+ # Starting from the snapshot position, we will walk the decoder forward until it gives us enough decoded
2405
+ # characters.
2406
+ saved_state = decoder.getstate()
2407
+ try:
2408
+ # Fast search for an acceptable start point, close to our current pos.
2409
+ # Rationale: calling decoder.decode() has a large overhead regardless of chunk size; we want the number of
2410
+ # such calls to be O(1) in most situations (common decoders, sensible input).
2411
+ # Actually, it will be exactly 1 for fixed-size codecs (all 8-bit codecs, also UTF-16 and UTF-32).
2412
+ skip_bytes = int(self._b2cratio * chars_to_skip)
2413
+ skip_back = 1
2414
+ assert skip_bytes <= len(next_input)
2415
+ while skip_bytes > 0:
2416
+ decoder.setstate((b'', dec_flags))
2417
+ # Decode up to temptative start point
2418
+ n = len(decoder.decode(next_input[:skip_bytes]))
2419
+ if n <= chars_to_skip:
2420
+ b, d = decoder.getstate()
2421
+ if not b:
2422
+ # Before pos and no bytes buffered in decoder => OK
2423
+ dec_flags = d
2424
+ chars_to_skip -= n
2425
+ break
2426
+ # Skip back by buffered amount and reset heuristic
2427
+ skip_bytes -= len(b)
2428
+ skip_back = 1
2429
+ else:
2430
+ # We're too far ahead, skip back a bit
2431
+ skip_bytes -= skip_back
2432
+ skip_back = skip_back * 2
2433
+ else:
2434
+ skip_bytes = 0
2435
+ decoder.setstate((b'', dec_flags))
2436
+
2437
+ # Note our initial start point.
2438
+ start_pos = position + skip_bytes
2439
+ start_flags = dec_flags
2440
+ if chars_to_skip == 0:
2441
+ # We haven't moved from the start point.
2442
+ return self._pack_cookie(start_pos, start_flags)
2443
+
2444
+ # Feed the decoder one byte at a time. As we go, note the nearest "safe start point" before the current
2445
+ # location (a point where the decoder has nothing buffered, so seek() can safely start from there and
2446
+ # advance to this location).
2447
+ bytes_fed = 0
2448
+ need_eof = False
2449
+ # Chars decoded since `start_pos`
2450
+ chars_decoded = 0
2451
+ for i in range(skip_bytes, len(next_input)):
2452
+ bytes_fed += 1
2453
+ chars_decoded += len(decoder.decode(next_input[i: i + 1]))
2454
+ dec_buffer, dec_flags = decoder.getstate()
2455
+ if not dec_buffer and chars_decoded <= chars_to_skip:
2456
+ # Decoder buffer is empty, so this is a safe start point.
2457
+ start_pos += bytes_fed
2458
+ chars_to_skip -= chars_decoded
2459
+ start_flags, bytes_fed, chars_decoded = dec_flags, 0, 0
2460
+ if chars_decoded >= chars_to_skip:
2461
+ break
2462
+ else:
2463
+ # We didn't get enough decoded data; signal EOF to get more.
2464
+ chars_decoded += len(decoder.decode(b'', final=True))
2465
+ need_eof = True
2466
+ if chars_decoded < chars_to_skip:
2467
+ raise OSError("can't reconstruct logical file position")
2468
+
2469
+ # The returned cookie corresponds to the last safe start point.
2470
+ return self._pack_cookie(
2471
+ start_pos,
2472
+ start_flags,
2473
+ bytes_fed,
2474
+ need_eof,
2475
+ chars_to_skip,
2476
+ )
2477
+ finally:
2478
+ decoder.setstate(saved_state)
2479
+
2480
+ def truncate(self, pos=None):
2481
+ self.flush()
2482
+ if pos is None:
2483
+ pos = self.tell()
2484
+ return self.buffer.truncate(pos)
2485
+
2486
+ def detach(self):
2487
+ if self.buffer is None:
2488
+ raise ValueError('buffer is already detached')
2489
+ self.flush()
2490
+ buffer = self._buffer
2491
+ self._buffer = None
2492
+ return buffer
2493
+
2494
+ def seek(self, cookie, whence=0):
2495
+ def _reset_encoder(position):
2496
+ """Reset the encoder (merely useful for proper BOM handling)"""
2497
+
2498
+ try:
2499
+ encoder = self._encoder or self._get_encoder()
2500
+ except LookupError:
2501
+ # Sometimes the encoder doesn't exist
2502
+ pass
2503
+ else:
2504
+ if position != 0:
2505
+ encoder.setstate(0)
2506
+ else:
2507
+ encoder.reset()
2508
+
2509
+ if self.closed:
2510
+ raise ValueError('tell on closed file')
2511
+ if not self._seekable:
2512
+ raise UnsupportedOperation('underlying stream is not seekable')
2513
+ if whence == io.SEEK_CUR:
2514
+ if cookie != 0:
2515
+ raise UnsupportedOperation("can't do nonzero cur-relative seeks")
2516
+ # Seeking to the current position should attempt to sync the underlying buffer with the current position.
2517
+ whence = 0
2518
+ cookie = self.tell()
2519
+ elif whence == io.SEEK_END:
2520
+ if cookie != 0:
2521
+ raise UnsupportedOperation("can't do nonzero end-relative seeks")
2522
+ self.flush()
2523
+ position = self.buffer.seek(0, whence)
2524
+ self._set_decoded_chars('')
2525
+ self._snapshot = None
2526
+ if self._decoder:
2527
+ self._decoder.reset()
2528
+ _reset_encoder(position)
2529
+ return position
2530
+ if whence != 0:
2531
+ raise ValueError('unsupported whence (%r)' % (whence,))
2532
+ if cookie < 0:
2533
+ raise ValueError('negative seek position %r' % (cookie,))
2534
+ self.flush()
2535
+
2536
+ # The strategy of seek() is to go back to the safe start point and replay the effect of read(chars_to_skip) from
2537
+ # there.
2538
+ start_pos, dec_flags, bytes_to_feed, need_eof, chars_to_skip = self._unpack_cookie(cookie)
2539
+
2540
+ # Seek back to the safe start point.
2541
+ self.buffer.seek(start_pos)
2542
+ self._set_decoded_chars('')
2543
+ self._snapshot = None
2544
+
2545
+ # Restore the decoder to its state from the safe start point.
2546
+ if cookie == 0 and self._decoder:
2547
+ self._decoder.reset()
2548
+ elif self._decoder or dec_flags or chars_to_skip:
2549
+ self._decoder = self._decoder or self._get_decoder()
2550
+ self._decoder.setstate((b'', dec_flags))
2551
+ self._snapshot = (dec_flags, b'')
2552
+
2553
+ if chars_to_skip:
2554
+ # Just like _read_chunk, feed the decoder and save a snapshot.
2555
+ input_chunk = self.buffer.read(bytes_to_feed)
2556
+ self._set_decoded_chars(self._decoder.decode(input_chunk, need_eof))
2557
+ self._snapshot = (dec_flags, input_chunk)
2558
+
2559
+ # Skip chars_to_skip of the decoded characters.
2560
+ if len(self._decoded_chars) < chars_to_skip:
2561
+ raise OSError("can't restore logical file position")
2562
+ self._decoded_chars_used = chars_to_skip
2563
+
2564
+ _reset_encoder(cookie)
2565
+ return cookie
2566
+
2567
+ def read(self, size=None):
2568
+ self._checkReadable()
2569
+
2570
+ if size is None:
2571
+ size = -1
2572
+ else:
2573
+ try:
2574
+ size_index = size.__index__
2575
+ except AttributeError:
2576
+ raise TypeError(f'{size!r} is not an integer')
2577
+ else:
2578
+ size = size_index()
2579
+
2580
+ decoder = self._decoder or self._get_decoder()
2581
+
2582
+ if size < 0:
2583
+ # Read everything.
2584
+ result = self._get_decoded_chars() + decoder.decode(self.buffer.read(), final=True)
2585
+ if self._snapshot is not None:
2586
+ self._set_decoded_chars('')
2587
+ self._snapshot = None
2588
+ return result
2589
+
2590
+ else:
2591
+ # Keep reading chunks until we have size characters to return.
2592
+ eof = False
2593
+ result = self._get_decoded_chars(size)
2594
+ while len(result) < size and not eof:
2595
+ eof = not self._read_chunk()
2596
+ result += self._get_decoded_chars(size - len(result))
2597
+ return result
2598
+
2599
+ def __next__(self):
2600
+ self._telling = False
2601
+ line = self.readline()
2602
+ if not line:
2603
+ self._snapshot = None
2604
+ self._telling = self._seekable
2605
+ raise StopIteration
2606
+ return line
2607
+
2608
+ def readline(self, size=None):
2609
+ if self.closed:
2610
+ raise ValueError('read from closed file')
2611
+ if size is None:
2612
+ size = -1
2613
+ else:
2614
+ try:
2615
+ size_index = size.__index__
2616
+ except AttributeError:
2617
+ raise TypeError(f'{size!r} is not an integer')
2618
+ else:
2619
+ size = size_index()
2620
+
2621
+ # Grab all the decoded text (we will rewind any extra bits later).
2622
+ line = self._get_decoded_chars()
2623
+
2624
+ start = 0
2625
+ # Make the decoder if it doesn't already exist.
2626
+ if not self._decoder:
2627
+ self._get_decoder()
2628
+
2629
+ pos = endpos = None
2630
+ while True:
2631
+ if self._readtranslate:
2632
+ # Newlines are already translated, only search for \n
2633
+ pos = line.find('\n', start)
2634
+ if pos >= 0:
2635
+ endpos = pos + 1
2636
+ break
2637
+ else:
2638
+ start = len(line)
2639
+
2640
+ elif self._readuniversal:
2641
+ # Universal newline search. Find any of \r, \r\n, \n
2642
+ # The decoder ensures that \r\n are not split in two pieces
2643
+
2644
+ # In C we'd look for these in parallel of course.
2645
+ nlpos = line.find('\n', start)
2646
+ crpos = line.find('\r', start)
2647
+ if crpos == -1:
2648
+ if nlpos == -1:
2649
+ # Nothing found
2650
+ start = len(line)
2651
+ else:
2652
+ # Found \n
2653
+ endpos = nlpos + 1
2654
+ break
2655
+ elif nlpos == -1:
2656
+ # Found lone \r
2657
+ endpos = crpos + 1
2658
+ break
2659
+ elif nlpos < crpos:
2660
+ # Found \n
2661
+ endpos = nlpos + 1
2662
+ break
2663
+ elif nlpos == crpos + 1:
2664
+ # Found \r\n
2665
+ endpos = crpos + 2
2666
+ break
2667
+ else:
2668
+ # Found \r
2669
+ endpos = crpos + 1
2670
+ break
2671
+ else:
2672
+ # non-universal
2673
+ pos = line.find(self._readnl)
2674
+ if pos >= 0:
2675
+ endpos = pos + len(self._readnl)
2676
+ break
2677
+
2678
+ if size >= 0 and len(line) >= size:
2679
+ endpos = size # reached length size
2680
+ break
2681
+
2682
+ # No line ending seen yet - get more data'
2683
+ while self._read_chunk():
2684
+ if self._decoded_chars:
2685
+ break
2686
+ if self._decoded_chars:
2687
+ line += self._get_decoded_chars()
2688
+ else:
2689
+ # end of file
2690
+ self._set_decoded_chars('')
2691
+ self._snapshot = None
2692
+ return line
2693
+
2694
+ if size >= 0 and endpos > size:
2695
+ endpos = size # don't exceed size
2696
+
2697
+ # Rewind _decoded_chars to just after the line ending we found.
2698
+ self._rewind_decoded_chars(len(line) - endpos)
2699
+ return line[:endpos]
2700
+
2701
+ @property
2702
+ def newlines(self):
2703
+ return self._decoder.newlines if self._decoder else None
2704
+
2705
+
2706
+ class StringIO(TextIOWrapper):
2707
+ """
2708
+ Text I/O implementation using an in-memory buffer.
2709
+
2710
+ The initial_value argument sets the value of object. The newline argument is like the one of TextIOWrapper's
2711
+ constructor.
2712
+ """
2713
+
2714
+ def __init__(self, initial_value='', newline='\n'):
2715
+ super().__init__(
2716
+ BytesIO(),
2717
+ encoding='utf-8',
2718
+ errors='surrogatepass',
2719
+ newline=newline,
2720
+ )
2721
+
2722
+ # Issue #5645: make universal newlines semantics the same as in the C version, even under Windows.
2723
+ if newline is None:
2724
+ self._writetranslate = False
2725
+ if initial_value is not None:
2726
+ if not isinstance(initial_value, str):
2727
+ raise TypeError(
2728
+ f'initial_value must be str or None, not {type(initial_value).__name__}',
2729
+ )
2730
+ self.write(initial_value)
2731
+ self.seek(0)
2732
+
2733
+ def getvalue(self):
2734
+ self.flush()
2735
+ decoder = self._decoder or self._get_decoder()
2736
+ old_state = decoder.getstate()
2737
+ decoder.reset()
2738
+ try:
2739
+ return decoder.decode(self.buffer.getvalue(), final=True)
2740
+ finally:
2741
+ decoder.setstate(old_state)
2742
+
2743
+ def __repr__(self):
2744
+ # TextIOWrapper tells the encoding in its repr. In StringIO, that's an implementation detail.
2745
+ return object.__repr__(self)
2746
+
2747
+ @property
2748
+ def errors(self):
2749
+ return None
2750
+
2751
+ @property
2752
+ def encoding(self):
2753
+ return None
2754
+
2755
+ def detach(self):
2756
+ # This doesn't make sense on StringIO.
2757
+ self._unsupported('detach')