django-action-triggers


Namedjango-action-triggers JSON
Version 0.5.1 PyPI version JSON
download
home_pagehttps://github.com/Salaah01/django-action-triggers
SummaryA Django library for asynchronously triggering actions in response to database changes. It supports integration with webhooks, message brokers (e.g., Kafka, RabbitMQ), and can trigger other processes, including AWS Lambda functions.
upload_time2024-10-10 00:50:21
maintainerNone
docs_urlNone
authorSalaah Amin
requires_python<3.13,>=3.8
licenseMIT
keywords django signals actions triggers webhooks kafka rabbitmq async asyncio aiohttp aiokafka aio-pika message-broker message-queue message-bus pubsub event-driven event-driven
VCS
bugtrack_url
requirements aio-pika aiohappyeyeballs aiohttp aioresponses aiormq aiosignal alabaster asgiref async-timeout attrs babel boto3 botocore build CacheControl cachetools certifi cffi chardet charset-normalizer cleo click colorama coverage crashtest cryptography Deprecated dill distlib Django django-coverage-plugin django-stubs django-stubs-ext djangorestframework dnslib dnspython docutils dulwich ecdsa fastjsonschema filelock frozenlist google-api-core google-auth google-cloud-pubsub googleapis-common-protos grpc-google-iam-v1 grpcio grpcio-status idna imagesize importlib_metadata iniconfig installer isort jaraco.classes jeepney Jinja2 jmespath keyring localstack localstack-core localstack-ext markdown-it-py MarkupSafe mdurl model-bakery more-itertools msgpack multidict mypy mypy-extensions opentelemetry-api opentelemetry-sdk opentelemetry-semantic-conventions packaging pamqp pexpect pkginfo platformdirs pluggy plux poetry poetry-core poetry-plugin-export proto-plus protobuf psutil psycopg2 ptyprocess pyaes pyasn1 pyasn1_modules pycparser Pygments pyotp pyproject-api pyproject_hooks pytest pytest-asyncio pytest-cov pytest-django python-dateutil python-dotenv python-jose PyYAML RapidFuzz redis requests requests-toolbelt rich rsa ruff s3transfer SecretStorage semver shellingham six snowballstemmer Sphinx sphinx-rtd-theme sphinxcontrib-applehelp sphinxcontrib-devhelp sphinxcontrib-htmlhelp sphinxcontrib-jquery sphinxcontrib-jsmath sphinxcontrib-qthelp sphinxcontrib-serializinghtml sqlparse tabulate tailer tomlkit tox trove-classifiers types-PyYAML typing_extensions urllib3 virtualenv wrapt yarl zipp
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# Django Action Triggers

![License: MIT](https://img.shields.io/badge/license-MIT-blue) [![PyPI version](https://badge.fury.io/py/django-action-triggers.svg)](https://badge.fury.io/py/django-action-triggers) [![codecov](https://codecov.io/github/Salaah01/django-action-triggers/graph/badge.svg?token=ROHNEE9D4X)](https://codecov.io/github/Salaah01/django-action-triggers) ![PyPI - Supported Python Versions](https://img.shields.io/pypi/pyversions/django-action-triggers) ![Supported Django Versions](https://img.shields.io/badge/django-3.2%20%7C%204.2%20%7C%205.1-blue)


## Table of Contents
- [Django Action Triggers](#django-action-triggers)
  - [Table of Contents](#table-of-contents)
  - [Description](#description)
  - [Why Use Django Action Triggers Over Django Signals?](#why-use-django-action-triggers-over-django-signals)
    - [How Django Action Triggers Helps](#how-django-action-triggers-helps)
    - [Built-in Integrations](#built-in-integrations)
    - [Key Benefits:](#key-benefits)
  - [Key Features](#key-features)
  - [Documentation](#documentation)
  - [Supported Message Brokers](#supported-message-brokers)
  - [Supported Actions](#supported-actions)
  - [Installation](#installation)
  - [Usage](#usage)
  - [Example Scenarios](#example-scenarios)
    - [Example 1: Webhook Trigger on User Creation/Update/Deletion](#example-1-webhook-trigger-on-user-creationupdatedeletion)
    - [Example 2: Webhooks and Message Queues on Product and Sale Creation/Update](#example-2-webhooks-and-message-queues-on-product-and-sale-creationupdate)
  - [Don't See What You're Looking For?](#dont-see-what-youre-looking-for)
  - [License](#license)


## Description

![Django Action Triggers Animation](./docs/source/_static/img/django-action-triggers-animation-dark.gif)

In Django, signals are a powerful tool for responding to changes in your models or other parts of the application. Typically, you define signals in a signals.py file, specifying actions to take when certain events occur, like saving or deleting an object. While this approach works well in many cases, it can have some limitations:

This application is highly flexible and can be configured via code or through the Django admin interface.

## Why Use Django Action Triggers Over Django Signals?

In Django, signals are typically hardcoded in a `signals.py` file, where you define logic like "if this happens, do that." While this works well for many cases, it introduces a few limitations:

- **Changes require code updates:** Adding or modifying signals requires changes to your codebase and redeployment.
- **Static and inflexible:** Anytime you need to modify, add, or remove signals, you have to manually edit the code and redeploy the application.
- **Maintenance overhead:** As your application grows, managing signals this way can make the code harder to maintain and scale.

### How Django Action Triggers Helps

Django Action Triggers builds on Django’s signals by offering more flexibility at runtime. It allows you to create, modify, or remove signals and actions dynamically—**without needing to change your code**. This can all be done through the **UI or API**, making it easier to manage triggers and actions as your application evolves.

With Django Action Triggers, you can:

- **Manage signals dynamically** without redeployment, using the admin interface or API.
- **Adjust workflows at runtime** to respond to new requirements or integrations.
- **Reduce the need for manual code changes** when setting up new signals or actions.

### Built-in Integrations

Django Action Triggers also includes **out-of-the-box support** for popular services such as **AWS SNS**, **RabbitMQ**, **Kafka**, and more. This allows you to easily send messages to these services, streamlining integrations without needing custom code.

### Key Benefits:

- **No code changes or redeploys needed:** Manage signals and actions entirely through the UI or API.
- **Flexibility at runtime:** Easily add, modify, or remove actions and triggers on the fly.
- **Built-in integrations:** Connect seamlessly with external services like AWS SNS, Kafka, Redis, and more, saving time on implementation.

In summary, Django Action Triggers provides a **dynamic**, **maintainable** and **scalable** way to manage actions triggered by signals. It reduces the need for constant code changes while offering simple integration with popular external services.

## Key Features

- **Database-Driven Triggers**: Automatically trigger actions based on model events (e.g., save, delete).
- **Webhook Integration**: Send HTTP requests to external services when triggers are activated.
- **Message Broker Integration**: Send messages to messaging brokers like Kafka and RabbitMQ.
- **Actions Integration**: Trigger actions like AWS Lambda functions based on model events.
- **Extensible**: Easily extend to support custom triggers and actions.
- **Secure Dynamic Configuration**: Dynamically set values at runtime for secure and flexible configuration.

## Documentation

For detailed documentation, including setup, configuration options, API specifications, and more examples, please refer to the [official documentation](https://django-action-triggers.readthedocs.io/en/latest/).

## Supported Message Brokers

* Kafka
* RabbitMQ
* Redis
* AWS SQS (Amazon Simple Queue Service)
* AWS SNS (Amazon Simple Notification Service)
* GCP Pub/Sub (Google Cloud Pub/Sub)

## Supported Actions

* AWS Lambda

Need support for another message broker or action? Please submit a feature request on the [GitHub repository](https://github.com/Salaah01/django-action-triggers/issues).

## Installation

To install the package, run the following command:

```bash
pip install django-action-triggers
```

This command above will only install the base library, in order to support
specific integrations, you can install the following extras:

| Integration | Installation Command                           |
| ----------- | ---------------------------------------------- |
| RabbitMQ    | `pip install django-action-triggers[rabbitmq]` |
| Kafka       | `pip install django-action-triggers[kafka]`    |
| Redis       | `pip install django-action-triggers[redis]`    |
| AWS SQS     | `pip install django-action-triggers[aws]`      |
| AWS SNS     | `pip install django-action-triggers[aws]`      |
| GCP Pub/Sub | `pip install django-action-triggers[gcp]`      |
| AWS Lambda  | `pip install django-action-triggers[aws]`      |
| Webhooks    | `pip install django-action-triggers[webhooks]` |

Then, add the following to your `INSTALLED_APPS` in your Django settings:

```python
INSTALLED_APPS = [
    ...
    'action_triggers',
    ...
]
```

If you plan on using the API, add the following to your `urls.py`:

```python
from django.urls import path, include

urlpatterns = [
    ...
    path('api/action-triggers/', include('action_triggers.urls')),
    ...
]
```

## Usage

Once installed, you can create triggers and actions using the Django admin interface or programmatically through the API.

For detailed usage instructions, configuration options, and examples, please refer to the [official documentation](https://django-action-triggers.readthedocs.io/en/latest/).

## Example Scenarios

### Example 1: Webhook Trigger on User Creation/Update/Deletion

Trigger a webhook whenever a `User` model is created, updated, or deleted:

```json
{
  "config_signals": [
    {"signal": "post_save"},
    {"signal": "post_delete"}
  ],
  "content_types": [
    {
      "app_label": "auth",
      "model_name": "User"
    }
  ],
  "webhooks": [
    {
      "url": "https://my-webhook.com",
      "http_method": "POST",
      "headers": {
        "Authorization": "Bearer {{ myapp.utils.get_token }}"
      },
      "timeout_secs": 22.5
    }
  ],
  "active": true
}

```

### Example 2: Webhooks and Message Queues on Product and Sale Creation/Update

Trigger multiple webhooks and add messages to queues when `Product` or `Sale` models are created or updated:

```json
{
  "config_signals": [
    {"signal": "post_save"}
  ],
  "content_types": [
    {
      "app_label": "myapp",
      "model_name": "Product"
    },
    {
      "app_label": "myapp",
      "model_name": "Sale"
    }
  ],
  "webhooks": [
    {
      "url": "https://my-webhook.com",
      "http_method": "POST",
      "headers": {
        "Authorization": "Bearer {{ myapp.utils.get_token }}"
      },
      "timeout_secs": 10.5
    },
    {
      "url": "https://my-other-webhook.com",
      "http_method": "POST",
      "headers": {
        "Authorization": "Bearer {{ myapp.utils.get_token }}"
      }
    }
  ],
  "msg_broker_queues": [
    {
      "name": "my-msg-broker-config",
      "parameters": {
        "product_id": "{{ myapp.utils.get_product_id }}"
      },
      "timeout_secs": 2.5
    },
    {
      "name": "my-other-msg-broker-config",
      "parameters": {
        "sale_id": "{{ myapp.utils.get_sale_id }}"
      }
    }
  ],
  "active": true
}
```

## Don't See What You're Looking For?

If you have any feature requests or issues, please submit them to the [GitHub repository](https://github.com/Salaah01/django-action-triggers/issues). This also helps us prioritise new features and bug fixes.

## License

This project is licensed under the MIT License - see [LICENSE](./LICENSE) file for details.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Salaah01/django-action-triggers",
    "name": "django-action-triggers",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.13,>=3.8",
    "maintainer_email": null,
    "keywords": "django, signals, actions, triggers, webhooks, kafka, rabbitmq, async, asyncio, aiohttp, aiokafka, aio-pika, message-broker, message-queue, message-bus, pubsub, event-driven, event-driven",
    "author": "Salaah Amin",
    "author_email": "salaah01@users.noreply.github.com",
    "download_url": "https://files.pythonhosted.org/packages/aa/c0/73a28ddca32bd7c87949b9c86cbc65d73c55444b80c390c9efee211351c8/django_action_triggers-0.5.1.tar.gz",
    "platform": null,
    "description": "\n# Django Action Triggers\n\n![License: MIT](https://img.shields.io/badge/license-MIT-blue) [![PyPI version](https://badge.fury.io/py/django-action-triggers.svg)](https://badge.fury.io/py/django-action-triggers) [![codecov](https://codecov.io/github/Salaah01/django-action-triggers/graph/badge.svg?token=ROHNEE9D4X)](https://codecov.io/github/Salaah01/django-action-triggers) ![PyPI - Supported Python Versions](https://img.shields.io/pypi/pyversions/django-action-triggers) ![Supported Django Versions](https://img.shields.io/badge/django-3.2%20%7C%204.2%20%7C%205.1-blue)\n\n\n## Table of Contents\n- [Django Action Triggers](#django-action-triggers)\n  - [Table of Contents](#table-of-contents)\n  - [Description](#description)\n  - [Why Use Django Action Triggers Over Django Signals?](#why-use-django-action-triggers-over-django-signals)\n    - [How Django Action Triggers Helps](#how-django-action-triggers-helps)\n    - [Built-in Integrations](#built-in-integrations)\n    - [Key Benefits:](#key-benefits)\n  - [Key Features](#key-features)\n  - [Documentation](#documentation)\n  - [Supported Message Brokers](#supported-message-brokers)\n  - [Supported Actions](#supported-actions)\n  - [Installation](#installation)\n  - [Usage](#usage)\n  - [Example Scenarios](#example-scenarios)\n    - [Example 1: Webhook Trigger on User Creation/Update/Deletion](#example-1-webhook-trigger-on-user-creationupdatedeletion)\n    - [Example 2: Webhooks and Message Queues on Product and Sale Creation/Update](#example-2-webhooks-and-message-queues-on-product-and-sale-creationupdate)\n  - [Don't See What You're Looking For?](#dont-see-what-youre-looking-for)\n  - [License](#license)\n\n\n## Description\n\n![Django Action Triggers Animation](./docs/source/_static/img/django-action-triggers-animation-dark.gif)\n\nIn Django, signals are a powerful tool for responding to changes in your models or other parts of the application. Typically, you define signals in a signals.py file, specifying actions to take when certain events occur, like saving or deleting an object. While this approach works well in many cases, it can have some limitations:\n\nThis application is highly flexible and can be configured via code or through the Django admin interface.\n\n## Why Use Django Action Triggers Over Django Signals?\n\nIn Django, signals are typically hardcoded in a `signals.py` file, where you define logic like \"if this happens, do that.\" While this works well for many cases, it introduces a few limitations:\n\n- **Changes require code updates:** Adding or modifying signals requires changes to your codebase and redeployment.\n- **Static and inflexible:** Anytime you need to modify, add, or remove signals, you have to manually edit the code and redeploy the application.\n- **Maintenance overhead:** As your application grows, managing signals this way can make the code harder to maintain and scale.\n\n### How Django Action Triggers Helps\n\nDjango Action Triggers builds on Django\u2019s signals by offering more flexibility at runtime. It allows you to create, modify, or remove signals and actions dynamically\u2014**without needing to change your code**. This can all be done through the **UI or API**, making it easier to manage triggers and actions as your application evolves.\n\nWith Django Action Triggers, you can:\n\n- **Manage signals dynamically** without redeployment, using the admin interface or API.\n- **Adjust workflows at runtime** to respond to new requirements or integrations.\n- **Reduce the need for manual code changes** when setting up new signals or actions.\n\n### Built-in Integrations\n\nDjango Action Triggers also includes **out-of-the-box support** for popular services such as **AWS SNS**, **RabbitMQ**, **Kafka**, and more. This allows you to easily send messages to these services, streamlining integrations without needing custom code.\n\n### Key Benefits:\n\n- **No code changes or redeploys needed:** Manage signals and actions entirely through the UI or API.\n- **Flexibility at runtime:** Easily add, modify, or remove actions and triggers on the fly.\n- **Built-in integrations:** Connect seamlessly with external services like AWS SNS, Kafka, Redis, and more, saving time on implementation.\n\nIn summary, Django Action Triggers provides a **dynamic**, **maintainable** and **scalable** way to manage actions triggered by signals. It reduces the need for constant code changes while offering simple integration with popular external services.\n\n## Key Features\n\n- **Database-Driven Triggers**: Automatically trigger actions based on model events (e.g., save, delete).\n- **Webhook Integration**: Send HTTP requests to external services when triggers are activated.\n- **Message Broker Integration**: Send messages to messaging brokers like Kafka and RabbitMQ.\n- **Actions Integration**: Trigger actions like AWS Lambda functions based on model events.\n- **Extensible**: Easily extend to support custom triggers and actions.\n- **Secure Dynamic Configuration**: Dynamically set values at runtime for secure and flexible configuration.\n\n## Documentation\n\nFor detailed documentation, including setup, configuration options, API specifications, and more examples, please refer to the [official documentation](https://django-action-triggers.readthedocs.io/en/latest/).\n\n## Supported Message Brokers\n\n* Kafka\n* RabbitMQ\n* Redis\n* AWS SQS (Amazon Simple Queue Service)\n* AWS SNS (Amazon Simple Notification Service)\n* GCP Pub/Sub (Google Cloud Pub/Sub)\n\n## Supported Actions\n\n* AWS Lambda\n\nNeed support for another message broker or action? Please submit a feature request on the [GitHub repository](https://github.com/Salaah01/django-action-triggers/issues).\n\n## Installation\n\nTo install the package, run the following command:\n\n```bash\npip install django-action-triggers\n```\n\nThis command above will only install the base library, in order to support\nspecific integrations, you can install the following extras:\n\n| Integration | Installation Command                           |\n| ----------- | ---------------------------------------------- |\n| RabbitMQ    | `pip install django-action-triggers[rabbitmq]` |\n| Kafka       | `pip install django-action-triggers[kafka]`    |\n| Redis       | `pip install django-action-triggers[redis]`    |\n| AWS SQS     | `pip install django-action-triggers[aws]`      |\n| AWS SNS     | `pip install django-action-triggers[aws]`      |\n| GCP Pub/Sub | `pip install django-action-triggers[gcp]`      |\n| AWS Lambda  | `pip install django-action-triggers[aws]`      |\n| Webhooks    | `pip install django-action-triggers[webhooks]` |\n\nThen, add the following to your `INSTALLED_APPS` in your Django settings:\n\n```python\nINSTALLED_APPS = [\n    ...\n    'action_triggers',\n    ...\n]\n```\n\nIf you plan on using the API, add the following to your `urls.py`:\n\n```python\nfrom django.urls import path, include\n\nurlpatterns = [\n    ...\n    path('api/action-triggers/', include('action_triggers.urls')),\n    ...\n]\n```\n\n## Usage\n\nOnce installed, you can create triggers and actions using the Django admin interface or programmatically through the API.\n\nFor detailed usage instructions, configuration options, and examples, please refer to the [official documentation](https://django-action-triggers.readthedocs.io/en/latest/).\n\n## Example Scenarios\n\n### Example 1: Webhook Trigger on User Creation/Update/Deletion\n\nTrigger a webhook whenever a `User` model is created, updated, or deleted:\n\n```json\n{\n  \"config_signals\": [\n    {\"signal\": \"post_save\"},\n    {\"signal\": \"post_delete\"}\n  ],\n  \"content_types\": [\n    {\n      \"app_label\": \"auth\",\n      \"model_name\": \"User\"\n    }\n  ],\n  \"webhooks\": [\n    {\n      \"url\": \"https://my-webhook.com\",\n      \"http_method\": \"POST\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {{ myapp.utils.get_token }}\"\n      },\n      \"timeout_secs\": 22.5\n    }\n  ],\n  \"active\": true\n}\n\n```\n\n### Example 2: Webhooks and Message Queues on Product and Sale Creation/Update\n\nTrigger multiple webhooks and add messages to queues when `Product` or `Sale` models are created or updated:\n\n```json\n{\n  \"config_signals\": [\n    {\"signal\": \"post_save\"}\n  ],\n  \"content_types\": [\n    {\n      \"app_label\": \"myapp\",\n      \"model_name\": \"Product\"\n    },\n    {\n      \"app_label\": \"myapp\",\n      \"model_name\": \"Sale\"\n    }\n  ],\n  \"webhooks\": [\n    {\n      \"url\": \"https://my-webhook.com\",\n      \"http_method\": \"POST\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {{ myapp.utils.get_token }}\"\n      },\n      \"timeout_secs\": 10.5\n    },\n    {\n      \"url\": \"https://my-other-webhook.com\",\n      \"http_method\": \"POST\",\n      \"headers\": {\n        \"Authorization\": \"Bearer {{ myapp.utils.get_token }}\"\n      }\n    }\n  ],\n  \"msg_broker_queues\": [\n    {\n      \"name\": \"my-msg-broker-config\",\n      \"parameters\": {\n        \"product_id\": \"{{ myapp.utils.get_product_id }}\"\n      },\n      \"timeout_secs\": 2.5\n    },\n    {\n      \"name\": \"my-other-msg-broker-config\",\n      \"parameters\": {\n        \"sale_id\": \"{{ myapp.utils.get_sale_id }}\"\n      }\n    }\n  ],\n  \"active\": true\n}\n```\n\n## Don't See What You're Looking For?\n\nIf you have any feature requests or issues, please submit them to the [GitHub repository](https://github.com/Salaah01/django-action-triggers/issues). This also helps us prioritise new features and bug fixes.\n\n## License\n\nThis project is licensed under the MIT License - see [LICENSE](./LICENSE) file for details.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Django library for asynchronously triggering actions in response to database changes. It supports integration with webhooks, message brokers (e.g., Kafka, RabbitMQ), and can trigger other processes, including AWS Lambda functions.",
    "version": "0.5.1",
    "project_urls": {
        "Documentation": "https://django-action-triggers.readthedocs.io/en/latest/",
        "Homepage": "https://github.com/Salaah01/django-action-triggers",
        "Repository": "https://github.com/Salaah01/django-action-triggers"
    },
    "split_keywords": [
        "django",
        " signals",
        " actions",
        " triggers",
        " webhooks",
        " kafka",
        " rabbitmq",
        " async",
        " asyncio",
        " aiohttp",
        " aiokafka",
        " aio-pika",
        " message-broker",
        " message-queue",
        " message-bus",
        " pubsub",
        " event-driven",
        " event-driven"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "45a9e6e6e8f6a62f2165a8d578b89c60d2cc53834181088b38aa17b0c5633baa",
                "md5": "a1d9cb2e03df5e27393694a99854d529",
                "sha256": "aed0d04ece05afe1eb2fc6658aa180265addd036a0231b20fd91de684ca607b8"
            },
            "downloads": -1,
            "filename": "django_action_triggers-0.5.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a1d9cb2e03df5e27393694a99854d529",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.13,>=3.8",
            "size": 46337,
            "upload_time": "2024-10-10T00:50:19",
            "upload_time_iso_8601": "2024-10-10T00:50:19.234734Z",
            "url": "https://files.pythonhosted.org/packages/45/a9/e6e6e8f6a62f2165a8d578b89c60d2cc53834181088b38aa17b0c5633baa/django_action_triggers-0.5.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "aac073a28ddca32bd7c87949b9c86cbc65d73c55444b80c390c9efee211351c8",
                "md5": "1f83a5c2b759fd80c6b5b6aac619513d",
                "sha256": "166e06504ca8d2c117074a00b1460d0db4293a522ebef6a668e71e2eff419888"
            },
            "downloads": -1,
            "filename": "django_action_triggers-0.5.1.tar.gz",
            "has_sig": false,
            "md5_digest": "1f83a5c2b759fd80c6b5b6aac619513d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.13,>=3.8",
            "size": 31567,
            "upload_time": "2024-10-10T00:50:21",
            "upload_time_iso_8601": "2024-10-10T00:50:21.203075Z",
            "url": "https://files.pythonhosted.org/packages/aa/c0/73a28ddca32bd7c87949b9c86cbc65d73c55444b80c390c9efee211351c8/django_action_triggers-0.5.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-10 00:50:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Salaah01",
    "github_project": "django-action-triggers",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "aio-pika",
            "specs": [
                [
                    "==",
                    "9.4.3"
                ]
            ]
        },
        {
            "name": "aiohappyeyeballs",
            "specs": [
                [
                    "==",
                    "2.4.0"
                ]
            ]
        },
        {
            "name": "aiohttp",
            "specs": [
                [
                    "==",
                    "3.10.5"
                ]
            ]
        },
        {
            "name": "aioresponses",
            "specs": [
                [
                    "==",
                    "0.7.6"
                ]
            ]
        },
        {
            "name": "aiormq",
            "specs": [
                [
                    "==",
                    "6.8.1"
                ]
            ]
        },
        {
            "name": "aiosignal",
            "specs": [
                [
                    "==",
                    "1.3.1"
                ]
            ]
        },
        {
            "name": "alabaster",
            "specs": [
                [
                    "==",
                    "0.7.16"
                ]
            ]
        },
        {
            "name": "asgiref",
            "specs": [
                [
                    "==",
                    "3.8.1"
                ]
            ]
        },
        {
            "name": "async-timeout",
            "specs": [
                [
                    "==",
                    "4.0.3"
                ]
            ]
        },
        {
            "name": "attrs",
            "specs": [
                [
                    "==",
                    "24.2.0"
                ]
            ]
        },
        {
            "name": "babel",
            "specs": [
                [
                    "==",
                    "2.16.0"
                ]
            ]
        },
        {
            "name": "boto3",
            "specs": [
                [
                    "==",
                    "1.35.33"
                ]
            ]
        },
        {
            "name": "botocore",
            "specs": [
                [
                    "==",
                    "1.35.33"
                ]
            ]
        },
        {
            "name": "build",
            "specs": [
                [
                    "==",
                    "1.2.2.post1"
                ]
            ]
        },
        {
            "name": "CacheControl",
            "specs": [
                [
                    "==",
                    "0.14.0"
                ]
            ]
        },
        {
            "name": "cachetools",
            "specs": [
                [
                    "==",
                    "5.5.0"
                ]
            ]
        },
        {
            "name": "certifi",
            "specs": [
                [
                    "==",
                    "2024.8.30"
                ]
            ]
        },
        {
            "name": "cffi",
            "specs": [
                [
                    "==",
                    "1.17.1"
                ]
            ]
        },
        {
            "name": "chardet",
            "specs": [
                [
                    "==",
                    "5.2.0"
                ]
            ]
        },
        {
            "name": "charset-normalizer",
            "specs": [
                [
                    "==",
                    "3.3.2"
                ]
            ]
        },
        {
            "name": "cleo",
            "specs": [
                [
                    "==",
                    "2.1.0"
                ]
            ]
        },
        {
            "name": "click",
            "specs": [
                [
                    "==",
                    "8.1.7"
                ]
            ]
        },
        {
            "name": "colorama",
            "specs": [
                [
                    "==",
                    "0.4.6"
                ]
            ]
        },
        {
            "name": "coverage",
            "specs": [
                [
                    "==",
                    "7.6.1"
                ]
            ]
        },
        {
            "name": "crashtest",
            "specs": [
                [
                    "==",
                    "0.4.1"
                ]
            ]
        },
        {
            "name": "cryptography",
            "specs": [
                [
                    "==",
                    "43.0.1"
                ]
            ]
        },
        {
            "name": "Deprecated",
            "specs": [
                [
                    "==",
                    "1.2.14"
                ]
            ]
        },
        {
            "name": "dill",
            "specs": [
                [
                    "==",
                    "0.3.6"
                ]
            ]
        },
        {
            "name": "distlib",
            "specs": [
                [
                    "==",
                    "0.3.8"
                ]
            ]
        },
        {
            "name": "Django",
            "specs": [
                [
                    "==",
                    "4.2.16"
                ]
            ]
        },
        {
            "name": "django-coverage-plugin",
            "specs": [
                [
                    "==",
                    "3.1.0"
                ]
            ]
        },
        {
            "name": "django-stubs",
            "specs": [
                [
                    "==",
                    "5.0.4"
                ]
            ]
        },
        {
            "name": "django-stubs-ext",
            "specs": [
                [
                    "==",
                    "5.0.4"
                ]
            ]
        },
        {
            "name": "djangorestframework",
            "specs": [
                [
                    "==",
                    "3.15.2"
                ]
            ]
        },
        {
            "name": "dnslib",
            "specs": [
                [
                    "==",
                    "0.9.25"
                ]
            ]
        },
        {
            "name": "dnspython",
            "specs": [
                [
                    "==",
                    "2.6.1"
                ]
            ]
        },
        {
            "name": "docutils",
            "specs": [
                [
                    "==",
                    "0.20.1"
                ]
            ]
        },
        {
            "name": "dulwich",
            "specs": [
                [
                    "==",
                    "0.21.7"
                ]
            ]
        },
        {
            "name": "ecdsa",
            "specs": [
                [
                    "==",
                    "0.19.0"
                ]
            ]
        },
        {
            "name": "fastjsonschema",
            "specs": [
                [
                    "==",
                    "2.20.0"
                ]
            ]
        },
        {
            "name": "filelock",
            "specs": [
                [
                    "==",
                    "3.16.1"
                ]
            ]
        },
        {
            "name": "frozenlist",
            "specs": [
                [
                    "==",
                    "1.4.1"
                ]
            ]
        },
        {
            "name": "google-api-core",
            "specs": [
                [
                    "==",
                    "2.20.0"
                ]
            ]
        },
        {
            "name": "google-auth",
            "specs": [
                [
                    "==",
                    "2.35.0"
                ]
            ]
        },
        {
            "name": "google-cloud-pubsub",
            "specs": [
                [
                    "==",
                    "2.25.2"
                ]
            ]
        },
        {
            "name": "googleapis-common-protos",
            "specs": [
                [
                    "==",
                    "1.65.0"
                ]
            ]
        },
        {
            "name": "grpc-google-iam-v1",
            "specs": [
                [
                    "==",
                    "0.13.1"
                ]
            ]
        },
        {
            "name": "grpcio",
            "specs": [
                [
                    "==",
                    "1.66.2"
                ]
            ]
        },
        {
            "name": "grpcio-status",
            "specs": [
                [
                    "==",
                    "1.66.2"
                ]
            ]
        },
        {
            "name": "idna",
            "specs": [
                [
                    "==",
                    "3.10"
                ]
            ]
        },
        {
            "name": "imagesize",
            "specs": [
                [
                    "==",
                    "1.4.1"
                ]
            ]
        },
        {
            "name": "importlib_metadata",
            "specs": [
                [
                    "==",
                    "8.4.0"
                ]
            ]
        },
        {
            "name": "iniconfig",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "installer",
            "specs": [
                [
                    "==",
                    "0.7.0"
                ]
            ]
        },
        {
            "name": "isort",
            "specs": [
                [
                    "==",
                    "5.13.2"
                ]
            ]
        },
        {
            "name": "jaraco.classes",
            "specs": [
                [
                    "==",
                    "3.4.0"
                ]
            ]
        },
        {
            "name": "jeepney",
            "specs": [
                [
                    "==",
                    "0.8.0"
                ]
            ]
        },
        {
            "name": "Jinja2",
            "specs": [
                [
                    "==",
                    "3.1.4"
                ]
            ]
        },
        {
            "name": "jmespath",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "keyring",
            "specs": [
                [
                    "==",
                    "24.3.1"
                ]
            ]
        },
        {
            "name": "localstack",
            "specs": [
                [
                    "==",
                    "3.7.1"
                ]
            ]
        },
        {
            "name": "localstack-core",
            "specs": [
                [
                    "==",
                    "3.7.1"
                ]
            ]
        },
        {
            "name": "localstack-ext",
            "specs": [
                [
                    "==",
                    "3.7.1"
                ]
            ]
        },
        {
            "name": "markdown-it-py",
            "specs": [
                [
                    "==",
                    "3.0.0"
                ]
            ]
        },
        {
            "name": "MarkupSafe",
            "specs": [
                [
                    "==",
                    "2.1.5"
                ]
            ]
        },
        {
            "name": "mdurl",
            "specs": [
                [
                    "==",
                    "0.1.2"
                ]
            ]
        },
        {
            "name": "model-bakery",
            "specs": [
                [
                    "==",
                    "1.19.5"
                ]
            ]
        },
        {
            "name": "more-itertools",
            "specs": [
                [
                    "==",
                    "10.5.0"
                ]
            ]
        },
        {
            "name": "msgpack",
            "specs": [
                [
                    "==",
                    "1.1.0"
                ]
            ]
        },
        {
            "name": "multidict",
            "specs": [
                [
                    "==",
                    "6.0.5"
                ]
            ]
        },
        {
            "name": "mypy",
            "specs": [
                [
                    "==",
                    "1.11.2"
                ]
            ]
        },
        {
            "name": "mypy-extensions",
            "specs": [
                [
                    "==",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "opentelemetry-api",
            "specs": [
                [
                    "==",
                    "1.27.0"
                ]
            ]
        },
        {
            "name": "opentelemetry-sdk",
            "specs": [
                [
                    "==",
                    "1.27.0"
                ]
            ]
        },
        {
            "name": "opentelemetry-semantic-conventions",
            "specs": [
                [
                    "==",
                    "0.48b0"
                ]
            ]
        },
        {
            "name": "packaging",
            "specs": [
                [
                    "==",
                    "24.1"
                ]
            ]
        },
        {
            "name": "pamqp",
            "specs": [
                [
                    "==",
                    "3.3.0"
                ]
            ]
        },
        {
            "name": "pexpect",
            "specs": [
                [
                    "==",
                    "4.9.0"
                ]
            ]
        },
        {
            "name": "pkginfo",
            "specs": [
                [
                    "==",
                    "1.11.1"
                ]
            ]
        },
        {
            "name": "platformdirs",
            "specs": [
                [
                    "==",
                    "4.3.6"
                ]
            ]
        },
        {
            "name": "pluggy",
            "specs": [
                [
                    "==",
                    "1.5.0"
                ]
            ]
        },
        {
            "name": "plux",
            "specs": [
                [
                    "==",
                    "1.11.1"
                ]
            ]
        },
        {
            "name": "poetry",
            "specs": [
                [
                    "==",
                    "1.8.3"
                ]
            ]
        },
        {
            "name": "poetry-core",
            "specs": [
                [
                    "==",
                    "1.9.0"
                ]
            ]
        },
        {
            "name": "poetry-plugin-export",
            "specs": [
                [
                    "==",
                    "1.8.0"
                ]
            ]
        },
        {
            "name": "proto-plus",
            "specs": [
                [
                    "==",
                    "1.24.0"
                ]
            ]
        },
        {
            "name": "protobuf",
            "specs": [
                [
                    "==",
                    "5.28.2"
                ]
            ]
        },
        {
            "name": "psutil",
            "specs": [
                [
                    "==",
                    "6.0.0"
                ]
            ]
        },
        {
            "name": "psycopg2",
            "specs": [
                [
                    "==",
                    "2.9.9"
                ]
            ]
        },
        {
            "name": "ptyprocess",
            "specs": [
                [
                    "==",
                    "0.7.0"
                ]
            ]
        },
        {
            "name": "pyaes",
            "specs": [
                [
                    "==",
                    "1.6.1"
                ]
            ]
        },
        {
            "name": "pyasn1",
            "specs": [
                [
                    "==",
                    "0.6.0"
                ]
            ]
        },
        {
            "name": "pyasn1_modules",
            "specs": [
                [
                    "==",
                    "0.4.1"
                ]
            ]
        },
        {
            "name": "pycparser",
            "specs": [
                [
                    "==",
                    "2.22"
                ]
            ]
        },
        {
            "name": "Pygments",
            "specs": [
                [
                    "==",
                    "2.18.0"
                ]
            ]
        },
        {
            "name": "pyotp",
            "specs": [
                [
                    "==",
                    "2.9.0"
                ]
            ]
        },
        {
            "name": "pyproject-api",
            "specs": [
                [
                    "==",
                    "1.8.0"
                ]
            ]
        },
        {
            "name": "pyproject_hooks",
            "specs": [
                [
                    "==",
                    "1.2.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "8.3.3"
                ]
            ]
        },
        {
            "name": "pytest-asyncio",
            "specs": [
                [
                    "==",
                    "0.24.0"
                ]
            ]
        },
        {
            "name": "pytest-cov",
            "specs": [
                [
                    "==",
                    "5.0.0"
                ]
            ]
        },
        {
            "name": "pytest-django",
            "specs": [
                [
                    "==",
                    "4.9.0"
                ]
            ]
        },
        {
            "name": "python-dateutil",
            "specs": [
                [
                    "==",
                    "2.9.0.post0"
                ]
            ]
        },
        {
            "name": "python-dotenv",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "python-jose",
            "specs": [
                [
                    "==",
                    "3.3.0"
                ]
            ]
        },
        {
            "name": "PyYAML",
            "specs": [
                [
                    "==",
                    "6.0.2"
                ]
            ]
        },
        {
            "name": "RapidFuzz",
            "specs": [
                [
                    "==",
                    "3.10.0"
                ]
            ]
        },
        {
            "name": "redis",
            "specs": [
                [
                    "==",
                    "5.0.8"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    "==",
                    "2.32.3"
                ]
            ]
        },
        {
            "name": "requests-toolbelt",
            "specs": [
                [
                    "==",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "rich",
            "specs": [
                [
                    "==",
                    "13.8.0"
                ]
            ]
        },
        {
            "name": "rsa",
            "specs": [
                [
                    "==",
                    "4.9"
                ]
            ]
        },
        {
            "name": "ruff",
            "specs": [
                [
                    "==",
                    "0.6.9"
                ]
            ]
        },
        {
            "name": "s3transfer",
            "specs": [
                [
                    "==",
                    "0.10.2"
                ]
            ]
        },
        {
            "name": "SecretStorage",
            "specs": [
                [
                    "==",
                    "3.3.3"
                ]
            ]
        },
        {
            "name": "semver",
            "specs": [
                [
                    "==",
                    "3.0.2"
                ]
            ]
        },
        {
            "name": "shellingham",
            "specs": [
                [
                    "==",
                    "1.5.4"
                ]
            ]
        },
        {
            "name": "six",
            "specs": [
                [
                    "==",
                    "1.16.0"
                ]
            ]
        },
        {
            "name": "snowballstemmer",
            "specs": [
                [
                    "==",
                    "2.2.0"
                ]
            ]
        },
        {
            "name": "Sphinx",
            "specs": [
                [
                    "==",
                    "7.4.7"
                ]
            ]
        },
        {
            "name": "sphinx-rtd-theme",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-applehelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-devhelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-htmlhelp",
            "specs": [
                [
                    "==",
                    "2.1.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-jquery",
            "specs": [
                [
                    "==",
                    "4.1"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-jsmath",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-qthelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-serializinghtml",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sqlparse",
            "specs": [
                [
                    "==",
                    "0.5.1"
                ]
            ]
        },
        {
            "name": "tabulate",
            "specs": [
                [
                    "==",
                    "0.9.0"
                ]
            ]
        },
        {
            "name": "tailer",
            "specs": [
                [
                    "==",
                    "0.4.1"
                ]
            ]
        },
        {
            "name": "tomlkit",
            "specs": [
                [
                    "==",
                    "0.13.2"
                ]
            ]
        },
        {
            "name": "tox",
            "specs": [
                [
                    "==",
                    "4.21.2"
                ]
            ]
        },
        {
            "name": "trove-classifiers",
            "specs": [
                [
                    "==",
                    "2024.9.12"
                ]
            ]
        },
        {
            "name": "types-PyYAML",
            "specs": [
                [
                    "==",
                    "6.0.12.20240808"
                ]
            ]
        },
        {
            "name": "typing_extensions",
            "specs": [
                [
                    "==",
                    "4.12.2"
                ]
            ]
        },
        {
            "name": "urllib3",
            "specs": [
                [
                    "==",
                    "2.2.3"
                ]
            ]
        },
        {
            "name": "virtualenv",
            "specs": [
                [
                    "==",
                    "20.26.6"
                ]
            ]
        },
        {
            "name": "wrapt",
            "specs": [
                [
                    "==",
                    "1.16.0"
                ]
            ]
        },
        {
            "name": "yarl",
            "specs": [
                [
                    "==",
                    "1.9.11"
                ]
            ]
        },
        {
            "name": "zipp",
            "specs": [
                [
                    "==",
                    "3.20.1"
                ]
            ]
        }
    ],
    "tox": true,
    "lcname": "django-action-triggers"
}
        
Elapsed time: 3.73798s