[Zodb-checkins] CVS: ZODB3/logging - handlers.py:1.3 config.py:1.4 __init__.py:1.3

Jeremy Hylton jeremy at zope.com
Thu Oct 2 14:17:48 EDT 2003


Update of /cvs-repository/ZODB3/logging
In directory cvs.zope.org:/tmp/cvs-serv18770/logging

Modified Files:
	handlers.py config.py __init__.py 
Log Message:
Merge changes from Zope-2_7-branch to the trunk.


=== ZODB3/logging/handlers.py 1.2 => 1.3 ===
--- ZODB3/logging/handlers.py:1.2	Wed Dec 11 16:17:09 2002
+++ ZODB3/logging/handlers.py	Thu Oct  2 14:17:17 2003
@@ -1,5 +1,3 @@
-#! /usr/bin/env python
-#
 # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
 #
 # Permission to use, copy, modify, and distribute this software and its
@@ -15,12 +13,6 @@
 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# For the change history, see README.txt in the distribution.
-#
-# This file is part of the Python logging distribution. See
-# http://www.red-dove.com/python_logging.html
-#
 
 """
 Logging package for Python. Based on PEP 282 and comments thereto in
@@ -34,7 +26,7 @@
 To use, simply 'import logging' and log away!
 """
 
-import sys, logging, socket, types, os, string, cPickle, struct
+import sys, logging, socket, types, os, string, cPickle, struct, time
 
 from SocketServer import ThreadingTCPServer, StreamRequestHandler
 
@@ -108,7 +100,7 @@
         """
         if self.maxBytes > 0:                   # are we rolling over?
             msg = "%s\n" % self.format(record)
-            #print msg
+            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
             if self.stream.tell() + len(msg) >= self.maxBytes:
                 self.doRollover()
         logging.FileHandler.emit(self, record)
@@ -119,8 +111,12 @@
     A handler class which writes logging records, in pickle format, to
     a streaming socket. The socket is kept open across logging calls.
     If the peer resets it, an attempt is made to reconnect on the next call.
-    Note that the very simple wire protocol used means that packet sizes
-    are expected to be encodable within 16 bits (i.e. < 32767 bytes).
+    The pickle which is sent is that of the LogRecord's attribute dictionary
+    (__dict__), so that the receiver does not need to have the logging module
+    installed in order to process the logging event.
+
+    To unpickle the record at the receiving end into a LogRecord, use the
+    makeLogRecord function.
     """
 
     def __init__(self, host, port):
@@ -153,11 +149,7 @@
         This function allows for partial sends which can happen when the
         network is busy.
         """
-        try:
-            v = sys.version_info
-        except:
-            v = None
-        if v and (v[0] >= 2) and (v[1] >= 2):
+        if hasattr(self.sock, "sendall"):
             self.sock.sendall(s)
         else:
             sentsofar = 0
@@ -178,7 +170,7 @@
         slen = struct.pack(">L", len(s))
         return slen + s
 
-    def handleError(self):
+    def handleError(self, record):
         """
         Handle an error during logging.
 
@@ -190,7 +182,7 @@
             self.sock.close()
             self.sock = None        #try to reconnect next time
         else:
-            logging.Handler.handleError(self)
+            logging.Handler.handleError(self, record)
 
     def emit(self, record):
         """
@@ -207,7 +199,7 @@
                 self.sock = self.makeSocket()
             self.send(s)
         except:
-            self.handleError()
+            self.handleError(record)
 
     def close(self):
         """
@@ -220,9 +212,12 @@
 class DatagramHandler(SocketHandler):
     """
     A handler class which writes logging records, in pickle format, to
-    a datagram socket. Note that the very simple wire protocol used means
-    that packet sizes are expected to be encodable within 16 bits
-    (i.e. < 32767 bytes).
+    a datagram socket.  The pickle which is sent is that of the LogRecord's
+    attribute dictionary (__dict__), so that the receiver does not need to
+    have the logging module installed in order to process the logging event.
+
+    To unpickle the record at the receiving end into a LogRecord, use the
+    makeLogRecord function.
 
     """
     def __init__(self, host, port):
@@ -248,14 +243,6 @@
         when the network is busy - UDP does not guarantee delivery and
         can deliver packets out of sequence.
         """
-        #old code
-        #sentsofar = 0
-        #left = len(s)
-        #addr = (self.host, self.port)
-        #while left > 0:
-        #    sent = self.sock.sendto(s[sentsofar:], addr)
-        #    sentsofar = sentsofar + sent
-        #    left = left - sent
         self.sock.sendto(s, (self.host, self.port))
 
 class SysLogHandler(logging.Handler):
@@ -360,6 +347,12 @@
         self.facility = facility
         if type(address) == types.StringType:
             self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+            # syslog may require either DGRAM or STREAM sockets
+            try:
+                self.socket.connect(address)
+            except socket.error:
+                self.socket.close()
+                self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
             self.socket.connect(address)
             self.unixsocket = 1
         else:
@@ -416,7 +409,7 @@
             else:
                 self.socket.sendto(msg, self.address)
         except:
-            self.handleError()
+            self.handleError(record)
 
 class SMTPHandler(logging.Handler):
     """
@@ -439,6 +432,8 @@
             self.mailhost = mailhost
             self.mailport = None
         self.fromaddr = fromaddr
+        if type(toaddrs) == types.StringType:
+            toaddrs = [toaddrs]
         self.toaddrs = toaddrs
         self.subject = subject
 
@@ -451,6 +446,21 @@
         """
         return self.subject
 
+    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+
+    monthname = [None,
+                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+    def date_time(self):
+        """Return the current date and time formatted for a MIME header."""
+        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time())
+        s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
+                self.weekdayname[wd],
+                day, self.monthname[month], year,
+                hh, mm, ss)
+        return s
+
     def emit(self, record):
         """
         Emit a record.
@@ -464,15 +474,15 @@
                 port = smtplib.SMTP_PORT
             smtp = smtplib.SMTP(self.mailhost, port)
             msg = self.format(record)
-            msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s" % (
+            msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
                             self.fromaddr,
                             string.join(self.toaddrs, ","),
-                            self.getSubject(record), msg
-                            )
+                            self.getSubject(record),
+                            self.date_time(), msg)
             smtp.sendmail(self.fromaddr, self.toaddrs, msg)
             smtp.quit()
         except:
-            self.handleError()
+            self.handleError(record)
 
 class NTEventLogHandler(logging.Handler):
     """
@@ -501,7 +511,7 @@
             self.typemap = {
                 logging.DEBUG   : win32evtlog.EVENTLOG_INFORMATION_TYPE,
                 logging.INFO    : win32evtlog.EVENTLOG_INFORMATION_TYPE,
-                logging.WARN    : win32evtlog.EVENTLOG_WARNING_TYPE,
+                logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE,
                 logging.ERROR   : win32evtlog.EVENTLOG_ERROR_TYPE,
                 logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
          }
@@ -536,7 +546,7 @@
         Override this if you want to specify your own types. This version does
         a mapping using the handler's typemap attribute, which is set up in
         __init__() to a dictionary which contains mappings for DEBUG, INFO,
-        WARN, ERROR and CRITICAL. If you are using your own levels you will
+        WARNING, ERROR and CRITICAL. If you are using your own levels you will
         either need to override this method or place a suitable dictionary in
         the handler's typemap attribute.
         """
@@ -557,7 +567,7 @@
                 msg = self.format(record)
                 self._welu.ReportEvent(self.appname, id, cat, type, [msg])
             except:
-                self.handleError()
+                self.handleError(record)
 
     def close(self):
         """
@@ -590,6 +600,14 @@
         self.url = url
         self.method = method
 
+    def mapLogRecord(self, record):
+        """
+        Default implementation of mapping the log record into a dict
+        that is send as the CGI data. Overwrite in your class.
+        Contributed by Franz  Glasner.
+        """
+        return record.__dict__
+
     def emit(self, record):
         """
         Emit a record.
@@ -600,7 +618,7 @@
             import httplib, urllib
             h = httplib.HTTP(self.host)
             url = self.url
-            data = urllib.urlencode(record.__dict__)
+            data = urllib.urlencode(self.mapLogRecord(record))
             if self.method == "GET":
                 if (string.find(url, '?') >= 0):
                     sep = '&'
@@ -615,7 +633,7 @@
                 h.send(data)
             h.getreply()    #can't do anything with the result
         except:
-            self.handleError()
+            self.handleError(record)
 
 class BufferingHandler(logging.Handler):
     """


=== ZODB3/logging/config.py 1.3 => 1.4 ===
--- ZODB3/logging/config.py:1.3	Thu Dec 19 20:55:00 2002
+++ ZODB3/logging/config.py	Thu Oct  2 14:17:17 2003
@@ -1,5 +1,3 @@
-#! /usr/bin/env python
-#
 # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
 #
 # Permission to use, copy, modify, and distribute this software and its
@@ -15,12 +13,6 @@
 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# For the change history, see README.txt in the distribution.
-#
-# This file is part of the Python logging distribution. See
-# http://www.red-dove.com/python_logging.html
-#
 
 """
 Logging package for Python. Based on PEP 282 and comments thereto in
@@ -48,7 +40,7 @@
 #   _listener holds the server object doing the listening
 _listener = None
 
-def fileConfig(fname,defaults=None):
+def fileConfig(fname, defaults=None):
     """
     Read the logging configuration from a ConfigParser-format file.
 
@@ -259,7 +251,7 @@
         allow_reuse_address = 1
 
         def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
-                handler=None):
+                     handler=None):
             ThreadingTCPServer.__init__(self, (host, port), handler)
             logging._acquireLock()
             self.abort = 0
@@ -279,20 +271,23 @@
                 abort = self.abort
                 logging._releaseLock()
 
-    def serve(rcvr, hdlr):
-        server = rcvr(handler=hdlr)
+    def serve(rcvr, hdlr, port):
+        server = rcvr(port=port, handler=hdlr)
         global _listener
         logging._acquireLock()
         _listener = server
         logging._releaseLock()
         server.serve_until_stopped()
 
-    return threading.Thread(target=serve, args=(ConfigSocketReceiver, ConfigStreamHandler))
+    return threading.Thread(target=serve,
+                            args=(ConfigSocketReceiver,
+                                  ConfigStreamHandler, port))
 
 def stopListening():
     """
     Stop the listening server which was created with a call to listen().
     """
+    global _listener
     if _listener:
         logging._acquireLock()
         _listener.abort = 1


=== ZODB3/logging/__init__.py 1.2 => 1.3 ===
--- ZODB3/logging/__init__.py:1.2	Wed Jul  9 12:25:32 2003
+++ ZODB3/logging/__init__.py	Thu Oct  2 14:17:17 2003
@@ -1,5 +1,3 @@
-#! /usr/bin/env python
-#
 # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved.
 #
 # Permission to use, copy, modify, and distribute this software and its
@@ -15,41 +13,31 @@
 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# For the change history, see README.txt in the distribution.
-#
-# This file is part of the Python logging distribution. See
-# http://www.red-dove.com/python_logging.html
-#
 
 """
 Logging package for Python. Based on PEP 282 and comments thereto in
 comp.lang.python, and influenced by Apache's log4j system.
 
 Should work under Python versions >= 1.5.2, except that source line
-information is not available unless 'inspect' is.
+information is not available unless 'sys._getframe()' is.
 
 Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved.
 
 To use, simply 'import logging' and log away!
 """
 
-import sys, os, types, time, string, struct, cPickle, cStringIO
+import sys, os, types, time, string, cStringIO
 
 try:
     import thread
     import threading
 except ImportError:
     thread = None
-try:
-    import inspect
-except ImportError:
-    inspect = None
 
 __author__  = "Vinay Sajip <vinay_sajip at red-dove.com>"
-__status__  = "alpha"
-__version__ = "0.4.7"
-__date__    = "15 November 2002"
+__status__  = "beta"
+__version__ = "0.4.8.1"
+__date__    = "26 June 2003"
 
 #---------------------------------------------------------------------------
 #   Miscellaneous module data
@@ -58,16 +46,19 @@
 #
 #_srcfile is used when walking the stack to check when we've got the first
 # caller stack frame.
-#If run as a script, __file__ is not bound.
 #
-if __name__ == "__main__":
-    _srcfile = None
+if string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
+    _srcfile = __file__[:-4] + '.py'
 else:
-    if string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
-        _srcfile = __file__[:-4] + '.py'
-    else:
-        _srcfile = __file__
-    _srcfile = os.path.normcase(_srcfile)
+    _srcfile = __file__
+_srcfile = os.path.normcase(_srcfile)
+
+# _srcfile is only used in conjunction with sys._getframe().
+# To provide compatibility with older versions of Python, set _srcfile
+# to None if _getframe() is not available; this value will prevent
+# findCaller() from being called.
+if not hasattr(sys, "_getframe"):
+    _srcfile = None
 
 #
 #_startTime is used as the base when calculating the relative time of events
@@ -80,13 +71,11 @@
 #
 raiseExceptions = 1
 
-
 # apply() is defined locally to avoid deprecation warnings for Python
 # 2.3 and newer
 def apply(func, args, kwargs):
     return func(*args, **kwargs)
 
-
 #---------------------------------------------------------------------------
 #   Level related stuff
 #---------------------------------------------------------------------------
@@ -100,7 +89,8 @@
 CRITICAL = 50
 FATAL = CRITICAL
 ERROR = 40
-WARN = 30
+WARNING = 30
+WARN = WARNING
 INFO = 20
 DEBUG = 10
 NOTSET = 0
@@ -108,13 +98,14 @@
 _levelNames = {
     CRITICAL : 'CRITICAL',
     ERROR : 'ERROR',
-    WARN : 'WARN',
+    WARNING : 'WARNING',
     INFO : 'INFO',
     DEBUG : 'DEBUG',
     NOTSET : 'NOTSET',
     'CRITICAL' : CRITICAL,
     'ERROR' : ERROR,
-    'WARN' : WARN,
+    'WARN' : WARNING,
+    'WARNING' : WARNING,
     'INFO' : INFO,
     'DEBUG' : DEBUG,
     'NOTSET' : NOTSET,
@@ -124,7 +115,7 @@
     """
     Return the textual representation of logging level 'level'.
 
