From 17357108732c731d6ed4f2bd123ee6ba1ff6891b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 17 Jun 2022 15:19:28 +0200 Subject: gh-77782: Py_FdIsInteractive() now uses PyConfig.interactive (#93916) --- Doc/c-api/sys.rst | 4 +++- Lib/test/test_capi.py | 17 +++++++++-------- Python/ceval.c | 6 +++--- Python/initconfig.c | 2 +- Python/pylifecycle.c | 22 ++++++++++++---------- Python/pystate.c | 1 + 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 7b71467..32c2bc8 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -21,10 +21,12 @@ Operating System Utilities Return true (nonzero) if the standard I/O file *fp* with name *filename* is deemed interactive. This is the case for files for which ``isatty(fileno(fp))`` - is true. If the global flag :c:data:`Py_InteractiveFlag` is true, this function + is true. If the :c:member:`PyConfig.interactive` is non-zero, this function also returns true if the *filename* pointer is ``NULL`` or if the name is equal to one of the strings ``''`` or ``'???'``. + This function must not be called before Python is initialized. + .. c:function:: void PyOS_BeforeFork() diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index cd6a4de..7e571ab 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -70,16 +70,17 @@ class CAPITest(unittest.TestCase): 'import _testcapi;' '_testcapi.crash_no_current_thread()'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + text=True) (out, err) = p.communicate() - self.assertEqual(out, b'') + self.assertEqual(out, '') # This used to cause an infinite loop. - self.assertTrue(err.rstrip().startswith( - b'Fatal Python error: ' - b'PyThreadState_Get: ' - b'the function must be called with the GIL held, ' - b'but the GIL is released ' - b'(the current Python thread state is NULL)'), + msg = ("Fatal Python error: PyThreadState_Get: " + "the function must be called with the GIL held, " + "after Python initialization and before Python finalization, " + "but the GIL is released " + "(the current Python thread state is NULL)") + self.assertTrue(err.rstrip().startswith(msg), err) def test_memoryview_from_NULL_pointer(self): diff --git a/Python/ceval.c b/Python/ceval.c index ca3797c..0d6855e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -347,9 +347,9 @@ void _Py_NO_RETURN _Py_FatalError_TstateNULL(const char *func) { _Py_FatalErrorFunc(func, - "the function must be called with the GIL held, " - "but the GIL is released " - "(the current Python thread state is NULL)"); + "the function must be called with the GIL held, " + "after Python initialization and before Python finalization, " + "but the GIL is released (the current Python thread state is NULL)"); } int diff --git a/Python/initconfig.c b/Python/initconfig.c index 86dcdd9..e5b8787 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -180,7 +180,7 @@ int Py_UTF8Mode = 0; int Py_DebugFlag = 0; /* Needed by parser.c */ int Py_VerboseFlag = 0; /* Needed by import.c */ int Py_QuietFlag = 0; /* Needed by sysmodule.c */ -int Py_InteractiveFlag = 0; /* Needed by Py_FdIsInteractive() below */ +int Py_InteractiveFlag = 0; /* Previously, was used by Py_FdIsInteractive() */ int Py_InspectFlag = 0; /* Needed to determine whether to exit at SystemExit */ int Py_OptimizeFlag = 0; /* Needed by compile.c */ int Py_NoSiteFlag = 0; /* Suppress 'import site' */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0937cce..c2c9e90 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2938,28 +2938,30 @@ Py_Exit(int sts) int Py_FdIsInteractive(FILE *fp, const char *filename) { - if (isatty((int)fileno(fp))) + if (isatty(fileno(fp))) { return 1; - if (!Py_InteractiveFlag) + } + if (!_Py_GetConfig()->interactive) { return 0; - return (filename == NULL) || - (strcmp(filename, "") == 0) || - (strcmp(filename, "???") == 0); + } + return ((filename == NULL) + || (strcmp(filename, "") == 0) + || (strcmp(filename, "???") == 0)); } int _Py_FdIsInteractive(FILE *fp, PyObject *filename) { - if (isatty((int)fileno(fp))) { + if (isatty(fileno(fp))) { return 1; } - if (!Py_InteractiveFlag) { + if (!_Py_GetConfig()->interactive) { return 0; } - return (filename == NULL) || - (PyUnicode_CompareWithASCIIString(filename, "") == 0) || - (PyUnicode_CompareWithASCIIString(filename, "???") == 0); + return ((filename == NULL) + || (PyUnicode_CompareWithASCIIString(filename, "") == 0) + || (PyUnicode_CompareWithASCIIString(filename, "???") == 0)); } diff --git a/Python/pystate.c b/Python/pystate.c index df56c05..3cc7613 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2136,6 +2136,7 @@ _Py_GetConfig(void) { assert(PyGILState_Check()); PyThreadState *tstate = _PyThreadState_GET(); + _Py_EnsureTstateNotNULL(tstate); return _PyInterpreterState_GetConfig(tstate->interp); } -- cgit v0.12