Skip to content

Commit

Permalink
Database/Table views inherit source/license/source_url/license_url me…
Browse files Browse the repository at this point in the history
…tadata

If you set the source_url/license_url/source/license fields in your root
metadata those values will now be inherited all the way down to the database
and table templates.

The title/description are NOT inherited.

Also added unit tests for the HTML generated by the metadata.

Refs #185
  • Loading branch information
simonw committed Mar 27, 2018
1 parent 012fc7c commit 89d9fbb
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 6 deletions.
22 changes: 16 additions & 6 deletions datasette/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ async def data(self, request, name, hash):
return await self.custom_sql(request, name, hash, sql)
info = self.ds.inspect()[name]
metadata = self.ds.metadata.get('databases', {}).get(name, {})
self.ds.update_with_inherited_metadata(metadata)
tables = list(info['tables'].values())
tables.sort(key=lambda t: (t['hidden'], t['name']))
return {
Expand All @@ -399,9 +400,7 @@ async def data(self, request, name, hash):
'database_hash': hash,
'show_hidden': request.args.get('_show_hidden'),
'editable': True,
'metadata': self.ds.metadata.get(
'databases', {}
).get(name, {}),
'metadata': metadata,
}, ('database-{}.html'.format(to_css_class(name)), 'database.html')


Expand Down Expand Up @@ -691,6 +690,10 @@ async def extra_template():
display_columns, display_rows = await self.display_columns_and_rows(
name, table, description, rows, link_column=not is_view, expand_foreign_keys=True
)
metadata = self.ds.metadata.get(
'databases', {}
).get(name, {}).get('tables', {}).get(table, {})
self.ds.update_with_inherited_metadata(metadata)
return {
'database_hash': hash,
'human_filter_description': human_description,
Expand All @@ -706,9 +709,7 @@ async def extra_template():
'_rows_and_columns-table-{}-{}.html'.format(to_css_class(name), to_css_class(table)),
'_rows_and_columns.html',
],
'metadata': self.ds.metadata.get(
'databases', {}
).get(name, {}).get('tables', {}).get(table, {}),
'metadata': metadata,
}

return {
Expand Down Expand Up @@ -892,6 +893,15 @@ def extra_css_urls(self):
def extra_js_urls(self):
return self.asset_urls('extra_js_urls')

def update_with_inherited_metadata(self, metadata):
# Fills in source/license with defaults, if available
metadata.update({
'source': metadata.get('source') or self.metadata.get('source'),
'source_url': metadata.get('source_url') or self.metadata.get('source_url'),
'license': metadata.get('license') or self.metadata.get('license'),
'license_url': metadata.get('license_url') or self.metadata.get('license_url'),
})

def prepare_connection(self, conn):
conn.row_factory = sqlite3.Row
conn.text_factory = lambda x: str(x, 'utf-8', 'replace')
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Contents
:maxdepth: 2

getting_started
json_api
sql_queries
metadata
custom_templates
Expand Down
22 changes: 22 additions & 0 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,35 @@ def app_client():
page_size=50,
max_returned_rows=100,
sql_time_limit_ms=20,
metadata=METADATA,
)
ds.sqlite_functions.append(
('sleep', 1, lambda n: time.sleep(float(n))),
)
yield ds.app().test_client


METADATA = {
'title': 'Datasette Title',
'description': 'Datasette Description',
'license': 'License',
'license_url': 'http://www.example.com/license',
'source': 'Source',
'source_url': 'http://www.example.com/source',
'databases': {
'test_tables': {
'description': 'Test tables description',
'tables': {
'simple_primary_key': {
'description_html': 'Simple <em>primary</em> key',
'title': 'This <em>HTML</em> is escaped',
}
}
}
}
}


TABLES = '''
CREATE TABLE simple_primary_key (
pk varchar(30) primary key,
Expand Down
55 changes: 55 additions & 0 deletions tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,58 @@ def test_view_html(app_client):
]
]
assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')]


def test_index_metadata(app_client):
response = app_client.get('/', gather_request=False)
soup = Soup(response.body, 'html.parser')
assert 'Datasette Title' == soup.find('h1').text
assert 'Datasette Description' == inner_html(
soup.find('div', {'class': 'metadata-description'})
)
assert_footer_links(soup)


def test_database_metadata(app_client):
response = app_client.get('/test_tables', gather_request=False)
soup = Soup(response.body, 'html.parser')
# Page title should be the default
assert 'test_tables' == soup.find('h1').text
# Description should be custom
assert 'Test tables description' == inner_html(
soup.find('div', {'class': 'metadata-description'})
)
# The source/license should be inherited
assert_footer_links(soup)


def test_table_metadata(app_client):
response = app_client.get('/test_tables/simple_primary_key', gather_request=False)
soup = Soup(response.body, 'html.parser')
# Page title should be custom and should be HTML escaped
assert 'This &lt;em&gt;HTML&lt;/em&gt; is escaped' == inner_html(soup.find('h1'))
# Description should be custom and NOT escaped (we used description_html)
assert 'Simple <em>primary</em> key' == inner_html(soup.find(
'div', {'class': 'metadata-description'})
)
# The source/license should be inherited
assert_footer_links(soup)


def assert_footer_links(soup):
footer_links = soup.find('div', {'class': 'ft'}).findAll('a')
assert 3 == len(footer_links)
datasette_link, license_link, source_link = footer_links
assert 'Datasette' == datasette_link.text.strip()
assert 'Source' == source_link.text.strip()
assert 'License' == license_link.text.strip()
assert 'https://github.com/simonw/datasette' == datasette_link['href']
assert 'http://www.example.com/source' == source_link['href']
assert 'http://www.example.com/license' == license_link['href']


def inner_html(soup):
html = str(soup)
# This includes the parent tag - so remove that
inner_html = html.split('>', 1)[1].rsplit('<', 1)[0]
return inner_html.strip()

0 comments on commit 89d9fbb

Please sign in to comment.