Package: object-watchdog
Object WatchdogThis library allow to monitor changes in a Python object and, when some attribute changes, then launch callbacks.Support this projectSupport this project (to solve issues, new features…) by applying the Github “Sponsor” button.Install$pipinstallobject-watchdogCallbacks typesThere’re 3 types of callbacks:Async callbacks: launch coroutines as callbacksCallbacks: launch functions as callbacksCache callbacks: Launch methods of class to update cachesGlobal vs local callbacksLocal callbacks are called only for these classes that have set the callbacksGlobal callbacks are called for all classes that uses the Object WatchdogHow to usageObject Watchdog should be used as metaclass:fromobject_watchdogimportObjectWatchdogclassUser(metaclass=ObjectWatchdog):...Defining local callbacksCallbacks could be defined in running time and in definition.Definition modeAt 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:asyncdefasync_callback(instance,klass_name,key,value):print(f"[!] New change local callback in key '{key}'. New value '{value}'")asyncdefasync_callback2(instance,klass_name,key,value):print(f"[0] New change local callback in key '{key}'. New value '{value}'")defcallback(instance,klass_name,key,value):print(f"[!] Sync New change local callback in key '{key}'. New value '{value}'")classUser(metaclass=ObjectWatchdog):__async_callbacks__=[async_callback,async_callback2]__callbacks__=[callback]__cache_callbacks__=["__build_hash__"]...Running timeIf you need to add some callback in run time, Metaclass add these methods:add_callbackadd_async_callbackadd_cache_callbackimportasynciofromtypingimportDictfromdataclassesimportdataclass,fieldfromobject_watchdogimportObjectWatchdog@dataclassclassUser(metaclass=ObjectWatchdog):user:strpassword:str@propertydefhash(self):ifnotself.__cached_hash:self.__build_hash__()returnself.__cached_hashdef__build_hash__(self,key:str=None):ifkeyandkey!="user"andkey!="password":returnh=hashlib.sha512()h.update(f"{self.user}#{self.password}".encode("UTF-8"))self.__cached_hash=h.hexdigest()asyncdefcoro_callback(instance,klass_name,key,value):print(f"[!] New change in key '{key}'. New value '{value}'")asyncdefmain():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!"defmain():asyncio.run(coro_main())main()Defining global callbacksGlobal 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_callbackadd_global_async_callbackadd_global_cache_callbackimportasynciofromtypingimportDictfromdataclassesimportdataclass,fieldfromobject_watchdogimportObjectWatchdog@dataclassclassMyClass(metaclass=ObjectWatchdog):value:strmy_dict:Dict=field(default_factory=dict)@dataclassclassMyClass2(metaclass=ObjectWatchdog):value:strmy_dict:Dict=field(default_factory=dict)asyncdefcoro_local_callback(instance,klass_name,key,value):print(f"[!] New change local callback in key '{key}'. New value '{value}'")asyncdefcoro_global_callback(instance,klass_name,key,value):print(f"[!] New change global callback in instance '{repr(instance)}' key '{key}'. New value '{value}'")asyncdefcoro_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!"defmain():asyncio.run(coro_main())main()