mirror of https://github.com/python/cpython
Trunk merge.
This commit is contained in:
commit
c58c392da7
|
@ -49,8 +49,9 @@ The :mod:`functools` module defines the following functions:
|
|||
Since a dictionary is used to cache results, the positional and keyword
|
||||
arguments to the function must be hashable.
|
||||
|
||||
If *maxsize* is set to None, the LRU feature is disabled and the cache
|
||||
can grow without bound.
|
||||
If *maxsize* is set to None, the LRU feature is disabled and the cache can
|
||||
grow without bound. The LRU feature performs best when *maxsize* is a
|
||||
power-of-two.
|
||||
|
||||
If *typed* is set to True, function arguments of different types will be
|
||||
cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated
|
||||
|
|
|
@ -87,7 +87,7 @@ PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **);
|
|||
PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
#if defined(__clang__) || \
|
||||
(defined(__GNUC__) && \
|
||||
(defined(__GNUC_MAJOR__) && \
|
||||
((__GNUC_MAJOR__ >= 3) || \
|
||||
(__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5)))
|
||||
#define _Py_NO_RETURN __attribute__((__noreturn__))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
16
Lib/os.py
16
Lib/os.py
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -10,6 +10,11 @@ What's New in Python 3.3.0 Beta 1?
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #14992: os.makedirs(path, exist_ok=True) would raise an OSError
|
||||
when the path existed and had the S_ISGID mode bit set when it was
|
||||
not explicitly asked for. This is no longer an exception as mkdir
|
||||
cannot control if the OS sets that bit for it or not.
|
||||
|
||||
- Issue #14989: Make the CGI enable option to http.server available via command
|
||||
line.
|
||||
|
||||
|
|
Loading…
Reference in New Issue