Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
30 changes: 28 additions & 2 deletions Doc/library/sqlite3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,40 @@ Module constants

The ``named`` DB-API parameter style is also supported.

.. data:: SQLITE_VERSION

The version string of the SQLite library that was used for building
the module.
This may be different from the SQLite library actually used at runtime,
which is available as :const:`sqlite_version`.

.. versionadded:: next

.. data:: sqlite_version

Version number of the runtime SQLite library as a :class:`string <str>`.

.. data:: SQLITE_VERSION_INFO

A named tuple containing the three components of the SQLite library
version that was used for building the module:
*major*, *minor*, and *patch*.
All values are integers.
The components can also be accessed by name,
so ``sqlite3.SQLITE_VERSION_INFO[0]`` is equivalent to
``sqlite3.SQLITE_VERSION_INFO.major`` and so on.
This may be different from the SQLite library actually used at runtime,
which is available as :const:`sqlite_version_info`.

.. versionadded:: next

.. data:: sqlite_version_info

Version number of the runtime SQLite library as a :class:`tuple` of
:class:`integers <int>`.
A named tuple containing the version of the runtime SQLite library,
with the same fields as :const:`SQLITE_VERSION_INFO`.

.. versionchanged:: next
It is now a named tuple.

.. data:: SQLITE_KEYWORDS

Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,12 @@ sqlite3
:exc:`SystemError` or :exc:`ValueError`.
(Contributed by Jiseok CHOI in :gh:`150449`.)

* Added constants :const:`~sqlite3.SQLITE_VERSION` and
:const:`~sqlite3.SQLITE_VERSION_INFO` which provide information
about the version of the SQLite library that was used for building the module.
:const:`~sqlite3.sqlite_version_info` is now a named tuple.
(Contributed by Serhiy Storchaka in :gh:`157470`.)


symtable
--------
Expand Down
2 changes: 0 additions & 2 deletions Lib/sqlite3/dbapi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ def TimestampFromTicks(ticks):
return Timestamp(*time.localtime(ticks)[:6])


sqlite_version_info = tuple([int(x) for x in sqlite_version.split(".")])

Binary = memoryview
collections.abc.Sequence.register(Row)

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ def collect_sqlite(info_add):
except ImportError:
return

attributes = ('sqlite_version',)
attributes = ('SQLITE_VERSION', 'sqlite_version')
copy_attributes(info_add, sqlite3, 'sqlite3.%s', attributes)


Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_sqlite3/test_dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import urllib.parse
import warnings

from test import support
from test.support import (
SHORT_TIMEOUT, check_disallow_instantiation, requires_subprocess
)
Expand Down Expand Up @@ -88,6 +89,33 @@ def test_programming_error(self):
def test_not_supported_error(self):
self.assertIsSubclass(sqlite.NotSupportedError, sqlite.DatabaseError)

def _test_sqlite_version(self, v, string):
self.assertIsInstance(v[:], tuple)
self.assertEqual(len(v), 3)
self.assertIsInstance(v[0], int)
self.assertIsInstance(v[1], int)
self.assertIsInstance(v[2], int)
self.assertIsInstance(v.major, int)
self.assertIsInstance(v.minor, int)
self.assertIsInstance(v.patch, int)
self.assertEqual(v[0], v.major)
self.assertEqual(v[1], v.minor)
self.assertEqual(v[2], v.patch)
self.assertGreaterEqual(v.major, 3)
self.assertGreaterEqual(v.minor, 0)
self.assertGreaterEqual(v.patch, 0)
self.assertEqual(string, '%d.%d.%d' % v)

def test_sqlite_version(self):
if support.verbose:
print(f'SQLITE_VERSION = {sqlite.SQLITE_VERSION}', flush=True)
print(f'sqlite_version = {sqlite.sqlite_version}', flush=True)
print(f'SQLITE_VERSION_INFO = {sqlite.SQLITE_VERSION_INFO}', flush=True)
print(f'sqlite_version_info = {sqlite.sqlite_version_info}', flush=True)
self._test_sqlite_version(sqlite.SQLITE_VERSION_INFO, sqlite.SQLITE_VERSION)
self._test_sqlite_version(sqlite.sqlite_version_info, sqlite.sqlite_version)
self.assertEqual(sqlite.SQLITE_VERSION_INFO[0], sqlite.sqlite_version_info[0])

def test_module_constants(self):
consts = [
"SQLITE_ABORT",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Add constants :const:`sqlite3.SQLITE_VERSION` and
:const:`sqlite3.SQLITE_VERSION_INFO` which provide information about
the version of the SQLite library that was used for building the module.
:const:`sqlite3.sqlite_version_info` is now a named tuple.
83 changes: 82 additions & 1 deletion Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,87 @@ add_keyword_tuple(PyObject *module)
#endif
}

PyDoc_STRVAR(sqlite_version_info__doc__,
"_sqlite3.sqlite_version_info\n\
\n\
SQLite version information as a named tuple.");

static PyStructSequence_Field sqlite_version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"patch", "Patch release number"},
{0}
};

static PyStructSequence_Desc sqlite_version_info_desc = {
"_sqlite3.sqlite_version_info", /* name */
sqlite_version_info__doc__, /* doc */
sqlite_version_info_fields, /* fields */
3
};

static PyObject *
make_sqlite_version_info(PyTypeObject *type, int number)
{
PyObject *version;
int pos = 0;
int major = number / 1000000;
int minor = (number % 1000000) / 1000;
int patch = number % 1000;

version = PyStructSequence_New(type);
if (version == NULL) {
return NULL;
}

#define SetItem(VALUE) \
PyStructSequence_SET_ITEM(version, pos++, VALUE); \
if (PyErr_Occurred()) { \
Py_DECREF(version); \
return NULL; \
}

SetItem(PyLong_FromLong(major))
SetItem(PyLong_FromLong(minor))
SetItem(PyLong_FromLong(patch))
#undef SetItem

return version;
}

static int
add_version_constants(PyObject *module)
{
if (PyModule_AddStringMacro(module, SQLITE_VERSION) < 0) {
return -1;
}
if (PyModule_AddStringConstant(module, "sqlite_version",
sqlite3_libversion()) < 0)
{
return -1;
}
PyTypeObject *version_type;
version_type = PyStructSequence_NewType(&sqlite_version_info_desc);
if (version_type == NULL) {
return -1;
}
if (PyModule_Add(module, "SQLITE_VERSION_INFO",
make_sqlite_version_info(version_type, SQLITE_VERSION_NUMBER)) < 0)
{
Py_DECREF(version_type);
return -1;
}
if (PyModule_Add(module, "sqlite_version_info",
make_sqlite_version_info(version_type,
sqlite3_libversion_number())) < 0)
{
Py_DECREF(version_type);
return -1;
}
Py_DECREF(version_type);
return 0;
}

static int
add_integer_constants(PyObject *module) {
#define ADD_INT(ival) \
Expand Down Expand Up @@ -741,7 +822,7 @@ module_exec(PyObject *module)
goto error;
}

if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) {
if (add_version_constants(module) < 0) {
goto error;
}

Expand Down
Loading