diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4db37dc..3ecda10 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,7 +19,7 @@ jobs:
sudo apt-get -qq update
sudo apt-get install -y clang-format cppcheck python3-pip python3-venv
python3 -m venv "$HOME/.lint-venv"
- "$HOME/.lint-venv/bin/pip" install pre-commit $PIP_DEPS black flake8 pylint
+ "$HOME/.lint-venv/bin/pip" install pre-commit $PIP_DEPS ruff
echo "$HOME/.lint-venv/bin" >> "$GITHUB_PATH"
- name: pre-commit
run: pre-commit run --all-files
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index abf7065..08a96db 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -17,26 +17,15 @@ repos:
verbose: true
entry: cppcheck
args: [-q,--std=c++11]
- - id: black
- name: black
+ - id: ruff-check
+ name: ruff-check
language: system
- files: \.py$
+ types: [python]
verbose: true
- entry: black
- args: [-l,'100']
- - id: flake8
- name: flake8
+ entry: ruff check
+ - id: ruff-format
+ name: ruff-format
language: system
- files: \.py$
+ types: [python]
verbose: true
- entry: flake8
- args: [--max-line-length, "100", "--ignore=E501,W503,E722"]
- - id: pylint
- name: pylint
- language: system
- files: \.py$
- exclude: version\.py
- verbose: true
- entry: env PYTHONPATH=bindings/python pylint
- args: [-d, "global-statement,missing-docstring,missing-module-docstring,line-too-long,too-many-arguments,too-many-positional-arguments,duplicate-code,redefined-outer-name,too-many-locals,bare-except,broad-except,import-outside-toplevel,protected-access,too-many-statements,too-many-branches,unspecified-encoding"]
-# CI re-run trigger 2026-10-19 (run 39294337754 lost its macOS runner to GitHub capacity)
+ entry: ruff format
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d095a63..067b952 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,13 +3,6 @@ if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
-# CMake 4 removed compatibility with projects declaring
-# cmake_minimum_required() below 3.5; the pinned SQLiteCpp fetched
-# below declares 3.1, which makes configure fail outright under
-# CMake 4 (e.g. the macos-15 runner image). Raise the policy-version
-# floor for fetched subprojects; harmless under older CMake.
-set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
-
include(FetchContent)
if(${CMAKE_VERSION} VERSION_LESS 3.14)
@@ -25,7 +18,7 @@ endif()
FetchContent_Declare(
sqlite_zstd_vfs
GIT_REPOSITORY https://github.com/mlin/sqlite_zstd_vfs.git
- GIT_TAG 2e9c7db
+ GIT_TAG 42257288a5f5d025d79967f8c2ec48f534cf8559
)
FetchContent_MakeAvailable(sqlite_zstd_vfs)
FetchContent_MakeAvailable(sqlitecpp)
diff --git a/Dockerfile b/Dockerfile
index faec530..cd2ff47 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,7 +4,7 @@
FROM almalinux:8 as builder
ARG CMAKE_VERSION=3.17.3
-ARG SQLITE_VERSION=3410200
+ARG SQLITE_VERSION=3540100
ARG ZSTD_VERSION=1.5.5
ARG CPU_ARCH=ivybridge
ENV CFLAGS="-march=${CPU_ARCH} -O3"
@@ -34,7 +34,7 @@ RUN mkdir -p /work/GenomicSQLite
# SQLite
WORKDIR /work
-RUN wget -nv http://www.sqlite.org/2023/sqlite-amalgamation-${SQLITE_VERSION}.zip \
+RUN wget -nv http://www.sqlite.org/2026/sqlite-amalgamation-${SQLITE_VERSION}.zip \
&& unzip -o sqlite-amalgamation-${SQLITE_VERSION}.zip
WORKDIR /work/sqlite-amalgamation-${SQLITE_VERSION}
RUN bash -c "gcc -shared -o libsqlite3.so.0 -fPIC -shared -Wl,-soname,libsqlite3.so.0 -g ${CFLAGS} ${SQLITE_CFLAGS} sqlite3.c & pid=$? \
diff --git a/README.md b/README.md
index 352593f..f31a516 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ cmake --build build -j 4 --target genomicsqlite
* htslib ≥ 1.9, samtools, and tabix
* pigz
-* Python ≥ 3.6 and packages: pytest pytest-xdist pre-commit black pylint flake8
+* Python ≥ 3.6 and packages: pytest pytest-xdist pre-commit ruff
* JDK, mvn, rust
* clang-format & cppcheck
diff --git a/bindings/jdbc/genomicsqlite-jdbc/pom.xml b/bindings/jdbc/genomicsqlite-jdbc/pom.xml
index 63b4894..b7b3646 100644
--- a/bindings/jdbc/genomicsqlite-jdbc/pom.xml
+++ b/bindings/jdbc/genomicsqlite-jdbc/pom.xml
@@ -61,7 +61,7 @@
junit
junit
- 4.13.1
+ 4.13.2
test
@@ -72,44 +72,44 @@
maven-clean-plugin
- 3.1.0
+ 3.5.0
maven-resources-plugin
- 3.0.2
+ 3.5.0
maven-compiler-plugin
- 3.8.0
+ 3.16.0
maven-surefire-plugin
- 2.22.2
+ 3.6.0
false
maven-jar-plugin
- 3.0.2
+ 3.5.1
maven-install-plugin
- 2.5.2
+ 3.2.0
maven-deploy-plugin
- 2.8.2
+ 3.2.0
maven-site-plugin
- 3.7.1
+ 3.22.0
maven-project-info-reports-plugin
- 3.0.0
+ 3.9.0
com.diffplug.spotless
diff --git a/bindings/python/genomicsqlite/__init__.py b/bindings/python/genomicsqlite/__init__.py
index c1ec17e..22504bf 100755
--- a/bindings/python/genomicsqlite/__init__.py
+++ b/bindings/python/genomicsqlite/__init__.py
@@ -3,12 +3,12 @@
GenomicSQLite Python binding
"""
+import json
import os
-import sys
import platform
-import json
import sqlite3
-from typing import Optional, NamedTuple, Dict, Any
+import sys
+from typing import Any, Dict, NamedTuple, Optional # noqa: UP035
_HERE = os.path.dirname(__file__)
_YES = ("1", "true", "t", "yes", "y")
@@ -182,9 +182,9 @@ def get_reference_sequences_by_rid(
params = (assembly,)
ans = {}
for row in con.execute(sql, params):
- assert (
- isinstance(row[0], int) and row[0] not in ans
- ), "genomicsqlite: invalid or duplicate reference sequence rid"
+ assert isinstance(row[0], int) and row[0] not in ans, (
+ "genomicsqlite: invalid or duplicate reference sequence rid"
+ )
ans[row[0]] = ReferenceSequence(
rid=row[0],
name=row[1],
@@ -200,7 +200,7 @@ def get_reference_sequences_by_name(
con: sqlite3.Connection, assembly: Optional[str] = None, schema: Optional[str] = None
) -> Dict[str, ReferenceSequence]:
ans = {}
- for _, item in get_reference_sequences_by_rid(con, assembly, schema).items():
+ for item in get_reference_sequences_by_rid(con, assembly, schema).values():
assert item.name not in ans, "genomicsqlite: non-unique reference sequence names"
ans[item.name] = item
return ans
@@ -333,12 +333,10 @@ def _cli(argv=None):
print(
" ".join(
(
- (
- (arg if " " not in arg else f"'{arg}'")
- + (" \\\n " if len(arg) > 50 else "")
- )
- for arg in cmd
+ (arg if " " not in arg else f"'{arg}'")
+ + (" \\\n " if len(arg) > 50 else "")
)
+ for arg in cmd
)
)
os.execvp("sqlite3", cmd)
@@ -403,7 +401,7 @@ def _compact(dbfilename, argv):
# sniff whether input db is currently compressed with zstd_vfs or not
con = None
- web = dbfilename.startswith("http:") or dbfilename.startswith("https:")
+ web = dbfilename.startswith(("http:", "https:"))
if not web:
con = sqlite3.connect(f"file:{urllib.parse.quote(dbfilename)}?mode=ro", uri=True)
if next(con.execute("PRAGMA application_id"))[0] != 0x7A737464:
diff --git a/bindings/python/genomicsqlite/__main__.py b/bindings/python/genomicsqlite/__main__.py
index ba91ed0..bd19d9c 100644
--- a/bindings/python/genomicsqlite/__main__.py
+++ b/bindings/python/genomicsqlite/__main__.py
@@ -1,4 +1,5 @@
import sys
+
from . import _cli
if __name__ == "__main__":
diff --git a/bindings/python/setup.py b/bindings/python/setup.py
index b9fee7b..cfd8a19 100755
--- a/bindings/python/setup.py
+++ b/bindings/python/setup.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from os import path
-from setuptools import setup, find_packages # pylint: disable=import-error
+
+from setuptools import find_packages, setup # pylint: disable=import-error
from version import get_version
HERE = path.abspath(path.dirname(__file__))
diff --git a/bindings/python/version.py b/bindings/python/version.py
index 5b7cfd8..964f594 100644
--- a/bindings/python/version.py
+++ b/bindings/python/version.py
@@ -76,7 +76,7 @@ def read_git_version():
return None
match = re.search(_GIT_DESCRIPTION_RE, ver)
if not match:
- sys.stderr.write("version: git description (%s) is invalid, " "ignoring\n" % ver)
+ sys.stderr.write("version: git description (%s) is invalid, ignoring\n" % ver)
return None
commits = int(match.group("commits"))
@@ -90,9 +90,7 @@ def read_release_version():
with open(RELEASE_VERSION_FILE) as infile:
ver = infile.readline().strip()
if not re.search(_PEP386_VERSION_RE, ver):
- sys.stderr.write(
- "version: release version (%s) is invalid, " "will use it anyway\n" % ver
- )
+ sys.stderr.write("version: release version (%s) is invalid, will use it anyway\n" % ver)
return ver
except:
return None
diff --git a/docs/guide_db.md b/docs/guide_db.md
index 7b8abea..ac7ad07 100644
--- a/docs/guide_db.md
+++ b/docs/guide_db.md
@@ -94,9 +94,9 @@ First complete the [installation instructions](index.md).
=== "Python"
``` python3
dbconn = genomicsqlite.connect(
- db_filename,
- read_only=False,
- **kwargs # genomicsqlite + sqlite3.connect() arguments
+ db_filename,
+ read_only=False,
+ **kwargs, # genomicsqlite + sqlite3.connect() arguments
)
assert isinstance(dbconn, sqlite3.Connection)
```
diff --git a/docs/guide_gri.md b/docs/guide_gri.md
index 8bf7f66..747e0db 100644
--- a/docs/guide_gri.md
+++ b/docs/guide_gri.md
@@ -21,11 +21,7 @@ The extension provides routines to populate a small `_gri_refseq` table describi
=== "Python"
``` python3
create_gri_sql = genomicsqlite.create_genomic_range_index_sql(
- dbconn,
- 'tableName',
- 'chromosome',
- 'beginPosition',
- 'endPosition'
+ dbconn, "tableName", "chromosome", "beginPosition", "endPosition"
)
dbconn.executescript(create_gri_sql)
```
@@ -229,9 +225,7 @@ The following routines support the aforementioned, recommended convention for st
=== "Python"
``` python3
- refseq_sql = genomicsqlite.put_reference_assembly_sql(
- dbconn, 'GRCh38_no_alt_analysis_set'
- )
+ refseq_sql = genomicsqlite.put_reference_assembly_sql(dbconn, "GRCh38_no_alt_analysis_set")
dbconn.executescript(refseq_sql)
```
@@ -307,8 +301,10 @@ Available assemblies:
=== "Python"
``` python3
refseq_sql = genomicsqlite.put_reference_sequence_sql(
- dbconn, 'chr17', 83257441
- # optional: assembly, refget_id, meta (dict), rid
+ dbconn,
+ "chr17",
+ 83257441,
+ # optional: assembly, refget_id, meta (dict), rid
)
dbconn.executescript(refseq_sql)
```
@@ -407,12 +403,13 @@ If the `rid` argument is omitted or -1 then it will be assigned automatically up
=== "Python"
``` python3
class ReferenceSequence(NamedTuple):
- rid: int
- name: str
- length: int
- assembly: Optional[str]
- refget_id: Optional[str]
- meta: Dict[str, Any]
+ rid: int
+ name: str
+ length: int
+ assembly: Optional[str]
+ refget_id: Optional[str]
+ meta: Dict[str, Any]
+
refseq_by_rid = genomicsqlite.get_reference_sequences_by_rid(dbconn)
# refseq_by_rid: Dict[int, ReferenceSequence]
@@ -492,12 +489,13 @@ The optional `assembly` argument restricts the retrieved sequences to those with
=== "Python"
``` python3
class ReferenceSequence(NamedTuple):
- rid: int
- name: str
- length: int
- assembly: Optional[str]
- refget_id: Optional[str]
- meta: Dict[str, Any]
+ rid: int
+ name: str
+ length: int
+ assembly: Optional[str]
+ refget_id: Optional[str]
+ meta: Dict[str, Any]
+
refseq_by_name = genomicsqlite.get_reference_sequences_by_name(dbconn)
# refseq_by_name: Dict[str, ReferenceSequence]
diff --git a/docs/guide_helpers.md b/docs/guide_helpers.md
index d1cd9a7..95bc3e3 100644
--- a/docs/guide_helpers.md
+++ b/docs/guide_helpers.md
@@ -88,8 +88,8 @@ The [UINT collating sequence](https://www.sqlite.org/uintcseq.html) is also bund
=== "Python"
``` python3
- dbconn = sqlite3.connect('any.db', uri=True)
- attach_sql = genomicsqlite.attach_sql(dbconn, 'compressed.db', 'db2')
+ dbconn = sqlite3.connect("any.db", uri=True)
+ attach_sql = genomicsqlite.attach_sql(dbconn, "compressed.db", "db2")
# attach_sql() also takes configuration keyword arguments like
# genomicsqlite.connect()
dbconn.executescript(attach_sql)
@@ -190,13 +190,13 @@ The [UINT collating sequence](https://www.sqlite.org/uintcseq.html) is also bund
=== "Python"
``` python3
- dbconn = sqlite3.connect('existing.db', uri=True)
- vacuum_sql = genomicsqlite.vacuum_into_sql(dbconn, 'compressed.db')
+ dbconn = sqlite3.connect("existing.db", uri=True)
+ vacuum_sql = genomicsqlite.vacuum_into_sql(dbconn, "compressed.db")
# vacuum_into_sql() also takes configuration keyword arguments like
# genomicsqlite.connect() to control compression level & page sizes
dbconn.executescript(vacuum_sql)
- dbconn2 = genomicsqlite.connect('compressed.db')
+ dbconn2 = genomicsqlite.connect("compressed.db")
```
=== "Java"
diff --git a/docs/internals.md b/docs/internals.md
index df34720..01dd569 100644
--- a/docs/internals.md
+++ b/docs/internals.md
@@ -70,13 +70,19 @@ The extension also exposes the routine to generate the SQL subquery, which you c
=== "Python"
``` python3
query = (
- 'SELECT * FROM tableName WHERE tableName._rowid_ IN ' +
- genomicsqlite.genomic_range_rowids_sql(dbconn, 'tableName',
- # defaults:
- qrid='?1', qbeg='?2', qend='?3',
- ceiling=-1, floor=-1)
+ "SELECT * FROM tableName WHERE tableName._rowid_ IN "
+ + genomicsqlite.genomic_range_rowids_sql(
+ dbconn,
+ "tableName",
+ # defaults:
+ qrid="?1",
+ qbeg="?2",
+ qend="?3",
+ ceiling=-1,
+ floor=-1,
+ )
)
- cursor = dbconn.execute(query, ('chr12',111803912,111804012))
+ cursor = dbconn.execute(query, ("chr12", 111803912, 111804012))
```
=== "SQLiteCpp"
diff --git a/loaders/common.hpp b/loaders/common.hpp
index 99eca19..559fa80 100644
--- a/loaders/common.hpp
+++ b/loaders/common.hpp
@@ -5,6 +5,7 @@
#include "strlcpy.h"
#include
#include
+#include
#include
#include
#include
diff --git a/loaders/sam_into_sqlite.cc b/loaders/sam_into_sqlite.cc
index a210537..1788b35 100644
--- a/loaders/sam_into_sqlite.cc
+++ b/loaders/sam_into_sqlite.cc
@@ -304,7 +304,7 @@ int main(int argc, char *argv[]) {
throw runtime_error("invalid header SQ");
}
errno = 0;
- sqlite3_int64 length = strtoll(ks->s, nullptr, 10);
+ int64_t length = strtoll(ks->s, nullptr, 10);
if (errno || length <= 0) {
throw runtime_error("invalid header SQ");
}
@@ -391,7 +391,7 @@ int main(int argc, char *argv[]) {
}
insert_read.exec();
- sqlite3_int64 rowid = db->getLastInsertRowid();
+ int64_t rowid = db->getLastInsertRowid();
insert_seqs.reset();
insert_seqs.clearBindings();
diff --git a/loaders/vcf_into_sqlite.cc b/loaders/vcf_into_sqlite.cc
index 359f469..ba9480d 100644
--- a/loaders/vcf_into_sqlite.cc
+++ b/loaders/vcf_into_sqlite.cc
@@ -157,7 +157,7 @@ void insert_samples(bcf_hdr_t *hdr, const string &table_prefix, SQLite::Database
SQLite::Statement stmt(db, "INSERT INTO " + table_prefix +
"samples(sample_id,sample_name) VALUES(?,?)");
- for (sqlite3_int64 i = 0; i < bcf_hdr_nsamples(hdr); ++i) {
+ for (int64_t i = 0; i < bcf_hdr_nsamples(hdr); ++i) {
stmt.bind(1, i);
stmt.bind(2, hdr->samples[i]);
stmt.exec();
@@ -486,12 +486,12 @@ unique_ptr format_helper::make(bcf_hdr_t *hdr, bcf1_t *rec,
}
void insert_genotypes(bcf_hdr_t *hdr, bcf1_t *rec, vector