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

........
  r59704 | christian.heimes | 2008-01-04 04:15:05 +0100 (Fri, 04 Jan 2008) | 1 line

  Moved include "Python.h" in front of other imports to silence a warning.
........
  r59706 | raymond.hettinger | 2008-01-04 04:22:53 +0100 (Fri, 04 Jan 2008) | 10 lines

  Minor fix-ups to named tuples:

  * Make the _replace() method respect subclassing.

  * Using property() to make _fields read-only wasn't a good idea.
    It caused len(Point._fields) to fail.

  * Add note to _cast() about length checking and alternative with the star-operator.
........
  r59707 | jeffrey.yasskin | 2008-01-04 09:01:23 +0100 (Fri, 04 Jan 2008) | 3 lines

  Make math.{floor,ceil}({int,long}) return float again for backwards
  compatibility after r59671 made them return integral types.
........
  r59709 | christian.heimes | 2008-01-04 14:21:07 +0100 (Fri, 04 Jan 2008) | 1 line

  Bug #1713: posixpath.ismount() claims symlink to a mountpoint is a mountpoint.
........
  r59712 | lars.gustaebel | 2008-01-04 15:00:33 +0100 (Fri, 04 Jan 2008) | 5 lines

  Issue #1735: TarFile.extractall() now correctly sets
  directory permissions and times.

  (will backport to 2.5)
........
  r59714 | andrew.kuchling | 2008-01-04 15:47:17 +0100 (Fri, 04 Jan 2008) | 1 line

  Update links to bug/patch tracker
........
  r59716 | christian.heimes | 2008-01-04 16:23:30 +0100 (Fri, 04 Jan 2008) | 1 line

  Added interface to Windows' WSAIoctl and a simple example for a network sniffer.
........
  r59717 | christian.heimes | 2008-01-04 16:29:00 +0100 (Fri, 04 Jan 2008) | 1 line

  And here is the rest of Hirokazu Yamamoto's patch for VS6.0 support. Thanks Hiro!
........
  r59719 | christian.heimes | 2008-01-04 16:34:06 +0100 (Fri, 04 Jan 2008) | 1 line

  Reverted last transaction. It's the wrong branch.
........
  r59721 | christian.heimes | 2008-01-04 16:48:06 +0100 (Fri, 04 Jan 2008) | 1 line

  socket.ioctl is only available on Windows
........
  r59722 | andrew.kuchling | 2008-01-04 19:24:41 +0100 (Fri, 04 Jan 2008) | 1 line

  Fix markup
........
  r59723 | andrew.kuchling | 2008-01-04 19:25:05 +0100 (Fri, 04 Jan 2008) | 1 line

  Fix markup
........
  r59725 | guido.van.rossum | 2008-01-05 01:59:59 +0100 (Sat, 05 Jan 2008) | 3 lines

  Patch #1725 by Mark Dickinson, fixes incorrect conversion of -1e1000
  and adds errors for -0x.
........
  r59726 | guido.van.rossum | 2008-01-05 02:21:57 +0100 (Sat, 05 Jan 2008) | 2 lines

  Patch #1698 by Senthil: allow '@' in username when parsed by urlparse.py.
........
  r59727 | raymond.hettinger | 2008-01-05 02:35:43 +0100 (Sat, 05 Jan 2008) | 1 line

  Improve namedtuple's _cast() method with a docstring, new name, and error-checking.
........
  r59728 | raymond.hettinger | 2008-01-05 03:17:24 +0100 (Sat, 05 Jan 2008) | 1 line

  Add error-checking to namedtuple's _replace() method.
........
  r59730 | fred.drake | 2008-01-05 05:38:38 +0100 (Sat, 05 Jan 2008) | 2 lines

  clean up a comment
........
  r59731 | jeffrey.yasskin | 2008-01-05 09:47:13 +0100 (Sat, 05 Jan 2008) | 11 lines

  Continue rolling back pep-3141 changes that changed behavior from 2.5. This
  round included:
   * Revert round to its 2.6 behavior (half away from 0).
   * Because round, floor, and ceil always return float again, it's no
     longer necessary to have them delegate to __xxx___, so I've ripped
     that out of their implementations and the Real ABC. This also helps
     in implementing types that work in both 2.6 and 3.0: you return int
     from the __xxx__ methods, and let it get enabled by the version
     upgrade.
   * Make pow(-1, .5) raise a ValueError again.
........
  r59736 | andrew.kuchling | 2008-01-05 16:13:49 +0100 (Sat, 05 Jan 2008) | 1 line

  Fix comment typo
........
  r59738 | thomas.heller | 2008-01-05 18:15:44 +0100 (Sat, 05 Jan 2008) | 1 line

  Add myself.
........
  r59739 | georg.brandl | 2008-01-05 18:49:17 +0100 (Sat, 05 Jan 2008) | 2 lines

  Fix C++-style comment.
........
  r59742 | georg.brandl | 2008-01-05 20:28:16 +0100 (Sat, 05 Jan 2008) | 2 lines

  Remove with_statement future imports from 2.6 docs.
........
  r59743 | georg.brandl | 2008-01-05 20:29:45 +0100 (Sat, 05 Jan 2008) | 2 lines

  Simplify index entries; fix #1712.
........
  r59744 | georg.brandl | 2008-01-05 20:44:22 +0100 (Sat, 05 Jan 2008) | 2 lines

  Doc patch #1730 from Robin Stocker; minor corrections mostly to os.rst.
........
  r59749 | georg.brandl | 2008-01-05 21:29:13 +0100 (Sat, 05 Jan 2008) | 2 lines

  Revert socket.rst to unix-eol.
........
  r59750 | georg.brandl | 2008-01-05 21:33:46 +0100 (Sat, 05 Jan 2008) | 2 lines

  Set native svn:eol-style property for text files.
........
  r59752 | georg.brandl | 2008-01-05 21:46:29 +0100 (Sat, 05 Jan 2008) | 2 lines

  #1719: capitalization error in "UuidCreate".
........
  r59753 | georg.brandl | 2008-01-05 22:02:25 +0100 (Sat, 05 Jan 2008) | 2 lines

  Repair markup.
........
  r59754 | georg.brandl | 2008-01-05 22:10:50 +0100 (Sat, 05 Jan 2008) | 2 lines

  Use markup.
........
  r59757 | christian.heimes | 2008-01-05 22:35:52 +0100 (Sat, 05 Jan 2008) | 1 line

  Final adjustments for #1601
........
  r59758 | guido.van.rossum | 2008-01-05 23:19:06 +0100 (Sat, 05 Jan 2008) | 3 lines

  Patch #1637: fix urlparse for URLs like 'http://x.com?arg=/foo'.
  Fix by John Nagle.
