Merged revisions 59985-60000,60002,60005-60007,60009-60042 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r59987 | raymond.hettinger | 2008-01-15 21:52:42 +0100 (Tue, 15 Jan 2008) | 1 line

  Refactor if/elif chain for clarity and speed.  Remove dependency on subclasses having to implement _empty and _full.
........
  r59988 | raymond.hettinger | 2008-01-15 22:22:47 +0100 (Tue, 15 Jan 2008) | 1 line

  Fix-up half-written paragraph in the docs
........
  r59989 | amaury.forgeotdarc | 2008-01-15 22:25:11 +0100 (Tue, 15 Jan 2008) | 3 lines

  test_doctest fails since r59984.
  Not sure if these are the correct values, but save_stdout has to be set before its usage...
........
  r59992 | andrew.kuchling | 2008-01-16 01:32:03 +0100 (Wed, 16 Jan 2008) | 1 line

  Docstring typos
........
  r59993 | andrew.kuchling | 2008-01-16 04:17:25 +0100 (Wed, 16 Jan 2008) | 1 line

  Add PEP 3141 section
........
  r59998 | andrew.kuchling | 2008-01-16 14:01:51 +0100 (Wed, 16 Jan 2008) | 1 line

  Markup fix
........
  r59999 | georg.brandl | 2008-01-16 17:56:29 +0100 (Wed, 16 Jan 2008) | 2 lines

  Fix MSDN library URL. (#1854)
........
  r60006 | georg.brandl | 2008-01-16 21:27:56 +0100 (Wed, 16 Jan 2008) | 3 lines

  Add Python-specific content to Doc dir. Update configuration file
  to work with the newest Sphinx.
........
  r60007 | georg.brandl | 2008-01-16 21:29:00 +0100 (Wed, 16 Jan 2008) | 2 lines

  Doc build should work with 2.4 now.
........
  r60009 | raymond.hettinger | 2008-01-17 00:38:16 +0100 (Thu, 17 Jan 2008) | 1 line

  Minor wordsmithing.
........
  r60010 | raymond.hettinger | 2008-01-17 00:40:45 +0100 (Thu, 17 Jan 2008) | 1 line

  Add queues will alternative fetch orders (priority based and stack based).
........
  r60011 | raymond.hettinger | 2008-01-17 00:49:35 +0100 (Thu, 17 Jan 2008) | 1 line

  Add news entry.
........
  r60013 | raymond.hettinger | 2008-01-17 04:02:14 +0100 (Thu, 17 Jan 2008) | 1 line

  Make starmap() match its pure python definition and accept any itertable input (not just tuples).
........
  r60015 | gregory.p.smith | 2008-01-17 08:43:20 +0100 (Thu, 17 Jan 2008) | 3 lines

  Comply with RFC 3207.
  Fixes issue 829951 - http://bugs.python.org/issue829951
........
  r60018 | gregory.p.smith | 2008-01-17 09:03:17 +0100 (Thu, 17 Jan 2008) | 2 lines

  entry for r60015
........
  r60019 | raymond.hettinger | 2008-01-17 09:07:05 +0100 (Thu, 17 Jan 2008) | 1 line

  Note versionadded.
........
  r60020 | gregory.p.smith | 2008-01-17 09:35:49 +0100 (Thu, 17 Jan 2008) | 8 lines

  Fixes (accepts patch) issue1339 - http://bugs.python.org/issue1339
  - Factor out the duplication of EHLO/HELO in login() and sendmail() to
    a new function, ehlo_or_helo_if_needed().
  - Use ehlo_or_helo_if_needed() in starttls()
  - Check for the starttls exception in starttls() in the same way as
    login() checks for the auth extension.
  Contributed by Bill Fenner.
........
  r60021 | andrew.kuchling | 2008-01-17 13:00:15 +0100 (Thu, 17 Jan 2008) | 1 line

  Revise 3141 section a bit; add some Windows items
........
  r60022 | brett.cannon | 2008-01-17 19:45:10 +0100 (Thu, 17 Jan 2008) | 2 lines

  Fix a function pointer declaration to silence the compiler.
........
  r60024 | raymond.hettinger | 2008-01-17 20:31:38 +0100 (Thu, 17 Jan 2008) | 1 line

  Issue #1861:  Add read-only attribute listing upcoming events in the order they will be run.
........
  r60025 | andrew.kuchling | 2008-01-17 20:49:24 +0100 (Thu, 17 Jan 2008) | 1 line

  Correction from Jordan Lewis: halfdelay() uses tenths of a second, not milliseconds
........
  r60026 | raymond.hettinger | 2008-01-17 23:27:49 +0100 (Thu, 17 Jan 2008) | 1 line

  Add advice on choosing between scheduler and threading.Timer().
........
  r60028 | christian.heimes | 2008-01-18 00:01:44 +0100 (Fri, 18 Jan 2008) | 2 lines

  Updated new property syntax. An elaborate example for subclassing and the getter was missing.
  Added comment about VS 2008 and PGO builds.
........
  r60029 | raymond.hettinger | 2008-01-18 00:32:01 +0100 (Fri, 18 Jan 2008) | 1 line

  Fix-up Timer() example.
........
  r60030 | raymond.hettinger | 2008-01-18 00:56:56 +0100 (Fri, 18 Jan 2008) | 1 line

  Fix markup
........
  r60031 | raymond.hettinger | 2008-01-18 01:10:42 +0100 (Fri, 18 Jan 2008) | 1 line

  clearcache() needs to remove the dict as well as clear it.
........
  r60033 | andrew.kuchling | 2008-01-18 03:26:16 +0100 (Fri, 18 Jan 2008) | 1 line

  Bump verson
........
  r60034 | andrew.kuchling | 2008-01-18 03:42:52 +0100 (Fri, 18 Jan 2008) | 1 line

  Typo fix
........
  r60035 | christian.heimes | 2008-01-18 08:30:20 +0100 (Fri, 18 Jan 2008) | 3 lines

  Coverity issue CID #197
  var_decl: Declared variable "stm" without initializer
  ninit_use_in_call: Using uninitialized value "stm" (field "stm".tm_zone uninitialized) in call to function "mktime"
........
  r60036 | christian.heimes | 2008-01-18 08:45:30 +0100 (Fri, 18 Jan 2008) | 11 lines

  Coverity issue CID #167
  Event alloc_fn: Called allocation function "metacompile" [model]
  Event var_assign: Assigned variable "gr" to storage returned from "metacompile"
  		gr = metacompile(n);
  Event pass_arg: Variable "gr" not freed or pointed-to in function "maketables" [model]
  		g = maketables(gr);
    		translatelabels(g);
    		addfirstsets(g);
  Event leaked_storage: Returned without freeing storage "gr"
  		return g;
........
  r60038 | christian.heimes | 2008-01-18 09:04:57 +0100 (Fri, 18 Jan 2008) | 3 lines

  Coverity issue CID #182
  size_error: Allocating 1 bytes to pointer "children", which needs at least 4 bytes
........
  r60041 | christian.heimes | 2008-01-18 09:47:59 +0100 (Fri, 18 Jan 2008) | 4 lines

  Coverity issue CID #169
  local_ptr_assign_local: Assigning address of stack variable "namebuf" to pointer "filename"
  out_of_scope: Variable "namebuf" goes out of scope
  use_invalid: Used "filename" pointing to out-of-scope variable "namebuf"
........
  r60042 | christian.heimes | 2008-01-18 09:53:45 +0100 (Fri, 18 Jan 2008) | 2 lines

  Coverity CID #168
  leaked_storage: Returned without freeing storage "fp"
........
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 5e1b16b..51758f2 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -2982,7 +2982,7 @@
     def _islogical(self):
         """Return True if self is a logical operand.
 
-        For being logical, it must be a finite numbers with a sign of 0,
+        For being logical, it must be a finite number with a sign of 0,
         an exponent of 0, and a coefficient whose digits must all be
         either 0 or 1.
         """
@@ -4098,7 +4098,7 @@
         """max compares two values numerically and returns the maximum.
 
         If either operand is a NaN then the general rules apply.
-        Otherwise, the operands are compared as as though by the compare
+        Otherwise, the operands are compared as though by the compare
         operation.  If they are numerically equal then the left-hand operand
         is chosen as the result.  Otherwise the maximum (closer to positive
         infinity) of the two operands is chosen as the result.
@@ -4122,7 +4122,7 @@
         """min compares two values numerically and returns the minimum.
 
         If either operand is a NaN then the general rules apply.
-        Otherwise, the operands are compared as as though by the compare
+        Otherwise, the operands are compared as though by the compare
         operation.  If they are numerically equal then the left-hand operand
         is chosen as the result.  Otherwise the minimum (closer to negative
         infinity) of the two operands is chosen as the result.
diff --git a/Lib/pdb.py b/Lib/pdb.py
index dfd745d..57a2b45 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -198,6 +198,8 @@
         globals = self.curframe.f_globals
         try:
             code = compile(line + '\n', '<stdin>', 'single')
+            save_stdout = sys.stdout
+            save_stdin = sys.stdin
             try:
                 sys.stdin = self.stdin
                 sys.stdout = self.stdout
diff --git a/Lib/sched.py b/Lib/sched.py
index 51c4e74..1c7bfea 100644
--- a/Lib/sched.py
+++ b/Lib/sched.py
@@ -29,14 +29,17 @@
 # XXX the global state of your particular time and delay functions.
 
 import heapq
+from collections import namedtuple
 
 __all__ = ["scheduler"]
 
+Event = namedtuple('Event', 'time, priority, action, argument')
+
 class scheduler:
     def __init__(self, timefunc, delayfunc):
         """Initialize a new instance, passing the time and delay
         functions"""
-        self.queue = []
+        self._queue = []
         self.timefunc = timefunc
         self.delayfunc = delayfunc
 
@@ -47,8 +50,8 @@
         if necessary.
 
         """
-        event = time, priority, action, argument
-        heapq.heappush(self.queue, event)
+        event = Event(time, priority, action, argument)
+        heapq.heappush(self._queue, event)
         return event # The ID
 
     def enter(self, delay, priority, action, argument):
@@ -67,12 +70,12 @@
         If the event is not in the queue, this raises RuntimeError.
 
         """
-        self.queue.remove(event)
-        heapq.heapify(self.queue)
+        self._queue.remove(event)
+        heapq.heapify(self._queue)
 
     def empty(self):
         """Check whether the queue is empty."""
-        return not self.queue
+        return not self._queue
 
     def run(self):
         """Execute events until the queue is empty.
@@ -97,7 +100,7 @@
         """
         # localize variable access to minimize overhead
         # and to improve thread safety
-        q = self.queue
+        q = self._queue
         delayfunc = self.delayfunc
         timefunc = self.timefunc
         pop = heapq.heappop
@@ -115,3 +118,17 @@
                     delayfunc(0)   # Let other threads run
                 else:
                     heapq.heappush(event)
+
+    @property
+    def queue(self):
+        """An ordered list of upcoming events.
+
+        Events are named tuples with fields for:
+            time, priority, action, arguments
+
+        """
+        # Use heapq to sort the queue rather than using 'sorted(self._queue)'.
+        # With heapq, two events scheduled at the same time will show in
+        # the actual order they would be retrieved.
+        events = self._queue[:]
+        return map(heapq.heappop, [events]*len(events))
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index 0b4cbf0..2b7befb 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -495,6 +495,23 @@
 
     # some useful methods
 
+    def ehlo_or_helo_if_needed(self):
+        """Call self.ehlo() and/or self.helo() if needed.
+
+        If there has been no previous EHLO or HELO command this session, this
+        method tries ESMTP EHLO first.
+
+        This method may raise the following exceptions:
+
+         SMTPHeloError            The server didn't reply properly to
+                                  the helo greeting.
+        """
+        if self.helo_resp is None and self.ehlo_resp is None:
+            if not (200 <= self.ehlo()[0] <= 299):
+                (code, resp) = self.helo()
+                if not (200 <= code <= 299):
+                    raise SMTPHeloError(code, resp)
+
     def login(self, user, password):
         """Log in on an SMTP server that requires authentication.
 
@@ -530,11 +547,7 @@
         AUTH_CRAM_MD5 = "CRAM-MD5"
         AUTH_LOGIN = "LOGIN"
 
-        if self.helo_resp is None and self.ehlo_resp is None:
-            if not (200 <= self.ehlo()[0] <= 299):
-                (code, resp) = self.helo()
-                if not (200 <= code <= 299):
-                    raise SMTPHeloError(code, resp)
+        self.ehlo_or_helo_if_needed()
 
         if not self.has_extn("auth"):
             raise SMTPException("SMTP AUTH extension not supported by server.")
@@ -580,18 +593,37 @@
     def starttls(self, keyfile = None, certfile = None):
         """Puts the connection to the SMTP server into TLS mode.
 
+        If there has been no previous EHLO or HELO command this session, this
+        method tries ESMTP EHLO first.
+
         If the server supports TLS, this will encrypt the rest of the SMTP
         session. If you provide the keyfile and certfile parameters,
         the identity of the SMTP server and client can be checked. This,
         however, depends on whether the socket module really checks the
         certificates.
+
+        This method may raise the following exceptions:
+
+         SMTPHeloError            The server didn't reply properly to
+                                  the helo greeting.
         """
+        self.ehlo_or_helo_if_needed()
+        if not self.has_extn("starttls"):
+            raise SMTPException("STARTTLS extension not supported by server.")
         (resp, reply) = self.docmd("STARTTLS")
         if resp == 220:
             if not _have_ssl:
                 raise RuntimeError("No SSL support included in this Python")
             self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)
             self.file = SSLFakeFile(self.sock)
+            # RFC 3207:
+            # The client MUST discard any knowledge obtained from
+            # the server, such as the list of SMTP service extensions,
+            # which was not obtained from the TLS negotiation itself.
+            self.helo_resp = None
+            self.ehlo_resp = None
+            self.esmtp_features = {}
+            self.does_esmtp = 0
         return (resp, reply)
 
     def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
@@ -651,11 +683,7 @@
         empty dictionary.
 
         """
-        if self.helo_resp is None and self.ehlo_resp is None:
-            if not (200 <= self.ehlo()[0] <= 299):
-                (code,resp) = self.helo()
-                if not (200 <= code <= 299):
-                    raise SMTPHeloError(code, resp)
+        self.ehlo_or_helo_if_needed()
         esmtp_opts = []
         if self.does_esmtp:
             # Hmmm? what's this? -ddm
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index 17e0058..4c0af07 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -300,7 +300,8 @@
         self.assertEqual(take(3, starmap(operator.pow, izip(count(), count(1)))),
                          [0**1, 1**2, 2**3])
         self.assertEqual(list(starmap(operator.pow, [])), [])
-        self.assertRaises(TypeError, list, starmap(operator.pow, [[4,5]]))
+        self.assertEqual(list(starmap(operator.pow, [iter([4,5])])), [4**5])
+        self.assertRaises(TypeError, list, starmap(operator.pow, [None]))
         self.assertRaises(TypeError, starmap)
         self.assertRaises(TypeError, starmap, operator.pow, [(4,5)], 'extra')
         self.assertRaises(TypeError, next, starmap(10, [(4,5)]))
diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py
index 4d89ed2..e15ee39 100644
--- a/Lib/test/test_queue.py
+++ b/Lib/test/test_queue.py
@@ -184,28 +184,35 @@
         raise RuntimeError("Call this function with an empty queue")
     # I guess we better check things actually queue correctly a little :)
     q.put(111)
+    q.put(333)
     q.put(222)
-    verify(q.get() == 111 and q.get() == 222,
+    target_order = dict(Queue = [111, 333, 222],
+                        LifoQueue = [222, 333, 111],
+                        PriorityQueue = [111, 222, 333])
+    actual_order = [q.get(), q.get(), q.get()]
+    verify(actual_order == target_order[q.__class__.__name__],
            "Didn't seem to queue the correct data!")
     for i in range(QUEUE_SIZE-1):
         q.put(i)
         verify(q.qsize(), "Queue should not be empty")
     verify(not qfull(q), "Queue should not be full")
-    q.put("last")
+    last = 2*QUEUE_SIZE
+    full = 3*2*QUEUE_SIZE
+    q.put(last)
     verify(qfull(q), "Queue should be full")
     try:
-        q.put("full", block=0)
+        q.put(full, block=0)
         raise TestFailed("Didn't appear to block with a full queue")
     except Queue.Full:
         pass
     try:
-        q.put("full", timeout=0.01)
+        q.put(full, timeout=0.01)
         raise TestFailed("Didn't appear to time-out with a full queue")
     except Queue.Full:
         pass
     # Test a blocking put
-    _doBlockingTest(q.put, ("full",), q.get, ())
-    _doBlockingTest(q.put, ("full", True, 10), q.get, ())
+    _doBlockingTest(q.put, (full,), q.get, ())
+    _doBlockingTest(q.put, (full, True, 10), q.get, ())
     # Empty it
     for i in range(QUEUE_SIZE):
         q.get()
@@ -250,8 +257,7 @@
         q.put(i)
     q.join()
     verify(cum==sum(range(100)), "q.join() did not block until all tasks were done")
-    for i in (0,1):
-        q.put(None)         # instruct the threads to close
+    q.put(None)         # instruct the threads to close
     q.join()                # verify that you can join twice
 
 def QueueTaskDoneTest(q):
@@ -263,18 +269,20 @@
         raise TestFailed("Did not detect task count going negative")
 
 def test():
-    q = Queue.Queue()
-    QueueTaskDoneTest(q)
-    QueueJoinTest(q)
-    QueueJoinTest(q)
-    QueueTaskDoneTest(q)
+    for Q in Queue.Queue, Queue.LifoQueue, Queue.PriorityQueue:
+        q = Q()
+        QueueTaskDoneTest(q)
+        QueueJoinTest(q)
+        QueueJoinTest(q)
+        QueueTaskDoneTest(q)
 
-    q = Queue.Queue(QUEUE_SIZE)
-    # Do it a couple of times on the same queue
-    SimpleQueueTest(q)
-    SimpleQueueTest(q)
-    if verbose:
-        print("Simple Queue tests seemed to work")
+        q = Q(QUEUE_SIZE)
+        # Do it a couple of times on the same queue
+        SimpleQueueTest(q)
+        SimpleQueueTest(q)
+        if verbose:
+            print("Simple Queue tests seemed to work for", Q.__name__)
+
     q = FailingQueue(QUEUE_SIZE)
     FailingQueueTest(q)
     FailingQueueTest(q)