mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Add test for RST heading underline lengths, closes #2544
Added test_rst_heading_underlines_match_title_length() to verify that RST heading underlines match their title lengths. The test properly handles: - Overline+underline style headings (skips validation for those) - Empty lines before underlines (ignores them) - Minimum 5-character underline length (avoids false positives) Running this test identified 14 heading underline mismatches which have been fixed across 5 documentation files: - docs/authentication.rst (3 headings) - docs/plugin_hooks.rst (4 headings) - docs/internals.rst (5 headings) - docs/deploying.rst (1 heading) - docs/changelog.rst (1 heading) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
653c94209c
commit
4fe1765dc3
6 changed files with 69 additions and 14 deletions
|
|
@ -1093,7 +1093,7 @@ All three endpoints support both HTML and JSON responses. Visit the endpoint dir
|
|||
.. _PermissionRulesView:
|
||||
|
||||
Permission rules view
|
||||
======================
|
||||
=====================
|
||||
|
||||
The ``/-/rules`` endpoint displays all permission rules (both allow and deny) for each candidate resource for the requested action.
|
||||
|
||||
|
|
@ -1106,7 +1106,7 @@ Pass ``?action=`` as a query parameter to specify which action to check.
|
|||
.. _PermissionCheckView:
|
||||
|
||||
Permission check view
|
||||
======================
|
||||
=====================
|
||||
|
||||
The ``/-/check`` endpoint evaluates a single action/resource pair and returns information indicating whether the access was allowed along with diagnostic information.
|
||||
|
||||
|
|
@ -1212,7 +1212,7 @@ Default *allow*.
|
|||
.. _permissions_view_database_download:
|
||||
|
||||
view-database-download
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
Actor is allowed to download a database, e.g. https://latest.datasette.io/fixtures.db
|
||||
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ Documentation
|
|||
.. _v0_62:
|
||||
|
||||
0.62 (2022-08-14)
|
||||
-------------------
|
||||
-----------------
|
||||
|
||||
Datasette can now run entirely in your browser using WebAssembly. Try out `Datasette Lite <https://lite.datasette.io/>`__, take a look `at the code <https://github.com/simonw/datasette-lite>`__ or read more about it in `Datasette Lite: a server-side Python web application running in a browser <https://simonwillison.net/2022/May/4/datasette-lite/>`__.
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ Datasette will not be accessible from outside the server because it is listening
|
|||
.. _deploying_openrc:
|
||||
|
||||
Running Datasette using OpenRC
|
||||
===============================
|
||||
==============================
|
||||
OpenRC is the service manager on non-systemd Linux distributions like `Alpine Linux <https://www.alpinelinux.org/>`__ and `Gentoo <https://www.gentoo.org/>`__.
|
||||
|
||||
Create an init script at ``/etc/init.d/datasette`` with the following contents:
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ For legacy string/tuple based permission checking, use :ref:`datasette_permissio
|
|||
.. _datasette_ensure_permission:
|
||||
|
||||
await .ensure_permission(action, resource=None, actor=None)
|
||||
------------------------------------------------------------
|
||||
-----------------------------------------------------------
|
||||
|
||||
``action`` - string
|
||||
The action to check. See :ref:`permissions` for a list of available actions.
|
||||
|
|
@ -1047,7 +1047,7 @@ These methods each return a ``datasette.utils.PrefixedUrlString`` object, which
|
|||
.. _internals_permission_classes:
|
||||
|
||||
Permission classes and utilities
|
||||
=================================
|
||||
================================
|
||||
|
||||
.. _internals_permission_sql:
|
||||
|
||||
|
|
@ -1296,7 +1296,7 @@ Example usage:
|
|||
.. _database_execute_write:
|
||||
|
||||
await db.execute_write(sql, params=None, block=True)
|
||||
-----------------------------------------------------
|
||||
----------------------------------------------------
|
||||
|
||||
SQLite only allows one database connection to write at a time. Datasette handles this for you by maintaining a queue of writes to be executed against a given database. Plugins can submit write operations to this queue and they will be executed in the order in which they are received.
|
||||
|
||||
|
|
@ -1313,7 +1313,7 @@ Each call to ``execute_write()`` will be executed inside a transaction.
|
|||
.. _database_execute_write_script:
|
||||
|
||||
await db.execute_write_script(sql, block=True)
|
||||
-----------------------------------------------
|
||||
----------------------------------------------
|
||||
|
||||
Like ``execute_write()`` but can be used to send multiple SQL statements in a single string separated by semicolons, using the ``sqlite3`` `conn.executescript() <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executescript>`__ method.
|
||||
|
||||
|
|
@ -1322,7 +1322,7 @@ Each call to ``execute_write_script()`` will be executed inside a transaction.
|
|||
.. _database_execute_write_many:
|
||||
|
||||
await db.execute_write_many(sql, params_seq, block=True)
|
||||
---------------------------------------------------------
|
||||
--------------------------------------------------------
|
||||
|
||||
Like ``execute_write()`` but uses the ``sqlite3`` `conn.executemany() <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executemany>`__ method. This will efficiently execute the same SQL statement against each of the parameters in the ``params_seq`` iterator, for example:
|
||||
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ The plugin hook can then be used to register the new facet class like this:
|
|||
.. _plugin_register_permissions:
|
||||
|
||||
register_permissions(datasette)
|
||||
--------------------------------
|
||||
-------------------------------
|
||||
|
||||
.. note::
|
||||
This hook is deprecated. Use :ref:`plugin_register_actions` instead, which provides a more flexible resource-based permission system.
|
||||
|
|
@ -830,7 +830,7 @@ The fields of the ``Permission`` class are as follows:
|
|||
.. _plugin_register_actions:
|
||||
|
||||
register_actions(datasette)
|
||||
----------------------------
|
||||
---------------------------
|
||||
|
||||
If your plugin needs to register actions that can be checked with Datasette's new resource-based permission system, return a list of those actions from this hook.
|
||||
|
||||
|
|
@ -931,7 +931,7 @@ The fields of the ``Action`` dataclass are as follows:
|
|||
- Have an ``__init__`` method that accepts appropriate parameters and calls ``super().__init__(parent=..., child=...)``
|
||||
|
||||
The ``resources_sql()`` method
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``resources_sql()`` classmethod is crucial to Datasette's permission system. It returns a SQL query that lists all resources of that type that exist in the system.
|
||||
|
||||
|
|
@ -1445,7 +1445,7 @@ Example: `datasette-permissions-sql <https://datasette.io/plugins/datasette-perm
|
|||
.. _plugin_hook_permission_resources_sql:
|
||||
|
||||
permission_resources_sql(datasette, actor, action)
|
||||
---------------------------------------------------
|
||||
--------------------------------------------------
|
||||
|
||||
``datasette`` - :ref:`internals_datasette`
|
||||
Access to the Datasette instance.
|
||||
|
|
|
|||
|
|
@ -106,6 +106,61 @@ def test_functions_marked_with_documented_are_documented(documented_fns, fn):
|
|||
assert fn.__name__ in documented_fns
|
||||
|
||||
|
||||
def test_rst_heading_underlines_match_title_length():
|
||||
"""Test that RST heading underlines are the same length as their titles."""
|
||||
# Common RST underline characters
|
||||
underline_chars = ['-', '=', '~', '^', '+', '*', '#']
|
||||
|
||||
errors = []
|
||||
|
||||
for rst_file in docs_path.glob("*.rst"):
|
||||
content = rst_file.read_text()
|
||||
lines = content.split('\n')
|
||||
|
||||
for i in range(len(lines) - 1):
|
||||
current_line = lines[i]
|
||||
next_line = lines[i + 1]
|
||||
|
||||
# Check if next line is entirely made of a single underline character
|
||||
# and is at least 5 characters long (to avoid false positives)
|
||||
if (next_line and
|
||||
len(next_line) >= 5 and
|
||||
len(set(next_line)) == 1 and
|
||||
next_line[0] in underline_chars):
|
||||
# Skip if the previous line is empty (blank line before underline)
|
||||
if not current_line:
|
||||
continue
|
||||
|
||||
# Check if this is an overline+underline style heading
|
||||
# Look at the line before current_line to see if it's also an underline
|
||||
if i > 0:
|
||||
prev_line = lines[i - 1]
|
||||
if (prev_line and
|
||||
len(prev_line) >= 5 and
|
||||
len(set(prev_line)) == 1 and
|
||||
prev_line[0] in underline_chars and
|
||||
len(prev_line) == len(next_line)):
|
||||
# This is overline+underline style, skip it
|
||||
continue
|
||||
|
||||
# This is a heading underline
|
||||
title_length = len(current_line)
|
||||
underline_length = len(next_line)
|
||||
|
||||
if title_length != underline_length:
|
||||
errors.append(
|
||||
f"{rst_file.name}:{i+1}: Title length {title_length} != underline length {underline_length}\n"
|
||||
f" Title: {current_line!r}\n"
|
||||
f" Underline: {next_line!r}"
|
||||
)
|
||||
|
||||
if errors:
|
||||
raise AssertionError(
|
||||
f"Found {len(errors)} RST heading(s) with mismatched underline length:\n\n" +
|
||||
"\n\n".join(errors)
|
||||
)
|
||||
|
||||
|
||||
# Tests for testing_plugins.rst documentation
|
||||
|
||||
# fmt: off
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue