Skip to content

gh-111726: Explicitly close database connections in sqlite3 doctests #111730

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 18 commits into from
Apr 8, 2024
Merged
Changes from 9 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
83 changes: 80 additions & 3 deletions Doc/library/sqlite3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
src = sqlite3.connect(":memory:", isolation_level=None)
dst = sqlite3.connect("tutorial.db", isolation_level=None)
src.backup(dst)
src.close()
dst.close()
del src, dst

.. _sqlite3-intro:
Expand Down Expand Up @@ -221,6 +223,13 @@ creating a new cursor, then querying the database:
>>> print(f'The highest scoring Monty Python movie is {title!r}, released in {year}')
The highest scoring Monty Python movie is 'Monty Python and the Holy Grail', released in 1975

.. testcleanup::

new_con.close()

import os
os.remove("tutorial.db")

You've now created an SQLite database using the :mod:`!sqlite3` module,
inserted data and retrieved values from it in multiple ways.

Expand Down Expand Up @@ -400,6 +409,8 @@ Module functions
.. testsetup:: sqlite3.trace

import sqlite3
import sys
old_hook = sys.unraisablehook

.. doctest:: sqlite3.trace

Expand All @@ -412,12 +423,16 @@ Module functions
>>> def debug(unraisable):
... print(f"{unraisable.exc_value!r} in callback {unraisable.object.__name__}")
... print(f"Error message: {unraisable.err_msg}")
>>> import sys
>>> sys.unraisablehook = debug
>>> cur = con.execute("SELECT 1")
ZeroDivisionError('division by zero') in callback evil_trace
Error message: None

.. testcleanup:: sqlite3.trace

con.close()
sys.unraisablehook = old_hook

.. function:: register_adapter(type, adapter, /)

Register an *adapter* :term:`callable` to adapt the Python type *type*
Expand Down Expand Up @@ -763,6 +778,10 @@ Connection objects
... print(row)
('acbd18db4cc2f85cedef654fccc4a4d8',)

.. testcleanup::

con.close()

.. versionchanged:: 3.13

Passing *name*, *narg*, and *func* as keyword arguments is deprecated.
Expand Down Expand Up @@ -908,6 +927,7 @@ Connection objects
FROM test ORDER BY x
""")
print(cur.fetchall())
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -1069,6 +1089,7 @@ Connection objects
Added the ``sqlite3.enable_load_extension`` auditing event.

.. testsetup:: sqlite3.loadext
:skipif: True

import sqlite3
con = sqlite3.connect(":memory:")
Expand Down Expand Up @@ -1098,14 +1119,17 @@ Connection objects
for row in con.execute("SELECT rowid, name, ingredients FROM recipe WHERE name MATCH 'pie'"):
print(row)

con.close()

.. testoutput:: sqlite3.loadext
:hide:

(2, 'broccoli pie', 'broccoli cheese onions flour')
(3, 'pumpkin pie', 'pumpkin sugar flour butter')

.. testcleanup::
:skipif: True

con.close()

.. method:: load_extension(path, /, *, entrypoint=None)

Load an SQLite extension from a shared library.
Expand Down Expand Up @@ -1161,6 +1185,11 @@ Connection objects
f.write('%s\n' % line)
con.close()

.. testcleanup::

import os
os.remove('dump.sql')

.. seealso::

:ref:`sqlite3-howto-encoding`
Expand Down Expand Up @@ -1223,13 +1252,25 @@ Connection objects

Copied 0 of 0 pages...

.. testcleanup::

import os
os.remove('backup.db')

Example 2, copy an existing database into a transient copy:

.. testcode::

src = sqlite3.connect('example.db')
dst = sqlite3.connect(':memory:')
src.backup(dst)
dst.close()
src.close()

.. testcleanup::

import os
os.remove('example.db')

.. versionadded:: 3.7

Expand Down Expand Up @@ -1264,6 +1305,10 @@ Connection objects
>>> con.getlimit(sqlite3.SQLITE_LIMIT_SQL_LENGTH)
1000000000

.. testcleanup:: sqlite3.limits

con.close()

.. versionadded:: 3.11


Expand Down Expand Up @@ -1577,6 +1622,10 @@ Cursor objects
# cur is an sqlite3.Cursor object
cur.executemany("INSERT INTO data VALUES(?)", rows)

.. testcleanup:: sqlite3.cursor

con.close()

.. note::

Any resulting rows are discarded,
Expand Down Expand Up @@ -1683,6 +1732,10 @@ Cursor objects
>>> cur.connection == con
True

.. testcleanup::

con.close()

.. attribute:: description

Read-only attribute that provides the column names of the last query. To
Expand Down Expand Up @@ -1802,6 +1855,7 @@ Blob objects
greeting = blob.read()

print(greeting) # outputs "b'Hello, world!'"
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -2114,6 +2168,7 @@ Here's an example of both styles:
params = (1972,)
cur.execute("SELECT * FROM lang WHERE first_appeared = ?", params)
print(cur.fetchall())
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -2172,6 +2227,7 @@ The object passed to *protocol* will be of type :class:`PrepareProtocol`.

cur.execute("SELECT ?", (Point(4.0, -3.2),))
print(cur.fetchone()[0])
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -2202,6 +2258,7 @@ This function can then be registered using :func:`register_adapter`.

cur.execute("SELECT ?", (Point(1.0, 2.5),))
print(cur.fetchone()[0])
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -2286,6 +2343,8 @@ The following example illustrates the implicit and explicit approaches:
cur.execute("INSERT INTO test(p) VALUES(?)", (p,))
cur.execute('SELECT p AS "p [point]" FROM test')
print("with column names:", cur.fetchone()[0])
cur.close()
con.close()

.. testoutput::
:hide:
Expand Down Expand Up @@ -2492,6 +2551,8 @@ Some useful URI tricks include:
res = con2.execute("SELECT data FROM shared")
assert res.fetchone() == (28,)

con1.close()
con2.close()

More information about this feature, including a list of parameters,
can be found in the `SQLite URI documentation`_.
Expand Down Expand Up @@ -2524,6 +2585,10 @@ assign it to the :attr:`!row_factory` attribute:
>>> con = sqlite3.connect(":memory:")
>>> con.row_factory = sqlite3.Row

.. testcleanup::

con.close()

Queries now return :class:`!Row` objects:

.. doctest::
Expand All @@ -2539,6 +2604,10 @@ Queries now return :class:`!Row` objects:
>>> row["RADIUS"] # Column names are case-insensitive.
6378

.. testcleanup::

con.close()

.. note::

The ``FROM`` clause can be omitted in the ``SELECT`` statement, as in the
Expand All @@ -2565,6 +2634,10 @@ Using it, queries now return a :class:`!dict` instead of a :class:`!tuple`:
... print(row)
{'a': 1, 'b': 2}

.. testcleanup::

con.close()

The following row factory returns a :term:`named tuple`:

.. testcode::
Expand All @@ -2591,6 +2664,10 @@ The following row factory returns a :term:`named tuple`:
>>> row.b # Attribute access.
2

.. testcleanup::

con.close()

With some adjustments, the above recipe can be adapted to use a
:class:`~dataclasses.dataclass`, or any other custom class,
instead of a :class:`~collections.namedtuple`.
Expand Down