watchify


Namewatchify JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://github.com/daniel-augustus/watchify
SummaryDecoupled event-driven communication between objects.
upload_time2024-02-12 16:18:36
maintainer
docs_urlNone
authorDaniel Augusto
requires_python>=3.8.1,<4.0.0
licenseMIT
keywords watchify observer decoupled listeners event-driven objects communication
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1 align="center">Watchify</h1>


                                    ⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⢠⡆⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠈⣷⣄⠀⠀⠀⠀⣾⣷⠀⠀⠀⠀⣠⣾⠃⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⢿⠿⠃⠀⠀⠀⠉⠉⠁⠀⠀⠐⠿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣶⣶⣶⣤⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⣠⣶⣿⣿⡿⣿⣿⣿⡿⠋⠉⠀⠀⠉⠙⢿⣿⣿⡿⣿⣿⣷⣦⡀⠀⠀⠀
                                    ⠀⢀⣼⣿⣿⠟⠁⢠⣿⣿⠏⠀⠀⢠⣤⣤⡀⠀⠀⢻⣿⣿⡀⠙⢿⣿⣿⣦⠀⠀
                                    ⣰⣿⣿⡟⠁⠀⠀⢸⣿⣿⠀⠀⠀⢿⣿⣿⡟⠀⠀⠈⣿⣿⡇⠀⠀⠙⣿⣿⣷⡄
                                    ⠈⠻⣿⣿⣦⣄⠀⠸⣿⣿⣆⠀⠀⠀⠉⠉⠀⠀⠀⣸⣿⣿⠃⢀⣤⣾⣿⣿⠟⠁
                                    ⠀⠀⠈⠻⣿⣿⣿⣶⣿⣿⣿⣦⣄⠀⠀⠀⢀⣠⣾⣿⣿⣿⣾⣿⣿⡿⠋⠁⠀⠀
                                    ⠀⠀⠀⠀⠀⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠁⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠛⠿⠿⠿⠿⠿⠿⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⢰⣷⡦⠀⠀⠀⢀⣀⣀⠀⠀⠀⢴⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⣸⠟⠁⠀⠀⠀⠘⣿⡇⠀⠀⠀⠀⠙⢷⠀⠀⠀⠀⠀⠀⠀⠀
                                    ⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠻⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀

***

<p align="center">
  <a href='https://coveralls.io/github/daniel-augustus/watchify?branch=main'><img src='https://coveralls.io/repos/github/daniel-augustus/watchify/badge.svg?branch=main' alt='Coverage Status' /></a>
  <img alt="License" src="https://img.shields.io/badge/License-MIT-blue.svg">
  <img alt="Python Version" src="https://img.shields.io/badge/Python-^3.8.1-blue.svg">
  <a href="https://pypi.org/project/watchify/">
    <img alt="PyPi" src="https://img.shields.io/badge/PyPi-0.2.0-yellow.svg">
  </a>
</p>

***

## About

`watchify` is an **event-driven** inter-object communication tool, promoting the **segregation of
complex functionalities** into smaller ones while enabling their relationship through a third-party entity.
This approach promotes **loosely coupled** implementations, simplifying **Single Responsibility Principle** commitment yet keeping a **cohesive code**.
As a result, the code becomes more flexible, maintainable, testable, and overrall healthier.

## Install

```console
$ pip install watchify
```

## Usage

```python
from watchify import AbstractWatcher, Watchers
from watchify.logger import logger


class Food:
    def cook(self, name: str) -> None:
        self.name = name


class CatWatcher(AbstractWatcher):
    def push(self, food: Food, *args, **kwargs) -> None:
        if food.name == 'fish':
            logger.debug(f'Cat loves %s!', food.name)
        else:
            logger.debug(f'Cat hates %s!', food.name)


class MonkeyWatcher(AbstractWatcher):
    def push(self, food: Food, *args, **kwargs) -> None:
        if food.name == 'banana':
            logger.debug(f'Monkey loves %s!', food.name)
        else:
            logger.debug(f'Monkey hates %s!', food.name)


>>> food, watchers = Food(), Watchers()
>>> watchers.attach_many([CatWatcher(), MonkeyWatcher()])
<Watchers object:Observers[CatWatcher, MonkeyWatcher]>
>>> food.cook('fish')
>>> watchers.notify(food)
[watchers][DEBUG][2077-12-27 00:00:00,111] >>> Notifying watcher: CatWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,112] >>> Cat loves fish!
[watchers][DEBUG][2077-12-27 00:00:00,113] >>> Notifying watcher: MonkeyWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,114] >>> Monkey hates fish!
>>> food.cook('banana')
>>> watchers.notify(food)
[watchers][DEBUG][2077-12-27 00:00:00,115] >>> Notifying watcher: CatWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,116] >>> Cat hates banana!
[watchers][DEBUG][2077-12-27 00:00:00,117] >>> Notifying watcher: MonkeyWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,118] >>> Monkey loves banana!
```

Or using `WatchersSpy`, you can notify listeners automatically whenever a specified constraint is
met, so you don't need to manually invoke `notify` as shown above:

