Created
August 19, 2021 11:24
-
-
Save amercader/857ee22e9ea1c913bee3133cae81b45f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ckan/plugins/blanket.py b/ckan/plugins/blanket.py | |
index 8be03eb19..f1c3fa52d 100644 | |
--- a/ckan/plugins/blanket.py | |
+++ b/ckan/plugins/blanket.py | |
@@ -1,83 +1,87 @@ | |
# -*- coding: utf-8 -*- | |
-"""Quick implementations for simplest interfaces. | |
- | |
-Decorate plugin with ``@tk.blanket.<GROUP>`` and it will automatically | |
-receive common implementation of interface corresponding to the chosen | |
-group. Common implementation is the one, that satisfies following | |
-requirements: | |
- | |
- - implementation of interface must provide just a single method | |
- - method, required by interface, returns either list or dictionary | |
- - all the items, that are returned from method are defined in separate module | |
- - all the items(and only those items) are listed inside ``module.__all__`` | |
- - module is available under common import path. Those paths are: | |
- | |
- - ``ckanext.ext.helpers`` for ``ITemplateHelpers`` | |
- - ``ckanext.ext.logic.auth`` for ``IAuthFunctions`` | |
- - ``ckanext.ext.logic.action`` for ``IActions`` | |
- - ``ckanext.ext.logic.validators`` for ``IValidators`` | |
- - ``ckanext.ext.views`` for ``IBlueprint`` | |
- - ``ckanext.ext.cli`` for ``IClick`` | |
- | |
-Available groups are: | |
- - ``tk.blanket.helpers``: implemets ``ITemplateHelpers`` | |
- - ``tk.blanket.auth``: implemets ``IAuthFunctions`` | |
- - ``tk.blanket.action``: implemets ``IActions`` | |
- - ``tk.blanket.validator``: implemets ``IValidators`` | |
- - ``tk.blanket.blueprint``: implemets ``IBlueprint`` | |
- - ``tk.blanket.cli``: implemets ``IClick`` | |
- | |
-Example:: | |
- | |
- @tk.blanket.action | |
- class MyPlugin(plugins.SingletonPlugin): | |
- pass | |
+"""Quick implementations of simple plugin interfaces. | |
+ | |
+Blankets allow to reduce boilerplate code in plugins by simplifying the way | |
+common interfaces are registered. | |
+ | |
+For instance, this is how template helpers are generally added using the | |
+:py:class:`~ckan.plugins.interfaces.ITemplateHelpers` interface:: | |
+ | |
+ from ckan import plugins as p | |
+ from ckanext.myext import helpers | |
-Is roughly equal to:: | |
- class MyPlugin(plugins.SingletonPlugin): | |
- plugins.implements(plugins.IActions) | |
+ class MyPlugin(p.SingletonPlugin): | |
- def get_actions(self): | |
- import ckanext.ext.logic.action as actions | |
- extra_actions = { | |
- name: getattr(actions, name) | |
- for name in actions.__all__ | |
+ p.implements(ITemplateHelpers) | |
+ | |
+ def get_helpers(self): | |
+ | |
+ return { | |
+ 'my_ext_custom_helper_1': helpers.my_ext_custom_helper_1, | |
+ 'my_ext_custom_helper_2': helpers.my_ext_custom_helper_2, | |
} | |
- return extra_actions | |
-In addition, if plugin follows custom naming conventions, it's | |
-possible to customize implementation, by providing argument to | |
-decorator. | |
+The same pattern is used for :py:class:`~ckan.plugins.interfaces.IActions`, | |
+:py:class:`~ckan.plugins.interfaces.IAuthFunctions`, etc. | |
+ | |
+With Blankets, assuming that you have created your module in the expected path | |
+with the expected name (see below), you can automate the registration of your helpers | |
+using the corresponding blanket decorator from the plugins toolkit:: | |
+ | |
+ | |
+ @p.toolkit.blanket.helpers | |
+ class MyPlugin(p.SingletonPlugin): | |
+ pass | |
+ | |
+ | |
+The following table lists the available blanket decorators, the interface they implement | |
+and the default module path where the blanket will automatically look for items to import: | |
-If extension uses different names for modules:: | |
- import ckanext.ext.custom_actions as custom_module | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| Decorator | Interface | Default module path | | |
++===============================+=======================================================+================================+ | |
+| ``toolkit.blanket.helpers`` | :py:class:`~ckan.plugins.interfaces.ITemplateHelpers` | ckanext.myext.helpers | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| ``toolkit.blanket.auth`` | :py:class:`~ckan.plugins.interfaces.IAuthFunctions` | ckanext.myext.helpers | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| ``toolkit.blanket.action`` | :py:class:`~ckan.plugins.interfaces.IActions` | ckanext.myext.logic.auth | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| ``toolkit.blanket.validator`` | :py:class:`~ckan.plugins.interfaces.IValidators` | ckanext.myext.logic.action | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| ``toolkit.blanket.blueprint`` | :py:class:`~ckan.plugins.interfaces.IBlueprint` | ckanext.myext.logic.validators | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
+| ``toolkit.blanket.cli`` | :py:class:`~ckan.plugins.interfaces.IClick` | ckanext.myext.cli | | |
++-------------------------------+-------------------------------------------------------+--------------------------------+ | |
- @tk.blanket.action(custom_module) | |
- class MyPlugin(plugins.SingletonPlugin): | |
+ | |
+If your extension uses a different naming convention for your modules, it is still possible | |
+to use blankets by passing the relevant module as a parameter to the decorator:: | |
+ | |
+ import ckanext.myext.custom_actions as custom_module | |
+ | |
+ @p.toolkit.blanket.action(custom_module) | |
+ class MyPlugin(p.SingletonPlugin): | |
pass | |
-If extension already defines function that returns items required by | |
-interface:: | |
+You can also pass a function that returns the items required by the interface:: | |
def all_actions(): | |
return {'ext_action': ext_action} | |
- @tk.blanket.action(all_actions) | |
- class MyPlugin(plugins.SingletonPlugin): | |
+ @p.toolkit.blanket.action(all_actions) | |
+ class MyPlugin(p.SingletonPlugin): | |
pass | |
-If extension statically defines collection of items required by | |
-interface:: | |
+Or just a dict with the items required by the interface:: | |
all_actions = {'ext_action': ext_action} | |
- @tk.blanket.action(all_actions) | |
- class MyPlugin(plugins.SingletonPlugin): | |
+ @p.toolkit.blanket.action(all_actions) | |
+ class MyPlugin(p.SingletonPlugin): | |
pass | |
- | |
""" | |
import logging | |
import enum | |
diff --git a/doc/extensions/tutorial.rst b/doc/extensions/tutorial.rst | |
index 4a21703e4..479eaa0d5 100644 | |
--- a/doc/extensions/tutorial.rst | |
+++ b/doc/extensions/tutorial.rst | |
@@ -298,7 +298,17 @@ implements the :class:`~ckan.plugins.interfaces.IAuthFunctions` interface, and | |
provides an implementation of the interface's | |
:func:`~ckan.plugins.interfaces.IAuthFunctions.get_auth_functions` method that | |
overrides the default :func:`~ckan.logic.auth.create.group_create` function | |
-with a custom one. This custom function simply returns ``{'success': False}`` | |
+with a custom one. | |
+ | |
+ | |
+.. seealso:: | |
+ | |
+ Starting from CKAN 2.10, you can also use the ``ckan.plugins.toolkit.blanket`` | |
+ decorators to implement common interfaces in your plugins. See the ``blanket`` method in the | |
+ :doc:`/extensions/plugins-toolkit`. | |
+ | |
+ | |
+Our custom function simply returns ``{'success': False}`` | |
to refuse to let anyone create a new group. | |
If you now restart CKAN and reload the ``/group`` page, as long as you're not a |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment