Repository guide · architecture · v2
simonw / sqlite-utils · Architecture
A Python CLI utility and library for SQLite databases, per author-claimed metadata. Analysis covered 107 files across tests/, docs/ and the sqlite_utils package. Execution starts at a __main__ guard in sqlite_utils/__main__.py that calls cli(); of the ten listed paths, nine from cli.py end at unresolved boundaries. db.py holds the highest incoming-call role; 7360 of 8672 relations are unresolved.
- Original repository
- simonw/sqlite-utils
- License
- Apache-2.0 · open-source license
- Analyzed revision · last verified
- 85b1be10c81d9dd3567e36faf8dd411e4a8789bd ·
Newer revision observed; the code this guide cites is unchanged. The default branch moved to 6bc1d33d583c, checked 2026-10-03. A revision diff of 2 changed files found no change in the code regions this guide cites. The guide still describes revision 85b1be10c81d; repository-wide counts (files, calls and so on) refer to that revision.
simonw/sqlite-utils architecture: modules and control flow
Terms used on this page
- Entrypoint record
- A file the analyzer marks as a place where execution can start. When it carries a __main__ guard excerpt, the file contains an if __name__ == "__main__": block and the excerpt shows what that block calls; without an excerpt, the file was flagged by its name only.
- Bounded static execution path
- A call chain reconstructed from the source code without running it, stopped after a fixed number of steps. It shows how far the code can be followed on paper, not what happens at run time.
- Unresolved boundary
- Where a static path stops because the next call goes into an external library or cannot be resolved without running the code. It marks the edge of this analysis, not a defect in the repository.
- Static relations
- Calls and imports found in the source. "External or unresolved" relations point outside the analyzed files.
- Module role
- The analyzer's label for a file, inferred from how many calls go in and out (for example core, entry/orchestration, leaf). It describes a position in the call graph, not the authors' design.
- Test-like files
- Files whose names or locations look like tests. This analysis counts them; it does not run them.
- Observed · inferred · author-claimed · unresolved
- How each statement is supported: read directly from the analyzed files; derived by the analyzer from them; stated by the repository's authors (metadata, README); or not established by this analysis.
- Verified
- Two uses on these pages. In an analyzer record ("verified provenance", "a verified entrypoint") it means the record was read directly from the analyzed files, which these guides call observed; for an entrypoint, the __main__ guard text is present. Since the analyzer fix of 2026-10-04, a file that only has an entrypoint-like name such as cli.py or main.py is recorded as inferred; guides analyzed before that still call such a file verified, and it is still only a guess about how the file is used. It does not mean the code was run or tested. "Last verified" is the date the guide last passed the lab's checks against the analysis record of the stated revision; it is not a review of the repository itself.
Shape at a glance
The GitHub repository metadata describes this project as a 'Python CLI utility and library for manipulating SQLite databases'; treat that as author-claimed, not analyzer-verified. Static analysis covered 107 files: 59 under tests/, 18 under docs/, 11 under sqlite_utils/, 10 under .github/, and 9 at the repository root. The top-level directories docs, sqlite_utils and tests are each flagged as a subsystem. The recorded primary language is Python; recorded topics include cli, click, sqlite and datasette.
Entrypoints and control flow
sqlite_utils/__main__.py contains a Python __main__ execution guard whose guarded body calls cli(). sqlite_utils/cli.py is separately flagged as a likely executable entrypoint by a filename heuristic and marked important for that reason. The listed bounded path from that guard is a single local step — sqlite_utils/__main__.py to cli in sqlite_utils/cli.py — ending with terminal reason 'leaf'; it is not truncated and reports no cycle. Of the 10 listed execution-path records, the 9 that start at sqlite_utils/cli.py all end at an unresolved external target (terminal reason 'unresolved_boundary'): one at strip, two via maximize_csv_field_size_limit in sqlite_utils/utils.py to csv.field_size_limit and int, and six at click.option; none is truncated and none reports a cycle. The reconstruction overview reports 2 entrypoints and 13 bounded execution paths, while only 10 path records are listed here.
Core modules and inferred roles
All 20 listed module-role records derive their roles from static resolved call degree and entrypoint membership, so every role below is an analyzer inference from call counts, not a runtime observation.
- sqlite_utils/db.py — 'service/core candidate' (381 incoming, 317 outgoing static calls)
- sqlite_utils/cli.py — 'entry/orchestration candidate' (127 in, 194 out)
- sqlite_utils/__init__.py — 'leaf/data-boundary candidate' (312 in, 0 out)
- sqlite_utils/create_table_parser.py — 'service/core candidate' (165 in, 122 out)
- sqlite_utils/utils.py — 'service/core candidate' (91 in, 16 out)
- sqlite_utils/plugins.py — 'service/core candidate' (19 in, 1 out)
Of the 20 listed role records, 14 are test modules labelled 'service/core candidate' or 'orchestration candidate'; tests/test_cli.py, for example, shows 7 incoming and 116 outgoing calls. Across those records, db.py holds the highest incoming-call count (381), and __init__.py the highest incoming count among records with zero outgoing calls (312).
Where static paths stop
All nine listed paths that start at sqlite_utils/cli.py stop at unresolved external targets instead of continuing into local code. The targets involved are strip and click.option (called from sqlite_utils/cli.py) and csv.field_size_limit and int (reached via maximize_csv_field_size_limit in sqlite_utils/utils.py). In totals, 7360 of the 8672 recorded static relations are external or unresolved; 1312 resolve locally, and the relations comprise 8263 calls and 409 imports. None of the 10 listed execution-path records shows plugin loading, although a sqlite_utils/plugins.py module appears among the role records.
Dependencies between parts
The packet contains no dependency records, so manifest-level dependencies between parts are not established here. The limitation record explains the gap: dependency records come only from requirements-style manifests, and pyproject.toml dependency tables were not parsed. Individual module-to-module import edges appear in the packet's resolved-relation sample without citable identifiers, so this asset does not restate them; in aggregate, 409 import relations and 8263 calls were recorded.
What static analysis cannot show
The limitation record states that reflection, runtime dependency injection, dynamic imports, monkey-patching, generated code, framework runtime wiring and dynamic dispatch are not resolved by this static analysis. Installation and run/build inference is partial, and installation commands are not verified. README claim extraction is line-based and may capture code lines instead of prose claims, so README-derived statements are author_claimed at best. The manifest's actual_capabilities fields describe the analyzer, not the analyzed repository, and are excluded from repository evidence. Dynamic dispatch, reflection, generated code and runtime framework behaviour therefore remain unestablished by this asset.
A reading order for the architecture
README.md, pyproject.toml and LICENSE are classified as project-level important files, so they make natural first reads. The two flagged entrypoints, sqlite_utils/__main__.py and sqlite_utils/cli.py, come next. A workable order from there: read the __main__ guard, follow its one-step path into cli(), then use the role records as a map for db.py, utils.py, create_table_parser.py and plugins.py before reading deeper code.
What this analysis could not establish
The writing model's own notes on the analysis record. Identifiers such as lim_3, exec_* or claim_… name records of that analysis; the claims table cites the same records.
- The reconstruction overview reports 13 bounded execution paths, while the packet lists 10 execution-path records; this asset describes only the 10 listed records.
- The reconstruction reports 1127 resolved static call relations, while relation_counts reports 1312 local relations of 8672 total; both figures are reported as given.
- The packet contains no dep_* dependency records, so package-level dependencies between parts are not established.
- boundaries_static and resolved_relation_summary_sample entries carry no citable IDs, so boundary and import statements here are grounded only via execution-path records and relation counts.
- important_2 (readme.md) is excluded from evidence because its path is not in the analyzed file inventory (case-variant match); only README.md is treated as present.
- Role records cover 20 modules, 14 of them test modules; other modules in sqlite_utils/ are not characterized in this packet.
Claims and evidence — 33 claims, 33 supported by an independent verifier
Every substantive statement above is a claim bound to grounding IDs of the analyzed revision. Global grounding IDs are namespaced by the analysis run.
| Claim | Epistemic status | Verifier | Grounding (global IDs) |
|---|---|---|---|
| c1 The GitHub repository metadata describes the project as a 'Python CLI utility and library for manipulating SQLite databases'; this is author-claimed, not analyzer-verified. | author_claimed | supported | analysis_4dc72394ecce6742:meta_description |
| c2 Static analysis covered 107 files: 59 under tests/, 18 under docs/, 11 under sqlite_utils/, 10 under .github/, and 9 at the repository root. | inferred | supported | analysis_4dc72394ecce6742:summary_repository |
| c3 The top-level directories docs, sqlite_utils and tests are each flagged as a subsystem. | observed | supported | analysis_4dc72394ecce6742:subsys_1, analysis_4dc72394ecce6742:subsys_2, analysis_4dc72394ecce6742:subsys_3 |
| c4 The recorded primary language is Python, and repository topics include cli, click, sqlite and datasette. | observed | supported | analysis_4dc72394ecce6742:meta_primary_language, analysis_4dc72394ecce6742:meta_topics |
| c5 sqlite_utils/__main__.py contains a Python __main__ execution guard; its guarded body calls cli(). | observed | supported | analysis_4dc72394ecce6742:py_entry_766b287179b9 |
| c6 sqlite_utils/cli.py is flagged as a likely executable entrypoint by a filename heuristic and is marked important for that reason. | observed | supported | analysis_4dc72394ecce6742:entry_1, analysis_4dc72394ecce6742:important_6 |
| c7 The listed bounded path from sqlite_utils/__main__.py:__main__ is a single local step to cli in sqlite_utils/cli.py, ending with terminal reason 'leaf'; it is not truncated and reports no cycle. | inferred | supported | analysis_4dc72394ecce6742:exec_646e4227082d |
| c8 Of the 10 listed execution-path records, the 9 starting at sqlite_utils/cli.py all terminate with reason 'unresolved_boundary': one at strip, two via maximize_csv_field_size_limit to csv.field_size_limit and int, and six at click.option; none is truncated and none reports a cycle. | inferred | supported | analysis_4dc72394ecce6742:exec_905105dee30d, analysis_4dc72394ecce6742:exec_585cacddd5fa, analysis_4dc72394ecce6742:exec_6afdc3bbf9ee, analysis_4dc72394ecce6742:exec_13a2f2c834ee, analysis_4dc72394ecce6742:exec_00b231e391d5, analysis_4dc72394ecce6742:exec_1f6b3c94d254, analysis_4dc72394ecce6742:exec_ffcc4c1e7a73, analysis_4dc72394ecce6742:exec_92345437f89a, analysis_4dc72394ecce6742:exec_1a66dc92ffff |
| c9 The reconstruction overview reports 2 entrypoints, 1127 resolved static call relations and 13 bounded execution paths, while this packet lists only 10 execution-path records. | inferred | supported | analysis_4dc72394ecce6742:architecture_reconstruction |
| c10 All 20 listed module-role records base their roles on static resolved call degree and entrypoint membership, so the roles are analyzer inferences from call counts, not runtime observations. | inferred | supported | analysis_4dc72394ecce6742:role_2, analysis_4dc72394ecce6742:role_4, analysis_4dc72394ecce6742:role_5, analysis_4dc72394ecce6742:role_6, analysis_4dc72394ecce6742:role_8, analysis_4dc72394ecce6742:role_10, analysis_4dc72394ecce6742:role_15, analysis_4dc72394ecce6742:role_18, analysis_4dc72394ecce6742:role_20, analysis_4dc72394ecce6742:role_23, analysis_4dc72394ecce6742:role_24, analysis_4dc72394ecce6742:role_25, analysis_4dc72394ecce6742:role_29, analysis_4dc72394ecce6742:role_31, analysis_4dc72394ecce6742:role_34, analysis_4dc72394ecce6742:role_35, analysis_4dc72394ecce6742:role_38, analysis_4dc72394ecce6742:role_39, analysis_4dc72394ecce6742:role_40, analysis_4dc72394ecce6742:role_49 |
| c11 sqlite_utils/db.py carries the role 'service/core candidate' with 381 incoming and 317 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_6 |
| c12 sqlite_utils/cli.py carries the role 'entry/orchestration candidate' with 127 incoming and 194 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_4 |
| c13 sqlite_utils/__init__.py carries the role 'leaf/data-boundary candidate' with 312 incoming and 0 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_2 |
| c14 sqlite_utils/create_table_parser.py carries the role 'service/core candidate' with 165 incoming and 122 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_5 |
| c15 sqlite_utils/utils.py carries the role 'service/core candidate' with 91 incoming and 16 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_10 |
| c16 sqlite_utils/plugins.py carries the role 'service/core candidate' with 19 incoming and 1 outgoing static calls. | inferred | supported | analysis_4dc72394ecce6742:role_8 |
| c17 Of the 20 listed role records, 14 are test modules under tests/, labelled 'service/core candidate' or 'orchestration candidate'; tests/test_cli.py, for example, shows 7 incoming and 116 outgoing calls. | inferred | supported | analysis_4dc72394ecce6742:role_2, analysis_4dc72394ecce6742:role_4, analysis_4dc72394ecce6742:role_5, analysis_4dc72394ecce6742:role_6, analysis_4dc72394ecce6742:role_8, analysis_4dc72394ecce6742:role_10, analysis_4dc72394ecce6742:role_15, analysis_4dc72394ecce6742:role_18, analysis_4dc72394ecce6742:role_20, analysis_4dc72394ecce6742:role_23, analysis_4dc72394ecce6742:role_24, analysis_4dc72394ecce6742:role_25, analysis_4dc72394ecce6742:role_29, analysis_4dc72394ecce6742:role_31, analysis_4dc72394ecce6742:role_34, analysis_4dc72394ecce6742:role_35, analysis_4dc72394ecce6742:role_38, analysis_4dc72394ecce6742:role_39, analysis_4dc72394ecce6742:role_40, analysis_4dc72394ecce6742:role_49 |
| c18 Across the 20 listed role records, sqlite_utils/db.py holds the highest incoming-call count (381), and sqlite_utils/__init__.py the highest incoming count among records with zero outgoing calls (312). | inferred | supported | analysis_4dc72394ecce6742:role_2, analysis_4dc72394ecce6742:role_4, analysis_4dc72394ecce6742:role_5, analysis_4dc72394ecce6742:role_6, analysis_4dc72394ecce6742:role_8, analysis_4dc72394ecce6742:role_10, analysis_4dc72394ecce6742:role_15, analysis_4dc72394ecce6742:role_18, analysis_4dc72394ecce6742:role_20, analysis_4dc72394ecce6742:role_23, analysis_4dc72394ecce6742:role_24, analysis_4dc72394ecce6742:role_25, analysis_4dc72394ecce6742:role_29, analysis_4dc72394ecce6742:role_31, analysis_4dc72394ecce6742:role_34, analysis_4dc72394ecce6742:role_35, analysis_4dc72394ecce6742:role_38, analysis_4dc72394ecce6742:role_39, analysis_4dc72394ecce6742:role_40, analysis_4dc72394ecce6742:role_49 |
| c19 All nine listed paths that start at sqlite_utils/cli.py stop at unresolved external targets instead of continuing into local code. | inferred | supported | analysis_4dc72394ecce6742:exec_905105dee30d, analysis_4dc72394ecce6742:exec_585cacddd5fa, analysis_4dc72394ecce6742:exec_6afdc3bbf9ee, analysis_4dc72394ecce6742:exec_13a2f2c834ee, analysis_4dc72394ecce6742:exec_00b231e391d5, analysis_4dc72394ecce6742:exec_1f6b3c94d254, analysis_4dc72394ecce6742:exec_ffcc4c1e7a73, analysis_4dc72394ecce6742:exec_92345437f89a, analysis_4dc72394ecce6742:exec_1a66dc92ffff |
| c20 The unresolved targets on those nine paths are strip and click.option (called from sqlite_utils/cli.py) and csv.field_size_limit and int (reached via maximize_csv_field_size_limit in sqlite_utils/utils.py). | inferred | supported | analysis_4dc72394ecce6742:exec_905105dee30d, analysis_4dc72394ecce6742:exec_585cacddd5fa, analysis_4dc72394ecce6742:exec_6afdc3bbf9ee, analysis_4dc72394ecce6742:exec_13a2f2c834ee, analysis_4dc72394ecce6742:exec_00b231e391d5, analysis_4dc72394ecce6742:exec_1f6b3c94d254, analysis_4dc72394ecce6742:exec_ffcc4c1e7a73, analysis_4dc72394ecce6742:exec_92345437f89a, analysis_4dc72394ecce6742:exec_1a66dc92ffff |
| c21 The analyzer recorded 8672 static relations in total: 8263 calls and 409 imports, of which 1312 resolve locally and 7360 are external or unresolved. | observed | supported | analysis_4dc72394ecce6742:relation_counts |
| c22 None of the 10 listed execution-path records shows plugin loading, although a sqlite_utils/plugins.py module appears among the role records. | inferred | supported | analysis_4dc72394ecce6742:exec_646e4227082d, analysis_4dc72394ecce6742:exec_905105dee30d, analysis_4dc72394ecce6742:exec_585cacddd5fa, analysis_4dc72394ecce6742:exec_6afdc3bbf9ee, analysis_4dc72394ecce6742:exec_13a2f2c834ee, analysis_4dc72394ecce6742:exec_00b231e391d5, analysis_4dc72394ecce6742:exec_1f6b3c94d254, analysis_4dc72394ecce6742:exec_ffcc4c1e7a73, analysis_4dc72394ecce6742:exec_92345437f89a, analysis_4dc72394ecce6742:exec_1a66dc92ffff, analysis_4dc72394ecce6742:role_8 |
| c23 This packet contains no dependency records, so manifest-level dependencies between parts are not established by this asset. | unresolved | supported | analysis_4dc72394ecce6742:lim_3 |
| c24 Dependency records in this analysis come only from requirements-style manifests; pyproject.toml dependency tables were not parsed by the analyzer. | observed | supported | analysis_4dc72394ecce6742:lim_3 |
| c25 The packet's resolved-relation sample lists individual import edges without citable identifiers, so this asset does not restate specific module-to-module imports; in aggregate the analyzer recorded 409 import relations and 8263 calls. | unresolved | supported | analysis_4dc72394ecce6742:relation_counts |
| c26 The limitation record states that reflection, runtime dependency injection, dynamic imports, monkey-patching, generated code, framework runtime wiring and dynamic dispatch are not resolved by this static analysis. | observed | supported | analysis_4dc72394ecce6742:lim_1 |
| c27 Installation and run/build inference is partial, and installation commands are not verified. | observed | supported | analysis_4dc72394ecce6742:lim_2 |
| c28 README claim extraction is line-based and may capture code lines instead of prose claims, so README-derived statements are author_claimed at best. | observed | supported | analysis_4dc72394ecce6742:lim_4 |
| c29 The manifest's actual_capabilities and non_capabilities fields describe the analyzer, not the analyzed repository, and are excluded from repository evidence. | observed | supported | analysis_4dc72394ecce6742:lim_5 |
| c30 Static analysis cannot establish all dynamic dispatch, reflection, generated-code or runtime framework behaviour, so this asset treats those behaviours as unresolved. | unresolved | supported | analysis_4dc72394ecce6742:claim_7c9925f9c8f4 |
| c31 README.md, pyproject.toml and LICENSE are classified as project-level important files. | observed | supported | analysis_4dc72394ecce6742:important_1, analysis_4dc72394ecce6742:important_3, analysis_4dc72394ecce6742:important_4 |
| c32 sqlite_utils/__main__.py and sqlite_utils/cli.py are flagged as likely entrypoints. | observed | supported | analysis_4dc72394ecce6742:important_5, analysis_4dc72394ecce6742:important_6, analysis_4dc72394ecce6742:entry_1 |
| c33 A workable reading order is: project-level files, then the __main__ guard and its one-step path into cli(), then db.py (381 incoming calls), utils.py, create_table_parser.py and plugins.py, using the listed execution paths and role records as the map. | inferred | supported | analysis_4dc72394ecce6742:important_1, analysis_4dc72394ecce6742:py_entry_766b287179b9, analysis_4dc72394ecce6742:exec_646e4227082d, analysis_4dc72394ecce6742:role_6, analysis_4dc72394ecce6742:role_10, analysis_4dc72394ecce6742:role_5, analysis_4dc72394ecce6742:role_8 |
Sources, rights and disclosure · attribution-license-templates/v0.1
Rights notice. Original repository hosted on GitHub. Repository source code, documentation, names, media, and related project materials remain subject to the rights of their respective authors, contributors, and other rights holders and to applicable repository license terms.
Platform notice. GitHub is the source hosting platform for the linked repository. GitHub and related marks are trademarks of GitHub, Inc. EVEMISS Technology is not affiliated with or endorsed by GitHub unless explicitly stated otherwise.
How this page is produced. This page was produced using revision-aware repository analysis and AI-assisted editorial tooling. Technical claims are tied to the analyzed repository revision and may be revalidated when the source repository changes.
AI-assisted analysis. Reviewed by EVEMISS Technology through human–AI collaborative review. · Report a rights concern · Back to the overview