From 95723d09d2ae2321b000acdc0a513ab27c5646e7 Mon Sep 17 00:00:00 2001 From: Keming Date: Thu, 18 Sep 2025 18:05:20 +0800 Subject: [PATCH 1/7] gh-139105: Fix the EOF key shows on Windows for .help command Signed-off-by: Keming --- Lib/sqlite3/__main__.py | 15 ++++++---- Lib/test/test_sqlite3/test_cli.py | 28 +++++++++++++++++++ ...-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst | 1 + 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 35344ecceff5260..3b217785a31eabe 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -41,6 +41,13 @@ def execute(c, sql, suppress_errors=True, theme=theme_no_color): sys.exit(1) +def _eof_key(): + if sys.platform == "win32" and "idlelib.run" not in sys.modules: + return "CTRL-Z" + else: + return "CTRL-D" + + class SqliteInteractiveConsole(InteractiveConsole): """A simple SQLite REPL.""" @@ -69,7 +76,7 @@ def runsource(self, source, filename="", symbol="single"): print(f"Enter SQL code or one of the below commands, and press enter.\n\n" f"{t.builtin}.version{t.reset} Print underlying SQLite library version\n" f"{t.builtin}.help{t.reset} Print this help message\n" - f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to CTRL-D\n") + f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to {_eof_key()}\n") case "quit": sys.exit(0) case "": @@ -117,16 +124,12 @@ def main(*args): db_name = repr(args.filename) # Prepare REPL banner and prompts. - if sys.platform == "win32" and "idlelib.run" not in sys.modules: - eofkey = "CTRL-Z" - else: - eofkey = "CTRL-D" banner = dedent(f""" sqlite3 shell, running on SQLite version {sqlite3.sqlite_version} Connected to {db_name} Each command will be run using execute() on the cursor. - Type ".help" for more information; type ".quit" or {eofkey} to quit. + Type ".help" for more information; type ".quit" or {_eof_key()} to quit. """).strip() theme = get_theme() diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 720fa3c4c1ea8b5..1429946a4e812a0 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -109,6 +109,34 @@ def test_interact(self): self.assertEqual(out.count(self.PS1), 1) self.assertEqual(out.count(self.PS2), 0) + @unittest.skipUnless(sys.platform == "win32", "Windows EOF is CTRL-Z") + def test_interact_banner_win(self): + _, err = self.run_cli() + self.assertIn('type ".quit" or CTRL-Z to quit', err) + + @unittest.skipUnless(sys.platform != "win32", "Non-Windows EOF is CTRL-D") + def test_interact_banner_non_win(self): + _, err = self.run_cli() + self.assertIn('type ".quit" or CTRL-D to quit', err) + + @unittest.skipUnless(sys.platform == "win32", "Windows EOF is CTRL-Z") + def test_interact_help_eof_win(self): + out, err = self.run_cli(commands=(".help",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("Exit the CLI, equivalent to CTRL-Z", out) + self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + + @unittest.skipUnless(sys.platform != "win32", "Non-Windows EOF is CTRL-D") + def test_interact_help_eof_non_win(self): + out, err = self.run_cli(commands=(".help",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("Exit the CLI, equivalent to CTRL-D", out) + self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + def test_interact_quit(self): out, err = self.run_cli(commands=(".quit",)) self.assertIn(self.MEMORY_DB_MSG, err) diff --git a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst new file mode 100644 index 000000000000000..a6fa3605960d32a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst @@ -0,0 +1 @@ +Fix the EOF key shows in sqlite3 `.help` command on Windows. From a6e2f6de556de0b25ee15e61887166574684b7b1 Mon Sep 17 00:00:00 2001 From: Keming Date: Thu, 18 Sep 2025 18:16:23 +0800 Subject: [PATCH 2/7] fix misc lint Signed-off-by: Keming --- .../next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst index a6fa3605960d32a..59242948397c7a1 100644 --- a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst +++ b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst @@ -1 +1 @@ -Fix the EOF key shows in sqlite3 `.help` command on Windows. +Fix the EOF key shows in sqlite3 ``.help`` command on Windows. From 13338fffb2b17c70cee15dc4e34380c533eccec0 Mon Sep 17 00:00:00 2001 From: Keming Date: Thu, 18 Sep 2025 23:13:44 +0800 Subject: [PATCH 3/7] use a global const to store the EOF key Signed-off-by: Keming --- Lib/sqlite3/__main__.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 3b217785a31eabe..80f0d1250e045ef 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -15,6 +15,9 @@ from ._completer import completer +EOF_KEY = "CTRL-Z" if sys.platform == "win32" else "CTRL-D" + + def execute(c, sql, suppress_errors=True, theme=theme_no_color): """Helper that wraps execution of SQL code. @@ -41,13 +44,6 @@ def execute(c, sql, suppress_errors=True, theme=theme_no_color): sys.exit(1) -def _eof_key(): - if sys.platform == "win32" and "idlelib.run" not in sys.modules: - return "CTRL-Z" - else: - return "CTRL-D" - - class SqliteInteractiveConsole(InteractiveConsole): """A simple SQLite REPL.""" @@ -76,7 +72,7 @@ def runsource(self, source, filename="", symbol="single"): print(f"Enter SQL code or one of the below commands, and press enter.\n\n" f"{t.builtin}.version{t.reset} Print underlying SQLite library version\n" f"{t.builtin}.help{t.reset} Print this help message\n" - f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to {_eof_key()}\n") + f"{t.builtin}.quit{t.reset} Exit the CLI, equivalent to {EOF_KEY}\n") case "quit": sys.exit(0) case "": @@ -129,7 +125,7 @@ def main(*args): Connected to {db_name} Each command will be run using execute() on the cursor. - Type ".help" for more information; type ".quit" or {_eof_key()} to quit. + Type ".help" for more information; type ".quit" or {EOF_KEY} to quit. """).strip() theme = get_theme() From 18398aba2e3d45986e39192b8dc18d33b0e7b235 Mon Sep 17 00:00:00 2001 From: Keming Date: Thu, 18 Sep 2025 23:14:32 +0800 Subject: [PATCH 4/7] update misc news content Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- .../next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst index 59242948397c7a1..0ffd44887425730 100644 --- a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst +++ b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst @@ -1 +1 @@ -Fix the EOF key shows in sqlite3 ``.help`` command on Windows. +Correct the EOF key shown in the :mod:`sqlite3` CLI ``.help`` text on Windows. From cbc19df88106377fb81903494fd0d1a042454a60 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 29 Oct 2026 20:28:07 +0000 Subject: [PATCH 5/7] Minor adjustments --- Lib/sqlite3/__main__.py | 6 +++++- Lib/test/test_sqlite3/test_cli.py | 27 ++++----------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 80f0d1250e045ef..d2c55c2dc85a70b 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -15,7 +15,11 @@ from ._completer import completer -EOF_KEY = "CTRL-Z" if sys.platform == "win32" else "CTRL-D" +# IDLE uses CTRL-D for EOF on all platforms (gh-102628). +if sys.platform == "win32" and "idlelib.run" not in sys.modules: + EOF_KEY = "CTRL-Z" +else: + EOF_KEY = "CTRL-D" def execute(c, sql, suppress_errors=True, theme=theme_no_color): diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index 1429946a4e812a0..56471b2a358c849 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -82,6 +82,7 @@ class InteractiveSession(unittest.TestCase): MEMORY_DB_MSG = "Connected to a transient in-memory database" PS1 = "sqlite> " PS2 = "... " + EOF_KEY = "CTRL-Z" if sys.platform == "win32" else "CTRL-D" def run_cli(self, *args, commands=()): with ( @@ -104,35 +105,15 @@ def run_cli(self, *args, commands=()): def test_interact(self): out, err = self.run_cli() self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(f'type ".quit" or {self.EOF_KEY} to quit', err) self.assertEndsWith(out, self.PS1) self.assertEqual(out.count(self.PS1), 1) self.assertEqual(out.count(self.PS2), 0) - @unittest.skipUnless(sys.platform == "win32", "Windows EOF is CTRL-Z") - def test_interact_banner_win(self): - _, err = self.run_cli() - self.assertIn('type ".quit" or CTRL-Z to quit', err) - - @unittest.skipUnless(sys.platform != "win32", "Non-Windows EOF is CTRL-D") - def test_interact_banner_non_win(self): - _, err = self.run_cli() - self.assertIn('type ".quit" or CTRL-D to quit', err) - - @unittest.skipUnless(sys.platform == "win32", "Windows EOF is CTRL-Z") - def test_interact_help_eof_win(self): - out, err = self.run_cli(commands=(".help",)) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("Exit the CLI, equivalent to CTRL-Z", out) - self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 2) - self.assertEqual(out.count(self.PS2), 0) - - @unittest.skipUnless(sys.platform != "win32", "Non-Windows EOF is CTRL-D") - def test_interact_help_eof_non_win(self): + def test_interact_help(self): out, err = self.run_cli(commands=(".help",)) self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("Exit the CLI, equivalent to CTRL-D", out) + self.assertIn(f"Exit the CLI, equivalent to {self.EOF_KEY}", out) self.assertEndsWith(out, self.PS1) self.assertEqual(out.count(self.PS1), 2) self.assertEqual(out.count(self.PS2), 0) From 445774a91c85067a4d4dbd78e2d6393ef684a146 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 29 Oct 2026 20:37:44 +0000 Subject: [PATCH 6/7] Fix line endings From 78bb5798708bd4a258662a23b9d871b0c4b2c5f8 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 29 Oct 2026 20:46:26 +0000 Subject: [PATCH 7/7] Convert line endings in news entry --- .../next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst index 0ffd44887425730..0494a66b094eee9 100644 --- a/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst +++ b/Misc/NEWS.d/next/Library/2025-09-18-18-03-32.gh-issue-139105.1QQ_W4.rst @@ -1 +1 @@ -Correct the EOF key shown in the :mod:`sqlite3` CLI ``.help`` text on Windows. +Correct the EOF key shown in the :mod:`sqlite3` CLI ``.help`` text on Windows.