gh-90016: Deprecate default sqlite3 adapters and converters (#94276)

Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
Erlend Egeberg Aasland 2022-07-20 21:37:59 +02:00 committed by GitHub
parent 000a4eebe7
commit 6dadf6ca01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 49 deletions

View File

@ -1,22 +0,0 @@
import sqlite3
import datetime
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(d date, ts timestamp)")
today = datetime.date.today()
now = datetime.datetime.now()
cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
cur.execute("select d, ts from test")
row = cur.fetchone()
print(today, "=>", row[0], type(row[0]))
print(now, "=>", row[1], type(row[1]))
cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))
con.close()

View File

@ -1333,6 +1333,8 @@ This function can then be registered using :func:`register_adapter`.
.. literalinclude:: ../includes/sqlite3/adapter_point_2.py
.. _sqlite3-converters:
Converting SQLite values to custom Python types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -1373,27 +1375,28 @@ The following example illustrates the implicit and explicit approaches:
.. literalinclude:: ../includes/sqlite3/converter_point.py
Default adapters and converters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. _sqlite3-default-converters:
There are default adapters for the date and datetime types in the datetime
module. They will be sent as ISO dates/ISO timestamps to SQLite.
Default adapters and converters (deprecated)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The default converters are registered under the name "date" for
:class:`datetime.date` and under the name "timestamp" for
:class:`datetime.datetime`.
.. note::
This way, you can use date/timestamps from Python without any additional
fiddling in most cases. The format of the adapters is also compatible with the
experimental SQLite date/time functions.
The default adapters and converters are deprecated as of Python 3.12.
Instead, use the :ref:`sqlite3-adapter-converter-recipes`
and tailor them to your needs.
The following example demonstrates this.
The deprecated default adapters and converters consist of:
.. literalinclude:: ../includes/sqlite3/pysqlite_datetime.py
If a timestamp stored in SQLite has a fractional part longer than 6
numbers, its value will be truncated to microsecond precision by the
timestamp converter.
* An adapter for :class:`datetime.date` objects to :class:`strings <str>` in
`ISO 8601`_ format.
* An adapter for :class:`datetime.datetime` objects to strings in
ISO 8601 format.
* A converter for :ref:`declared <sqlite3-converters>` "date" types to
:class:`datetime.date` objects.
* A converter for declared "timestamp" types to
:class:`datetime.datetime` objects.
Fractional parts will be truncated to 6 digits (microsecond precision).
.. note::
@ -1402,6 +1405,10 @@ timestamp converter.
offsets in timestamps, either leave converters disabled, or register an
offset-aware converter with :func:`register_converter`.
.. deprecated:: 3.12
.. _ISO 8601: https://en.wikipedia.org/wiki/ISO_8601
.. _sqlite3-adapter-converter-recipes:

View File

@ -135,6 +135,12 @@ Deprecated
* :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable`
and :class:`collections.abc.Sized`. (:gh:`94309`)
* The :mod:`sqlite3` :ref:`default adapters and converters
<sqlite3-default-converters>` are now deprecated.
Instead, use the :ref:`sqlite3-adapter-converter-recipes`
and tailor them to your needs.
(Contributed by Erlend E. Aasland in :gh:`90016`.)
Pending Removal in Python 3.13
------------------------------

View File

@ -55,16 +55,25 @@ 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".")

View File

@ -129,7 +129,8 @@ class RegressionTests(unittest.TestCase):
con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table foo(bar timestamp)")
cur.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
with self.assertWarnsRegex(DeprecationWarning, "adapter"):
cur.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
cur.execute(SELECT)
cur.execute("drop table foo")
cur.execute("create table foo(bar integer)")
@ -305,7 +306,8 @@ class RegressionTests(unittest.TestCase):
cur.execute("INSERT INTO t (x) VALUES ('2012-04-04 15:06:00.123456789')")
cur.execute("SELECT * FROM t")
values = [x[0] for x in cur.fetchall()]
with self.assertWarnsRegex(DeprecationWarning, "converter"):
values = [x[0] for x in cur.fetchall()]
self.assertEqual(values, [
datetime.datetime(2012, 4, 4, 15, 6, 0, 456000),

View File

@ -496,38 +496,51 @@ class DateTimeTests(unittest.TestCase):
def test_sqlite_date(self):
d = sqlite.Date(2004, 2, 14)
self.cur.execute("insert into test(d) values (?)", (d,))
with self.assertWarnsRegex(DeprecationWarning, "adapter") as cm:
self.cur.execute("insert into test(d) values (?)", (d,))
self.assertEqual(cm.filename, __file__)
self.cur.execute("select d from test")
d2 = self.cur.fetchone()[0]
with self.assertWarnsRegex(DeprecationWarning, "converter") as cm:
d2 = self.cur.fetchone()[0]
self.assertEqual(cm.filename, __file__)
self.assertEqual(d, d2)
def test_sqlite_timestamp(self):
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0)
self.cur.execute("insert into test(ts) values (?)", (ts,))
with self.assertWarnsRegex(DeprecationWarning, "adapter") as cm:
self.cur.execute("insert into test(ts) values (?)", (ts,))
self.assertEqual(cm.filename, __file__)
self.cur.execute("select ts from test")
ts2 = self.cur.fetchone()[0]
with self.assertWarnsRegex(DeprecationWarning, "converter") as cm:
ts2 = self.cur.fetchone()[0]
self.assertEqual(cm.filename, __file__)
self.assertEqual(ts, ts2)
def test_sql_timestamp(self):
now = datetime.datetime.utcnow()
self.cur.execute("insert into test(ts) values (current_timestamp)")
self.cur.execute("select ts from test")
ts = self.cur.fetchone()[0]
with self.assertWarnsRegex(DeprecationWarning, "converter"):
ts = self.cur.fetchone()[0]
self.assertEqual(type(ts), datetime.datetime)
self.assertEqual(ts.year, now.year)
def test_date_time_sub_seconds(self):
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 500000)
self.cur.execute("insert into test(ts) values (?)", (ts,))
with self.assertWarnsRegex(DeprecationWarning, "adapter"):
self.cur.execute("insert into test(ts) values (?)", (ts,))
self.cur.execute("select ts from test")
ts2 = self.cur.fetchone()[0]
with self.assertWarnsRegex(DeprecationWarning, "converter"):
ts2 = self.cur.fetchone()[0]
self.assertEqual(ts, ts2)
def test_date_time_sub_seconds_floating_point(self):
ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 510241)
self.cur.execute("insert into test(ts) values (?)", (ts,))
with self.assertWarnsRegex(DeprecationWarning, "adapter"):
self.cur.execute("insert into test(ts) values (?)", (ts,))
self.cur.execute("select ts from test")
ts2 = self.cur.fetchone()[0]
with self.assertWarnsRegex(DeprecationWarning, "converter"):
ts2 = self.cur.fetchone()[0]
self.assertEqual(ts, ts2)

View File

@ -0,0 +1,2 @@
Deprecate :mod:`sqlite3` :ref:`default adapters and converters
<sqlite3-default-converters>`. Patch by Erlend E. Aasland.