Test against multiple SQLite versions (#654)

* Test against pre-upsert SQLite 3.23.1

Borrowed from 8f86d2af6

* Try this on Python 3.9

* select ... from pragma_function_list()

Refs https://github.com/simonw/sqlite-utils/pull/654#issuecomment-2860898278

* Fix spelling error

* Compatible with latest black

* Skip plugin test that needs pragma_function_list

Refs https://github.com/simonw/sqlite-utils/pull/654#issuecomment-2860924225

* Ran cog
This commit is contained in:
Simon Willison 2025-05-07 17:49:50 -07:00 committed by GitHub
commit 0e4e270d44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 29 deletions

View file

@ -0,0 +1,41 @@
name: Test SQLite versions
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ${{ matrix.platform }}
continue-on-error: true
strategy:
matrix:
platform: [ubuntu-latest]
python-version: ["3.9"]
sqlite-version: [
"3.46",
"3.23.1", # 2018-04-10, before UPSERT
]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
cache: pip
cache-dependency-path: setup.py
- name: Set up SQLite ${{ matrix.sqlite-version }}
uses: asg017/sqlite-versions@71ea0de37ae739c33e447af91ba71dda8fcf22e6
with:
version: ${{ matrix.sqlite-version }}
cflags: "-DSQLITE_ENABLE_DESERIALIZE -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_JSON1"
- run: python3 -c "import sqlite3; print(sqlite3.sqlite_version)"
- name: Install dependencies
run: |
pip install -e '.[test]'
pip freeze
- name: Run tests
run: |
python -m pytest

View file

@ -1045,23 +1045,6 @@ disable-fts
-h, --help Show this message and exit.
.. _cli_ref_tui:
tui
===
See :ref:`cli_tui`.
::
Usage: sqlite-utils tui [OPTIONS]
Open Textual TUI.
Options:
-h, --help Show this message and exit.
.. _cli_ref_optimize:
optimize

View file

@ -237,37 +237,30 @@ if pd:
class AlterError(Exception):
"Error altering table"
pass
class NoObviousTable(Exception):
"Could not tell which table this operation refers to"
pass
class NoTable(Exception):
"Specified table does not exist"
pass
class BadPrimaryKey(Exception):
"Table does not have a single obvious primary key"
pass
class NotFoundError(Exception):
"Record not found"
pass
class PrimaryKeyRequired(Exception):
"Primary key needs to be specified"
pass
class InvalidColumns(Exception):
"Specified columns do not exist"
pass
class DescIndex(str):
@ -3203,7 +3196,7 @@ class Table(Queryable):
:param not_null: Set of strings specifying columns that should be ``NOT NULL``.
:param defaults: Dictionary specifying default values for specific columns.
:param hash_id: Name of a column to create and use as a primary key, where the
value of thet primary key will be derived as a SHA1 hash of the other column values
value of that primary key will be derived as a SHA1 hash of the other column values
in the record. ``hash_id="id"`` is a common column name used for this.
:param alter: Boolean, should any missing columns be added automatically?
:param ignore: Boolean, if a record already exists with this primary key, ignore this insert.
@ -3852,7 +3845,7 @@ def jsonify_if_needed(value):
def resolve_extracts(
extracts: Optional[Union[Dict[str, str], List[str], Tuple[str]]]
extracts: Optional[Union[Dict[str, str], List[str], Tuple[str]]],
) -> dict:
if extracts is None:
extracts = {}

View file

@ -916,7 +916,7 @@ def test_query_json_with_json_cols(db_path):
@pytest.mark.parametrize(
"content,is_binary",
[(b"\x00\x0Fbinary", True), ("this is text", False), (1, False), (1.5, False)],
[(b"\x00\x0fbinary", True), ("this is text", False), (1, False), (1.5, False)],
)
def test_query_raw(db_path, content, is_binary):
Database(db_path)["files"].insert({"content": content})
@ -931,7 +931,7 @@ def test_query_raw(db_path, content, is_binary):
@pytest.mark.parametrize(
"content,is_binary",
[(b"\x00\x0Fbinary", True), ("this is text", False), (1, False), (1.5, False)],
[(b"\x00\x0fbinary", True), ("this is text", False), (1, False), (1.5, False)],
)
def test_query_raw_lines(db_path, content, is_binary):
Database(db_path)["files"].insert_all({"content": content} for _ in range(3))

View file

@ -1,9 +1,19 @@
from click.testing import CliRunner
import click
import importlib
import pytest
from sqlite_utils import cli, Database, hookimpl, plugins
def _supports_pragma_function_list():
db = Database(memory=True)
try:
db.execute("select * from pragma_function_list()")
except Exception:
return False
return True
def test_register_commands():
importlib.reload(cli)
assert plugins.get_plugins() == []
@ -37,6 +47,10 @@ def test_register_commands():
assert plugins.get_plugins() == []
@pytest.mark.skipif(
not _supports_pragma_function_list(),
reason="Needs SQLite version that supports pragma_function_list()",
)
def test_prepare_connection():
importlib.reload(cli)
assert plugins.get_plugins() == []
@ -54,7 +68,7 @@ def test_prepare_connection():
return [
row[0]
for row in db.execute(
"select distinct name from pragma_function_list order by 1"
"select distinct name from pragma_function_list() order by 1"
).fetchall()
]