Skip to content

Instantly share code, notes, and snippets.

@socrateslee
Created May 23, 2019 07:20
Show Gist options
  • Save socrateslee/b19f7e26522dfe2e7f29a74c2fdb2f18 to your computer and use it in GitHub Desktop.
Save socrateslee/b19f7e26522dfe2e7f29a74c2fdb2f18 to your computer and use it in GitHub Desktop.
An object stores the change history of its attributes, the object can be use to store the hierarchies of different levels of configurations.
'''
An object stores the change history of its attributes,
the object can be use to store the hierarchies of different
levels of configurations.
Example
-------
# Set up config object
config = TracedObj()
config.server = "127.0.0.1"
config.port = 8080
config.remote = TracedObj()
config.remote.endpoint = "https://localhost:7997"
# Update the config somewhere else
config.server = "192.168.1.10"
# Get the history
config.get_history('server')
[{'datetime': '2019-05-23 15:15:46.208067',
'filename': '<stdin>',
'lineno': 1,
'op': 'set',
'value': '127.0.0.1'},
{'datetime': '2019-05-23 15:15:53.288555',
'filename': '<stdin>',
'lineno': 1,
'op': 'set',
'value': '192.168.1.10'}]
# Get the config hierarchy as as dict
config.as_dict()
{'port': 8080,
'remote': {'endpoint': 'https://localhost:7997'},
'server': '192.168.1.10'}
'''
import sys
import copy
import datetime
class TracedObj(object):
def __init__(self):
object.__setattr__(self, '_current', {})
object.__setattr__(self, '_history', {})
def update_trace_info(self, key, op, value=None):
if key not in self._history:
self._history[key] = []
frame = sys._getframe(2)
self._history[key].append({
"op": op,
"value": value,
"datetime": str(datetime.datetime.now()),
"filename": frame.f_code.co_filename,
"lineno": frame.f_code.co_firstlineno
})
def __setattr__(self, key, value):
self.update_trace_info(key, 'set', value=value)
self._current[key] = value
def __getattr__(self, key):
return self._current[key]
def __delattr__(self, key):
self.update_trace_info(key, 'del')
del self._current[key]
def as_dict(self):
ret = {}
for k, v in self._current.items():
if isinstance(v, TracedObj):
ret[k] = v.as_dict()
else:
ret[k] = copy.copy(v)
return ret
def get_history(self, key):
return self._history.get(key)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment