Skip to content

Commit 26f18b1

Browse files
committed
merge 3.4 (#23093)
2 parents 22b2b62 + cc479d0 commit 26f18b1

5 files changed

Lines changed: 61 additions & 42 deletions

File tree

Lib/_pyio.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ def __repr__(self):
812812
clsname = self.__class__.__qualname__
813813
try:
814814
name = self.name
815-
except AttributeError:
815+
except Exception:
816816
return "<{}.{}>".format(modname, clsname)
817817
else:
818818
return "<{}.{} name={!r}>".format(modname, clsname, name)
@@ -1640,13 +1640,13 @@ def __repr__(self):
16401640
self.__class__.__qualname__)
16411641
try:
16421642
name = self.name
1643-
except AttributeError:
1643+
except Exception:
16441644
pass
16451645
else:
16461646
result += " name={0!r}".format(name)
16471647
try:
16481648
mode = self.mode
1649-
except AttributeError:
1649+
except Exception:
16501650
pass
16511651
else:
16521652
result += " mode={0!r}".format(mode)

Lib/test/test_io.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,8 @@ def test_detach(self):
697697
self.assertIs(buf.detach(), raw)
698698
self.assertRaises(ValueError, buf.detach)
699699

700+
repr(buf) # Should still work
701+
700702
def test_fileno(self):
701703
rawio = self.MockRawIO()
702704
bufio = self.tp(rawio)
@@ -2087,6 +2089,12 @@ def test_detach(self):
20872089
self.assertEqual(r.getvalue(), b"howdy")
20882090
self.assertRaises(ValueError, t.detach)
20892091

2092+
# Operations independent of the detached stream should still work
2093+
repr(t)
2094+
self.assertEqual(t.encoding, "ascii")
2095+
self.assertEqual(t.errors, "strict")
2096+
self.assertFalse(t.line_buffering)
2097+
20902098
def test_repr(self):
20912099
raw = self.BytesIO("hello".encode("utf-8"))
20922100
b = self.BufferedReader(raw)
@@ -2104,6 +2112,9 @@ def test_repr(self):
21042112
self.assertEqual(repr(t),
21052113
"<%s.TextIOWrapper name=b'dummy' mode='r' encoding='utf-8'>" % modname)
21062114

2115+
t.buffer.detach()
2116+
repr(t) # Should not raise an exception
2117+
21072118
def test_line_buffering(self):
21082119
r = self.BytesIO()
21092120
b = self.BufferedWriter(r, 1000)
@@ -2904,6 +2915,9 @@ def test_initialization(self):
29042915
self.assertRaises(ValueError, t.__init__, b, newline='xyzzy')
29052916
self.assertRaises(ValueError, t.read)
29062917

2918+
t = self.TextIOWrapper.__new__(self.TextIOWrapper)
2919+
self.assertRaises(Exception, repr, t)
2920+
29072921
def test_garbage_collection(self):
29082922
# C TextIOWrapper objects are collected, and collecting them flushes
29092923
# all data to disk.

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ Core and Builtins
196196
Library
197197
-------
198198

199+
- Issue #23093: In the io, module allow more operations to work on detached
200+
streams.
201+
199202
- Issue #22585: On OpenBSD 5.6 and newer, os.urandom() now calls getentropy(),
200203
instead of reading /dev/urandom, to get pseudo-random bytes.
201204

Modules/_io/bufferedio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,7 @@ buffered_repr(buffered *self)
14041404

