--load-extension=spatialite shortcut, closes #1028

This commit is contained in:
Simon Willison 2020-10-19 15:37:31 -07:00
commit 6aa5886379
6 changed files with 54 additions and 6 deletions

View file

@ -49,12 +49,14 @@ from .utils import (
display_actor,
escape_css_string,
escape_sqlite,
find_spatialite,
format_bytes,
module_from_path,
parse_metadata,
resolve_env_secrets,
sqlite3,
to_css_class,
SpatialiteNotFound,
)
from .utils.asgi import (
AsgiLifespan,
@ -242,7 +244,14 @@ class Datasette:
metadata = parse_metadata(fp.read())
self._metadata = metadata or {}
self.sqlite_functions = []
self.sqlite_extensions = sqlite_extensions or []
self.sqlite_extensions = []
for extension in sqlite_extensions or []:
# Resolve spatialite, if requested
if extension == "spatialite":
# Could raise SpatialiteNotFound
self.sqlite_extensions.append(find_spatialite())
else:
self.sqlite_extensions.append(extension)
if config_dir and (config_dir / "templates").is_dir() and not template_dir:
template_dir = str((config_dir / "templates").resolve())
self.template_dir = template_dir

View file

@ -19,6 +19,7 @@ from .utils import (
SpatialiteConnectionProblem,
temporary_docker_directory,
value_as_boolean,
SpatialiteNotFound,
StaticMount,
ValueAsBooleanError,
)
@ -78,7 +79,6 @@ def cli():
"--load-extension",
envvar="SQLITE_EXTENSIONS",
multiple=True,
type=click.Path(exists=True, resolve_path=True),
help="Path to a SQLite extension to load",
)
def inspect(files, inspect_file, sqlite_extensions):
@ -299,7 +299,6 @@ def uninstall(packages, yes):
"--load-extension",
envvar="SQLITE_EXTENSIONS",
multiple=True,
type=click.Path(exists=True, resolve_path=True),
help="Path to a SQLite extension to load",
)
@click.option(
@ -433,7 +432,10 @@ def serve(
kwargs["config_dir"] = pathlib.Path(files[0])
files = []
ds = Datasette(files, **kwargs)
try:
ds = Datasette(files, **kwargs)
except SpatialiteNotFound:
raise click.ClickException("Could not find SpatiaLite extension")
if return_instance:
# Private utility mechanism for writing unit tests

View file

@ -54,6 +54,12 @@ RUN apt-get update && \
ENV SQLITE_EXTENSIONS /usr/lib/x86_64-linux-gnu/mod_spatialite.so
"""
# Can replace with sqlite-utils when I add that dependency
SPATIALITE_PATHS = (
"/usr/lib/x86_64-linux-gnu/mod_spatialite.so",
"/usr/local/lib/mod_spatialite.dylib",
)
# Can replace this with Column from sqlite_utils when I add that dependency
Column = namedtuple(
"Column", ("cid", "name", "type", "notnull", "default_value", "is_pk")
@ -971,3 +977,15 @@ def display_actor(actor):
if actor.get(key):
return actor[key]
return str(actor)
class SpatialiteNotFound(Exception):
pass
# Can replace with sqlite-utils when I add that dependency
def find_spatialite():
for path in SPATIALITE_PATHS:
if os.path.exists(path):
return path
raise SpatialiteNotFound

View file

@ -170,7 +170,7 @@ module, use the following command::
docker run -p 8001:8001 -v `pwd`:/mnt \
datasetteproject/datasette \
datasette -p 8001 -h 0.0.0.0 /mnt/fixtures.db \
--load-extension=/usr/local/lib/mod_spatialite.so
--load-extension=spatialite
You can confirm that SpatiaLite is successfully loaded by visiting
http://127.0.0.1:8001/-/versions

View file

@ -8,6 +8,14 @@ The `SpatiaLite module <https://www.gaia-gis.it/fossil/libspatialite/index>`_ fo
To use it with Datasette, you need to install the ``mod_spatialite`` dynamic library. This can then be loaded into Datasette using the ``--load-extension`` command-line option.
Datasette can look for SpatiaLite in common installation locations if you run it like this::
datasette --load-extension=spatialite
If SpatiaLite is in another location, use the full path to the extension instead::
datasette --load-extension=/usr/local/lib/mod_spatialite.dylib
Installation
============
@ -25,7 +33,7 @@ This will install the ``spatialite`` command-line tool and the ``mod_spatialite`
You can now run Datasette like so::
datasette --load-extension=/usr/local/lib/mod_spatialite.dylib
datasette --load-extension=spatialite
Installing SpatiaLite on Linux
------------------------------

View file

@ -59,6 +59,17 @@ def test_spatialite_error_if_attempt_to_open_spatialite():
assert "trying to load a SpatiaLite database" in result.output
@mock.patch("datasette.utils.SPATIALITE_PATHS", ["/does/not/exist"])
def test_spatialite_error_if_cannot_find_load_extension_spatialite():
runner = CliRunner()
result = runner.invoke(
cli, ["serve", str(pathlib.Path(__file__).parent / "spatialite.db"),
"--load-extension", "spatialite"]
)
assert result.exit_code != 0
assert "Could not find SpatiaLite extension" in result.output
def test_plugins_cli(app_client):
runner = CliRunner()
result1 = runner.invoke(cli, ["plugins"])