merge the io-c branch: C implementation of the io module

The main io module now uses the C implementation.  The Python one still exists
in Lib/_pyio.py for ease of testing new features and usefulness to other
implementers.

The rewrite was done by Antoine Pitrou and Amaury Forgeot d'Arc.  I was slightly
helpful at the end. :)


Following are the log messages from the io-c branch:

Merged revisions 68683-68685,68687-68689,68693,68704,68741-68743,68745,68747,68752-68754,68756,68758,68812,68816-68817,68820-68822,68824-68825,68828,68876-68877,69037,69044,69104,69115,69194,69626-69629,69636,69638,69641-69642,69644-69654,69656-69661,69671,69677,69812-69815,69817,69827-69830,69839,69841-69845,69848,69850,69852,69854,69860,69865-69866,69868,69872-69873,69885,69888,69891-69893,69911,69913-69916,69963,70033,70035,70038,70041-70048,70067-70070,70075,70112,70133,70135,70140 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/io-c

........
  r68683 | antoine.pitrou | 2009-01-17 17:13:48 -0600 (Sat, 17 Jan 2009) | 3 lines

  Merge in changes from the io-c sandbox. Tests will follow in separate commits.
........
  r68684 | antoine.pitrou | 2009-01-17 17:17:26 -0600 (Sat, 17 Jan 2009) | 3 lines

  Fixes and additions to test_io.py
........
  r68685 | antoine.pitrou | 2009-01-17 17:22:04 -0600 (Sat, 17 Jan 2009) | 1 line

  Fix test_fileio
........
  r68687 | antoine.pitrou | 2009-01-17 17:35:11 -0600 (Sat, 17 Jan 2009) | 3 lines

  Add dependency to _iomodule.h for the various C sources
........
  r68688 | antoine.pitrou | 2009-01-17 17:38:18 -0600 (Sat, 17 Jan 2009) | 3 lines

  These precautions are not needed anymore!
........
  r68689 | antoine.pitrou | 2009-01-17 17:41:48 -0600 (Sat, 17 Jan 2009) | 3 lines

  Fix another test
........
  r68693 | antoine.pitrou | 2009-01-17 17:49:58 -0600 (Sat, 17 Jan 2009) | 3 lines

  Fix test_uu (which was using private attributes of TextIOWrapper)
