Skip to main content

Object Watchdog

This library allow to monitor changes in a Python object and, when some attribute changes, then launch callbacks.

Support this project

Support this project (to solve issues, new features…) by applying the Github “Sponsor” button.

Install

$ pip install object-watchdog

Callbacks types

There’re 3 types of callbacks:

  • Async callbacks: launch coroutines as callbacks

  • Callbacks: launch functions as callbacks

  • Cache callbacks: Launch methods of class to update caches

Global vs local callbacks

  • Local callbacks are called only for these classes that have set the callbacks

  • Global callbacks are called for all classes that uses the Object Watchdog

How to usage

Object Watchdog should be used as metaclass:

from object_watchdog import ObjectWatchdog

class User(metaclass=ObjectWatchdog):
    ...

Defining local callbacks

Callbacks could be defined in running time and in definition.

Definition mode

At the classes you can put callbacks when any attribute changes, you can define these types of callbacks in these properties:

  • __async_callbacks__

  • __callbacks__

  • __cache_callbacks__

Example:

async def async_callback(instance, klass_name, key, value):
    print(f"[!] New change local callback in key '{key}'. New value '{value}'")


async def async_callback2(instance, klass_name, key, value):
    print(f"[0] New change local callback in key '{key}'. New value '{value}'")


def callback(instance, klass_name, key, value):
    print(f"[!] Sync New change local callback in key '{key}'. New value '{value}'")


class User(metaclass=ObjectWatchdog):
    __async_callbacks__ = [async_callback, async_callback2]
    __callbacks__ = [callback]
    __cache_callbacks__ = ["__build_hash__"]

    ...

Running time

If you need to add some callback in run time, Metaclass add these methods:

  • add_callback

  • add_async_callback

  • add_cache_callback

import asyncio

from typing import Dict
from dataclasses import dataclass, field

from object_watchdog import ObjectWatchdog


@dataclass
class User(metaclass=ObjectWatchdog):
    user: str
    password: str

    @property
    def hash(self):
        if not self.__cached_hash:
            self.__build_hash__()
        return self.__cached_hash

    def __build_hash__(self, key: str = None):
        if key and key != "user" and key != "password":
            return

        h = hashlib.sha512()
        h.update(
            f"{self.user}#{self.password}".encode("UTF-8")
        )

        self.__cached_hash = h.hexdigest()

async def coro_callback(instance, klass_name, key, value):
    print(f"[!] New change in key '{key}'. New value '{value}'")


async def main():

    u = User(user="john", password="password")
    u.add_async_callback(coro_callback)
    u.add_cache_callback("__build_hash__")

    print("[*] Modifying property 'value'")
    u.password = "new password!"


def main():
    asyncio.run(coro_main())


main()

Defining global callbacks

Global callback applies to all classes (or dataclasses) that uses ObjectWatchdog as a metaclass.

If you want to call any function / coroutine when some class have been modified, you also can use this method. ObjectWatchdog metaclass has these methods:

  • add_global_callback

  • add_global_async_callback

  • add_global_cache_callback

import asyncio

from typing import Dict
from dataclasses import dataclass, field

from object_watchdog import ObjectWatchdog


@dataclass
class MyClass(metaclass=ObjectWatchdog):
    value: str
    my_dict: Dict = field(default_factory=dict)


@dataclass
class MyClass2(metaclass=ObjectWatchdog):
    value: str
    my_dict: Dict = field(default_factory=dict)


async def coro_local_callback(instance, klass_name, key, value):
    print(f"[!] New change local callback in key '{key}'. New value '{value}'")


async def coro_global_callback(instance, klass_name, key, value):
    print(f"[!] New change global callback in instance '{repr(instance)}' key '{key}'. New value '{value}'")


async def coro_main():

    ObjectWatchdog.add_global_callback(coro_global_callback)

    u1 = MyClass(value="class 1", my_dict={"k": "v"})
    u2 = MyClass2(value="class 2", my_dict={"k": "v"})

    print("[*] Modifying property 'value'")
    u1.value = "new value!"
    u2.value = "new value!"


def main():
    asyncio.run(coro_main())


main()

Metadata

Release files for object-watchdog 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for object-watchdog 0.0.2
File Size Uploaded Provenance
object-watchdog-0.0.2.tar.gz 3.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for object-watchdog 0.0.2
File Interpreter ABI Platform
object_watchdog-0.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 7.4 kB

Release files / object-watchdog-0.0.2.tar.gz

Download URL object-watchdog-0.0.2.tar.gz
Size 3.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e1877af82641fe2ebebb33564887f9be864ce787087dafbc58cf98cf29f8adf0
BLAKE2b-256 checksum
How to use checksums
0fd888b7a3764c9a7043288d878e987f0bdfeafaea45f89b3cc794f270c9dcb6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.6

Release files / object_watchdog-0.0.2-py3-none-any.whl

Download URL object_watchdog-0.0.2-py3-none-any.whl
Size 3.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d3cd0a9243b906b974929089d393d314d8e72ebf2a2fdcbefaf3118c4ba80598
BLAKE2b-256 checksum
How to use checksums
3723e6090683eb97032fa57b89397efdc866265ffa6683b03ce3264d4b71cc3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.6

Security for object-watchdog 0.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page