diff --git a/docs/sdk/plugins.md b/docs/sdk/plugins.md
index 3f620bcbf..8fc07884e 100644
--- a/docs/sdk/plugins.md
+++ b/docs/sdk/plugins.md
@@ -19,15 +19,19 @@ plugin_folder
|__ helper.py
```
-The plugin you are going to upload has to contain a `class PluginHandler(PluginCore)` (in the case of the module type plugin it has to be inside `main.py`) that implements two methods for the different types of events:
-- `on_submit`
-- `on_review`
+> **Note**: `on_submit` and `on_review` handlers are deprecated. Please use `on_event` instead. If your plugin was already uploaded with thoses handlers, it will still work. If you want the same behavior as `on_submit` and `on_review`, when you upload your plugin, you can use `event_matcher=["labels.created.submit"]` for `on_submit` and `event_matcher=["labels.created.review"]` for `on_review` events.
-These methods have a predefined set of parameters:
-- the `label` submitted (a dictionary containing the fields of the GraphQL type [Label](https://api-docs.kili-technology.com/types/objects/label/))
-- the `asset_id` of the asset labeled
+The plugin you are going to upload has to contain a `class PluginHandler(PluginCore)` (in the case of the module type plugin it has to be inside `main.py`) that implements one method for the different types of events:
+
+- `on_event`
+
+These methods have a predefined set of parameter:
+
+- the `payload` submitted (a dictionary containing the fields for your plugins)
+ - `payload.event` the name of the event (ex: for submit : `labels.created.submit`, for review `labels.created.review`)
+ - `payload.label` the label containing the fields of the GraphQL type [Label](https://api-docs.kili-technology.com/types/objects/label/)
You can add custom methods in your class as well.
@@ -53,12 +57,18 @@ class PluginHandler(PluginCore):
def custom_method(self):
# Do something...
- def on_review(self, label: Dict, asset_id: str) -> None:
+ def on_event(self, payload: dict) -> None: # This can replace on_review method
"""Dedicated handler for Review action"""
+ event = payload.get("event")
+
+ if event == 'labels.created.review':
# Do something...
- def on_submit(self, label: Dict, asset_id: str) -> None:
+ def on_event(self, payload: dict) -> None: # This can replace on_submit method
"""Dedicated handler for Submit action"""
+ event = payload.get("event")
+
+ if event == 'labels.created.submit':
# Do something...
```
@@ -85,15 +95,22 @@ def custom_function(label: Dict, logger: Logger):
class PluginHandler(PluginCore):
"""Custom plugin"""
- 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")
- custom_function(label, self.logger)
+ event = payload.get("event")
+ if event == 'labels.created.submit':
+ self.logger.info("On Submit called")
+ label = payload["label"]
+ custom_function(label, self.logger)
```
## Model for Plugins
::: kili.services.plugins.model.PluginCore
+ options:
+ filters:
+ - "!^on_review$"
+ - "!^on_submit$"
## Queries
diff --git a/docs/sdk/tutorials/plugins_development.md b/docs/sdk/tutorials/plugins_development.md
deleted file mode 100644
index 18772b99e..000000000
--- a/docs/sdk/tutorials/plugins_development.md
+++ /dev/null
@@ -1,281 +0,0 @@
-
-
-
-# How to develop and test a Kili plugin
-
-## Preliminary
-
-This notebook will teach you how to build your first plugin.
-
-A plugin is an uploaded Python script triggered by an event that you define.
-
-For instance, you can trigger a plugin when a labeler clicks on **Submit** with the `on_submit` handler.
-
-The plugin should have different methods for the different types of events:
-
-- `on_submit`
-- `on_review`
-
-These methods have a predefined set of parameters:
-
-- the `label` submitted
-- the `asset_id` of the asset labeled
-
-Some attributes are available in the class:
-
-- `self.kili`
-- `self.project_id`
-
-Therefore, the skeleton of the plugin should look like this:
-
-```python
-from kili.plugins import PluginCore
-from typing import Dict
-import numpy as np
-
-class PluginHandler(PluginCore):
- """Custom plugin"""
-
- def on_review(self, label: Dict, asset_id: str) -> None:
- """Dedicated handler for Review action"""
- # Do something...
-
- def on_submit(self, label: Dict, asset_id: str) -> None:
- """Dedicated handler for Submit action"""
- # Do something...
-```
-
-Do not hesitate to reach out to us if you need more.
-
-**NB: The plugin capabilities of Kili are under active development, and compatible with version 2.125.2 and later of Kili. Don't hesitate to reach out via Github or Kili support to provide feedback.**
-
-## Instantiate Kili
-
-
-```python
-%pip install kili
-```
-
-
-```python
-%load_ext autoreload
-%autoreload 2
-
-
-from kili.client import Kili
-
-kili = Kili(
- # api_endpoint="https://cloud.kili-technology.com/api/label/v2/graphql",
- # the line above can be uncommented and changed if you are working with an on-premise version of Kili
-)
-```
-
-## Develop your plugin
-
-The first step is to define the functions that will be called when the event is triggered. You will be able to iterate on these functions locally (more on that in the next section).
-
-The plugin can be defined in two ways: a single `.py` file with everything inside or a module (folder containing multiple `.py` files). In the case of the module type, a file named `main.py` needs to be at the root of the folder and will serve as the entrypoint.
-
-### 1. First option - Plugin defined in a single file
-
-This cell should be the contents of the `.py` file that you will upload as a plugin at the end.
-
-**This file should define the `PluginHandler` class that will contain the proper methods.**
-
-We recommend using a modern IDE like VScode to get type hints and autocompletion on the methods.
-
-
-```python
-import numpy as np
-
-from kili.plugins import PluginCore
-
-
-def custom_function(label: dict):
- label_id = label.get("id")
- print(f"My custom function for review of label with id {label_id}")
-
-
-class PluginHandler(PluginCore):
- """Custom plugin instance"""
-
- def custom_method(self, project_id, label_id):
- print(f"custom_method called for label {label_id}")
- random_seed = np.random.random(1)[0]
- if random_seed > 0.5:
- self.logger.warning("Generating issue")
- # Use kili for actions with self.kili
- self.kili.create_issues(
- project_id=project_id,
- label_id_array=[label_id],
- text_array=["Random issue generated for this label"],
- )
-
- def on_review(self, label: dict, asset_id: str) -> None:
- """Dedicated handler for Review action"""
- custom_function(label)
-
- def on_submit(self, label: dict, asset_id: str) -> None:
- """Dedicated handler for Submit action"""
- print("On submit called")
-
- project_id = self.project_id
- label_id = label.get("id")
-
- self.custom_method(project_id, label_id)
-```
-
-### 2. Second option - Plugin defined in a folder
-
-As said previously, the structure of the folder can be the following (the only constraint being the presence of the `main.py` file):
-```
-plugin_folder
-|__ main.py
-|__ other_file.py
-|__ requirements.txt
-|
-|___helpers
- |__ helper.py
-```
-
-You can notice that you can also include a `requirements.txt` file in the folder and the necessary packages will be installed with your plugin. Don't forget to add them, since the plugin could work on your machine if you have them installed, but it won't be possible to create the plugin if there are missing dependencies.
-
-**Note:** The `requirements.txt` file can only be included for the SaaS version of the Kili platform, for on-premise deployments there is a pre-defined list of packages that can be used. For more details, see the [documentation of plugins](https://python-sdk-docs.kili-technology.com/latest/sdk/plugins/)
-
-**Important: The main.py file need to have the same skeleton as the plugin defined in a single file (presence of the class `PluginHandler`), the difference being that it can import and call functions defined in other files**
-
-Depending on where the folder is stored, there are two ways to import the plugin in order to test it:
-
-- The first way is to use a relative import (having the plugin folder and the notebook in the same folder). It is simpler and we recommend it as it will also allow the IDE to detect the correct methods and propose hints and autocompletion.
-- The second is to use an absolute path to the plugin folder
-
-#### 2.1 Relative import
-
-
-```python
-# Here replace 'plugin_folder' with the actual name of the folder
-from plugin_folder.main import PluginHandler
-```
-
-#### 2.2 Absolute path import
-
-
-```python
-import sys
-from pathlib import Path
-
-# Input the path to the plugin folder (it should include the folder), for example '/path/to/plugin_folder'
-plugin_path = ""
-
-module_path = str(Path(plugin_path).parent.absolute())
-
-# We are inserting the path in the system PATH to be able to import the module in the next line
-sys.path.insert(0, module_path)
-
-# In the next line replace 'plugin_folder' with the actual name of the folder
-from plugin_folder.main import PluginHandler
-```
-
-### Testing the plugin locally
-
-In this we will show you how to test your plugin locally before uploading it.
-
-
-```python
-project_id = ""
-```
-
-Instantiate the plugin:
-
-
-```python
-my_plugin_instance = PluginHandler(kili, project_id)
-
-
-def get_label(label_id, project_id):
- """Function to get the object Label with the same keys as it will be in the plugin"""
- label = list(
- kili.labels(
- project_id=project_id,
- label_id=label_id,
- fields=["id", "jsonResponse", "author.id", "labelType", "createdAt", "secondsToLabel"],
- )
- )[0]
-
- label["authorId"] = label["author"]["id"]
- del label["author"]
- return label
-```
-
-### Test the plugin run
-
-If you already have a test project with labels added, you can directly use the IDs of these labels (see the following cell). Otherwise, you can follow the *plugins_example.ipynb* notebook to create a new project and then upload an asset with an associated label.
-
-
-```python
-asset_id = ""
-label_id = ""
-```
-
-
-```python
-label = get_label(label_id=label_id, project_id=project_id)
-
-my_plugin_instance.on_submit(label=label, asset_id=asset_id)
-```
-
-### Test the plugin run on Kili
-
-When you finish debugging the code, you may want to upload it directly into Kili.
-
-Note that you might get an error if the plugin name already exists in your Kili organization.
-
-
-```python
-path_to_plugin = "path/to/my/plugin.py"
-plugin_name = "My first kili plugin"
-```
-
-
-```python
-from kili.exceptions import GraphQLError
-
-try:
- kili.upload_plugin(path_to_plugin, plugin_name)
-except GraphQLError as error:
- print(str(error))
-```
-
-Plugins must be activated in the project that you want them to run in. Be careful with production projects: your custom workflows or rules will also be applied
-
-
-```python
-kili.activate_plugin_on_project(plugin_name, project_id=project_id)
-```
-
-## Monitoring the plugin
-
-Plugin creation takes some time (around 5 minutes). The plugin will begin to run only after it's been fully created (if labeling events are to be triggered on this project).
-
-Additionally, you can get the logs of the runs:
-
-
-```python
-kili.get_plugin_logs(project_id=project_id, plugin_name=plugin_name)
-```
-
-You can set custom date rules for filtering your logs:
-
-
-```python
-from datetime import date, datetime
-
-dt = date.today() # You can change this date if needed
-start_date = datetime.combine(dt, datetime.min.time())
-
-kili.get_plugin_logs(project_id=project_id, plugin_name=plugin_name, start_date=start_date)
-```
-
-## Managing your plugin
-
-There are several other methods to manage your plugins and their lifecycle. To find out more, check the plugins [tutorials](https://python-sdk-docs.kili-technology.com/latest/tutorials).
diff --git a/docs/sdk/tutorials/plugins_example.md b/docs/sdk/tutorials/plugins_example.md
index 6315c0e49..e5d72bb0d 100644
--- a/docs/sdk/tutorials/plugins_example.md
+++ b/docs/sdk/tutorials/plugins_example.md
@@ -98,7 +98,6 @@ This project has one job of bounding box creation with two categories.
With our plugin, we want to make sure that the labelers don't create more than one bounding box of category A.
-To iterate on the plugin code, you can refer to the plugins_development.ipynb notebook.
## Step 3: Write the plugin
diff --git a/docs/sdk/tutorials/plugins_library.md b/docs/sdk/tutorials/plugins_library.md
index c286b3e76..c7b4e31a7 100644
--- a/docs/sdk/tutorials/plugins_library.md
+++ b/docs/sdk/tutorials/plugins_library.md
@@ -4,7 +4,7 @@
In this section you can find multiple examples of use-cases where our system of plugins can help you in the Kili projects.
-You can also refer to our [tutorial](./plugins_development.md) to develop your plugin and iterate on it locally, before uploading the final version to Kili.
+You can also refer to our [tutorial](./plugins_example.md) to develop your plugin and iterate on it locally, before uploading the final version to Kili.
For further information concerning the Kili plugins, refer to the [Reference page](../plugins.md)
diff --git a/mkdocs.yml b/mkdocs.yml
index 40df8b9d2..1f1a79668 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -44,7 +44,7 @@ nav:
- PDF Assets: sdk/tutorials/importing_pdf_assets.md
- Rich Text Assets: sdk/tutorials/import_text_assets.md
- Multi-Layer Geospatial Assets: sdk/tutorials/importing_multilayer_geospatial_assets.md
- - LLM Static Assets : sdk/tutorials/llm_static.md
+ - LLM Static Assets: sdk/tutorials/llm_static.md
- Importing Labels:
- Importing Labels: sdk/tutorials/importing_labels.md
- OpenAI NER Pre-annotations: sdk/tutorials/ner_pre_annotations_openai.md
@@ -64,8 +64,7 @@ nav:
- Parsing Labels: sdk/tutorials/label_parsing.md
- LLM Dynamic Projects: sdk/tutorials/llm_dynamic.md
- Setting Up Plugins:
- - Developing Plugins: sdk/tutorials/plugins_development.md
- - Plugin Example - Programmatic QA: sdk/tutorials/plugins_example.md
+ - Developing Plugins: sdk/tutorials/plugins_example.md
- Plugins Library: sdk/tutorials/plugins_library.md
- Webhooks: sdk/tutorials/webhooks_example.md
- Integrations:
diff --git a/recipes/plugins_development.ipynb b/recipes/plugins_development.ipynb
deleted file mode 100644
index 7e203f9ab..000000000
--- a/recipes/plugins_development.ipynb
+++ /dev/null
@@ -1,440 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# How to develop and test a Kili plugin"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Preliminary\n",
- "\n",
- "This notebook will teach you how to build your first plugin.\n",
- "\n",
- "A plugin is an uploaded Python script triggered by an event that you define.\n",
- "\n",
- "For instance, you can trigger a plugin when a labeler clicks on **Submit** with the `on_submit` handler.\n",
- "\n",
- "The plugin should have different methods for the different types of events:\n",
- "\n",
- "- `on_submit`\n",
- "- `on_review`\n",
- "\n",
- "These methods have a predefined set of parameters:\n",
- "\n",
- "- the `label` submitted\n",
- "- the `asset_id` of the asset labeled\n",
- "\n",
- "Some attributes are available in the class:\n",
- "\n",
- "- `self.kili`\n",
- "- `self.project_id`\n",
- "\n",
- "Therefore, the skeleton of the plugin should look like this:\n",
- "\n",
- "```python\n",
- "from kili.plugins import PluginCore\n",
- "from typing import Dict\n",
- "import numpy as np\n",
- "\n",
- "class PluginHandler(PluginCore):\n",
- " \"\"\"Custom plugin\"\"\"\n",
- "\n",
- " def on_review(self, label: Dict, asset_id: str) -> None:\n",
- " \"\"\"Dedicated handler for Review action\"\"\"\n",
- " # Do something...\n",
- "\n",
- " def on_submit(self, label: Dict, asset_id: str) -> None:\n",
- " \"\"\"Dedicated handler for Submit action\"\"\"\n",
- " # Do something...\n",
- "```\n",
- "\n",
- "Do not hesitate to reach out to us if you need more.\n",
- "\n",
- "**NB: The plugin capabilities of Kili are under active development, and compatible with version 2.125.2 and later of Kili. Don't hesitate to reach out via Github or Kili support to provide feedback.**"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Instantiate Kili"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%pip install kili"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%load_ext autoreload\n",
- "%autoreload 2\n",
- "\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",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Develop your plugin\n",
- "\n",
- "The first step is to define the functions that will be called when the event is triggered. You will be able to iterate on these functions locally (more on that in the next section).\n",
- "\n",
- "The plugin can be defined in two ways: a single `.py` file with everything inside or a module (folder containing multiple `.py` files). In the case of the module type, a file named `main.py` needs to be at the root of the folder and will serve as the entrypoint."
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 1. First option - Plugin defined in a single file\n",
- "\n",
- "This cell should be the contents of the `.py` file that you will upload as a plugin at the end.\n",
- "\n",
- "**This file should define the `PluginHandler` class that will contain the proper methods.**\n",
- "\n",
- "We recommend using a modern IDE like VScode to get type hints and autocompletion on the methods."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "\n",
- "from kili.plugins import PluginCore\n",
- "\n",
- "\n",
- "def custom_function(label: dict):\n",
- " label_id = label.get(\"id\")\n",
- " print(f\"My custom function for review of label with id {label_id}\")\n",
- "\n",
- "\n",
- "class PluginHandler(PluginCore):\n",
- " \"\"\"Custom plugin instance\"\"\"\n",
- "\n",
- " def custom_method(self, project_id, label_id):\n",
- " print(f\"custom_method called for label {label_id}\")\n",
- " random_seed = np.random.random(1)[0]\n",
- " if random_seed > 0.5:\n",
- " self.logger.warning(\"Generating issue\")\n",
- " # Use kili for actions with self.kili\n",
- " self.kili.create_issues(\n",
- " project_id=project_id,\n",
- " label_id_array=[label_id],\n",
- " text_array=[\"Random issue generated for this label\"],\n",
- " )\n",
- "\n",
- " def on_review(self, label: dict, asset_id: str) -> None:\n",
- " \"\"\"Dedicated handler for Review action\"\"\"\n",
- " custom_function(label)\n",
- "\n",
- " def on_submit(self, label: dict, asset_id: str) -> None:\n",
- " \"\"\"Dedicated handler for Submit action\"\"\"\n",
- " print(\"On submit called\")\n",
- "\n",
- " project_id = self.project_id\n",
- " label_id = label.get(\"id\")\n",
- "\n",
- " self.custom_method(project_id, label_id)"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 2. Second option - Plugin defined in a folder\n",
- "\n",
- "As said previously, the structure of the folder can be the following (the only constraint being the presence of the `main.py` file):\n",
- "```\n",
- "plugin_folder\n",
- "|__ main.py\n",
- "|__ other_file.py\n",
- "|__ requirements.txt\n",
- "|\n",
- "|___helpers\n",
- " |__ helper.py\n",
- "```\n",
- "\n",
- "You can notice that you can also include a `requirements.txt` file in the folder and the necessary packages will be installed with your plugin. Don't forget to add them, since the plugin could work on your machine if you have them installed, but it won't be possible to create the plugin if there are missing dependencies.\n",
- "\n",
- "**Note:** The `requirements.txt` file can only be included for the SaaS version of the Kili platform, for on-premise deployments there is a pre-defined list of packages that can be used. For more details, see the [documentation of plugins](https://python-sdk-docs.kili-technology.com/latest/sdk/plugins/)\n",
- "\n",
- "**Important: The main.py file need to have the same skeleton as the plugin defined in a single file (presence of the class `PluginHandler`), the difference being that it can import and call functions defined in other files**\n",
- "\n",
- "Depending on where the folder is stored, there are two ways to import the plugin in order to test it:\n",
- "\n",
- "- The first way is to use a relative import (having the plugin folder and the notebook in the same folder). It is simpler and we recommend it as it will also allow the IDE to detect the correct methods and propose hints and autocompletion.\n",
- "- The second is to use an absolute path to the plugin folder"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 2.1 Relative import"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Here replace 'plugin_folder' with the actual name of the folder\n",
- "from plugin_folder.main import PluginHandler"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 2.2 Absolute path import"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "import sys\n",
- "from pathlib import Path\n",
- "\n",
- "# Input the path to the plugin folder (it should include the folder), for example '/path/to/plugin_folder'\n",
- "plugin_path = \"\"\n",
- "\n",
- "module_path = str(Path(plugin_path).parent.absolute())\n",
- "\n",
- "# We are inserting the path in the system PATH to be able to import the module in the next line\n",
- "sys.path.insert(0, module_path)\n",
- "\n",
- "# In the next line replace 'plugin_folder' with the actual name of the folder\n",
- "from plugin_folder.main import PluginHandler"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Testing the plugin locally\n",
- "\n",
- "In this we will show you how to test your plugin locally before uploading it."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "project_id = \"\""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Instantiate the plugin:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "my_plugin_instance = PluginHandler(kili, project_id)\n",
- "\n",
- "\n",
- "def get_label(label_id, project_id):\n",
- " \"\"\"Function to get the object Label with the same keys as it will be in the plugin\"\"\"\n",
- " label = list(\n",
- " kili.labels(\n",
- " project_id=project_id,\n",
- " label_id=label_id,\n",
- " fields=[\"id\", \"jsonResponse\", \"author.id\", \"labelType\", \"createdAt\", \"secondsToLabel\"],\n",
- " )\n",
- " )[0]\n",
- "\n",
- " label[\"authorId\"] = label[\"author\"][\"id\"]\n",
- " del label[\"author\"]\n",
- " return label"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "tags": []
- },
- "source": [
- "### Test the plugin run\n",
- "\n",
- "If you already have a test project with labels added, you can directly use the IDs of these labels (see the following cell). Otherwise, you can follow the *plugins_example.ipynb* notebook to create a new project and then upload an asset with an associated label."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "asset_id = \"\"\n",
- "label_id = \"\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "label = get_label(label_id=label_id, project_id=project_id)\n",
- "\n",
- "my_plugin_instance.on_submit(label=label, asset_id=asset_id)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Test the plugin run on Kili\n",
- "\n",
- "When you finish debugging the code, you may want to upload it directly into Kili.\n",
- "\n",
- "Note that you might get an error if the plugin name already exists in your Kili organization."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "path_to_plugin = \"path/to/my/plugin.py\"\n",
- "plugin_name = \"My first kili plugin\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from kili.exceptions import GraphQLError\n",
- "\n",
- "try:\n",
- " kili.upload_plugin(path_to_plugin, plugin_name)\n",
- "except GraphQLError as error:\n",
- " print(str(error))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Plugins must be activated in the project that you want them to run in. Be careful with production projects: your custom workflows or rules will also be applied"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "kili.activate_plugin_on_project(plugin_name, project_id=project_id)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Monitoring the plugin\n",
- "\n",
- "Plugin creation takes some time (around 5 minutes). The plugin will begin to run only after it's been fully created (if labeling events are to be triggered on this project).\n",
- "\n",
- "Additionally, you can get the logs of the runs:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "kili.get_plugin_logs(project_id=project_id, plugin_name=plugin_name)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You can set custom date rules for filtering your logs:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from datetime import date, datetime\n",
- "\n",
- "dt = date.today() # You can change this date if needed\n",
- "start_date = datetime.combine(dt, datetime.min.time())\n",
- "\n",
- "kili.get_plugin_logs(project_id=project_id, plugin_name=plugin_name, start_date=start_date)"
- ]
- },
- {
- "attachments": {},
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Managing your plugin\n",
- "\n",
- "There are several other methods to manage your plugins and their lifecycle. To find out more, check the plugins [tutorials](https://python-sdk-docs.kili-technology.com/latest/tutorials)."
- ]
- }
- ],
- "metadata": {
- "language_info": {
- "name": "python"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/recipes/plugins_example.ipynb b/recipes/plugins_example.ipynb
index 54043f0d7..5b0993dd2 100644
--- a/recipes/plugins_example.ipynb
+++ b/recipes/plugins_example.ipynb
@@ -169,9 +169,7 @@
"source": [
"This project has one job of bounding box creation with two categories.\n",
"\n",
- "With our plugin, we want to make sure that the labelers don't create more than one bounding box of category A.\n",
- "\n",
- "To iterate on the plugin code, you can refer to the plugins_development.ipynb notebook."
+ "With our plugin, we want to make sure that the labelers don't create more than one bounding box of category A.\n"
]
},
{
diff --git a/recipes/plugins_library/README.md b/recipes/plugins_library/README.md
index 7fbbe6203..e8db5aa2c 100644
--- a/recipes/plugins_library/README.md
+++ b/recipes/plugins_library/README.md
@@ -4,7 +4,7 @@
In this section you can find multiple examples of use-cases where our system of plugins can help you in the Kili projects.
-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.
+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_example.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).
diff --git a/src/kili/entrypoints/mutations/plugins/__init__.py b/src/kili/entrypoints/mutations/plugins/__init__.py
index fa8fed1af..c39d13825 100644
--- a/src/kili/entrypoints/mutations/plugins/__init__.py
+++ b/src/kili/entrypoints/mutations/plugins/__init__.py
@@ -110,7 +110,10 @@ def create_webhook(
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."
+ f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use"
+ " event_matcher instead. To replace onSubmit and onReview, use"
+ " 'labels.created.submit' and 'labels.created.review' event_matchers"
+ " respectively."
)
return WebhookUploader(
@@ -158,7 +161,10 @@ def update_webhook(
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."
+ f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use"
+ " event_matcher instead. To replace onSubmit and onReview, use"
+ " 'labels.created.submit' and 'labels.created.review' event_matchers"
+ " respectively."
)
return WebhookUploader(
diff --git a/src/kili/services/plugins/model.py b/src/kili/services/plugins/model.py
index 4d6d7f366..9981efac3 100644
--- a/src/kili/services/plugins/model.py
+++ b/src/kili/services/plugins/model.py
@@ -16,15 +16,14 @@ class PluginCore:
Implements:
- on_submit(self, label: Dict, asset_id: str)
- on_review(self, label: Dict, asset_id: str)
on_custom_interface_click(self, label: Dict, asset_id: str)
on_project_updated(self, settings_updated: List[Dict])
on_send_back_to_queue(self, asset_id: str)
on_event(self, payload: Dict)
!!! warning
- if using a custom init, be sure to call super().__init__()
+ - if using a custom init, be sure to call super().__init__()
+ - `on_submit` and `on_review` are deprecated, prefer `on_event` instead.
"""
logger: logging.Logger
@@ -66,6 +65,12 @@ def on_submit(self, label: Dict, asset_id: str):
else:
self.kili.send_back_to_queue(asset_ids=[asset_id])
```
+
+ !!! warning
+ This method is deprecated. Use `on_event` instead.
+
+ You can have the same behavior using `on_event` and
+ checking for the `'labels.created.submit'` event in payload.
"""
# pylint: disable=unused-argument
self.logger.warning("Method Deprecated. Use on_event instead.")
@@ -95,6 +100,11 @@ def on_review(self, label: Dict, asset_id: str):
else:
self.kili.send_back_to_queue(asset_ids=[asset_id])
```
+
+ !!! warning
+ This method is deprecated. Use `on_event` instead.
+ You can have the same behavior using `on_event`
+ and checking for the `'labels.created.review'` event in payload.
"""
# pylint: disable=unused-argument
self.logger.warning("Method Deprecated. Use on_event instead.")
diff --git a/src/kili/services/plugins/upload.py b/src/kili/services/plugins/upload.py
index 696d3748b..5490096b5 100644
--- a/src/kili/services/plugins/upload.py
+++ b/src/kili/services/plugins/upload.py
@@ -204,7 +204,10 @@ def _retrieve_plugin_src(self) -> list[Path]:
handler in DEPRECATED_HANDLERS for handler in handler_types
):
raise ValueError(
- f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead."
+ f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use"
+ " event_matcher instead. To replace onSubmit and onReview, use"
+ " 'labels.created.submit' and 'labels.created.review' event_matchers"
+ " respectively."
)
self.handler_types = handler_types
@@ -230,7 +233,10 @@ def _retrieve_plugin_src(self) -> list[Path]:
handler in DEPRECATED_HANDLERS for handler in handler_types
):
raise ValueError(
- f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use event_matcher instead."
+ f"The handler_types {DEPRECATED_HANDLERS} are deprecated. Please use"
+ " event_matcher instead. To replace onSubmit and onReview, use"
+ " 'labels.created.submit' and 'labels.created.review' event_matchers"
+ " respectively."
)
self.handler_types = handler_types