sqlite-utils 4.0rc1: миграции и вложенные транзакции для SQLite

21 июня 2026 года Саймон Уиллисон (Simon Willison) — автор Datasette и десятков полезных Python-инструментов — выпустил первый релиз-кандидат sqlite-utils 4.0. Это важная веха для одного из самых удобных инструментов экосистемы SQLite: версия 4.0rc1 приносит долгожданную поддержку миграций схемы базы данных и вложенных транзакций.

sqlite-utils — это одновременно CLI-утилита (инструмент командной строки) и Python-библиотека для работы с базами данных SQLite. Проект активно развивается с 2019 года и насчитывает сотни звёзд на GitHub.

Что такое sqlite-utils и зачем он нужен

sqlite-utils — комбинированный инструмент: с одной стороны, это pip-устанавливаемая Python-библиотека, позволяющая создавать таблицы, вставлять данные и делать запросы к SQLite буквально в несколько строк кода. С другой стороны, это CLI-утилита, которая позволяет работать с базой данных прямо из терминала, не написав ни строчки Python.

Проект особенно популярен среди исследователей данных, журналистов и разработчиков, работающих с локальными наборами данных, а также внутри экосистемы Datasette — инструмента для публикации и исследования данных.

# Пример: создаём базу и вставляем данные в три строки
import sqlite_utils

db = sqlite_utils.Database("my_database.db")
db["creatures"].insert({"id": 1, "name": "Барсук", "species": "Meles meles"})
print(list(db["creatures"].rows))
ℹ Что такое релиз-кандидат (rc)
Версия с суффиксом rc (release candidate, кандидат на релиз) означает, что разработчик считает код готовым к финальному выпуску, но хочет дать сообществу время протестировать его и сообщить об ошибках. Устанавливается через pip install sqlite-utils==4.0rc1.

Что изменилось в версии 4.0rc1

Версия 4.0 — мажорный релиз, то есть содержит изменения, которые могут нарушить обратную совместимость с кодом, написанным для версии 3.x. Основные нововведения:

ФункциональностьВерсия 3.xВерсия 4.0rc1
Миграции схемыТолько через сторонний плагин sqlite-migrateВстроена в ядро
Вложенные транзакцииНе поддерживалисьПоддержка через SAVEPOINT
Обратная совместимостьБазоваяИмеются breaking changes
СтатусStableRelease Candidate

Миграции схемы (Migrations)

Миграция (migration) — это контролируемое изменение структуры базы данных: добавление столбца, переименование таблицы, создание индекса. В крупных проектах миграции обычно ведутся как история изменений — каждое изменение фиксируется в коде и применяется строго по порядку.

До версии 4.0 для этого использовался отдельный плагин sqlite-migrate. Теперь функциональность входит непосредственно в sqlite-utils. Концепция осталась той же: вы описываете миграции как Python-функции, декорированные специальным декоратором, а инструмент сам отслеживает, какие из них уже применены.

Файл миграций выглядит так:

from sqlite_migrate import Migrations

# Уникальное имя набора миграций
migration = Migrations("my_project")

@migration()
def create_table(db):
    """Создаём таблицу существ"""
    db["creatures"].create({
        "id": int,
        "name": str,
        "species": str
    }, pk="id")

@migration()
def add_weight(db):
    """Добавляем столбец weight"""
    db["creatures"].add_column("weight", float)

Затем применяем миграции из командной строки:

sqlite-utils migrate my_database.db path/to/migrations.py

Повторный запуск той же команды ничего не сломает — уже применённые миграции пропускаются. Можно также остановить процесс перед конкретной миграцией:

sqlite-utils migrate my_database.db path/to/migrations.py --stop-before add_weight
📝 Вывод команды --list

Команда sqlite-utils migrate my_database.db migrations.py --list выводит список всех миграций и их статус:

Migrations for: my_project
Applied:
  create_table - 2026-06-20 10:00:00.123456
  add_weight   - 2026-06-20 10:00:01.654321
Pending:
  add_age

Это позволяет легко проверить состояние схемы базы данных перед деплоем.

Для включения verbose-режима (подробного вывода с diff схемы до и после) используется флаг -v:

sqlite-utils migrate my_database.db migrations.py -v

Вложенные транзакции (Nested Transactions)

Транзакция (transaction) — это группа операций с базой данных, которые либо все выполняются успешно, либо все отменяются (откатываются). В SQLite стандартные транзакции через BEGIN...COMMIT не поддерживают вложенность.

Вместо этого SQLite использует механизм SAVEPOINT — точек сохранения, которые позволяют создавать «вложенные» уровни транзакций. Если что-то пошло не так внутри вложенного блока, можно откатиться к ближайшей точке сохранения, не отменяя всю внешнюю транзакцию.

sqlite-utils 4.0rc1 добавляет удобную поддержку этого механизма в Python API, что упрощает написание надёжного кода при сложных операциях с базой данных.

db = sqlite_utils.Database("my_database.db")

with db.conn:
    db["orders"].insert({"id": 1, "status": "new"})
    
    # Вложенная транзакция через SAVEPOINT
    with db.savepoint():
        db["orders"].update(1, {"status": "processing"})
        # Если здесь возникнет ошибка — откатимся только до savepoint,
        # внешняя транзакция останется активной
⚠ Важно при обновлении с версии 3.x
Версия 4.0 содержит breaking changes — изменения, нарушающие обратную совместимость. Перед обновлением проектов, использующих sqlite-utils 3.x, внимательно изучите список изменений в changelog. Особенно это важно, если вы используете библиотеку в продакшн-коде.

Как работает система миграций: общая схема


graph TD
    A[Файл migrations.py] --> B[sqlite-utils migrate db.sqlite migrations.py]
    B --> C{Проверка таблицы _sqlite_migrations}
    C -->|Миграция уже применена| D[Пропустить]
    C -->|Миграция новая| E[Применить функцию миграции]
    E --> F[Записать результат в _sqlite_migrations]
    F --> G[Следующая миграция]
    G --> C
    D --> G

Система хранит историю применённых миграций в специальной служебной таблице _sqlite_migrations прямо внутри вашей базы данных. Каждая запись содержит имя набора миграций, имя конкретной функции и время применения.

История пути к версии 4.0

Путь к мажорному релизу был долгим. В ноябре 2025 года Уиллисон выпустил 4.0a1 (alpha 1) с первыми breaking changes и описал их в своём блоге. С тех пор проект прошёл через несколько альфа-версий, постепенно накапливая новые возможности и исправляя обнаруженные проблемы, и наконец достиг стадии релиз-кандидата.

💡 Как протестировать RC-версию

Если вы хотите помочь проекту — установите релиз-кандидат в изолированном окружении и протестируйте его с вашим кодом:

pip install sqlite-utils==4.0rc1

Об обнаруженных проблемах сообщайте в репозитории на GitHub. Именно такая обратная связь помогает довести RC до стабильного релиза.

Экосистема: sqlite-utils и Datasette

sqlite-utils — не изолированный инструмент, а часть более широкой экосистемы вокруг Datasette. Библиотека используется как основа для загрузки и подготовки данных, которые затем публикуются через Datasette для визуализации и анализа.

В том же июне 2026 года Уиллисон анонсировал Datasette Apps — механизм размещения кастомных HTML-приложений прямо внутри Datasette. Эти два релиза вместе показывают активное развитие всей экосистемы.

Итог

sqlite-utils 4.0rc1 — это зрелый шаг к стабильной мажорной версии инструмента, который давно стал незаменимым для всех, кто работает с SQLite в Python. Встроенные миграции снижают зависимость от сторонних плагинов, а поддержка вложенных транзакций делает код надёжнее при сложных операциях. Если вы используете sqlite-utils в своих проектах — самое время протестировать RC и помочь довести версию 4.0 до финального релиза.