Repository guide · overview · v2
simonw / datasette
“An open source multi-tool for exploring and publishing data” — as described by its authors
- Data and Databases
- Python
- Apache-2.0 · open-source license
- Original repository
- simonw/datasette
- Source platform
- GitHub
- Repository owner / organization
- simonw
- License
- Apache-2.0 · open-source license
- Analyzed revision
- b338c6f5f6b39dd3e0a341431f071d8cecb0d12b
- Last verified
Newer revision observed; parts of this guide may be outdated. The default branch moved to cec5e6b2ef5d, checked 2026-10-03. The whole guide describes revision b338c6f5f6b3. A revision diff found changes in 4 code regions it cites (listed below); statements about those regions may not hold at the new revision and have not been rechecked yet.
- datasette/app.py:394-3037 · lines changed
- datasette/app.py:3040-3314 · lines changed
- datasette/app.py:168 · call site on the execution path changed
- datasette/utils/asgi.py:86-284 · lines changed
simonw/datasette repository overview: Python data exploration tool
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.
Datasette is an open-source Python tool for exploring and publishing data (per GitHub metadata), licensed Apache-2.0. Its __main__ guard calls the CLI in datasette/cli.py; datasette/app.py hosts the Datasette and DatasetteRouter classes. Code splits into the datasette package plus tests and docs trees. Analysis is static-only: 15,850 of 21,338 relations remain unresolved.
What this repository is
GitHub metadata describes the project as "An open source multi-tool for exploring and publishing data", and gives datasette.io as its homepage. The primary language is Python; the byte breakdown lists about 2.47 million Python bytes alongside JavaScript, HTML, CSS, Shell, C, Dockerfile and Just files. Repository topics include asgi, automatic-api, csv, datasets, datasette, docker, json, python, sql and sqlite. The license is Apache-2.0, and a LICENSE file sits at the repository root. Structurally, the analyzed snapshot has 333 files: a datasette package (135 files) plus tests (102), docs (50), demos (7) and a few other top-level directories. The latest listed release is 1.0a39 (published 2026-09-11), and the repository had 11,460 stars on 2026-09-14.
How the program starts
The only launch code shown in datasette/__main__.py is a main guard that calls cli():
if __name__ == "__main__":
cli()
A bounded static execution path records that __main__ hands off to cli in datasette/cli.py and stops there as a leaf. datasette/app.py and datasette/cli.py are both flagged as likely executable entrypoints (filename heuristic). app.py is labeled an entry/orchestration candidate with 356 incoming and 197 outgoing static calls. It contains the two large classes Datasette (lines 394-3037) and DatasetteRouter (lines 3040-3314). Note the limits: every traced execution path starting at app.py ends at an unresolved external boundary such as logging.getLogger, contextvars.ContextVar, collections.namedtuple or Setting, so deeper runtime wiring is not established.
Repository structure and most-connected modules
- Top-level layout separates the application package
datasettefrom thedocsandtestssubsystems. datasette/utils/__init__.pyis the most connected Python module (519 incoming / 53 outgoing calls) and definesCustomJSONEncoderandsqlite_timelimit.datasette/utils/asgi.pyis next (369 incoming) and definesRequest,AsgiLifespan,AsgiStreamandAsgiWriter, plus exception classes likeNotFoundandForbidden.datasette/views/table.pyhas the highest outgoing degree among the listed Python modules (283 out / 46 in), which suggests it coordinates many modules; it definesTableContextandRow.datasette/__init__.py(348 in / 0 out) anddatasette/resources.py(227 in / 0 out) look like leaf/data-boundary modules;resources.pydefinesDatabaseResource,TableResourceandQueryResource.- Front-end assets live under
datasette/static; the analyzer reports the highest overall degree foredit-tools.js(808/808) andtable.js(83/83), but JavaScript analysis is only a bounded heuristic.
Dependencies and tests
Manifest evidence in this packet covers JavaScript tooling only. package.json, one of two detected build/dependency manifests, lists runtime dependencies @codemirror/lang-sql ^6.3.3, codemirror ^6.0.1, rollup ^3.30.0, @rollup/plugin-node-resolve ^15.0.1 and @rollup/plugin-terser ^0.1.0, plus prettier ^3.0.0 as a dev dependency. Dependency parsing has a hard limit here: only requirements-style manifests were parsed, and pyproject.toml dependency tables were not, so the Python package's own dependencies are not established by this analysis. The tests subsystem contains 102 test files. Sampled file tests/test_api_write.py defines helpers ds_write and write_token and tests such as test_structured_writes_require_ordinary_tables and test_base64_write_api_insert_upsert_update_decode_blobs. tests/build_small_spatialite_db.py is a project-important likely entrypoint whose __main__ guard calls generate_it("spatialite.db"), generating a SQLite test database.
A reading order for newcomers
README.md- marked project-level important; the usual first stop.pyproject.tomlandpackage.json- packaging and tooling manifests, both flagged important.datasette/__main__.py, thendatasette/cli.py- the launch chain; the static path runs from the__main__guard tocli.datasette/app.py- central orchestration module, holding theDatasetteandDatasetteRouterclasses.datasette/utils/__init__.pyanddatasette/utils/asgi.py- the highest incoming-call counts among the listed Python modules (519 and 369;edit-tools.jsreports 808 incoming overall).datasette/views/table.py- view logic with the highest outgoing call degree among Python modules (283;edit-tools.jsreports 808 outgoing overall), a good window into how requests reach the rest of the code.
When changing code, start tracing at the detected entrypoint datasette/app.py and check downstream effects by hand, because dynamic behaviour is not resolved statically.
What this analysis cannot tell you
- Static only: reflection, dynamic imports, monkey-patching, generated code, framework runtime wiring and dynamic dispatch are not resolved, so how plugins are discovered and loaded cannot be established from this packet.
- Install, run and build inference is partial; installation commands are not verified, and the packet contains no runtime or execution results.
- Of 21,338 static relations, 15,850 are external or unresolved and 5,488 resolve locally.
- Two files were inventoried but not parsed (oversized, minified or vendored); bounded analysis also skips files over 400 kB, minified bundles and vendored directories.
- Dependency coverage is partial:
pyproject.tomldependency tables were not parsed. - README claim extraction is line-based and may capture code lines, so any README-derived statement is author_claimed at best.
Symbols worth knowing
Datasette(datasette/app.py, lines 394-3037) andDatasetteRouter(lines 3040-3314): the two large classes inapp.py, which the analyzer labels an entry/orchestration candidate.DatabaseResource,TableResource,QueryResource(datasette/resources.py): classes in a module labeled a leaf/data-boundary candidate.Request,AsgiLifespan,AsgiStream,AsgiWriterand theNotFound/Forbidden/BadRequest/PayloadTooLargeexceptions (datasette/utils/asgi.py): classes in the module with the second-highest incoming call count among the listed Python modules (369).CustomJSONEncoderandsqlite_timelimit(datasette/utils/__init__.py) plusTableContextandRow(datasette/views/table.py): symbols in the listed Python modules with the most incoming calls (519) and the most outgoing calls (283).
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.
- Python dependencies are unknown for this snapshot: the analyzer parsed only requirements-style manifests and skipped pyproject.toml dependency tables (lim_3).
- 15,850 of 21,338 static relations are external or unresolved, so module-interaction statements beyond the cited samples may be incomplete.
- Plugin discovery and loading behaviour could not be traced; dynamic imports and framework runtime wiring are unresolved (lim_1).
- Two minified JavaScript bundles under datasette/static were inventoried but not parsed.
- The analyzer's inferred purpose ('web or Node.js application') sits awkwardly with the Python-primary language statistics; that framing should be treated cautiously.
- No runtime or execution evidence exists in the packet; startup behaviour beyond the __main__ -> cli edge is inference.
- important_2 (readme.md) was excluded as a case-variant path of README.md, a filesystem path-matching quirk in the analysis.
Claims and evidence — 39 claims, 39 supported by an independent verifier
Every statement above is a claim that cites grounding IDs from the analysis. IDs are internal to the analysis run; the columns show what each claim rests on and how strong that ground is.
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 GitHub metadata describes the project as "An open source multi-tool for exploring and publishing data" and gives datasette.io as its homepage. | author_claimed | supported | analysis_ef14c7222eb9f538:meta_description, analysis_ef14c7222eb9f538:meta_homepage |
| c2 The repository's primary language is Python, and the language-byte breakdown lists about 2.47 million Python bytes alongside JavaScript, HTML, CSS, Shell, C, Dockerfile and Just. | observed | supported | analysis_ef14c7222eb9f538:meta_primary_language, analysis_ef14c7222eb9f538:meta_language_bytes |
| c3 Repository topics include asgi, automatic-api, csv, datasets, datasette, docker, json, python, sql and sqlite. | observed | supported | analysis_ef14c7222eb9f538:meta_topics |
| c4 The license is Apache-2.0 per repository metadata, and a LICENSE file exists at the repository root. | observed | supported | analysis_ef14c7222eb9f538:meta_license, analysis_ef14c7222eb9f538:important_5 |
| c5 The analyzed snapshot has 333 files, including a datasette package of 135 files, a tests tree of 102 files, docs with 50 and demos with 7. | inferred | supported | analysis_ef14c7222eb9f538:summary_repository, analysis_ef14c7222eb9f538:subsys_1, analysis_ef14c7222eb9f538:subsys_2, analysis_ef14c7222eb9f538:subsys_3 |
| c6 The latest listed release is 1.0a39, published 2026-09-11; the repository had 11,460 stargazers as of 2026-09-14. | observed | supported | analysis_ef14c7222eb9f538:meta_latest_release, analysis_ef14c7222eb9f538:meta_stars |
| c7 datasette/__main__.py contains a __main__ execution guard whose body calls cli(); it is classified as project-important and a likely entrypoint. | observed | supported | analysis_ef14c7222eb9f538:py_entry_7cbf1557a33b, analysis_ef14c7222eb9f538:important_6 |
| c8 A bounded static execution path records datasette/__main__.py transferring to cli in datasette/cli.py, terminating as a leaf. | inferred | supported | analysis_ef14c7222eb9f538:exec_707222db7901 |
| c9 datasette/app.py and datasette/cli.py are flagged as likely executable entrypoints by filename heuristic. | observed | supported | analysis_ef14c7222eb9f538:entry_1, analysis_ef14c7222eb9f538:entry_2 |
| c10 Call-degree evidence labels datasette/app.py an entry/orchestration candidate with 356 incoming and 197 outgoing static calls. | inferred | supported | analysis_ef14c7222eb9f538:role_5 |
| c11 app.py defines the Datasette class at lines 394-3037 and the DatasetteRouter class at lines 3040-3314. | observed | supported | analysis_ef14c7222eb9f538:py_class_e1f78b54738f, analysis_ef14c7222eb9f538:py_class_5b91150ffc65 |
| c12 Traced execution paths starting at app.py terminate at unresolved external boundaries including logging.getLogger, contextvars.ContextVar, collections.namedtuple and Setting. | inferred | supported | analysis_ef14c7222eb9f538:exec_141532159c69, analysis_ef14c7222eb9f538:exec_6c1e96f0a6c1, analysis_ef14c7222eb9f538:exec_99dfaf114e63, analysis_ef14c7222eb9f538:exec_af5f4c46e06d, analysis_ef14c7222eb9f538:exec_bb193f5bffdb |
| c13 Top-level directories datasette, docs and tests are identified as subsystems. | observed | supported | analysis_ef14c7222eb9f538:subsys_1, analysis_ef14c7222eb9f538:subsys_2, analysis_ef14c7222eb9f538:subsys_3 |
| c14 datasette/utils/__init__.py has 519 incoming and 53 outgoing calls (service/core candidate) and defines helpers such as CustomJSONEncoder and sqlite_timelimit. | inferred | supported | analysis_ef14c7222eb9f538:role_52, analysis_ef14c7222eb9f538:py_class_faf43d86d5e4, analysis_ef14c7222eb9f538:py_func_43f232c11a74 |
| c15 datasette/utils/asgi.py has 369 incoming calls and defines Request, AsgiLifespan, AsgiStream, AsgiWriter, and exception classes including NotFound and Forbidden. | inferred | supported | analysis_ef14c7222eb9f538:role_54, analysis_ef14c7222eb9f538:py_class_cd4cbe1b803b, analysis_ef14c7222eb9f538:py_class_35d6af4bda0b, analysis_ef14c7222eb9f538:py_class_95cbf9060202, analysis_ef14c7222eb9f538:py_class_817272a7a16b, analysis_ef14c7222eb9f538:py_class_d21aa11be3ea, analysis_ef14c7222eb9f538:py_class_82a449d307f2 |
| c16 Among the listed Python modules, datasette/views/table.py has the highest outgoing degree (283 out, 46 in), suggesting it coordinates many modules; it defines TableContext and Row. | inferred | supported | analysis_ef14c7222eb9f538:role_73, analysis_ef14c7222eb9f538:role_44, analysis_ef14c7222eb9f538:py_class_6bca6cbe2675, analysis_ef14c7222eb9f538:py_class_e322d4ac69f5 |
| c17 datasette/__init__.py (348 in, 0 out) and datasette/resources.py (227 in, 0 out) are leaf/data-boundary candidates; resources.py defines DatabaseResource, TableResource and QueryResource. | inferred | supported | analysis_ef14c7222eb9f538:role_1, analysis_ef14c7222eb9f538:role_41, analysis_ef14c7222eb9f538:py_class_03bbfae65c78, analysis_ef14c7222eb9f538:py_class_3c5aca171b90, analysis_ef14c7222eb9f538:py_class_dd9acf15784d |
| c18 The highest reported degree belongs to datasette/static/edit-tools.js (808 incoming/outgoing), with datasette/static/table.js at 83/83; JavaScript analysis is bounded-heuristic. | inferred | supported | analysis_ef14c7222eb9f538:role_44, analysis_ef14c7222eb9f538:role_46 |
| c19 package.json - one of two detected build/dependency manifests - lists runtime dependencies @codemirror/lang-sql ^6.3.3, @rollup/plugin-node-resolve ^15.0.1, @rollup/plugin-terser ^0.1.0, codemirror ^6.0.1, rollup ^3.30.0, and dev dependency prettier ^3.0.0. | observed | supported | analysis_ef14c7222eb9f538:dep_1, analysis_ef14c7222eb9f538:dep_2, analysis_ef14c7222eb9f538:dep_3, analysis_ef14c7222eb9f538:dep_4, analysis_ef14c7222eb9f538:dep_5, analysis_ef14c7222eb9f538:dep_6, analysis_ef14c7222eb9f538:ev_manifest_1, analysis_ef14c7222eb9f538:important_4 |
| c20 Dependency records come only from requirements-style manifests; pyproject.toml dependency tables were not parsed, so Python dependencies are not established by this analysis. | observed | supported | analysis_ef14c7222eb9f538:lim_3 |
| c21 The repository contains 102 test files or test-like files, and the tests directory is a recognized subsystem. | observed | supported | analysis_ef14c7222eb9f538:ev_tests_1, analysis_ef14c7222eb9f538:subsys_3 |
| c22 tests/test_api_write.py defines helpers ds_write and write_token plus tests such as test_structured_writes_require_ordinary_tables and test_base64_write_api_insert_upsert_update_decode_blobs; the analyzer counts 123 incoming calls for the file. | inferred | supported | analysis_ef14c7222eb9f538:py_func_7e4eb77eebbc, analysis_ef14c7222eb9f538:py_func_cb2fb92f620c, analysis_ef14c7222eb9f538:py_func_44bcadc2eed8, analysis_ef14c7222eb9f538:py_func_5ee2d6343eed, analysis_ef14c7222eb9f538:role_92 |
| c23 tests/build_small_spatialite_db.py is a project-important likely entrypoint whose __main__ guard calls generate_it("spatialite.db"), generating a SQLite test database. | observed | supported | analysis_ef14c7222eb9f538:py_entry_f23c245ed3b2, analysis_ef14c7222eb9f538:important_7 |
| c24 README.md is classified as a project-level important file, making it the first orientation stop. | observed | supported | analysis_ef14c7222eb9f538:important_1 |
| c25 pyproject.toml and package.json are both project-level important files covering packaging and tooling. | observed | supported | analysis_ef14c7222eb9f538:important_3, analysis_ef14c7222eb9f538:important_4 |
| c26 datasette/__main__.py and datasette/cli.py are important likely entrypoints, and the static execution path runs from the __main__ guard to cli. | inferred | supported | analysis_ef14c7222eb9f538:important_6, analysis_ef14c7222eb9f538:important_10, analysis_ef14c7222eb9f538:exec_707222db7901 |
| c27 datasette/app.py is a project-important likely entrypoint holding the Datasette and DatasetteRouter classes. | observed | supported | analysis_ef14c7222eb9f538:important_9, analysis_ef14c7222eb9f538:entry_1, analysis_ef14c7222eb9f538:py_class_e1f78b54738f, analysis_ef14c7222eb9f538:py_class_5b91150ffc65 |
| c28 datasette/utils/__init__.py and datasette/utils/asgi.py have the highest incoming-call counts among the listed Python modules (519 and 369); datasette/static/edit-tools.js reports 808 incoming overall. | inferred | supported | analysis_ef14c7222eb9f538:role_52, analysis_ef14c7222eb9f538:role_54, analysis_ef14c7222eb9f538:role_44 |
| c29 datasette/views/table.py has the highest outgoing call degree among Python modules (283), making it a useful window into how view logic reaches other modules; datasette/static/edit-tools.js reports 808 outgoing overall. | inferred | supported | analysis_ef14c7222eb9f538:role_73, analysis_ef14c7222eb9f538:role_44 |
| c30 Start modification tracing at detected entrypoint datasette/app.py and check downstream effects by hand, because dynamic behaviour is not resolved statically. | observed | supported | analysis_ef14c7222eb9f538:entry_1, analysis_ef14c7222eb9f538:lim_1 |
| c31 Install, run and build inference is partial; installation commands are not verified, and the packet contains no runtime or execution results. | observed | supported | analysis_ef14c7222eb9f538:lim_2 |
| c32 Reflection, dynamic imports, monkey-patching, generated code, framework runtime wiring and dynamic dispatch are not resolved, so plugin discovery and loading cannot be established from this packet. | observed | supported | analysis_ef14c7222eb9f538:lim_1 |
| c33 Of 21,338 static relations, 15,850 are external or unresolved and 5,488 resolve locally. | observed | supported | analysis_ef14c7222eb9f538:relation_counts |
| c34 Two files were inventoried but not parsed (oversized, minified or vendored); bounded analysis also skips files over 400 kB, minified bundles and vendored directories. | unresolved | supported | analysis_ef14c7222eb9f538:claim_e6126b089362, analysis_ef14c7222eb9f538:lim_6 |
| c35 README claim extraction is line-based and may capture code lines, so README-derived statements are author_claimed at best. | observed | supported | analysis_ef14c7222eb9f538:lim_4 |
| c36 pyproject.toml is a project-important manifest, but its dependency tables were not parsed by the analyzer. | observed | supported | analysis_ef14c7222eb9f538:important_3, analysis_ef14c7222eb9f538:lim_3 |
| c37 Named symbols include Datasette (datasette/app.py, lines 394-3037), DatasetteRouter (lines 3040-3314), and DatabaseResource, TableResource, QueryResource in datasette/resources.py. | observed | supported | analysis_ef14c7222eb9f538:py_class_e1f78b54738f, analysis_ef14c7222eb9f538:py_class_5b91150ffc65, analysis_ef14c7222eb9f538:py_class_03bbfae65c78, analysis_ef14c7222eb9f538:py_class_3c5aca171b90, analysis_ef14c7222eb9f538:py_class_dd9acf15784d |
| c38 datasette/utils/asgi.py defines Request (lines 86-284), AsgiLifespan, AsgiStream, AsgiWriter, and exceptions NotFound, Forbidden, BadRequest and PayloadTooLarge. | observed | supported | analysis_ef14c7222eb9f538:py_class_cd4cbe1b803b, analysis_ef14c7222eb9f538:py_class_35d6af4bda0b, analysis_ef14c7222eb9f538:py_class_95cbf9060202, analysis_ef14c7222eb9f538:py_class_817272a7a16b, analysis_ef14c7222eb9f538:py_class_d21aa11be3ea, analysis_ef14c7222eb9f538:py_class_82a449d307f2, analysis_ef14c7222eb9f538:py_class_50ac9c96bf68, analysis_ef14c7222eb9f538:py_class_c8521a5abce5 |
| c39 datasette/utils/__init__.py defines CustomJSONEncoder and sqlite_timelimit, and datasette/views/table.py defines TableContext and Row. | observed | supported | analysis_ef14c7222eb9f538:py_class_faf43d86d5e4, analysis_ef14c7222eb9f538:py_func_43f232c11a74, analysis_ef14c7222eb9f538:py_class_6bca6cbe2675, analysis_ef14c7222eb9f538:py_class_e322d4ac69f5 |
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 · All repository guides