Merged revisions 77967,77969,77973,77979,77985-77986,78009,78029,78031-78033,78081,78085,78103,78105-78106,78108,78246,78703,78728,78731,78853,78855 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r77967 | vinay.sajip | 2010-02-04 12:48:53 -0600 (Thu, 04 Feb 2010) | 1 line

  Logging: Implemented PEP 391.
........
  r77969 | vinay.sajip | 2010-02-04 14:18:28 -0600 (Thu, 04 Feb 2010) | 1 line

  Removed spurious print statement.
........
  r77973 | vinay.sajip | 2010-02-04 14:23:45 -0600 (Thu, 04 Feb 2010) | 1 line

  Issue #7851: logging: clarification on logging configuration files.
........
  r77979 | vinay.sajip | 2010-02-04 15:40:56 -0600 (Thu, 04 Feb 2010) | 1 line

  Added unit test for cfg:// resolution.
........
  r77985 | vinay.sajip | 2010-02-05 08:52:05 -0600 (Fri, 05 Feb 2010) | 1 line

  Issue #7857: test_logging: listener test now uses find_unused_port().
........
  r77986 | vinay.sajip | 2010-02-05 09:40:20 -0600 (Fri, 05 Feb 2010) | 1 line

  Issue #7857: test_logging: listener tests disabled for now.
........
  r78009 | vinay.sajip | 2010-02-05 17:43:11 -0600 (Fri, 05 Feb 2010) | 1 line

  test_logging: minor tweaks to timeouts, listening tests marked as skipped.
........
  r78029 | vinay.sajip | 2010-02-06 14:00:43 -0600 (Sat, 06 Feb 2010) | 1 line

  Issue #7857: Tentatively re-enabling one test to see effect on buildbots.
........
  r78031 | vinay.sajip | 2010-02-06 14:28:36 -0600 (Sat, 06 Feb 2010) | 1 line

  Issue #7857: Gave server thread more time to get ready, and re-enabled a skipped test.
........
  r78032 | georg.brandl | 2010-02-06 15:54:40 -0600 (Sat, 06 Feb 2010) | 1 line

  Remove unused imports from test_logging.
........
  r78033 | benjamin.peterson | 2010-02-06 16:08:15 -0600 (Sat, 06 Feb 2010) | 1 line

  make waiting for the server to start robust
........
  r78081 | vinay.sajip | 2010-02-07 06:56:54 -0600 (Sun, 07 Feb 2010) | 1 line

  Issue #7869: logging: improved format-time diagnostics and removed some 1.5.2 support code.
........
  r78085 | vinay.sajip | 2010-02-07 07:06:51 -0600 (Sun, 07 Feb 2010) | 1 line

  logging: Removed some more 1.5.2 support code.
........
  r78103 | vinay.sajip | 2010-02-08 00:50:14 -0600 (Mon, 08 Feb 2010) | 1 line

  Removed spurious print statement in test.
........
  r78105 | vinay.sajip | 2010-02-08 09:32:08 -0600 (Mon, 08 Feb 2010) | 1 line

  logging: skipped listening tests because they're not working reliably.
........
  r78106 | vinay.sajip | 2010-02-08 10:05:50 -0600 (Mon, 08 Feb 2010) | 1 line

  Issue #7857: Another attempt to keep the buildbots happy.
........
  r78108 | vinay.sajip | 2010-02-08 15:18:15 -0600 (Mon, 08 Feb 2010) | 1 line

  logging: gingerly re-enabling skipped tests after improving thread sync code in configurator.
........
  r78246 | vinay.sajip | 2010-02-19 17:53:17 -0600 (Fri, 19 Feb 2010) | 1 line

  logging: Documented warnings module integration.
........
  r78703 | vinay.sajip | 2010-03-05 16:11:24 -0600 (Fri, 05 Mar 2010) | 1 line

  Factored out time usage determination into a method, to facilitate alternative formatting implementations in the future.
........
  r78728 | vinay.sajip | 2010-03-06 09:12:08 -0600 (Sat, 06 Mar 2010) | 1 line

  Added schema version test in dictConfig.
........
  r78731 | vinay.sajip | 2010-03-06 09:56:03 -0600 (Sat, 06 Mar 2010) | 1 line

  Added checks for tuples in dictConfig.
........
  r78853 | vinay.sajip | 2010-03-12 00:01:21 -0600 (Fri, 12 Mar 2010) | 1 line

  Issue #8117: logging: Improved algorithm for computing initial rollover time.