........
  r68704 | antoine.pitrou | 2009-01-17 18:45:29 -0600 (Sat, 17 Jan 2009) | 3 lines

  Most io sources are Py_ssize_t-clean (I don't know about bytesio and stringio)
........
  r68741 | antoine.pitrou | 2009-01-18 15:20:30 -0600 (Sun, 18 Jan 2009) | 3 lines

  Check return type in TextIOWrapper.__next__
........
  r68742 | antoine.pitrou | 2009-01-18 15:28:48 -0600 (Sun, 18 Jan 2009) | 4 lines

  Make binary buffered readline and iteration much faster
  (8x as fast as the IOBase generic implementation)
........
  r68743 | antoine.pitrou | 2009-01-18 15:47:47 -0600 (Sun, 18 Jan 2009) | 3 lines

  Reinsert test_io_after_close (was removed by mistake)
........
  r68745 | antoine.pitrou | 2009-01-18 16:16:06 -0600 (Sun, 18 Jan 2009) | 3 lines

  Add read, read1 and write methods to BufferedIOBase
........
  r68747 | antoine.pitrou | 2009-01-18 16:35:58 -0600 (Sun, 18 Jan 2009) | 3 lines

  Kill test failure
........
  r68752 | amaury.forgeotdarc | 2009-01-18 17:05:43 -0600 (Sun, 18 Jan 2009) | 3 lines

  Fix a segfault when e.g a BufferedReader is created with a FileIO in
  read mode.
........
  r68753 | antoine.pitrou | 2009-01-18 17:13:09 -0600 (Sun, 18 Jan 2009) | 3 lines

  Add truncate() to text IO objects
........
  r68754 | antoine.pitrou | 2009-01-18 17:51:08 -0600 (Sun, 18 Jan 2009) | 3 lines

  Remove IOBase.__del__ and replace it with custom code with tp_dealloc
........
  r68756 | antoine.pitrou | 2009-01-18 18:10:16 -0600 (Sun, 18 Jan 2009) | 3 lines

  Remove irrelevant comment.
........
  r68758 | antoine.pitrou | 2009-01-18 18:36:16 -0600 (Sun, 18 Jan 2009) | 3 lines

  in importlib:_fileio._FileIO -> _io.FileIO
........
  r68812 | antoine.pitrou | 2009-01-20 14:15:51 -0600 (Tue, 20 Jan 2009) | 3 lines

  Add garbage collection support to FileIO objects
........
  r68816 | antoine.pitrou | 2009-01-20 14:56:28 -0600 (Tue, 20 Jan 2009) | 3 lines

  Add GC support to Buffered and Text IO objects
........
  r68817 | antoine.pitrou | 2009-01-20 15:19:45 -0600 (Tue, 20 Jan 2009) | 3 lines

  Add some file headers
........
  r68820 | antoine.pitrou | 2009-01-20 15:29:59 -0600 (Tue, 20 Jan 2009) | 3 lines

  Add class TextIOBase
........
  r68821 | antoine.pitrou | 2009-01-20 15:36:16 -0600 (Tue, 20 Jan 2009) | 3 lines

  Add properties to TextIOBase
........
  r68822 | antoine.pitrou | 2009-01-20 15:41:19 -0600 (Tue, 20 Jan 2009) | 3 lines

  Disable the pure Python TextIOBase class, and inject C the implementation instead
........
  r68824 | antoine.pitrou | 2009-01-20 16:36:28 -0600 (Tue, 20 Jan 2009) | 3 lines

  Fix two leaks
........
  r68825 | antoine.pitrou | 2009-01-20 16:38:29 -0600 (Tue, 20 Jan 2009) | 3 lines

  FileIO.name is just a plain attribute, we can set it directly
........
  r68828 | antoine.pitrou | 2009-01-20 17:06:33 -0600 (Tue, 20 Jan 2009) | 3 lines

  Speed up closed checks on text IO objects. Good for a 25% speedup on small ops.
........
  r68876 | antoine.pitrou | 2009-01-23 17:01:25 -0600 (Fri, 23 Jan 2009) | 3 lines

  Two typos
........
  r68877 | antoine.pitrou | 2009-01-23 18:13:20 -0600 (Fri, 23 Jan 2009) | 3 lines

  Remove two unused functions
........
  r69037 | amaury.forgeotdarc | 2009-01-27 17:10:25 -0600 (Tue, 27 Jan 2009) | 2 lines

  Update the win32 project files
........
  r69044 | antoine.pitrou | 2009-01-27 18:51:07 -0600 (Tue, 27 Jan 2009) | 3 lines

  Improve heuristic in IncrementalNewlineDecoder + some micro-optimizations
........
  r69104 | antoine.pitrou | 2009-01-29 15:23:42 -0600 (Thu, 29 Jan 2009) | 3 lines

  Fix some crashers found by Victor
........
  r69115 | hirokazu.yamamoto | 2009-01-29 20:36:28 -0600 (Thu, 29 Jan 2009) | 1 line

  Updated VC6 project file.
........
  r69194 | antoine.pitrou | 2009-02-01 16:57:18 -0600 (Sun, 01 Feb 2009) | 3 lines

  Fix downcasting warnings in 32-bit mode with 64-bit offsets (Windows)
........
  r69626 | benjamin.peterson | 2009-02-14 17:33:34 -0600 (Sat, 14 Feb 2009) | 1 line

  only catch AttributeError and UnsupportedOperation
........
  r69627 | benjamin.peterson | 2009-02-14 21:35:28 -0600 (Sat, 14 Feb 2009) | 1 line

  give the IO module its own state and store the os and locale modules in it
........
  r69628 | benjamin.peterson | 2009-02-14 22:08:32 -0600 (Sat, 14 Feb 2009) | 1 line

  put interned strings in the module state structure
........
  r69629 | benjamin.peterson | 2009-02-14 22:15:29 -0600 (Sat, 14 Feb 2009) | 1 line

  put UnsupportedOperation in the module state
........
  r69636 | benjamin.peterson | 2009-02-15 08:31:42 -0600 (Sun, 15 Feb 2009) | 1 line

  dealloc unsupported_operation
........
  r69638 | benjamin.peterson | 2009-02-15 09:24:45 -0600 (Sun, 15 Feb 2009) | 1 line

  actually test the C implementation
........
  r69641 | benjamin.peterson | 2009-02-15 10:12:37 -0600 (Sun, 15 Feb 2009) | 5 lines

  make interned strings globals again ;(

  putting them in the module state was asking for trouble when the module
  was dealloced before the classes in it were
........
  r69642 | benjamin.peterson | 2009-02-15 10:19:45 -0600 (Sun, 15 Feb 2009) | 1 line

  actually test the python implementations
........
  r69644 | antoine.pitrou | 2009-02-15 11:59:30 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix memory leak in destructor when a Python class inherits from IOBase (or an IOBase-derived type)
........
  r69645 | antoine.pitrou | 2009-02-15 12:23:26 -0600 (Sun, 15 Feb 2009) | 3 lines

  Add a warning about the embarassing state of IOBase finalization
........
  r69646 | antoine.pitrou | 2009-02-15 13:14:42 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix opening of 8-bit filenames with FileIO
........
  r69647 | antoine.pitrou | 2009-02-15 13:20:22 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix leak in FileIO constructor
........
  r69648 | antoine.pitrou | 2009-02-15 13:58:16 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix some refleaks
........
  r69649 | antoine.pitrou | 2009-02-15 14:05:13 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix a leak in IOBase.writelines
........
  r69650 | antoine.pitrou | 2009-02-15 14:11:56 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix memory leak in BufferedWriter.truncate
........
  r69651 | antoine.pitrou | 2009-02-15 14:25:34 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix a leak in TextIOWrapper.seek
........
  r69652 | antoine.pitrou | 2009-02-15 14:26:28 -0600 (Sun, 15 Feb 2009) | 3 lines

  Unify implementations of truncate for buffered objects
........
  r69653 | antoine.pitrou | 2009-02-15 15:15:15 -0600 (Sun, 15 Feb 2009) | 3 lines

  Fix more leaks in TextIOWrapper
........
  r69654 | antoine.pitrou | 2009-02-15 15:21:57 -0600 (Sun, 15 Feb 2009) | 3 lines

  Smaller chunk size for a faster test
........
  r69656 | benjamin.peterson | 2009-02-15 17:29:48 -0600 (Sun, 15 Feb 2009) | 1 line

  braces make this much clearer
........
  r69657 | benjamin.peterson | 2009-02-15 17:46:07 -0600 (Sun, 15 Feb 2009) | 1 line

  use the correct macro
........
  r69658 | antoine.pitrou | 2009-02-15 19:38:59 -0600 (Sun, 15 Feb 2009) | 5 lines

  Fix crash in test_urllib2_localnet in debug mode. It was due to an HTTPResponse
  object being revived when calling its close() method in IOBase's tp_dealloc.
  _PyIOBase_finalize() starts looking scary...
........
  r69659 | benjamin.peterson | 2009-02-15 20:55:48 -0600 (Sun, 15 Feb 2009) | 1 line

  fix segfault on initialization failing
........
  r69660 | benjamin.peterson | 2009-02-15 21:09:31 -0600 (Sun, 15 Feb 2009) | 1 line

  apparently locale.getprefferedencoding() can raise a ImportError, too
........
  r69661 | benjamin.peterson | 2009-02-15 21:54:15 -0600 (Sun, 15 Feb 2009) | 1 line

  it's amazing this worked at all; I was using the wrong structs!
........
  r69671 | benjamin.peterson | 2009-02-16 08:38:27 -0600 (Mon, 16 Feb 2009) | 1 line

  add garbage collection support to bytesio
........
  r69677 | benjamin.peterson | 2009-02-16 10:31:03 -0600 (Mon, 16 Feb 2009) | 5 lines

  reduce ImportError catching code duplication

  I'm not sure this makes the code clearer with its new gotos, but
  at least I added a big fat comment
........
  r69812 | antoine.pitrou | 2009-02-20 13:50:16 -0600 (Fri, 20 Feb 2009) | 3 lines

  _StringIO now belongs to the _io modules, rather to its own _stringio module
........
  r69813 | antoine.pitrou | 2009-02-20 13:58:22 -0600 (Fri, 20 Feb 2009) | 3 lines

  Add a test for StringIO properties
........
  r69814 | antoine.pitrou | 2009-02-20 14:06:03 -0600 (Fri, 20 Feb 2009) | 3 lines

  Reimplement a few trivial StringIO functions and properties in C
........
  r69815 | antoine.pitrou | 2009-02-20 14:13:11 -0600 (Fri, 20 Feb 2009) | 3 lines

  Add the line_buffering property to TextIOWrapper, and test for it
........
  r69817 | antoine.pitrou | 2009-02-20 14:45:50 -0600 (Fri, 20 Feb 2009) | 4 lines

  Allow IncrementalNewlineDecoder to take unicode objects as decoding input if the decoder parameter is None
  This will help rewriting StringIO to C
........
  r69827 | antoine.pitrou | 2009-02-20 19:00:30 -0600 (Fri, 20 Feb 2009) | 3 lines

  Rewrite most of StringIO in C. Some almost empty stubs remain to be converted.
........
  r69828 | antoine.pitrou | 2009-02-20 19:09:25 -0600 (Fri, 20 Feb 2009) | 3 lines

  Plug a leak, and remove an unused string
........
  r69829 | benjamin.peterson | 2009-02-20 20:02:28 -0600 (Fri, 20 Feb 2009) | 1 line

  this assertions makes more sense here
........
  r69830 | benjamin.peterson | 2009-02-20 20:03:04 -0600 (Fri, 20 Feb 2009) | 1 line

  PyModule_AddObject can fail; simplify this code with a macro
........
  r69839 | antoine.pitrou | 2009-02-21 12:54:01 -0600 (Sat, 21 Feb 2009) | 3 lines

  StringIO is now written entirely in C (and blazingly fast)
........
  r69841 | benjamin.peterson | 2009-02-21 14:05:40 -0600 (Sat, 21 Feb 2009) | 1 line

  split the Python implementation of io into another module and rewrite the tests to test both implementations
........
  r69842 | benjamin.peterson | 2009-02-21 14:10:00 -0600 (Sat, 21 Feb 2009) | 1 line

  closed is not a function
........
  r69843 | benjamin.peterson | 2009-02-21 14:13:04 -0600 (Sat, 21 Feb 2009) | 1 line

  fix __all__ test
........
  r69844 | benjamin.peterson | 2009-02-21 14:21:24 -0600 (Sat, 21 Feb 2009) | 1 line

  fix the rest of the Misc tests
........
  r69845 | benjamin.peterson | 2009-02-21 14:26:59 -0600 (Sat, 21 Feb 2009) | 1 line

  RawIOBase is better for FileIO
........
  r69848 | benjamin.peterson | 2009-02-21 15:33:53 -0600 (Sat, 21 Feb 2009) | 1 line

  fix some more tests broken by bag argument validation
........
  r69850 | benjamin.peterson | 2009-02-21 16:16:42 -0600 (Sat, 21 Feb 2009) | 1 line

  make the python IncrementalNewineDecoder support a None decoder
........
  r69852 | benjamin.peterson | 2009-02-21 16:36:09 -0600 (Sat, 21 Feb 2009) | 1 line

  fix a BlockingIOError.characters_written bug
........
  r69854 | benjamin.peterson | 2009-02-21 16:49:02 -0600 (Sat, 21 Feb 2009) | 1 line

  check whence
........
  r69860 | benjamin.peterson | 2009-02-21 17:42:50 -0600 (Sat, 21 Feb 2009) | 1 line

  fix some of these Misbehaving io tests
........
  r69865 | benjamin.peterson | 2009-02-21 18:59:52 -0600 (Sat, 21 Feb 2009) | 1 line

  don't use super here()
........
  r69866 | benjamin.peterson | 2009-02-21 19:05:28 -0600 (Sat, 21 Feb 2009) | 1 line

  use implementation specific classes
........
  r69868 | benjamin.peterson | 2009-02-21 22:12:05 -0600 (Sat, 21 Feb 2009) | 1 line

  use a more DRY friendly approach to injecting module contents into test classes
........
  r69872 | antoine.pitrou | 2009-02-22 13:39:45 -0600 (Sun, 22 Feb 2009) | 3 lines

  Sanitize destructor behaviour of IOBase. Now Python-defined attributes can be accessed from close().
........
  r69873 | antoine.pitrou | 2009-02-22 13:50:14 -0600 (Sun, 22 Feb 2009) | 4 lines

  Only set the internal fd after it has been checked to be valid
  (otherwise, the destructor will attempt to close it)
........
  r69885 | benjamin.peterson | 2009-02-22 15:30:14 -0600 (Sun, 22 Feb 2009) | 1 line

  convert some other tests to use both io implementations
........
  r69888 | antoine.pitrou | 2009-02-22 17:03:16 -0600 (Sun, 22 Feb 2009) | 3 lines

  Silence all exceptions when finalizing
........
  r69891 | benjamin.peterson | 2009-02-22 17:27:24 -0600 (Sun, 22 Feb 2009) | 1 line

  convert another test to test both io implementations
........
  r69892 | benjamin.peterson | 2009-02-22 17:32:15 -0600 (Sun, 22 Feb 2009) | 1 line

  help poor people like me to find their io tests (did I miss any?)
........
  r69893 | benjamin.peterson | 2009-02-22 17:37:56 -0600 (Sun, 22 Feb 2009) | 1 line

  put a big note in the test telling people to write tests for both implementations now
........
  r69911 | antoine.pitrou | 2009-02-23 13:57:18 -0600 (Mon, 23 Feb 2009) | 3 lines

  expose DEFAULT_BUFFER_SIZE again (fixes a bunch of test failures)
........
  r69913 | antoine.pitrou | 2009-02-23 14:10:30 -0600 (Mon, 23 Feb 2009) | 4 lines

  Do the cyclic garbage collection tests only on the C version.
  The Python version is helpless as it uses __del__.
........
  r69914 | antoine.pitrou | 2009-02-23 14:21:41 -0600 (Mon, 23 Feb 2009) | 3 lines

  Adapt test_largefile to test both implementations
........
  r69915 | antoine.pitrou | 2009-02-23 14:25:14 -0600 (Mon, 23 Feb 2009) | 3 lines

  One small failure
........
  r69916 | antoine.pitrou | 2009-02-23 14:28:33 -0600 (Mon, 23 Feb 2009) | 3 lines

  Add a comment, at BP's request
........
  r69963 | antoine.pitrou | 2009-02-25 09:42:59 -0600 (Wed, 25 Feb 2009) | 3 lines

  Add a test of ABC inheritance
........
  r70033 | antoine.pitrou | 2009-02-27 15:49:50 -0600 (Fri, 27 Feb 2009) | 3 lines

  The base classes now are ABCs.
........
  r70035 | benjamin.peterson | 2009-02-27 15:57:41 -0600 (Fri, 27 Feb 2009) | 1 line

  good house keeping
........
  r70038 | antoine.pitrou | 2009-02-27 17:05:23 -0600 (Fri, 27 Feb 2009) | 4 lines

  Make the buffer allocation overflow tests specific to the C implementation, since the Python implementation resizes its buffers when needed rather than allocating them up front.
........
  r70041 | benjamin.peterson | 2009-02-27 18:26:12 -0600 (Fri, 27 Feb 2009) | 1 line

  kill java naming for sanity
........
  r70042 | benjamin.peterson | 2009-02-27 18:28:53 -0600 (Fri, 27 Feb 2009) | 2 lines

  timingTest is superseded by iobench
........
  r70043 | antoine.pitrou | 2009-02-27 19:13:50 -0600 (Fri, 27 Feb 2009) | 3 lines

  Remove the last traces of java naming in test_io
........
  r70044 | antoine.pitrou | 2009-02-27 19:18:34 -0600 (Fri, 27 Feb 2009) | 3 lines

  Better resource cleanup
........
  r70045 | antoine.pitrou | 2009-02-27 19:29:00 -0600 (Fri, 27 Feb 2009) | 3 lines

  Remove dubious uses of super(), and fix one test
........
  r70046 | antoine.pitrou | 2009-02-27 19:31:00 -0600 (Fri, 27 Feb 2009) | 3 lines

  Bump up CHUNK_SIZE (no need to make the Python version look slower than it is)
........
  r70047 | benjamin.peterson | 2009-02-27 20:03:26 -0600 (Fri, 27 Feb 2009) | 1 line

  fix typo
........
  r70048 | benjamin.peterson | 2009-02-27 21:35:11 -0600 (Fri, 27 Feb 2009) | 1 line

  move code to a better place
........
  r70067 | benjamin.peterson | 2009-02-28 10:43:20 -0600 (Sat, 28 Feb 2009) | 4 lines

  1. make sure to undo buffered read aheads in BufferedRandom.seek()
  2. refill the buffer if have <= 0
  3. fix the last failing test_io test!
........
  r70068 | benjamin.peterson | 2009-02-28 10:57:50 -0600 (Sat, 28 Feb 2009) | 1 line

  define read1() on the python implementation's BufferedIOBase
........
  r70069 | benjamin.peterson | 2009-02-28 11:01:17 -0600 (Sat, 28 Feb 2009) | 1 line

  document read1() in BufferedIOBase
........
  r70070 | benjamin.peterson | 2009-02-28 11:06:42 -0600 (Sat, 28 Feb 2009) | 1 line

  give credit where credit is due
........
  r70075 | antoine.pitrou | 2009-02-28 13:34:59 -0600 (Sat, 28 Feb 2009) | 3 lines

  Amaury's name
........
  r70112 | antoine.pitrou | 2009-03-02 17:11:55 -0600 (Mon, 02 Mar 2009) | 4 lines

  Looks like this is necessary in order to build cleanly under Windows
  (someone correct this if it's wrong, I'm no Windows user)
........
  r70133 | benjamin.peterson | 2009-03-03 15:23:32 -0600 (Tue, 03 Mar 2009) | 1 line

  fix test_newline_property on _pyio.StringIO
........
  r70135 | benjamin.peterson | 2009-03-03 15:47:30 -0600 (Tue, 03 Mar 2009) | 1 line

  fix typos and inconsistencies. thanks to Daniel Diniz
........
  r70140 | benjamin.peterson | 2009-03-03 16:21:10 -0600 (Tue, 03 Mar 2009) | 1 line

  add the test from #5266
........
This commit is contained in:
Benjamin Peterson 2009-03-04 00:14:51 +00:00
parent 03ad812435
commit 4fa88fa0ba
30 changed files with 10295 additions and 2820 deletions

View File

@ -6,6 +6,8 @@
.. moduleauthor:: Guido van Rossum <guido@python.org>
.. moduleauthor:: Mike Verdone <mike.verdone@gmail.com>
.. moduleauthor:: Mark Russell <mark.russell@zen.co.uk>
.. moduleauthor:: Antoine Pitrou <solipsis@pitrou.net>
.. moduleauthor:: Amaury Forgeot d'Arc <amauryfa@gmail.com>
.. sectionauthor:: Benjamin Peterson <benjamin@python.org>
The :mod:`io` module provides the Python interfaces to stream handling. The
@ -364,6 +366,11 @@ I/O Base Classes
A :exc:`BlockingIOError` is raised if the underlying raw stream has no
data at the moment.
.. method:: read1([n])
Read and return up to *n* bytes, with at most one call to the underlying
raw stream's :meth:`~RawIOBase.read` method.
.. method:: readinto(b)
Read up to len(b) bytes into bytearray *b* and return the number of bytes
@ -501,7 +508,7 @@ Buffered Streams
The constructor creates a :class:`BufferedWriter` for the given writeable
*raw* stream. If the *buffer_size* is not given, it defaults to
:data:`DEAFULT_BUFFER_SIZE`. If *max_buffer_size* is omitted, it defaults to
:data:`DEFAULT_BUFFER_SIZE`. If *max_buffer_size* is omitted, it defaults to
twice the buffer size.
:class:`BufferedWriter` provides or overrides these methods in addition to

1831
Lib/_pyio.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -93,12 +93,12 @@ except ImportError:
except ImportError:
raise ImportError('posix, nt, or os2 module required for importlib')
_bootstrap._os = _os
import imp, sys, marshal, errno, _fileio
import imp, sys, marshal, errno, _io
_bootstrap.imp = imp
_bootstrap.sys = sys
_bootstrap.marshal = marshal
_bootstrap.errno = errno
_bootstrap._fileio = _fileio
_bootstrap._io = _io
import _warnings
_bootstrap._warnings = _warnings

View File

@ -473,7 +473,7 @@ class PyFileLoader(PyLoader):
if source_path is None:
return None
import tokenize
with closing(_fileio._FileIO(source_path, 'r')) as file:
with closing(_io.FileIO(source_path, 'r')) as file:
encoding, lines = tokenize.detect_encoding(file.readline)
# XXX Will fail when passed to compile() if the encoding is
# anything other than UTF-8.
@ -527,7 +527,7 @@ class PyPycFileLoader(PyPycLoader, PyFileLoader):
bytecode_path = self.bytecode_path(name)
if not bytecode_path:
bytecode_path = self._base_path + suffix_list(imp.PY_COMPILED)[0]
file = _fileio._FileIO(bytecode_path, 'w')
file = _io.FileIO(bytecode_path, 'w')
try:
with closing(file) as bytecode_file:
bytecode_file.write(data)

2122
Lib/io.py

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
import unittest
from test import support
# Simple test to ensure that optimizations in fileobject.c deliver
# the expected results. For best testing, run this under a debug-build
# Python too (to exercise asserts in the C code).
import io # C implementation.
import _pyio as pyio # Python implementation.
# Simple test to ensure that optimizations in the IO library deliver the
# expected results. For best testing, run this under a debug-build Python too
# (to exercise asserts in the C code).
lengths = list(range(1, 257)) + [512, 1000, 1024, 2048, 4096, 8192, 10000,
16384, 32768, 65536, 1000000]
@ -18,7 +21,7 @@ class BufferSizeTest(unittest.TestCase):
# Since C doesn't guarantee we can write/read arbitrary bytes in text
# files, use binary mode.
f = open(support.TESTFN, "wb")
f = self.open(support.TESTFN, "wb")
try:
# write once with \n and once without
f.write(s)
@ -58,8 +61,16 @@ class BufferSizeTest(unittest.TestCase):
def test_nullpat(self):
self.drive_one(bytes(1000))
class CBufferSizeTest(BufferSizeTest):
open = io.open
class PyBufferSizeTest(BufferSizeTest):
open = staticmethod(pyio.open)
def test_main():
support.run_unittest(BufferSizeTest)
support.run_unittest(CBufferSizeTest, PyBufferSizeTest)
if __name__ == "__main__":
test_main()

View File

@ -2605,10 +2605,10 @@ order (MRO) for bases """
def test_descrdoc(self):
# Testing descriptor doc strings...
from _fileio import _FileIO
from _io import FileIO
def check(descr, what):
self.assertEqual(descr.__doc__, what)
check(_FileIO.closed, "True if the file is closed") # getset descriptor
check(FileIO.closed, "True if the file is closed") # getset descriptor
check(complex.real, "the real part of a complex number") # member descriptor
def test_doc_descriptor(self):

View File

@ -4,6 +4,9 @@ import unittest
from array import array
from weakref import proxy
import io
import _pyio as pyio
from test.support import TESTFN, findfile, run_unittest
from collections import UserList
@ -11,7 +14,7 @@ class AutoFileTests(unittest.TestCase):
# file tests for which a test file is automatically set up
def setUp(self):
self.f = open(TESTFN, 'wb')
self.f = self.open(TESTFN, 'wb')
def tearDown(self):
if self.f:
@ -39,7 +42,7 @@ class AutoFileTests(unittest.TestCase):
self.f.write(b'12')
self.f.close()
a = array('b', b'x'*10)
self.f = open(TESTFN, 'rb')
self.f = self.open(TESTFN, 'rb')
n = self.f.readinto(a)
self.assertEquals(b'12', a.tostring()[:n])
@ -47,7 +50,7 @@ class AutoFileTests(unittest.TestCase):
# verify readinto refuses text files
a = array('b', b'x'*10)
self.f.close()
self.f = open(TESTFN, 'r')
self.f = self.open(TESTFN, 'r')
if hasattr(self.f, "readinto"):
self.assertRaises(TypeError, self.f.readinto, a)
@ -56,7 +59,7 @@ class AutoFileTests(unittest.TestCase):
l = UserList([b'1', b'2'])
self.f.writelines(l)
self.f.close()
self.f = open(TESTFN, 'rb')
self.f = self.open(TESTFN, 'rb')
buf = self.f.read()
self.assertEquals(buf, b'12')
@ -126,13 +129,20 @@ class AutoFileTests(unittest.TestCase):
def testReadWhenWriting(self):
self.assertRaises(IOError, self.f.read)
class CAutoFileTests(AutoFileTests):
open = io.open
class PyAutoFileTests(AutoFileTests):
open = staticmethod(pyio.open)
class OtherFileTests(unittest.TestCase):
def testModeStrings(self):
# check invalid mode strings
for mode in ("", "aU", "wU+"):
try:
f = open(TESTFN, mode)
f = self.open(TESTFN, mode)
except ValueError:
pass
else:
@ -153,7 +163,7 @@ class OtherFileTests(unittest.TestCase):
# verify that we get a sensible error message for bad mode argument
bad_mode = "qwerty"
try:
f = open(TESTFN, bad_mode)
f = self.open(TESTFN, bad_mode)
except ValueError as msg:
if msg.args[0] != 0:
s = str(msg)
@ -170,11 +180,11 @@ class OtherFileTests(unittest.TestCase):
# misbehaviour especially with repeated close() calls
for s in (-1, 0, 1, 512):
try:
f = open(TESTFN, 'wb', s)
f = self.open(TESTFN, 'wb', s)
f.write(str(s).encode("ascii"))
f.close()
f.close()
f = open(TESTFN, 'rb', s)
f = self.open(TESTFN, 'rb', s)
d = int(f.read().decode("ascii"))
f.close()
f.close()
@ -187,13 +197,13 @@ class OtherFileTests(unittest.TestCase):
# "file.truncate fault on windows"
os.unlink(TESTFN)
f = open(TESTFN, 'wb')
f = self.open(TESTFN, 'wb')
try:
f.write(b'12345678901') # 11 bytes
f.close()
f = open(TESTFN,'rb+')
f = self.open(TESTFN,'rb+')
data = f.read(5)
if data != b'12345':
self.fail("Read on file opened for update failed %r" % data)
@ -233,13 +243,13 @@ class OtherFileTests(unittest.TestCase):
try:
# Prepare the testfile
bag = open(TESTFN, "wb")
bag = self.open(TESTFN, "wb")
bag.write(filler * nchunks)
bag.writelines(testlines)
bag.close()
# Test for appropriate errors mixing read* and iteration
for methodname, args in methods:
f = open(TESTFN, 'rb')
f = self.open(TESTFN, 'rb')
if next(f) != filler:
self.fail, "Broken testfile"
meth = getattr(f, methodname)
@ -253,7 +263,7 @@ class OtherFileTests(unittest.TestCase):
# ("h", "a", "m", "\n"), so 4096 lines of that should get us
# exactly on the buffer boundary for any power-of-2 buffersize
# between 4 and 16384 (inclusive).
f = open(TESTFN, 'rb')
f = self.open(TESTFN, 'rb')
for i in range(nchunks):
next(f)
testline = testlines.pop(0)
@ -295,7 +305,7 @@ class OtherFileTests(unittest.TestCase):
self.fail("readlines() after next() with empty buffer "
"failed. Got %r, expected %r" % (line, testline))
# Reading after iteration hit EOF shouldn't hurt either
f = open(TESTFN, 'rb')
f = self.open(TESTFN, 'rb')
try:
for line in f:
pass
@ -311,12 +321,19 @@ class OtherFileTests(unittest.TestCase):
finally:
os.unlink(TESTFN)
class COtherFileTests(OtherFileTests):
open = io.open
class PyOtherFileTests(OtherFileTests):
open = staticmethod(pyio.open)
def test_main():
# Historically, these tests have been sloppy about removing TESTFN.
# So get rid of it no matter what.
try:
run_unittest(AutoFileTests, OtherFileTests)
run_unittest(CAutoFileTests, PyAutoFileTests,
COtherFileTests, PyOtherFileTests)
finally:
if os.path.exists(TESTFN):
os.unlink(TESTFN)

View File

@ -10,13 +10,13 @@ from test.support import (TESTFN, findfile, check_warnings, run_unittest,
make_bad_fd)
from collections import UserList
import _fileio
from _io import FileIO as _FileIO
class AutoFileTests(unittest.TestCase):
# file tests for which a test file is automatically set up
def setUp(self):
self.f = _fileio._FileIO(TESTFN, 'w')
self.f = _FileIO(TESTFN, 'w')
def tearDown(self):
if self.f:
@ -63,13 +63,13 @@ class AutoFileTests(unittest.TestCase):
self.f.write(bytes([1, 2]))
self.f.close()
a = array('b', b'x'*10)
self.f = _fileio._FileIO(TESTFN, 'r')
self.f = _FileIO(TESTFN, 'r')
n = self.f.readinto(a)
self.assertEquals(array('b', [1, 2]), a[:n])
def testRepr(self):
self.assertEquals(repr(self.f),
"_fileio._FileIO(%d, %s)" % (self.f.fileno(),
"io.FileIO(%d, %s)" % (self.f.fileno(),
repr(self.f.mode)))
def testErrors(self):
@ -80,7 +80,7 @@ class AutoFileTests(unittest.TestCase):
self.assertRaises(ValueError, f.read, 10) # Open for reading
f.close()
self.assert_(f.closed)
f = _fileio._FileIO(TESTFN, 'r')
f = _FileIO(TESTFN, 'r')
self.assertRaises(TypeError, f.readinto, "")
self.assert_(not f.closed)
f.close()
@ -106,7 +106,7 @@ class AutoFileTests(unittest.TestCase):
# Windows always returns "[Errno 13]: Permission denied
# Unix calls dircheck() and returns "[Errno 21]: Is a directory"
try:
_fileio._FileIO('.', 'r')
_FileIO('.', 'r')
except IOError as e:
self.assertNotEqual(e.errno, 0)
self.assertEqual(e.filename, ".")
@ -118,19 +118,19 @@ class OtherFileTests(unittest.TestCase):
def testAbles(self):
try:
f = _fileio._FileIO(TESTFN, "w")
f = _FileIO(TESTFN, "w")
self.assertEquals(f.readable(), False)
self.assertEquals(f.writable(), True)
self.assertEquals(f.seekable(), True)
f.close()
f = _fileio._FileIO(TESTFN, "r")
f = _FileIO(TESTFN, "r")
self.assertEquals(f.readable(), True)
self.assertEquals(f.writable(), False)
self.assertEquals(f.seekable(), True)
f.close()
f = _fileio._FileIO(TESTFN, "a+")
f = _FileIO(TESTFN, "a+")
self.assertEquals(f.readable(), True)
self.assertEquals(f.writable(), True)
self.assertEquals(f.seekable(), True)
@ -139,14 +139,14 @@ class OtherFileTests(unittest.TestCase):
if sys.platform != "win32":
try:
f = _fileio._FileIO("/dev/tty", "a")
f = _FileIO("/dev/tty", "a")
except EnvironmentError:
# When run in a cron job there just aren't any
# ttys, so skip the test. This also handles other
# OS'es that don't support /dev/tty.
pass
else:
f = _fileio._FileIO("/dev/tty", "a")
f = _FileIO("/dev/tty", "a")
self.assertEquals(f.readable(), False)
self.assertEquals(f.writable(), True)
if sys.platform != "darwin" and \
@ -163,7 +163,7 @@ class OtherFileTests(unittest.TestCase):
# check invalid mode strings
for mode in ("", "aU", "wU+", "rw", "rt"):
try:
f = _fileio._FileIO(TESTFN, mode)
f = _FileIO(TESTFN, mode)
except ValueError:
pass
else:
@ -172,10 +172,26 @@ class OtherFileTests(unittest.TestCase):
def testUnicodeOpen(self):
# verify repr works for unicode too
f = _fileio._FileIO(str(TESTFN), "w")
f = _FileIO(str(TESTFN), "w")
f.close()
os.unlink(TESTFN)
def testBytesOpen(self):
# Opening a bytes filename
try:
fn = TESTFN.encode("ascii")
except UnicodeEncodeError:
# Skip test
return
f = _FileIO(fn, "w")
try:
f.write(b"abc")
f.close()
with open(TESTFN, "rb") as f:
self.assertEquals(f.read(), b"abc")
finally:
os.unlink(TESTFN)
def testInvalidFd(self):
self.assertRaises(ValueError, _fileio._FileIO, -10)
self.assertRaises(OSError, _fileio._FileIO, make_bad_fd())
@ -184,7 +200,7 @@ class OtherFileTests(unittest.TestCase):
# verify that we get a sensible error message for bad mode argument
bad_mode = "qwerty"
try:
f = _fileio._FileIO(TESTFN, bad_mode)
f = _FileIO(TESTFN, bad_mode)
except ValueError as msg:
if msg.args[0] != 0:
s = str(msg)
@ -200,11 +216,11 @@ class OtherFileTests(unittest.TestCase):
def bug801631():
# SF bug <http://www.python.org/sf/801631>
# "file.truncate fault on windows"
f = _fileio._FileIO(TESTFN, 'w')
f = _FileIO(TESTFN, 'w')
f.write(bytes(range(11)))
f.close()
f = _fileio._FileIO(TESTFN,'r+')
f = _FileIO(TESTFN,'r+')
data = f.read(5)
if data != bytes(range(5)):
self.fail("Read on file opened for update failed %r" % data)
@ -244,14 +260,14 @@ class OtherFileTests(unittest.TestCase):
pass
def testInvalidInit(self):
self.assertRaises(TypeError, _fileio._FileIO, "1", 0, 0)
self.assertRaises(TypeError, _FileIO, "1", 0, 0)
def testWarnings(self):
with check_warnings() as w:
self.assertEqual(w.warnings, [])
self.assertRaises(TypeError, _fileio._FileIO, [])
self.assertRaises(TypeError, _FileIO, [])
self.assertEqual(w.warnings, [])
self.assertRaises(ValueError, _fileio._FileIO, "/some/invalid/name", "rt")
self.assertRaises(ValueError, _FileIO, "/some/invalid/name", "rt")
self.assertEqual(w.warnings, [])

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,8 @@ import sys
import unittest
from test.support import run_unittest, TESTFN, verbose, requires, \
TestSkipped, unlink
import io # C implementation of io
import _pyio as pyio # Python implementation of io
try:
import signal
@ -21,7 +23,7 @@ except (ImportError, AttributeError):
size = 2500000000
class TestCase(unittest.TestCase):
class LargeFileTest(unittest.TestCase):
"""Test that each file function works as expected for a large
(i.e. > 2GB, do we have to check > 4GB) files.
@ -34,7 +36,7 @@ class TestCase(unittest.TestCase):
def test_seek(self):
if verbose:
print('create large file via seek (may be sparse file) ...')
with open(TESTFN, 'wb') as f:
with self.open(TESTFN, 'wb') as f:
f.write(b'z')
f.seek(0)
f.seek(size)
@ -52,7 +54,7 @@ class TestCase(unittest.TestCase):
def test_seek_read(self):
if verbose:
print('play around with seek() and read() with the built largefile')
with open(TESTFN, 'rb') as f:
with self.open(TESTFN, 'rb') as f:
self.assertEqual(f.tell(), 0)
self.assertEqual(f.read(1), b'z')
self.assertEqual(f.tell(), 1)
@ -85,7 +87,7 @@ class TestCase(unittest.TestCase):
def test_lseek(self):
if verbose:
print('play around with os.lseek() with the built largefile')
with open(TESTFN, 'rb') as f:
with self.open(TESTFN, 'rb') as f:
self.assertEqual(os.lseek(f.fileno(), 0, 0), 0)
self.assertEqual(os.lseek(f.fileno(), 42, 0), 42)
self.assertEqual(os.lseek(f.fileno(), 42, 1), 84)
@ -100,7 +102,7 @@ class TestCase(unittest.TestCase):
def test_truncate(self):
if verbose:
print('try truncate')
with open(TESTFN, 'r+b') as f:
with self.open(TESTFN, 'r+b') as f:
# this is already decided before start running the test suite
# but we do it anyway for extra protection
if not hasattr(f, 'truncate'):
@ -143,7 +145,7 @@ def test_main():
# Only run if the current filesystem supports large files.
# (Skip this test on Windows, since we now always support
# large files.)
f = open(TESTFN, 'wb')
f = open(TESTFN, 'wb', buffering=0)
try:
# 2**31 == 2147483648
f.seek(2147483649)
@ -158,14 +160,19 @@ def test_main():
else:
f.close()
suite = unittest.TestSuite()
suite.addTest(TestCase('test_seek'))
suite.addTest(TestCase('test_osstat'))
suite.addTest(TestCase('test_seek_read'))
suite.addTest(TestCase('test_lseek'))
with open(TESTFN, 'w') as f:
if hasattr(f, 'truncate'):
suite.addTest(TestCase('test_truncate'))
unlink(TESTFN)
for _open, prefix in [(io.open, 'C'), (pyio.open, 'Py')]:
class TestCase(LargeFileTest):
pass
TestCase.open = staticmethod(_open)
TestCase.__name__ = prefix + LargeFileTest.__name__
suite.addTest(TestCase('test_seek'))
suite.addTest(TestCase('test_osstat'))
suite.addTest(TestCase('test_seek_read'))
suite.addTest(TestCase('test_lseek'))
with _open(TESTFN, 'wb') as f:
if hasattr(f, 'truncate'):
suite.addTest(TestCase('test_truncate'))
unlink(TESTFN)
try:
run_unittest(suite)
finally:

View File

@ -7,13 +7,52 @@ import unittest
from test import support
import io
import _pyio as pyio
import sys
try:
import _bytesio, _stringio
has_c_implementation = True
except ImportError:
has_c_implementation = False
class MemorySeekTestMixin:
def testInit(self):
buf = self.buftype("1234567890")
bytesIo = self.ioclass(buf)
def testRead(self):
buf = self.buftype("1234567890")
bytesIo = self.ioclass(buf)
self.assertEquals(buf[:1], bytesIo.read(1))
self.assertEquals(buf[1:5], bytesIo.read(4))
self.assertEquals(buf[5:], bytesIo.read(900))
self.assertEquals(self.EOF, bytesIo.read())
def testReadNoArgs(self):
buf = self.buftype("1234567890")
bytesIo = self.ioclass(buf)
self.assertEquals(buf, bytesIo.read())
self.assertEquals(self.EOF, bytesIo.read())
def testSeek(self):
buf = self.buftype("1234567890")
bytesIo = self.ioclass(buf)
bytesIo.read(5)
bytesIo.seek(0)
self.assertEquals(buf, bytesIo.read())
bytesIo.seek(3)
self.assertEquals(buf[3:], bytesIo.read())
self.assertRaises(TypeError, bytesIo.seek, 0.0)
def testTell(self):
buf = self.buftype("1234567890")
bytesIo = self.ioclass(buf)
self.assertEquals(0, bytesIo.tell())
bytesIo.seek(5)
self.assertEquals(5, bytesIo.tell())
bytesIo.seek(10000)
self.assertEquals(10000, bytesIo.tell())
class MemoryTestMixin:
@ -148,7 +187,7 @@ class MemoryTestMixin:
self.assertEqual(memio.readline(), self.EOF)
memio.seek(0)
self.assertEqual(type(memio.readline()), type(buf))
self.assertEqual(memio.readline(None), buf)
self.assertEqual(memio.readline(), buf)
self.assertRaises(TypeError, memio.readline, '')
memio.close()
self.assertRaises(ValueError, memio.readline)
@ -296,11 +335,11 @@ class MemoryTestMixin:
self.assertEqual(test2(), buf)
class PyBytesIOTest(MemoryTestMixin, unittest.TestCase):
class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
@staticmethod
def buftype(s):
return s.encode("ascii")
ioclass = io._BytesIO
ioclass = pyio.BytesIO
EOF = b""
def test_read1(self):
@ -371,11 +410,32 @@ class PyBytesIOTest(MemoryTestMixin, unittest.TestCase):
self.assertEqual(memio.getvalue(), buf)
class PyStringIOTest(MemoryTestMixin, unittest.TestCase):
class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
buftype = str
ioclass = io._StringIO
ioclass = pyio.StringIO
EOF = ""
# TextIO-specific behaviour.
def test_newlines_property(self):
memio = self.ioclass(newline=None)
# The C StringIO decodes newlines in write() calls, but the Python
# implementation only does when reading. This function forces them to
# be decoded for testing.
def force_decode():
memio.seek(0)
memio.read()
self.assertEqual(memio.newlines, None)
memio.write("a\n")
force_decode()
self.assertEqual(memio.newlines, "\n")
memio.write("b\r\n")
force_decode()
self.assertEqual(memio.newlines, ("\n", "\r\n"))
memio.write("c\rd")
force_decode()
self.assertEqual(memio.newlines, ("\r", "\n", "\r\n"))
def test_relative_seek(self):
memio = self.ioclass()
@ -386,32 +446,99 @@ class PyStringIOTest(MemoryTestMixin, unittest.TestCase):
self.assertRaises(IOError, memio.seek, 1, 1)
self.assertRaises(IOError, memio.seek, 1, 2)
def test_textio_properties(self):
memio = self.ioclass()
# These are just dummy values but we nevertheless check them for fear
# of unexpected breakage.
self.assertEqual(memio.encoding, "utf-8")
self.assertEqual(memio.errors, "strict")
self.assertEqual(memio.line_buffering, False)
def test_newline_none(self):
# newline=None
memio = self.ioclass("a\nb\r\nc\rd", newline=None)
self.assertEqual(list(memio), ["a\n", "b\n", "c\n", "d"])
memio.seek(0)
self.assertEqual(memio.read(1), "a")
self.assertEqual(memio.read(2), "\nb")
self.assertEqual(memio.read(2), "\nc")
self.assertEqual(memio.read(1), "\n")
memio = self.ioclass(newline=None)
self.assertEqual(2, memio.write("a\n"))
self.assertEqual(3, memio.write("b\r\n"))
self.assertEqual(3, memio.write("c\rd"))
memio.seek(0)
self.assertEqual(memio.read(), "a\nb\nc\nd")
memio = self.ioclass("a\r\nb", newline=None)
self.assertEqual(memio.read(3), "a\nb")
def test_newline_empty(self):
# newline=""
memio = self.ioclass("a\nb\r\nc\rd", newline="")
self.assertEqual(list(memio), ["a\n", "b\r\n", "c\r", "d"])
memio.seek(0)
self.assertEqual(memio.read(4), "a\nb\r")
self.assertEqual(memio.read(2), "\nc")
self.assertEqual(memio.read(1), "\r")
memio = self.ioclass(newline="")
self.assertEqual(2, memio.write("a\n"))
self.assertEqual(2, memio.write("b\r"))
self.assertEqual(2, memio.write("\nc"))
self.assertEqual(2, memio.write("\rd"))
memio.seek(0)
self.assertEqual(list(memio), ["a\n", "b\r\n", "c\r", "d"])
def test_newline_lf(self):
# newline="\n"
memio = self.ioclass("a\nb\r\nc\rd")
self.assertEqual(list(memio), ["a\n", "b\r\n", "c\rd"])
def test_newline_cr(self):
# newline="\r"
memio = self.ioclass("a\nb\r\nc\rd", newline="\r")
memio.seek(0)
self.assertEqual(memio.read(), "a\rb\r\rc\rd")
memio.seek(0)
self.assertEqual(list(memio), ["a\r", "b\r", "\r", "c\r", "d"])
def test_newline_crlf(self):
# newline="\r\n"
memio = self.ioclass("a\nb\r\nc\rd", newline="\r\n")
memio.seek(0)
self.assertEqual(memio.read(), "a\r\nb\r\r\nc\rd")
memio.seek(0)
self.assertEqual(list(memio), ["a\r\n", "b\r\r\n", "c\rd"])
def test_issue5265(self):
# StringIO can duplicate newlines in universal newlines mode
memio = self.ioclass("a\r\nb\r\n", newline=None)
self.assertEqual(memio.read(5), "a\nb\n")
class CBytesIOTest(PyBytesIOTest):
ioclass = io.BytesIO
class CStringIOTest(PyStringIOTest):
ioclass = io.StringIO
# XXX: For the Python version of io.StringIO, this is highly
# dependent on the encoding used for the underlying buffer.
# def test_widechar(self):
# buf = self.buftype("\U0002030a\U00020347")
# memio = self.ioclass(buf)
#
# self.assertEqual(memio.getvalue(), buf)
# self.assertEqual(memio.write(buf), len(buf))
# self.assertEqual(memio.tell(), len(buf))
# self.assertEqual(memio.getvalue(), buf)
# self.assertEqual(memio.write(buf), len(buf))
# self.assertEqual(memio.tell(), len(buf) * 2)
# self.assertEqual(memio.getvalue(), buf + buf)
def test_widechar(self):
buf = self.buftype("\U0002030a\U00020347")
memio = self.ioclass(buf)
if has_c_implementation:
class CBytesIOTest(PyBytesIOTest):
ioclass = io.BytesIO
class CStringIOTest(PyStringIOTest):
ioclass = io.StringIO
self.assertEqual(memio.getvalue(), buf)
self.assertEqual(memio.write(buf), len(buf))
self.assertEqual(memio.tell(), len(buf))
self.assertEqual(memio.getvalue(), buf)
self.assertEqual(memio.write(buf), len(buf))
self.assertEqual(memio.tell(), len(buf) * 2)
self.assertEqual(memio.getvalue(), buf + buf)
def test_main():
tests = [PyBytesIOTest, PyStringIOTest]
if has_c_implementation:
tests.extend([CBytesIOTest, CStringIOTest])
tests = [PyBytesIOTest, PyStringIOTest, CBytesIOTest, CStringIOTest]
support.run_unittest(*tests)
if __name__ == '__main__':

View File

@ -1,4 +1,6 @@
# Tests universal newline support for both reading and parsing files.
import io
import _pyio as pyio
import unittest
import os
import sys
@ -35,7 +37,7 @@ class TestGenericUnivNewlines(unittest.TestCase):
WRITEMODE = 'wb'
def setUp(self):
fp = open(support.TESTFN, self.WRITEMODE)
fp = self.open(support.TESTFN, self.WRITEMODE)
data = self.DATA
if "b" in self.WRITEMODE:
data = data.encode("ascii")
@ -49,19 +51,19 @@ class TestGenericUnivNewlines(unittest.TestCase):
pass
def test_read(self):
fp = open(support.TESTFN, self.READMODE)
fp = self.open(support.TESTFN, self.READMODE)
data = fp.read()
self.assertEqual(data, DATA_LF)
self.assertEqual(repr(fp.newlines), repr(self.NEWLINE))
def test_readlines(self):
fp = open(support.TESTFN, self.READMODE)
fp = self.open(support.TESTFN, self.READMODE)
data = fp.readlines()
self.assertEqual(data, DATA_SPLIT)
self.assertEqual(repr(fp.newlines), repr(self.NEWLINE))
def test_readline(self):
fp = open(support.TESTFN, self.READMODE)
fp = self.open(support.TESTFN, self.READMODE)
data = []
d = fp.readline()
while d:
@ -71,7 +73,7 @@ class TestGenericUnivNewlines(unittest.TestCase):
self.assertEqual(repr(fp.newlines), repr(self.NEWLINE))
def test_seek(self):
fp = open(support.TESTFN, self.READMODE)
fp = self.open(support.TESTFN, self.READMODE)
fp.readline()
pos = fp.tell()
data = fp.readlines()
@ -94,7 +96,7 @@ class TestCRLFNewlines(TestGenericUnivNewlines):
DATA = DATA_CRLF
def test_tell(self):
fp = open(support.TESTFN, self.READMODE)
fp = self.open(support.TESTFN, self.READMODE)
self.assertEqual(repr(fp.newlines), repr(None))
data = fp.readline()
pos = fp.tell()
@ -106,12 +108,22 @@ class TestMixedNewlines(TestGenericUnivNewlines):
def test_main():
support.run_unittest(
TestCRNewlines,
TestLFNewlines,
TestCRLFNewlines,
TestMixedNewlines
)
base_tests = (TestCRNewlines,
TestLFNewlines,
TestCRLFNewlines,
TestMixedNewlines)
tests = []
# Test the C and Python implementations.
for test in base_tests:
class CTest(test):
open = io.open
CTest.__name__ = "C" + test.__name__
class PyTest(test):
open = staticmethod(pyio.open)
PyTest.__name__ = "Py" + test.__name__
tests.append(CTest)
tests.append(PyTest)
support.run_unittest(*tests)
if __name__ == '__main__':
test_main()

View File

@ -32,6 +32,8 @@ class FakeIO(io.TextIOWrapper):
encoding=encoding,
errors=errors,
newline=newline)
self._encoding = encoding
self._errors = errors
if initial_value:
if not isinstance(initial_value, str):
initial_value = str(initial_value)

View File

@ -193,6 +193,15 @@ MODULE_OBJS= \
# Used of signalmodule.o is not available
SIGNAL_OBJS= @SIGNAL_OBJS@
IO_H= Modules/_iomodule.h
IO_OBJS= \
Modules/io.o \
Modules/_iobase.o \
Modules/_fileio.o \
Modules/_bufferedio.o \
Modules/_textio.o \
Modules/_bytesio.o
##########################################################################
# Grammar
@ -521,6 +530,7 @@ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
Modules/python.o: $(srcdir)/Modules/python.c
$(MAINCC) -c $(PY_CFLAGS) -o $@ $(srcdir)/Modules/python.c
$(IO_OBJS): $(IO_H)
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
-@$(INSTALL) -d Include

View File

@ -14,6 +14,8 @@ Core and Builtins
=======
- The io module has been reimplemented in C for speed.
- Give dict views an informative __repr__.
- Issue #5247: Improve error message when unknown format codes are

View File

@ -111,10 +111,10 @@ pwd pwdmodule.c # this is needed to find out the user's home dir
# if $HOME is not set
_sre _sre.c # Fredrik Lundh's new regular expressions
_codecs _codecsmodule.c # access to the builtin codecs and codec registry
_fileio _fileio.c # Standard I/O baseline
_weakref _weakref.c # weak references
_bytesio _bytesio.c # For Lib/io.py
_stringio _stringio.c # For Lib/io.py
# Standard I/O baseline
_io io.c _iobase.c _fileio.c _bytesio.c _bufferedio.c _textio.c _stringio.c
# The zipimport module is always imported at startup. Having it as a
# builtin module avoids some bootstrapping problems and reduces overhead.
@ -164,7 +164,6 @@ _symtable symtablemodule.c
#_collections _collectionsmodule.c # Container types
#itertools itertoolsmodule.c # Functions creating iterators for efficient looping
#atexit atexitmodule.c # Register functions to be run at interpreter-shutdown
#_functools _functoolsmodule.c # Tools for working with functions and callable objects
#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator
#_pickle _pickle.c # pickle accelerator
#datetime datetimemodule.c # date/time type

2130
Modules/_bufferedio.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
#include "Python.h"
#include "structmember.h" /* for offsetof() */
#include "_iomodule.h"
typedef struct {
PyObject_HEAD
@ -6,6 +8,8 @@ typedef struct {
Py_ssize_t pos;
Py_ssize_t string_size;
size_t buf_size;
PyObject *dict;
PyObject *weakreflist;
} BytesIOObject;
#define CHECK_CLOSED(self) \
@ -144,10 +148,12 @@ write_bytes(BytesIOObject *self, const char *bytes, Py_ssize_t len)
static PyObject *
bytesio_get_closed(BytesIOObject *self)
{
if (self->buf == NULL)
if (self->buf == NULL) {
Py_RETURN_TRUE;
else
}
else {
Py_RETURN_FALSE;
}
}
/* Generic getter for the writable, readable and seekable properties */
@ -532,22 +538,22 @@ PyDoc_STRVAR(write_doc,
static PyObject *
bytesio_write(BytesIOObject *self, PyObject *obj)
{
const char *bytes;
Py_ssize_t size;
Py_ssize_t n = 0;
Py_buffer buf;
PyObject *result = NULL;
CHECK_CLOSED(self);
if (PyObject_AsReadBuffer(obj, (void *)&bytes, &size) < 0)
if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0)
return NULL;
if (size != 0) {
n = write_bytes(self, bytes, size);
if (n < 0)
return NULL;
}
if (buf.len != 0)
n = write_bytes(self, buf.buf, buf.len);
if (n >= 0)
result = PyLong_FromSsize_t(n);
return PyLong_FromSsize_t(n);
PyBuffer_Release(&buf);
return result;
}
PyDoc_STRVAR(writelines_doc,
@ -607,6 +613,7 @@ bytesio_dealloc(BytesIOObject *self)
PyMem_Free(self->buf);
self->buf = NULL;
}
Py_TYPE(self)->tp_clear((PyObject *)self);
Py_TYPE(self)->tp_free(self);
}
@ -656,6 +663,24 @@ bytesio_init(BytesIOObject *self, PyObject *args, PyObject *kwds)
return 0;
}
static int
bytesio_traverse(BytesIOObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->dict);
Py_VISIT(self->weakreflist);
return 0;
}
static int
bytesio_clear(BytesIOObject *self)
{
Py_CLEAR(self->dict);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
return 0;
}
static PyGetSetDef bytesio_getsetlist[] = {
{"closed", (getter)bytesio_get_closed, NULL,
"True if the file is closed."},
@ -689,9 +714,9 @@ PyDoc_STRVAR(bytesio_doc,
"Create a buffered I/O implementation using an in-memory bytes\n"
"buffer, ready for reading and writing.");
static PyTypeObject BytesIO_Type = {
PyTypeObject PyBytesIO_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_bytesio._BytesIO", /*tp_name*/
"_io.BytesIO", /*tp_name*/
sizeof(BytesIOObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)bytesio_dealloc, /*tp_dealloc*/
@ -709,12 +734,13 @@ static PyTypeObject BytesIO_Type = {
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /*tp_flags*/
bytesio_doc, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
(traverseproc)bytesio_traverse, /*tp_traverse*/
(inquiry)bytesio_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(BytesIOObject, weakreflist), /*tp_weaklistoffset*/
PyObject_SelfIter, /*tp_iter*/
(iternextfunc)bytesio_iternext, /*tp_iternext*/
bytesio_methods, /*tp_methods*/
@ -724,36 +750,8 @@ static PyTypeObject BytesIO_Type = {
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
offsetof(BytesIOObject, dict), /*tp_dictoffset*/
(initproc)bytesio_init, /*tp_init*/
0, /*tp_alloc*/
bytesio_new, /*tp_new*/
};
static struct PyModuleDef _bytesiomodule = {
PyModuleDef_HEAD_INIT,
"_bytesio",
NULL,
-1,
NULL,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__bytesio(void)
{
PyObject *m;
if (PyType_Ready(&BytesIO_Type) < 0)
return NULL;
m = PyModule_Create(&_bytesiomodule);
if (m == NULL)
return NULL;
Py_INCREF(&BytesIO_Type);
PyModule_AddObject(m, "_BytesIO", (PyObject *)&BytesIO_Type);
return m;
}

View File

@ -6,6 +6,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <stddef.h> /* For offsetof */
#include "_iomodule.h"
/*
* Known likely problems:
@ -49,14 +50,19 @@ typedef struct {
int seekable : 2; /* -1 means unknown */
int closefd : 1;
PyObject *weakreflist;
PyObject *dict;
} PyFileIOObject;
PyTypeObject PyFileIO_Type;
#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
static PyObject *
portable_lseek(int fd, PyObject *posobj, int whence);
int
_PyFileIO_closed(PyObject *self)
{
return ((PyFileIOObject *)self)->fd < 0;
}
/* Returns 0 on success, -1 with exception set on failure. */
static int
@ -88,14 +94,18 @@ fileio_close(PyFileIOObject *self)
self->fd = -1;
Py_RETURN_NONE;
}
if (internal_close(self))
errno = internal_close(self);
if (errno < 0) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_RETURN_NONE;
return PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,
"close", "O", self);
}
static PyObject *
fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyFileIOObject *self;
@ -119,7 +129,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
directories, so we need a check. */
static int
dircheck(PyFileIOObject* self, char *name)
dircheck(PyFileIOObject* self, const char *name)
{
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf;
@ -146,7 +156,7 @@ check_fd(int fd)
{
#if defined(HAVE_FSTAT)
struct stat buf;
if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
if (fstat(fd, &buf) < 0 && errno == EBADF) {
PyObject *exc;
char *msg = strerror(EBADF);
exc = PyObject_CallFunction(PyExc_OSError, "(is)",
@ -165,7 +175,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
{
PyFileIOObject *self = (PyFileIOObject *) oself;
static char *kwlist[] = {"file", "mode", "closefd", NULL};
char *name = NULL;
const char *name = NULL;
PyObject *nameobj;
char *mode = "r";
char *s;
#ifdef MS_WINDOWS
@ -184,42 +195,58 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
return -1;
}
if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
kwlist, &fd, &mode, &closefd)) {
if (fd < 0) {
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",
kwlist, &nameobj, &mode, &closefd))
return -1;
if (PyFloat_Check(nameobj)) {
PyErr_SetString(PyExc_TypeError,
"integer argument expected, got float");
return -1;
}
fd = PyLong_AsLong(nameobj);
if (fd < 0) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError,
"Negative filedescriptor");
return -1;
}
if (check_fd(fd))
return -1;
}
else {
PyErr_Clear();
}
#ifdef Py_WIN_WIDE_FILENAMES
if (GetVersion() < 0x80000000) {
if (GetVersion() < 0x80000000) {
/* On NT, so wide API available */
PyObject *po;
if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
kwlist, &po, &mode, &closefd)
) {
widename = PyUnicode_AS_UNICODE(po);
} else {
/* Drop the argument parsing error as narrow
strings are also valid. */
PyErr_Clear();
}
}
if (widename == NULL)
if (PyUnicode_Check(nameobj))
widename = PyUnicode_AS_UNICODE(nameobj);
}
if (widename == NULL)
#endif
{
if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
kwlist,
Py_FileSystemDefaultEncoding,
&name, &mode, &closefd))
return -1;
}
if (fd < 0)
{
if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {
if (PyObject_AsCharBuffer(nameobj, &name, NULL) < 0)
return -1;
}
else {
PyObject *s;
PyObject *u = PyUnicode_FromObject(nameobj);
if (u == NULL)
return -1;
s = PyUnicode_AsEncodedString(
u, Py_FileSystemDefaultEncoding, NULL);
Py_DECREF(u);
if (s == NULL)
return -1;
if (!PyBytes_Check(s)) {
PyErr_SetString(PyExc_TypeError,
"encoder failed to return bytes");
}
name = PyBytes_AS_STRING(s);
}
}
s = mode;
@ -287,6 +314,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
if (fd >= 0) {
self->fd = fd;
self->closefd = closefd;
if (check_fd(fd))
goto error;
}
else {
self->closefd = 1;
@ -318,15 +347,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
goto error;
}
if (append) {
/* For consistent behaviour, we explicitly seek to the
end of file (otherwise, it might be done only on the
first write()). */
PyObject *pos = portable_lseek(self->fd, NULL, 2);
if (pos == NULL)
goto error;
Py_DECREF(pos);
}
if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)
goto error;
goto done;
@ -334,21 +356,32 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
ret = -1;
done:
PyMem_Free(name);
return ret;
}
static int
fileio_traverse(PyFileIOObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->dict);
return 0;
}
static int
fileio_clear(PyFileIOObject *self)
{
Py_CLEAR(self->dict);
return 0;
}
static void
fileio_dealloc(PyFileIOObject *self)
{
if (_PyIOBase_finalize((PyObject *) self) < 0)
return;
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
if (self->fd >= 0 && self->closefd) {
if(internal_close(self))
PyErr_WriteUnraisable((PyObject*)self);
}
Py_CLEAR(self->dict);
Py_TYPE(self)->tp_free((PyObject *)self);
}
@ -437,6 +470,31 @@ fileio_readinto(PyFileIOObject *self, PyObject *args)
return PyLong_FromSsize_t(n);
}
static size_t
new_buffersize(PyFileIOObject *self, size_t currentsize)
{
#ifdef HAVE_FSTAT
off_t pos, end;
struct stat st;
if (fstat(self->fd, &st) == 0) {
end = st.st_size;
pos = lseek(self->fd, 0L, SEEK_CUR);
if (end >= pos && pos >= 0)
return currentsize + end - pos + 1;
/* Add 1 so if the file were to grow we'd notice. */
}
#endif
if (currentsize > SMALLCHUNK) {
/* Keep doubling until we reach BIGCHUNK;
then keep adding BIGCHUNK. */
if (currentsize <= BIGCHUNK)
return currentsize + currentsize;
else
return currentsize + BIGCHUNK;
}
return currentsize + SMALLCHUNK;
}
static PyObject *
fileio_readall(PyFileIOObject *self)
{
@ -449,17 +507,7 @@ fileio_readall(PyFileIOObject *self)
return NULL;
while (1) {
Py_ssize_t newsize = (total < SMALLCHUNK) ? SMALLCHUNK : total;
/* Keep doubling until we reach BIGCHUNK;
then keep adding BIGCHUNK. */
if (newsize <= BIGCHUNK) {
newsize += newsize;
}
else {
/* NOTE: overflow impossible due to limits on BUFSIZ */
newsize += BIGCHUNK;
}
Py_ssize_t newsize = new_buffersize(self, total);
if (PyBytes_GET_SIZE(result) < newsize) {
if (_PyBytes_Resize(&result, newsize) < 0) {
@ -583,12 +631,6 @@ fileio_write(PyFileIOObject *self, PyObject *args)
/* XXX Windows support below is likely incomplete */
#if defined(MS_WIN64) || defined(MS_WINDOWS)
typedef PY_LONG_LONG Py_off_t;
#else
typedef off_t Py_off_t;
#endif
/* Cribbed from posix_lseek() */
static PyObject *
portable_lseek(int fd, PyObject *posobj, int whence)
@ -755,9 +797,9 @@ static PyObject *
fileio_repr(PyFileIOObject *self)
{
if (self->fd < 0)
return PyUnicode_FromFormat("_fileio._FileIO(-1)");
return PyUnicode_FromFormat("io.FileIO(-1)");
return PyUnicode_FromFormat("_fileio._FileIO(%d, '%s')",
return PyUnicode_FromFormat("io.FileIO(%d, '%s')",
self->fd, mode_string(self));
}
@ -899,15 +941,15 @@ static PyGetSetDef fileio_getsetlist[] = {
};
PyTypeObject PyFileIO_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"_FileIO",
PyVarObject_HEAD_INIT(NULL, 0)
"FileIO",
sizeof(PyFileIOObject),
0,
(destructor)fileio_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_compare */
(reprfunc)fileio_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@ -918,10 +960,11 @@ PyTypeObject PyFileIO_Type = {
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
fileio_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(traverseproc)fileio_traverse, /* tp_traverse */
(inquiry)fileio_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(PyFileIOObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
@ -933,40 +976,9 @@ PyTypeObject PyFileIO_Type = {
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
offsetof(PyFileIOObject, dict), /* tp_dictoffset */
fileio_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
fileio_new, /* tp_new */
PyObject_Del, /* tp_free */
PyObject_GC_Del, /* tp_free */
};
static PyMethodDef module_methods[] = {
{NULL, NULL}
};
static struct PyModuleDef fileiomodule = {
PyModuleDef_HEAD_INIT,
"_fileio",
"Fast implementation of io.FileIO.",
-1,
module_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__fileio(void)
{
PyObject *m; /* a module object */
m = PyModule_Create(&fileiomodule);
if (m == NULL)
return NULL;
if (PyType_Ready(&PyFileIO_Type) < 0)
return NULL;
Py_INCREF(&PyFileIO_Type);
PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type);
return m;
}

905
Modules/_iobase.c Normal file
View File

@ -0,0 +1,905 @@
/*
An implementation of the I/O abstract base classes hierarchy
as defined by PEP 3116 - "New I/O"
Classes defined here: IOBase, RawIOBase.
Written by Amaury Forgeot d'Arc and Antoine Pitrou
*/
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#include "_iomodule.h"
/*
* IOBase class, an abstract class
*/
typedef struct {
PyObject_HEAD
PyObject *dict;
PyObject *weakreflist;
} IOBaseObject;
PyDoc_STRVAR(IOBase_doc,
"The abstract base class for all I/O classes, acting on streams of\n"
"bytes. There is no public constructor.\n"
"\n"
"This class provides dummy implementations for many methods that\n"
"derived classes can override selectively; the default implementations\n"
"represent a file that cannot be read, written or seeked.\n"
"\n"
"Even though IOBase does not declare read, readinto, or write because\n"
"their signatures will vary, implementations and clients should\n"
"consider those methods part of the interface. Also, implementations\n"
"may raise a IOError when operations they do not support are called.\n"
"\n"
"The basic type used for binary data read from or written to a file is\n"
"bytes. bytearrays are accepted too, and in some cases (such as\n"
"readinto) needed. Text I/O classes work with str data.\n"
"\n"
"Note that calling any method (even inquiries) on a closed stream is\n"
"undefined. Implementations may raise IOError in this case.\n"
"\n"
"IOBase (and its subclasses) support the iterator protocol, meaning\n"
"that an IOBase object can be iterated over yielding the lines in a\n"
"stream.\n"
"\n"
"IOBase also supports the :keyword:`with` statement. In this example,\n"
"fp is closed after the suite of the with statment is complete:\n"
"\n"
"with open('spam.txt', 'r') as fp:\n"
" fp.write('Spam and eggs!')\n");
/* Use this macro whenever you want to check the internal `closed` status
of the IOBase object rather than the virtual `closed` attribute as returned
by whatever subclass. */
#define IS_CLOSED(self) \
PyObject_HasAttrString(self, "__IOBase_closed")
/* Internal methods */
static PyObject *
IOBase_unsupported(const char *message)
{
PyErr_SetString(IO_STATE->unsupported_operation, message);
return NULL;
}
/* Positionning */
PyDoc_STRVAR(IOBase_seek_doc,
"Change stream position.\n"
"\n"
"Change the stream position to byte offset offset. offset is\n"
"interpreted relative to the position indicated by whence. Values\n"
"for whence are:\n"
"\n"
"* 0 -- start of stream (the default); offset should be zero or positive\n"
"* 1 -- current stream position; offset may be negative\n"
"* 2 -- end of stream; offset is usually negative\n"
"\n"
"Return the new absolute position.");
static PyObject *
IOBase_seek(PyObject *self, PyObject *args)
{
return IOBase_unsupported("seek");
}
PyDoc_STRVAR(IOBase_tell_doc,
"Return current stream position.");
static PyObject *
IOBase_tell(PyObject *self, PyObject *args)
{
return PyObject_CallMethod(self, "seek", "ii", 0, 1);
}
PyDoc_STRVAR(IOBase_truncate_doc,
"Truncate file to size bytes.\n"
"\n"
"Size defaults to the current IO position as reported by tell(). Return\n"
"the new size.");
static PyObject *
IOBase_truncate(PyObject *self, PyObject *args)
{
return IOBase_unsupported("truncate");
}
/* Flush and close methods */
PyDoc_STRVAR(IOBase_flush_doc,
"Flush write buffers, if applicable.\n"
"\n"
"This is not implemented for read-only and non-blocking streams.\n");
static PyObject *
IOBase_flush(PyObject *self, PyObject *args)
{
/* XXX Should this return the number of bytes written??? */
if (IS_CLOSED(self)) {
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
return NULL;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(IOBase_close_doc,
"Flush and close the IO object.\n"
"\n"
"This method has no effect if the file is already closed.\n");
static int
IOBase_closed(PyObject *self)
{
PyObject *res;
int closed;
/* This gets the derived attribute, which is *not* __IOBase_closed
in most cases! */
res = PyObject_GetAttr(self, _PyIO_str_closed);
if (res == NULL)
return 0;
closed = PyObject_IsTrue(res);
Py_DECREF(res);
return closed;
}
static PyObject *
IOBase_closed_get(PyObject *self, void *context)
{
return PyBool_FromLong(IS_CLOSED(self));
}
PyObject *
_PyIOBase_checkClosed(PyObject *self, PyObject *args)
{
if (IOBase_closed(self)) {
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
return NULL;
}
if (args == Py_True)
return Py_None;
else
Py_RETURN_NONE;
}
/* XXX: IOBase thinks it has to maintain its own internal state in
`__IOBase_closed` and call flush() by itself, but it is redundant with
whatever behaviour a non-trivial derived class will implement. */
static PyObject *
IOBase_close(PyObject *self, PyObject *args)
{
PyObject *res;
if (IS_CLOSED(self))
Py_RETURN_NONE;
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
if (res == NULL) {
/* If flush() fails, just give up */
if (PyErr_ExceptionMatches(PyExc_IOError))
PyErr_Clear();
else
return NULL;
}
Py_XDECREF(res);
Py_RETURN_NONE;
}
/* Finalization and garbage collection support */
int
_PyIOBase_finalize(PyObject *self)
{
PyObject *res;
PyObject *tp, *v, *tb;
int closed = 1;
int is_zombie;
/* If _PyIOBase_finalize() is called from a destructor, we need to
resurrect the object as calling close() can invoke arbitrary code. */
is_zombie = (Py_REFCNT(self) == 0);
if (is_zombie) {
++Py_REFCNT(self);
}
PyErr_Fetch(&tp, &v, &tb);
/* If `closed` doesn't exist or can't be evaluated as bool, then the
object is probably in an unusable state, so ignore. */
res = PyObject_GetAttr(self, _PyIO_str_closed);
if (res == NULL)
PyErr_Clear();
else {
closed = PyObject_IsTrue(res);
Py_DECREF(res);
if (closed == -1)
PyErr_Clear();
}
if (closed == 0) {
res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
NULL);
/* Silencing I/O errors is bad, but printing spurious tracebacks is
equally as bad, and potentially more frequent (because of
shutdown issues). */
if (res == NULL)
PyErr_Clear();
else
Py_DECREF(res);
}
PyErr_Restore(tp, v, tb);
if (is_zombie) {
if (--Py_REFCNT(self) != 0) {
/* The object lives again. The following code is taken from
slot_tp_del in typeobject.c. */
Py_ssize_t refcnt = Py_REFCNT(self);
_Py_NewReference(self);
Py_REFCNT(self) = refcnt;
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
* we need to undo that. */
_Py_DEC_REFTOTAL;
/* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
* chain, so no more to do there.
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
* _Py_NewReference bumped tp_allocs: both of those need to be
* undone.
*/
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
--Py_TYPE(self)->tp_allocs;
#endif
return -1;
}
}
return 0;
}
static int
IOBase_traverse(IOBaseObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->dict);
return 0;
}
static int
IOBase_clear(IOBaseObject *self)
{
if (_PyIOBase_finalize((PyObject *) self) < 0)
return -1;
Py_CLEAR(self->dict);
return 0;
}
/* Destructor */
static void
IOBase_dealloc(IOBaseObject *self)
{
/* NOTE: since IOBaseObject has its own dict, Python-defined attributes
are still available here for close() to use.
However, if the derived class declares a __slots__, those slots are
already gone.
*/
if (_PyIOBase_finalize((PyObject *) self) < 0) {
/* When called from a heap type's dealloc, the type will be
decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */
if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE))
Py_INCREF(Py_TYPE(self));
return;
}
_PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->dict);
Py_TYPE(self)->tp_free((PyObject *) self);
}
/* Inquiry methods */
PyDoc_STRVAR(IOBase_seekable_doc,
"Return whether object supports random access.\n"
"\n"
"If False, seek(), tell() and truncate() will raise IOError.\n"
"This method may need to do a test seek().");
static PyObject *
IOBase_seekable(PyObject *self, PyObject *args)
{
Py_RETURN_FALSE;
}
PyObject *
_PyIOBase_checkSeekable(PyObject *self, PyObject *args)
{
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_seekable, NULL);
if (res == NULL)
return NULL;
if (res != Py_True) {
Py_CLEAR(res);
PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
return NULL;
}
if (args == Py_True) {
Py_DECREF(res);
}
return res;
}
PyDoc_STRVAR(IOBase_readable_doc,
"Return whether object was opened for reading.\n"
"\n"
"If False, read() will raise IOError.");
static PyObject *
IOBase_readable(PyObject *self, PyObject *args)
{
Py_RETURN_FALSE;
}
/* May be called with any object */
PyObject *
_PyIOBase_checkReadable(PyObject *self, PyObject *args)
{
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_readable, NULL);
if (res == NULL)
return NULL;
if (res != Py_True) {
Py_CLEAR(res);
PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
return NULL;
}
if (args == Py_True) {
Py_DECREF(res);
}
return res;
}
PyDoc_STRVAR(IOBase_writable_doc,
"Return whether object was opened for writing.\n"
"\n"
"If False, read() will raise IOError.");
static PyObject *
IOBase_writable(PyObject *self, PyObject *args)
{
Py_RETURN_FALSE;
}
/* May be called with any object */
PyObject *
_PyIOBase_checkWritable(PyObject *self, PyObject *args)
{
PyObject *res = PyObject_CallMethodObjArgs(self, _PyIO_str_writable, NULL);
if (res == NULL)
return NULL;
if (res != Py_True) {
Py_CLEAR(res);
PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
return NULL;
}
if (args == Py_True) {
Py_DECREF(res);
}
return res;
}
/* Context manager */
static PyObject *
IOBase_enter(PyObject *self, PyObject *args)
{
if (_PyIOBase_checkClosed(self, Py_True) == NULL)
return NULL;
Py_INCREF(self);
return self;
}
static PyObject *
IOBase_exit(PyObject *self, PyObject *args)
{
return PyObject_CallMethodObjArgs(self, _PyIO_str_close, NULL);
}
/* Lower-level APIs */
/* XXX Should these be present even if unimplemented? */
PyDoc_STRVAR(IOBase_fileno_doc,
"Returns underlying file descriptor if one exists.\n"
"\n"
"An IOError is raised if the IO object does not use a file descriptor.\n");
static PyObject *
IOBase_fileno(PyObject *self, PyObject *args)
{
return IOBase_unsupported("fileno");
}
PyDoc_STRVAR(IOBase_isatty_doc,
"Return whether this is an 'interactive' stream.\n"
"\n"
"Return False if it can't be determined.\n");
static PyObject *
IOBase_isatty(PyObject *self, PyObject *args)
{
if (_PyIOBase_checkClosed(self, Py_True) == NULL)
return NULL;
Py_RETURN_FALSE;
}
/* Readline(s) and writelines */
PyDoc_STRVAR(IOBase_readline_doc,
"Read and return a line from the stream.\n"
"\n"
"If limit is specified, at most limit bytes will be read.\n"
"\n"
"The line terminator is always b'\n' for binary files; for text\n"
"files, the newlines argument to open can be used to select the line\n"
"terminator(s) recognized.\n");
static PyObject *
IOBase_readline(PyObject *self, PyObject *args)
{
/* For backwards compatibility, a (slowish) readline(). */
Py_ssize_t limit = -1;
int has_peek = 0;
PyObject *buffer, *result;
Py_ssize_t old_size = -1;
if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
return NULL;
}
if (_PyIOBase_checkClosed(self, Py_True) == NULL)
return NULL;
if (PyObject_HasAttrString(self, "peek"))
has_peek = 1;
buffer = PyByteArray_FromStringAndSize(NULL, 0);
if (buffer == NULL)
return NULL;
while (limit < 0 || Py_SIZE(buffer) < limit) {
Py_ssize_t nreadahead = 1;
PyObject *b;
if (has_peek) {
PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
if (readahead == NULL)
goto fail;
if (!PyBytes_Check(readahead)) {
PyErr_Format(PyExc_IOError,
"peek() should have returned a bytes object, "
"not '%.200s'", Py_TYPE(readahead)->tp_name);
Py_DECREF(readahead);
goto fail;
}
if (PyBytes_GET_SIZE(readahead) > 0) {
Py_ssize_t n = 0;
const char *buf = PyBytes_AS_STRING(readahead);
if (limit >= 0) {
do {
if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
break;
if (buf[n++] == '\n')
break;
} while (1);
}
else {
do {
if (n >= PyBytes_GET_SIZE(readahead))
break;
if (buf[n++] == '\n')
break;
} while (1);
}
nreadahead = n;
}
Py_DECREF(readahead);
}
b = PyObject_CallMethod(self, "read", "n", nreadahead);
if (b == NULL)
goto fail;
if (!PyBytes_Check(b)) {
PyErr_Format(PyExc_IOError,
"read() should have returned a bytes object, "
"not '%.200s'", Py_TYPE(b)->tp_name);
Py_DECREF(b);
goto fail;
}
if (PyBytes_GET_SIZE(b) == 0) {
Py_DECREF(b);
break;
}
old_size = PyByteArray_GET_SIZE(buffer);
PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b));
memcpy(PyByteArray_AS_STRING(buffer) + old_size,
PyBytes_AS_STRING(b), PyBytes_GET_SIZE(b));
Py_DECREF(b);
if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n')
break;
}
result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
PyByteArray_GET_SIZE(buffer));
Py_DECREF(buffer);
return result;
fail:
Py_DECREF(buffer);
return NULL;
}
static PyObject *
IOBase_iter(PyObject *self)
{
if (_PyIOBase_checkClosed(self, Py_True) == NULL)
return NULL;
Py_INCREF(self);
return self;
}
static PyObject *
IOBase_iternext(PyObject *self)
{
PyObject *line = PyObject_CallMethodObjArgs(self, _PyIO_str_readline, NULL);
if (line == NULL)
return NULL;
if (PyObject_Size(line) == 0) {
Py_DECREF(line);
return NULL;
}
return line;
}
PyDoc_STRVAR(IOBase_readlines_doc,
"Return a list of lines from the stream.\n"
"\n"
"hint can be specified to control the number of lines read: no more\n"
"lines will be read if the total size (in bytes/characters) of all\n"
"lines so far exceeds hint.");
static PyObject *
IOBase_readlines(PyObject *self, PyObject *args)
{
Py_ssize_t hint = -1, length = 0;
PyObject *hintobj = Py_None, *result;
if (!PyArg_ParseTuple(args, "|O:readlines", &hintobj)) {
return NULL;
}
if (hintobj != Py_None) {
hint = PyNumber_AsSsize_t(hintobj, PyExc_ValueError);
if (hint == -1 && PyErr_Occurred())
return NULL;
}
result = PyList_New(0);
if (result == NULL)
return NULL;
if (hint <= 0) {
/* XXX special-casing this made sense in the Python version in order
to remove the bytecode interpretation overhead, but it could
probably be removed here. */
PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
if (ret == NULL) {
Py_DECREF(result);
return NULL;
}
Py_DECREF(ret);
return result;
}
while (1) {
PyObject *line = PyIter_Next(self);
if (line == NULL) {
if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
}
else
break; /* StopIteration raised */
}
if (PyList_Append(result, line) < 0) {
Py_DECREF(line);
Py_DECREF(result);
return NULL;
}
length += PyObject_Size(line);
Py_DECREF(line);
if (length > hint)
break;
}
return result;
}
static PyObject *
IOBase_writelines(PyObject *self, PyObject *args)
{
PyObject *lines, *iter, *res;
if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
return NULL;
}
if (_PyIOBase_checkClosed(self, Py_True) == NULL)
return NULL;
iter = PyObject_GetIter(lines);
if (iter == NULL)
return NULL;
while (1) {
PyObject *line = PyIter_Next(iter);
if (line == NULL) {
if (PyErr_Occurred()) {
Py_DECREF(iter);
return NULL;
}
else
break; /* Stop Iteration */
}
res = PyObject_CallMethodObjArgs(self, _PyIO_str_write, line, NULL);
Py_DECREF(line);
if (res == NULL) {
Py_DECREF(iter);
return NULL;
}
Py_DECREF(res);
}
Py_DECREF(iter);
Py_RETURN_NONE;
}
static PyMethodDef IOBase_methods[] = {
{"seek", IOBase_seek, METH_VARARGS, IOBase_seek_doc},
{"tell", IOBase_tell, METH_NOARGS, IOBase_tell_doc},
{"truncate", IOBase_truncate, METH_VARARGS, IOBase_truncate_doc},
{"flush", IOBase_flush, METH_NOARGS, IOBase_flush_doc},
{"close", IOBase_close, METH_NOARGS, IOBase_close_doc},
{"seekable", IOBase_seekable, METH_NOARGS, IOBase_seekable_doc},
{"readable", IOBase_readable, METH_NOARGS, IOBase_readable_doc},
{"writable", IOBase_writable, METH_NOARGS, IOBase_writable_doc},
{"_checkClosed", _PyIOBase_checkClosed, METH_NOARGS},
{"_checkSeekable", _PyIOBase_checkSeekable, METH_NOARGS},
{"_checkReadable", _PyIOBase_checkReadable, METH_NOARGS},
{"_checkWritable", _PyIOBase_checkWritable, METH_NOARGS},
{"fileno", IOBase_fileno, METH_NOARGS, IOBase_fileno_doc},
{"isatty", IOBase_isatty, METH_NOARGS, IOBase_isatty_doc},
{"__enter__", IOBase_enter, METH_NOARGS},
{"__exit__", IOBase_exit, METH_VARARGS},
{"readline", IOBase_readline, METH_VARARGS, IOBase_readline_doc},
{"readlines", IOBase_readlines, METH_VARARGS, IOBase_readlines_doc},
{"writelines", IOBase_writelines, METH_VARARGS},
{NULL, NULL}
};
static PyGetSetDef IOBase_getset[] = {
{"closed", (getter)IOBase_closed_get, NULL, NULL},
{0}
};
PyTypeObject PyIOBase_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_io._IOBase", /*tp_name*/
sizeof(IOBaseObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)IOBase_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
IOBase_doc, /* tp_doc */
(traverseproc)IOBase_traverse, /* tp_traverse */
(inquiry)IOBase_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(IOBaseObject, weakreflist), /* tp_weaklistoffset */
IOBase_iter, /* tp_iter */
IOBase_iternext, /* tp_iternext */
IOBase_methods, /* tp_methods */
0, /* tp_members */
IOBase_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(IOBaseObject, dict), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
/*
* RawIOBase class, Inherits from IOBase.
*/
PyDoc_STRVAR(RawIOBase_doc,
"Base class for raw binary I/O.");
/*
* The read() method is implemented by calling readinto(); derived classes
* that want to support read() only need to implement readinto() as a
* primitive operation. In general, readinto() can be more efficient than
* read().
*
* (It would be tempting to also provide an implementation of readinto() in
* terms of read(), in case the latter is a more suitable primitive operation,
* but that would lead to nasty recursion in case a subclass doesn't implement
* either.)
*/
static PyObject *
RawIOBase_read(PyObject *self, PyObject *args)
{
Py_ssize_t n = -1;
PyObject *b, *res;
if (!PyArg_ParseTuple(args, "|n:read", &n)) {
return NULL;
}
if (n < 0)
return PyObject_CallMethod(self, "readall", NULL);
/* TODO: allocate a bytes object directly instead and manually construct
a writable memoryview pointing to it. */
b = PyByteArray_FromStringAndSize(NULL, n);
if (b == NULL)
return NULL;
res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, b, NULL);
if (res == NULL) {
Py_DECREF(b);
return NULL;
}
n = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
if (n == -1 && PyErr_Occurred()) {
Py_DECREF(b);
return NULL;
}
res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
Py_DECREF(b);
return res;
}
PyDoc_STRVAR(RawIOBase_readall_doc,
"Read until EOF, using multiple read() call.");
static PyObject *
RawIOBase_readall(PyObject *self, PyObject *args)
{
PyObject *b = NULL;
Py_ssize_t cursize = 0;
while (1) {
Py_ssize_t length;
PyObject *data = PyObject_CallMethod(self, "read",
"i", DEFAULT_BUFFER_SIZE);
if (!data) {
Py_XDECREF(b);
return NULL;
}
if (!PyBytes_Check(data)) {
Py_XDECREF(b);
Py_DECREF(data);
PyErr_SetString(PyExc_TypeError, "read() should return bytes");
return NULL;
}
length = Py_SIZE(data);
if (b == NULL)
b = data;
else if (length != 0) {
_PyBytes_Resize(&b, cursize + length);
if (b == NULL) {
Py_DECREF(data);
return NULL;
}
memcpy(PyBytes_AS_STRING(b) + cursize,
PyBytes_AS_STRING(data), length);
Py_DECREF(data);
}
if (length == 0)
break;
}
return b;
}
static PyMethodDef RawIOBase_methods[] = {
{"read", RawIOBase_read, METH_VARARGS},
{"readall", RawIOBase_readall, METH_NOARGS, RawIOBase_readall_doc},
{NULL, NULL}
};
PyTypeObject PyRawIOBase_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_io._RawIOBase", /*tp_name*/
0, /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
RawIOBase_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
RawIOBase_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyIOBase_Type, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};

