diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/collections.py | 18 | ||||
-rw-r--r-- | Lib/ntpath.py | 10 | ||||
-rw-r--r-- | Lib/posixpath.py | 6 | ||||
-rw-r--r-- | Lib/tarfile.py | 8 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 19 | ||||
-rw-r--r-- | Lib/test/test_doctest.py | 2 | ||||
-rw-r--r-- | Lib/test/test_ntpath.py | 1 | ||||
-rw-r--r-- | Lib/test/test_posixpath.py | 1 | ||||
-rw-r--r-- | Lib/test/test_socket.py | 11 | ||||
-rw-r--r-- | Lib/test/test_tarfile.py | 17 | ||||
-rw-r--r-- | Lib/test/test_urlparse.py | 23 | ||||
-rw-r--r-- | Lib/urlparse.py | 21 |
12 files changed, 101 insertions, 36 deletions
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 @@ def namedtuple(typename, field_names, verbose=False): 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 @@ def namedtuple(typename, field_names, verbose=False): 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 @@ def walk(top, func, arg): 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 @@ def relpath(path, start=curdir): 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 samestat(s1, s2): 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 @@ def relpath(path, start=curdir): 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 @@ class TarFile(object): # 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 @@ class TestNamedTuple(unittest.TestCase): 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 @@ class TestNamedTuple(unittest.TestCase): 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 @@ class TestNamedTuple(unittest.TestCase): 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 @@ class TestNamedTuple(unittest.TestCase): 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 @@ class TestNamedTuple(unittest.TestCase): 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 @@ Tests of `DocTestRunner`'s option flag handling. 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")', '..\\'+currentdir+'\\a') 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 @@ class PosixPathTest(unittest.TestCase): 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 time import thread, threading import Queue import sys +import os +import array from weakref import proxy import signal @@ -508,6 +510,15 @@ class GeneralModuleTests(unittest.TestCase): 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 @@ class MiscReadTest(ReadTest): 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 @@ class UrlParseTestCase(unittest.TestCase): 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 @@ class UrlParseTestCase(unittest.TestCase): 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 @@ class BaseResult(tuple): 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 @@ class BaseResult(tuple): 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 @@ class BaseResult(tuple): 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 @@ class BaseResult(tuple): 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 @@ def _splitparams(url): 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: |