Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

?_extra= support (draft) #1999

Merged
merged 47 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
853edc8
Initial ?_extra= prototype, refs #262
simonw Jan 21, 2023
58c1a39
Start building new table_view function
simonw Jan 28, 2023
de9eec1
Copied across more code for the new table view
simonw Feb 5, 2023
ab17c4e
Nest the debug information
simonw Feb 6, 2023
999c1bc
Got _extra working against new table_view
simonw Feb 8, 2023
732285c
?_extra=request and ?_extra=extras, refs #262
simonw Feb 8, 2023
21568f9
Improved ?_extra=extras to show selected and available, refs #262
simonw Feb 8, 2023
f392946
Removed accidental import
simonw Feb 14, 2023
db1a88f
_next support for new tables, refs #1999
simonw Mar 8, 2023
a5fff75
Remove code resetting the offset, refs #1999
simonw Mar 8, 2023
96e94f9
?_extra=query, refs #1999
simonw Mar 8, 2023
da36707
extra_display_columns / extra_display_rows, refs #1999
simonw Mar 8, 2023
ca23b0c
Trying out a ?_extra=_html bundle mechanism, refs #1999
simonw Mar 8, 2023
11f7feb
Hacked together just enough for basic HTML table view to work, refs #…
simonw Mar 9, 2023
6d07a7d
HTML table page now loads even in strict variable mode, refs #1999
simonw Mar 10, 2023
b6b14b3
Applied latest Black
simonw Mar 12, 2023
dbe73ef
All tests it test_api.py now pass
simonw Mar 18, 2023
066ed9c
A whole bunch more test_table_api tests pass
simonw Mar 18, 2023
faf4ae3
Fixed more test_table_api tests
simonw Mar 18, 2023
2f38479
More tests pass, fixed infinities removal against dicts
simonw Mar 18, 2023
a78fcc9
Fixed headers['link']
simonw Mar 19, 2023
4280976
All test_table_api.py tests now pass
simonw Mar 19, 2023
775bb8f
asyncinject dependency
simonw Mar 19, 2023
1edeaf3
More HTML table tests pass
simonw Mar 20, 2023
0a90e39
Just 11 HTML failures now
simonw Mar 20, 2023
6fabeb0
Only 3 failing HTML table tests left
simonw Mar 20, 2023
32fd20b
All tests in test_table_html now pass
simonw Mar 20, 2023
395bd6b
Fixed test_routes tests
simonw Mar 20, 2023
4bb4984
Fix bug with facet_array= not returning facets
simonw Mar 20, 2023
397759a
Tests in test_facets all pass
simonw Mar 21, 2023
538ca9d
Deleted some code, tried to get alternative formats working
simonw Mar 21, 2023
1ccf132
Fixed the canned query tests
simonw Mar 21, 2023
73291ab
Fixed test_table_api again
simonw Mar 22, 2023
43aa060
Tests in test_html all pass
simonw Mar 22, 2023
b331c7a
Removed rogue print
simonw Mar 22, 2023
0728c2e
Fixed link text
simonw Jan 21, 2023
226dde0
render_cell(..., request) argument, closes #2007
simonw Jan 28, 2023
8297032
Add Python 3.11 classifier (#2028)
dtrodrigues Mar 6, 2023
84b726c
datasette install -r requirements.txt, closes #2033
simonw Mar 6, 2023
1d1d126
Use service-specific image ID for Cloud Run deploys, refs #2036
simonw Mar 8, 2023
f4c13bc
use tmpdir instead of isolated_filesystem, refs #2037
simonw Mar 8, 2023
ad1ba5c
0.64 release notes, refs #2036
simonw Mar 8, 2023
9b60357
Include columns in default HTML context
simonw Mar 22, 2023
e772eb6
Just need to fix CSV tests now
simonw Mar 22, 2023
921faae
Got CSV working again
simonw Mar 22, 2023
1071292
Remove obsolete TableView class
simonw Mar 22, 2023
69a31cd
Merge branch 'main' into extras
simonw Mar 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions datasette/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
from pydoc import plain
from typing import Sequence, Union, Tuple, Optional, Dict, Iterable
import asgi_csrf
import collections
Expand All @@ -24,7 +23,12 @@

from markupsafe import Markup, escape
from itsdangerous import URLSafeSerializer
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader
from jinja2 import (
ChoiceLoader,
Environment,
FileSystemLoader,
PrefixLoader,
)
from jinja2.environment import Template
from jinja2.exceptions import TemplateNotFound

Expand All @@ -42,7 +46,12 @@
PermissionsDebugView,
MessagesDebugView,
)
from .views.table import TableView, TableInsertView, TableUpsertView, TableDropView
from .views.table import (
TableInsertView,
TableUpsertView,
TableDropView,
table_view,
)
from .views.row import RowView, RowDeleteView, RowUpdateView
from .renderer import json_renderer
from .url_builder import Urls
Expand Down Expand Up @@ -389,7 +398,10 @@ def __init__(
]
)
self.jinja_env = Environment(
loader=template_loader, autoescape=True, enable_async=True
loader=template_loader,
autoescape=True,
enable_async=True,
# undefined=StrictUndefined,
)
self.jinja_env.filters["escape_css_string"] = escape_css_string
self.jinja_env.filters["quote_plus"] = urllib.parse.quote_plus
Expand Down Expand Up @@ -1358,7 +1370,7 @@ def add_route(view, regex):
)
add_route(TableCreateView.as_view(self), r"/(?P<database>[^\/\.]+)/-/create$")
add_route(
TableView.as_view(self),
wrap_view(table_view, self),
r"/(?P<database>[^\/\.]+)/(?P<table>[^\/\.]+)(\.(?P<format>\w+))?$",
)
add_route(
Expand Down
1 change: 1 addition & 0 deletions datasette/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def sqlite_extensions(fn):
multiple=True,
help="Path to a SQLite extension to load, and optional entrypoint",
)(fn)

