Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c58c392

Browse files
committed
Trunk merge.
2 parents 409da15 + bcd3044 commit c58c392

8 files changed

Lines changed: 74 additions & 25 deletions

File tree

Doc/library/functools.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ The :mod:`functools` module defines the following functions:
4949
Since a dictionary is used to cache results, the positional and keyword
5050
arguments to the function must be hashable.
5151

52-
If *maxsize* is set to None, the LRU feature is disabled and the cache
53-
can grow without bound.
52+
If *maxsize* is set to None, the LRU feature is disabled and the cache can
53+
grow without bound. The LRU feature performs best when *maxsize* is a
54+
power-of-two.
5455

5556
If *typed* is set to True, function arguments of different types will be
5657
cached separately. For example, ``f(3)`` and ``f(3.0)`` will be treated

Include/pyerrors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **);
8787
PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *);
8888

8989
#if defined(__clang__) || \
90-
(defined(__GNUC__) && \
90+
(defined(__GNUC_MAJOR__) && \
9191
((__GNUC_MAJOR__ >= 3) || \
9292
(__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5)))
9393
#define _Py_NO_RETURN __attribute__((__noreturn__))

Lib/functools.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -142,30 +142,35 @@ def __ne__(self, other):
142142

143143
_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
144144

145-
class _CacheKey(list):
146-
'Make a cache key from optionally typed positional and keyword arguments'
147-
145+
class _HashedSeq(list):
148146
__slots__ = 'hashvalue'
149147

150-
def __init__(self, args, kwds, typed,
151-
kwd_mark = (object(),),
152-
sorted=sorted, tuple=tuple, type=type, hash=hash):
153-
key = args
154-
if kwds:
155-
sorted_items = sorted(kwds.items())
156-
key += kwd_mark
157-
for item in sorted_items:
158-
key += item
159-
if typed:
160-
key += tuple(type(v) for v in args)
161-
if kwds:
162-
key += tuple(type(v) for k, v in sorted_items)
163-
self[:] = key
164-
self.hashvalue = hash(key) # so we only have to hash just once
148+
def __init__(self, tup, hash=hash):
149+
self[:] = tup
150+
self.hashvalue = hash(tup)
165151

166152
def __hash__(self):
167153
return self.hashvalue
168154

155+
def _make_key(args, kwds, typed,
156+
kwd_mark = (object(),),
157+
fasttypes = {int, str, frozenset, type(None)},
158+
sorted=sorted, tuple=tuple, type=type, len=len):
159+
'Make a cache key from optionally typed positional and keyword arguments'
160+
key = args
161+
if kwds:
162+
sorted_items = sorted(kwds.items())
163+
key += kwd_mark
164+
for item in sorted_items:
165+
key += item
166+
if typed:
167+
key += tuple(type(v) for v in args)
168+
if kwds:
169+
key += tuple(type(v) for k, v in sorted_items)
170+
elif len(key) == 1 and type(key[0]) in fasttypes:
171+
return key[0]
172+
return _HashedSeq(key)
173+
169174
def lru_cache(maxsize=128, typed=False):
170175
"""Least-recently-used cache decorator.
171176
@@ -193,7 +198,7 @@ def lru_cache(maxsize=128, typed=False):
193198

194199
# Constants shared by all lru cache instances:
195200
sentinel = object() # unique object used to signal cache misses
196-
make_key = _CacheKey # build a key from the function arguments
201+
make_key = _make_key # build a key from the function arguments
197202
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
198203

199204
def decorating_function(user_function):

Lib/ipaddress.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,7 @@ def is_unspecified(self):
11301130
"""
11311131
unspecified_address = IPv4Address('0.0.0.0')
11321132
if isinstance(self, _BaseAddress):
1133-
return self in unspecified_address
1133+
return self == unspecified_address
11341134
return (self.network_address == self.broadcast_address ==
11351135
unspecified_address)
11361136

Lib/os.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,20 @@ def makedirs(name, mode=0o777, exist_ok=False):
160160
try:
161161
mkdir(name, mode)
162162
except OSError as e:
163-
if not (e.errno == errno.EEXIST and exist_ok and path.isdir(name) and
164-
st.S_IMODE(lstat(name).st_mode) == _get_masked_mode(mode)):
163+
dir_exists = path.isdir(name)
164+
expected_mode = _get_masked_mode(mode)
165+
if dir_exists:
166+
# S_ISGID is automatically copied by the OS from parent to child
167+
# directories on mkdir. Don't consider it being set to be a mode
168+
# mismatch as mkdir does not unset it when not specified in mode.
169+
actual_mode = st.S_IMODE(lstat(name).st_mode) & ~st.S_ISGID
170+
else:
171+
actual_mode = -1
172+
if not (e.errno == errno.EEXIST and exist_ok and dir_exists and
173+
actual_mode == expected_mode):
174+
if dir_exists and actual_mode != expected_mode:
175+
e.strerror += ' (mode %o != expected mode %o)' % (
176+
actual_mode, expected_mode)
165177
raise
166178

167179
def removedirs(name):

Lib/test/test_ipaddress.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ def testReservedIpv4(self):
837837
self.assertEqual(False, ipaddress.ip_network('128.0.0.0').is_loopback)
838838

839839
# test addresses
840+
self.assertEqual(True, ipaddress.ip_address('0.0.0.0').is_unspecified)
840841
self.assertEqual(True, ipaddress.ip_address('224.1.1.1').is_multicast)
841842
self.assertEqual(False, ipaddress.ip_address('240.0.0.0').is_multicast)
842843

Lib/test/test_os.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,31 @@ def test_exist_ok_existing_directory(self):
838838
os.makedirs(path, mode=mode, exist_ok=True)
839839
os.umask(old_mask)
840840

841+
def test_exist_ok_s_isgid_directory(self):
842+
path = os.path.join(support.TESTFN, 'dir1')
843+
S_ISGID = stat.S_ISGID
844+
mode = 0o777
845+
old_mask = os.umask(0o022)
846+
try:
847+
existing_testfn_mode = stat.S_IMODE(
848+
os.lstat(support.TESTFN).st_mode)
849+
os.chmod(support.TESTFN, existing_testfn_mode | S_ISGID)
850+
if (os.lstat(support.TESTFN).st_mode & S_ISGID != S_ISGID):
851+
raise unittest.SkipTest('No support for S_ISGID dir mode.')
852+
# The os should apply S_ISGID from the parent dir for us, but
853+
# this test need not depend on that behavior. Be explicit.
854+
os.makedirs(path, mode | S_ISGID)
855+
# http://bugs.python.org/issue14992
856+
# Should not fail when the bit is already set.
857+
os.makedirs(path, mode, exist_ok=True)
858+
# remove the bit.
859+
os.chmod(path, stat.S_IMODE(os.lstat(path).st_mode) & ~S_ISGID)
860+
with self.assertRaises(OSError):
861+
# Should fail when the bit is not already set when demanded.
862+
os.makedirs(path, mode | S_ISGID, exist_ok=True)
863+
finally:
864+
os.umask(old_mask)
865+
841866
def test_exist_ok_existing_regular_file(self):
842867
base = support.TESTFN
843868
path = os.path.join(support.TESTFN, 'dir1')

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ What's New in Python 3.3.0 Beta 1?
1010
Library
1111
-------
1212

13+
- Issue #14992: os.makedirs(path, exist_ok=True) would raise an OSError
14+
when the path existed and had the S_ISGID mode bit set when it was
15+
not explicitly asked for. This is no longer an exception as mkdir
16+
cannot control if the OS sets that bit for it or not.
17+
1318
- Issue #14989: Make the CGI enable option to http.server available via command
1419
line.
1520

0 commit comments

Comments
 (0)