diff --git a/datasette/utils/__init__.py b/datasette/utils/__init__.py index 38a16b79..34b3ac02 100644 --- a/datasette/utils/__init__.py +++ b/datasette/utils/__init__.py @@ -165,7 +165,31 @@ def compound_keys_after_sql(pks, start_index=0): return "({})".format("\n or\n".join(or_clauses)) +@documented class CustomJSONEncoder(json.JSONEncoder): + """ + The CustomJSONEncoder class handles serialization for objects commonly used by Datasette, + including SQLite cursors and binary blobs. Datasette uses it internally to serve .json endpoints, + and plugins that return JSON can use it to match Datasette's own handling. + + Built-in types (text, numbers, lists, etc) are encoded the same as Python's built-in ``json`` module. + + - ``sqlite3.Row`` becomes a tuple + - ``sqlite3.Cursor`` becomes a list + + If a binary blob can be decoded as UTF-8, the encoder returns it as text. + + If it can't (for example, images), it is encoded as an object, with the actual + data base64-encoded, like so: :: + + { + "$base64": True, + "encoded": ..., + } + + Example: https://latest.datasette.io/fixtures/binary_data.json + """ + def default(self, obj): if isinstance(obj, sqlite3.Row): return tuple(obj) diff --git a/docs/Makefile b/docs/Makefile index 2b092179..a0d17c81 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -20,4 +20,4 @@ help: @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) livehtml: - sphinx-autobuild -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(0) + sphinx-autobuild -b html --watch ../datasette "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(0) diff --git a/docs/internals.rst b/docs/internals.rst index 8575ac14..70728e5f 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1567,6 +1567,13 @@ Note that the space character is a special case: it will be replaced with a ``+` .. _internals_tracer: +JSON encoding +------------- + +.. _internals_utils_CustomJSONEncoder: + +.. autoclass:: datasette.utils.CustomJSONEncoder + datasette.tracer ================