class Node(NanoResource): context_attributes = ['name', 'realm', 'address', 'node_monitor'] def __init__(self, name, realm=None, address=None, node_monitor=None, monitoring_groups=None, **kwargs): self.name = name self.realm = realm self.address = address or name self.node_monitor = node_monitor self.monitoring_groups = WeakValueDictionary() self._tasks = [] if monitoring_groups: for group in monitoring_groups: if not isinstance(group, MonitoringGroup): try: group = MonitoringGroup.registry[group] except KeyError: logger.error( "Unable to find MonitoringGroup '%s' " "in registry, skipping.", group) group.add_node(self) super(Node, self).__init__(name, **kwargs) def _build_context(self, monitoring_group, monitor): context = {} for obj in (monitoring_group, self, monitor): context = obj.build_context(context) return context @property def monitors(self): if self._tasks: return self._tasks for group in self.monitoring_groups.itervalues(): for monitor in group.monitors.itervalues(): self._tasks.append(self._build_context(group, monitor)) return self._tasks
class Node(NanoResource): context_attributes = ['name', 'realm', 'address', 'node_monitor'] def __init__(self, name, realm=None, address=None, node_monitor=None, monitoring_groups=None, **kwargs): self.name = name self.realm = realm self.address = address or name self.node_monitor = node_monitor self.monitoring_groups = WeakValueDictionary() self._tasks = [] if monitoring_groups: for group in monitoring_groups: if not isinstance(group, MonitoringGroup): try: group = MonitoringGroup.registry[group] except KeyError: logger.error("Unable to find MonitoringGroup '%s' " "in registry, skipping.", group) group.add_node(self) super(Node, self).__init__(name, **kwargs) def _build_context(self, monitoring_group, monitor): context = {} for obj in (monitoring_group, self, monitor): context = obj.build_context(context) return context @property def monitors(self): if self._tasks: return self._tasks for group in self.monitoring_groups.itervalues(): for monitor in group.monitors.itervalues(): self._tasks.append(self._build_context(group, monitor)) return self._tasks
class Data(object): """ Class to handle Data, especailly Users: Data[item] -> returns a item object. If item is a string, it is case insensitive, but item can be anything. The item is stored as "handle" into the Item object, probably often just flying around, sometimes meaning you have double entries (with db). You can change self.main_key to change the default item to a name different from 'handle'. For example the ID in the database, or whatever. AS USER IS THE MAIN INTEREST, ALL HELP MAY REFER TO Users==Data and User == Item! Other things (ie, users.online) are added from outside. NOTES: o Use Registered functions to add functionality to user class. The registered function can change the items value by directly editing the User.items dictionary. o Registered functions are executed in the order that they are gotten. Classes ones are executed before Instance ones, so that they could modify the value before the instance thinks it changed. Instance ones _will_ also be executed if old == new. TIPS: o Instead of registering say "rating" which would be set when a function parsed the finger of a user, have it set "finger_update" = time.time() and register to that. That way you get notified even if the rating does not change AND always know when it was last updated. o For the same example, you might have a loader regestration for your database backend. The status module will set the items, but if a user is not connected, he does not have it set, so that loader gets called when you cannot get it through FICS. Yes, that means that you will need the dummy "finger_update" to force a reload through the finger function. (Of course this is rather hypethetical, afterall finger is always more up to date ;)) Maybe the buffer should be improved ... """ def __init__(self, main_key='handle', buffer_size = 20): # Define a dummy class and self.Item to make sure that each Users class # has its own child User class. class Items(_Item): _on_update = {} _loader = {} self.main_key = main_key Items.main_key = main_key self.Item = Items # Buffer to make sure we don't discard items that often ... # As long as the item has a reference stored here or ANYWHERE else # he will not be discarted. if buffer_size < 1: self._buffer = None else: self._buffer = [None]*buffer_size # dictionary mapping item_name -> item object. This is a WEAKREF! from weakref import WeakValueDictionary self._loaded_items = WeakValueDictionary() def register(self, item, function, persistent=True, loader=False): """ register(item, function, persistent=True) Register a function to be executed when item gets updated next time. Multiple functions can be registered, all will update when this happens. NOTES: o Function must take (item_object, item_name, old, new) as arguments. o Do not mass use this, otherwise its probably better to add it to the _item_set()/_item_load() special function. o loader keyword: The funciton is not called on set, but on a get event. (First time load). Only one function can be assigned. quietly overwrites all existing ones. Always persistent. The function MUST set the item. This will register for ALL items. """ if loader == True: self.Item._loader[item] = function return if self.Item._on_update.has_key(item): self.Item._on_update[item].append([function, persistent]) return self.Item._on_update[item] = [[function, persistent]] def unregister(self, item, function, loader): """ Unregister a function again ... """ if loader: del self.Item._loader[item] return try: self.Item._on_update[item].remove([function, True]) except ValueError: self.Item._on_update[item].remove([function, False]) def __getitem__(self, handle): try: ident = handle.lower() except AttributeError: ident = handle if not self._loaded_items.has_key(ident): return self._load(handle) #print handle, ident, self._loaded_items[ident].items return self._loaded_items[ident] def _load(self, handle): new_item = self.Item(handle) try: ident = handle.lower() except AttributeError: ident = handle self._loaded_items[ident] = new_item if self._buffer is not None: del self._buffer[0] self._buffer += [new_item] return new_item def iteritems(self): """Iterator over all stored items. """ return self._loaded_items.iteritems() def iterkeys(self): """Iterator over all stored keys. """ return self._loaded_items.iterkeys() def itervalues(self): """Iterator over all stored items. """ return self._loaded_items.itervalues() def __iter__(self): return self._loaded_items.__iter__()
class Data(object): """ Class to handle Data, especailly Users: Data[item] -> returns a item object. If item is a string, it is case insensitive, but item can be anything. The item is stored as "handle" into the Item object, probably often just flying around, sometimes meaning you have double entries (with db). You can change self.main_key to change the default item to a name different from 'handle'. For example the ID in the database, or whatever. AS USER IS THE MAIN INTEREST, ALL HELP MAY REFER TO Users==Data and User == Item! Other things (ie, users.online) are added from outside. NOTES: o Use Registered functions to add functionality to user class. The registered function can change the items value by directly editing the User.items dictionary. o Registered functions are executed in the order that they are gotten. Classes ones are executed before Instance ones, so that they could modify the value before the instance thinks it changed. Instance ones _will_ also be executed if old == new. TIPS: o Instead of registering say "rating" which would be set when a function parsed the finger of a user, have it set "finger_update" = time.time() and register to that. That way you get notified even if the rating does not change AND always know when it was last updated. o For the same example, you might have a loader regestration for your database backend. The status module will set the items, but if a user is not connected, he does not have it set, so that loader gets called when you cannot get it through FICS. Yes, that means that you will need the dummy "finger_update" to force a reload through the finger function. (Of course this is rather hypethetical, afterall finger is always more up to date ;)) Maybe the buffer should be improved ... """ def __init__(self, main_key='handle', buffer_size=20): # Define a dummy class and self.Item to make sure that each Users class # has its own child User class. class Items(_Item): _on_update = {} _loader = {} self.main_key = main_key Items.main_key = main_key self.Item = Items # Buffer to make sure we don't discard items that often ... # As long as the item has a reference stored here or ANYWHERE else # he will not be discarted. if buffer_size < 1: self._buffer = None else: self._buffer = [None] * buffer_size # dictionary mapping item_name -> item object. This is a WEAKREF! from weakref import WeakValueDictionary self._loaded_items = WeakValueDictionary() def register(self, item, function, persistent=True, loader=False): """ register(item, function, persistent=True) Register a function to be executed when item gets updated next time. Multiple functions can be registered, all will update when this happens. NOTES: o Function must take (item_object, item_name, old, new) as arguments. o Do not mass use this, otherwise its probably better to add it to the _item_set()/_item_load() special function. o loader keyword: The funciton is not called on set, but on a get event. (First time load). Only one function can be assigned. quietly overwrites all existing ones. Always persistent. The function MUST set the item. This will register for ALL items. """ if loader == True: self.Item._loader[item] = function return if self.Item._on_update.has_key(item): self.Item._on_update[item].append([function, persistent]) return self.Item._on_update[item] = [[function, persistent]] def unregister(self, item, function, loader): """ Unregister a function again ... """ if loader: del self.Item._loader[item] return try: self.Item._on_update[item].remove([function, True]) except ValueError: self.Item._on_update[item].remove([function, False]) def __getitem__(self, handle): try: ident = handle.lower() except AttributeError: ident = handle if not self._loaded_items.has_key(ident): return self._load(handle) #print handle, ident, self._loaded_items[ident].items return self._loaded_items[ident] def _load(self, handle): new_item = self.Item(handle) try: ident = handle.lower() except AttributeError: ident = handle self._loaded_items[ident] = new_item if self._buffer is not None: del self._buffer[0] self._buffer += [new_item] return new_item def iteritems(self): """Iterator over all stored items. """ return self._loaded_items.iteritems() def iterkeys(self): """Iterator over all stored keys. """ return self._loaded_items.iterkeys() def itervalues(self): """Iterator over all stored items. """ return self._loaded_items.itervalues() def __iter__(self): return self._loaded_items.__iter__()