diff --git a/Doc/includes/sqlite3/pysqlite_datetime.py b/Doc/includes/sqlite3/pysqlite_datetime.py deleted file mode 100644 index 5d843f906b3062..00000000000000 --- a/Doc/includes/sqlite3/pysqlite_datetime.py +++ /dev/null @@ -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() diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index d2997dc9251786..a7581f2fcbd8c0 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -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 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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. +.. _sqlite3-default-converters: -The default converters are registered under the name "date" for -:class:`datetime.date` and under the name "timestamp" for -:class:`datetime.datetime`. +Default adapters and converters (deprecated) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -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. +.. note:: -The following example demonstrates this. + 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. -.. literalinclude:: ../includes/sqlite3/pysqlite_datetime.py +The deprecated default adapters and converters consist of: -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 ` in + `ISO 8601`_ format. +* An adapter for :class:`datetime.datetime` objects to strings in + ISO 8601 format. +* A converter for :ref:`declared ` "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: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 942196c03fd929..15282a755c8acc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -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 + ` 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 ------------------------------ diff --git a/Lib/sqlite3/dbapi2.py b/Lib/sqlite3/dbapi2.py index 3b6d2f7ba2d595..56fc0461e6c922 100644 --- a/Lib/sqlite3/dbapi2.py +++ b/Lib/sqlite3/dbapi2.py @@ -55,16 +55,25 @@ def TimestampFromTicks(ticks): 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".") diff --git a/Lib/test/test_sqlite3/test_regression.py b/Lib/test/test_sqlite3/test_regression.py index 0b727cecb0e8cb..ad83a97c8c40d6 100644 --- a/Lib/test/test_sqlite3/test_regression.py +++ b/Lib/test/test_sqlite3/test_regression.py @@ -129,7 +129,8 @@ def test_type_map_usage(self): 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 @@ def test_convert_timestamp_microsecond_padding(self): 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), diff --git a/Lib/test/test_sqlite3/test_types.py b/Lib/test/test_sqlite3/test_types.py index 177cd102350397..62318823510d40 100644 --- a/Lib/test/test_sqlite3/test_types.py +++ b/Lib/test/test_sqlite3/test_types.py @@ -496,38 +496,51 @@ def tearDown(self): 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) diff --git a/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst b/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst new file mode 100644 index 00000000000000..040ba44be2b912 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-25-23-44-44.gh-issue-90016.EB409s.rst @@ -0,0 +1,2 @@ +Deprecate :mod:`sqlite3` :ref:`default adapters and converters +`. Patch by Erlend E. Aasland. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy