From d5bf51df35a527aae19417c97eb3949ffb6df5bc Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sun, 5 Jul 2026 14:26:56 -0700 Subject: [PATCH] Fix TypeError when sorting mixed compound/single foreign keys sorted() on a foreign_keys list containing both compound (column=None) and single-column ForeignKeys raised TypeError because dataclass ordering compared None against str. column/other_column are now excluded from comparison - ordering and equality use the always populated columns/other_columns lists instead. Co-Authored-By: Claude Fable 5 --- sqlite_utils/db.py | 6 ++++-- tests/test_foreign_keys.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index b1cdf83..67623fe 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -182,9 +182,11 @@ class ForeignKey: """ table: str - column: Optional[str] + # column/other_column are None for compound keys, which would break + # ordering against str values - comparison uses columns/other_columns + column: Optional[str] = field(compare=False) other_table: str - other_column: Optional[str] + other_column: Optional[str] = field(compare=False) columns: List[str] = field(default_factory=list) other_columns: List[str] = field(default_factory=list) is_compound: bool = False diff --git a/tests/test_foreign_keys.py b/tests/test_foreign_keys.py index c785b59..4b371a9 100644 --- a/tests/test_foreign_keys.py +++ b/tests/test_foreign_keys.py @@ -80,3 +80,31 @@ def test_foreign_keys_are_sortable(fresh_db): fks = sorted(fresh_db["books"].foreign_keys) assert fks[0].column == "author_id" assert fks[1].column == "category_id" + + +def test_mixed_compound_and_single_foreign_keys_are_sortable(): + # compound FKs have column=None, which must not break sorting + # against single-column FKs (None < str raises TypeError) + db = Database(memory=True) + db.executescript(""" + CREATE TABLE departments ( + campus_name TEXT NOT NULL, + dept_code TEXT NOT NULL, + PRIMARY KEY (campus_name, dept_code) + ); + CREATE TABLE accreditations (id INTEGER PRIMARY KEY); + CREATE TABLE courses ( + course_code TEXT PRIMARY KEY, + campus_name TEXT NOT NULL, + dept_code TEXT NOT NULL, + accreditation_id INTEGER REFERENCES accreditations(id), + FOREIGN KEY (campus_name, dept_code) + REFERENCES departments(campus_name, dept_code) + ); + """) + fks = db["courses"].foreign_keys + assert len(fks) == 2 + assert {fk.is_compound for fk in fks} == {True, False} + fks_sorted = sorted(fks) + assert fks_sorted[0].other_table == "accreditations" + assert fks_sorted[1].other_table == "departments"