diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5b51273ed6b9a2..c29c33035e897c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -98,6 +98,14 @@ New Modules Improved Modules ================ +builtins +-------- + +* In the interactive REPL, typing "exit" or "quit" will directly exit the + interpreter session instead of printing a message suggesting to use "exit()" or + "quit()" instead. Contributed by Pablo Galindo in :issue:`44603`. + + fractions --------- diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-12-17-26-39.bpo-44603.wAxvpc.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-12-17-26-39.bpo-44603.wAxvpc.rst new file mode 100644 index 00000000000000..d69866cc6e8b5f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-12-17-26-39.bpo-44603.wAxvpc.rst @@ -0,0 +1,3 @@ +In the interactive REPL, typing "exit" or "quit" will directly exit the +interpreter session instead of printing a message suggesting to use "exit()" +or "quit()" instead. Patch by Pablo Galindo diff --git a/Python/pythonrun.c b/Python/pythonrun.c index f00e3eb0de803f..586339e7824500 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -188,6 +188,25 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag } +static int +PyRun_IsInteractiveExitCommand(mod_ty mod) { + if (asdl_seq_LEN(mod->v.Module.body) != 1) { + return 0; + } + stmt_ty statement = asdl_seq_GET(mod->v.Module.body, 0); + if (statement->kind != Expr_kind) { + return 0; + } + expr_ty expr = statement->v.Expr.value; + if (expr->kind != Name_kind) { + return 0; + } + if (expr->v.Name.ctx != Load) { + return 0; + } + return PyUnicode_CompareWithASCIIString(expr->v.Name.id, "exit") == 0 || + PyUnicode_CompareWithASCIIString(expr->v.Name.id, "quit") == 0; +} /* A PyRun_InteractiveOneObject() auxiliary function that does not print the * error on failure. */ @@ -267,6 +286,14 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, } return -1; } + + if (PyRun_IsInteractiveExitCommand(mod)) { + Py_INCREF(Py_None); + PyErr_SetObject(PyExc_SystemExit, Py_None); + _PyArena_Free(arena); + return -1; + } + m = PyImport_AddModuleObject(mod_name); if (m == NULL) { _PyArena_Free(arena);