2025-10-30 10:41:41 -07:00
|
|
|
[project]
|
|
|
|
|
name = "datasette"
|
|
|
|
|
dynamic = ["version"]
|
|
|
|
|
description = "An open source multi-tool for exploring and publishing data"
|
|
|
|
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
|
|
|
authors = [
|
|
|
|
|
{ name = "Simon Willison" },
|
|
|
|
|
]
|
|
|
|
|
license = "Apache-2.0"
|
|
|
|
|
requires-python = ">=3.10"
|
|
|
|
|
classifiers = [
|
|
|
|
|
"Development Status :: 4 - Beta",
|
|
|
|
|
"Framework :: Datasette",
|
|
|
|
|
"Intended Audience :: Developers",
|
|
|
|
|
"Intended Audience :: Science/Research",
|
|
|
|
|
"Intended Audience :: End Users/Desktop",
|
|
|
|
|
"Topic :: Database",
|
|
|
|
|
"Programming Language :: Python :: 3.10",
|
|
|
|
|
"Programming Language :: Python :: 3.11",
|
|
|
|
|
"Programming Language :: Python :: 3.12",
|
|
|
|
|
"Programming Language :: Python :: 3.13",
|
|
|
|
|
"Programming Language :: Python :: 3.14",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
|
|
|
|
"asgiref>=3.2.10",
|
|
|
|
|
"click>=7.1.1",
|
|
|
|
|
"click-default-group>=1.2.3",
|
|
|
|
|
"Jinja2>=2.10.3",
|
|
|
|
|
"hupper>=1.9",
|
2026-09-10 19:44:49 -07:00
|
|
|
"httpx2>=2.0",
|
2025-10-30 10:41:41 -07:00
|
|
|
"pluggy>=1.0",
|
2026-09-01 09:32:37 -07:00
|
|
|
"uvicorn>=0.29",
|
2025-10-30 10:41:41 -07:00
|
|
|
"aiofiles>=0.4",
|
|
|
|
|
"PyYAML>=5.3",
|
|
|
|
|
"mergedeep>=1.1.1",
|
|
|
|
|
"itsdangerous>=1.1",
|
2026-07-07 13:51:29 -07:00
|
|
|
"sqlite-utils>=4.0",
|
2026-06-11 06:42:08 -07:00
|
|
|
"asyncinject>=0.7",
|
2025-10-30 10:41:41 -07:00
|
|
|
"setuptools",
|
|
|
|
|
"pip",
|
2026-06-17 09:14:19 -07:00
|
|
|
"pydantic>=2",
|
Add opentelemetry-api dependency and datasette/telemetry.py scaffolding
Datasette core is gaining OpenTelemetry spans alongside the existing
hand-rolled tracer. This commit only lays the groundwork - no span is
emitted yet.
Core takes a runtime dependency on opentelemetry-api and nothing more.
It deliberately never creates a TracerProvider, configures an exporter,
or touches sampling: that belongs to whoever runs Datasette, normally
via an opentelemetry-instrument agent. Owning a provider in core was
tried in an earlier design and produced a cross-request span leak, a
process-global provider that tests could not tear down, and a sampling
env var that silently blanked output. With no provider installed every
span is a NonRecordingSpan and costs approximately nothing.
datasette/telemetry.py exposes the module-level tracer plus
sql_attribute(), which truncates SQL to 2048 characters. On a public
instance the SQL is attacker-controlled and unbounded - someone can
paste a 10MB query into ?sql= - so it must never reach a telemetry
pipeline verbatim.
opentelemetry-sdk goes in the dev dependency group only, because the
test suite needs it to assert on spans while the package itself must
not import it. tests/test_telemetry.py enforces that by importing
datasette in a fresh interpreter and inspecting sys.modules, which
catches a lazy import inside a function body that a grep would miss.
conftest.py gains a session-scoped autouse fixture installing an SDK
provider with an InMemorySpanExporter. It has to be session-scoped
because set_tracer_provider() is effectively once-per-process - a
second call logs a warning and is ignored. SimpleSpanProcessor rather
than BatchSpanProcessor, so assertions made right after a request never
race a background export thread. The otel_spans fixture that later
tickets assert against is added here too.
test_datasette_package_never_imports_the_sdk is moved to the front of
the run. Late in a serial run the pytest process holds enough threads
that the fork half of subprocess' fork+exec segfaults the interpreter
on macOS/CPython 3.13. That reproduces with any subprocess call in that
position on an unmodified tree, so it is a pre-existing hazard rather
than something this commit introduces; the repo already moves its other
subprocess-spawning tests to the front for related reasons.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 17:30:52 -07:00
|
|
|
"opentelemetry-api>=1.37",
|
2025-10-30 10:41:41 -07:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
[project.urls]
|
|
|
|
|
Homepage = "https://datasette.io/"
|
|
|
|
|
Documentation = "https://docs.datasette.io/en/stable/"
|
|
|
|
|
Changelog = "https://docs.datasette.io/en/stable/changelog.html"
|
|
|
|
|
"Live demo" = "https://latest.datasette.io/"
|
|
|
|
|
"Source code" = "https://github.com/simonw/datasette"
|
|
|
|
|
Issues = "https://github.com/simonw/datasette/issues"
|
|
|
|
|
CI = "https://github.com/simonw/datasette/actions?query=workflow%3ATest"
|
|
|
|
|
|
|
|
|
|
[project.scripts]
|
|
|
|
|
datasette = "datasette.cli:cli"
|
|
|
|
|
|
2026-04-16 20:15:50 -07:00
|
|
|
[project.entry-points.pytest11]
|
|
|
|
|
datasette = "datasette._pytest_plugin"
|
|
|
|
|
|
2025-12-11 17:32:58 -08:00
|
|
|
[dependency-groups]
|
|
|
|
|
dev = [
|
2025-12-04 21:36:39 -08:00
|
|
|
"pytest>=9",
|
2025-10-30 10:41:41 -07:00
|
|
|
"pytest-xdist>=2.2.1",
|
|
|
|
|
"pytest-asyncio>=1.2.0",
|
|
|
|
|
"beautifulsoup4>=4.8.1",
|
2026-05-20 12:18:01 -07:00
|
|
|
"black==26.3.1",
|
2025-10-30 10:41:41 -07:00
|
|
|
"blacken-docs==1.20.0",
|
|
|
|
|
"pytest-timeout>=1.4.2",
|
|
|
|
|
"trustme>=0.7",
|
|
|
|
|
"cogapp>=3.3.0",
|
Add request.form() for multipart form data and file uploads
* Add request.form() for multipart form data and file uploads
New Request.form() method that handles both application/x-www-form-urlencoded
and multipart/form-data content types with streaming parsing.
Features:
- Streaming multipart parser that doesn't buffer entire body in memory
- Files spill to disk above 1MB threshold via SpooledTemporaryFile
- files=False (default) discards file content, files=True stores them
- Security limits: max_request_size, max_file_size, max_fields, max_files
- FormData container with dict-like access and getlist() for multiple values
- UploadedFile class with async read(), seek(), filename, content_type, size
- Support for RFC 5987 filename* encoding for international filenames
Uses multipart-form-data-conformance test suite for validation.
* Update views to use request.form() and document new API
- Migrate PermissionsDebugView, MessagesDebugView, and CreateTokenView
from post_vars() to form()
- Add documentation for request.form(), FormData, and UploadedFile classes
Centralize multipart defaults and expose stricter limits via Request.form().
Enforce header, part, file, and disk space limits even when files are discarded; detect truncated bodies and client disconnects; and move blocking work off the event loop.
Add FormData close/aclose context managers, update internals docs, and expand multipart tests (including len semantics and stricter conformance expectations).
2026-01-28 18:41:03 -08:00
|
|
|
"multipart-form-data-conformance==0.1a0",
|
2026-07-25 15:47:08 -07:00
|
|
|
"ruff>=0.16.0",
|
Add opentelemetry-api dependency and datasette/telemetry.py scaffolding
Datasette core is gaining OpenTelemetry spans alongside the existing
hand-rolled tracer. This commit only lays the groundwork - no span is
emitted yet.
Core takes a runtime dependency on opentelemetry-api and nothing more.
It deliberately never creates a TracerProvider, configures an exporter,
or touches sampling: that belongs to whoever runs Datasette, normally
via an opentelemetry-instrument agent. Owning a provider in core was
tried in an earlier design and produced a cross-request span leak, a
process-global provider that tests could not tear down, and a sampling
env var that silently blanked output. With no provider installed every
span is a NonRecordingSpan and costs approximately nothing.
datasette/telemetry.py exposes the module-level tracer plus
sql_attribute(), which truncates SQL to 2048 characters. On a public
instance the SQL is attacker-controlled and unbounded - someone can
paste a 10MB query into ?sql= - so it must never reach a telemetry
pipeline verbatim.
opentelemetry-sdk goes in the dev dependency group only, because the
test suite needs it to assert on spans while the package itself must
not import it. tests/test_telemetry.py enforces that by importing
datasette in a fresh interpreter and inspecting sys.modules, which
catches a lazy import inside a function body that a grep would miss.
conftest.py gains a session-scoped autouse fixture installing an SDK
provider with an InMemorySpanExporter. It has to be session-scoped
because set_tracer_provider() is effectively once-per-process - a
second call logs a warning and is ignored. SimpleSpanProcessor rather
than BatchSpanProcessor, so assertions made right after a request never
race a background export thread. The otel_spans fixture that later
tickets assert against is added here too.
test_datasette_package_never_imports_the_sdk is moved to the front of
the run. Late in a serial run the pytest process holds enough threads
that the fork half of subprocess' fork+exec segfaults the interpreter
on macOS/CPython 3.13. That reproduces with any subprocess call in that
position on an unmodified tree, so it is a pre-existing hazard rather
than something this commit introduces; the repo already moves its other
subprocess-spawning tests to the front for related reasons.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 17:30:52 -07:00
|
|
|
"opentelemetry-sdk>=1.37",
|
2025-12-11 17:32:58 -08:00
|
|
|
# docs
|
|
|
|
|
"Sphinx==7.4.7",
|
|
|
|
|
"furo==2025.9.25",
|
|
|
|
|
"sphinx-autobuild",
|
|
|
|
|
"codespell>=2.2.5",
|
|
|
|
|
"sphinx-copybutton",
|
|
|
|
|
"sphinx-inline-tabs",
|
|
|
|
|
"myst-parser",
|
|
|
|
|
"sphinx-markdown-builder",
|
|
|
|
|
"ruamel.yaml",
|
2026-04-16 20:18:05 -07:00
|
|
|
"psutil>=5.9",
|
2025-10-30 10:41:41 -07:00
|
|
|
]
|
2026-06-14 16:39:55 -07:00
|
|
|
playwright = [
|
|
|
|
|
"pytest-playwright>=0.8.0",
|
|
|
|
|
]
|
2025-12-11 17:32:58 -08:00
|
|
|
|
|
|
|
|
[project.optional-dependencies]
|
2025-10-30 10:41:41 -07:00
|
|
|
rich = ["rich"]
|
|
|
|
|
|
|
|
|
|
[build-system]
|
|
|
|
|
requires = ["setuptools"]
|
|
|
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
|
|
|
|
|
|
[tool.setuptools.packages.find]
|
|
|
|
|
include = ["datasette*"]
|
|
|
|
|
|
|
|
|
|
[tool.setuptools.package-data]
|
|
|
|
|
datasette = ["templates/*.html"]
|
|
|
|
|
|
|
|
|
|
[tool.setuptools.dynamic]
|
|
|
|
|
version = {attr = "datasette.version.__version__"}
|
2025-12-02 19:19:48 -08:00
|
|
|
|
|
|
|
|
[tool.uv]
|
|
|
|
|
package = true
|