diff --git a/docs/sdk/tutorials/plugins_example.md b/docs/sdk/tutorials/plugins_example.md index 4b9c4b28a..6315c0e49 100644 --- a/docs/sdk/tutorials/plugins_example.md +++ b/docs/sdk/tutorials/plugins_example.md @@ -125,28 +125,33 @@ class PluginHandler(PluginCore): Custom plugin instance """ - def on_submit(self, label: Dict, asset_id: str) -> None: + def on_event(self, payload: dict) -> None: """ Dedicated handler for Submit action """ - self.logger.info("On submit called") + event = payload.get("event") - issues_array = check_rules_on_label(label) + if event == 'labels.created.submit': + label = payload["label"] + asset_id = label["assetId"] + self.logger.info("On submit called") - project_id = self.project_id + issues_array = check_rules_on_label(label) - if len(issues_array) > 0: - print("Creating an issue...") + project_id = self.project_id - self.kili.create_issues( - project_id=project_id, - label_id_array=[label['id']] * len(issues_array), - text_array=issues_array, - ) + if len(issues_array) > 0: + print("Creating an issue...") - print("Issue created!") + self.kili.create_issues( + project_id=project_id, + label_id_array=[label['id']] * len(issues_array), + text_array=issues_array, + ) - self.kili.send_back_to_queue(asset_ids=[asset_id]) + print("Issue created!") + + self.kili.send_back_to_queue(asset_ids=[asset_id]) ``` @@ -208,7 +213,7 @@ plugin_name = "Plugin bbox count" from kili.exceptions import GraphQLError try: - kili.upload_plugin(plugin_folder, plugin_name) + kili.upload_plugin(plugin_folder, plugin_name, event_matcher=["labels.created.submit"]) except GraphQLError as error: print(str(error)) ``` @@ -231,7 +236,9 @@ path_to_plugin = Path(plugin_folder) / "main.py" plugin_name_file = "Plugin bbox count - file" try: - kili.upload_plugin(str(path_to_plugin), plugin_name_file) + kili.upload_plugin( + str(path_to_plugin), plugin_name_file, event_matcher=["labels.created.submit"] + ) except GraphQLError as error: print(str(error)) ``` diff --git a/docs/sdk/tutorials/plugins_library.md b/docs/sdk/tutorials/plugins_library.md index 0269fd512..c286b3e76 100644 --- a/docs/sdk/tutorials/plugins_library.md +++ b/docs/sdk/tutorials/plugins_library.md @@ -27,7 +27,6 @@ Let's imagine a project where we want to process images and detect some objects. Let's imagine another project where we process invoices. The project has two jobs and several transcription tasks associated with them. One of the jobs is about payment information and must contain a proper IBAN number as well as currency. The IBAN must start with FR, and the currency should be one of: *EURO* or *DOLLAR*. Kili's interface customization options are powerful and flexible, but won't help us in this specific situation so we have to turn to Kili plugins for help. We'll set up our Kili plugin to check these two rules when labelers click *Submit*. If the annotations don't match our predefined rules, our QA bot will add issues to the asset and send the asset back to the labeling queue. At the end, our script will calculate labeling accuracy and insert the accuracy metric in the json_metadata of the asset. All that with no need to engage a human reviewer. - Plugin file: [`plugin_document.py`](https://github.com/kili-technology/kili-python-sdk/blob/main/recipes/plugins_library/plugin_document.py){target=_blank} -- End-to-end notebook showcasing this example: [`plugins_example_document.ipynb`](https://github.com/kili-technology/kili-python-sdk/blob/main/recipes/plugins_example_document.ipynb){target=_blank} ### 2. Consensus resolution diff --git a/recipes/plugins_example.ipynb b/recipes/plugins_example.ipynb index bc3a5ddfa..54043f0d7 100644 --- a/recipes/plugins_example.ipynb +++ b/recipes/plugins_example.ipynb @@ -205,28 +205,33 @@ " Custom plugin instance\n", " \"\"\"\n", "\n", - " def on_submit(self, label: Dict, asset_id: str) -> None:\n", + " def on_event(self, payload: dict) -> None:\n", " \"\"\"\n", " Dedicated handler for Submit action \n", " \"\"\"\n", - " self.logger.info(\"On submit called\")\n", + " event = payload.get(\"event\")\n", "\n", - " issues_array = check_rules_on_label(label)\n", + " if event == 'labels.created.submit':\n", + " label = payload[\"label\"]\n", + " asset_id = label[\"assetId\"]\n", + " self.logger.info(\"On submit called\")\n", "\n", - " project_id = self.project_id\n", + " issues_array = check_rules_on_label(label)\n", "\n", - " if len(issues_array) > 0:\n", - " print(\"Creating an issue...\")\n", + " project_id = self.project_id\n", "\n", - " self.kili.create_issues(\n", - " project_id=project_id,\n", - " label_id_array=[label['id']] * len(issues_array),\n", - " text_array=issues_array,\n", - " )\n", + " if len(issues_array) > 0:\n", + " print(\"Creating an issue...\")\n", "\n", - " print(\"Issue created!\")\n", + " self.kili.create_issues(\n", + " project_id=project_id,\n", + " label_id_array=[label['id']] * len(issues_array),\n", + " text_array=issues_array,\n", + " )\n", "\n", - " self.kili.send_back_to_queue(asset_ids=[asset_id])\n", + " print(\"Issue created!\")\n", + "\n", + " self.kili.send_back_to_queue(asset_ids=[asset_id])\n", "\n", "```" ] @@ -319,7 +324,7 @@ "from kili.exceptions import GraphQLError\n", "\n", "try:\n", - " kili.upload_plugin(plugin_folder, plugin_name)\n", + " kili.upload_plugin(plugin_folder, plugin_name, event_matcher=[\"labels.created.submit\"])\n", "except GraphQLError as error:\n", " print(str(error))" ] @@ -359,7 +364,9 @@ "plugin_name_file = \"Plugin bbox count - file\"\n", "\n", "try:\n", - " kili.upload_plugin(str(path_to_plugin), plugin_name_file)\n", + " kili.upload_plugin(\n", + " str(path_to_plugin), plugin_name_file, event_matcher=[\"labels.created.submit\"]\n", + " )\n", "except GraphQLError as error:\n", " print(str(error))" ] diff --git a/recipes/plugins_example_document.ipynb b/recipes/plugins_example_document.ipynb deleted file mode 100644 index 12b5634c1..000000000 --- a/recipes/plugins_example_document.ipynb +++ /dev/null @@ -1,259 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "b06a48a2", - "metadata": {}, - "source": [ - "## Context\n", - "\n", - "This notebook is an end-to-end example that you can follow to create a project, upload a first plugin and activate it on this project, and later see the plugin in action and monitor it.\n", - "\n", - "**NB: The plugin capabilities of Kili are under active development, and compatible with version 2.125.2 & superior of kili. don't hesitate to reach out via github or the support to provide feedbacks.**\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "32b7bb39", - "metadata": {}, - "source": [ - "## Step 1 : Instantiate Kili with your KILI_API_KEY" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1acd5fe", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install --upgrade kili" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "751f4b11", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "from kili.client import Kili\n", - "\n", - "kili = Kili(\n", - " # api_endpoint=\"https://cloud.kili-technology.com/api/label/v2/graphql\",\n", - " # the line above can be uncommented and changed if you are working with an on-premise version of Kili\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "7063407a", - "metadata": {}, - "source": [ - "## Step 2 : Create the project\n", - "\n", - "First, we need to create a new project. For our example, it will be a project of type `IMAGE` and it will have the following `jsonInterace` :" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc56bc57", - "metadata": {}, - "outputs": [], - "source": [ - "# Create the project\n", - "\n", - "title = \"[Kili SDK Notebook]: Programmatic QA - Invoices processing\"\n", - "description = \"Programmatic QA - Invoices processing\"\n", - "input_type = \"IMAGE\"\n", - "\n", - "\n", - "filename = \"./datasets/document_plugin_data/jsoninterface.json\"\n", - "\n", - "with open(filename) as f:\n", - " json_interface = json.load(f)\n", - "\n", - "project = kili.create_project(\n", - " title=title, description=description, input_type=input_type, json_interface=json_interface\n", - ")\n", - "\n", - "project_id = project[\"id\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b4ef53d4", - "metadata": {}, - "outputs": [], - "source": [ - "# Add assets\n", - "\n", - "content_array = [\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/1502519745_VFT024147517-1.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/734-16a4595dbfa7f0126f0ddcaa54c6531ae554356d.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/document_data.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/facture%20.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/fcl091709145134-1.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/images.png\",\n", - " \"https://storage.googleapis.com/label-public-staging/doc-plugins/modele_de_facture-1.png\",\n", - "]\n", - "names_array = [\n", - " \"document1\",\n", - " \"document2\",\n", - " \"document3\",\n", - " \"document4\",\n", - " \"document5\",\n", - " \"document6\",\n", - " \"document7\",\n", - "]\n", - "\n", - "\n", - "project = kili.append_many_to_dataset(\n", - " project_id=project_id, content_array=content_array, external_id_array=names_array\n", - ")\n", - "\n", - "\n", - "kili.update_properties_in_project(\n", - " project_id=project[\"id\"],\n", - " metadata_types={\n", - " \"accuracy\": \"number\",\n", - " },\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "4d8490f2", - "metadata": {}, - "source": [ - "This project has two jobs with several tasks of transcription associated. We will be interested in the *Payment information* job, and more precisely the *IBAN* and the *Currency* sub-jobs. With our plugin, we want to be sure that the labelers write the correct values for the two transcriptions (so we are interested only in the `on_submit` handler of the plugin), since we know for sure that the IBAN should start with the 2 letters *FR*, and that the currency should be one of : *EURO*, *DOLLAR*. At then end, we also calculate an accuracy and we insert it in the `json_metadata` of the asset.\n", - "\n", - "To iterate on the plugin code, you can refer to *plugins_development.ipynb* notebook" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "67e3ab74", - "metadata": {}, - "source": [ - "\n", - "```python\n", - "from kili.plugins import PluginCore\n", - "from typing import Dict\n", - "\n", - "\n", - "class PluginHandler(PluginCore):\n", - " \"\"\"\n", - " Custom plugin instance\n", - " \"\"\"\n", - "\n", - " def check_rules_on_label(self, label: Dict):\n", - "\n", - " issues_array = []\n", - " mid_issues_array = []\n", - "\n", - " for bbox in label[\"jsonResponse\"][\"JOB_0\"][\"annotations\"]:\n", - "\n", - " # Rule 1 - Check IBAN starts by FR\n", - " if bbox[\"categories\"][0][\"name\"] == \"IBAN\":\n", - " iban = bbox[\"children\"][\"TRANSCRIPTION_JOB\"][\"text\"]\n", - "\n", - " if iban[0:2] != \"FR\":\n", - " issues_array.append(\"IBAN number should start by FR\")\n", - " mid_issues_array.append(bbox[\"mid\"])\n", - "\n", - " # Rule 2 - Check if Currency is in list of fields\n", - " if bbox[\"categories\"][0][\"name\"] == \"CURRENCY\":\n", - " currency = bbox[\"children\"][\"TRANSCRIPTION_JOB_2\"][\"text\"]\n", - "\n", - " if currency not in [\"DOLLAR\", \"EURO\"]:\n", - " issues_array.append(\"Authorized currency are only Euro and Dollar\")\n", - " mid_issues_array.append(bbox[\"mid\"])\n", - "\n", - " return issues_array, mid_issues_array\n", - "\n", - " def on_submit(self, label: Dict, asset_id: str) -> None:\n", - " \"\"\"\n", - " Dedicated handler for Submit action\n", - " \"\"\"\n", - " self.logger.info(\"On submit called\")\n", - "\n", - " issues_array, mid_issues_array = self.check_rules_on_label(label)\n", - "\n", - " project_id = self.project_id\n", - "\n", - " if len(issues_array) > 0:\n", - " print(\"Creating an issue...\")\n", - "\n", - " self.kili.create_issues(\n", - " project_id=project_id,\n", - " label_id_array=[label['id']] * len(issues_array),\n", - " object_mid_array=mid_issues_array,\n", - " text_array=issues_array,\n", - " )\n", - "\n", - " print(\"Issue created!\")\n", - "\n", - " self.kili.add_to_review(asset_ids=[asset_id])\n", - "\n", - " print(\"Asset added to review\")\n", - "\n", - " accuracy = (\n", - " 100 - len(issues_array) / len(label[\"jsonResponse\"][\"JOB_0\"][\"annotations\"]) * 100\n", - " )\n", - "\n", - " print(accuracy)\n", - " self.kili.update_properties_in_assets(\n", - " asset_ids=[asset_id], json_metadatas=[\"{'accuracy': accuracy}\"]\n", - " )\n", - "\n", - " print(\"Accuracy score computed\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "fa10cdff", - "metadata": {}, - "source": [ - "## Step 3 : Uploading the plugin\n", - "\n", - "With the plugin defined in a separate `python` file, we can now upload it and activate it on our project.\n", - "\n", - "- the upload will create the necessary builds to execute the plugin, it will take a few minutes.\n", - "- After the activation, you can start using it right away." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d25e7851", - "metadata": {}, - "outputs": [], - "source": [ - "path_to_plugin = \"./plugins_library/plugin_document.py\"\n", - "plugin_name = \"Plugin - Programmatic QA invoices\"\n", - "\n", - "kili.upload_plugin(path_to_plugin, plugin_name)\n", - "\n", - "kili.activate_plugin_on_project(plugin_name, project_id=project_id)" - ] - } - ], - "metadata": { - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/recipes/plugins_library/README.md b/recipes/plugins_library/README.md index ff5e32f47..7fbbe6203 100644 --- a/recipes/plugins_library/README.md +++ b/recipes/plugins_library/README.md @@ -6,7 +6,7 @@ In this section you can find multiple examples of use-cases where our system of You can refer to our [tutorial](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/plugins_development/) to develop your plugin and iterate on it locally (or use the [plugins_development.ipynb](../plugins_development.ipynb) notebook), before uploading the final version to Kili. -If you want to see some end-to-end example of our plugins, you can refer to the notebooks [plugins_example.ipynb](../plugins_example.ipynb) (example of a plugin checking the number of annotation) and [plugins_example_document.ipynb](../plugins_example_document.ipynb) (example of a plugin checking some document processing rules). +If you want to see some end-to-end example of our plugins, you can refer to the notebooks [plugins_example.ipynb](../plugins_example.ipynb) (example of a plugin checking the number of annotation). For further information concerning the Kili plugins, refer to our [Documentation](https://python-sdk-docs.kili-technology.com/latest/sdk/plugins/) @@ -29,7 +29,6 @@ Let's imagine a project where we want to process images and detect some objects. Let's imagine another project where we process invoices. The project has two jobs and several transcription tasks associated with them. One of the jobs is about payment information and must contain a proper IBAN number as well as currency. The IBAN must start with FR, and the currency should be one of: *EURO* or *DOLLAR*. Kili's interface customization options are powerful and flexible, but won't help us in this specific situation so we have to turn to Kili plugins for help. We'll set up our Kili plugin to check these two rules when labelers click *Submit*. If the annotations don't match our predefined rules, our QA bot will add issues to the asset and send the asset back to the labeling queue. At the end, our script will calculate labeling accuracy and insert the accuracy metric in the json_metadata of the asset. All that with no need to engage a human reviewer. - Plugin file: `plugin_document.py` -- End-to-end notebook showcasing this example: `plugins_example_document.ipynb` ### 2. Consensus resolution diff --git a/recipes/plugins_library/plugin_image.py b/recipes/plugins_library/plugin_image.py index 995166812..f3ce06f5e 100644 --- a/recipes/plugins_library/plugin_image.py +++ b/recipes/plugins_library/plugin_image.py @@ -22,23 +22,29 @@ def check_rules_on_label(label: dict) -> list[Optional[str]]: class PluginHandler(PluginCore): """Custom plugin instance.""" - def on_submit(self, label: dict, asset_id: str) -> None: - """Dedicated handler for Submit action.""" - self.logger.info("On submit called") + def on_event(self, payload: dict) -> None: + """Dedicated handler for Event action.""" + event = payload.get("event") - issues_array = check_rules_on_label(label) + if event == "labels.created.submit": + self.logger.info("On submit called") - project_id = self.project_id + label = payload["label"] + asset_id = label["assetId"] - if len(issues_array) > 0: - print("Creating an issue...") + issues_array = check_rules_on_label(label) - self.kili.create_issues( - project_id=project_id, - label_id_array=[label["id"]] * len(issues_array), - text_array=issues_array, - ) + project_id = self.project_id - print("Issue created!") + if len(issues_array) > 0: + print("Creating an issue...") - self.kili.send_back_to_queue(asset_ids=[asset_id]) + self.kili.create_issues( + project_id=project_id, + label_id_array=[label["id"]] * len(issues_array), + text_array=issues_array, + ) + + print("Issue created!") + + self.kili.send_back_to_queue(asset_ids=[asset_id]) diff --git a/src/kili/domain_api/plugins.py b/src/kili/domain_api/plugins.py index 303e3530a..08c6ed37d 100644 --- a/src/kili/domain_api/plugins.py +++ b/src/kili/domain_api/plugins.py @@ -67,17 +67,18 @@ def create( - logPayload: - runId: a unique identifier of the run for observability - projectId: the Kili project the webhook is called on - - payload: the event produced, for example for `onSubmit` event: + - payload: the event produced, for example for `labels.created.submit` event: - label: the label produced - asset_id: the asset on which the label is produced plugin_name: Name of your plugin header: Authorization header to access the routes verbose: If false, minimal logs are displayed - handler_type: Action for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - handler_types: List of actions for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - By default, is [`onSubmit`, `onReview`]. + handler_type: Deprecated. Use event_pattern or event_matcher instead. + Legacy action handler. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. + handler_types: Deprecated. Use event_matcher instead. + Legacy list of action handlers. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. event_pattern: Event pattern for which the webhook should be called. event_matcher: List of events for which the webhook should be called. @@ -93,20 +94,18 @@ def create( ... header='Bearer token123' ... ) - >>> # Create webhook with single handler type + >>> # Create webhook with single event pattern >>> result = kili.plugins.webhooks.create( ... webhook_url='https://my-webhook.com/api/kili', ... plugin_name='custom webhook', - ... handler_type='onSubmit', - ... event_pattern='project.*' + ... event_pattern='labels.created.submit' ... ) - >>> # Create webhook with multiple handler types + >>> # Create webhook with multiple event matchers >>> result = kili.plugins.webhooks.create( ... webhook_url='https://my-webhook.com/api/kili', ... plugin_name='custom webhook', - ... handler_types=['onSubmit', 'onReview'], - ... event_matcher=['project.*', 'asset.*'] + ... event_matcher=['labels.created.submit', 'labels.created.review'] ... ) """ # Convert singular to plural @@ -141,11 +140,12 @@ def update( plugin_name: Name of your plugin new_header: Authorization header to access the routes verbose: If false, minimal logs are displayed - handler_type: Action for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - handler_types: List of actions for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - By default, is [`onSubmit`, `onReview`] + handler_type: Deprecated. Use event_pattern or event_matcher instead. + Legacy action handler. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. + handler_types: Deprecated. Use event_matcher instead. + Legacy list of action handlers. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. event_pattern: Event pattern for which the webhook should be called. event_matcher: List of events for which the webhook should be called. @@ -161,20 +161,18 @@ def update( ... new_header='Bearer new_token456' ... ) - >>> # Update webhook with single handler + >>> # Update webhook with single event pattern >>> result = kili.plugins.webhooks.update( ... new_webhook_url='https://updated-webhook.com/api', ... plugin_name='my webhook', - ... handler_type='onSubmit', - ... event_pattern='asset.*' + ... event_pattern='labels.created.submit' ... ) - >>> # Update webhook with multiple event handlers + >>> # Update webhook with multiple event matchers >>> result = kili.plugins.webhooks.update( ... new_webhook_url='https://updated-webhook.com/api', ... plugin_name='my webhook', - ... handler_types=['onSubmit', 'onReview'], - ... event_matcher=['asset.*', 'label.*'] + ... event_matcher=['labels.created.submit', 'labels.created.review'] ... ) """ # Convert singular to plural @@ -497,14 +495,14 @@ def create( >>> result = kili.plugins.create( ... plugin_path="./my_plugin/", ... plugin_name="custom_plugin_name", - ... event_pattern="onSubmit" + ... event_pattern="labels.created.submit" ... ) >>> # Upload with custom name and multiple event matchers >>> result = kili.plugins.create( ... plugin_path="./my_plugin/", ... plugin_name="custom_plugin_name", - ... event_matcher=["onSubmit", "onReview"] + ... event_matcher=["labels.created.submit", "labels.created.review"] ... ) """ # Convert singular to plural diff --git a/src/kili/entrypoints/mutations/plugins/__init__.py b/src/kili/entrypoints/mutations/plugins/__init__.py index 108f7c75c..fa8fed1af 100644 --- a/src/kili/entrypoints/mutations/plugins/__init__.py +++ b/src/kili/entrypoints/mutations/plugins/__init__.py @@ -15,6 +15,8 @@ ) from kili.utils.logcontext import for_all_methods, log_call +DEPRECATED_HANDLERS = {"onSubmit", "onReview"} + @for_all_methods(log_call, exclude=["__init__"]) class MutationsPlugins(BaseOperationEntrypointMixin): @@ -93,9 +95,9 @@ def create_webhook( plugin_name: name of your plugin header: Authorization header to access the routes verbose: If false, minimal logs are displayed - handler_types: List of actions for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - By default, is [`onSubmit`, `onReview`]. + handler_types: Deprecated. Use event_matcher instead. + Legacy list of action handlers. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. event_matcher: List of events for which the webhook should be called. Returns: @@ -105,6 +107,12 @@ def create_webhook( Examples: >>> kili.create_webhook(webhook_url='https://my-custom-url-publicly-accessible/', plugin_name='my webhook', header='...') """ + if handler_types is not None: + if any(handler in DEPRECATED_HANDLERS for handler in handler_types): + raise ValueError( + f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead." + ) + return WebhookUploader( self, # pyright: ignore[reportArgumentType] webhook_url, @@ -135,9 +143,9 @@ def update_webhook( plugin_name: name of your plugin new_header: Authorization header to access the routes verbose: If false, minimal logs are displayed - handler_types: List of actions for which the webhook should be called. - Possible variants: `onSubmit`, `onReview`. - By default, is [`onSubmit`, `onReview`] + handler_types: Deprecated. Use event_matcher instead. + Legacy list of action handlers. Possible variants: `onCustomInterfaceClick`, + `onProjectUpdated`, `onSendBackToQueue`. event_matcher: List of events for which the webhook should be called. Returns: @@ -147,6 +155,12 @@ def update_webhook( Examples: >>> kili.update_webhook(webhook_url='https://my-custom-url-publicly-accessible/', plugin_name='my webhook', header='...') """ + if handler_types is not None: + if any(handler in DEPRECATED_HANDLERS for handler in handler_types): + raise ValueError( + f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead." + ) + return WebhookUploader( self, # pyright: ignore[reportArgumentType] new_webhook_url, diff --git a/src/kili/services/plugins/model.py b/src/kili/services/plugins/model.py index 43e53dce2..4d6d7f366 100644 --- a/src/kili/services/plugins/model.py +++ b/src/kili/services/plugins/model.py @@ -68,7 +68,7 @@ def on_submit(self, label: Dict, asset_id: str): ``` """ # pylint: disable=unused-argument - self.logger.warning("Method not implemented. Define a custom on_submit on your plugin") + self.logger.warning("Method Deprecated. Use on_event instead.") def on_review( self, @@ -97,7 +97,7 @@ def on_review(self, label: Dict, asset_id: str): ``` """ # pylint: disable=unused-argument - self.logger.warning("Method not implemented. Define a custom on_review on your plugin") + self.logger.warning("Method Deprecated. Use on_event instead.") def on_custom_interface_click( self, diff --git a/src/kili/services/plugins/upload.py b/src/kili/services/plugins/upload.py index 4fada015d..696d3748b 100644 --- a/src/kili/services/plugins/upload.py +++ b/src/kili/services/plugins/upload.py @@ -43,6 +43,8 @@ "on_send_back_to_queue": "onSendBackToQueue", } +DEPRECATED_HANDLERS = {"onSubmit", "onReview"} + def check_file_mime_type( path: Path, compatible_mime_extensions: list[str], verbose: bool = True @@ -198,6 +200,13 @@ def _retrieve_plugin_src(self) -> list[Path]: if handler_types and self.event_matcher: raise ValueError("Cannot have both handler types and event matcher.") + if handler_types is not None and any( + handler in DEPRECATED_HANDLERS for handler in handler_types + ): + raise ValueError( + f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead." + ) + self.handler_types = handler_types return list(self.plugin_path.glob("**/*.py")) @@ -217,6 +226,13 @@ def _retrieve_plugin_src(self) -> list[Path]: if handler_types and self.event_matcher: raise ValueError("Cannot have both handler types and event matcher.") + if handler_types is not None and any( + handler in DEPRECATED_HANDLERS for handler in handler_types + ): + raise ValueError( + f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead." + ) + self.handler_types = handler_types return [file_path] diff --git a/tests/unit/services/plugins/plugin_folder/main.py b/tests/unit/services/plugins/plugin_folder/main.py index c9cca7400..bb0315ac8 100644 --- a/tests/unit/services/plugins/plugin_folder/main.py +++ b/tests/unit/services/plugins/plugin_folder/main.py @@ -4,5 +4,5 @@ class PluginHandler(PluginCore): - def on_submit(self, label: dict, asset_id: str) -> None: + def on_event(self, label: dict, asset_id: str) -> None: custom_function() diff --git a/tests/unit/services/plugins/test_unit_plugins.py b/tests/unit/services/plugins/test_unit_plugins.py index 669adbb76..6972ac19d 100644 --- a/tests/unit/services/plugins/test_unit_plugins.py +++ b/tests/unit/services/plugins/test_unit_plugins.py @@ -175,7 +175,7 @@ def test_zip_creation_from_file(kili): HttpClient( kili_endpoint="https://fake_endpoint.kili-technology.com", api_key="", verify=True ), - event_matcher=None, + event_matcher=["labels.created.submit"], )._create_zip(tmp_dir) zip_path = tmp_dir / "archive.zip" @@ -208,7 +208,7 @@ def test_no_main_when_creating_zip_from_folder(kili): api_key="", verify=True, ), - event_matcher=None, + event_matcher=["labels.created.submit"], )._create_zip(tmp_dir) @@ -248,7 +248,7 @@ def test_zip_creation_from_folder(kili): HttpClient( kili_endpoint="https://fake_endpoint.kili-technology.com", api_key="", verify=True ), - event_matcher=None, + event_matcher=["labels.created.submit"], )._create_zip(tmp_dir) zip_path = tmp_dir / "archive.zip"