sqlite-utils 4.1: Python-код вместо файла при импорте данных

Всего четыре дня прошло с выхода sqlite-utils 4.0 — и Саймон Уиллисон уже выпустил версию 4.1. Это первый минорный релиз в ветке 4.x, и несмотря на небольшой номер, в нём есть по-настоящему удобные нововведения для разработчиков, активно работающих с SQLite из командной строки.

Sqlite-utils — это одновременно Python-библиотека и CLI-утилита (инструмент командной строки) для управления базами данных SQLite, созданная Саймоном Уиллисоном — автором фреймворка Django и инструмента Datasette.


Что нового в 4.1

Опция --code: вставка данных прямо из Python-кода

Главная новинка версии 4.1 — опция --code для команд sqlite-utils insert и sqlite-utils upsert.

Раньше для загрузки данных нужно было обязательно подготовить файл (JSON, CSV, TSV) или передать данные через stdin (стандартный поток ввода). Теперь можно передать блок Python-кода прямо в аргументе командной строки — или указать путь к .py-файлу. Этот код должен определять либо функцию rows(), возвращающую итерируемую последовательность строк, либо итерируемую переменную rows.

ℹ Что такое upsert?
Upsert — это операция «вставить или обновить»: если запись с таким первичным ключом уже существует — она обновляется, если нет — добавляется новая. В sqlite-utils с версии 4.0 upsert использует синтаксис INSERT ... ON CONFLICT ... DO UPDATE SET.

Пример: вставка данных через inline-код

# Вставляем строки, сгенерированные прямо в аргументе командной строки
sqlite-utils insert mydb.db users \n  --code 'rows = [{"name": "Иван", "city": "Москва"}, {\"name\": \"Мария\", \"city\": \"СПб\"}]'\n```\n\n#### Пример: функция `rows()` с логикой генерации\n\n```bash\nsqlite-utils insert mydb.db products \\\n  --code '\ndef rows():\n    import json\n    data = json.loads(open(\"catalog.json\").read())\n    for item in data:\n        yield {\"sku\": item[\"id\"], \"price\": item[\"price\"]}\n'\n```\n\n#### Пример: указание пути к `.py`-файлу\n\n```bash\n# Вместо кода — путь к файлу\nsqlite-utils insert mydb.db events --code ./generate_events.py\n```\n\n


