Merged revisions 60481,60485,60489-60520,60523-60527,60530-60533,60535-60538,60540-60551 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

NOTE: I blocked the following revisions:
      svnmerge.py block -r 60521,60522,60528,60529,60534,60539
      The new tests must be merged with lots of manual work.

........
  r60493 | georg.brandl | 2008-02-01 12:59:08 +0100 (Fri, 01 Feb 2008) | 2 lines

  Update IPv6 RFC number.
........
  r60497 | georg.brandl | 2008-02-01 16:50:15 +0100 (Fri, 01 Feb 2008) | 2 lines

  Add link checker builder, written for GHOP by Thomas Lamb.
........
  r60500 | georg.brandl | 2008-02-01 19:08:09 +0100 (Fri, 01 Feb 2008) | 2 lines

  Rename batch file.
........
  r60504 | christian.heimes | 2008-02-01 19:49:26 +0100 (Fri, 01 Feb 2008) | 1 line

  More int -> pid_t.
........
  r60507 | georg.brandl | 2008-02-01 20:24:01 +0100 (Fri, 01 Feb 2008) | 2 lines

  Wording nit.
........
  r60510 | georg.brandl | 2008-02-01 21:45:33 +0100 (Fri, 01 Feb 2008) | 2 lines

  Update for latest sphinx latex writer.
........
  r60511 | raymond.hettinger | 2008-02-01 22:30:23 +0100 (Fri, 01 Feb 2008) | 1 line

  Issue #1996: float.as_integer_ratio() should return fraction in lowest terms.
........
  r60512 | raymond.hettinger | 2008-02-01 23:15:52 +0100 (Fri, 01 Feb 2008) | 1 line

  Integer ratio should return ints instead of longs whereever possible.
........
  r60513 | raymond.hettinger | 2008-02-01 23:22:50 +0100 (Fri, 01 Feb 2008) | 1 line

  labs() takes a long for an input.
........
  r60514 | raymond.hettinger | 2008-02-01 23:42:59 +0100 (Fri, 01 Feb 2008) | 1 line

  Test round-trip on float.as_integer_ratio() and float.__truediv__().
........
  r60515 | marc-andre.lemburg | 2008-02-01 23:58:17 +0100 (Fri, 01 Feb 2008) | 3 lines

  Bump distutils version number to match Python version.
........
  r60516 | raymond.hettinger | 2008-02-02 00:12:19 +0100 (Sat, 02 Feb 2008) | 1 line

  Fix int/long typecase.  Add check for non-binary floating point.
........
  r60517 | raymond.hettinger | 2008-02-02 00:45:44 +0100 (Sat, 02 Feb 2008) | 1 line

  Add protection from weirdness while scaling the mantissa to an integer.
........
  r60518 | raymond.hettinger | 2008-02-02 06:11:40 +0100 (Sat, 02 Feb 2008) | 1 line

  Simpler solution to handling non-IEEE 754 environments.
........
  r60519 | raymond.hettinger | 2008-02-02 06:24:44 +0100 (Sat, 02 Feb 2008) | 1 line

  Neaten-up a bit.
........
  r60520 | georg.brandl | 2008-02-02 10:56:20 +0100 (Sat, 02 Feb 2008) | 2 lines

  Amendments to the urllib2 docs, written for GHOP by Thomas Lamb.
........
  r60525 | georg.brandl | 2008-02-02 11:49:58 +0100 (Sat, 02 Feb 2008) | 3 lines

  Add email example how to send a multipart message.
  Written for GHOP by Martin Matejek.
........
  r60526 | georg.brandl | 2008-02-02 12:05:00 +0100 (Sat, 02 Feb 2008) | 2 lines

  Rewrite test_socketserver as unittest, written for GHOP by Benjamin Petersen.
........
  r60527 | georg.brandl | 2008-02-02 12:05:34 +0100 (Sat, 02 Feb 2008) | 2 lines

  Add GHOP contributor.
........
  r60530 | mark.dickinson | 2008-02-02 18:16:13 +0100 (Sat, 02 Feb 2008) | 2 lines

  Make the Rational constructor accept '3.' and '.2' as well as '3.2'.
........
  r60531 | neal.norwitz | 2008-02-02 19:52:51 +0100 (Sat, 02 Feb 2008) | 1 line

  Update the leaky tests (ie, ignore these tests if they report leaks).  This version has been running for a while.
........
  r60533 | skip.montanaro | 2008-02-02 20:11:57 +0100 (Sat, 02 Feb 2008) | 7 lines

  Split the refleak mail body into two parts, the first being those failing
  tests which are deemed more important issues, the second those which are
  known to have difficult to solve problems and are generally expected to
  leak.  Hopefully this doesn't break the script...
........
  r60535 | georg.brandl | 2008-02-03 01:04:50 +0100 (Sun, 03 Feb 2008) | 3 lines

  Wait for a delay before reaping children -- this should fix the
  test_socketserver failures on several platforms.
........
  r60536 | brett.cannon | 2008-02-03 03:07:55 +0100 (Sun, 03 Feb 2008) | 2 lines

  Fix a minor typo.
........
  r60537 | brett.cannon | 2008-02-03 03:08:45 +0100 (Sun, 03 Feb 2008) | 3 lines

  Directories from CPPFLAGS and LDFLAGS were being added in the reverse order for
  searches as to how they were listed in the environment variable.
........
  r60538 | brett.cannon | 2008-02-03 03:34:14 +0100 (Sun, 03 Feb 2008) | 2 lines

  Remove extra tick marks and add a missing closing parenthesis.
........
  r60540 | andrew.macintyre | 2008-02-03 07:58:06 +0100 (Sun, 03 Feb 2008) | 2 lines

  Update OS/2 EMX build bits for 2.6.
........
  r60541 | andrew.macintyre | 2008-02-03 08:01:11 +0100 (Sun, 03 Feb 2008) | 2 lines

  Rename module definition file to reflect v2.6.
........
  r60542 | andrew.macintyre | 2008-02-03 08:07:31 +0100 (Sun, 03 Feb 2008) | 6 lines

  The wrapper function is supposed to be for spawnvpe() so that's
  what we should call [this wrapper only available on OS/2].

  Backport candidate to 2.5.
........
  r60544 | gregory.p.smith | 2008-02-03 08:20:53 +0100 (Sun, 03 Feb 2008) | 6 lines

  Merge this fix from the pybsddb tree:
  r293 | jcea | 2008-01-31 01:08:19 -0800 (Thu, 31 Jan 2008) | 4 lines

  Solved memory leak when using cursors with
  databases without environment.
........
  r60546 | gregory.p.smith | 2008-02-03 09:01:46 +0100 (Sun, 03 Feb 2008) | 2 lines

  remove a repeated occurance of a hardcoded berkeleydb library version number
........
  r60549 | brett.cannon | 2008-02-03 10:59:21 +0100 (Sun, 03 Feb 2008) | 2 lines

  Add an entry for r60537.
........
  r60550 | georg.brandl | 2008-02-03 13:29:00 +0100 (Sun, 03 Feb 2008) | 2 lines

  #2003: fix sentence.
........
  r60551 | christian.heimes | 2008-02-03 15:34:18 +0100 (Sun, 03 Feb 2008) | 2 lines

  Fixed paths to Windows build directories in build_ext.py
  Use vsbuild instead of devenv in build.bat and _bsddb.vcproj
........
diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py
index f71c3ad..0c3d939 100644
--- a/Lib/distutils/__init__.py
+++ b/Lib/distutils/__init__.py
@@ -18,4 +18,4 @@
 # In general, major and minor version should loosely follow the Python
 # version number the distutils code was shipped with.
 #
-__version__ = "2.5.1"
+__version__ = "2.6.0"
diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py
index 6d42278..ff84bca 100644
--- a/Lib/distutils/command/build_ext.py
+++ b/Lib/distutils/command/build_ext.py
@@ -178,13 +178,13 @@
             self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC'))
             if MSVC_VERSION == 9:
                 self.library_dirs.append(os.path.join(sys.exec_prefix,
-                                         'PCBuild9'))
+                                         'PCbuild'))
             elif MSVC_VERSION == 8:
                 self.library_dirs.append(os.path.join(sys.exec_prefix,
-                                         'PCBuild8', 'win32release'))
+                                         'PC', 'VS8.0', 'win32release'))
             else:
                 self.library_dirs.append(os.path.join(sys.exec_prefix,
-                                         'PCBuild'))
+                                         'PC', 'VS7.1'))
 
         # OS/2 (EMX) doesn't support Debug vs Release builds, but has the
         # import libraries in its "Config" subdirectory
diff --git a/Lib/rational.py b/Lib/rational.py
index 55d4a41..e2fed23 100755
--- a/Lib/rational.py
+++ b/Lib/rational.py
@@ -24,9 +24,18 @@
     return a
 
 
-_RATIONAL_FORMAT = re.compile(
-    r'^\s*(?P<sign>[-+]?)(?P<num>\d+)'
-    r'(?:/(?P<denom>\d+)|\.(?P<decimal>\d+))?\s*$')
+_RATIONAL_FORMAT = re.compile(r"""
+    \A\s*                      # optional whitespace at the start, then
+    (?P<sign>[-+]?)            # an optional sign, then
+    (?=\d|\.\d)                # lookahead for digit or .digit
+    (?P<num>\d*)               # numerator (possibly empty)
+    (?:                        # followed by an optional
+       /(?P<denom>\d+)         # / and denominator
+    |                          # or
+       \.(?P<decimal>\d*)      # decimal point and fractional part
+    )?
+    \s*\Z                      # and optional whitespace to finish
+""", re.VERBOSE)
 
 
 class Rational(RationalAbc):
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 35cdcd4..cc31e93 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -593,6 +593,20 @@
         self.assertEqual(format(0, C('10')), '         0')
 
     def test_floatasratio(self):
+        for f, ratio in [
+                (0.875, (7, 8)),
+                (-0.875, (-7, 8)),
+                (0.0, (0, 1)),
+                (11.5, (23, 2)),
+            ]:
+            self.assertEqual(f.as_integer_ratio(), ratio)
+
+        for i in range(10000):
+            f = random.random()
+            f *= 10 ** random.randint(-100, 100)
+            n, d = f.as_integer_ratio()
+            self.assertEqual(float(n).__truediv__(d), f)
+
         R = rational.Rational
         self.assertEqual(R(0, 1),
                          R(*float(0.0).as_integer_ratio()))
diff --git a/Lib/test/test_rational.py b/Lib/test/test_rational.py
index c9a129f..4f248be 100644
--- a/Lib/test/test_rational.py
+++ b/Lib/test/test_rational.py
@@ -77,6 +77,8 @@
         self.assertEquals((3, 2), _components(R("    03/02 \n  ")))
         self.assertEquals((16, 5), _components(R(" 3.2 ")))
         self.assertEquals((-16, 5), _components(R(" -3.2 ")))
+        self.assertEquals((-3, 1), _components(R(" -3. ")))
+        self.assertEquals((3, 5), _components(R(" .6 ")))
 
         self.assertRaisesMessage(
             ZeroDivisionError, "Rational(3, 0)",
@@ -111,6 +113,10 @@
             # Don't accept combinations of decimals and rationals.
             ValueError, "Invalid literal for Rational: 3.2/7",
             R, "3.2/7")
+        self.assertRaisesMessage(
+            # Allow 3. and .3, but not .
+            ValueError, "Invalid literal for Rational: .",
+            R, ".")
 
     def testImmutable(self):
         r = R(7, 3)
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
index 3e0c7a4..5ae8e6d 100644
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -1,20 +1,32 @@
-# Test suite for SocketServer.py
+"""
+Test suite for SocketServer.py.
+"""
 
-from test import test_support
-from test.test_support import (verbose, verify, TESTFN, TestSkipped,
-                               reap_children)
-test_support.requires('network')
-
-from SocketServer import *
+import os
 import socket
 import errno
+import imp
 import select
 import time
 import threading
-import os
+from functools import wraps
+import unittest
+import SocketServer
+
+import test.test_support
+from test.test_support import reap_children, verbose, TestSkipped
+from test.test_support import TESTFN as TEST_FILE
+
+test.test_support.requires("network")
 
 NREQ = 3
 DELAY = 0.5
+TEST_STR = b"hello world\n"
+HOST = "localhost"
+
+HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
+HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
+
 
 class MyMixinHandler:
     def handle(self):
@@ -23,23 +35,41 @@
         time.sleep(DELAY)
         self.wfile.write(line)
 
-class MyStreamHandler(MyMixinHandler, StreamRequestHandler):
+
+def receive(sock, n, timeout=20):
+    r, w, x = select.select([sock], [], [], timeout)
+    if sock in r:
+        return sock.recv(n)
+    else:
+        raise RuntimeError("timed out on %r" % (sock,))
+
+
+class MyStreamHandler(MyMixinHandler, SocketServer.StreamRequestHandler):
     pass
 
-class MyDatagramHandler(MyMixinHandler, DatagramRequestHandler):
+class MyDatagramHandler(MyMixinHandler,
+    SocketServer.DatagramRequestHandler):
     pass
 
+class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
+                              SocketServer.UnixStreamServer):
+    pass
+
+class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
+                                SocketServer.UnixDatagramServer):
+    pass
+
+
 class MyMixinServer:
     def serve_a_few(self):
         for i in range(NREQ):
             self.handle_request()
+
     def handle_error(self, request, client_address):
         self.close_request(request)
         self.server_close()
         raise
 
-teststring = b"hello world\n"
-
 def receive(sock, n, timeout=20):
     r, w, x = select.select([sock], [], [], timeout)
     if sock in r:
@@ -75,6 +105,7 @@
         self.__svrcls = svrcls
         self.__hdlrcls = hdlrcls
         self.ready = threading.Event()
+
     def run(self):
         class svrcls(MyMixinServer, self.__svrcls):
             pass
@@ -93,64 +124,8 @@
         svr.serve_a_few()
         if verbose: print("thread: done")
 
-seed = 0
-def pickport():
-    global seed
-    seed += 1
-    return 10000 + (os.getpid() % 1000)*10 + seed
 
-host = "localhost"
-testfiles = []
-def pickaddr(proto):
-    if proto == socket.AF_INET:
-        return (host, pickport())
-    else:
-        fn = TESTFN + str(pickport())
-        if os.name == 'os2':
-            # AF_UNIX socket names on OS/2 require a specific prefix
-            # which can't include a drive letter and must also use
-            # backslashes as directory separators
-            if fn[1] == ':':
-                fn = fn[2:]
-            if fn[0] in (os.sep, os.altsep):
-                fn = fn[1:]
-            fn = os.path.join('\socket', fn)
-            if os.sep == '/':
-                fn = fn.replace(os.sep, os.altsep)
-            else:
-                fn = fn.replace(os.altsep, os.sep)
-        testfiles.append(fn)
-        return fn
-
-def cleanup():
-    for fn in testfiles:
-        try:
-            os.remove(fn)
-        except os.error:
-            pass
-    testfiles[:] = []
-
-def testloop(proto, servers, hdlrcls, testfunc):
-    for svrcls in servers:
-        addr = pickaddr(proto)
-        if verbose:
-            print("ADDR =", addr)
-            print("CLASS =", svrcls)
-        t = ServerThread(addr, svrcls, hdlrcls)
-        if verbose: print("server created")
-        t.start()
-        if verbose: print("server running")
-        for i in range(NREQ):
-            t.ready.wait(10*DELAY)
-            if not t.ready.isSet():
-                raise RuntimeError("Server not ready within a reasonable time")
-            if verbose: print("test client", i)
-            testfunc(proto, addr)
-        if verbose: print("waiting for server")
-        t.join()
-        if verbose: print("done")
-
-class ForgivingTCPServer(TCPServer):
+class ForgivingTCPServer(SocketServer.TCPServer):
     # prevent errors if another process is using the port we want
     def server_bind(self):
         host, default_port = self.server_address
@@ -160,7 +135,7 @@
         for port in [default_port, 3434, 8798, 23833]:
             try:
                 self.server_address = host, port
-                TCPServer.server_bind(self)
+                SocketServer.TCPServer.server_bind(self)
                 break
             except socket.error as e:
                 (err, msg) = e
@@ -168,56 +143,139 @@
                     raise
                 print('  WARNING: failed to listen on port %d, trying another' % port, file=sys.__stderr__)
 
-tcpservers = [ForgivingTCPServer, ThreadingTCPServer]
-if hasattr(os, 'fork') and os.name not in ('os2',):
-    tcpservers.append(ForkingTCPServer)
-udpservers = [UDPServer, ThreadingUDPServer]
-if hasattr(os, 'fork') and os.name not in ('os2',):
-    udpservers.append(ForkingUDPServer)
+class SocketServerTest(unittest.TestCase):
+    """Test all socket servers."""
 
-if not hasattr(socket, 'AF_UNIX'):
-    streamservers = []
-    dgramservers = []
-else:
-    class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
-    streamservers = [UnixStreamServer, ThreadingUnixStreamServer]
-    if hasattr(os, 'fork') and os.name not in ('os2',):
-        streamservers.append(ForkingUnixStreamServer)
-    class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
-    dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer]
-    if hasattr(os, 'fork') and os.name not in ('os2',):
-        dgramservers.append(ForkingUnixDatagramServer)
+    def setUp(self):
+        self.port_seed = 0
+        self.test_files = []
 
-def sloppy_cleanup():
-    # See http://python.org/sf/1540386
-    # We need to reap children here otherwise a child from one server
-    # can be left running for the next server and cause a test failure.
-    time.sleep(DELAY)
-    reap_children()
+    def tearDown(self):
+        time.sleep(DELAY)
+        reap_children()
 
-def testall():
-    testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
-    sloppy_cleanup()
-    testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
-    if hasattr(socket, 'AF_UNIX'):
-        sloppy_cleanup()
-        testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
-        # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
-        # client address so this cannot work:
-        ##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)
+        for fn in self.test_files:
+            try:
+                os.remove(fn)
+            except os.error:
+                pass
+        self.test_files[:] = []
+
+    def pickport(self):
+        self.port_seed += 1
+        return 10000 + (os.getpid() % 1000)*10 + self.port_seed
+
+    def pickaddr(self, proto):
+        if proto == socket.AF_INET:
+            return (HOST, self.pickport())
+        else:
+            fn = TEST_FILE + str(self.pickport())
+            if os.name == 'os2':
+                # AF_UNIX socket names on OS/2 require a specific prefix
+                # which can't include a drive letter and must also use
+                # backslashes as directory separators
+                if fn[1] == ':':
+                    fn = fn[2:]
+                if fn[0] in (os.sep, os.altsep):
+                    fn = fn[1:]
+                fn = os.path.join('\socket', fn)
+                if os.sep == '/':
+                    fn = fn.replace(os.sep, os.altsep)
+                else:
+                    fn = fn.replace(os.altsep, os.sep)
+            self.test_files.append(fn)
+            return fn
+
+    def run_servers(self, proto, servers, hdlrcls, testfunc):
+        for svrcls in servers:
+            addr = self.pickaddr(proto)
+            if verbose:
+                print "ADDR =", addr
+                print "CLASS =", svrcls
+            t = ServerThread(addr, svrcls, hdlrcls)
+            if verbose: print "server created"
+            t.start()
+            if verbose: print "server running"
+            for i in range(NREQ):
+                t.ready.wait(10*DELAY)
+                self.assert_(t.ready.isSet(),
+                    "Server not ready within a reasonable time")
+                if verbose: print "test client", i
+                testfunc(proto, addr)
+            if verbose: print "waiting for server"
+            t.join()
+            if verbose: print "done"
+
+    def stream_examine(self, proto, addr):
+        s = socket.socket(proto, socket.SOCK_STREAM)
+        s.connect(addr)
+        s.sendall(TEST_STR)
+        buf = data = receive(s, 100)
+        while data and '\n' not in buf:
+            data = receive(s, 100)
+            buf += data
+        self.assertEquals(buf, TEST_STR)
+        s.close()
+
+    def dgram_examine(self, proto, addr):
+        s = socket.socket(proto, socket.SOCK_DGRAM)
+        s.sendto(TEST_STR, addr)
+        buf = data = receive(s, 100)
+        while data and '\n' not in buf:
+            data = receive(s, 100)
+            buf += data
+        self.assertEquals(buf, TEST_STR)
+        s.close()
+
+    def test_TCPServers(self):
+        # Test SocketServer.TCPServer
+        servers = [ForgivingTCPServer, SocketServer.ThreadingTCPServer]
+        if HAVE_FORKING:
+            servers.append(SocketServer.ForkingTCPServer)
+        self.run_servers(socket.AF_INET, servers,
+                         MyStreamHandler, self.stream_examine)
+
+    def test_UDPServers(self):
+        # Test SocketServer.UDPServer
+        servers = [SocketServer.UDPServer,
+                   SocketServer.ThreadingUDPServer]
+        if HAVE_FORKING:
+            servers.append(SocketServer.ForkingUDPServer)
+        self.run_servers(socket.AF_INET, servers, MyDatagramHandler,
+                         self.dgram_examine)
+
+    def test_stream_servers(self):
+        # Test SocketServer's stream servers
+        if not HAVE_UNIX_SOCKETS:
+            return
+        servers = [SocketServer.UnixStreamServer,
+                   SocketServer.ThreadingUnixStreamServer]
+        if HAVE_FORKING:
+            servers.append(ForkingUnixStreamServer)
+        self.run_servers(socket.AF_UNIX, servers, MyStreamHandler,
+                         self.stream_examine)
+
+    # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
+    # client address so this cannot work:
+
+    # def test_dgram_servers(self):
+    #     # Test SocketServer.UnixDatagramServer
+    #     if not HAVE_UNIX_SOCKETS:
+    #         return
+    #     servers = [SocketServer.UnixDatagramServer,
+    #                SocketServer.ThreadingUnixDatagramServer]
+    #     if HAVE_FORKING:
+    #         servers.append(ForkingUnixDatagramServer)
+    #     self.run_servers(socket.AF_UNIX, servers, MyDatagramHandler,
+    #                      self.dgram_examine)
+
 
 def test_main():
-    import imp
     if imp.lock_held():
-        # If the import lock is held, the threads will hang.
+        # If the import lock is held, the threads will hang
         raise TestSkipped("can't run when import lock is held")
 
-    reap_children()
-    try:
-        testall()
-    finally:
-        cleanup()
-    reap_children()
+    test.test_support.run_unittest(SocketServerTest)
 
 if __name__ == "__main__":
     test_main()