Skip to content

Instantly share code, notes, and snippets.

@lucaswiman
Created July 10, 2023 23:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucaswiman/6610fa9f997cdfb5f297424bdbe98c4b to your computer and use it in GitHub Desktop.
Save lucaswiman/6610fa9f997cdfb5f297424bdbe98c4b to your computer and use it in GitHub Desktop.
re: https://hachyderm.io/@glyph@mastodon.social/110692244224116619
from typing import Callable
class AuditDescriptor:
def __init__(self, field_name, audit_action):
self.field_name = field_name
self.audit_action = audit_action
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.field_name]
def __set__(self, instance, value):
self.audit_action((instance, self.field_name, value))
instance.__dict__[self.field_name] = value
from dataclasses import dataclass
def audit_fields(audit_action: Callable):
def make_auditable(cls):
cls = dataclass(cls) # or whatever you want to do here
for k, v in cls.__annotations__.items():
# Ommitted bookkeeping around class level defaults, inheritance of audited classes, etc.
setattr(cls, k, AuditDescriptor(k, audit_action))
return cls
return make_auditable
audit_log = []
@audit_fields(audit_log.append)
class MyClass:
name: str
age: int
person = MyClass(name="John", age=30)
person.name = "Bob"
print(audit_log)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment