Skip to content

Commit

Permalink
consolidating objects.py into config.py
Browse files Browse the repository at this point in the history
  • Loading branch information
opalmer committed Mar 15, 2014
1 parent 85aec74 commit 107192b
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 164 deletions.
138 changes: 136 additions & 2 deletions pyfarm/agent/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,143 @@
>>> from pyfarm.agent.config import config
"""

try:
from UserDict import IterableUserDict, UserDict
except ImportError: # pragma: no cover
from collections import IterableUserDict, UserDict

from pyfarm.core.enums import NOTSET
from pyfarm.core.logger import getLogger


class LoggingConfiguration(IterableUserDict):
"""
Special configuration object which logs when a key is changed in
a dictionary. If the reactor is not running then log messages will
be queued until they can be emitted so they are not lost.
"""
MODIFIED = "modified"
CREATED = "created"
DELETED = "deleted"
log = getLogger("agent.config")

def __setitem__(self, key, value):
if key not in self:
self.changed(self.CREATED, key, value)
elif self[key] != value:
self.changed(self.MODIFIED, key, value)

IterableUserDict.__setitem__(self, key, value)

def __delitem__(self, key):
IterableUserDict.__delitem__(self, key)
self.changed(self.DELETED, key)

def pop(self, key, *args):
IterableUserDict.pop(self, key, *args)
self.changed(self.DELETED, key)

def clear(self):
keys = self.keys()
IterableUserDict.clear(self)

for key in keys:
self.changed(self.DELETED, key)

def update(self, data=None, **kwargs):
if isinstance(data, (dict, UserDict)):
for key, value in data.items():
if key not in self:
self.changed(self.CREATED, key, value)
elif self[key] != value: # pragma: no cover
self.changed(self.MODIFIED, key, value)

for key, value in kwargs.iteritems():
if key not in self:
self.changed(self.CREATED, key, value)
elif self[key] != value: # pragma: no cover
self.changed(self.MODIFIED, key, value)

IterableUserDict.update(self, dict=data, **kwargs)

def changed(self, change_type, key, value=NOTSET):
assert value is not NOTSET if change_type != self.DELETED else True

if change_type == self.MODIFIED:
self.log.info("modified %r = %r", key, value)

elif change_type == self.CREATED:
self.log.info("set %r = %r", key, value)

elif change_type == self.DELETED:
self.log.warning("deleted %r", key)

else:
raise NotImplementedError(
"Don't know how to handle change_type %r" % change_type)

class ConfigurationWithCallbacks(LoggingConfiguration):
"""
Subclass of :class:`.LoggingDictionary` that provides the ability to
run a function when a value is changed.
"""
callbacks = {}

@classmethod
def register_callback(cls, key, callback, append=False):
"""
Register a function as a callback for ``key``. When ``key``
is set the given ``callback`` will be run by :meth:`.changed`
:param string key:
the key which when changed in any way will execute
``callback``
:param callable callback:
the function or method to register
:param boolean append:
by default attempting to register a callback which has
already been registered will do nothing, setting this
to ``True`` overrides this behavior.
"""
assert callable(callback)
callbacks = cls.callbacks.setdefault(key, [])

if callback in callbacks and not append:
cls.log.warning(
"%r is already a registered callback for %r", callback, key)
return

callbacks.append(callback)
cls.log.debug("Registered callback %r for %r", callback, key)

@classmethod
def deregister_callback(cls, key, callback):
if key in cls.callbacks and callback in cls.callbacks[key]:
# remove all instances of the callback
while callback in cls.callbacks[key]:
cls.callbacks[key].remove(callback)

# if callbacks no longer exist, remove the key
if not cls.callbacks[key]:
cls.callbacks.pop(key)
else: # pragma: no cover
cls.log.warning(
"%r is not a registered callback for %r", callback, key)

def changed(self, change_type, key, value=NOTSET):
LoggingConfiguration.changed(self, change_type, key, value)

if key in self.callbacks:
for callback in self.callbacks[key]:
callback(change_type, key, value)
self.log.debug(
"Key %r was %r, calling callback %s",
key, change_type, callback)

# prevent a call to reload() from dumping the config object
try:
config
except NameError:
from pyfarm.agent.utility.objects import ConfigurationWithCallbacks
config = ConfigurationWithCallbacks()
config = ConfigurationWithCallbacks()
160 changes: 0 additions & 160 deletions pyfarm/agent/utility/objects.py

This file was deleted.

3 changes: 1 addition & 2 deletions tests/test_agent/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
from os import urandom

from pyfarm.core.enums import NOTSET
from pyfarm.agent.config import LoggingConfiguration, ConfigurationWithCallbacks
from pyfarm.agent.testutil import TestCase
from pyfarm.agent.utility.objects import (
LoggingConfiguration, ConfigurationWithCallbacks)


class ChangedLoggingConfiguration(LoggingConfiguration):
Expand Down

0 comments on commit 107192b

Please sign in to comment.