datasette/datasette/hookspecs.py
Claude dd9b83301c
Refactor ColumnType: register classes, return instances with config
- register_column_types() now returns classes instead of instances
- ColumnType.__init__ takes optional config=, baking it into the instance
- get_column_type() returns a ColumnType instance (or None) instead of a
  (name, config) tuple
- get_column_types() returns {col: ColumnType instance} instead of tuples
- Remove get_column_type_class() - no longer needed
- render_cell/validate/transform_value methods no longer take config arg;
  use self.config instead
- render_cell hook takes column_type (ColumnType or None) instead of
  column_type + column_type_config

https://claude.ai/code/session_01SvPEPqHgURTWESRp28pTC3
2026-03-17 05:18:14 +00:00

264 lines
6.6 KiB
Python

from pluggy import HookimplMarker
from pluggy import HookspecMarker
hookspec = HookspecMarker("datasette")
hookimpl = HookimplMarker("datasette")
@hookspec
def startup(datasette):
"""Fires directly after Datasette first starts running"""
@hookspec
def asgi_wrapper(datasette):
"""Returns an ASGI middleware callable to wrap our ASGI application with"""
@hookspec
def prepare_connection(conn, database, datasette):
"""Modify SQLite connection in some way e.g. register custom SQL functions"""
@hookspec
def prepare_jinja2_environment(env, datasette):
"""Modify Jinja2 template environment e.g. register custom template tags"""
@hookspec
def extra_css_urls(template, database, table, columns, view_name, request, datasette):
"""Extra CSS URLs added by this plugin"""
@hookspec
def extra_js_urls(template, database, table, columns, view_name, request, datasette):
"""Extra JavaScript URLs added by this plugin"""
@hookspec
def extra_body_script(
template, database, table, columns, view_name, request, datasette
):
"""Extra JavaScript code to be included in <script> at bottom of body"""
@hookspec
def extra_template_vars(
template, database, table, columns, view_name, request, datasette
):
"""Extra template variables to be made available to the template - can return dict or callable or awaitable"""
@hookspec
def publish_subcommand(publish):
"""Subcommands for 'datasette publish'"""
@hookspec
def render_cell(
row,
value,
column,
table,
pks,
database,
datasette,
request,
column_type,
):
"""Customize rendering of HTML table cell values"""
@hookspec
def register_output_renderer(datasette):
"""Register a renderer to output data in a different format"""
@hookspec
def register_facet_classes():
"""Register Facet subclasses"""
@hookspec
def register_actions(datasette):
"""Register actions: returns a list of datasette.permission.Action objects"""
@hookspec
def register_column_types(datasette):
"""Return a list of ColumnType instances"""
@hookspec
def register_routes(datasette):
"""Register URL routes: return a list of (regex, view_function) pairs"""
@hookspec
def register_commands(cli):
"""Register additional CLI commands, e.g. 'datasette mycommand ...'"""
@hookspec
def actor_from_request(datasette, request):
"""Return an actor dictionary based on the incoming request"""
@hookspec(firstresult=True)
def actors_from_ids(datasette, actor_ids):
"""Returns a dictionary mapping those IDs to actor dictionaries"""
@hookspec
def jinja2_environment_from_request(datasette, request, env):
"""Return a Jinja2 environment based on the incoming request"""
@hookspec
def filters_from_request(request, database, table, datasette):
"""
Return datasette.filters.FilterArguments(
where_clauses=[str, str, str],
params={},
human_descriptions=[str, str, str],
extra_context={}
) based on the request"""
@hookspec
def permission_resources_sql(datasette, actor, action):
"""Return SQL query fragments for permission checks on resources.
Returns None, a PermissionSQL object, or a list of PermissionSQL objects.
Each PermissionSQL contains SQL that should return rows with columns:
parent (str|None), child (str|None), allow (int), reason (str).
Used to efficiently check permissions across multiple resources at once.
"""
@hookspec
def canned_queries(datasette, database, actor):
"""Return a dictionary of canned query definitions or an awaitable function that returns them"""
@hookspec
def register_magic_parameters(datasette):
"""Return a list of (name, function) magic parameter functions"""
@hookspec
def forbidden(datasette, request, message):
"""Custom response for a 403 forbidden error"""
@hookspec
def menu_links(datasette, actor, request):
"""Links for the navigation menu"""
@hookspec
def row_actions(datasette, actor, request, database, table, row):
"""Links for the row actions menu"""
@hookspec
def table_actions(datasette, actor, database, table, request):
"""Links for the table actions menu"""
@hookspec
def view_actions(datasette, actor, database, view, request):
"""Links for the view actions menu"""
@hookspec
def query_actions(datasette, actor, database, query_name, request, sql, params):
"""Links for the query and canned query actions menu"""
@hookspec
def database_actions(datasette, actor, database, request):
"""Links for the database actions menu"""
@hookspec
def homepage_actions(datasette, actor, request):
"""Links for the homepage actions menu"""
@hookspec
def skip_csrf(datasette, scope):
"""Mechanism for skipping CSRF checks for certain requests"""
@hookspec
def handle_exception(datasette, request, exception):
"""Handle an uncaught exception. Can return a Response or None."""
@hookspec
def track_event(datasette, event):
"""Respond to an event tracked by Datasette"""
@hookspec
def register_events(datasette):
"""Return a list of Event subclasses to use with track_event()"""
@hookspec
def top_homepage(datasette, request):
"""HTML to include at the top of the homepage"""
@hookspec
def top_database(datasette, request, database):
"""HTML to include at the top of the database page"""
@hookspec
def top_table(datasette, request, database, table):
"""HTML to include at the top of the table page"""
@hookspec
def top_row(datasette, request, database, table, row):
"""HTML to include at the top of the row page"""
@hookspec
def top_query(datasette, request, database, sql):
"""HTML to include at the top of the query results page"""
@hookspec
def top_canned_query(datasette, request, database, query_name):
"""HTML to include at the top of the canned query page"""
@hookspec
def register_token_handler(datasette):
"""Return a TokenHandler instance for token creation and verification"""
@hookspec
def write_wrapper(datasette, database, request, transaction):
"""Called when a write function is about to execute.
Return a generator function that accepts a ``conn`` argument.
The generator should ``yield`` exactly once: code before the
``yield`` runs before the write, code after the ``yield`` runs
after the write completes. The result of the write is sent
back through the ``yield``, so you can capture it with
``result = yield``.
If the write raises an exception, it is thrown into the generator
so you can handle it with a try/except around the ``yield``.
``request`` may be ``None`` for writes not originating from an
HTTP request. ``transaction`` is ``True`` if the write will
be wrapped in a transaction.
Return ``None`` to skip wrapping.
"""