Skip to content

Commit f24131f

Browse files
Issue #20175: Converted the _io module to Argument Clinic.
1 parent 7f90cba commit f24131f

16 files changed

Lines changed: 4199 additions & 1362 deletions

Lib/test/test_fileio.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ def testErrors(self):
190190
self.assertTrue(f.closed)
191191

192192
def testMethods(self):
193-
methods = ['fileno', 'isatty', 'read',
194-
'tell', 'truncate', 'seekable',
195-
'readable', 'writable']
193+
methods = ['fileno', 'isatty', 'seekable', 'readable', 'writable',
194+
'read', 'readall', 'readline', 'readlines',
195+
'tell', 'truncate', 'flush']
196196

197197
self.f.close()
198198
self.assertTrue(self.f.closed)
@@ -201,9 +201,15 @@ def testMethods(self):
201201
method = getattr(self.f, methodname)
202202
# should raise on closed file
203203
self.assertRaises(ValueError, method)
204-
self.assertRaises(ValueError, self.f.readinto, bytearray())
205-
self.assertRaises(ValueError, self.f.seek, 0, os.SEEK_CUR)
204+
205+
self.assertRaises(TypeError, self.f.readinto)
206+
self.assertRaises(ValueError, self.f.readinto, bytearray(1))
207+
self.assertRaises(TypeError, self.f.seek)
208+
self.assertRaises(ValueError, self.f.seek, 0)
209+
self.assertRaises(TypeError, self.f.write)
206210
self.assertRaises(ValueError, self.f.write, b'')
211+
self.assertRaises(TypeError, self.f.writelines)
212+
self.assertRaises(ValueError, self.f.writelines, b'')
207213

208214
def testOpendir(self):
209215
# Issue 3703: opening a directory should fill the errno

Lib/test/test_io.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2163,6 +2163,17 @@ def test_constructor(self):
21632163
self.assertRaises(TypeError, t.__init__, b, newline=42)
21642164
self.assertRaises(ValueError, t.__init__, b, newline='xyzzy')
21652165

2166+
def test_uninitialized(self):
2167+
t = self.TextIOWrapper.__new__(self.TextIOWrapper)
2168+
del t
2169+
t = self.TextIOWrapper.__new__(self.TextIOWrapper)
2170+
self.assertRaises(Exception, repr, t)
2171+
self.assertRaisesRegex((ValueError, AttributeError),
2172+
'uninitialized|has no attribute',
2173+
t.read, 0)
2174+
t.__init__(self.MockRawIO())
2175+
self.assertEqual(t.read(0), '')
2176+
21662177
def test_non_text_encoding_codecs_are_rejected(self):
21672178
# Ensure the constructor complains if passed a codec that isn't
21682179
# marked as a text encoding
@@ -3024,8 +3035,6 @@ def test_initialization(self):
30243035
r = self.BytesIO(b"\xc3\xa9\n\n")
30253036
b = self.BufferedReader(r, 1000)
30263037
t = self.TextIOWrapper(b)
3027-
self.assertRaises(TypeError, t.__init__, b, newline=42)
3028-
self.assertRaises(ValueError, t.read)
30293038
self.assertRaises(ValueError, t.__init__, b, newline='xyzzy')
30303039
self.assertRaises(ValueError, t.read)
30313040

Modules/_io/_iomodule.c

Lines changed: 139 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -93,140 +93,145 @@ PyDoc_STRVAR(module_doc,
9393
/*
9494
* The main open() function
9595
*/
96-
PyDoc_STRVAR(open_doc,
97-
"open(file, mode='r', buffering=-1, encoding=None,\n"
98-
" errors=None, newline=None, closefd=True, opener=None) -> file object\n"
99-
"\n"
100-
"Open file and return a stream. Raise IOError upon failure.\n"
101-
"\n"
102-
"file is either a text or byte string giving the name (and the path\n"
103-
"if the file isn't in the current working directory) of the file to\n"
104-
"be opened or an integer file descriptor of the file to be\n"
105-
"wrapped. (If a file descriptor is given, it is closed when the\n"
106-
"returned I/O object is closed, unless closefd is set to False.)\n"
107-
"\n"
108-
"mode is an optional string that specifies the mode in which the file\n"
109-
"is opened. It defaults to 'r' which means open for reading in text\n"
110-
"mode. Other common values are 'w' for writing (truncating the file if\n"
111-
"it already exists), 'x' for creating and writing to a new file, and\n"
112-
"'a' for appending (which on some Unix systems, means that all writes\n"
113-
"append to the end of the file regardless of the current seek position).\n"
114-
"In text mode, if encoding is not specified the encoding used is platform\n"
115-
"dependent: locale.getpreferredencoding(False) is called to get the\n"
116-
"current locale encoding. (For reading and writing raw bytes use binary\n"
117-
"mode and leave encoding unspecified.) The available modes are:\n"
118-
"\n"
119-
"========= ===============================================================\n"
120-
"Character Meaning\n"
121-
"--------- ---------------------------------------------------------------\n"
122-
"'r' open for reading (default)\n"
123-
"'w' open for writing, truncating the file first\n"
124-
"'x' create a new file and open it for writing\n"
125-
"'a' open for writing, appending to the end of the file if it exists\n"
126-
"'b' binary mode\n"
127-
"'t' text mode (default)\n"
128-
"'+' open a disk file for updating (reading and writing)\n"
129-
"'U' universal newline mode (deprecated)\n"
130-
"========= ===============================================================\n"
131-
"\n"
132-
"The default mode is 'rt' (open for reading text). For binary random\n"
133-
"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n"
134-
"'r+b' opens the file without truncation. The 'x' mode implies 'w' and\n"
135-
"raises an `FileExistsError` if the file already exists.\n"
136-
"\n"
137-
"Python distinguishes between files opened in binary and text modes,\n"
138-
"even when the underlying operating system doesn't. Files opened in\n"
139-
"binary mode (appending 'b' to the mode argument) return contents as\n"
140-
"bytes objects without any decoding. In text mode (the default, or when\n"
141-
"'t' is appended to the mode argument), the contents of the file are\n"
142-
"returned as strings, the bytes having been first decoded using a\n"
143-
"platform-dependent encoding or using the specified encoding if given.\n"
144-
"\n"
145-
"'U' mode is deprecated and will raise an exception in future versions\n"
146-
"of Python. It has no effect in Python 3. Use newline to control\n"
147-
"universal newlines mode.\n"
148-
"\n"
149-
"buffering is an optional integer used to set the buffering policy.\n"
150-
"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n"
151-
"line buffering (only usable in text mode), and an integer > 1 to indicate\n"
152-
"the size of a fixed-size chunk buffer. When no buffering argument is\n"
153-
"given, the default buffering policy works as follows:\n"
154-
"\n"
155-
"* Binary files are buffered in fixed-size chunks; the size of the buffer\n"
156-
" is chosen using a heuristic trying to determine the underlying device's\n"
157-
" \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n"
158-
" On many systems, the buffer will typically be 4096 or 8192 bytes long.\n"
159-
"\n"
160-
"* \"Interactive\" text files (files for which isatty() returns True)\n"
161-
" use line buffering. Other text files use the policy described above\n"
162-
" for binary files.\n"
163-
"\n"
164-
"encoding is the name of the encoding used to decode or encode the\n"
165-
"file. This should only be used in text mode. The default encoding is\n"
166-
"platform dependent, but any encoding supported by Python can be\n"
167-
"passed. See the codecs module for the list of supported encodings.\n"
168-
"\n"
169-
"errors is an optional string that specifies how encoding errors are to\n"
170-
"be handled---this argument should not be used in binary mode. Pass\n"
171-
"'strict' to raise a ValueError exception if there is an encoding error\n"
172-
"(the default of None has the same effect), or pass 'ignore' to ignore\n"
173-
"errors. (Note that ignoring encoding errors can lead to data loss.)\n"
174-
"See the documentation for codecs.register or run 'help(codecs.Codec)'\n"
175-
"for a list of the permitted encoding error strings.\n"
176-
"\n"
177-
"newline controls how universal newlines works (it only applies to text\n"
178-
"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'. It works as\n"
179-
"follows:\n"
180-
"\n"
181-
"* On input, if newline is None, universal newlines mode is\n"
182-
" enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
183-
" these are translated into '\\n' before being returned to the\n"
184-
" caller. If it is '', universal newline mode is enabled, but line\n"
185-
" endings are returned to the caller untranslated. If it has any of\n"
186-
" the other legal values, input lines are only terminated by the given\n"
187-
" string, and the line ending is returned to the caller untranslated.\n"
188-
"\n"
189-
"* On output, if newline is None, any '\\n' characters written are\n"
190-
" translated to the system default line separator, os.linesep. If\n"
191-
" newline is '' or '\\n', no translation takes place. If newline is any\n"
192-
" of the other legal values, any '\\n' characters written are translated\n"
193-
" to the given string.\n"
194-
"\n"
195-
"If closefd is False, the underlying file descriptor will be kept open\n"
196-
"when the file is closed. This does not work when a file name is given\n"
197-
"and must be True in that case.\n"
198-
"\n"
199-
"A custom opener can be used by passing a callable as *opener*. The\n"
200-
"underlying file descriptor for the file object is then obtained by\n"
201-
"calling *opener* with (*file*, *flags*). *opener* must return an open\n"
202-
"file descriptor (passing os.open as *opener* results in functionality\n"
203-
"similar to passing None).\n"
204-
"\n"
205-
"open() returns a file object whose type depends on the mode, and\n"
206-
"through which the standard file operations such as reading and writing\n"
207-
"are performed. When open() is used to open a file in a text mode ('w',\n"
208-
"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n"
209-
"a file in a binary mode, the returned class varies: in read binary\n"
210-
"mode, it returns a BufferedReader; in write binary and append binary\n"
211-
"modes, it returns a BufferedWriter, and in read/write mode, it returns\n"
212-
"a BufferedRandom.\n"
213-
"\n"
214-
"It is also possible to use a string or bytearray as a file for both\n"
215-
"reading and writing. For strings StringIO can be used like a file\n"
216-
"opened in a text mode, and for bytes a BytesIO can be used like a file\n"
217-
"opened in a binary mode.\n"
218-
);
96+
/*[clinic input]
97+
module _io
98+
99+
_io.open
100+
file: object
101+
mode: str = "r"
102+
buffering: int = -1
103+
encoding: str(nullable=True) = NULL
104+
errors: str(nullable=True) = NULL
105+
newline: str(nullable=True) = NULL
106+
closefd: int(c_default="1") = True
107+
opener: object = None
108+
109+
Open file and return a stream. Raise IOError upon failure.
110+
111+
file is either a text or byte string giving the name (and the path
112+
if the file isn't in the current working directory) of the file to
113+
be opened or an integer file descriptor of the file to be
114+
wrapped. (If a file descriptor is given, it is closed when the
115+
returned I/O object is closed, unless closefd is set to False.)
116+
117+
mode is an optional string that specifies the mode in which the file
118+
is opened. It defaults to 'r' which means open for reading in text
119+
mode. Other common values are 'w' for writing (truncating the file if
120+
it already exists), 'x' for creating and writing to a new file, and
121+
'a' for appending (which on some Unix systems, means that all writes
122+
append to the end of the file regardless of the current seek position).
123+
In text mode, if encoding is not specified the encoding used is platform
124+
dependent: locale.getpreferredencoding(False) is called to get the
125+
current locale encoding. (For reading and writing raw bytes use binary
126+
mode and leave encoding unspecified.) The available modes are:
127+
128+
========= ===============================================================
129+
Character Meaning
130+
--------- ---------------------------------------------------------------
131+
'r' open for reading (default)
132+
'w' open for writing, truncating the file first
133+
'x' create a new file and open it for writing
134+
'a' open for writing, appending to the end of the file if it exists
135+
'b' binary mode
136+
't' text mode (default)
137+
'+' open a disk file for updating (reading and writing)
138+
'U' universal newline mode (deprecated)
139+
========= ===============================================================
140+
141+
The default mode is 'rt' (open for reading text). For binary random
142+
access, the mode 'w+b' opens and truncates the file to 0 bytes, while
143+
'r+b' opens the file without truncation. The 'x' mode implies 'w' and
144+
raises an `FileExistsError` if the file already exists.
145+
146+
Python distinguishes between files opened in binary and text modes,
147+
even when the underlying operating system doesn't. Files opened in
148+
binary mode (appending 'b' to the mode argument) return contents as
149+
bytes objects without any decoding. In text mode (the default, or when
150+
't' is appended to the mode argument), the contents of the file are
151+
returned as strings, the bytes having been first decoded using a
152+
platform-dependent encoding or using the specified encoding if given.
153+
154+
'U' mode is deprecated and will raise an exception in future versions
155+
of Python. It has no effect in Python 3. Use newline to control
156+
universal newlines mode.
157+
158+
buffering is an optional integer used to set the buffering policy.
159+
Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
160+
line buffering (only usable in text mode), and an integer > 1 to indicate
161+
the size of a fixed-size chunk buffer. When no buffering argument is
162+
given, the default buffering policy works as follows:
163+
164+
* Binary files are buffered in fixed-size chunks; the size of the buffer
165+
is chosen using a heuristic trying to determine the underlying device's
166+
"block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
167+
On many systems, the buffer will typically be 4096 or 8192 bytes long.
168+
169+
* "Interactive" text files (files for which isatty() returns True)
170+
use line buffering. Other text files use the policy described above
171+
for binary files.
172+
173+
encoding is the name of the encoding used to decode or encode the
174+
file. This should only be used in text mode. The default encoding is
175+
platform dependent, but any encoding supported by Python can be
176+
passed. See the codecs module for the list of supported encodings.
177+
178+
errors is an optional string that specifies how encoding errors are to
179+
be handled---this argument should not be used in binary mode. Pass
180+
'strict' to raise a ValueError exception if there is an encoding error
181+
(the default of None has the same effect), or pass 'ignore' to ignore
182+
errors. (Note that ignoring encoding errors can lead to data loss.)
183+
See the documentation for codecs.register or run 'help(codecs.Codec)'
184+
for a list of the permitted encoding error strings.
185+
186+
newline controls how universal newlines works (it only applies to text
187+
mode). It can be None, '', '\n', '\r', and '\r\n'. It works as
188+
follows:
189+
190+
* On input, if newline is None, universal newlines mode is
191+
enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
192+
these are translated into '\n' before being returned to the
193+
caller. If it is '', universal newline mode is enabled, but line
194+
endings are returned to the caller untranslated. If it has any of
195+
the other legal values, input lines are only terminated by the given
196+
string, and the line ending is returned to the caller untranslated.
197+
198+
* On output, if newline is None, any '\n' characters written are
199+
translated to the system default line separator, os.linesep. If
200+
newline is '' or '\n', no translation takes place. If newline is any
201+
of the other legal values, any '\n' characters written are translated
202+
to the given string.
203+
204+
If closefd is False, the underlying file descriptor will be kept open
205+
when the file is closed. This does not work when a file name is given
206+
and must be True in that case.
207+
208+
A custom opener can be used by passing a callable as *opener*. The
209+
underlying file descriptor for the file object is then obtained by
210+
calling *opener* with (*file*, *flags*). *opener* must return an open
211+
file descriptor (passing os.open as *opener* results in functionality
212+
similar to passing None).
213+
214+
open() returns a file object whose type depends on the mode, and
215+
through which the standard file operations such as reading and writing
216+
are performed. When open() is used to open a file in a text mode ('w',
217+
'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
218+
a file in a binary mode, the returned class varies: in read binary
219+
mode, it returns a BufferedReader; in write binary and append binary
220+
modes, it returns a BufferedWriter, and in read/write mode, it returns
221+
a BufferedRandom.
222+
223+
It is also possible to use a string or bytearray as a file for both
224+
reading and writing. For strings StringIO can be used like a file
225+
opened in a text mode, and for bytes a BytesIO can be used like a file
226+
opened in a binary mode.
227+
[clinic start generated code]*/
219228

220229
static PyObject *
221-
io_open(PyObject *self, PyObject *args, PyObject *kwds)
230+
_io_open_impl(PyModuleDef *module, PyObject *file, const char *mode,
231+
int buffering, const char *encoding, const char *errors,
232+
const char *newline, int closefd, PyObject *opener)
233+
/*[clinic end generated code: output=7615d0d746eb14d2 input=0541ce15691a82f2]*/
222234
{
223-
char *kwlist[] = {"file", "mode", "buffering",
224-
"encoding", "errors", "newline",
225-
"closefd", "opener", NULL};
226-
PyObject *file, *opener = Py_None;
227-
char *mode = "r";
228-
int buffering = -1, closefd = 1;
229-
char *encoding = NULL, *errors = NULL, *newline = NULL;
230235
unsigned i;
231236

232237
int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0;
@@ -242,13 +247,6 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
242247
_Py_IDENTIFIER(mode);
243248
_Py_IDENTIFIER(close);
244249

245-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist,
246-
&file, &mode, &buffering,
247-
&encoding, &errors, &newline,
248-
&closefd, &opener)) {
249-
return NULL;
250-
}
251-
252250
if (!PyUnicode_Check(file) &&
253251
!PyBytes_Check(file) &&
254252
!PyNumber_Check(file)) {
@@ -611,8 +609,10 @@ iomodule_free(PyObject *mod) {
611609
* Module definition
612610
*/
613611

612+
#include "clinic/_iomodule.c.h"
613+
614614
static PyMethodDef module_methods[] = {
615-
{"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
615+
_IO_OPEN_METHODDEF
616616
{NULL, NULL}
617617
};
618618

0 commit comments

Comments
 (0)