........
  r78855 | vinay.sajip | 2010-03-12 03:16:10 -0600 (Fri, 12 Mar 2010) | 1 line

  Issue #8117: Updated NEWS entry and added to logging documentation.
........
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 073213f..3d7ff82 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -432,6 +432,12 @@
             s = s[:-1]
         return s
 
+    def usesTime(self):
+        """
+        Check if the format uses the creation time of the record.
+        """
+        return self._fmt.find("%(asctime)") >= 0
+
     def format(self, record):
         """
         Format the specified record as text.
@@ -440,13 +446,13 @@
         string formatting operation which yields the returned string.
         Before formatting the dictionary, a couple of preparatory steps
         are carried out. The message attribute of the record is computed
-        using LogRecord.getMessage(). If the formatting string contains
-        "%(asctime)", formatTime() is called to format the event time.
-        If there is exception information, it is formatted using
-        formatException() and appended to the message.
+        using LogRecord.getMessage(). If the formatting string uses the
+        time (as determined by a call to usesTime(), formatTime() is
+        called to format the event time. If there is exception information,
+        it is formatted using formatException() and appended to the message.
         """
         record.message = record.getMessage()
-        if self._fmt.find("%(asctime)") >= 0:
+        if self.usesTime():
             record.asctime = self.formatTime(record, self.datefmt)
         s = self._fmt % record.__dict__
         if record.exc_info:
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 767c630..beb51e5 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -261,7 +261,6 @@
             logger.disabled = 1
 
 
-
 IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)
 
 
@@ -448,7 +447,7 @@
                  isinstance(value, tuple):
             value = ConvertingTuple(value)
             value.configurator = self
-        elif isinstance(value, str):
+        elif isinstance(value, str): # str for py3k
             m = self.CONVERT_PATTERN.match(value)
             if m:
                 d = m.groupdict()
@@ -474,6 +473,12 @@
                 setattr(result, name, value)
         return result
 
+    def as_tuple(self, value):
+        """Utility function which converts lists to tuples."""
+        if isinstance(value, list):
+            value = tuple(value)
+        return value
+
 class DictConfigurator(BaseConfigurator):
     """
     Configure logging using a dictionary-like object to describe the
@@ -484,6 +489,10 @@
         """Do the configuration."""
 
         config = self.config
+        if 'version' not in config:
+            raise ValueError("dictionary doesn't specify a version")
+        if config['version'] != 1:
+            raise ValueError("Unsupported version: %s" % config['version'])
         incremental = config.pop('incremental', False)
         EMPTY_DICT = {}
         logging._acquireLock()
@@ -684,6 +693,12 @@
                 except Exception as e:
                     raise ValueError('Unable to set target handler '
                                      '%r: %s' % (config['target'], e))
+            elif issubclass(klass, logging.handlers.SMTPHandler) and\
+                'mailhost' in config:
+                config['mailhost'] = self.as_tuple(config['mailhost'])
+            elif issubclass(klass, logging.handlers.SysLogHandler) and\
+                'address' in config:
+                config['address'] = self.as_tuple(config['address'])
             factory = klass
         kwargs = dict([(k, config[k]) for k in config if valid_ident(k)])
         try:
@@ -788,7 +803,7 @@
                     chunk = self.connection.recv(slen)
                     while len(chunk) < slen:
                         chunk = chunk + conn.recv(slen - len(chunk))
-                    chunk = chunk.decode('utf-8')
+                    chunk = chunk.decode("utf-8")
                     try:
                         import json
                         d =json.loads(chunk)
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 1e174e6..692d104 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -25,7 +25,7 @@
 """
 
 import logging, socket, os, pickle, struct, time, re
-from stat import ST_DEV, ST_INO
+from stat import ST_DEV, ST_INO, ST_MTIME
 
 try:
     import codecs
@@ -203,7 +203,11 @@
 
         self.extMatch = re.compile(self.extMatch, re.ASCII)
         self.interval = self.interval * interval # multiply by units requested
-        self.rolloverAt = self.computeRollover(int(time.time()))
+        if os.path.exists(filename):
+            t = os.stat(filename)[ST_MTIME]
+        else:
+            t = int(time.time())
+        self.rolloverAt = self.computeRollover(t)
 
     def computeRollover(self, currentTime):
         """