From 52545d2857cfab49056f2e0334ed570a63be3e6d Mon Sep 17 00:00:00 2001 From: Collin Anderson Date: Wed, 1 Dec 2021 00:04:24 -0500 Subject: [PATCH] bpo-45944: Avoid calling isatty() for most open() calls --- Lib/_pyio.py | 3 ++- Modules/_io/_iomodule.c | 12 ++++++++++++ Modules/_io/fileio.c | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py index d7119742b9d22b..757c1d5718b5b2 100644 --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -237,7 +237,7 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None, result = raw try: line_buffering = False - if buffering == 1 or buffering < 0 and raw.isatty(): + if buffering == 1 or buffering < 0 and getattr(raw, '_size', 0) == 0 and raw.isatty(): buffering = -1 line_buffering = True if buffering < 0: @@ -1594,6 +1594,7 @@ def __init__(self, file, mode='r', closefd=True, opener=None): self._blksize = getattr(fdfstat, 'st_blksize', 0) if self._blksize <= 1: self._blksize = DEFAULT_BUFFER_SIZE + self._size = fdfstat.st_size if _setmode: # don't translate newlines (\r\n <=> \n) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index b4743fbd5e04f0..6d37a4ea5d3067 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -237,11 +237,13 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, char rawmode[6], *m; int line_buffering, is_number; + __int64_t size = 0; long isatty = 0; PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL, *path_or_fd = NULL; _Py_IDENTIFIER(_blksize); + _Py_IDENTIFIER(_size); _Py_IDENTIFIER(isatty); _Py_IDENTIFIER(mode); _Py_IDENTIFIER(close); @@ -381,6 +383,16 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, /* buffering */ if (buffering < 0) { + PyObject *size_obj; + size_obj = _PyObject_GetAttrId(raw, &PyId__size); + if (size_obj == NULL) + goto error; + size = PyLong_AsLongLong(size_obj); + Py_DECREF(size_obj); + if (size == -1 && PyErr_Occurred()) + goto error; + } + if (buffering < 0 && size == 0) { PyObject *res = _PyObject_CallMethodIdNoArgs(raw, &PyId_isatty); if (res == NULL) goto error; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index dd215e89399442..a42983e8bda9f2 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -66,6 +66,7 @@ typedef struct { unsigned int closefd : 1; char finalizing; unsigned int blksize; + __int64_t size; PyObject *weakreflist; PyObject *dict; } fileio; @@ -186,6 +187,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self->appending = 0; self->seekable = -1; self->blksize = 0; + self->size = 0; self->closefd = 1; self->weakreflist = NULL; } @@ -469,6 +471,7 @@ _Py_COMP_DIAG_POP if (fdfstat.st_blksize > 1) self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + self->size = fdfstat.st_size; } #if defined(MS_WINDOWS) || defined(__CYGWIN__) @@ -1184,6 +1187,7 @@ static PyGetSetDef fileio_getsetlist[] = { static PyMemberDef fileio_members[] = { {"_blksize", T_UINT, offsetof(fileio, blksize), 0}, + {"_size", T_UINT, offsetof(fileio, size), 0}, {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, {NULL} };