........
  r59759 | guido.van.rossum | 2008-01-05 23:20:01 +0100 (Sat, 05 Jan 2008) | 2 lines

  Add John Nagle (of issue #1637).
........
  r59765 | raymond.hettinger | 2008-01-06 10:02:24 +0100 (Sun, 06 Jan 2008) | 1 line

  Small code simplification.  Forgot that classmethods can be called from intances.
........
  r59766 | martin.v.loewis | 2008-01-06 11:09:48 +0100 (Sun, 06 Jan 2008) | 2 lines

  Use vcbuild for VS 2009.
........
  r59767 | martin.v.loewis | 2008-01-06 12:03:43 +0100 (Sun, 06 Jan 2008) | 2 lines

  Package using VS 2008.
........
  r59768 | martin.v.loewis | 2008-01-06 12:13:16 +0100 (Sun, 06 Jan 2008) | 2 lines

  Don't try to package msvcr90 for the moment.
........
  r59769 | georg.brandl | 2008-01-06 15:17:36 +0100 (Sun, 06 Jan 2008) | 4 lines

  #1696393: don't check for '.' and '..' in ntpath.walk since
  they aren't returned from os.listdir anymore.
  Reported by Michael Haggerty.
........
  r59770 | georg.brandl | 2008-01-06 15:27:15 +0100 (Sun, 06 Jan 2008) | 3 lines

  #1742: don't raise exception on os.path.relpath("a", "a"), but return os.curdir.
  Reported by Jesse Towner.
........
  r59771 | georg.brandl | 2008-01-06 15:33:52 +0100 (Sun, 06 Jan 2008) | 2 lines

  #1591: Clarify docstring of Popen3.
........
  r59772 | georg.brandl | 2008-01-06 16:30:34 +0100 (Sun, 06 Jan 2008) | 2 lines

  #1680: fix context manager example function name.
........
  r59773 | georg.brandl | 2008-01-06 16:34:57 +0100 (Sun, 06 Jan 2008) | 2 lines

  #1755097: document default values for [].sort() and sorted().
........
diff --git a/Lib/collections.py b/Lib/collections.py
index d539683..504ae19 100644
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -54,15 +54,23 @@
         seen_names.add(name)
 
     # Create and fill-in the class template
+    numfields = len(field_names)
     argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
     reprtxt = ', '.join('%s=%%r' % name for name in field_names)
     dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names))
     template = '''class %(typename)s(tuple):
         '%(typename)s(%(argtxt)s)' \n
         __slots__ = () \n
+        _fields = %(field_names)r \n
         def __new__(cls, %(argtxt)s):
             return tuple.__new__(cls, (%(argtxt)s)) \n
-        _cast = classmethod(tuple.__new__) \n
+        @classmethod
+        def _make(cls, iterable):
+            'Make a new %(typename)s object from a sequence or iterable'
+            result = tuple.__new__(cls, iterable)
+            if len(result) != %(numfields)d:
+                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
+            return result \n
         def __repr__(self):
             return '%(typename)s(%(reprtxt)s)' %% self \n
         def _asdict(t):
@@ -70,10 +78,10 @@
             return {%(dicttxt)s} \n
         def _replace(self, **kwds):
             'Return a new %(typename)s object replacing specified fields with new values'
-            return %(typename)s._cast(map(kwds.get, %(field_names)r, self)) \n
-        @property
-        def _fields(self):
-            return %(field_names)r \n\n''' % locals()
+            result = self._make(map(kwds.pop, %(field_names)r, self))
+            if kwds:
+                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
+            return result \n\n''' % locals()
     for i, name in enumerate(field_names):
         template += '        %s = property(itemgetter(%d))\n' % (name, i)
     if verbose:
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
index 06b2293..c4a4ac5 100644
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -254,12 +254,10 @@
     except os.error:
         return
     func(arg, top, names)
-    exceptions = ('.', '..')
     for name in names:
-        if name not in exceptions:
-            name = join(top, name)
-            if isdir(name):
-                walk(name, func, arg)
+        name = join(top, name)
+        if isdir(name):
+            walk(name, func, arg)
 
 
 # Expand paths beginning with '~' or '~user'.
@@ -492,4 +490,6 @@
         i += 1
 
     rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+    if not rel_list:
+        return curdir
     return join(*rel_list)
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index 6d4a9e2..ee6d0f2 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -178,8 +178,8 @@
 def ismount(path):
     """Test whether a path is a mount point"""
     try:
-        s1 = os.stat(path)
-        s2 = os.stat(join(path, '..'))
+        s1 = os.lstat(path)
+        s2 = os.lstat(join(path, '..'))
     except os.error:
         return False # It doesn't exist -- so not a mount point :-)
     dev1 = s1.st_dev
@@ -398,4 +398,6 @@
     i = len(commonprefix([start_list, path_list]))
 
     rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+    if not rel_list:
+        return curdir
     return join(*rel_list)
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index a21f1ab..9ea92d0 100644
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2021,11 +2021,11 @@
 
         # Set correct owner, mtime and filemode on directories.
         for tarinfo in directories:
-            path = os.path.join(path, tarinfo.name)
+            dirpath = os.path.join(path, tarinfo.name)
             try:
-                self.chown(tarinfo, path)
-                self.utime(tarinfo, path)
-                self.chmod(tarinfo, path)
+                self.chown(tarinfo, dirpath)
+                self.utime(tarinfo, dirpath)
+                self.chmod(tarinfo, dirpath)
             except ExtractError as e:
                 if self.errorlevel > 1:
                     raise
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index fdc82fc..d8cf72e 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -20,6 +20,7 @@
         self.assertEqual(Point.__slots__, ())
         self.assertEqual(Point.__module__, __name__)
         self.assertEqual(Point.__getitem__, tuple.__getitem__)
+        self.assertEqual(Point._fields, ('x', 'y'))
 
         self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi')       # type has non-alpha char
         self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi')      # type has keyword
@@ -34,6 +35,9 @@
         namedtuple('Point0', 'x1 y2')   # Verify that numbers are allowed in names
         namedtuple('_', 'a b c')        # Test leading underscores in a typename
 
+        self.assertRaises(TypeError, Point._make, [11])                     # catch too few args
+        self.assertRaises(TypeError, Point._make, [11, 22, 33])             # catch too many args
+
     def test_instance(self):
         Point = namedtuple('Point', 'x y')
         p = Point(11, 22)
@@ -49,18 +53,17 @@
         self.assertEqual(repr(p), 'Point(x=11, y=22)')
         self.assert_('__dict__' not in dir(p))                              # verify instance has no dict
         self.assert_('__weakref__' not in dir(p))
-        self.assertEqual(p, Point._cast([11, 22]))                          # test _cast classmethod
+        self.assertEqual(p, Point._make([11, 22]))                          # test _make classmethod
         self.assertEqual(p._fields, ('x', 'y'))                             # test _fields attribute
         self.assertEqual(p._replace(x=1), (1, 22))                          # test _replace method
         self.assertEqual(p._asdict(), dict(x=11, y=22))                     # test _asdict method
 
-        # Verify that _fields is read-only
         try:
-            p._fields = ('F1' ,'F2')
-        except AttributeError:
+            p._replace(x=1, error=2)
+        except ValueError:
             pass
         else:
-            self.fail('The _fields attribute needs to be read-only')
+            self._fail('Did not detect an incorrect fieldname')
 
         # verify that field string can have commas
         Point = namedtuple('Point', 'x, y')
@@ -94,14 +97,14 @@
     def test_odd_sizes(self):
         Zero = namedtuple('Zero', '')
         self.assertEqual(Zero(), ())
-        self.assertEqual(Zero._cast([]), ())
+        self.assertEqual(Zero._make([]), ())
         self.assertEqual(repr(Zero()), 'Zero()')
         self.assertEqual(Zero()._asdict(), {})
         self.assertEqual(Zero()._fields, ())
 
         Dot = namedtuple('Dot', 'd')
         self.assertEqual(Dot(1), (1,))
-        self.assertEqual(Dot._cast([1]), (1,))
+        self.assertEqual(Dot._make([1]), (1,))
         self.assertEqual(Dot(1).d, 1)
         self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
         self.assertEqual(Dot(1)._asdict(), {'d':1})
@@ -115,7 +118,7 @@
         Big = namedtuple('Big', names)
         b = Big(*range(n))
         self.assertEqual(b, tuple(range(n)))
-        self.assertEqual(Big._cast(range(n)), tuple(range(n)))
+        self.assertEqual(Big._make(range(n)), tuple(range(n)))
         for pos, name in enumerate(names):
             self.assertEqual(getattr(b, name), pos)
         repr(b)                                 # make sure repr() doesn't blow-up
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 6ebfb69..db370b1 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -909,7 +909,7 @@
 
 Several option flags can be used to customize the behavior of the test
 runner.  These are defined as module constants in doctest, and passed
-to the DocTestRunner constructor (multiple constants should be or-ed
+to the DocTestRunner constructor (multiple constants should be ORed
 together).
 
 The DONT_ACCEPT_TRUE_FOR_1 flag disables matches between True/False
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index c6dbf2e..3c05e63 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -166,6 +166,7 @@
 tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b')
 tester('ntpath.relpath("a", "b/c")', '..\\..\\a')
 tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a')
+tester('ntpath.relpath("a", "a")', '.')
 
 if errors:
     raise TestFailed(str(errors) + " errors.")
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index 8c0d5ff..a25e2b2 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -501,6 +501,7 @@
             self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
             self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+curdir+"/a/b")
             self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
+            self.assertEqual(posixpath.relpath("a", "a"), ".")
         finally:
             os.getcwd = real_getcwd
 
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 97445a0..535f0ef 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -9,6 +9,8 @@
 import thread, threading
 import Queue
 import sys
+import os
+import array
 from weakref import proxy
 import signal
 
@@ -508,6 +510,15 @@
         self.assertEqual(sock.proto, 0)
         sock.close()
 
+    def test_sock_ioctl(self):
+        if os.name != "nt":
+            return
+        self.assert_(hasattr(socket.socket, 'ioctl'))
+        self.assert_(hasattr(socket, 'SIO_RCVALL'))
+        self.assert_(hasattr(socket, 'RCVALL_ON'))
+        self.assert_(hasattr(socket, 'RCVALL_OFF'))
+
+
 class BasicTCPTest(SocketConnectedTest):
 
     def __init__(self, methodName='runTest'):
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index a97df37..91cf024 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -243,6 +243,23 @@
         data = open(os.path.join(TEMPDIR, "ustar/symtype"), "rb").read()
         self.assertEqual(md5sum(data), md5_regtype)
 
+    def test_extractall(self):
+        # Test if extractall() correctly restores directory permissions
+        # and times (see issue1735).
+        if sys.platform == "win32":
+            # Win32 has no support for utime() on directories or
+            # fine grained permissions.
+            return
+
+        tar = tarfile.open(tarname, encoding="iso8859-1")
+        directories = [t for t in tar if t.isdir()]
+        tar.extractall(TEMPDIR, directories)
+        for tarinfo in directories:
+            path = os.path.join(TEMPDIR, tarinfo.name)
+            self.assertEqual(tarinfo.mode & 0o777, os.stat(path).st_mode & 0o777)
+            self.assertEqual(tarinfo.mtime, os.path.getmtime(path))
+        tar.close()
+
 
 class StreamReadTest(ReadTest):
 
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
index de08613..8ab8f35 100644
--- a/Lib/test/test_urlparse.py
+++ b/Lib/test/test_urlparse.py
@@ -254,6 +254,24 @@
         self.assertEqual(p.port, 80)
         self.assertEqual(p.geturl(), url)
 
+        # Addressing issue1698, which suggests Username can contain
+        # "@" characters.  Though not RFC compliant, many ftp sites allow
+        # and request email addresses as usernames.
+
+        url = "http://User@example.com:Pass@www.python.org:080/doc/?query=yes#frag"
+        p = urlparse.urlsplit(url)
+        self.assertEqual(p.scheme, "http")
+        self.assertEqual(p.netloc, "User@example.com:Pass@www.python.org:080")
+        self.assertEqual(p.path, "/doc/")
+        self.assertEqual(p.query, "query=yes")
+        self.assertEqual(p.fragment, "frag")
+        self.assertEqual(p.username, "User@example.com")
+        self.assertEqual(p.password, "Pass")
+        self.assertEqual(p.hostname, "www.python.org")
+        self.assertEqual(p.port, 80)
+        self.assertEqual(p.geturl(), url)
+
+
     def test_attributes_bad_port(self):
         """Check handling of non-integer ports."""
         p = urlparse.urlsplit("http://www.example.net:foo")
@@ -287,6 +305,11 @@
         self.assertEqual(p.port, None)
         self.assertEqual(p.geturl(), uri)
 
+    def test_noslash(self):
+        # Issue 1637: http://foo.com?query is legal
+        self.assertEqual(urlparse.urlparse("http://example.com?blahblah=/foo"),
+                         ('http', 'example.com', '', '', 'blahblah=/foo', ''))
+
 def test_main():
     test_support.run_unittest(UrlParseTestCase)
 
diff --git a/Lib/urlparse.py b/Lib/urlparse.py
index 4317714..1f435b9 100644
--- a/Lib/urlparse.py
+++ b/Lib/urlparse.py
@@ -82,7 +82,7 @@
     def username(self):
         netloc = self.netloc
         if "@" in netloc:
-            userinfo = netloc.split("@", 1)[0]
+            userinfo = netloc.rsplit("@", 1)[0]
             if ":" in userinfo:
                 userinfo = userinfo.split(":", 1)[0]
             return userinfo
@@ -92,7 +92,7 @@
     def password(self):
         netloc = self.netloc
         if "@" in netloc:
-            userinfo = netloc.split("@", 1)[0]
+            userinfo = netloc.rsplit("@", 1)[0]
             if ":" in userinfo:
                 return userinfo.split(":", 1)[1]
         return None
@@ -101,7 +101,7 @@
     def hostname(self):
         netloc = self.netloc
         if "@" in netloc:
-            netloc = netloc.split("@", 1)[1]
+            netloc = netloc.rsplit("@", 1)[1]
         if ":" in netloc:
             netloc = netloc.split(":", 1)[0]
         return netloc.lower() or None
@@ -110,7 +110,7 @@
     def port(self):
         netloc = self.netloc
         if "@" in netloc:
-            netloc = netloc.split("@", 1)[1]
+            netloc = netloc.rsplit("@", 1)[1]
         if ":" in netloc:
             port = netloc.split(":", 1)[1]
             return int(port, 10)
@@ -169,13 +169,12 @@
     return url[:i], url[i+1:]
 
 def _splitnetloc(url, start=0):
-    for c in '/?#': # the order is important!
-        delim = url.find(c, start)
-        if delim >= 0:
-            break
-    else:
-        delim = len(url)
-    return url[start:delim], url[delim:]
+    delim = len(url)   # position of end of domain part of url, default is end
+    for c in '/?#':    # look for delimiters; the order is NOT important
+        wdelim = url.find(c, start)        # find first of this delim
+        if wdelim >= 0:                    # if found
+            delim = min(delim, wdelim)     # use earliest delim position
+    return url[start:delim], url[delim:]   # return (domain, rest)
 
 def urlsplit(url, scheme='', allow_fragments=True):
     """Parse a URL into 5 components: