{"id":16518886,"url":"https://github.com/crimson-crow/pyobservable","last_synced_at":"2025-10-28T07:31:16.234Z","repository":{"id":62582184,"uuid":"380858387","full_name":"Crimson-Crow/pyobservable","owner":"Crimson-Crow","description":"Simple event system for Python with weak reference support","archived":false,"fork":false,"pushed_at":"2021-06-29T00:42:13.000Z","size":14,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-01T12:45:26.669Z","etag":null,"topics":["event-emitter","event-handling","events","observable","observer-pattern","python","simple","weak-references"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Crimson-Crow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-27T23:39:59.000Z","updated_at":"2023-11-25T22:58:51.000Z","dependencies_parsed_at":"2022-11-03T20:17:23.892Z","dependency_job_id":null,"html_url":"https://github.com/Crimson-Crow/pyobservable","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crimson-Crow%2Fpyobservable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crimson-Crow%2Fpyobservable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crimson-Crow%2Fpyobservable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crimson-Crow%2Fpyobservable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Crimson-Crow","download_url":"https://codeload.github.com/Crimson-Crow/pyobservable/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238614459,"owners_count":19501461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-emitter","event-handling","events","observable","observer-pattern","python","simple","weak-references"],"created_at":"2024-10-11T16:43:59.259Z","updated_at":"2025-10-28T07:31:15.862Z","avatar_url":"https://github.com/Crimson-Crow.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"pyobservable\n============\n\n[![PyPI](https://img.shields.io/pypi/v/pyobservable)](https://pypi.org/project/pyobservable/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyobservable)](https://pypi.org/project/pyobservable/)\n[![Lines of code](https://img.shields.io/tokei/lines/github/Crimson-Crow/pyobservable)](https://github.com/Crimson-Crow/pyobservable)\n[![GitHub](https://img.shields.io/github/license/Crimson-Crow/pyobservable)]((https://github.com/Crimson-Crow/pyobservable/blob/main/LICENSE.txt))\n\nDescription\n-----------\n\n`pyobservable` provides a simple event system for Python with weak reference support.\nThis ensures that the event handlers do not stay in memory when they aren't needed anymore. \n\nInstallation\n------------\n\n`pyobservable` can be installed using [`pip`](http://www.pip-installer.org/):\n\n    $ pip install pyobservable\n\nAlternatively, you can download the repository and run the following command from within the source directory:\n\n    $ python setup.py install\n\nUsage\n-----\n\nFor a quick start, a minimal example is:\n\n```python\nfrom pyobservable import Observable\n\n\nobs = Observable()\nobs.add_event('foo')\nobs.add_event('bar')\n\n# Event keys can be any object that is hashable\nevent = object()\nobs.add_event(event)\n\n\n# Binding with decorator usage\n@obs.bind('foo')\ndef foo_handler(foo_number):\n    print('foo_handler called:', foo_number)\n\n\n# Binding with function usage\ndef bar_handler(bar_list):\n    print('bar_handler called:', bar_list)\nobs.bind('bar', bar_handler)\n\n\nobs.notify('foo', 1)\nobs.notify('bar', [1, 2, 3])\n```\n\nThe rationale behind the requirement to add events before binding to them is to ensure the code is less error-prone from mistyping event names.\nAlso, if a duplicated event key is present, `ValueError` will be raised.\\\nHowever, the next example shows that event registration can be simplified using the special `_events_` attribute:\n\n```python\nfrom pyobservable import Observable\n\n\nclass EventEmitter(Observable):\n    _events_ = ['foo', 2]\n    \n    def triggers_foo(self):\n        self.notify('foo', 1, 2, 3)\n\n\nevent_emitter = EventEmitter()        \n\n\n@event_emitter.bind('foo')\ndef foo_handler(*args):\n    print(*args)\n\n\nevent_emitter.triggers_foo()\n```\nAlso note that `_events_` can be defined multiple times in an inheritance tree.\n`Observable` scans the MRO for this attribute and adds every event it finds.\nAgain, a `ValueError` will be raised if a duplicate event key is present. \n\nFinally, here's an advanced and clean example using [`enum`](https://docs.python.org/3/library/enum.html):\n\n```python\nfrom enum import Enum, auto\nfrom pyobservable import Observable\n\n\nclass EventType(Enum):\n    FOO = auto()\n    BAR = auto()\n\nclass EventEmitter(Observable):\n    _events_ = EventType  # Enums are iterable\n\n    def triggers_foo(self):\n        self.notify(EventType.FOO, 'foo happened!')\n\n\nclass EventListener:\n    def on_foo(self, message):\n        print(\"Here's a message from foo:\", message)\n\n\nevent_emitter = EventEmitter()\nevent_listener = EventListener()\nevent_emitter.bind(EventType.FOO, event_listener.on_foo)  # pyobservable also supports bound methods\n\n\nevent_emitter.triggers_foo()\n```\n\nFor more information, please refer to the `Observable` class docstrings.\n\nTests\n-----\n\nThe simplest way to run tests:\n\n    $ python tests.py\n\nAs a more robust alternative, you can install [`tox`](https://tox.readthedocs.io/en/latest/install.html) (or [`tox-conda`](https://github.com/tox-dev/tox-conda) if you use [`conda`](https://docs.conda.io/en/latest/)) to automatically support testing across the supported python versions, then run:\n\n    $ tox\n\nIssue tracker\n-------------\n\nPlease report any bugs and enhancement ideas using the [issue tracker](https://github.com/Crimson-Crow/pyobservable/issues).\n\nLicense\n-------\n\n`pyobservable` is licensed under the terms of the [MIT License](https://opensource.org/licenses/MIT) (see [LICENSE.txt](https://github.com/Crimson-Crow/pyobservable/blob/main/LICENSE.txt) for more information).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrimson-crow%2Fpyobservable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrimson-crow%2Fpyobservable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrimson-crow%2Fpyobservable/lists"}