diff --git a/datasette/utils/__init__.py b/datasette/utils/__init__.py index c6973d06..7fb81f02 100644 --- a/datasette/utils/__init__.py +++ b/datasette/utils/__init__.py @@ -1086,12 +1086,35 @@ def _gather_arguments(fn, kwargs): return call_with +@documented def call_with_supported_arguments(fn, **kwargs): + """ + Call ``fn`` with the subset of ``**kwargs`` matching its signature. + + This implements dependency injection: the caller provides all available + keyword arguments and the function receives only the ones it declares + as parameters. + + :param fn: A callable (sync function) + :param kwargs: All available keyword arguments + :returns: The return value of ``fn`` + """ call_with = _gather_arguments(fn, kwargs) return fn(*call_with) +@documented async def async_call_with_supported_arguments(fn, **kwargs): + """ + Async version of :func:`call_with_supported_arguments`. + + Calls ``await fn(...)`` with the subset of ``**kwargs`` matching its + signature. + + :param fn: An async callable + :param kwargs: All available keyword arguments + :returns: The return value of ``await fn(...)`` + """ call_with = _gather_arguments(fn, kwargs) return await fn(*call_with) diff --git a/docs/internals.rst b/docs/internals.rst index 704643cc..829b4dd4 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -2115,6 +2115,43 @@ Note that the space character is a special case: it will be replaced with a ``+` .. autofunction:: datasette.utils.tilde_decode +.. _internals_utils_call_with_supported_arguments: + +call_with_supported_arguments(fn, **kwargs) +------------------------------------------- + +Call ``fn``, passing it only those keyword arguments that match its function signature. This implements a dependency injection pattern - the caller provides all available arguments, and the function receives only the ones it declares as parameters. + +This is useful in plugins that want to define callback functions that only declare the arguments they need. For example: + +.. code-block:: python + + from datasette.utils import call_with_supported_arguments + + + def my_callback(request, datasette): ... + + + # This will pass only request and datasette, ignoring other kwargs: + call_with_supported_arguments( + my_callback, + request=request, + datasette=datasette, + database=database, + table=table, + ) + +.. autofunction:: datasette.utils.call_with_supported_arguments + +.. _internals_utils_async_call_with_supported_arguments: + +await async_call_with_supported_arguments(fn, **kwargs) +------------------------------------------------------- + +Async version of :ref:`call_with_supported_arguments `. Use this for ``async def`` callback functions. + +.. autofunction:: datasette.utils.async_call_with_supported_arguments + .. _internals_tracer: datasette.tracer