```python
from watchify import AbstractWatcher, WatchersSpy
from watchify.logger import logger

# [...]

>>> food, watchers = Food(), WatchersSpy()
>>> watchers.attach_many([CatWatcher(), MonkeyWatcher()])
<WatchersSpy object:Observers[CatWatcher, MonkeyWatcher]>
>>> watchers.spy(food, 'cook')
Spying(sender'=<Food object>', method='cook', constraint='after')
>>> food.cook('fish')
[watchers][DEBUG][2077-12-27 00:00:00,111] >>> Notifying watcher: CatWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,112] >>> Cat loves fish!
[watchers][DEBUG][2077-12-27 00:00:00,113] >>> Notifying watcher: MonkeyWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,114] >>> Monkey hates fish!
>>> food.cook('banana')
[watchers][DEBUG][2077-12-27 00:00:00,115] >>> Notifying watcher: CatWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,116] >>> Cat hates banana!
[watchers][DEBUG][2077-12-27 00:00:00,117] >>> Notifying watcher: MonkeyWatcher object...
[watchers][DEBUG][2077-12-27 00:00:00,118] >>> Monkey loves banana!
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/daniel-augustus/watchify",
    "name": "watchify",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8.1,<4.0.0",
    "maintainer_email": "",
    "keywords": "watchify,observer,decoupled,listeners,event-driven,objects communication",
    "author": "Daniel Augusto",
    "author_email": "dev.daniel.augusto@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/82/7d/f80a06299a0f959b17e64dd4bb3f0ced4c764d730c9ec9b85b8f1f44fa29/watchify-0.2.0.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\">Watchify</h1>\n\n\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2880\u2800\u2800\u2800\u2800\u2800\u2800\u28a0\u2846\u2800\u2800\u2800\u2800\u2800\u2800\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2808\u28f7\u28c4\u2800\u2800\u2800\u2800\u28fe\u28f7\u2800\u2800\u2800\u2800\u28e0\u28fe\u2803\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28bf\u283f\u2803\u2800\u2800\u2800\u2809\u2809\u2801\u2800\u2800\u2810\u283f\u287f\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28c0\u28e0\u28e4\u28e4\u28f6\u28f6\u28f6\u28e4\u28e4\u28c4\u28c0\u2840\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2880\u28e4\u28f6\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28f7\u28e6\u28c4\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u28e0\u28f6\u28ff\u28ff\u287f\u28ff\u28ff\u28ff\u287f\u280b\u2809\u2800\u2800\u2809\u2819\u28bf\u28ff\u28ff\u287f\u28ff\u28ff\u28f7\u28e6\u2840\u2800\u2800\u2800\n                                    \u2800\u2880\u28fc\u28ff\u28ff\u281f\u2801\u28a0\u28ff\u28ff\u280f\u2800\u2800\u28a0\u28e4\u28e4\u2840\u2800\u2800\u28bb\u28ff\u28ff\u2840\u2819\u28bf\u28ff\u28ff\u28e6\u2800\u2800\n                                    \u28f0\u28ff\u28ff\u285f\u2801\u2800\u2800\u28b8\u28ff\u28ff\u2800\u2800\u2800\u28bf\u28ff\u28ff\u285f\u2800\u2800\u2808\u28ff\u28ff\u2847\u2800\u2800\u2819\u28ff\u28ff\u28f7\u2844\n                                    \u2808\u283b\u28ff\u28ff\u28e6\u28c4\u2800\u2838\u28ff\u28ff\u28c6\u2800\u2800\u2800\u2809\u2809\u2800\u2800\u2800\u28f8\u28ff\u28ff\u2803\u2880\u28e4\u28fe\u28ff\u28ff\u281f\u2801\n                                    \u2800\u2800\u2808\u283b\u28ff\u28ff\u28ff\u28f6\u28ff\u28ff\u28ff\u28e6\u28c4\u2800\u2800\u2800\u2880\u28e0\u28fe\u28ff\u28ff\u28ff\u28fe\u28ff\u28ff\u287f\u280b\u2801\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2819\u283b\u28bf\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u28ff\u283f\u281b\u2801\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2808\u2809\u281b\u281b\u283f\u283f\u283f\u283f\u283f\u283f\u281b\u280b\u2809\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28b0\u28f7\u2866\u2800\u2800\u2800\u2880\u28c0\u28c0\u2800\u2800\u2800\u28b4\u28fe\u2847\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u28f8\u281f\u2801\u2800\u2800\u2800\u2818\u28ff\u2847\u2800\u2800\u2800\u2800\u2819\u28b7\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n                                    \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2801\u2800\u2800\u2800\u2800\u2800\u2800\u283b\u2800\u2800\u2800\u2800\u2800\u2800\u2808\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\n\n***\n\n<p align=\"center\">\n  <a href='https://coveralls.io/github/daniel-augustus/watchify?branch=main'><img src='https://coveralls.io/repos/github/daniel-augustus/watchify/badge.svg?branch=main' alt='Coverage Status' /></a>\n  <img alt=\"License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\">\n  <img alt=\"Python Version\" src=\"https://img.shields.io/badge/Python-^3.8.1-blue.svg\">\n  <a href=\"https://pypi.org/project/watchify/\">\n    <img alt=\"PyPi\" src=\"https://img.shields.io/badge/PyPi-0.2.0-yellow.svg\">\n  </a>\n</p>\n\n***\n\n## About\n\n`watchify` is an **event-driven** inter-object communication tool, promoting the **segregation of\ncomplex functionalities** into smaller ones while enabling their relationship through a third-party entity.\nThis approach promotes **loosely coupled** implementations, simplifying **Single Responsibility Principle** commitment yet keeping a **cohesive code**.\nAs a result, the code becomes more flexible, maintainable, testable, and overrall healthier.\n\n## Install\n\n```console\n$ pip install watchify\n```\n\n## Usage\n\n```python\nfrom watchify import AbstractWatcher, Watchers\nfrom watchify.logger import logger\n\n\nclass Food:\n    def cook(self, name: str) -> None:\n        self.name = name\n\n\nclass CatWatcher(AbstractWatcher):\n    def push(self, food: Food, *args, **kwargs) -> None:\n        if food.name == 'fish':\n            logger.debug(f'Cat loves %s!', food.name)\n        else:\n            logger.debug(f'Cat hates %s!', food.name)\n\n\nclass MonkeyWatcher(AbstractWatcher):\n    def push(self, food: Food, *args, **kwargs) -> None:\n        if food.name == 'banana':\n            logger.debug(f'Monkey loves %s!', food.name)\n        else:\n            logger.debug(f'Monkey hates %s!', food.name)\n\n\n>>> food, watchers = Food(), Watchers()\n>>> watchers.attach_many([CatWatcher(), MonkeyWatcher()])\n<Watchers object:Observers[CatWatcher, MonkeyWatcher]>\n>>> food.cook('fish')\n>>> watchers.notify(food)\n[watchers][DEBUG][2077-12-27 00:00:00,111] >>> Notifying watcher: CatWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,112] >>> Cat loves fish!\n[watchers][DEBUG][2077-12-27 00:00:00,113] >>> Notifying watcher: MonkeyWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,114] >>> Monkey hates fish!\n>>> food.cook('banana')\n>>> watchers.notify(food)\n[watchers][DEBUG][2077-12-27 00:00:00,115] >>> Notifying watcher: CatWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,116] >>> Cat hates banana!\n[watchers][DEBUG][2077-12-27 00:00:00,117] >>> Notifying watcher: MonkeyWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,118] >>> Monkey loves banana!\n```\n\nOr using `WatchersSpy`, you can notify listeners automatically whenever a specified constraint is\nmet, so you don't need to manually invoke `notify` as shown above:\n\n```python\nfrom watchify import AbstractWatcher, WatchersSpy\nfrom watchify.logger import logger\n\n# [...]\n\n>>> food, watchers = Food(), WatchersSpy()\n>>> watchers.attach_many([CatWatcher(), MonkeyWatcher()])\n<WatchersSpy object:Observers[CatWatcher, MonkeyWatcher]>\n>>> watchers.spy(food, 'cook')\nSpying(sender'=<Food object>', method='cook', constraint='after')\n>>> food.cook('fish')\n[watchers][DEBUG][2077-12-27 00:00:00,111] >>> Notifying watcher: CatWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,112] >>> Cat loves fish!\n[watchers][DEBUG][2077-12-27 00:00:00,113] >>> Notifying watcher: MonkeyWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,114] >>> Monkey hates fish!\n>>> food.cook('banana')\n[watchers][DEBUG][2077-12-27 00:00:00,115] >>> Notifying watcher: CatWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,116] >>> Cat hates banana!\n[watchers][DEBUG][2077-12-27 00:00:00,117] >>> Notifying watcher: MonkeyWatcher object...\n[watchers][DEBUG][2077-12-27 00:00:00,118] >>> Monkey loves banana!\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Decoupled event-driven communication between objects.",
    "version": "0.2.0",
    "project_urls": {
        "Homepage": "https://github.com/daniel-augustus/watchify",
        "Repository": "https://github.com/daniel-augustus/watchify"
    },
    "split_keywords": [
        "watchify",
        "observer",
        "decoupled",
        "listeners",
        "event-driven",
        "objects communication"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "12da18ec52e4d9ec5ecd3afa8ab8cc300b811635bdef6117ecda3f1f7ad6d114",
                "md5": "7559adb4f158f3467b6c54e12fa90e98",
                "sha256": "770758ac5af609872c64f37a9564869f3c02833164116a7cc4b5f3ba94a187a6"
            },
            "downloads": -1,
            "filename": "watchify-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7559adb4f158f3467b6c54e12fa90e98",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8.1,<4.0.0",
            "size": 11323,
            "upload_time": "2024-02-12T16:18:34",
            "upload_time_iso_8601": "2024-02-12T16:18:34.464868Z",
            "url": "https://files.pythonhosted.org/packages/12/da/18ec52e4d9ec5ecd3afa8ab8cc300b811635bdef6117ecda3f1f7ad6d114/watchify-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "827df80a06299a0f959b17e64dd4bb3f0ced4c764d730c9ec9b85b8f1f44fa29",
                "md5": "0539701ddb1af568ba118254d136d728",
                "sha256": "8928dbbc9518bb8252f100ce835dc353a8f5089d229a60438ddfcba0f938d564"
            },
            "downloads": -1,
            "filename": "watchify-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "0539701ddb1af568ba118254d136d728",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8.1,<4.0.0",
            "size": 9945,
            "upload_time": "2024-02-12T16:18:36",
            "upload_time_iso_8601": "2024-02-12T16:18:36.577533Z",
            "url": "https://files.pythonhosted.org/packages/82/7d/f80a06299a0f959b17e64dd4bb3f0ced4c764d730c9ec9b85b8f1f44fa29/watchify-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-12 16:18:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "daniel-augustus",
    "github_project": "watchify",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "watchify"
}
        
Elapsed time: 0.18906s