-    If the level is one of the predefined levels (CRITICAL, ERROR, WARN,
+    If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
     INFO, DEBUG) then you get the corresponding string. If you have
     associated levels with names using addLevelName then the name you have
     associated with 'level' is returned. Otherwise, the string
@@ -220,6 +211,10 @@
             self.thread = thread.get_ident()
         else:
             self.thread = None
+        if hasattr(os, 'getpid'):
+            self.process = os.getpid()
+        else:
+            self.process = None
 
     def __str__(self):
         return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
@@ -232,11 +227,28 @@
         Return the message for this LogRecord after merging any user-supplied
         arguments with the message.
         """
-        msg = str(self.msg)
+        if not hasattr(types, "UnicodeType"): #if no unicode support...
+            msg = str(self.msg)
+        else:
+            try:
+                msg = str(self.msg)
+            except UnicodeError:
+                msg = self.msg      #Defer encoding till later
         if self.args:
             msg = msg % self.args
         return msg
 
+def makeLogRecord(dict):
+    """
+    Make a LogRecord whose attributes are defined by the specified dictionary,
+    This function is useful for converting a logging event received over
+    a socket connection (which is sent as a dictionary) into a LogRecord
+    instance.
+    """
+    rv = LogRecord(None, None, "", 0, "", (), None)
+    rv.__dict__.update(dict)
+    return rv
+
 #---------------------------------------------------------------------------
 #   Formatter classes and functions
 #---------------------------------------------------------------------------
@@ -259,9 +271,9 @@
 
     %(name)s            Name of the logger (logging channel)
     %(levelno)s         Numeric logging level for the message (DEBUG, INFO,
-                        WARN, ERROR, CRITICAL)
+                        WARNING, ERROR, CRITICAL)
     %(levelname)s       Text logging level for the message ("DEBUG", "INFO",
-                        "WARN", "ERROR", "CRITICAL")
+                        "WARNING", "ERROR", "CRITICAL")
     %(pathname)s        Full pathname of the source file where the logging
                         call was issued (if available)
     %(filename)s        Filename portion of pathname
@@ -276,6 +288,7 @@
                         relative to the time the logging module was loaded
                         (typically at application startup time)
     %(thread)d          Thread ID (if available)
+    %(process)d         Process ID (if available)
     %(message)s         The result of record.getMessage(), computed just as
                         the record is emitted
     """
@@ -574,14 +587,17 @@
 
         Emission depends on filters which may have been added to the handler.
         Wrap the actual emission of the record with acquisition/release of
-        the I/O thread lock.
+        the I/O thread lock. Returns whether the filter passed the record for
+        emission.
         """
-        if self.filter(record):
+        rv = self.filter(record)
+        if rv:
             self.acquire()
             try:
                 self.emit(record)
             finally:
                 self.release()
+        return rv
 
     def setFormatter(self, fmt):
         """
@@ -607,17 +623,17 @@
         """
         pass
 
-    def handleError(self):
+    def handleError(self, record):
         """
         Handle errors which occur during an emit() call.
 
         This method should be called from handlers when an exception is
-        encountered during an emit() call. By default it does nothing,
-        because by default raiseExceptions is false, which means that
+        encountered during an emit() call. If raiseExceptions is false,
         exceptions get silently ignored. This is what is mostly wanted
         for a logging system - most users will not care about errors in
         the logging system, they are more interested in application errors.
         You could, however, replace this with a custom handler if you wish.
+        The record which was being processed is passed in to this method.
         """
         if raiseExceptions:
             import traceback
@@ -661,10 +677,16 @@
         """
         try:
             msg = self.format(record)
-            self.stream.write("%s\n" % msg)
+            if not hasattr(types, "UnicodeType"): #if no unicode support...
+                self.stream.write("%s\n" % msg)
+            else:
+                try:
+                    self.stream.write("%s\n" % msg)
+                except UnicodeError:
+                    self.stream.write("%s\n" % msg.encode("UTF-8"))
             self.flush()
         except:
-            self.handleError()
+            self.handleError(record)
 
 class FileHandler(StreamHandler):
     """
@@ -719,8 +741,6 @@
     __init__() should call Logger.__init__()
     """
     if klass != Logger:
-        if type(klass) != types.ClassType:
-            raise TypeError, "setLoggerClass is expecting a class"
         if not issubclass(klass, Logger):
             raise TypeError, "logger not derived from logging.Logger: " + \
                             klass.__name__
@@ -732,11 +752,11 @@
     There is [under normal circumstances] just one Manager instance, which
     holds the hierarchy of loggers.
     """
-    def __init__(self, root):
+    def __init__(self, rootnode):
         """
         Initialize the manager with the root node of the logger hierarchy.
         """
-        self.root = root
+        self.root = rootnode
         self.disable = 0
         self.emittedNoHandlerWarning = 0
         self.loggerDict = {}
@@ -877,19 +897,21 @@
         if INFO >= self.getEffectiveLevel():
             apply(self._log, (INFO, msg, args), kwargs)
 
-    def warn(self, msg, *args, **kwargs):
+    def warning(self, msg, *args, **kwargs):
         """
-        Log 'msg % args' with severity 'WARN'.
+        Log 'msg % args' with severity 'WARNING'.
 
         To pass exception information, use the keyword argument exc_info with
         a true value, e.g.
 
-        logger.warn("Houston, we have a %s", "bit of a problem", exc_info=1)
+        logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1)
         """
-        if self.manager.disable >= WARN:
+        if self.manager.disable >= WARNING:
             return
-        if self.isEnabledFor(WARN):
-            apply(self._log, (WARN, msg, args), kwargs)
+        if self.isEnabledFor(WARNING):
+            apply(self._log, (WARNING, msg, args), kwargs)
+
+    warn = warning
 
     def error(self, msg, *args, **kwargs):
         """
@@ -946,19 +968,14 @@
         Find the stack frame of the caller so that we can note the source
         file name and line number.
         """
-        rv = (None, None)
-        frame = inspect.currentframe().f_back
-        while frame:
-            sfn = inspect.getsourcefile(frame)
-            if sfn:
-                sfn = os.path.normcase(sfn)
-            if sfn != _srcfile:
-                #print frame.f_code.co_code
-                lineno = inspect.getlineno(frame)
-                rv = (sfn, lineno)
-                break
-            frame = frame.f_back
-        return rv
+        f = sys._getframe(1)
+        while 1:
+            co = f.f_code
+            filename = os.path.normcase(co.co_filename)
+            if filename == _srcfile:
+                f = f.f_back
+                continue
+            return filename, f.f_lineno
 
     def makeRecord(self, name, level, fn, lno, msg, args, exc_info):
         """
@@ -972,12 +989,8 @@
         Low-level logging routine which creates a LogRecord and then calls
         all the handlers of this logger to handle the record.
         """
-        if inspect and _srcfile:
-            _acquireLock()
-            try:
-                fn, lno = self.findCaller()
-            finally:
-                _releaseLock()
+        if _srcfile:
+            fn, lno = self.findCaller()
         else:
             fn, lno = "<unknown file>", 0
         if exc_info:
@@ -1007,7 +1020,7 @@
         Remove the specified handler from this logger.
         """
         if hdlr in self.handlers:
-            hdlr.close()
+            #hdlr.close()
             self.handlers.remove(hdlr)
 
     def callHandlers(self, record):
@@ -1072,7 +1085,7 @@
 
 _loggerClass = Logger
 
-root = RootLogger(WARN)
+root = RootLogger(WARNING)
 Logger.root = root
 Logger.manager = Manager(Logger.root)
 
@@ -1144,13 +1157,15 @@
     """
     apply(error, (msg,)+args, {'exc_info': 1})
 
-def warn(msg, *args, **kwargs):
+def warning(msg, *args, **kwargs):
     """
-    Log a message with severity 'WARN' on the root logger.
+    Log a message with severity 'WARNING' on the root logger.
     """
     if len(root.handlers) == 0:
         basicConfig()
-    apply(root.warn, (msg,)+args, kwargs)
+    apply(root.warning, (msg,)+args, kwargs)
+
+warn = warning
 
 def info(msg, *args, **kwargs):
     """
@@ -1184,6 +1199,3 @@
     for h in _handlers.keys():
         h.flush()
         h.close()
-
-if __name__ == "__main__":
-    print __doc__




More information about the Zodb-checkins mailing list