14051405
nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
14061406
if (nameobj == NULL) {
1407-
if (PyErr_ExceptionMatches(PyExc_AttributeError))
1407+
if (PyErr_ExceptionMatches(PyExc_Exception))
14081408
PyErr_Clear();
14091409
else
14101410
return NULL;

Modules/_io/textio.c

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,25 +1219,27 @@ textiowrapper_closed_get(textio *self, void *context);
12191219

12201220
#define CHECK_INITIALIZED(self) \
12211221
if (self->ok <= 0) { \
1222-
if (self->detached) { \
1223-
PyErr_SetString(PyExc_ValueError, \
1224-
"underlying buffer has been detached"); \
1225-
} else { \
1226-
PyErr_SetString(PyExc_ValueError, \
1227-
"I/O operation on uninitialized object"); \
1228-
} \
1222+
PyErr_SetString(PyExc_ValueError, \
1223+
"I/O operation on uninitialized object"); \
1224+
return NULL; \
1225+
}
1226+
1227+
#define CHECK_ATTACHED(self) \
1228+
CHECK_INITIALIZED(self); \
1229+
if (self->detached) { \
1230+
PyErr_SetString(PyExc_ValueError, \
1231+
"underlying buffer has been detached"); \
12291232
return NULL; \
12301233
}
12311234

1232-
#define CHECK_INITIALIZED_INT(self) \
1235+
#define CHECK_ATTACHED_INT(self) \
12331236
if (self->ok <= 0) { \
1234-
if (self->detached) { \
1235-
PyErr_SetString(PyExc_ValueError, \
1236-
"underlying buffer has been detached"); \
1237-
} else { \
1238-
PyErr_SetString(PyExc_ValueError, \
1239-
"I/O operation on uninitialized object"); \
1240-
} \
1237+
PyErr_SetString(PyExc_ValueError, \
1238+
"I/O operation on uninitialized object"); \
1239+
return -1; \
1240+
} else if (self->detached) { \
1241+
PyErr_SetString(PyExc_ValueError, \
1242+
"underlying buffer has been detached"); \
12411243
return -1; \
12421244
}
12431245

@@ -1246,15 +1248,14 @@ static PyObject *
12461248
textiowrapper_detach(textio *self)
12471249
{
12481250
PyObject *buffer, *res;
1249-
CHECK_INITIALIZED(self);
1251+
CHECK_ATTACHED(self);
12501252
res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
12511253
if (res == NULL)
12521254
return NULL;
12531255
Py_DECREF(res);
12541256
buffer = self->buffer;
12551257
self->buffer = NULL;
12561258
self->detached = 1;
1257-
self->ok = 0;
12581259
return buffer;
12591260
}
12601261

@@ -1299,7 +1300,7 @@ textiowrapper_write(textio *self, PyObject *args)
12991300
int haslf = 0;
13001301
int needflush = 0, text_needflush = 0;
13011302

1302-
CHECK_INITIALIZED(self);
1303+
CHECK_ATTACHED(self);
13031304

13041305
if (!PyArg_ParseTuple(args, "U:write", &text)) {
13051306
return NULL;
@@ -1562,7 +1563,7 @@ textiowrapper_read(textio *self, PyObject *args)
15621563
Py_ssize_t n = -1;
15631564
PyObject *result = NULL, *chunks = NULL;
15641565

1565-
CHECK_INITIALIZED(self);
1566+
CHECK_ATTACHED(self);
15661567

15671568
if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n))
15681569
return NULL;
@@ -1937,7 +1938,7 @@ textiowrapper_readline(textio *self, PyObject *args)
19371938
{
19381939
Py_ssize_t limit = -1;
19391940

1940-
CHECK_INITIALIZED(self);
1941+
CHECK_ATTACHED(self);
19411942
if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
19421943
return NULL;
19431944
}
@@ -2075,7 +2076,7 @@ textiowrapper_seek(textio *self, PyObject *args)
20752076
PyObject *res;
20762077
int cmp;
20772078

2078-
CHECK_INITIALIZED(self);
2079+
CHECK_ATTACHED(self);
20792080

20802081
if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence))
20812082
return NULL;
@@ -2255,7 +2256,7 @@ textiowrapper_tell(textio *self, PyObject *args)
22552256
Py_ssize_t dec_buffer_len;
22562257
int dec_flags;
22572258

2258-
CHECK_INITIALIZED(self);
2259+
CHECK_ATTACHED(self);
22592260
CHECK_CLOSED(self);
22602261

22612262
if (!self->seekable) {
@@ -2458,7 +2459,7 @@ textiowrapper_truncate(textio *self, PyObject *args)
24582459
PyObject *pos = Py_None;
24592460
PyObject *res;
24602461

2461-
CHECK_INITIALIZED(self)
2462+
CHECK_ATTACHED(self)
24622463
if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
24632464
return NULL;
24642465
}
@@ -2481,9 +2482,10 @@ textiowrapper_repr(textio *self)
24812482
res = PyUnicode_FromString("<_io.TextIOWrapper");
24822483
if (res == NULL)
24832484
return NULL;
2485+
24842486
nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
24852487
if (nameobj == NULL) {
2486-
if (PyErr_ExceptionMatches(PyExc_AttributeError))
2488+
if (PyErr_ExceptionMatches(PyExc_Exception))
24872489
PyErr_Clear();
24882490
else
24892491
goto error;
@@ -2499,7 +2501,7 @@ textiowrapper_repr(textio *self)
24992501
}
25002502
modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode);
25012503
if (modeobj == NULL) {
2502-
if (PyErr_ExceptionMatches(PyExc_AttributeError))
2504+
if (PyErr_ExceptionMatches(PyExc_Exception))
25032505
PyErr_Clear();
25042506
else
25052507
goto error;
@@ -2528,35 +2530,35 @@ textiowrapper_repr(textio *self)
25282530
static PyObject *
25292531
textiowrapper_fileno(textio *self, PyObject *args)
25302532
{
2531-
CHECK_INITIALIZED(self);
2533+
CHECK_ATTACHED(self);
25322534
return _PyObject_CallMethodId(self->buffer, &PyId_fileno, NULL);
25332535
}
25342536

25352537
static PyObject *
25362538
textiowrapper_seekable(textio *self, PyObject *args)
25372539
{
2538-
CHECK_INITIALIZED(self);
2540+
CHECK_ATTACHED(self);
25392541
return _PyObject_CallMethodId(self->buffer, &PyId_seekable, NULL);
25402542
}
25412543

25422544
static PyObject *
25432545
textiowrapper_readable(textio *self, PyObject *args)
25442546
{
2545-
CHECK_INITIALIZED(self);
2547+
CHECK_ATTACHED(self);
25462548
return _PyObject_CallMethodId(self->buffer, &PyId_readable, NULL);
25472549
}
25482550

25492551
static PyObject *
25502552
textiowrapper_writable(textio *self, PyObject *args)
25512553
{
2552-
CHECK_INITIALIZED(self);
2554+
CHECK_ATTACHED(self);
25532555
return _PyObject_CallMethodId(self->buffer, &PyId_writable, NULL);
25542556
}
25552557

25562558
static PyObject *
25572559
textiowrapper_isatty(textio *self, PyObject *args)
25582560
{
2559-
CHECK_INITIALIZED(self);
2561+
CHECK_ATTACHED(self);
25602562
return _PyObject_CallMethodId(self->buffer, &PyId_isatty, NULL);
25612563
}
25622564

@@ -2571,7 +2573,7 @@ textiowrapper_getstate(textio *self, PyObject *args)
25712573
static PyObject *
25722574
textiowrapper_flush(textio *self, PyObject *args)
25732575
{
2574-
CHECK_INITIALIZED(self);
2576+
CHECK_ATTACHED(self);
25752577
CHECK_CLOSED(self);
25762578
self->telling = self->seekable;
25772579
if (_textiowrapper_writeflush(self) < 0)
@@ -2584,7 +2586,7 @@ textiowrapper_close(textio *self, PyObject *args)
25842586
{
25852587
PyObject *res;
25862588
int r;
2587-
CHECK_INITIALIZED(self);
2589+
CHECK_ATTACHED(self);
25882590

25892591
res = textiowrapper_closed_get(self, NULL);
25902592
if (res == NULL)
@@ -2626,7 +2628,7 @@ textiowrapper_iternext(textio *self)
26262628
{
26272629
PyObject *line;
26282630

2629-
CHECK_INITIALIZED(self);
2631+
CHECK_ATTACHED(self);
26302632

26312633
self->telling = 0;
26322634
if (Py_TYPE(self) == &PyTextIOWrapper_Type) {
@@ -2662,22 +2664,22 @@ textiowrapper_iternext(textio *self)
26622664
static PyObject *
26632665
textiowrapper_name_get(textio *self, void *context)
26642666
{
2665-
CHECK_INITIALIZED(self);
2667+
CHECK_ATTACHED(self);
26662668
return _PyObject_GetAttrId(self->buffer, &PyId_name);
26672669
}
26682670

26692671
static PyObject *
26702672
textiowrapper_closed_get(textio *self, void *context)
26712673
{
2672-
CHECK_INITIALIZED(self);
2674+
CHECK_ATTACHED(self);
26732675
return PyObject_GetAttr(self->buffer, _PyIO_str_closed);
26742676
}
26752677

26762678
static PyObject *
26772679
textiowrapper_newlines_get(textio *self, void *context)
26782680
{
26792681
PyObject *res;
2680-
CHECK_INITIALIZED(self);
2682+
CHECK_ATTACHED(self);
26812683
if (self->decoder == NULL)
26822684
Py_RETURN_NONE;
26832685
res = PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
@@ -2703,15 +2705,15 @@ textiowrapper_errors_get(textio *self, void *context)
27032705
static PyObject *
27042706
textiowrapper_chunk_size_get(textio *self, void *context)
27052707
{
2706-
CHECK_INITIALIZED(self);
2708+
CHECK_ATTACHED(self);
27072709
return PyLong_FromSsize_t(self->chunk_size);
27082710
}
27092711

27102712
static int
27112713
textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context)
27122714
{
27132715
Py_ssize_t n;
2714-
CHECK_INITIALIZED_INT(self);
2716+
CHECK_ATTACHED_INT(self);
27152717
n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
27162718
if (n == -1 && PyErr_Occurred())
27172719
return -1;

0 commit comments

Comments
 (0)