# Wrap it in a custom error handler
@functools.wraps(fn)
def wrapped(*args, **kwargs):
Expand Down
20 changes: 14 additions & 6 deletions datasette/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
remove_infinites,
CustomJSONEncoder,
path_from_row_pks,
sqlite3,
)
from datasette.utils.asgi import Response

Expand Down Expand Up @@ -49,10 +50,14 @@ def json_renderer(args, data, view_name):
if data.get("error"):
shape = "objects"

next_url = data.get("next_url")

if shape == "arrayfirst":
data = [row[0] for row in data["rows"]]
if not data["rows"]:
data = []
elif isinstance(data["rows"][0], sqlite3.Row):
data = [row[0] for row in data["rows"]]
else:
assert isinstance(data["rows"][0], dict)
data = [next(iter(row.values())) for row in data["rows"]]
elif shape in ("objects", "object", "array"):
columns = data.get("columns")
rows = data.get("rows")
Expand Down Expand Up @@ -80,7 +85,12 @@ def json_renderer(args, data, view_name):
data = data["rows"]

elif shape == "arrays":
pass
if not data["rows"]:
pass
elif isinstance(data["rows"][0], sqlite3.Row):
data["rows"] = [list(row) for row in data["rows"]]
else:
data["rows"] = [list(row.values()) for row in data["rows"]]
else:
status_code = 400
data = {
Expand All @@ -98,8 +108,6 @@ def json_renderer(args, data, view_name):
body = json.dumps(data, cls=CustomJSONEncoder)
content_type = "application/json; charset=utf-8"
headers = {}
if next_url:
headers["link"] = f'<{next_url}>; rel="next"'
return Response(
body, status=status_code, headers=headers, content_type=content_type
)
4 changes: 2 additions & 2 deletions datasette/templates/_description_source_license.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% if metadata.description_html or metadata.description %}
{% if metadata.get("description_html") or metadata.get("description") %}
<div class="metadata-description">
{% if metadata.description_html %}
{% if metadata.get("description_html") %}
{{ metadata.description_html|safe }}
{% else %}
{{ metadata.description }}
Expand Down
2 changes: 1 addition & 1 deletion datasette/templates/_suggested_facets.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<p class="suggested-facets">
Suggested facets: {% for facet in suggested_facets %}<a href="{{ facet.toggle_url }}#facet-{{ facet.name|to_css_class }}">{{ facet.name }}</a>{% if facet.type %} ({{ facet.type }}){% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
Suggested facets: {% for facet in suggested_facets %}<a href="{{ facet.toggle_url }}#facet-{{ facet.name|to_css_class }}">{{ facet.name }}</a>{% if facet.get("type") %} ({{ facet.type }}){% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
</p>
4 changes: 2 additions & 2 deletions datasette/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
<link rel="stylesheet" href="{{ urls.static('app.css') }}?{{ app_css_hash }}">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% for url in extra_css_urls %}
<link rel="stylesheet" href="{{ url.url }}"{% if url.sri %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}>
<link rel="stylesheet" href="{{ url.url }}"{% if url.get("sri") %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}>
{% endfor %}
{% for url in extra_js_urls %}
<script {% if url.module %}type="module" {% endif %}src="{{ url.url }}"{% if url.sri %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}></script>
<script {% if url.module %}type="module" {% endif %}src="{{ url.url }}"{% if url.get("sri") %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}></script>
{% endfor %}
{%- if alternate_url_json -%}
<link rel="alternate" type="application/json+datasette" href="{{ alternate_url_json }}">
Expand Down
6 changes: 3 additions & 3 deletions datasette/templates/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

{% block content %}
<div class="page-header" style="border-color: #{{ database_color(database) }}">
<h1>{{ metadata.title or table }}{% if is_view %} (view){% endif %}{% if private %} 🔒{% endif %}</h1>
<h1>{{ metadata.get("title") or table }}{% if is_view %} (view){% endif %}{% if private %} 🔒{% endif %}</h1>
{% set links = table_actions() %}{% if links %}
<details class="actions-menu-links details-menu">
<summary><svg aria-labelledby="actions-menu-links-title" role="img"
Expand All @@ -47,7 +47,7 @@ <h1>{{ metadata.title or table }}{% if is_view %} (view){% endif %}{% if private

{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}

{% if metadata.columns %}
{% if metadata.get("columns") %}
<dl class="column-descriptions">
{% for column_name, column_description in metadata.columns.items() %}
<dt>{{ column_name }}</dt><dd>{{ column_description }}</dd>
Expand Down Expand Up @@ -94,7 +94,7 @@ <h3>{% if count or count == 0 %}{{ "{:,}".format(count) }} row{% if count == 1 %
</div><div class="select-wrapper filter-op">
<select name="_filter_op">
{% for key, display, no_argument in filters.lookups() %}
<option value="{{ key }}{% if no_argument %}__1{% endif %}"{% if key == lookup %} selected{% endif %}>{{ display }}</option>
<option value="{{ key }}{% if no_argument %}__1{% endif %}">{{ display }}</option>
{% endfor %}
</select>
</div><input type="text" name="_filter_value" class="filter-value">
Expand Down
13 changes: 11 additions & 2 deletions datasette/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,9 +828,18 @@ async def write(self, content):


def remove_infinites(row):
if any((c in _infinities) if isinstance(c, float) else 0 for c in row):
to_check = row
if isinstance(row, dict):
to_check = row.values()
if not any((c in _infinities) if isinstance(c, float) else 0 for c in to_check):
return row
if isinstance(row, dict):
return {
k: (None if (isinstance(v, float) and v in _infinities) else v)
for k, v in row.items()
}
else:
return [None if (isinstance(c, float) and c in _infinities) else c for c in row]
return row


class StaticMount(click.ParamType):
Expand Down
Loading