Merged revisions 59822-59841 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r59822 | georg.brandl | 2008-01-07 17:43:47 +0100 (Mon, 07 Jan 2008) | 2 lines

  Restore "somenamedtuple" as the "class" for named tuple attrs.
........
  r59824 | georg.brandl | 2008-01-07 18:09:35 +0100 (Mon, 07 Jan 2008) | 2 lines

  Patch #602345 by Neal Norwitz and me: add -B option and PYTHONDONTWRITEBYTECODE envvar to skip writing bytecode.
........
  r59827 | georg.brandl | 2008-01-07 18:25:53 +0100 (Mon, 07 Jan 2008) | 2 lines

  patch #1668: clarify envvar docs; rename THREADDEBUG to PYTHONTHREADDEBUG.
........
  r59830 | georg.brandl | 2008-01-07 19:16:36 +0100 (Mon, 07 Jan 2008) | 2 lines

  Make Python compile with --disable-unicode.
........
  r59831 | georg.brandl | 2008-01-07 19:23:27 +0100 (Mon, 07 Jan 2008) | 2 lines

  Restructure urllib doc structure.
........
  r59833 | georg.brandl | 2008-01-07 19:41:34 +0100 (Mon, 07 Jan 2008) | 2 lines

  Fix #define ordering.
........
  r59834 | georg.brandl | 2008-01-07 19:47:44 +0100 (Mon, 07 Jan 2008) | 2 lines

  #467924, patch by Alan McIntyre: Add ZipFile.extract and ZipFile.extractall.
........
  r59835 | raymond.hettinger | 2008-01-07 19:52:19 +0100 (Mon, 07 Jan 2008) | 1 line

  Fix inconsistent title levels -- it made the whole doc build crash horribly.
........
  r59836 | georg.brandl | 2008-01-07 19:57:03 +0100 (Mon, 07 Jan 2008) | 2 lines

  Fix two further doc build warnings.
........
  r59837 | georg.brandl | 2008-01-07 20:17:10 +0100 (Mon, 07 Jan 2008) | 2 lines

  Clarify metaclass docs and add example.
........
  r59838 | vinay.sajip | 2008-01-07 20:40:10 +0100 (Mon, 07 Jan 2008) | 1 line

  Added section about adding contextual information to log output.
........
  r59839 | christian.heimes | 2008-01-07 20:58:41 +0100 (Mon, 07 Jan 2008) | 1 line

  Fixed indention problem that caused the second TIPC test to run on systems without TIPC
........
  r59840 | raymond.hettinger | 2008-01-07 21:07:38 +0100 (Mon, 07 Jan 2008) | 1 line

  Cleanup named tuple subclassing example.
........
diff --git a/Lib/collections.py b/Lib/collections.py
index 884c91f..2f0d038 100644
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -119,10 +119,11 @@
         @property
         def hypot(self):
             return (self.x ** 2 + self.y ** 2) ** 0.5
-        def __repr__(self):
-            return 'Point(x=%.3f, y=%.3f, hypot=%.3f)' % (self.x, self.y, self.hypot)
+        def __str__(self):
+            return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
 
-    print(Point(3, 4),'\n', Point(2, 5), '\n', Point(9./7, 6))
+    for p in Point(3,4), Point(14,5), Point(9./7,6):
+        print (p)
 
     class Point(namedtuple('Point', 'x y')):
         'Point class with optimized _make() and _replace() without error-checking'
diff --git a/Lib/test/output/test_cProfile b/Lib/test/output/test_cProfile
index 7561bcb..1221c63 100644
--- a/Lib/test/output/test_cProfile
+++ b/Lib/test/output/test_cProfile
@@ -5,7 +5,7 @@
 
    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
         1    0.000    0.000    1.000    1.000 <string>:1(<module>)
-        2    0.000    0.000    0.000    0.000 io.py:1212(flush)
+        2    0.000    0.000    0.000    0.000 io.py:1213(flush)
         1    0.000    0.000    0.000    0.000 io.py:269(flush)
         1    0.000    0.000    0.000    0.000 io.py:656(closed)
         1    0.000    0.000    0.000    0.000 io.py:874(flush)
@@ -30,7 +30,7 @@
 Function                                          called...
                                                       ncalls  tottime  cumtime
 <string>:1(<module>)                              ->       1    0.270    1.000  test_cProfile.py:30(testfunc)
-io.py:1212(flush)                                 ->       1    0.000    0.000  io.py:269(flush)
+io.py:1213(flush)                                 ->       1    0.000    0.000  io.py:269(flush)
                                                            1    0.000    0.000  io.py:874(flush)
 io.py:269(flush)                                  -> 
 io.py:656(closed)                                 -> 
@@ -53,7 +53,7 @@
 test_cProfile.py:93(helper2)                      ->       8    0.064    0.080  test_cProfile.py:103(subhelper)
                                                            8    0.000    0.008  {hasattr}
 {exec}                                            ->       1    0.000    1.000  <string>:1(<module>)
-                                                           2    0.000    0.000  io.py:1212(flush)
+                                                           2    0.000    0.000  io.py:1213(flush)
 {hasattr}                                         ->      12    0.012    0.012  test_cProfile.py:115(__getattr__)
 {method 'append' of 'list' objects}               -> 
 {method 'disable' of '_lsprof.Profiler' objects}  -> 
@@ -65,10 +65,10 @@
 Function                                          was called by...
                                                       ncalls  tottime  cumtime
 <string>:1(<module>)                              <-       1    0.000    1.000  {exec}
-io.py:1212(flush)                                 <-       2    0.000    0.000  {exec}
-io.py:269(flush)                                  <-       1    0.000    0.000  io.py:1212(flush)
+io.py:1213(flush)                                 <-       2    0.000    0.000  {exec}
+io.py:269(flush)                                  <-       1    0.000    0.000  io.py:1213(flush)
 io.py:656(closed)                                 <-       1    0.000    0.000  io.py:874(flush)
-io.py:874(flush)                                  <-       1    0.000    0.000  io.py:1212(flush)
+io.py:874(flush)                                  <-       1    0.000    0.000  io.py:1213(flush)
 test_cProfile.py:103(subhelper)                   <-       8    0.064    0.080  test_cProfile.py:93(helper2)
 test_cProfile.py:115(__getattr__)                 <-      16    0.016    0.016  test_cProfile.py:103(subhelper)
                                                           12    0.012    0.012  {hasattr}
diff --git a/Lib/test/output/test_profile b/Lib/test/output/test_profile
index f5e7160..0582611 100644
--- a/Lib/test/output/test_profile
+++ b/Lib/test/output/test_profile
@@ -10,7 +10,7 @@
        12    0.000    0.000    0.012    0.001 :0(hasattr)
         1    0.000    0.000    0.000    0.000 :0(setprofile)
         1    0.000    0.000    1.000    1.000 <string>:1(<module>)
-        2    0.000    0.000    0.000    0.000 io.py:1212(flush)
+        2    0.000    0.000    0.000    0.000 io.py:1213(flush)
         1    0.000    0.000    0.000    0.000 io.py:269(flush)
         1    0.000    0.000    0.000    0.000 io.py:656(closed)
         1    0.000    0.000    0.000    0.000 io.py:874(flush)
@@ -33,11 +33,11 @@
 :0(append)                            -> 
 :0(exc_info)                          -> 
 :0(exec)                              -> <string>:1(<module>)(1)    1.000
-                                         io.py:1212(flush)(2)    0.000
+                                         io.py:1213(flush)(2)    0.000
 :0(hasattr)                           -> test_profile.py:115(__getattr__)(12)    0.028
 :0(setprofile)                        -> 
 <string>:1(<module>)                  -> test_profile.py:30(testfunc)(1)    1.000
-io.py:1212(flush)                     -> io.py:269(flush)(1)    0.000
+io.py:1213(flush)                     -> io.py:269(flush)(1)    0.000
                                          io.py:874(flush)(1)    0.000
 io.py:269(flush)                      -> 
 io.py:656(closed)                     -> 
@@ -74,10 +74,10 @@
                                          test_profile.py:93(helper2)(8)    0.400
 :0(setprofile)                        <- profile:0(testfunc())(1)    1.000
 <string>:1(<module>)                  <- :0(exec)(1)    1.000
-io.py:1212(flush)                     <- :0(exec)(2)    1.000
-io.py:269(flush)                      <- io.py:1212(flush)(1)    0.000
+io.py:1213(flush)                     <- :0(exec)(2)    1.000
+io.py:269(flush)                      <- io.py:1213(flush)(1)    0.000
 io.py:656(closed)                     <- io.py:874(flush)(1)    0.000
-io.py:874(flush)                      <- io.py:1212(flush)(1)    0.000
+io.py:874(flush)                      <- io.py:1213(flush)(1)    0.000
 profile:0(profiler)                   <- 
 profile:0(testfunc())                 <- profile:0(profiler)(1)    0.000
 test_profile.py:103(subhelper)        <- test_profile.py:93(helper2)(8)    0.400
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index facf9fd..bc31620 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1215,7 +1215,7 @@
         tests.append(TestLinuxAbstractNamespace)
     if isTipcAvailable():
         tests.append(TIPCTest)
-    tests.append(TIPCThreadableTest)
+        tests.append(TIPCThreadableTest)
 
     thread_info = test_support.threading_setup()
     test_support.run_unittest(*tests)
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index ee8150e..7e401da 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -14,6 +14,11 @@
 TESTFN2 = TESTFN + "2"
 FIXEDTEST_SIZE = 1000
 
+SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
+                   ('ziptest2dir/_ziptest2', 'qawsedrftg'),
+                   ('/ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
+                   ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
+
 class TestsWithSourceFile(unittest.TestCase):
     def setUp(self):
         self.line_gen = (bytes("Zipfile test line %d. random float: %f" %
@@ -289,6 +294,57 @@
         self.assertRaises(RuntimeError, zipf.write, TESTFN)
         zipf.close()
 
+    def testExtract(self):
+        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
+        for fpath, fdata in SMALL_TEST_DATA:
+            zipfp.writestr(fpath, fdata)
+        zipfp.close()
+
+        zipfp = zipfile.ZipFile(TESTFN2, "r")
+        for fpath, fdata in SMALL_TEST_DATA:
+            writtenfile = zipfp.extract(fpath)
+
+            # make sure it was written to the right place
+            if os.path.isabs(fpath):
+                correctfile = os.path.join(os.getcwd(), fpath[1:])
+            else:
+                correctfile = os.path.join(os.getcwd(), fpath)
+
+            self.assertEqual(writtenfile, correctfile)
+
+            # make sure correct data is in correct file
+            self.assertEqual(fdata.encode(), open(writtenfile, "rb").read())
+
+            os.remove(writtenfile)
+
+        zipfp.close()
+
+        # remove the test file subdirectories
+        shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
+
+    def testExtractAll(self):
+        zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
+        for fpath, fdata in SMALL_TEST_DATA:
+            zipfp.writestr(fpath, fdata)
+        zipfp.close()
+
+        zipfp = zipfile.ZipFile(TESTFN2, "r")
+        zipfp.extractall()
+        for fpath, fdata in SMALL_TEST_DATA:
+            if os.path.isabs(fpath):
+                outfile = os.path.join(os.getcwd(), fpath[1:])
+            else:
+                outfile = os.path.join(os.getcwd(), fpath)
+
+            self.assertEqual(fdata.encode(), open(outfile, "rb").read())
+
+            os.remove(outfile)
+
+        zipfp.close()
+
+        # remove the test file subdirectories
+        shutil.rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
+
     def tearDown(self):
         os.remove(TESTFN)
         os.remove(TESTFN2)
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index b274682..2d308c3 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -3,7 +3,7 @@
 
 XXX references to utf-8 need further investigation.
 """
-import struct, os, time, sys
+import struct, os, time, sys, shutil
 import binascii, io
 
 try:
@@ -817,6 +817,62 @@
             zef.set_univ_newlines(True)
         return zef
 
+    def extract(self, member, path=None, pwd=None):
+        """Extract a member from the archive to the current working directory,
+           using its full name. Its file information is extracted as accurately
+           as possible. `member' may be a filename or a ZipInfo object. You can
+           specify a different directory using `path'.
+        """
+        if not isinstance(member, ZipInfo):
+            member = self.getinfo(member)
+
+        if path is None:
+            path = os.getcwd()
+
+        return self._extract_member(member, path, pwd)
+
+    def extractall(self, path=None, members=None, pwd=None):
+        """Extract all members from the archive to the current working
+           directory. `path' specifies a different directory to extract to.
+           `members' is optional and must be a subset of the list returned
+           by namelist().
+        """
+        if members is None:
+            members = self.namelist()
+
+        for zipinfo in members:
+            self.extract(zipinfo, path, pwd)
+
+    def _extract_member(self, member, targetpath, pwd):
+        """Extract the ZipInfo object 'member' to a physical
+           file on the path targetpath.
+        """
+        # build the destination pathname, replacing
+        # forward slashes to platform specific separators.
+        if targetpath[-1:] == "/":
+            targetpath = targetpath[:-1]
+
+        # don't include leading "/" from file name if present
+        if os.path.isabs(member.filename):
+            targetpath = os.path.join(targetpath, member.filename[1:])
+        else:
+            targetpath = os.path.join(targetpath, member.filename)
+
+        targetpath = os.path.normpath(targetpath)
+
+        # Create all upper directories if necessary.
+        upperdirs = os.path.dirname(targetpath)
+        if upperdirs and not os.path.exists(upperdirs):
+            os.makedirs(upperdirs)
+
+        source = self.open(member.filename, pwd=pwd)
+        target = open(targetpath, "wb")
+        shutil.copyfileobj(source, target)
+        source.close()
+        target.close()
+
+        return targetpath
+
     def _writecheck(self, zinfo):
         """Check for errors before writing a file to the archive."""
         if zinfo.filename in self.NameToInfo: