diff options
author | Barry Warsaw <barry@python.org> | 2012-06-04 13:41:48 (GMT) |
---|---|---|
committer | Barry Warsaw <barry@python.org> | 2012-06-04 13:41:48 (GMT) |
commit | c58c392da7f8fb49b84b2f4de35d3c40ed6d36c1 (patch) | |
tree | a574ea8bd98e1d8d3be264c68b9952bda33b18c6 /Lib | |
parent | 409da157d7ff2a49892e20a94a3fc83475845d22 (diff) | |
parent | bcd304480f16f3f936a7bdbff4dfab41f8e30292 (diff) | |
download | cpython-c58c392da7f8fb49b84b2f4de35d3c40ed6d36c1.zip cpython-c58c392da7f8fb49b84b2f4de35d3c40ed6d36c1.tar.gz cpython-c58c392da7f8fb49b84b2f4de35d3c40ed6d36c1.tar.bz2 |
Trunk merge.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/functools.py | 43 | ||||
-rw-r--r-- | Lib/ipaddress.py | 2 | ||||
-rw-r--r-- | Lib/os.py | 16 | ||||
-rw-r--r-- | Lib/test/test_ipaddress.py | 1 | ||||
-rw-r--r-- | Lib/test/test_os.py | 25 |
5 files changed, 65 insertions, 22 deletions
diff --git a/Lib/functools.py b/Lib/functools.py index 9f024f1..226a46e 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -142,30 +142,35 @@ except ImportError: _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) -class _CacheKey(list): - 'Make a cache key from optionally typed positional and keyword arguments' - +class _HashedSeq(list): __slots__ = 'hashvalue' - def __init__(self, args, kwds, typed, - kwd_mark = (object(),), - sorted=sorted, tuple=tuple, type=type, hash=hash): - key = args - if kwds: - sorted_items = sorted(kwds.items()) - key += kwd_mark - for item in sorted_items: - key += item - if typed: - key += tuple(type(v) for v in args) - if kwds: - key += tuple(type(v) for k, v in sorted_items) - self[:] = key - self.hashvalue = hash(key) # so we only have to hash just once + def __init__(self, tup, hash=hash): + self[:] = tup + self.hashvalue = hash(tup) def __hash__(self): return self.hashvalue +def _make_key(args, kwds, typed, + kwd_mark = (object(),), + fasttypes = {int, str, frozenset, type(None)}, + sorted=sorted, tuple=tuple, type=type, len=len): + 'Make a cache key from optionally typed positional and keyword arguments' + key = args + if kwds: + sorted_items = sorted(kwds.items()) + key += kwd_mark + for item in sorted_items: + key += item + if typed: + key += tuple(type(v) for v in args) + if kwds: + key += tuple(type(v) for k, v in sorted_items) + elif len(key) == 1 and type(key[0]) in fasttypes: + return key[0] + return _HashedSeq(key) + def lru_cache(maxsize=128, typed=False): """Least-recently-used cache decorator. @@ -193,7 +198,7 @@ def lru_cache(maxsize=128, typed=False): # Constants shared by all lru cache instances: sentinel = object() # unique object used to signal cache misses - make_key = _CacheKey # build a key from the function arguments + make_key = _make_key # build a key from the function arguments PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields def decorating_function(user_function): diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index a8edcd1..25bcccd 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1130,7 +1130,7 @@ class _BaseV4: """ unspecified_address = IPv4Address('0.0.0.0') if isinstance(self, _BaseAddress): - return self in unspecified_address + return self == unspecified_address return (self.network_address == self.broadcast_address == unspecified_address) @@ -160,8 +160,20 @@ def makedirs(name, mode=0o777, exist_ok=False): try: mkdir(name, mode) except OSError as e: - if not (e.errno == errno.EEXIST and exist_ok and path.isdir(name) and - st.S_IMODE(lstat(name).st_mode) == _get_masked_mode(mode)): + dir_exists = path.isdir(name) + expected_mode = _get_masked_mode(mode) + if dir_exists: + # S_ISGID is automatically copied by the OS from parent to child + # directories on mkdir. Don't consider it being set to be a mode + # mismatch as mkdir does not unset it when not specified in mode. + actual_mode = st.S_IMODE(lstat(name).st_mode) & ~st.S_ISGID + else: + actual_mode = -1 + if not (e.errno == errno.EEXIST and exist_ok and dir_exists and + actual_mode == expected_mode): + if dir_exists and actual_mode != expected_mode: + e.strerror += ' (mode %o != expected mode %o)' % ( + actual_mode, expected_mode) raise def removedirs(name): diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index aff4ff9..5b7d013 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -837,6 +837,7 @@ class IpaddrUnitTest(unittest.TestCase): self.assertEqual(False, ipaddress.ip_network('128.0.0.0').is_loopback) # test addresses + self.assertEqual(True, ipaddress.ip_address('0.0.0.0').is_unspecified) self.assertEqual(True, ipaddress.ip_address('224.1.1.1').is_multicast) self.assertEqual(False, ipaddress.ip_address('240.0.0.0').is_multicast) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 9b29b37..3ee5a1e 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -838,6 +838,31 @@ class MakedirTests(unittest.TestCase): os.makedirs(path, mode=mode, exist_ok=True) os.umask(old_mask) + def test_exist_ok_s_isgid_directory(self): + path = os.path.join(support.TESTFN, 'dir1') + S_ISGID = stat.S_ISGID + mode = 0o777 + old_mask = os.umask(0o022) + try: + existing_testfn_mode = stat.S_IMODE( + os.lstat(support.TESTFN).st_mode) + os.chmod(support.TESTFN, existing_testfn_mode | S_ISGID) + if (os.lstat(support.TESTFN).st_mode & S_ISGID != S_ISGID): + raise unittest.SkipTest('No support for S_ISGID dir mode.') + # The os should apply S_ISGID from the parent dir for us, but + # this test need not depend on that behavior. Be explicit. + os.makedirs(path, mode | S_ISGID) + # http://bugs.python.org/issue14992 + # Should not fail when the bit is already set. + os.makedirs(path, mode, exist_ok=True) + # remove the bit. + os.chmod(path, stat.S_IMODE(os.lstat(path).st_mode) & ~S_ISGID) + with self.assertRaises(OSError): + # Should fail when the bit is not already set when demanded. + os.makedirs(path, mode | S_ISGID, exist_ok=True) + finally: + os.umask(old_mask) + def test_exist_ok_existing_regular_file(self): base = support.TESTFN path = os.path.join(support.TESTFN, 'dir1') |