Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
f8c2001f
Commit
f8c2001f
authored
Dec 21, 2014
by
Benjamin Peterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
allow more operations to work on detached streams (closes #23093)
Patch by Martin Panter.
parent
22b21357
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
58 additions
and
40 deletions
+58
-40
Lib/_pyio.py
Lib/_pyio.py
+2
-2
Lib/test/test_io.py
Lib/test/test_io.py
+14
-0
Misc/NEWS
Misc/NEWS
+3
-0
Modules/_io/bufferedio.c
Modules/_io/bufferedio.c
+1
-1
Modules/_io/textio.c
Modules/_io/textio.c
+38
-37
No files found.
Lib/_pyio.py
View file @
f8c2001f
...
@@ -775,7 +775,7 @@ class _BufferedIOMixin(BufferedIOBase):
...
@@ -775,7 +775,7 @@ class _BufferedIOMixin(BufferedIOBase):
clsname
=
self
.
__class__
.
__name__
clsname
=
self
.
__class__
.
__name__
try
:
try
:
name
=
self
.
name
name
=
self
.
name
except
AttributeError
:
except
Exception
:
return
"<_pyio.{0}>"
.
format
(
clsname
)
return
"<_pyio.{0}>"
.
format
(
clsname
)
else
:
else
:
return
"<_pyio.{0} name={1!r}>"
.
format
(
clsname
,
name
)
return
"<_pyio.{0} name={1!r}>"
.
format
(
clsname
,
name
)
...
@@ -1538,7 +1538,7 @@ class TextIOWrapper(TextIOBase):
...
@@ -1538,7 +1538,7 @@ class TextIOWrapper(TextIOBase):
def
__repr__
(
self
):
def
__repr__
(
self
):
try
:
try
:
name
=
self
.
name
name
=
self
.
name
except
AttributeError
:
except
Exception
:
return
"<_pyio.TextIOWrapper encoding='{0}'>"
.
format
(
self
.
encoding
)
return
"<_pyio.TextIOWrapper encoding='{0}'>"
.
format
(
self
.
encoding
)
else
:
else
:
return
"<_pyio.TextIOWrapper name={0!r} encoding='{1}'>"
.
format
(
return
"<_pyio.TextIOWrapper name={0!r} encoding='{1}'>"
.
format
(
...
...
Lib/test/test_io.py
View file @
f8c2001f
...
@@ -654,6 +654,8 @@ class CommonBufferedTests:
...
@@ -654,6 +654,8 @@ class CommonBufferedTests:
self
.
assertIs
(
buf
.
detach
(),
raw
)
self
.
assertIs
(
buf
.
detach
(),
raw
)
self
.
assertRaises
(
ValueError
,
buf
.
detach
)
self
.
assertRaises
(
ValueError
,
buf
.
detach
)
repr
(
buf
)
# Should still work
def
test_fileno
(
self
):
def
test_fileno
(
self
):
rawio
=
self
.
MockRawIO
()
rawio
=
self
.
MockRawIO
()
bufio
=
self
.
tp
(
rawio
)
bufio
=
self
.
tp
(
rawio
)
...
@@ -1922,6 +1924,12 @@ class TextIOWrapperTest(unittest.TestCase):
...
@@ -1922,6 +1924,12 @@ class TextIOWrapperTest(unittest.TestCase):
self
.
assertEqual
(
r
.
getvalue
(),
b"howdy"
)
self
.
assertEqual
(
r
.
getvalue
(),
b"howdy"
)
self
.
assertRaises
(
ValueError
,
t
.
detach
)
self
.
assertRaises
(
ValueError
,
t
.
detach
)
# Operations independent of the detached stream should still work
repr
(
t
)
self
.
assertEqual
(
t
.
encoding
,
"ascii"
)
self
.
assertEqual
(
t
.
errors
,
"strict"
)
self
.
assertFalse
(
t
.
line_buffering
)
def
test_repr
(
self
):
def
test_repr
(
self
):
raw
=
self
.
BytesIO
(
"hello"
.
encode
(
"utf-8"
))
raw
=
self
.
BytesIO
(
"hello"
.
encode
(
"utf-8"
))
b
=
self
.
BufferedReader
(
raw
)
b
=
self
.
BufferedReader
(
raw
)
...
@@ -1936,6 +1944,9 @@ class TextIOWrapperTest(unittest.TestCase):
...
@@ -1936,6 +1944,9 @@ class TextIOWrapperTest(unittest.TestCase):
self
.
assertEqual
(
repr
(
t
),
self
.
assertEqual
(
repr
(
t
),
"<%s.TextIOWrapper name='dummy' encoding='utf-8'>"
%
modname
)
"<%s.TextIOWrapper name='dummy' encoding='utf-8'>"
%
modname
)
t
.
buffer
.
detach
()
repr
(
t
)
# Should not raise an exception
def
test_line_buffering
(
self
):
def
test_line_buffering
(
self
):
r
=
self
.
BytesIO
()
r
=
self
.
BytesIO
()
b
=
self
.
BufferedWriter
(
r
,
1000
)
b
=
self
.
BufferedWriter
(
r
,
1000
)
...
@@ -2537,6 +2548,9 @@ class CTextIOWrapperTest(TextIOWrapperTest):
...
@@ -2537,6 +2548,9 @@ class CTextIOWrapperTest(TextIOWrapperTest):
self
.
assertRaises
(
ValueError
,
t
.
__init__
,
b
,
newline
=
'xyzzy'
)
self
.
assertRaises
(
ValueError
,
t
.
__init__
,
b
,
newline
=
'xyzzy'
)
self
.
assertRaises
(
ValueError
,
t
.
read
)
self
.
assertRaises
(
ValueError
,
t
.
read
)
t
=
self
.
TextIOWrapper
.
__new__
(
self
.
TextIOWrapper
)
self
.
assertRaises
(
Exception
,
repr
,
t
)
def
test_garbage_collection
(
self
):
def
test_garbage_collection
(
self
):
# C TextIOWrapper objects are collected, and collecting them flushes
# C TextIOWrapper objects are collected, and collecting them flushes
# all data to disk.
# all data to disk.
...
...
Misc/NEWS
View file @
f8c2001f
...
@@ -15,6 +15,9 @@ Core and Builtins
...
@@ -15,6 +15,9 @@ Core and Builtins
Library
Library
-------
-------
- Issue #23093: In the io, module allow more operations to work on detached
streams.
- Issue #23071: Added missing names to codecs.__all__. Patch by Martin Panter.
- Issue #23071: Added missing names to codecs.__all__. Patch by Martin Panter.
- Issue #23016: A warning no longer produces an AttributeError when sys.stderr
- Issue #23016: A warning no longer produces an AttributeError when sys.stderr
...
...
Modules/_io/bufferedio.c
View file @
f8c2001f
...
@@ -1222,7 +1222,7 @@ buffered_repr(buffered *self)
...
@@ -1222,7 +1222,7 @@ buffered_repr(buffered *self)
nameobj
=
PyObject_GetAttrString
((
PyObject
*
)
self
,
"name"
);
nameobj
=
PyObject_GetAttrString
((
PyObject
*
)
self
,
"name"
);
if
(
nameobj
==
NULL
)
{
if
(
nameobj
==
NULL
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_
AttributeError
))
if
(
PyErr_ExceptionMatches
(
PyExc_
Exception
))
PyErr_Clear
();
PyErr_Clear
();
else
else
return
NULL
;
return
NULL
;
...
...
Modules/_io/textio.c
View file @
f8c2001f
...
@@ -1152,25 +1152,27 @@ textiowrapper_closed_get(textio *self, void *context);
...
@@ -1152,25 +1152,27 @@ textiowrapper_closed_get(textio *self, void *context);
#define CHECK_INITIALIZED(self) \
#define CHECK_INITIALIZED(self) \
if (self->ok <= 0) { \
if (self->ok <= 0) { \
if (self->detached) { \
PyErr_SetString(PyExc_ValueError, \
PyErr_SetString(PyExc_ValueError, \
"I/O operation on uninitialized object"); \
"underlying buffer has been detached"); \
return NULL; \
} else { \
}
PyErr_SetString(PyExc_ValueError, \
"I/O operation on uninitialized object"); \
#define CHECK_ATTACHED(self) \
} \
CHECK_INITIALIZED(self); \
if (self->detached) { \
PyErr_SetString(PyExc_ValueError, \
"underlying buffer has been detached"); \
return NULL; \
return NULL; \
}
}
#define CHECK_
INITIALIZ
ED_INT(self) \
#define CHECK_
ATTACH
ED_INT(self) \
if (self->ok <= 0) { \
if (self->ok <= 0) { \
if (self->detached) { \
PyErr_SetString(PyExc_ValueError, \
PyErr_SetString(PyExc_ValueError, \
"I/O operation on uninitialized object"); \
"underlying buffer has been detached"); \
return -1; \
} else { \
} else if (self->detached) { \
PyErr_SetString(PyExc_ValueError, \
PyErr_SetString(PyExc_ValueError, \
"I/O operation on uninitialized object"); \
"underlying buffer has been detached"); \
} \
return -1; \
return -1; \
}
}
...
@@ -1179,7 +1181,7 @@ static PyObject *
...
@@ -1179,7 +1181,7 @@ static PyObject *
textiowrapper_detach
(
textio
*
self
)
textiowrapper_detach
(
textio
*
self
)
{
{
PyObject
*
buffer
,
*
res
;
PyObject
*
buffer
,
*
res
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
res
=
PyObject_CallMethodObjArgs
((
PyObject
*
)
self
,
_PyIO_str_flush
,
NULL
);
res
=
PyObject_CallMethodObjArgs
((
PyObject
*
)
self
,
_PyIO_str_flush
,
NULL
);
if
(
res
==
NULL
)
if
(
res
==
NULL
)
return
NULL
;
return
NULL
;
...
@@ -1187,7 +1189,6 @@ textiowrapper_detach(textio *self)
...
@@ -1187,7 +1189,6 @@ textiowrapper_detach(textio *self)
buffer
=
self
->
buffer
;
buffer
=
self
->
buffer
;
self
->
buffer
=
NULL
;
self
->
buffer
=
NULL
;
self
->
detached
=
1
;
self
->
detached
=
1
;
self
->
ok
=
0
;
return
buffer
;
return
buffer
;
}
}
...
@@ -1244,7 +1245,7 @@ textiowrapper_write(textio *self, PyObject *args)
...
@@ -1244,7 +1245,7 @@ textiowrapper_write(textio *self, PyObject *args)
int
haslf
=
0
;
int
haslf
=
0
;
int
needflush
=
0
;
int
needflush
=
0
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
if
(
!
PyArg_ParseTuple
(
args
,
"U:write"
,
&
text
))
{
if
(
!
PyArg_ParseTuple
(
args
,
"U:write"
,
&
text
))
{
return
NULL
;
return
NULL
;
...
@@ -1486,7 +1487,7 @@ textiowrapper_read(textio *self, PyObject *args)
...
@@ -1486,7 +1487,7 @@ textiowrapper_read(textio *self, PyObject *args)
Py_ssize_t
n
=
-
1
;
Py_ssize_t
n
=
-
1
;
PyObject
*
result
=
NULL
,
*
chunks
=
NULL
;
PyObject
*
result
=
NULL
,
*
chunks
=
NULL
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
if
(
!
PyArg_ParseTuple
(
args
,
"|O&:read"
,
&
_PyIO_ConvertSsize_t
,
&
n
))
if
(
!
PyArg_ParseTuple
(
args
,
"|O&:read"
,
&
_PyIO_ConvertSsize_t
,
&
n
))
return
NULL
;
return
NULL
;
...
@@ -1849,7 +1850,7 @@ textiowrapper_readline(textio *self, PyObject *args)
...
@@ -1849,7 +1850,7 @@ textiowrapper_readline(textio *self, PyObject *args)
PyObject
*
limitobj
=
NULL
;
PyObject
*
limitobj
=
NULL
;
Py_ssize_t
limit
=
-
1
;
Py_ssize_t
limit
=
-
1
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
if
(
!
PyArg_ParseTuple
(
args
,
"|O:readline"
,
&
limitobj
))
{
if
(
!
PyArg_ParseTuple
(
args
,
"|O:readline"
,
&
limitobj
))
{
return
NULL
;
return
NULL
;
}
}
...
@@ -2004,7 +2005,7 @@ textiowrapper_seek(textio *self, PyObject *args)
...
@@ -2004,7 +2005,7 @@ textiowrapper_seek(textio *self, PyObject *args)
PyObject
*
res
;
PyObject
*
res
;
int
cmp
;
int
cmp
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
if
(
!
PyArg_ParseTuple
(
args
,
"O|i:seek"
,
&
cookieObj
,
&
whence
))
if
(
!
PyArg_ParseTuple
(
args
,
"O|i:seek"
,
&
cookieObj
,
&
whence
))
return
NULL
;
return
NULL
;
...
@@ -2189,7 +2190,7 @@ textiowrapper_tell(textio *self, PyObject *args)
...
@@ -2189,7 +2190,7 @@ textiowrapper_tell(textio *self, PyObject *args)
PyObject
*
saved_state
=
NULL
;
PyObject
*
saved_state
=
NULL
;
char
*
input
,
*
input_end
;
char
*
input
,
*
input_end
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
CHECK_CLOSED
(
self
);
CHECK_CLOSED
(
self
);
if
(
!
self
->
seekable
)
{
if
(
!
self
->
seekable
)
{
...
@@ -2353,7 +2354,7 @@ textiowrapper_truncate(textio *self, PyObject *args)
...
@@ -2353,7 +2354,7 @@ textiowrapper_truncate(textio *self, PyObject *args)
PyObject
*
pos
=
Py_None
;
PyObject
*
pos
=
Py_None
;
PyObject
*
res
;
PyObject
*
res
;
CHECK_
INITIALIZ
ED
(
self
)
CHECK_
ATTACH
ED
(
self
)
if
(
!
PyArg_ParseTuple
(
args
,
"|O:truncate"
,
&
pos
))
{
if
(
!
PyArg_ParseTuple
(
args
,
"|O:truncate"
,
&
pos
))
{
return
NULL
;
return
NULL
;
}
}
...
@@ -2376,7 +2377,7 @@ textiowrapper_repr(textio *self)
...
@@ -2376,7 +2377,7 @@ textiowrapper_repr(textio *self)
nameobj
=
PyObject_GetAttrString
((
PyObject
*
)
self
,
"name"
);
nameobj
=
PyObject_GetAttrString
((
PyObject
*
)
self
,
"name"
);
if
(
nameobj
==
NULL
)
{
if
(
nameobj
==
NULL
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_
AttributeError
))
if
(
PyErr_ExceptionMatches
(
PyExc_
Exception
))
PyErr_Clear
();
PyErr_Clear
();
else
else
goto
error
;
goto
error
;
...
@@ -2408,42 +2409,42 @@ error:
...
@@ -2408,42 +2409,42 @@ error:
static
PyObject
*
static
PyObject
*
textiowrapper_fileno
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_fileno
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_CallMethod
(
self
->
buffer
,
"fileno"
,
NULL
);
return
PyObject_CallMethod
(
self
->
buffer
,
"fileno"
,
NULL
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_seekable
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_seekable
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_CallMethod
(
self
->
buffer
,
"seekable"
,
NULL
);
return
PyObject_CallMethod
(
self
->
buffer
,
"seekable"
,
NULL
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_readable
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_readable
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_CallMethod
(
self
->
buffer
,
"readable"
,
NULL
);
return
PyObject_CallMethod
(
self
->
buffer
,
"readable"
,
NULL
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_writable
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_writable
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_CallMethod
(
self
->
buffer
,
"writable"
,
NULL
);
return
PyObject_CallMethod
(
self
->
buffer
,
"writable"
,
NULL
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_isatty
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_isatty
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_CallMethod
(
self
->
buffer
,
"isatty"
,
NULL
);
return
PyObject_CallMethod
(
self
->
buffer
,
"isatty"
,
NULL
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_flush
(
textio
*
self
,
PyObject
*
args
)
textiowrapper_flush
(
textio
*
self
,
PyObject
*
args
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
CHECK_CLOSED
(
self
);
CHECK_CLOSED
(
self
);
self
->
telling
=
self
->
seekable
;
self
->
telling
=
self
->
seekable
;
if
(
_textiowrapper_writeflush
(
self
)
<
0
)
if
(
_textiowrapper_writeflush
(
self
)
<
0
)
...
@@ -2456,7 +2457,7 @@ textiowrapper_close(textio *self, PyObject *args)
...
@@ -2456,7 +2457,7 @@ textiowrapper_close(textio *self, PyObject *args)
{
{
PyObject
*
res
;
PyObject
*
res
;
int
r
;
int
r
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
res
=
textiowrapper_closed_get
(
self
,
NULL
);
res
=
textiowrapper_closed_get
(
self
,
NULL
);
if
(
res
==
NULL
)
if
(
res
==
NULL
)
...
@@ -2498,7 +2499,7 @@ textiowrapper_iternext(textio *self)
...
@@ -2498,7 +2499,7 @@ textiowrapper_iternext(textio *self)
{
{
PyObject
*
line
;
PyObject
*
line
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
self
->
telling
=
0
;
self
->
telling
=
0
;
if
(
Py_TYPE
(
self
)
==
&
PyTextIOWrapper_Type
)
{
if
(
Py_TYPE
(
self
)
==
&
PyTextIOWrapper_Type
)
{
...
@@ -2534,14 +2535,14 @@ textiowrapper_iternext(textio *self)
...
@@ -2534,14 +2535,14 @@ textiowrapper_iternext(textio *self)
static
PyObject
*
static
PyObject
*
textiowrapper_name_get
(
textio
*
self
,
void
*
context
)
textiowrapper_name_get
(
textio
*
self
,
void
*
context
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_GetAttrString
(
self
->
buffer
,
"name"
);
return
PyObject_GetAttrString
(
self
->
buffer
,
"name"
);
}
}
static
PyObject
*
static
PyObject
*
textiowrapper_closed_get
(
textio
*
self
,
void
*
context
)
textiowrapper_closed_get
(
textio
*
self
,
void
*
context
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyObject_GetAttr
(
self
->
buffer
,
_PyIO_str_closed
);
return
PyObject_GetAttr
(
self
->
buffer
,
_PyIO_str_closed
);
}
}
...
@@ -2549,7 +2550,7 @@ static PyObject *
...
@@ -2549,7 +2550,7 @@ static PyObject *
textiowrapper_newlines_get
(
textio
*
self
,
void
*
context
)
textiowrapper_newlines_get
(
textio
*
self
,
void
*
context
)
{
{
PyObject
*
res
;
PyObject
*
res
;
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
if
(
self
->
decoder
==
NULL
)
if
(
self
->
decoder
==
NULL
)
Py_RETURN_NONE
;
Py_RETURN_NONE
;
res
=
PyObject_GetAttr
(
self
->
decoder
,
_PyIO_str_newlines
);
res
=
PyObject_GetAttr
(
self
->
decoder
,
_PyIO_str_newlines
);
...
@@ -2576,7 +2577,7 @@ textiowrapper_errors_get(textio *self, void *context)
...
@@ -2576,7 +2577,7 @@ textiowrapper_errors_get(textio *self, void *context)
static
PyObject
*
static
PyObject
*
textiowrapper_chunk_size_get
(
textio
*
self
,
void
*
context
)
textiowrapper_chunk_size_get
(
textio
*
self
,
void
*
context
)
{
{
CHECK_
INITIALIZ
ED
(
self
);
CHECK_
ATTACH
ED
(
self
);
return
PyLong_FromSsize_t
(
self
->
chunk_size
);
return
PyLong_FromSsize_t
(
self
->
chunk_size
);
}
}
...
@@ -2584,7 +2585,7 @@ static int
...
@@ -2584,7 +2585,7 @@ static int
textiowrapper_chunk_size_set
(
textio
*
self
,
PyObject
*
arg
,
void
*
context
)
textiowrapper_chunk_size_set
(
textio
*
self
,
PyObject
*
arg
,
void
*
context
)
{
{
Py_ssize_t
n
;
Py_ssize_t
n
;
CHECK_
INITIALIZ
ED_INT
(
self
);
CHECK_
ATTACH
ED_INT
(
self
);
n
=
PyNumber_AsSsize_t
(
arg
,
PyExc_TypeError
);
n
=
PyNumber_AsSsize_t
(
arg
,
PyExc_TypeError
);
if
(
n
==
-
1
&&
PyErr_Occurred
())
if
(
n
==
-
1
&&
PyErr_Occurred
())
return
-
1
;
return
-
1
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment