mirror of
https://github.com/python/cpython.git
synced 2025-08-05 17:39:02 +00:00
bpo-31572: Get rid of PyObject_HasAttr() and _PyObject_HasAttrId() in the _io module. (#3726)
This commit is contained in:
parent
378edee0a3
commit
4d9aec0220
5 changed files with 114 additions and 72 deletions
|
@ -36,6 +36,7 @@ PyObject *_PyIO_str_getstate = NULL;
|
||||||
PyObject *_PyIO_str_isatty = NULL;
|
PyObject *_PyIO_str_isatty = NULL;
|
||||||
PyObject *_PyIO_str_newlines = NULL;
|
PyObject *_PyIO_str_newlines = NULL;
|
||||||
PyObject *_PyIO_str_nl = NULL;
|
PyObject *_PyIO_str_nl = NULL;
|
||||||
|
PyObject *_PyIO_str_peek = NULL;
|
||||||
PyObject *_PyIO_str_read = NULL;
|
PyObject *_PyIO_str_read = NULL;
|
||||||
PyObject *_PyIO_str_read1 = NULL;
|
PyObject *_PyIO_str_read1 = NULL;
|
||||||
PyObject *_PyIO_str_readable = NULL;
|
PyObject *_PyIO_str_readable = NULL;
|
||||||
|
@ -740,6 +741,7 @@ PyInit__io(void)
|
||||||
ADD_INTERNED(getstate)
|
ADD_INTERNED(getstate)
|
||||||
ADD_INTERNED(isatty)
|
ADD_INTERNED(isatty)
|
||||||
ADD_INTERNED(newlines)
|
ADD_INTERNED(newlines)
|
||||||
|
ADD_INTERNED(peek)
|
||||||
ADD_INTERNED(read)
|
ADD_INTERNED(read)
|
||||||
ADD_INTERNED(read1)
|
ADD_INTERNED(read1)
|
||||||
ADD_INTERNED(readable)
|
ADD_INTERNED(readable)
|
||||||
|
|
|
@ -164,6 +164,7 @@ extern PyObject *_PyIO_str_getstate;
|
||||||
extern PyObject *_PyIO_str_isatty;
|
extern PyObject *_PyIO_str_isatty;
|
||||||
extern PyObject *_PyIO_str_newlines;
|
extern PyObject *_PyIO_str_newlines;
|
||||||
extern PyObject *_PyIO_str_nl;
|
extern PyObject *_PyIO_str_nl;
|
||||||
|
extern PyObject *_PyIO_str_peek;
|
||||||
extern PyObject *_PyIO_str_read;
|
extern PyObject *_PyIO_str_read;
|
||||||
extern PyObject *_PyIO_str_read1;
|
extern PyObject *_PyIO_str_read1;
|
||||||
extern PyObject *_PyIO_str_readable;
|
extern PyObject *_PyIO_str_readable;
|
||||||
|
|
|
@ -1521,7 +1521,7 @@ static PyObject *
|
||||||
_bufferedreader_read_all(buffered *self)
|
_bufferedreader_read_all(buffered *self)
|
||||||
{
|
{
|
||||||
Py_ssize_t current_size;
|
Py_ssize_t current_size;
|
||||||
PyObject *res = NULL, *data = NULL, *tmp = NULL, *chunks = NULL;
|
PyObject *res = NULL, *data = NULL, *tmp = NULL, *chunks = NULL, *readall;
|
||||||
|
|
||||||
/* First copy what we have in the current buffer. */
|
/* First copy what we have in the current buffer. */
|
||||||
current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
|
current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
|
||||||
|
@ -1541,32 +1541,28 @@ _bufferedreader_read_all(buffered *self)
|
||||||
}
|
}
|
||||||
_bufferedreader_reset_buf(self);
|
_bufferedreader_reset_buf(self);
|
||||||
|
|
||||||
if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) {
|
readall = _PyObject_GetAttrWithoutError(self->raw, _PyIO_str_readall);
|
||||||
tmp = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL);
|
if (readall) {
|
||||||
|
tmp = _PyObject_CallNoArg(readall);
|
||||||
|
Py_DECREF(readall);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
if (tmp != Py_None && !PyBytes_Check(tmp)) {
|
if (tmp != Py_None && !PyBytes_Check(tmp)) {
|
||||||
PyErr_SetString(PyExc_TypeError, "readall() should return bytes");
|
PyErr_SetString(PyExc_TypeError, "readall() should return bytes");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (tmp == Py_None) {
|
if (current_size == 0) {
|
||||||
if (current_size == 0) {
|
|
||||||
res = Py_None;
|
|
||||||
goto cleanup;
|
|
||||||
} else {
|
|
||||||
res = data;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (current_size) {
|
|
||||||
PyBytes_Concat(&data, tmp);
|
|
||||||
res = data;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res = tmp;
|
res = tmp;
|
||||||
goto cleanup;
|
} else {
|
||||||
|
if (tmp != Py_None) {
|
||||||
|
PyBytes_Concat(&data, tmp);
|
||||||
|
}
|
||||||
|
res = data;
|
||||||
}
|
}
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
else if (PyErr_Occurred()) {
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks = PyList_New(0);
|
chunks = PyList_New(0);
|
||||||
|
|
|
@ -68,11 +68,9 @@ PyDoc_STRVAR(iobase_doc,
|
||||||
by whatever subclass. */
|
by whatever subclass. */
|
||||||
|
|
||||||
_Py_IDENTIFIER(__IOBase_closed);
|
_Py_IDENTIFIER(__IOBase_closed);
|
||||||
#define IS_CLOSED(self) \
|
|
||||||
_PyObject_HasAttrId(self, &PyId___IOBase_closed)
|
|
||||||
|
|
||||||
_Py_IDENTIFIER(read);
|
_Py_IDENTIFIER(read);
|
||||||
|
|
||||||
|
|
||||||
/* Internal methods */
|
/* Internal methods */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
iobase_unsupported(const char *message)
|
iobase_unsupported(const char *message)
|
||||||
|
@ -131,6 +129,24 @@ iobase_truncate(PyObject *self, PyObject *args)
|
||||||
return iobase_unsupported("truncate");
|
return iobase_unsupported("truncate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iobase_is_closed(PyObject *self)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
/* This gets the derived attribute, which is *not* __IOBase_closed
|
||||||
|
in most cases! */
|
||||||
|
res = _PyObject_GetAttrId(self, &PyId___IOBase_closed);
|
||||||
|
if (res == NULL) {
|
||||||
|
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Py_DECREF(res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Flush and close methods */
|
/* Flush and close methods */
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -146,45 +162,60 @@ _io__IOBase_flush_impl(PyObject *self)
|
||||||
/*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/
|
/*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/
|
||||||
{
|
{
|
||||||
/* XXX Should this return the number of bytes written??? */
|
/* XXX Should this return the number of bytes written??? */
|
||||||
if (IS_CLOSED(self)) {
|
int closed = iobase_is_closed(self);
|
||||||
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
if (!closed) {
|
||||||
iobase_closed(PyObject *self)
|
Py_RETURN_NONE;
|
||||||
{
|
}
|
||||||
PyObject *res;
|
if (closed > 0) {
|
||||||
int closed;
|
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
||||||
/* This gets the derived attribute, which is *not* __IOBase_closed
|
}
|
||||||
in most cases! */
|
return NULL;
|
||||||
res = PyObject_GetAttr(self, _PyIO_str_closed);
|
|
||||||
if (res == NULL)
|
|
||||||
return 0;
|
|
||||||
closed = PyObject_IsTrue(res);
|
|
||||||
Py_DECREF(res);
|
|
||||||
return closed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
iobase_closed_get(PyObject *self, void *context)
|
iobase_closed_get(PyObject *self, void *context)
|
||||||
{
|
{
|
||||||
return PyBool_FromLong(IS_CLOSED(self));
|
int closed = iobase_is_closed(self);
|
||||||
|
if (closed < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyBool_FromLong(closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iobase_check_closed(PyObject *self)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
int closed;
|
||||||
|
/* This gets the derived attribute, which is *not* __IOBase_closed
|
||||||
|
in most cases! */
|
||||||
|
res = _PyObject_GetAttrWithoutError(self, _PyIO_str_closed);
|
||||||
|
if (res == NULL) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
closed = PyObject_IsTrue(res);
|
||||||
|
Py_DECREF(res);
|
||||||
|
if (closed <= 0) {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyIOBase_check_closed(PyObject *self, PyObject *args)
|
_PyIOBase_check_closed(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
if (iobase_closed(self)) {
|
if (iobase_check_closed(self)) {
|
||||||
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (args == Py_True)
|
if (args == Py_True) {
|
||||||
return Py_None;
|
return Py_None;
|
||||||
else
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: IOBase thinks it has to maintain its own internal state in
|
/* XXX: IOBase thinks it has to maintain its own internal state in
|
||||||
|
@ -204,9 +235,14 @@ _io__IOBase_close_impl(PyObject *self)
|
||||||
/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
|
/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
|
||||||
{
|
{
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
int closed = iobase_is_closed(self);
|
||||||
|
|
||||||
if (IS_CLOSED(self))
|
if (closed < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (closed) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
|
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
|
||||||
|
|
||||||
|
@ -237,7 +273,7 @@ iobase_finalize(PyObject *self)
|
||||||
|
|
||||||
/* If `closed` doesn't exist or can't be evaluated as bool, then the
|
/* If `closed` doesn't exist or can't be evaluated as bool, then the
|
||||||
object is probably in an unusable state, so ignore. */
|
object is probably in an unusable state, so ignore. */
|
||||||
res = PyObject_GetAttr(self, _PyIO_str_closed);
|
res = _PyObject_GetAttrWithoutError(self, _PyIO_str_closed);
|
||||||
if (res == NULL) {
|
if (res == NULL) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
closed = -1;
|
closed = -1;
|
||||||
|
@ -428,7 +464,7 @@ _PyIOBase_check_writable(PyObject *self, PyObject *args)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
iobase_enter(PyObject *self, PyObject *args)
|
iobase_enter(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
if (iobase_check_closed(self))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Py_INCREF(self);
|
Py_INCREF(self);
|
||||||
|
@ -472,7 +508,7 @@ static PyObject *
|
||||||
_io__IOBase_isatty_impl(PyObject *self)
|
_io__IOBase_isatty_impl(PyObject *self)
|
||||||
/*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/
|
/*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/
|
||||||
{
|
{
|
||||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
if (iobase_check_closed(self))
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -499,24 +535,26 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
|
||||||
{
|
{
|
||||||
/* For backwards compatibility, a (slowish) readline(). */
|
/* For backwards compatibility, a (slowish) readline(). */
|
||||||
|
|
||||||
int has_peek = 0;
|
PyObject *peek, *buffer, *result;
|
||||||
PyObject *buffer, *result;
|
|
||||||
Py_ssize_t old_size = -1;
|
Py_ssize_t old_size = -1;
|
||||||
_Py_IDENTIFIER(peek);
|
|
||||||
|
|
||||||
if (_PyObject_HasAttrId(self, &PyId_peek))
|
peek = _PyObject_GetAttrWithoutError(self, _PyIO_str_peek);
|
||||||
has_peek = 1;
|
if (peek == NULL && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = PyByteArray_FromStringAndSize(NULL, 0);
|
buffer = PyByteArray_FromStringAndSize(NULL, 0);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL) {
|
||||||
|
Py_XDECREF(peek);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
while (limit < 0 || PyByteArray_GET_SIZE(buffer) < limit) {
|
while (limit < 0 || PyByteArray_GET_SIZE(buffer) < limit) {
|
||||||
Py_ssize_t nreadahead = 1;
|
Py_ssize_t nreadahead = 1;
|
||||||
PyObject *b;
|
PyObject *b;
|
||||||
|
|
||||||
if (has_peek) {
|
if (peek != NULL) {
|
||||||
PyObject *readahead = _PyObject_CallMethodId(self, &PyId_peek, "i", 1);
|
PyObject *readahead = PyObject_CallFunctionObjArgs(peek, _PyLong_One, NULL);
|
||||||
if (readahead == NULL) {
|
if (readahead == NULL) {
|
||||||
/* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
|
/* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
|
||||||
when EINTR occurs so we needn't do it ourselves. */
|
when EINTR occurs so we needn't do it ourselves. */
|
||||||
|
@ -593,9 +631,11 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
|
||||||
|
|
||||||
result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
|
result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
|
||||||
PyByteArray_GET_SIZE(buffer));
|
PyByteArray_GET_SIZE(buffer));
|
||||||
|
Py_XDECREF(peek);
|
||||||
Py_DECREF(buffer);
|
Py_DECREF(buffer);
|
||||||
return result;
|
return result;
|
||||||
fail:
|
fail:
|
||||||
|
Py_XDECREF(peek);
|
||||||
Py_DECREF(buffer);
|
Py_DECREF(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -603,7 +643,7 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
iobase_iter(PyObject *self)
|
iobase_iter(PyObject *self)
|
||||||
{
|
{
|
||||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
if (iobase_check_closed(self))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Py_INCREF(self);
|
Py_INCREF(self);
|
||||||
|
@ -716,7 +756,7 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines)
|
||||||
{
|
{
|
||||||
PyObject *iter, *res;
|
PyObject *iter, *res;
|
||||||
|
|
||||||
if (_PyIOBase_check_closed(self, Py_True) == NULL)
|
if (iobase_check_closed(self))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
iter = PyObject_GetIter(lines);
|
iter = PyObject_GetIter(lines);
|
||||||
|
|
|
@ -29,7 +29,6 @@ _Py_IDENTIFIER(mode);
|
||||||
_Py_IDENTIFIER(name);
|
_Py_IDENTIFIER(name);
|
||||||
_Py_IDENTIFIER(raw);
|
_Py_IDENTIFIER(raw);
|
||||||
_Py_IDENTIFIER(read);
|
_Py_IDENTIFIER(read);
|
||||||
_Py_IDENTIFIER(read1);
|
|
||||||
_Py_IDENTIFIER(readable);
|
_Py_IDENTIFIER(readable);
|
||||||
_Py_IDENTIFIER(replace);
|
_Py_IDENTIFIER(replace);
|
||||||
_Py_IDENTIFIER(reset);
|
_Py_IDENTIFIER(reset);
|
||||||
|
@ -1202,7 +1201,17 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
|
||||||
goto error;
|
goto error;
|
||||||
self->seekable = self->telling = r;
|
self->seekable = self->telling = r;
|
||||||
|
|
||||||
self->has_read1 = _PyObject_HasAttrId(buffer, &PyId_read1);
|
res = _PyObject_GetAttrWithoutError(buffer, _PyIO_str_read1);
|
||||||
|
if (res != NULL) {
|
||||||
|
Py_DECREF(res);
|
||||||
|
self->has_read1 = 1;
|
||||||
|
}
|
||||||
|
else if (!PyErr_Occurred()) {
|
||||||
|
self->has_read1 = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
self->encoding_start_of_stream = 0;
|
self->encoding_start_of_stream = 0;
|
||||||
if (_textiowrapper_fix_encoder_state(self) < 0) {
|
if (_textiowrapper_fix_encoder_state(self) < 0) {
|
||||||
|
@ -3013,15 +3022,9 @@ textiowrapper_newlines_get(textio *self, void *context)
|
||||||
CHECK_ATTACHED(self);
|
CHECK_ATTACHED(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_GetAttrWithoutError(self->decoder, _PyIO_str_newlines);
|
||||||
if (res == NULL) {
|
if (res == NULL && !PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
Py_RETURN_NONE;
|
||||||
PyErr_Clear();
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue