diff --git a/datasette/app.py b/datasette/app.py index 75be58bc..2dd92841 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -16,6 +16,7 @@ import itertools import json import jinja2 import hashlib +import sys import time import pint import pluggy @@ -42,6 +43,7 @@ from .utils import ( urlsafe_components, validate_sql_select, ) +from . import __version__ from . import hookspecs from .version import __version__ @@ -1341,6 +1343,39 @@ class Datasette: for unit in self.metadata.get('custom_units', []): ureg.define(unit) + def versions(self): + conn = sqlite3.connect(':memory:') + self.prepare_connection(conn) + sqlite_version = conn.execute( + 'select sqlite_version()' + ).fetchone()[0] + sqlite_extensions = {} + for extension, testsql, hasversion in ( + ('json1', "SELECT json('{}')", False), + ('spatialite', "SELECT spatialite_version()", True), + ): + try: + result = conn.execute(testsql) + if hasversion: + sqlite_extensions[extension] = result.fetchone()[0] + else: + sqlite_extensions[extension] = None + except Exception as e: + pass + return { + 'python': { + 'version': '.'.join(map(str, sys.version_info[:3])), + 'full': sys.version, + }, + 'datasette': { + 'version': __version__, + }, + 'sqlite': { + 'version': sqlite_version, + 'extensions': sqlite_extensions, + } + } + def app(self): app = Sanic(__name__) default_templates = str(app_root / 'datasette' / 'templates') @@ -1388,6 +1423,10 @@ class Datasette: JsonDataView.as_view(self, 'metadata.json', lambda: self.metadata), '/-/metadata' ) + app.add_route( + JsonDataView.as_view(self, 'versions.json', self.versions), + '/-/versions' + ) app.add_route( JsonDataView.as_view(self, 'plugins.json', lambda: [{ 'name': p['name'], diff --git a/tests/test_api.py b/tests/test_api.py index 81a95c36..98bb690c 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -765,6 +765,20 @@ def test_plugins_json(app_client): } in response.json +def test_versions_json(app_client): + response = app_client.get( + "/-/versions.json", + gather_request=False + ) + assert 'python' in response.json + assert 'version' in response.json['python'] + assert 'full' in response.json['python'] + assert 'datasette' in response.json + assert 'version' in response.json['datasette'] + assert 'sqlite' in response.json + assert 'version' in response.json['sqlite'] + + def test_page_size_matching_max_returned_rows(app_client_returend_rows_matches_page_size): fetched = [] path = '/test_tables/no_primary_key.json'