惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
T
The Blog of Author Tim Ferriss
S
SegmentFault 最新的问题
D
DataBreaches.Net
博客园_首页
罗磊的独立博客
B
Blog
T
Threat Research - Cisco Blogs
C
Cisco Blogs
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
G
GRAHAM CLULEY
H
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
爱范儿
爱范儿
SecWiki News
SecWiki News
T
Threatpost
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Schneier on Security
Schneier on Security
T
The Exploit Database - CXSecurity.com
Google Online Security Blog
Google Online Security Blog
T
Tor Project blog
小众软件
小众软件
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Y
Y Combinator Blog
H
Hacker News: Front Page
V
V2EX
Security Latest
Security Latest
Cloudbric
Cloudbric
Simon Willison's Weblog
Simon Willison's Weblog
Attack and Defense Labs
Attack and Defense Labs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
博客园 - 三生石上(FineUI控件)
NISL@THU
NISL@THU
S
Secure Thoughts
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
V2EX - 技术
V2EX - 技术
Vercel News
Vercel News
P
Palo Alto Networks Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
有赞技术团队
有赞技术团队
Application and Cybersecurity Blog
Application and Cybersecurity Blog
D
Docker
Google DeepMind News
Google DeepMind News
Webroot Blog
Webroot Blog

Simon Willison's Weblog

Thoughts on GitLab’s workforce reduction A quote from James Shore Your AI Use Is Breaking My Brain TIL: Using LLM in the shebang line of a script Learning on the Shop floor A quote from New York Times Editors’ Note A quote from Andrew Quinn A quote from Luke Curley Release: llm-gemini 0.31 Tool: Big Words Behind the Scenes Hardening Firefox with Claude Mythos Preview Notes on the xAI/Anthropic data center deal Tool: GitHub Repo Stats Live blog: Code w/ Claude 2026 Vibe coding and agentic engineering are getting closer than I’d like Release: datasette-referrer-policy 0.1 Release: datasette-llm 0.1a7 Release: llm-echo 0.5a0 Granite 4.1 3B SVG Pelican Gallery A quote from Andy Masley April 2026 newsletter Research: TRE Python binding — ReDoS robustness demo Tool: Redis Array Playground A quote from Anthropic Sightings iNaturalist Sightings Codex CLI 0.128.0 adds /goal Our evaluation of OpenAI's GPT-5.5 cyber capabilities Quoting Andrew Kelley We need RSS for sharing abundant vibe-coded apps Release: llm 0.32a1 LLM 0.32a0 is a major backwards-compatible refactor Release: llm 0.32a0 Quoting OpenAI Codex base_instructions Quoting Matthew Yglesias What's new in pip 26.1 - lockfiles and dependency cooldowns! Introducing talkie: a 13B vintage language model from 1930 microsoft/VibeVoice Tracking the history of the now-deceased OpenAI Microsoft AGI clause WHY ARE YOU LIKE THIS Quoting Romain Huet GPT-5.5 prompting guide llm 0.31 DeepSeek V4 - almost on the frontier, a fraction of the price Tool: Millisecond Converter It's a big one russellromney/honker Serving the For You feed Extract PDF text in your browser with LiteParse for the web A pelican for GPT-5.5 via the semi-official Codex backdoor API Release: llm-openai-via-codex 0.1a0 Quoting Maggie Appleton A quote from Bobby Holley Is Claude Code going to cost $100/month? Probably not—it’s all very confusing Where’s the raccoon with the ham radio? (ChatGPT Images 2.0) A quote from Andreas Påhlsson-Notini scosman/pelicans_riding_bicycles Release: llm-openrouter 0.6 TIL: SQL functions in Google Sheets to fetch data from Datasette Claude Token Counter, now with model comparisons Headless everything for personal AI Research: Claude system prompts as a git timeline Adding a new content type to my blog-to-newsletter tool - Agentic Engineering Patterns Join us at PyCon US 2026 in Long Beach—we have new AI and security tracks this year Release: datasette 1.0a28 Release: llm-anthropic 0.25 Qwen3.6-35B-A3B on my laptop drew me a better pelican than Claude Opus 4.7 Tool: datasette.io news preview Release: datasette-export-database 0.3a1 Release: datasette 1.0a27 Gemini 3.1 Flash TTS Tool: Gemini 3.1 Flash TTS A quote from Kyle Kingsbury Release: datasette-ports 0.3 Zig 0.16.0 release notes: “Juicy Main” datasette PR #2689: Replace token-based CSRF with Sec-Fetch-Site header protection Tool: SQLite Query Result Formatter Demo Tool: SQLite Query Result Formatter Demo A quote from Giles Turnbull A quote from Giles Turnbull Research: SQLite WAL Mode Across Docker Containers Sharing a Volume Research: SQLite WAL Mode Across Docker Containers Sharing a Volume Tool: Cleanup Claude Code Paste Release: datasette-ports 0.1 Eight years of wanting, three months of building with AI A quote from Chengpeng Mou Tool: Syntaqlite Playground Release: scan-for-secrets 0.2 Release: scan-for-secrets 0.1.1 Release: scan-for-secrets 0.1 Release: research-llm-apis 2026-04-04 A quote from Kyle Daigle Vulnerability Research Is Cooked The cognitive impact of coding agents A quote from Willy Tarreau A quote from Daniel Stenberg A quote from Greg Kroah-Hartman Research: Can JavaScript Escape a CSP Meta Tag Inside an Iframe? The Axios supply chain attack used individually targeted social engineering Highlights from my conversation about agentic engineering on Lenny’s Podcast
sqlite-utils 4.0rc1 adds migrations and nested transactions
Simon Willison · 2026-06-22 · via Simon Willison's Weblog

21st June 2026

sqlite-utils is my combined Python library and CLI tool for working with SQLite databases. It provides an extensive set of higher-level operations on top of Python’s default sqlite3 package, including support for complex table transformations, automatic table creation from JSON data and a whole lot more.

I released sqlite-utils 4.0rc1, the first release candidate for sqlite-utils v4. The major version bump indicates some (minor) backwards incompatible changes, so I’m interested in having people try this out before I commit to a stable release.

New feature: migrations

There are two significant new features in this RC compared to the previous 4.0 alphas.

The first is support for database migrations. This isn’t a completely new implementation—it’s a slightly modified port of the sqlite-migrate package I released a few years ago. I think that package has proved itself over time, so I’m now ready to bundle it with sqlite-utils directly.

Here’s what a set of migrations in a migrations.py file looks like:

from sqlite_utils import Database, Migrations

migrations = Migrations("creatures")

@migrations()
def create_table(db):
    db["creatures"].create(
        {"id": int, "name": str, "species": str},
        pk="id",
    )

@migrations()
def add_weight(db):
    db["creatures"].add_column("weight", float)

This defines a set of two migrations, one creating the creatures table and another adding a column to it.

You can then run those migrations either using Python:

db = Database("creatures.db")
migrations.apply(db)

Or with the command-line migrate command:

sqlite-utils migrate creatures.db migrations.py

The system is deliberately small: it doesn’t provide reverse migrations, so any mistakes you make should be fixed by deploying a fresh migration to undo them.

Its predecessor has been used by LLM and various other projects for several years, so I’m confident that the design is stable and works well.

The new migrations feature is documented here.

New feature: db.atomic() transactions

This feature is a lot less exercised than migrations, so it deserves more attention from testers.

Previously, sqlite-utils mostly left transaction management up to its users, via a with db.conn: construct that reused the sqlite3 mechanism directly.

SQLite supports nested transactions in the form of savepoints, so I wanted an abstraction that could make those as easy to use as possible.

I borrowed the terminology “atomic” from Django and Peewee. Here’s what the new API looks like:

with db.atomic():
    db.table("dogs").insert({"id": 1, "name": "Cleo"}, pk="id")
    try:
        with db.atomic():
            db.table("dogs").insert({"id": 2, "name": "Pancakes"})
            raise ValueError("skip this one")
    except ValueError:
        pass
    db.table("dogs").insert({"id": 3, "name": "Marnie"})

More details in the documentation.

Backwards incompatible changes

The backwards incompatible changes in v4 were described in the alpha release notes. For 4.0a0:

  • Upsert operations now use SQLite’s INSERT ... ON CONFLICT SET syntax on all SQLite versions later than 3.23.1. This is a very slight breaking change for apps that depend on the previous INSERT OR IGNORE followed by UPDATE behavior. (#652)
  • Python library users can opt-in to the previous implementation by passing use_old_upsert=True to the Database() constructor, see Alternative upserts using INSERT OR IGNORE.
  • Dropped support for Python 3.8, added support for Python 3.13. (#646)
  • sqlite-utils tui is now provided by the sqlite-utils-tui plugin. (#648)
  • Test suite now also runs against SQLite 3.23.1, the last version (from 2018-04-10) before the new INSERT ... ON CONFLICT SET syntax was added. (#654)

And for 4.0a1:

  • Breaking change: The db.table(table_name) method now only works with tables. To access a SQL view use db.view(view_name) instead. (#657)
  • The table.insert_all() and table.upsert_all() methods can now accept an iterator of lists or tuples as an alternative to dictionaries. The first item should be a list/tuple of column names. See Inserting data from a list or tuple iterator for details. (#672)
  • Breaking change: The default floating point column type has been changed from FLOAT to REAL, which is the correct SQLite type for floating point values. This affects auto-detected columns when inserting data. (#645)
  • Now uses pyproject.toml in place of setup.py for packaging. (#675)
  • Tables in the Python API now do a much better job of remembering the primary key and other schema details from when they were first created. (#655)
  • Breaking change: The table.convert() and sqlite-utils convert mechanisms no longer skip values that evaluate to False. Previously the --skip-false option was needed, this has been removed. (#542)
  • Breaking change: Tables created by this library now wrap table and column names in "double-quotes" in the schema. Previously they would use [square-braces]. (#677)
  • The --functions CLI argument now accepts a path to a Python file in addition to accepting a string full of Python code. It can also now be specified multiple times. (#659)
  • Breaking change: Type detection is now the default behavior for the insert and upsert CLI commands when importing CSV or TSV data. Previously all columns were treated as TEXT unless the --detect-types flag was passed. Use the new --no-detect-types flag to restore the old behavior. The SQLITE_UTILS_DETECT_TYPES environment variable has been removed. (#679)

Try it out

You can install the new RC like this:

pip install sqlite-utils==4.0rc1

Or try the CLI version directly with uvx like this:

uvx --with sqlite-utils==4.0rc1 sqlite-utils --help

Come chat with us about it in the sqlite-utils Discord channel, or file any bugs in GitHub Issues.