--- logging/__init__.py-orig 2006-11-02 15:09:21.000000000 +1100 +++ logging/__init__.py 2006-12-13 12:00:59.000000000 +1100 @@ -544,9 +544,112 @@ #--------------------------------------------------------------------------- # Handler classes and functions #--------------------------------------------------------------------------- +_marker = object() -_handlers = {} #repository of handlers (for flushing when shutdown called) -_handlerList = [] # added to allow handlers to be removed in reverse of order initialized +class OrderedDict(dict): + _order = [] + + def __init__(self, *args, **kwargs): + """ Initialise the dict and the order with keys """ + dict.__init__(self, *args, **kwargs) + self._order = dict.keys(self) + + def __setitem__(self, key, value): + """ Set the key, if new make it the last one """ + if key not in self: + self._order.append(key) + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + """ Standard delete just remove from order too """ + dict.__delitem__(self, key) + self._order.remove(key) + + def update(self, _d): + for key, value in _d.items(): + self[key] = value + + def keys(self): + """ Return an order list of the keys """ + return self._order + + def clear(self): + """ Empty the dict and keys order """ + self._order = [] + dict.clear(self) + + def items(self): + """ + Return the list of tuples (key, val) in the correct order they were + added. + """ + return [ kv for kv in self.iteritems() ] + + def itervalues(self): + """ + Returns a generator for iterating over the values of this dict + """ + for key in self._order: + yield self[key] + + def iteritems(self): + """ + Returns a generator for iterating over the tuple of (key, val) pairs + in this dictionary, returns them in the order they were added. + """ + for key in self._order: + yield (key, self[key]) + + def iterkeys(self): + """ Returns an iterator over the ordered keys """ + return iter(self._order) + + def pop(self, key, default=_marker): + """ + Remove the specified key from the mapping and return the corresponding + value. + """ + if key in self: + value = self[key] + del self[key] + elif default is not _marker: + value = default + else: + raise KeyError('%s is not in dictionary.' % key) + return value + + def popitem(self, key, default=_marker): + """ + Remove the given key from the mapping and return the (k, v) tuple + """ + if key in self: + value = self[key] + del self[key] + elif default is not _marker: + value = default + else: + raise KeyError('%s is not in dictionary.' % key) + return (key, value) + + def callOnKeys(self, callback, reverse=False): + """ + Call the function `callback` for each 'key' in this dictionary. + + :Parameters: + - `callback` is a function which expects a single argument. + + Iterate over the keys of this dictionary calling `callback` passing + the key. This is done in an ordered manner. + """ + # take a copy of the keys in case the `callback` is modifying this dict + keys = self._order[:] + if reverse: + keys.reverse() + map(callback, keys) + + +#repository of handlers (for flushing when shutdown called) +_handlers = OrderedDict() class Handler(Filterer): """ @@ -569,7 +672,6 @@ _acquireLock() try: #unlikely to raise an exception, but you never know... _handlers[self] = 1 - _handlerList.insert(0, self) finally: _releaseLock() self.createLock() @@ -672,7 +774,6 @@ _acquireLock() try: #unlikely to raise an exception, but you never know... del _handlers[self] - _handlerList.remove(self) finally: _releaseLock() @@ -1324,17 +1425,22 @@ buffers). Should be called at application exit. + + Shutdown handlers in the opposite order to what they were added. """ - for h in _handlerList[:]: # was _handlers.keys(): + def func(handler): #errors might occur, for example, if files are locked #we just ignore them if raiseExceptions is not set try: - h.flush() - h.close() + handler.flush() + handler.close() except: if raiseExceptions: raise #else, swallow + _handlers.callOnKeys(func, reverse=True) + if len(_handlers) and raiseExceptions: + raise ValueError('not all handlers closed at shutdown.') #Let's try and shutdown automatically on application exit... try: