summaryrefslogtreecommitdiffstats
path: root/Lib/sqlite3
diff options
context:
space:
mode:
authorErlend Egeberg Aasland <erlend.aasland@protonmail.com>2022-08-01 10:25:16 (GMT)
committerGitHub <noreply@github.com>2022-08-01 10:25:16 (GMT)
commitbc7c7cd18a4ae015449f95454a762a7276585bb8 (patch)
tree2b477534f2442eb0af34526bbdc5fa9217bfe9f1 /Lib/sqlite3
parent1e6b63542e4856436c5c12148a6608ef9d148b71 (diff)
downloadcpython-bc7c7cd18a4ae015449f95454a762a7276585bb8.zip
cpython-bc7c7cd18a4ae015449f95454a762a7276585bb8.tar.gz
cpython-bc7c7cd18a4ae015449f95454a762a7276585bb8.tar.bz2
gh-77617: Add sqlite3 command-line interface (#95026)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Diffstat (limited to 'Lib/sqlite3')
-rw-r--r--Lib/sqlite3/__main__.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py
new file mode 100644
index 0000000..c62fad8
--- /dev/null
+++ b/Lib/sqlite3/__main__.py
@@ -0,0 +1,97 @@
+import sqlite3
+import sys
+
+from argparse import ArgumentParser
+from code import InteractiveConsole
+from textwrap import dedent
+
+
+def execute(c, sql, suppress_errors=True):
+ try:
+ for row in c.execute(sql):
+ print(row)
+ except sqlite3.Error as e:
+ tp = type(e).__name__
+ try:
+ print(f"{tp} ({e.sqlite_errorname}): {e}", file=sys.stderr)
+ except AttributeError:
+ print(f"{tp}: {e}", file=sys.stderr)
+ if not suppress_errors:
+ sys.exit(1)
+
+
+class SqliteInteractiveConsole(InteractiveConsole):
+
+ def __init__(self, connection):
+ super().__init__()
+ self._con = connection
+ self._cur = connection.cursor()
+
+ def runsource(self, source, filename="<input>", symbol="single"):
+ match source:
+ case ".version":
+ print(f"{sqlite3.sqlite_version}")
+ case ".help":
+ print("Enter SQL code and press enter.")
+ case ".quit":
+ sys.exit(0)
+ case _:
+ if not sqlite3.complete_statement(source):
+ return True
+ execute(self._cur, source)
+ return False
+
+
+def main():
+ parser = ArgumentParser(
+ description="Python sqlite3 CLI",
+ prog="python -m sqlite3",
+ )
+ parser.add_argument(
+ "filename", type=str, default=":memory:", nargs="?",
+ help=(
+ "SQLite database to open (defaults to ':memory:'). "
+ "A new database is created if the file does not previously exist."
+ ),
+ )
+ parser.add_argument(
+ "sql", type=str, nargs="?",
+ help=(
+ "An SQL query to execute. "
+ "Any returned rows are printed to stdout."
+ ),
+ )
+ parser.add_argument(
+ "-v", "--version", action="version",
+ version=f"SQLite version {sqlite3.sqlite_version}",
+ help="Print underlying SQLite library version",
+ )
+ args = parser.parse_args()
+
+ if args.filename == ":memory:":
+ db_name = "a transient in-memory database"
+ else:
+ db_name = repr(args.filename)
+
+ 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 CTRL-D to quit.
+ """).strip()
+ sys.ps1 = "sqlite> "
+ sys.ps2 = " ... "
+
+ con = sqlite3.connect(args.filename, isolation_level=None)
+ try:
+ if args.sql:
+ execute(con, args.sql, suppress_errors=False)
+ else:
+ console = SqliteInteractiveConsole(con)
+ console.interact(banner, exitmsg="")
+ finally:
+ con.close()
+
+
+main()