From 3ce43cc006f1b508873e95238a4e889d9dd41cbe Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Fri, 1 Dec 2023 05:05:55 -0900 Subject: [PATCH] gh-112510: Add `readline.backend` for the backend readline uses (GH-112511) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Donghee Na --- Doc/library/readline.rst | 15 ++++++++++----- Lib/site.py | 3 +-- Lib/test/test_pdb.py | 2 +- Lib/test/test_readline.py | 9 ++++++--- ...2023-11-29-02-26-32.gh-issue-112510.j-zXGc.rst | 1 + Modules/readline.c | 9 ++++++++- 6 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-29-02-26-32.gh-issue-112510.j-zXGc.rst diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst index 8fb0eca8df74d89..2e0f45ced30b9cd 100644 --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -27,16 +27,15 @@ Readline library in general. .. note:: The underlying Readline library API may be implemented by - the ``libedit`` library instead of GNU readline. + the ``editline`` (``libedit``) library instead of GNU readline. On macOS the :mod:`readline` module detects which library is being used at run time. - The configuration file for ``libedit`` is different from that + The configuration file for ``editline`` is different from that of GNU readline. If you programmatically load configuration strings - you can check for the text "libedit" in :const:`readline.__doc__` - to differentiate between GNU readline and libedit. + you can use :data:`backend` to determine which library is being used. - If you use *editline*/``libedit`` readline emulation on macOS, the + If you use ``editline``/``libedit`` readline emulation on macOS, the initialization file located in your home directory is named ``.editrc``. For example, the following content in ``~/.editrc`` will turn ON *vi* keybindings and TAB completion:: @@ -44,6 +43,12 @@ Readline library in general. python:bind -v python:bind ^I rl_complete +.. data:: backend + + The name of the underlying Readline library being used, either + ``"readline"`` or ``"editline"``. + + .. versionadded:: 3.13 Init file --------- diff --git a/Lib/site.py b/Lib/site.py index 672fa7b000ad02c..2517b7e5f1d22a3 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -444,8 +444,7 @@ def register_readline(): # Reading the initialization (config) file may not be enough to set a # completion key, so we set one first and then read the file. - readline_doc = getattr(readline, '__doc__', '') - if readline_doc is not None and 'libedit' in readline_doc: + if readline.backend == 'editline': readline.parse_and_bind('bind ^I rl_complete') else: readline.parse_and_bind('tab: complete') diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 2a279ca869e9c7b..50d8c8f52a909de 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3293,7 +3293,7 @@ def setUpClass(): # Ensure that the readline module is loaded # If this fails, the test is skipped because SkipTest will be raised readline = import_module('readline') - if readline.__doc__ and "libedit" in readline.__doc__: + if readline.backend == "editline": raise unittest.SkipTest("libedit readline is not supported for pdb") def test_basic_completion(self): diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 6c2726d3209ecf0..5e0e6f8dfac6510 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -19,7 +19,7 @@ if hasattr(readline, "_READLINE_LIBRARY_VERSION"): is_editline = ("EditLine wrapper" in readline._READLINE_LIBRARY_VERSION) else: - is_editline = (readline.__doc__ and "libedit" in readline.__doc__) + is_editline = readline.backend == "editline" def setUpModule(): @@ -145,6 +145,9 @@ def test_init(self): TERM='xterm-256color') self.assertEqual(stdout, b'') + def test_backend(self): + self.assertIn(readline.backend, ("readline", "editline")) + auto_history_script = """\ import readline readline.set_auto_history({}) @@ -171,7 +174,7 @@ def complete(text, state): if state == 0 and text == "$": return "$complete" return None - if "libedit" in getattr(readline, "__doc__", ""): + if readline.backend == "editline": readline.parse_and_bind(r'bind "\\t" rl_complete') else: readline.parse_and_bind(r'"\\t": complete') @@ -198,7 +201,7 @@ def test_nonascii(self): script = r"""import readline -is_editline = readline.__doc__ and "libedit" in readline.__doc__ +is_editline = readline.backend == "editline" inserted = "[\xEFnserted]" macro = "|t\xEB[after]" set_pre_input_hook = getattr(readline, "set_pre_input_hook", None) diff --git a/Misc/NEWS.d/next/Library/2023-11-29-02-26-32.gh-issue-112510.j-zXGc.rst b/Misc/NEWS.d/next/Library/2023-11-29-02-26-32.gh-issue-112510.j-zXGc.rst new file mode 100644 index 000000000000000..02de6fa80c1b3eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-29-02-26-32.gh-issue-112510.j-zXGc.rst @@ -0,0 +1 @@ +Add :data:`readline.backend` for the backend readline uses (``editline`` or ``readline``) diff --git a/Modules/readline.c b/Modules/readline.c index eb9a3d4693ee90b..afbb7f8f0ec18f6 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1538,6 +1538,7 @@ static struct PyModuleDef readlinemodule = { PyMODINIT_FUNC PyInit_readline(void) { + const char *backend = "readline"; PyObject *m; readlinestate *mod_state; @@ -1545,8 +1546,10 @@ PyInit_readline(void) using_libedit_emulation = 1; } - if (using_libedit_emulation) + if (using_libedit_emulation) { readlinemodule.m_doc = doc_module_le; + backend = "editline"; + } m = PyModule_Create(&readlinemodule); @@ -1568,6 +1571,10 @@ PyInit_readline(void) goto error; } + if (PyModule_AddStringConstant(m, "backend", backend) < 0) { + goto error; + } + mod_state = (readlinestate *) PyModule_GetState(m); if (mod_state == NULL){ goto error;