Skip to content

Revert "gh-133390: Support SQL keyword completion for sqlite3 CLI (#133393)" temporarily #135232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,6 @@ shelve
(Contributed by Andrea Oliveri in :gh:`134004`.)


sqlite3
-------

* Support SQL keyword completion in the :mod:`sqlite3` command-line interface.
(Contributed by Long Tan in :gh:`133393`.)


ssl
---

Expand Down
11 changes: 6 additions & 5 deletions Lib/sqlite3/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from textwrap import dedent
from _colorize import get_theme, theme_no_color

from ._completer import completer


def execute(c, sql, suppress_errors=True, theme=theme_no_color):
"""Helper that wraps execution of SQL code.
Expand Down Expand Up @@ -138,9 +136,12 @@ def main(*args):
execute(con, args.sql, suppress_errors=False, theme=theme)
else:
# No SQL provided; start the REPL.
with completer():
console = SqliteInteractiveConsole(con, use_color=True)
console.interact(banner, exitmsg="")
console = SqliteInteractiveConsole(con, use_color=True)
try:
import readline # noqa: F401
except ImportError:
pass
console.interact(banner, exitmsg="")
finally:
con.close()

Expand Down
42 changes: 0 additions & 42 deletions Lib/sqlite3/_completer.py

This file was deleted.

98 changes: 0 additions & 98 deletions Lib/test/test_sqlite3/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
"""sqlite3 CLI tests."""
import sqlite3
import sys
import textwrap
import unittest

from sqlite3.__main__ import main as cli
from test.support.import_helper import import_module
from test.support.os_helper import TESTFN, unlink
from test.support.pty_helper import run_pty
from test.support import (
captured_stdout,
captured_stderr,
captured_stdin,
force_not_colorized_test_class,
requires_subprocess,
)


Expand Down Expand Up @@ -205,98 +200,5 @@ def test_color(self):
self.assertIn('\x1b[1;35mOperationalError (SQLITE_ERROR)\x1b[0m: '
'\x1b[35mnear "sel": syntax error\x1b[0m', err)


@requires_subprocess()
@force_not_colorized_test_class
class Completion(unittest.TestCase):
PS1 = "sqlite> "

@classmethod
def setUpClass(cls):
_sqlite3 = import_module("_sqlite3")
if not hasattr(_sqlite3, "SQLITE_KEYWORDS"):
raise unittest.SkipTest("unable to determine SQLite keywords")

readline = import_module("readline")
if readline.backend == "editline":
raise unittest.SkipTest("libedit readline is not supported")

def write_input(self, input_, env=None):
script = textwrap.dedent("""
import readline
from sqlite3.__main__ import main

readline.parse_and_bind("set colored-completion-prefix off")
main()
""")
return run_pty(script, input_, env)

def test_complete_sql_keywords(self):
# List candidates starting with 'S', there should be multiple matches.
input_ = b"S\t\tEL\t 1;\n.quit\n"
output = self.write_input(input_)
self.assertIn(b"SELECT", output)
self.assertIn(b"SET", output)
self.assertIn(b"SAVEPOINT", output)
self.assertIn(b"(1,)", output)

# Keywords are completed in upper case for even lower case user input.
input_ = b"sel\t\t 1;\n.quit\n"
output = self.write_input(input_)
self.assertIn(b"SELECT", output)
self.assertIn(b"(1,)", output)

@unittest.skipIf(sys.platform.startswith("freebsd"),
"Two actual tabs are inserted when there are no matching"
" completions in the pseudo-terminal opened by run_pty()"
" on FreeBSD")
def test_complete_no_match(self):
input_ = b"xyzzy\t\t\b\b\b\b\b\b\b.quit\n"
# Set NO_COLOR to disable coloring for self.PS1.
output = self.write_input(input_, env={"NO_COLOR": "1"})
lines = output.decode().splitlines()
indices = (
i for i, line in enumerate(lines, 1)
if line.startswith(f"{self.PS1}xyzzy")
)
line_num = next(indices, -1)
self.assertNotEqual(line_num, -1)
# Completions occupy lines, assert no extra lines when there is nothing
# to complete.
self.assertEqual(line_num, len(lines))

def test_complete_no_input(self):
from _sqlite3 import SQLITE_KEYWORDS

script = textwrap.dedent("""
import readline
from sqlite3.__main__ import main

# Configure readline to ...:
# - hide control sequences surrounding each candidate
# - hide "Display all xxx possibilities? (y or n)"
# - hide "--More--"
# - show candidates one per line
readline.parse_and_bind("set colored-completion-prefix off")
readline.parse_and_bind("set colored-stats off")
readline.parse_and_bind("set completion-query-items 0")
readline.parse_and_bind("set page-completions off")
readline.parse_and_bind("set completion-display-width 0")

main()
""")
input_ = b"\t\t.quit\n"
output = run_pty(script, input_, env={"NO_COLOR": "1"})
lines = output.decode().splitlines()
indices = [
i for i, line in enumerate(lines)
if line.startswith(self.PS1)
]
self.assertEqual(len(indices), 2)
start, end = indices
candidates = [l.strip() for l in lines[start+1:end]]
self.assertEqual(candidates, sorted(SQLITE_KEYWORDS))


if __name__ == "__main__":
unittest.main()
1 change: 0 additions & 1 deletion Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1868,7 +1868,6 @@ Neil Tallim
Geoff Talvola
Anish Tambe
Musashi Tamura
Long Tan
William Tanksley
Christian Tanzer
Steven Taschuk
Expand Down

This file was deleted.

39 changes: 0 additions & 39 deletions Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "microprotocols.h"
#include "row.h"
#include "blob.h"
#include "util.h"

#if SQLITE_VERSION_NUMBER < 3015002
#error "SQLite 3.15.2 or higher required"
Expand Down Expand Up @@ -405,40 +404,6 @@ pysqlite_error_name(int rc)
return NULL;
}

static int
add_keyword_tuple(PyObject *module)
{
#if SQLITE_VERSION_NUMBER >= 3024000
int count = sqlite3_keyword_count();
PyObject *keywords = PyTuple_New(count);
if (keywords == NULL) {
return -1;
}
for (int i = 0; i < count; i++) {
const char *keyword;
int size;
int result = sqlite3_keyword_name(i, &keyword, &size);
if (result != SQLITE_OK) {
pysqlite_state *state = pysqlite_get_state(module);
set_error_from_code(state, result);
goto error;
}
PyObject *kwd = PyUnicode_FromStringAndSize(keyword, size);
if (!kwd) {
goto error;
}
PyTuple_SET_ITEM(keywords, i, kwd);
}
return PyModule_Add(module, "SQLITE_KEYWORDS", keywords);

error:
Py_DECREF(keywords);
return -1;
#else
return 0;
#endif
}

static int
add_integer_constants(PyObject *module) {
#define ADD_INT(ival) \
Expand Down Expand Up @@ -737,10 +702,6 @@ module_exec(PyObject *module)
goto error;
}

if (add_keyword_tuple(module) < 0) {
goto error;
}

if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) {
goto error;
}
Expand Down
Loading