daffi


Namedaffi JSON
Version 2.2.1 PyPI version JSON
download
home_pageNone
SummaryDaffi is fast, simple and lightweight library for inter process communication
upload_time2023-06-10 12:30:17
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords async distributed grpc job python queue rpc stream task
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1> 
    <img src="https://600apples.github.io/dafi/images/logo.png"
    width="40"
    height="40"
    style="float: left;">
    Daffi
</h1>


![test and validate](https://github.com/600apples/dafi/actions/workflows/test_and_validate.yml/badge.svg)
![publish docs](https://github.com/600apples/dafi/actions/workflows/publish_docs.yml/badge.svg)
![coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/600apples/c64b2cee548575858e40834754432018/raw/covbadge.json)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
[![Linux](https://svgshare.com/i/Zhy.svg)](https://svgshare.com/i/Zhy.svg)
[![macOS](https://svgshare.com/i/ZjP.svg)](https://svgshare.com/i/ZjP.svg)
[![Downloads](https://static.pepy.tech/badge/daffi/month)](https://pepy.tech/project/daffi)

Daffi facilitates remote computing and enables remote procedure calls between multiple endpoints.
It supports many-to-many relationships between endpoints, allowing for seamless communication between distributed systems.
The library abstracts the complexities of remote computing and provides a user-friendly interface for initiating and managing remote procedure calls.
It also offers various features such as fault tolerance, load balancing, streaming and security, to ensure reliable and secure communication between endpoints.

Daffi comprises three primary classes:

- *Global* - Initialization entrypoint. Once *Global* object is initialized application can respond on remote requests and trigger remote callbacks itself.
- *Callback* - Represents a collection of methods encapsulated in a class inherited from *Callback* or a standalone function decorated with the *callback* decorator. These functions/methods can be triggered from another process.
- *Fetcher* - Represents a collection of methods encapsulated in a class inherited from *Fetcher* or a standalone function decorated with the *fetcher* decorator. These functions/methods serve as triggers for the corresponding callbacks defined in another process.

## Documentation

View full documentation at: [https://600apples.github.io/dafi/](https://600apples.github.io/dafi/)


## Basic example

You need to create two files `shopping_service.py` and `shopper.py`

`shopping_service.py` - represents a set of remote callbacks that can be triggered by a client application.

`shopper.py` - represents shopping_service client (fetcher)

#### Class based approach


`shopping_service.py`:
```python
import logging
from daffi import Global
from daffi.registry import Callback

logging.basicConfig(level=logging.INFO)


class ShoppingService(Callback):
    auto_init = True # class is automatically initialized, eliminating the need to manually create an object.

    def __post_init__(self):
        self.shopping_list = []

    def get_items(self):
        """Return all items that are currently present in shopping list"""
        return self.shopping_list

    def add_item(self, item):
        """Add new item to shopping list"""
        self.shopping_list.append(item)

    def clear_items(self):
        """Clear shopping list"""
        self.shopping_list.clear()


if __name__ == '__main__':
    Global(init_controller=True, host="localhost", port=8888).join()
```
(This script is complete, it should run "as is")


`shopper.py`:
```python
import logging
from daffi import Global
from daffi.decorators import alias
from daffi.registry import Fetcher

logging.basicConfig(level=logging.INFO)


class Shopper(Fetcher):
    """
    Note: Functions without a body are treated as proxies for remote callbacks.
    All arguments provided to this function will be sent to the remote service as-is.
    """

    def get_items(self):
        """Return all items that are currently present in shopping list."""
        pass

    def add_item(self, item):
        """Add new item to shopping list."""
        pass

    def clear_items(self):
        """Clear shopping list"""
        pass

    @alias("add_item")
    def add_many_items(self, *items):
        """
        Alias for `add_item` callback.
        This function shows streaming capabilities for transferring data from one service to another.
        """
        for item in items:
            yield item


if __name__ == '__main__':
    g = Global(host="localhost", port=8888)

    shopper = Shopper()
    items = shopper.get_items()
    print(items)

    shopper.add_item("orange")
    items = shopper.get_items()
    print(items)

    shopper.add_many_items("bread", "cheese")
    items = shopper.get_items()
    print(items)

    shopper.clear_items()
    items = shopper.get_items()
    print(items)

    g.stop()
```
(This script is complete, it should run "as is")

To check the full example, you need to execute two scripts in separate terminals

```bash
python3 shopping_service.py

...
INFO 2023-03-27 19:49:45 | controller[0x91adb83e] | Controller has been started successfully. Process identificator: '0x91adb83e'. Connection info: tcp: [ host '[::]', port: 8888 ]
INFO 2023-03-27 19:49:45 | node[0x91adb83e] | Node has been started successfully. Process identificator: '0x91adb83e'. Connection info: tcp: [ host '[::]', port: 8888 ]
```

```bash
python3 shopper.py

...
INFO 2023-03-27 19:53:15 | node[0xd7e5d488] | Node has been started successfully. Process identificator: '0xd7e5d488'. Connection info: tcp: [ host '[::]', port: 8888 ]
[]
['orange']
['orange', 'bread', 'cheese']
[]
INFO 2023-03-27 19:53:15 | node[0xd7e5d488] | Node stopped.
```

### Decorators base approach

`shopping_service.py`:
```python
import logging
from daffi import Global
from daffi.decorators import callback

logging.basicConfig(level=logging.INFO)

shopping_list = []


@callback
def get_items():
    """Return all items that are currently present in shopping list"""
    return shopping_list


@callback
def add_item(item):
    """Add new item to shopping list"""
    shopping_list.append(item)


@callback
def clear_items():
    """Clear shopping list"""
    shopping_list.clear()


if __name__ == '__main__':
    Global(init_controller=True, host="localhost", port=8888).join()
```
(This script is complete, it should run "as is")


`shopper.py`:
```python
"""
Note: Functions without a body are treated as proxies for remote callbacks.
    All arguments provided to this function will be sent to the remote service as-is.
"""
import logging
from daffi import Global
from daffi.decorators import alias, fetcher

logging.basicConfig(level=logging.INFO)


@fetcher
def get_items():
    """Return all items that are currently present in shopping list."""
    pass


@fetcher
def add_item(item):
    """Add new item to shopping list."""
    pass


@fetcher
def clear_items():
    """Add new item to shopping list."""
    pass


@alias("add_item")
@fetcher
def add_many_items(*items):
    """
    Alias for `add_item` callback.
    This function shows streaming capabilities for transferring data from one service to another.
    """
    for item in items:
        yield item


if __name__ == '__main__':
    g = Global(host="localhost", port=8888)

    items = get_items()
    print(items)

    add_item("orange")
    items = get_items()
    print(items)

    add_many_items("bread", "cheese")
    items = get_items()
    print(items)

    clear_items()
    items = get_items()
    print(items)

    g.stop()
```
(This script is complete, it should run "as is")

To check the full example, you need to execute two scripts in separate terminals

```bash
python3 shopping_service.py

...
INFO 2023-03-27 20:31:27 | controller[0xbac16ef4] | Controller has been started successfully. Process identificator: '0xbac16ef4'. Connection info: tcp: [ host '[::]', port: 8888 ]
INFO 2023-03-27 20:31:27 | node[0xbac16ef4] | Node has been started successfully. Process identificator: '0xbac16ef4'. Connection info: tcp: [ host '[::]', port: 8888 ]
```

```bash
python3 shopper.py

...
INFO 2023-03-27 20:31:43 | node[0xb9e10444] | Node has been started successfully. Process identificator: '0xb9e10444'. Connection info: tcp: [ host '[::]', port: 8888 ]
[]
['orange']
['orange', 'bread', 'cheese']
[]
INFO 2023-03-27 20:31:44 | node[0xb9e10444] | Node stopped.
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "daffi",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "async,distributed,grpc,job,python,queue,rpc,stream,task",
    "author": null,
    "author_email": "Volodymyr Boiko <600apples@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/dd/82/3db855fb0e78d66a9166b01877dd0c16f4bf13d93758590a36f7b369f371/daffi-2.2.1.tar.gz",
    "platform": null,
    "description": "<h1> \n    <img src=\"https://600apples.github.io/dafi/images/logo.png\"\n    width=\"40\"\n    height=\"40\"\n    style=\"float: left;\">\n    Daffi\n</h1>\n\n\n![test and validate](https://github.com/600apples/dafi/actions/workflows/test_and_validate.yml/badge.svg)\n![publish docs](https://github.com/600apples/dafi/actions/workflows/publish_docs.yml/badge.svg)\n![coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/600apples/c64b2cee548575858e40834754432018/raw/covbadge.json)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n[![Linux](https://svgshare.com/i/Zhy.svg)](https://svgshare.com/i/Zhy.svg)\n[![macOS](https://svgshare.com/i/ZjP.svg)](https://svgshare.com/i/ZjP.svg)\n[![Downloads](https://static.pepy.tech/badge/daffi/month)](https://pepy.tech/project/daffi)\n\nDaffi facilitates remote computing and enables remote procedure calls between multiple endpoints.\nIt supports many-to-many relationships between endpoints, allowing for seamless communication between distributed systems.\nThe library abstracts the complexities of remote computing and provides a user-friendly interface for initiating and managing remote procedure calls.\nIt also offers various features such as fault tolerance, load balancing, streaming and security, to ensure reliable and secure communication between endpoints.\n\nDaffi comprises three primary classes:\n\n- *Global* - Initialization entrypoint. Once *Global* object is initialized application can respond on remote requests and trigger remote callbacks itself.\n- *Callback* - Represents a collection of methods encapsulated in a class inherited from *Callback* or a standalone function decorated with the *callback* decorator. These functions/methods can be triggered from another process.\n- *Fetcher* - Represents a collection of methods encapsulated in a class inherited from *Fetcher* or a standalone function decorated with the *fetcher* decorator. These functions/methods serve as triggers for the corresponding callbacks defined in another process.\n\n## Documentation\n\nView full documentation at: [https://600apples.github.io/dafi/](https://600apples.github.io/dafi/)\n\n\n## Basic example\n\nYou need to create two files `shopping_service.py` and `shopper.py`\n\n`shopping_service.py` - represents a set of remote callbacks that can be triggered by a client application.\n\n`shopper.py` - represents shopping_service client (fetcher)\n\n#### Class based approach\n\n\n`shopping_service.py`:\n```python\nimport logging\nfrom daffi import Global\nfrom daffi.registry import Callback\n\nlogging.basicConfig(level=logging.INFO)\n\n\nclass ShoppingService(Callback):\n    auto_init = True # class is automatically initialized, eliminating the need to manually create an object.\n\n    def __post_init__(self):\n        self.shopping_list = []\n\n    def get_items(self):\n        \"\"\"Return all items that are currently present in shopping list\"\"\"\n        return self.shopping_list\n\n    def add_item(self, item):\n        \"\"\"Add new item to shopping list\"\"\"\n        self.shopping_list.append(item)\n\n    def clear_items(self):\n        \"\"\"Clear shopping list\"\"\"\n        self.shopping_list.clear()\n\n\nif __name__ == '__main__':\n    Global(init_controller=True, host=\"localhost\", port=8888).join()\n```\n(This script is complete, it should run \"as is\")\n\n\n`shopper.py`:\n```python\nimport logging\nfrom daffi import Global\nfrom daffi.decorators import alias\nfrom daffi.registry import Fetcher\n\nlogging.basicConfig(level=logging.INFO)\n\n\nclass Shopper(Fetcher):\n    \"\"\"\n    Note: Functions without a body are treated as proxies for remote callbacks.\n    All arguments provided to this function will be sent to the remote service as-is.\n    \"\"\"\n\n    def get_items(self):\n        \"\"\"Return all items that are currently present in shopping list.\"\"\"\n        pass\n\n    def add_item(self, item):\n        \"\"\"Add new item to shopping list.\"\"\"\n        pass\n\n    def clear_items(self):\n        \"\"\"Clear shopping list\"\"\"\n        pass\n\n    @alias(\"add_item\")\n    def add_many_items(self, *items):\n        \"\"\"\n        Alias for `add_item` callback.\n        This function shows streaming capabilities for transferring data from one service to another.\n        \"\"\"\n        for item in items:\n            yield item\n\n\nif __name__ == '__main__':\n    g = Global(host=\"localhost\", port=8888)\n\n    shopper = Shopper()\n    items = shopper.get_items()\n    print(items)\n\n    shopper.add_item(\"orange\")\n    items = shopper.get_items()\n    print(items)\n\n    shopper.add_many_items(\"bread\", \"cheese\")\n    items = shopper.get_items()\n    print(items)\n\n    shopper.clear_items()\n    items = shopper.get_items()\n    print(items)\n\n    g.stop()\n```\n(This script is complete, it should run \"as is\")\n\nTo check the full example, you need to execute two scripts in separate terminals\n\n```bash\npython3 shopping_service.py\n\n...\nINFO 2023-03-27 19:49:45 | controller[0x91adb83e] | Controller has been started successfully. Process identificator: '0x91adb83e'. Connection info: tcp: [ host '[::]', port: 8888 ]\nINFO 2023-03-27 19:49:45 | node[0x91adb83e] | Node has been started successfully. Process identificator: '0x91adb83e'. Connection info: tcp: [ host '[::]', port: 8888 ]\n```\n\n```bash\npython3 shopper.py\n\n...\nINFO 2023-03-27 19:53:15 | node[0xd7e5d488] | Node has been started successfully. Process identificator: '0xd7e5d488'. Connection info: tcp: [ host '[::]', port: 8888 ]\n[]\n['orange']\n['orange', 'bread', 'cheese']\n[]\nINFO 2023-03-27 19:53:15 | node[0xd7e5d488] | Node stopped.\n```\n\n### Decorators base approach\n\n`shopping_service.py`:\n```python\nimport logging\nfrom daffi import Global\nfrom daffi.decorators import callback\n\nlogging.basicConfig(level=logging.INFO)\n\nshopping_list = []\n\n\n@callback\ndef get_items():\n    \"\"\"Return all items that are currently present in shopping list\"\"\"\n    return shopping_list\n\n\n@callback\ndef add_item(item):\n    \"\"\"Add new item to shopping list\"\"\"\n    shopping_list.append(item)\n\n\n@callback\ndef clear_items():\n    \"\"\"Clear shopping list\"\"\"\n    shopping_list.clear()\n\n\nif __name__ == '__main__':\n    Global(init_controller=True, host=\"localhost\", port=8888).join()\n```\n(This script is complete, it should run \"as is\")\n\n\n`shopper.py`:\n```python\n\"\"\"\nNote: Functions without a body are treated as proxies for remote callbacks.\n    All arguments provided to this function will be sent to the remote service as-is.\n\"\"\"\nimport logging\nfrom daffi import Global\nfrom daffi.decorators import alias, fetcher\n\nlogging.basicConfig(level=logging.INFO)\n\n\n@fetcher\ndef get_items():\n    \"\"\"Return all items that are currently present in shopping list.\"\"\"\n    pass\n\n\n@fetcher\ndef add_item(item):\n    \"\"\"Add new item to shopping list.\"\"\"\n    pass\n\n\n@fetcher\ndef clear_items():\n    \"\"\"Add new item to shopping list.\"\"\"\n    pass\n\n\n@alias(\"add_item\")\n@fetcher\ndef add_many_items(*items):\n    \"\"\"\n    Alias for `add_item` callback.\n    This function shows streaming capabilities for transferring data from one service to another.\n    \"\"\"\n    for item in items:\n        yield item\n\n\nif __name__ == '__main__':\n    g = Global(host=\"localhost\", port=8888)\n\n    items = get_items()\n    print(items)\n\n    add_item(\"orange\")\n    items = get_items()\n    print(items)\n\n    add_many_items(\"bread\", \"cheese\")\n    items = get_items()\n    print(items)\n\n    clear_items()\n    items = get_items()\n    print(items)\n\n    g.stop()\n```\n(This script is complete, it should run \"as is\")\n\nTo check the full example, you need to execute two scripts in separate terminals\n\n```bash\npython3 shopping_service.py\n\n...\nINFO 2023-03-27 20:31:27 | controller[0xbac16ef4] | Controller has been started successfully. Process identificator: '0xbac16ef4'. Connection info: tcp: [ host '[::]', port: 8888 ]\nINFO 2023-03-27 20:31:27 | node[0xbac16ef4] | Node has been started successfully. Process identificator: '0xbac16ef4'. Connection info: tcp: [ host '[::]', port: 8888 ]\n```\n\n```bash\npython3 shopper.py\n\n...\nINFO 2023-03-27 20:31:43 | node[0xb9e10444] | Node has been started successfully. Process identificator: '0xb9e10444'. Connection info: tcp: [ host '[::]', port: 8888 ]\n[]\n['orange']\n['orange', 'bread', 'cheese']\n[]\nINFO 2023-03-27 20:31:44 | node[0xb9e10444] | Node stopped.\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Daffi is fast, simple and lightweight library for inter process communication",
    "version": "2.2.1",
    "project_urls": {
        "Documentation": "https://600apples.github.io/dafi/",
        "Source": "https://github.com/600apples/dafi"
    },
    "split_keywords": [
        "async",
        "distributed",
        "grpc",
        "job",
        "python",
        "queue",
        "rpc",
        "stream",
        "task"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7a4b43d245b8075283d8d08035e27d706a5d5d8cf3e26ad222b6570a78dc95a9",
                "md5": "f595b271eeee76f0275732a62ac6bd43",
                "sha256": "d2d6855a681fd72f4755a0c75592e71c9f5fdbac40d875af0aeb0002dc6f1420"
            },
            "downloads": -1,
            "filename": "daffi-2.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f595b271eeee76f0275732a62ac6bd43",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 74411,
            "upload_time": "2023-06-10T12:30:14",
            "upload_time_iso_8601": "2023-06-10T12:30:14.330866Z",
            "url": "https://files.pythonhosted.org/packages/7a/4b/43d245b8075283d8d08035e27d706a5d5d8cf3e26ad222b6570a78dc95a9/daffi-2.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "dd823db855fb0e78d66a9166b01877dd0c16f4bf13d93758590a36f7b369f371",
                "md5": "93ed7e0b722e093e99d82e71b68f0c01",
                "sha256": "106bc20da31eb6da91710f26ece0de76dc091c19ddc89635539c84088d533ff4"
            },
            "downloads": -1,
            "filename": "daffi-2.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "93ed7e0b722e093e99d82e71b68f0c01",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 447044,
            "upload_time": "2023-06-10T12:30:17",
            "upload_time_iso_8601": "2023-06-10T12:30:17.437654Z",
            "url": "https://files.pythonhosted.org/packages/dd/82/3db855fb0e78d66a9166b01877dd0c16f4bf13d93758590a36f7b369f371/daffi-2.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-10 12:30:17",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "600apples",
    "github_project": "dafi",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "daffi"
}
        
Elapsed time: 0.07341s