<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"
}