💡 Совет
\nПодход с --code и файлом .py удобен для воспроизводимых пайплайнов (pipeline, конвейер обработки данных): скрипт находится в репозитории, вы можете версионировать его через Git, и при этом не нужно отдельный шаг для экспорта данных в промежуточный файл.\n
\n\n---\n\n### Не первый подобный механизм в sqlite-utils\n\nВажный контекст: передача Python-кода прямо в CLI — не новая концепция для sqlite-utils. Подобный механизм уже существовал для команды `sqlite-utils convert`, которая позволяет трансформировать значения в столбцах на лету. Теперь тот же подход распространён и на операции вставки/обновления данных.\n\nКоманда `sqlite-utils convert` ранее уже умела принимать прямые callable-ссылки вроде `r.parsedate` или `json.loads --import json` в качестве кода преобразования.\n\nТаким образом, версия 4.1 выравнивает возможности разных команд: теперь Python-код как источник данных работает единообразно по всему CLI.\n\n---\n\n## Контекст: что изменилось в 4.0\n\nЧтобы оценить значимость 4.1, важно понимать, что произошло в предшествующем мажорном (крупном) релизе.\n\nРелиз 4.0 включает ряд незначительных несовместимых исправлений и представляет три крупных новых возможности: миграции базы данных, вложенные транзакции и поддержку составных внешних ключей.\n\nКаждая из них заслуживает отдельного внимания:\n\n### 1. Миграции базы данных (Database Migrations)\n\nНовая система миграций включает в себя функциональность, ранее предоставлявшуюся отдельным пакетом `sqlite-migrate`. Наборы миграций определяются с помощью нового класса `sqlite_utils.Migrations`, а применяются через команду `sqlite-utils migrate` или Python API.\n\nПодход sqlite-utils намеренно проще, чем в Django: библиотека поощряет программное создание таблиц, а не ORM с описанием моделей, поэтому автогенерация миграций невозможна. Откат (rollback) был сознательно исключён — по опыту автора, эта функция используется редко. Простой способ откатиться — сделать копию файла базы данных перед применением миграций.\n\n### 2. Вложенные транзакции через `db.atomic()`\n\nНовый контекстный менеджер `db.atomic()` обеспечивает поддержку вложенных транзакций через SQLite-транзакции и точки сохранения (savepoints). Внутренние многошаговые операции, такие как `table.transform()`, теперь используют этот механизм, чтобы избежать случайного подтверждения (commit) существующей транзакции.\n\n### 3. Составные внешние ключи (Compound Foreign Keys)\n\nДобавлена поддержка составных внешних ключей (compound foreign keys) — их создание, трансформация и интроспекция через `table.foreign_keys`.\n\n---\n\n## Сравнение подходов к загрузке данных в sqlite-utils\n\n| Метод | Источник данных | Гибкость | Воспроизводимость |\n|---|---|---|---|\n| `--csv` / `--tsv` | Файл на диске | Низкая | Высокая |\n| stdin (JSON) | Пайп из другой команды | Средняя | Средняя |\n| `--code` (inline) | Python-код в аргументе | Высокая | Низкая |\n| `--code` (`.py`-файл) | Python-скрипт | Высокая | Высокая |\n| Python API | Код приложения | Максимальная | Максимальная |\n\n
⚠ Важно при обновлении с 3.x
\nЕсли вы обновляетесь с версии 3.x, проверьте список несовместимых изменений 4.0: определение типов теперь включено по умолчанию для команд insert и upsert при импорте CSV или TSV-данных; раньше все столбцы трактовались как TEXT, если не был передан флаг --detect-types. Для восстановления старого поведения используйте --no-detect-types.\n
\n\n---\n\n## Путь к 4.0: роль ИИ в разработке\n\nИнтересен сам процесс создания версии 4.0, который стал образцом совместной работы разработчика с LLM-моделями (Large Language Models — большими языковыми моделями).\n\nПомощь от Claude Fable 5 (и в меньшей степени от Opus 4.8 и GPT-5.5) дала необходимый импульс для преодоления инерции. По словам Уиллисона, у Fable отличный вкус в дизайне API, и модель проявляет инициативу, если дать ей достаточно открытую задачу.\n\nClaude Fable 5 написал 12 скриптов, выявил 4 блокирующих выпуск ошибки и 10 дополнительных проблем, а также создал удобный объединённый скрипт для воспроизведения найденных дефектов.\n\nЭто показательный пример того, как современные ИИ-ассистенты вписываются в реальные рабочие процессы open-source разработки — не заменяя автора, но ускоряя выявление и устранение ошибок.\n\n---\n\n## Диаграмма: экосистема sqlite-utils\n\n
\ngraph TD\n    A[sqlite-utils 4.x] --> B[CLI-команды]\n    A --> C[Python API]\n    A --> D[Система плагинов]\n    B --> B1[insert / upsert]\n    B --> B2[migrate]\n    B --> B3[convert]\n    B --> B4[memory]\n    B1 --> B1a[--code NEW in 4.1]\n    B1 --> B1b[--csv / --tsv]\n    B1 --> B1c[stdin JSON]\n    C --> C1[db.atomic — вложенные транзакции]\n    C --> C2[Migrations — миграции]\n    C --> C3[table.foreign_keys — внешние ключи]\n    D --> D1[sqlite-utils-tui]\n    D --> D2[sqlite-utils-fast-fks]\n    A --> E[Datasette]\n    A --> F[LLM-инструмент]\n
\n\n---\n\n## Как установить и обновить\n\n```bash\n# Установка через pip\npip install sqlite-utils\n\n# Обновление до последней версии\npip install --upgrade sqlite-utils\n\n# Проверка версии\nsqlite-utils --version\n```\n\nЕсли вы используете [`uv`](https://github.com/astral-sh/uv) — современный менеджер пакетов Python:\n\n```bash\nuv tool install sqlite-utils\n# или обновление\nuv tool upgrade sqlite-utils\n```\n\n
📝 Быстрый старт с --code
\nПопробуйте новую возможность прямо сейчас — создайте тестовую базу данных с данными, сгенерированными на лету:\n\nbash\nsqlite-utils insert test.db numbers \\\n --code 'rows = [{\"n\": i, \"square\": i*i} for i in range(1, 11)]'\n\nsqlite-utils test.db \"SELECT * FROM numbers\"\n\n
\n\n---\n\n## Итог\n\nСqlite-utils 4.1 — компактное, но полезное дополнение к уже весьма мощному инструменту. Опция `--code` устраняет необходимость в промежуточных файлах при нестандартной генерации данных и делает CLI-интерфейс библиотеки значительно выразительнее.\n\nsqlite-utils позволяет направлять JSON, CSV или TSV прямо в новый файл SQLite-базы с автоматическим созданием таблицы нужной схемы, выполнять SQL-запросы в оперативной памяти к данным из файлов, управлять полнотекстовым поиском и миграциями схемы.\n\nС учётом того, что sqlite-utils 4.0 стал 124-м релизом проекта и первым мажорным обновлением с версии 3.0 в 2020 году, активный темп разработки после его выхода — хороший знак для всей экосистемы Datasette/LLM.\n\n**Ссылки:**\n- [Репозиторий на GitHub](https://github.com/simonw/sqlite-utils)\n- [Документация](https://sqlite-utils.datasette.io/)\n- [Changelog](https://sqlite-utils.datasette.io/en/stable/changelog.html)\n- [Пост о 4.0 в блоге Уиллисона](https://simonwillison.net/2026/Jul/7/sqlite-utils-4/)","image_prompt":"A modern tech illustration showing a Python command-line terminal with glowing SQLite database icon, code snippets floating around, dark background with blue and green accents, data rows flowing into a database cylinder, minimalist flat design style"}