150
Modules/_iomodule.h Normal file
View File

@ -0,0 +1,150 @@
/*
* Declarations shared between the different parts of the io module
*/
/* ABCs */
extern PyTypeObject PyIOBase_Type;
extern PyTypeObject PyRawIOBase_Type;
extern PyTypeObject PyBufferedIOBase_Type;
extern PyTypeObject PyTextIOBase_Type;
/* Concrete classes */
extern PyTypeObject PyFileIO_Type;
extern PyTypeObject PyBytesIO_Type;
extern PyTypeObject PyStringIO_Type;
extern PyTypeObject PyBufferedReader_Type;
extern PyTypeObject PyBufferedWriter_Type;
extern PyTypeObject PyBufferedRWPair_Type;
extern PyTypeObject PyBufferedRandom_Type;
extern PyTypeObject PyTextIOWrapper_Type;
extern PyTypeObject PyIncrementalNewlineDecoder_Type;
/* These functions are used as METH_NOARGS methods, are normally called
* with args=NULL, and return a new reference.
* BUT when args=Py_True is passed, they return a borrowed reference.
*/
extern PyObject* _PyIOBase_checkReadable(PyObject *self, PyObject *args);
extern PyObject* _PyIOBase_checkWritable(PyObject *self, PyObject *args);
extern PyObject* _PyIOBase_checkSeekable(PyObject *self, PyObject *args);
extern PyObject* _PyIOBase_checkClosed(PyObject *self, PyObject *args);
/* Helper for finalization.
This function will revive an object ready to be deallocated and try to
close() it. It returns 0 if the object can be destroyed, or -1 if it
is alive again. */
extern int _PyIOBase_finalize(PyObject *self);
/* Returns true if the given FileIO object is closed.
Doesn't check the argument type, so be careful! */
extern int _PyFileIO_closed(PyObject *self);
/* Shortcut to the core of the IncrementalNewlineDecoder.decode method */
extern PyObject *_PyIncrementalNewlineDecoder_decode(
PyObject *self, PyObject *input, int final);
/* Finds the first line ending between `start` and `end`.
If found, returns the index after the line ending and doesn't touch
`*consumed`.
If not found, returns -1 and sets `*consumed` to the number of characters
which can be safely put aside until another search.
NOTE: for performance reasons, `end` must point to a NUL character ('\0').
Otherwise, the function will scan further and return garbage. */
extern Py_ssize_t _PyIO_find_line_ending(
int translated, int universal, PyObject *readnl,
Py_UNICODE *start, Py_UNICODE *end, Py_ssize_t *consumed);
#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
typedef struct {
PyException_HEAD
PyObject *myerrno;
PyObject *strerror;
PyObject *filename; /* Not used, but part of the IOError object */
Py_ssize_t written;
} PyBlockingIOErrorObject;
PyObject *PyExc_BlockingIOError;
/*
* Offset type for positioning.
*/
#if defined(MS_WIN64) || defined(MS_WINDOWS)
/* Windows uses long long for offsets */
typedef PY_LONG_LONG Py_off_t;
# define PyLong_AsOff_t PyLong_AsLongLong
# define PyLong_FromOff_t PyLong_FromLongLong
# define PY_OFF_T_MAX PY_LLONG_MAX
# define PY_OFF_T_MIN PY_LLONG_MIN
#else
/* Other platforms use off_t */
typedef off_t Py_off_t;
#if (SIZEOF_OFF_T == SIZEOF_SIZE_T)
# define PyLong_AsOff_t PyLong_AsSsize_t
# define PyLong_FromOff_t PyLong_FromSsize_t
# define PY_OFF_T_MAX PY_SSIZE_T_MAX
# define PY_OFF_T_MIN PY_SSIZE_T_MIN
#elif (SIZEOF_OFF_T == SIZEOF_LONG_LONG)
# define PyLong_AsOff_t PyLong_AsLongLong
# define PyLong_FromOff_t PyLong_FromLongLong
# define PY_OFF_T_MAX PY_LLONG_MAX
# define PY_OFF_T_MIN PY_LLONG_MIN
#elif (SIZEOF_OFF_T == SIZEOF_LONG)
# define PyLong_AsOff_t PyLong_AsLong
# define PyLong_FromOff_t PyLong_FromLong
# define PY_OFF_T_MAX LONG_MAX
# define PY_OFF_T_MIN LONG_MIN
#else
# error off_t does not match either size_t, long, or long long!
#endif
#endif
extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err);
/* Implementation details */
/* IO module structure */
extern PyModuleDef _PyIO_Module;
typedef struct {
int initialized;
PyObject *os_module;
PyObject *locale_module;
PyObject *unsupported_operation;
} _PyIO_State;
#define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod))
#define IO_STATE IO_MOD_STATE(PyState_FindModule(&_PyIO_Module))
extern PyObject *_PyIO_str_close;
extern PyObject *_PyIO_str_closed;
extern PyObject *_PyIO_str_decode;
extern PyObject *_PyIO_str_encode;
extern PyObject *_PyIO_str_fileno;
extern PyObject *_PyIO_str_flush;
extern PyObject *_PyIO_str_getstate;
extern PyObject *_PyIO_str_isatty;
extern PyObject *_PyIO_str_newlines;
extern PyObject *_PyIO_str_nl;
extern PyObject *_PyIO_str_read;
extern PyObject *_PyIO_str_read1;
extern PyObject *_PyIO_str_readable;
extern PyObject *_PyIO_str_readinto;
extern PyObject *_PyIO_str_readline;
extern PyObject *_PyIO_str_reset;
extern PyObject *_PyIO_str_seek;
extern PyObject *_PyIO_str_seekable;
extern PyObject *_PyIO_str_tell;
extern PyObject *_PyIO_str_truncate;
extern PyObject *_PyIO_str_writable;
extern PyObject *_PyIO_str_write;
extern PyObject *_PyIO_empty_str;
extern PyObject *_PyIO_empty_bytes;

View File

@ -1,8 +1,11 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#include "_iomodule.h"
/* This module is a stripped down version of _bytesio.c with a Py_UNICODE
buffer. Most of the functionality is provided by subclassing _StringIO. */
/* Implementation note: the buffer is always at least one character longer
than the enclosed string, for proper functioning of _PyIO_find_line_ending.
*/
typedef struct {
PyObject_HEAD
@ -10,8 +13,39 @@ typedef struct {
Py_ssize_t pos;
Py_ssize_t string_size;
size_t buf_size;
char ok; /* initialized? */
char closed;
char readuniversal;
char readtranslate;
PyObject *decoder;
PyObject *readnl;
PyObject *writenl;
PyObject *dict;
PyObject *weakreflist;
} StringIOObject;
#define CHECK_INITIALIZED(self) \
if (self->ok <= 0) { \
PyErr_SetString(PyExc_ValueError, \
"I/O operation on uninitialized object"); \
return NULL; \
}
#define CHECK_CLOSED(self) \
if (self->closed) { \
PyErr_SetString(PyExc_ValueError, \
"I/O operation on closed file"); \
return NULL; \
}
PyDoc_STRVAR(stringio_doc,
"Text I/O implementation using an in-memory buffer.\n"
"\n"
"The initial_value argument sets the value of object. The newline\n"
"argument is like the one of TextIOWrapper's constructor.");
/* Internal routine for changing the size, in terms of characters, of the
buffer of StringIO objects. The caller should ensure that the 'size'
@ -26,6 +60,8 @@ resize_buffer(StringIOObject *self, size_t size)
assert(self->buf != NULL);
/* Reserve one more char for line ending detection. */
size = size + 1;
/* For simplicity, stay in the range of the signed type. Anyway, Python
doesn't allow strings to be longer than this. */
if (size > PY_SSIZE_T_MAX)
@ -67,13 +103,38 @@ resize_buffer(StringIOObject *self, size_t size)
return -1;
}
/* Internal routine for writing a string of characters to the buffer of a
StringIO object. Returns the number of bytes wrote, or -1 on error. */
/* Internal routine for writing a whole PyUnicode object to the buffer of a
StringIO object. Returns 0 on success, or -1 on error. */
static Py_ssize_t
write_str(StringIOObject *self, const Py_UNICODE *str, Py_ssize_t len)
write_str(StringIOObject *self, PyObject *obj)
{
Py_UNICODE *str;
Py_ssize_t len;
PyObject *decoded = NULL;
assert(self->buf != NULL);
assert(self->pos >= 0);
if (self->decoder != NULL) {
decoded = _PyIncrementalNewlineDecoder_decode(
self->decoder, obj, 1 /* always final */);
}
else {
decoded = obj;
Py_INCREF(decoded);
}
if (self->writenl) {
PyObject *translated = PyUnicode_Replace(
decoded, _PyIO_str_nl, self->writenl, -1);
Py_DECREF(decoded);
decoded = translated;
}
if (decoded == NULL)
return -1;
assert(PyUnicode_Check(decoded));
str = PyUnicode_AS_UNICODE(decoded);
len = PyUnicode_GET_SIZE(decoded);
assert(len >= 0);
/* This overflow check is not strictly necessary. However, it avoids us to
@ -82,11 +143,11 @@ write_str(StringIOObject *self, const Py_UNICODE *str, Py_ssize_t len)
if (self->pos > PY_SSIZE_T_MAX - len) {
PyErr_SetString(PyExc_OverflowError,
"new position too large");
return -1;
goto fail;
}
if (self->pos + len > self->string_size) {
if (resize_buffer(self, self->pos + len) < 0)
return -1;
goto fail;
}
if (self->pos > self->string_size) {
@ -108,26 +169,47 @@ write_str(StringIOObject *self, const Py_UNICODE *str, Py_ssize_t len)
memcpy(self->buf + self->pos, str, len * sizeof(Py_UNICODE));
self->pos += len;
/* Set the new length of the internal string if it has changed */
/* Set the new length of the internal string if it has changed. */
if (self->string_size < self->pos) {
self->string_size = self->pos;
}
return len;
Py_DECREF(decoded);
return 0;
fail:
Py_XDECREF(decoded);
return -1;
}
PyDoc_STRVAR(stringio_getvalue_doc,
"Retrieve the entire contents of the object.");
static PyObject *
stringio_getvalue(StringIOObject *self)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
return PyUnicode_FromUnicode(self->buf, self->string_size);
}
PyDoc_STRVAR(stringio_tell_doc,
"Tell the current file position.");
static PyObject *
stringio_tell(StringIOObject *self)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
return PyLong_FromSsize_t(self->pos);
}
PyDoc_STRVAR(stringio_read_doc,
"Read at most n characters, returned as a string.\n"
"\n"
"If the argument is negative or omitted, read until EOF\n"
"is reached. Return an empty string at EOF.\n");
static PyObject *
stringio_read(StringIOObject *self, PyObject *args)
{
@ -135,11 +217,13 @@ stringio_read(StringIOObject *self, PyObject *args)
Py_UNICODE *output;
PyObject *arg = Py_None;
CHECK_INITIALIZED(self);
if (!PyArg_ParseTuple(args, "|O:read", &arg))
return NULL;
CHECK_CLOSED(self);
if (PyLong_Check(arg)) {
size = PyLong_AsSsize_t(arg);
if (PyNumber_Check(arg)) {
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (size == -1 && PyErr_Occurred())
return NULL;
}
@ -161,24 +245,127 @@ stringio_read(StringIOObject *self, PyObject *args)
size = 0;
}
assert(self->buf != NULL);
output = self->buf + self->pos;
self->pos += size;
return PyUnicode_FromUnicode(output, size);
}
/* Internal helper, used by stringio_readline and stringio_iternext */
static PyObject *
_stringio_readline(StringIOObject *self, Py_ssize_t limit)
{
Py_UNICODE *start, *end, old_char;
Py_ssize_t len, consumed;
/* In case of overseek, return the empty string */
if (self->pos >= self->string_size)
return PyUnicode_FromString("");
start = self->buf + self->pos;
if (limit < 0 || limit > self->string_size - self->pos)
limit = self->string_size - self->pos;
end = start + limit;
old_char = *end;
*end = '\0';
len = _PyIO_find_line_ending(
self->readtranslate, self->readuniversal, self->readnl,
start, end, &consumed);
*end = old_char;
/* If we haven't found any line ending, we just return everything
(`consumed` is ignored). */
if (len < 0)
len = limit;
self->pos += len;
return PyUnicode_FromUnicode(start, len);
}
PyDoc_STRVAR(stringio_readline_doc,
"Read until newline or EOF.\n"
"\n"
"Returns an empty string if EOF is hit immediately.\n");
static PyObject *
stringio_readline(StringIOObject *self, PyObject *args)
{
PyObject *arg = Py_None;
Py_ssize_t limit = -1;
CHECK_INITIALIZED(self);
if (!PyArg_ParseTuple(args, "|O:readline", &arg))
return NULL;
CHECK_CLOSED(self);
if (PyNumber_Check(arg)) {
limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (limit == -1 && PyErr_Occurred())
return NULL;
}
else if (arg != Py_None) {
PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
Py_TYPE(arg)->tp_name);
return NULL;
}
return _stringio_readline(self, limit);
}
static PyObject *
stringio_iternext(StringIOObject *self)
{
PyObject *line;
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
if (Py_TYPE(self) == &PyStringIO_Type) {
/* Skip method call overhead for speed */
line = _stringio_readline(self, -1);
}
else {
/* XXX is subclassing StringIO really supported? */
line = PyObject_CallMethodObjArgs((PyObject *)self,
_PyIO_str_readline, NULL);
if (line && !PyUnicode_Check(line)) {
PyErr_Format(PyExc_IOError,
"readline() should have returned an str object, "
"not '%.200s'", Py_TYPE(line)->tp_name);
Py_DECREF(line);
return NULL;
}
}
if (line == NULL)
return NULL;
if (PyUnicode_GET_SIZE(line) == 0) {
/* Reached EOF */
Py_DECREF(line);
return NULL;
}
return line;
}
PyDoc_STRVAR(stringio_truncate_doc,
"Truncate size to pos.\n"
"\n"
"The pos argument defaults to the current file position, as\n"
"returned by tell(). Imply an absolute seek to pos.\n"
"Returns the new absolute position.\n");
static PyObject *
stringio_truncate(StringIOObject *self, PyObject *args)
{
Py_ssize_t size;
PyObject *arg = Py_None;
CHECK_INITIALIZED(self);
if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
return NULL;
CHECK_CLOSED(self);
if (PyLong_Check(arg)) {
size = PyLong_AsSsize_t(arg);
if (PyNumber_Check(arg)) {
size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (size == -1 && PyErr_Occurred())
return NULL;
}
@ -199,23 +386,34 @@ stringio_truncate(StringIOObject *self, PyObject *args)
}
if (size < self->string_size) {
self->string_size = size;
if (resize_buffer(self, size) < 0)
return NULL;
self->string_size = size;
}
self->pos = size;
return PyLong_FromSsize_t(size);
}
PyDoc_STRVAR(stringio_seek_doc,
"Change stream position.\n"
"\n"
"Seek to character offset pos relative to position indicated by whence:\n"
" 0 Start of stream (the default). pos should be >= 0;\n"
" 1 Current position - pos must be 0;\n"
" 2 End of stream - pos must be 0.\n"
"Returns the new absolute position.\n");
static PyObject *
stringio_seek(StringIOObject *self, PyObject *args)
{
Py_ssize_t pos;
int mode = 0;
CHECK_INITIALIZED(self);
if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode))
return NULL;
CHECK_CLOSED(self);
if (mode != 0 && mode != 1 && mode != 2) {
PyErr_Format(PyExc_ValueError,
@ -248,36 +446,76 @@ stringio_seek(StringIOObject *self, PyObject *args)
return PyLong_FromSsize_t(self->pos);
}
PyDoc_STRVAR(stringio_write_doc,
"Write string to file.\n"
"\n"
"Returns the number of characters written, which is always equal to\n"
"the length of the string.\n");
static PyObject *
stringio_write(StringIOObject *self, PyObject *obj)
{
const Py_UNICODE *str;
Py_ssize_t size;
Py_ssize_t n = 0;
if (PyUnicode_Check(obj)) {
str = PyUnicode_AsUnicode(obj);
size = PyUnicode_GetSize(obj);
}
else {
CHECK_INITIALIZED(self);
if (!PyUnicode_Check(obj)) {
PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
Py_TYPE(obj)->tp_name);
return NULL;
}
CHECK_CLOSED(self);
size = PyUnicode_GET_SIZE(obj);
if (size != 0) {
n = write_str(self, str, size);
if (n < 0)
return NULL;
}
if (size > 0 && write_str(self, obj) < 0)
return NULL;
return PyLong_FromSsize_t(n);
return PyLong_FromSsize_t(size);
}
PyDoc_STRVAR(stringio_close_doc,
"Close the IO object. Attempting any further operation after the\n"
"object is closed will raise a ValueError.\n"
"\n"
"This method has no effect if the file is already closed.\n");
static PyObject *
stringio_close(StringIOObject *self)
{
self->closed = 1;
/* Free up some memory */
if (resize_buffer(self, 0) < 0)
return NULL;
Py_CLEAR(self->readnl);
Py_CLEAR(self->writenl);
Py_CLEAR(self->decoder);
Py_RETURN_NONE;
}
static int
stringio_traverse(StringIOObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->dict);
return 0;
}
static int
stringio_clear(StringIOObject *self)
{
Py_CLEAR(self->dict);
return 0;
}
static void
stringio_dealloc(StringIOObject *self)
{
PyMem_Free(self->buf);
_PyObject_GC_UNTRACK(self);
Py_CLEAR(self->readnl);
Py_CLEAR(self->writenl);
Py_CLEAR(self->decoder);
if (self->buf)
PyMem_Free(self->buf);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_TYPE(self)->tp_free(self);
}
@ -303,19 +541,194 @@ stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)self;
}
static int
stringio_init(StringIOObject *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"initial_value", "newline", NULL};
PyObject *value = NULL;
char *newline = "\n";
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
&value, &newline))
return -1;
if (newline && newline[0] != '\0'
&& !(newline[0] == '\n' && newline[1] == '\0')
&& !(newline[0] == '\r' && newline[1] == '\0')
&& !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
PyErr_Format(PyExc_ValueError,
"illegal newline value: %s", newline);
return -1;
}
if (value && value != Py_None && !PyUnicode_Check(value)) {
PyErr_Format(PyExc_ValueError,
"initial_value must be str or None, not %.200s",
Py_TYPE(value)->tp_name);
return -1;
}
self->ok = 0;
Py_CLEAR(self->readnl);
Py_CLEAR(self->writenl);
Py_CLEAR(self->decoder);
if (newline) {
self->readnl = PyUnicode_FromString(newline);
if (self->readnl == NULL)
return -1;
}
self->readuniversal = (newline == NULL || newline[0] == '\0');
self->readtranslate = (newline == NULL);
/* If newline == "", we don't translate anything.
If newline == "\n" or newline == None, we translate to "\n", which is
a no-op.
(for newline == None, TextIOWrapper translates to os.sepline, but it
is pointless for StringIO)
*/
if (newline != NULL && newline[0] == '\r') {
self->writenl = self->readnl;
Py_INCREF(self->writenl);
}
if (self->readuniversal) {
self->decoder = PyObject_CallFunction(
(PyObject *)&PyIncrementalNewlineDecoder_Type,
"Oi", Py_None, (int) self->readtranslate);
if (self->decoder == NULL)
return -1;
}
/* Now everything is set up, resize buffer to size of initial value,
and copy it */
self->string_size = 0;
if (value && value != Py_None) {
Py_ssize_t len = PyUnicode_GetSize(value);
/* This is a heuristic, for newline translation might change
the string length. */
if (resize_buffer(self, len) < 0)
return -1;
self->pos = 0;
if (write_str(self, value) < 0)
return -1;
}
else {
if (resize_buffer(self, 0) < 0)
return -1;
}
self->pos = 0;
self->closed = 0;
self->ok = 1;
return 0;
}
/* Properties and pseudo-properties */
static PyObject *
stringio_seekable(StringIOObject *self, PyObject *args)
{
CHECK_INITIALIZED(self);
Py_RETURN_TRUE;
}
static PyObject *
stringio_readable(StringIOObject *self, PyObject *args)
{
CHECK_INITIALIZED(self);
Py_RETURN_TRUE;
}
static PyObject *
stringio_writable(StringIOObject *self, PyObject *args)
{
CHECK_INITIALIZED(self);
Py_RETURN_TRUE;
}
static PyObject *
stringio_buffer(StringIOObject *self, void *context)
{
PyErr_SetString(IO_STATE->unsupported_operation,
"buffer attribute is unsupported on type StringIO");
return NULL;
}
static PyObject *
stringio_closed(StringIOObject *self, void *context)
{
CHECK_INITIALIZED(self);
return PyBool_FromLong(self->closed);
}
static PyObject *
stringio_encoding(StringIOObject *self, void *context)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
return PyUnicode_FromString("utf-8");
}
static PyObject *
stringio_errors(StringIOObject *self, void *context)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
return PyUnicode_FromString("strict");
}
static PyObject *
stringio_line_buffering(StringIOObject *self, void *context)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
Py_RETURN_FALSE;
}
static PyObject *
stringio_newlines(StringIOObject *self, void *context)
{
CHECK_INITIALIZED(self);
CHECK_CLOSED(self);
if (self->decoder == NULL)
Py_RETURN_NONE;
return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
}
static struct PyMethodDef stringio_methods[] = {
{"getvalue", (PyCFunction)stringio_getvalue, METH_VARARGS, NULL},
{"read", (PyCFunction)stringio_read, METH_VARARGS, NULL},
{"tell", (PyCFunction)stringio_tell, METH_NOARGS, NULL},
{"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, NULL},
{"seek", (PyCFunction)stringio_seek, METH_VARARGS, NULL},
{"write", (PyCFunction)stringio_write, METH_O, NULL},
{"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
{"getvalue", (PyCFunction)stringio_getvalue, METH_VARARGS, stringio_getvalue_doc},
{"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
{"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
{"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
{"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
{"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
{"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
{"seekable", (PyCFunction)stringio_seekable, METH_NOARGS},
{"readable", (PyCFunction)stringio_readable, METH_NOARGS},
{"writable", (PyCFunction)stringio_writable, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
static PyTypeObject StringIO_Type = {
static PyGetSetDef stringio_getset[] = {
{"closed", (getter)stringio_closed, NULL, NULL},
{"newlines", (getter)stringio_newlines, NULL, NULL},
/* (following comments straight off of the original Python wrapper:)
XXX Cruft to support the TextIOWrapper API. This would only
be meaningful if StringIO supported the buffer attribute.
Hopefully, a better solution, than adding these pseudo-attributes,
will be found.
*/
{"buffer", (getter)stringio_buffer, NULL, NULL},
{"encoding", (getter)stringio_encoding, NULL, NULL},
{"errors", (getter)stringio_errors, NULL, NULL},
{"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
{0}
};
PyTypeObject PyStringIO_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_stringio._StringIO", /*tp_name*/
"_io.StringIO", /*tp_name*/
sizeof(StringIOObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)stringio_dealloc, /*tp_dealloc*/
@ -333,51 +746,24 @@ static PyTypeObject StringIO_Type = {
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC, /*tp_flags*/
stringio_doc, /*tp_doc*/
(traverseproc)stringio_traverse, /*tp_traverse*/
(inquiry)stringio_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(StringIOObject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
(iternextfunc)stringio_iternext, /*tp_iternext*/
stringio_methods, /*tp_methods*/
0, /*tp_members*/
0, /*tp_getset*/
stringio_getset, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
0, /*tp_init*/
offsetof(StringIOObject, dict), /*tp_dictoffset*/
(initproc)stringio_init, /*tp_init*/
0, /*tp_alloc*/
stringio_new, /*tp_new*/
};
static struct PyModuleDef _stringiomodule = {
PyModuleDef_HEAD_INIT,
"_stringio",
NULL,
-1,
NULL,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__stringio(void)
{
PyObject *m;
if (PyType_Ready(&StringIO_Type) < 0)
return NULL;
m = PyModule_Create(&_stringiomodule);
if (m == NULL)
return NULL;
Py_INCREF(&StringIO_Type);
if (PyModule_AddObject(m, "_StringIO", (PyObject *)&StringIO_Type) < 0)
return NULL;
return m;
}

2389
Modules/_textio.c Normal file

File diff suppressed because it is too large Load Diff

760
Modules/io.c Normal file
View File

@ -0,0 +1,760 @@
/*
An implementation of the new I/O lib as defined by PEP 3116 - "New I/O"
Classes defined here: UnsupportedOperation, BlockingIOError.
Functions defined here: open().
Mostly written by Amaury Forgeot d'Arc
*/
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#include "_iomodule.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */
/* Various interned strings */
PyObject *_PyIO_str_close;
PyObject *_PyIO_str_closed;
PyObject *_PyIO_str_decode;
PyObject *_PyIO_str_encode;
PyObject *_PyIO_str_fileno;
PyObject *_PyIO_str_flush;
PyObject *_PyIO_str_getstate;
PyObject *_PyIO_str_isatty;
PyObject *_PyIO_str_newlines;
PyObject *_PyIO_str_nl;
PyObject *_PyIO_str_read;
PyObject *_PyIO_str_read1;
PyObject *_PyIO_str_readable;
PyObject *_PyIO_str_readinto;
PyObject *_PyIO_str_readline;
PyObject *_PyIO_str_reset;
PyObject *_PyIO_str_seek;
PyObject *_PyIO_str_seekable;
PyObject *_PyIO_str_tell;
PyObject *_PyIO_str_truncate;
PyObject *_PyIO_str_writable;
PyObject *_PyIO_str_write;
PyObject *_PyIO_empty_str;
PyObject *_PyIO_empty_bytes;
PyDoc_STRVAR(module_doc,
"The io module provides the Python interfaces to stream handling. The\n"
"builtin open function is defined in this module.\n"
"\n"
"At the top of the I/O hierarchy is the abstract base class IOBase. It\n"
"defines the basic interface to a stream. Note, however, that there is no\n"
"seperation between reading and writing to streams; implementations are\n"
"allowed to throw an IOError if they do not support a given operation.\n"
"\n"
"Extending IOBase is RawIOBase which deals simply with the reading and\n"
"writing of raw bytes to a stream. FileIO subc lasses RawIOBase to provide\n"
"an interface to OS files.\n"
"\n"
"BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its\n"
"subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer\n"
"streams that are readable, writable, and both respectively.\n"
"BufferedRandom provides a buffered interface to random access\n"
"streams. BytesIO is a simple stream of in-memory bytes.\n"
"\n"
"Another IOBase subclass, TextIOBase, deals with the encoding and decoding\n"
"of streams into text. TextIOWrapper, which extends it, is a buffered text\n"
"interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO\n"
"is a in-memory stream for text.\n"
"\n"
"Argument names are not part of the specification, and only the arguments\n"
"of open() are intended to be used as keyword arguments.\n"
"\n"
"data:\n"
"\n"
"DEFAULT_BUFFER_SIZE\n"
"\n"
" An int containing the default buffer size used by the module's buffered\n"
" I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n"
" possible.\n"
);
/*
* BlockingIOError extends IOError
*/
static int
BlockingIOError_init(PyBlockingIOErrorObject *self, PyObject *args,
PyObject *kwds)
{
PyObject *myerrno = NULL, *strerror = NULL;
PyObject *baseargs = NULL;
Py_ssize_t written = 0;
assert(PyTuple_Check(args));
self->written = 0;
if (!PyArg_ParseTuple(args, "OO|n:BlockingIOError",
&myerrno, &strerror, &written))
return -1;
baseargs = PyTuple_Pack(2, myerrno, strerror);
if (baseargs == NULL)
return -1;
/* This will take care of initializing of myerrno and strerror members */
if (((PyTypeObject *)PyExc_IOError)->tp_init(
(PyObject *)self, baseargs, kwds) == -1) {
Py_DECREF(baseargs);
return -1;
}
Py_DECREF(baseargs);
self->written = written;
return 0;
}
static PyMemberDef BlockingIOError_members[] = {
{"characters_written", T_PYSSIZET, offsetof(PyBlockingIOErrorObject, written), 0},
{NULL} /* Sentinel */
};
static PyTypeObject _PyExc_BlockingIOError = {
PyVarObject_HEAD_INIT(NULL, 0)
"BlockingIOError", /*tp_name*/
sizeof(PyBlockingIOErrorObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
PyDoc_STR("Exception raised when I/O would block "
"on a non-blocking I/O stream"), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
BlockingIOError_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)BlockingIOError_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
PyObject *PyExc_BlockingIOError = (PyObject *)&_PyExc_BlockingIOError;
/*
* The main open() function
*/
PyDoc_STRVAR(open_doc,
"Open file and return a stream. Raise IOError upon failure.\n"
"\n"
"file is either a text or byte string giving the name (and the path\n"
"if the file isn't in the current working directory) of the file to\n"
"be opened or an integer file descriptor of the file to be\n"
"wrapped. (If a file descriptor is given, it is closed when the\n"
"returned I/O object is closed, unless closefd is set to False.)\n"
"\n"
"mode is an optional string that specifies the mode in which the file\n"
"is opened. It defaults to 'r' which means open for reading in text\n"
"mode. Other common values are 'w' for writing (truncating the file if\n"
"it already exists), and 'a' for appending (which on some Unix systems,\n"
"means that all writes append to the end of the file regardless of the\n"
"current seek position). In text mode, if encoding is not specified the\n"
"encoding used is platform dependent. (For reading and writing raw\n"
"bytes use binary mode and leave encoding unspecified.) The available\n"
"modes are:\n"
"\n"
"========= ===============================================================\n"
"Character Meaning\n"
"--------- ---------------------------------------------------------------\n"
"'r' open for reading (default)\n"
"'w' open for writing, truncating the file first\n"
"'a' open for writing, appending to the end of the file if it exists\n"
"'b' binary mode\n"
"'t' text mode (default)\n"
"'+' open a disk file for updating (reading and writing)\n"
"'U' universal newline mode (for backwards compatibility; unneeded\n"
" for new code)\n"
"========= ===============================================================\n"
"\n"
"The default mode is 'rt' (open for reading text). For binary random\n"
"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n"
"'r+b' opens the file without truncation.\n"
"\n"
"Python distinguishes between files opened in binary and text modes,\n"
"even when the underlying operating system doesn't. Files opened in\n"
"binary mode (appending 'b' to the mode argument) return contents as\n"
"bytes objects without any decoding. In text mode (the default, or when\n"
"'t' is appended to the mode argument), the contents of the file are\n"
"returned as strings, the bytes having been first decoded using a\n"
"platform-dependent encoding or using the specified encoding if given.\n"
"\n"
"buffering is an optional integer used to set the buffering policy. By\n"
"default full buffering is on. Pass 0 to switch buffering off (only\n"
"allowed in binary mode), 1 to set line buffering, and an integer > 1\n"
"for full buffering.\n"
"\n"
"encoding is the name of the encoding used to decode or encode the\n"
"file. This should only be used in text mode. The default encoding is\n"
"platform dependent, but any encoding supported by Python can be\n"
"passed. See the codecs module for the list of supported encodings.\n"
"\n"
"errors is an optional string that specifies how encoding errors are to\n"
"be handled---this argument should not be used in binary mode. Pass\n"
"'strict' to raise a ValueError exception if there is an encoding error\n"
"(the default of None has the same effect), or pass 'ignore' to ignore\n"
"errors. (Note that ignoring encoding errors can lead to data loss.)\n"
"See the documentation for codecs.register for a list of the permitted\n"
"encoding error strings.\n"
"\n"
"newline controls how universal newlines works (it only applies to text\n"
"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'. It works as\n"
"follows:\n"
"\n"
"* On input, if newline is None, universal newlines mode is\n"
" enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
" these are translated into '\\n' before being returned to the\n"
" caller. If it is '', universal newline mode is enabled, but line\n"
" endings are returned to the caller untranslated. If it has any of\n"
" the other legal values, input lines are only terminated by the given\n"
" string, and the line ending is returned to the caller untranslated.\n"
"\n"
"* On output, if newline is None, any '\\n' characters written are\n"
" translated to the system default line separator, os.linesep. If\n"
" newline is '', no translation takes place. If newline is any of the\n"
" other legal values, any '\\n' characters written are translated to\n"
" the given string.\n"
"\n"
"If closefd is False, the underlying file descriptor will be kept open\n"
"when the file is closed. This does not work when a file name is given\n"
"and must be True in that case.\n"
"\n"
"open() returns a file object whose type depends on the mode, and\n"
"through which the standard file operations such as reading and writing\n"
"are performed. When open() is used to open a file in a text mode ('w',\n"
"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n"
"a file in a binary mode, the returned class varies: in read binary\n"
"mode, it returns a BufferedReader; in write binary and append binary\n"
"modes, it returns a BufferedWriter, and in read/write mode, it returns\n"
"a BufferedRandom.\n"
"\n"
"It is also possible to use a string or bytearray as a file for both\n"
"reading and writing. For strings StringIO can be used like a file\n"
"opened in a text mode, and for bytes a BytesIO can be used like a file\n"
"opened in a binary mode.\n"
);
static PyObject *
io_open(PyObject *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"file", "mode", "buffering",
"encoding", "errors", "newline",
"closefd", NULL};
PyObject *file;
char *mode = "r";
int buffering = -1, closefd = 1;
char *encoding = NULL, *errors = NULL, *newline = NULL;
unsigned i;
int reading = 0, writing = 0, appending = 0, updating = 0;
int text = 0, binary = 0, universal = 0;
char rawmode[5], *m;
int line_buffering, isatty;
PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
&file, &mode, &buffering,
&encoding, &errors, &newline,
&closefd)) {
return NULL;
}
if (!PyUnicode_Check(file) &&
!PyBytes_Check(file) &&
!PyNumber_Check(file)) {
PyErr_Format(PyExc_TypeError, "invalid file: %R", file);
return NULL;
}
/* Decode mode */
for (i = 0; i < strlen(mode); i++) {
char c = mode[i];
switch (c) {
case 'r':
reading = 1;
break;
case 'w':
writing = 1;
break;
case 'a':
appending = 1;
break;
case '+':
updating = 1;
break;
case 't':
text = 1;
break;
case 'b':
binary = 1;
break;
case 'U':
universal = 1;
reading = 1;
break;
default:
goto invalid_mode;
}
/* c must not be duplicated */
if (strchr(mode+i+1, c)) {
invalid_mode:
PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode);
return NULL;
}
}
m = rawmode;
if (reading) *(m++) = 'r';
if (writing) *(m++) = 'w';
if (appending) *(m++) = 'a';
if (updating) *(m++) = '+';
*m = '\0';
/* Parameters validation */
if (universal) {
if (writing || appending) {
PyErr_SetString(PyExc_ValueError,
"can't use U and writing mode at once");
return NULL;
}
reading = 1;
}
if (text && binary) {
PyErr_SetString(PyExc_ValueError,
"can't have text and binary mode at once");
return NULL;
}
if (reading + writing + appending > 1) {
PyErr_SetString(PyExc_ValueError,
"must have exactly one of read/write/append mode");
return NULL;
}
if (binary && encoding != NULL) {
PyErr_SetString(PyExc_ValueError,
"binary mode doesn't take an encoding argument");
return NULL;
}
if (binary && errors != NULL) {
PyErr_SetString(PyExc_ValueError,
"binary mode doesn't take an errors argument");
return NULL;
}
if (binary && newline != NULL) {
PyErr_SetString(PyExc_ValueError,
"binary mode doesn't take a newline argument");
return NULL;
}
/* Create the Raw file stream */
raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type,
"Osi", file, rawmode, closefd);
if (raw == NULL)
return NULL;
modeobj = PyUnicode_FromString(mode);
if (modeobj == NULL)
goto error;
/* buffering */
{
PyObject *res = PyObject_CallMethod(raw, "isatty", NULL);
if (res == NULL)
goto error;
isatty = PyLong_AsLong(res);
Py_DECREF(res);
if (isatty == -1 && PyErr_Occurred())
goto error;
}
if (buffering == 1 || (buffering < 0 && isatty)) {
buffering = -1;
line_buffering = 1;
}
else
line_buffering = 0;
if (buffering < 0) {
buffering = DEFAULT_BUFFER_SIZE;
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
{
struct stat st;
long fileno;
PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);
if (res == NULL)
goto error;
fileno = PyLong_AsLong(res);
Py_DECREF(res);
if (fileno == -1 && PyErr_Occurred())
goto error;
if (fstat(fileno, &st) >= 0)
buffering = st.st_blksize;
}
#endif
}
if (buffering < 0) {
PyErr_SetString(PyExc_ValueError,
"invalid buffering size");
goto error;
}
/* if not buffering, returns the raw file object */
if (buffering == 0) {
if (!binary) {
PyErr_SetString(PyExc_ValueError,
"can't have unbuffered text I/O");
goto error;
}
Py_DECREF(modeobj);
return raw;
}
/* wraps into a buffered file */
{
PyObject *Buffered_class;
if (updating)
Buffered_class = (PyObject *)&PyBufferedRandom_Type;
else if (writing || appending)
Buffered_class = (PyObject *)&PyBufferedWriter_Type;
else if (reading)
Buffered_class = (PyObject *)&PyBufferedReader_Type;
else {
PyErr_Format(PyExc_ValueError,
"unknown mode: '%s'", mode);
goto error;
}
buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
}
Py_CLEAR(raw);
if (buffer == NULL)
goto error;
/* if binary, returns the buffered file */
if (binary) {
Py_DECREF(modeobj);
return buffer;
}
/* wraps into a TextIOWrapper */
wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type,
"Osssi",
buffer,
encoding, errors, newline,
line_buffering);
Py_CLEAR(buffer);
if (wrapper == NULL)
goto error;
if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
goto error;
Py_DECREF(modeobj);
return wrapper;
error:
Py_XDECREF(raw);
Py_XDECREF(modeobj);
Py_XDECREF(buffer);
Py_XDECREF(wrapper);
return NULL;
}
/*
* Private helpers for the io module.
*/
Py_off_t
PyNumber_AsOff_t(PyObject *item, PyObject *err)
{
Py_off_t result;
PyObject *runerr;
PyObject *value = PyNumber_Index(item);
if (value == NULL)
return -1;
/* We're done if PyLong_AsSsize_t() returns without error. */
result = PyLong_AsOff_t(value);
if (result != -1 || !(runerr = PyErr_Occurred()))
goto finish;
/* Error handling code -- only manage OverflowError differently */
if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
goto finish;
PyErr_Clear();
/* If no error-handling desired then the default clipping
is sufficient.
*/
if (!err) {
assert(PyLong_Check(value));
/* Whether or not it is less than or equal to
zero is determined by the sign of ob_size
*/
if (_PyLong_Sign(value) < 0)
result = PY_OFF_T_MIN;
else
result = PY_OFF_T_MAX;
}
else {
/* Otherwise replace the error with caller's error object. */
PyErr_Format(err,
"cannot fit '%.200s' into an offset-sized integer",
item->ob_type->tp_name);
}
finish:
Py_DECREF(value);
return result;
}
static int
iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
_PyIO_State *state = IO_MOD_STATE(mod);
if (!state->initialized)
return 0;
Py_VISIT(state->os_module);
if (state->locale_module != NULL) {
Py_VISIT(state->locale_module);
}
Py_VISIT(state->unsupported_operation);
return 0;
}
static int
iomodule_clear(PyObject *mod) {
_PyIO_State *state = IO_MOD_STATE(mod);
if (!state->initialized)
return 0;
Py_CLEAR(state->os_module);
if (state->locale_module != NULL)
Py_CLEAR(state->locale_module);
Py_CLEAR(state->unsupported_operation);
return 0;
}
static void
iomodule_free(PyObject *mod) {
iomodule_clear(mod);
}
/*
* Module definition
*/
static PyMethodDef module_methods[] = {
{"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
{NULL, NULL}
};
struct PyModuleDef _PyIO_Module = {
PyModuleDef_HEAD_INIT,
"io",
module_doc,
sizeof(_PyIO_State),
module_methods,
NULL,
iomodule_traverse,
iomodule_clear,
(freefunc)iomodule_free,
};
PyMODINIT_FUNC
PyInit__io(void)
{
PyObject *m = PyModule_Create(&_PyIO_Module);
_PyIO_State *state = NULL;
if (m == NULL)
return NULL;
state = IO_MOD_STATE(m);
state->initialized = 0;
/* put os in the module state */
state->os_module = PyImport_ImportModule("os");
if (state->os_module == NULL)
goto fail;
#define ADD_TYPE(type, name) \
if (PyType_Ready(type) < 0) \
goto fail; \
Py_INCREF(type); \
if (PyModule_AddObject(m, name, (PyObject *)type) < 0) { \
Py_DECREF(type); \
goto fail; \
}
/* DEFAULT_BUFFER_SIZE */
if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
goto fail;
/* UnsupportedOperation inherits from ValueError and IOError */
state->unsupported_operation = PyObject_CallFunction(
(PyObject *)&PyType_Type, "s(OO){}",
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
if (state->unsupported_operation == NULL)
goto fail;
Py_INCREF(state->unsupported_operation);
if (PyModule_AddObject(m, "UnsupportedOperation",
state->unsupported_operation) < 0)
goto fail;
/* BlockingIOError */
_PyExc_BlockingIOError.tp_base = (PyTypeObject *) PyExc_IOError;
ADD_TYPE(&_PyExc_BlockingIOError, "BlockingIOError");
/* Concrete base types of the IO ABCs.
(the ABCs themselves are declared through inheritance in io.py)
*/
ADD_TYPE(&PyIOBase_Type, "_IOBase");
ADD_TYPE(&PyRawIOBase_Type, "_RawIOBase");
ADD_TYPE(&PyBufferedIOBase_Type, "_BufferedIOBase");
ADD_TYPE(&PyTextIOBase_Type, "_TextIOBase");
/* Implementation of concrete IO objects. */
/* FileIO */
PyFileIO_Type.tp_base = &PyRawIOBase_Type;
ADD_TYPE(&PyFileIO_Type, "FileIO");
/* BytesIO */
PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBytesIO_Type, "BytesIO");
/* StringIO */
PyStringIO_Type.tp_base = &PyTextIOBase_Type;
ADD_TYPE(&PyStringIO_Type, "StringIO");
/* BufferedReader */
PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedReader_Type, "BufferedReader");
/* BufferedWriter */
PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedWriter_Type, "BufferedWriter");
/* BufferedRWPair */
PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedRWPair_Type, "BufferedRWPair");
/* BufferedRandom */
PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
ADD_TYPE(&PyBufferedRandom_Type, "BufferedRandom");
/* TextIOWrapper */
PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type;
ADD_TYPE(&PyTextIOWrapper_Type, "TextIOWrapper");
/* IncrementalNewlineDecoder */
ADD_TYPE(&PyIncrementalNewlineDecoder_Type, "IncrementalNewlineDecoder");
/* Interned strings */
if (!(_PyIO_str_close = PyUnicode_InternFromString("close")))
goto fail;
if (!(_PyIO_str_closed = PyUnicode_InternFromString("closed")))
goto fail;
if (!(_PyIO_str_decode = PyUnicode_InternFromString("decode")))
goto fail;
if (!(_PyIO_str_encode = PyUnicode_InternFromString("encode")))
goto fail;
if (!(_PyIO_str_fileno = PyUnicode_InternFromString("fileno")))
goto fail;
if (!(_PyIO_str_flush = PyUnicode_InternFromString("flush")))
goto fail;
if (!(_PyIO_str_getstate = PyUnicode_InternFromString("getstate")))
goto fail;
if (!(_PyIO_str_isatty = PyUnicode_InternFromString("isatty")))
goto fail;
if (!(_PyIO_str_newlines = PyUnicode_InternFromString("newlines")))
goto fail;
if (!(_PyIO_str_nl = PyUnicode_InternFromString("\n")))
goto fail;
if (!(_PyIO_str_read = PyUnicode_InternFromString("read")))
goto fail;
if (!(_PyIO_str_read1 = PyUnicode_InternFromString("read1")))
goto fail;
if (!(_PyIO_str_readable = PyUnicode_InternFromString("readable")))
goto fail;
if (!(_PyIO_str_readinto = PyUnicode_InternFromString("readinto")))
goto fail;
if (!(_PyIO_str_readline = PyUnicode_InternFromString("readline")))
goto fail;
if (!(_PyIO_str_reset = PyUnicode_InternFromString("reset")))
goto fail;
if (!(_PyIO_str_seek = PyUnicode_InternFromString("seek")))
goto fail;
if (!(_PyIO_str_seekable = PyUnicode_InternFromString("seekable")))
goto fail;
if (!(_PyIO_str_tell = PyUnicode_InternFromString("tell")))
goto fail;
if (!(_PyIO_str_truncate = PyUnicode_InternFromString("truncate")))
goto fail;
if (!(_PyIO_str_write = PyUnicode_InternFromString("write")))
goto fail;
if (!(_PyIO_str_writable = PyUnicode_InternFromString("writable")))
goto fail;
if (!(_PyIO_empty_str = PyUnicode_FromStringAndSize(NULL, 0)))
goto fail;
if (!(_PyIO_empty_bytes = PyBytes_FromStringAndSize(NULL, 0)))
goto fail;
state->initialized = 1;
return m;
fail:
Py_XDECREF(state->os_module);
Py_XDECREF(state->unsupported_operation);
Py_DECREF(m);
return NULL;
}

View File

@ -97,6 +97,10 @@ SOURCE=..\..\Modules\_bisectmodule.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_bufferedio.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_bytesio.c
# End Source File
# Begin Source File
@ -149,6 +153,10 @@ SOURCE=..\..\Modules\_heapqmodule.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_iobase.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_json.c
# End Source File
# Begin Source File
@ -185,6 +193,10 @@ SOURCE=..\..\PC\_subprocess.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_textio.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\_threadmodule.c
# End Source File
# Begin Source File
@ -463,6 +475,10 @@ SOURCE=..\..\Modules\zlib\inftrees.c
# End Source File
# Begin Source File
SOURCE=..\..\Modules\io.c
# End Source File
# Begin Source File
SOURCE=..\..\Objects\iterobject.c
# End Source File
# Begin Source File

View File

@ -58,9 +58,7 @@ extern PyObject* PyInit__codecs_tw(void);
extern PyObject* PyInit__subprocess(void);
extern PyObject* PyInit__lsprof(void);
extern PyObject* PyInit__ast(void);
extern PyObject* PyInit__fileio(void);
extern PyObject* PyInit__bytesio(void);
extern PyObject* PyInit__stringio(void);
extern PyObject* PyInit__io(void);
extern PyObject* PyInit__pickle(void);
extern PyObject* PyInit_atexit(void);
extern PyObject* _PyWarnings_Init(void);
@ -150,9 +148,7 @@ struct _inittab _PyImport_Inittab[] = {
{"sys", NULL},
{"_warnings", _PyWarnings_Init},
{"_fileio", PyInit__fileio},
{"_bytesio", PyInit__bytesio},
{"_stringio", PyInit__stringio},
{"_io", PyInit__io},
{"_pickle", PyInit__pickle},
{"atexit", PyInit_atexit},

View File

@ -974,6 +974,10 @@
RelativePath="..\Modules\_bisectmodule.c"
>
</File>
<File
RelativePath="..\Modules\_bufferedio.c"
>
</File>
<File
RelativePath="..\Modules\_codecsmodule.c"
>
@ -1002,6 +1006,14 @@
RelativePath="..\Modules\_heapqmodule.c"
>
</File>
<File
RelativePath="..\Modules\_iobase.c"
>
</File>
<File
RelativePath="..\Modules\_iomodule.h"
>
</File>
<File
RelativePath="..\Modules\_json.c"
>
@ -1034,6 +1046,10 @@
RelativePath="..\Modules\_struct.c"
>
</File>
<File
RelativePath="..\Modules\_textio.c"
>
</File>
<File
RelativePath="..\Modules\_weakref.c"
>
@ -1074,6 +1090,10 @@
RelativePath="..\Modules\itertoolsmodule.c"
>
</File>
<File
RelativePath="..\Modules\io.c"
>
</File>
<File
RelativePath="..\Modules\main.c"
>

View File

@ -769,7 +769,7 @@ create_stdio(PyObject* io,
}
text = PyUnicode_FromString(name);
if (text == NULL || PyObject_SetAttrString(raw, "_name", text) < 0)
if (text == NULL || PyObject_SetAttrString(raw, "name", text) < 0)
goto error;
res = PyObject_CallMethod(raw, "isatty", "");
if (res == NULL)

View File

@ -982,8 +982,6 @@ class PyBuildExt(build_ext):
# Thomas Heller's _ctypes module
self.detect_ctypes(inc_dirs, lib_dirs)
# _fileio -- supposedly cross platform
exts.append(Extension('_fileio', ['_fileio.c']))
# Richard Oudkerk's multiprocessing module
if platform == 'win32': # Windows
macros = dict()