summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/sqlite3
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/src/Lib/sqlite3')
-rw-r--r--contrib/tools/python3/src/Lib/sqlite3/__init__.py21
-rw-r--r--contrib/tools/python3/src/Lib/sqlite3/__main__.py127
-rw-r--r--contrib/tools/python3/src/Lib/sqlite3/dbapi2.py37
3 files changed, 159 insertions, 26 deletions
diff --git a/contrib/tools/python3/src/Lib/sqlite3/__init__.py b/contrib/tools/python3/src/Lib/sqlite3/__init__.py
index 5a2dbd360fb..927267cf0b9 100644
--- a/contrib/tools/python3/src/Lib/sqlite3/__init__.py
+++ b/contrib/tools/python3/src/Lib/sqlite3/__init__.py
@@ -55,17 +55,16 @@ The sqlite3 module is written by Gerhard Häring <[email protected]>.
"""
from sqlite3.dbapi2 import *
+from sqlite3.dbapi2 import (_deprecated_names,
+ _deprecated_version_info,
+ _deprecated_version)
-# bpo-42264: OptimizedUnicode was deprecated in Python 3.10. It's scheduled
-# for removal in Python 3.12.
def __getattr__(name):
- if name == "OptimizedUnicode":
- import warnings
- msg = ("""
- OptimizedUnicode is deprecated and will be removed in Python 3.12.
- Since Python 3.3 it has simply been an alias for 'str'.
- """)
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- return str
- raise AttributeError(f"module 'sqlite3' has no attribute '{name}'")
+ if name in _deprecated_names:
+ from warnings import warn
+
+ warn(f"{name} is deprecated and will be removed in Python 3.14",
+ DeprecationWarning, stacklevel=2)
+ return globals()[f"_deprecated_{name}"]
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
diff --git a/contrib/tools/python3/src/Lib/sqlite3/__main__.py b/contrib/tools/python3/src/Lib/sqlite3/__main__.py
new file mode 100644
index 00000000000..3b59763375c
--- /dev/null
+++ b/contrib/tools/python3/src/Lib/sqlite3/__main__.py
@@ -0,0 +1,127 @@
+"""A simple SQLite CLI for the sqlite3 module.
+
+Apart from using 'argparse' for the command-line interface,
+this module implements the REPL as a thin wrapper around
+the InteractiveConsole class from the 'code' stdlib module.
+"""
+import sqlite3
+import sys
+
+from argparse import ArgumentParser
+from code import InteractiveConsole
+from textwrap import dedent
+
+
+def execute(c, sql, suppress_errors=True):
+ """Helper that wraps execution of SQL code.
+
+ This is used both by the REPL and by direct execution from the CLI.
+
+ 'c' may be a cursor or a connection.
+ 'sql' is the SQL string to execute.
+ """
+
+ 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):
+ """A simple SQLite REPL."""
+
+ def __init__(self, connection):
+ super().__init__()
+ self._con = connection
+ self._cur = connection.cursor()
+
+ def runsource(self, source, filename="<input>", symbol="single"):
+ """Override runsource, the core of the InteractiveConsole REPL.
+
+ Return True if more input is needed; buffering is done automatically.
+ Return False is input is a complete statement ready for execution.
+ """
+ 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(*args):
+ 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(*args)
+
+ if args.filename == ":memory:":
+ db_name = "a transient in-memory database"
+ else:
+ 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.
+ """).strip()
+ sys.ps1 = "sqlite> "
+ sys.ps2 = " ... "
+
+ con = sqlite3.connect(args.filename, isolation_level=None)
+ try:
+ if args.sql:
+ # SQL statement provided on the command-line; execute it directly.
+ execute(con, args.sql, suppress_errors=False)
+ else:
+ # No SQL provided; start the REPL.
+ console = SqliteInteractiveConsole(con)
+ console.interact(banner, exitmsg="")
+ finally:
+ con.close()
+
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/contrib/tools/python3/src/Lib/sqlite3/dbapi2.py b/contrib/tools/python3/src/Lib/sqlite3/dbapi2.py
index 7cf4dd32d54..56fc0461e6c 100644
--- a/contrib/tools/python3/src/Lib/sqlite3/dbapi2.py
+++ b/contrib/tools/python3/src/Lib/sqlite3/dbapi2.py
@@ -25,6 +25,9 @@ import time
import collections.abc
from _sqlite3 import *
+from _sqlite3 import _deprecated_version
+
+_deprecated_names = frozenset({"version", "version_info"})
paramstyle = "qmark"
@@ -45,23 +48,32 @@ def TimeFromTicks(ticks):
def TimestampFromTicks(ticks):
return Timestamp(*time.localtime(ticks)[:6])
-version_info = tuple([int(x) for x in version.split(".")])
+_deprecated_version_info = tuple(map(int, _deprecated_version.split(".")))
sqlite_version_info = tuple([int(x) for x in sqlite_version.split(".")])
Binary = memoryview
collections.abc.Sequence.register(Row)
def register_adapters_and_converters():
+ from warnings import warn
+
+ msg = ("The default {what} is deprecated as of Python 3.12; "
+ "see the sqlite3 documentation for suggested replacement recipes")
+
def adapt_date(val):
+ warn(msg.format(what="date adapter"), DeprecationWarning, stacklevel=2)
return val.isoformat()
def adapt_datetime(val):
+ warn(msg.format(what="datetime adapter"), DeprecationWarning, stacklevel=2)
return val.isoformat(" ")
def convert_date(val):
+ warn(msg.format(what="date converter"), DeprecationWarning, stacklevel=2)
return datetime.date(*map(int, val.split(b"-")))
def convert_timestamp(val):
+ warn(msg.format(what="timestamp converter"), DeprecationWarning, stacklevel=2)
datepart, timepart = val.split(b" ")
year, month, day = map(int, datepart.split(b"-"))
timepart_full = timepart.split(b".")
@@ -82,20 +94,15 @@ def register_adapters_and_converters():
register_adapters_and_converters()
-# bpo-24464: enable_shared_cache was deprecated in Python 3.10. It's
-# scheduled for removal in Python 3.12.
-def enable_shared_cache(enable):
- from _sqlite3 import enable_shared_cache as _old_enable_shared_cache
- import warnings
- msg = (
- "enable_shared_cache is deprecated and will be removed in Python 3.12. "
- "Shared cache is strongly discouraged by the SQLite 3 documentation. "
- "If shared cache must be used, open the database in URI mode using"
- "the cache=shared query parameter."
- )
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- return _old_enable_shared_cache(enable)
-
# Clean up namespace
del(register_adapters_and_converters)
+
+def __getattr__(name):
+ if name in _deprecated_names:
+ from warnings import warn
+
+ warn(f"{name} is deprecated and will be removed in Python 3.14",
+ DeprecationWarning, stacklevel=2)
+ return globals()[f"_deprecated_{name}"]
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")