Merge 3.5.1rc1 release changes back into main 3.5 branch.

This commit is contained in:
Larry Hastings 2015-11-22 23:27:07 -08:00
commit 3715cab3cb
9 changed files with 201 additions and 24 deletions

View file

@ -1105,6 +1105,29 @@ class TestShutil(unittest.TestCase):
names2 = zf.namelist() names2 = zf.namelist()
self.assertEqual(sorted(names), sorted(names2)) self.assertEqual(sorted(names), sorted(names2))
@requires_zlib
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
@unittest.skipUnless(shutil.which('unzip'),
'Need the unzip command to run')
def test_unzip_zipfile(self):
root_dir, base_dir = self._create_files()
base_name = os.path.join(self.mkdtemp(), 'archive')
archive = make_archive(base_name, 'zip', root_dir, base_dir)
# check if ZIP file was created
self.assertEqual(archive, base_name + '.zip')
self.assertTrue(os.path.isfile(archive))
# now check the ZIP file using `unzip -t`
zip_cmd = ['unzip', '-t', archive]
with support.change_cwd(root_dir):
try:
subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exc:
details = exc.output.decode(errors="replace")
msg = "{}\n\n**Unzip Output**\n{}"
self.fail(msg.format(exc, details))
def test_make_archive(self): def test_make_archive(self):
tmpdir = self.mkdtemp() tmpdir = self.mkdtemp()
base_name = os.path.join(tmpdir, 'archive') base_name = os.path.join(tmpdir, 'archive')

View file

@ -244,6 +244,33 @@ class ElementTreeTest(unittest.TestCase):
self.assertEqual(ET.XML, ET.fromstring) self.assertEqual(ET.XML, ET.fromstring)
self.assertEqual(ET.PI, ET.ProcessingInstruction) self.assertEqual(ET.PI, ET.ProcessingInstruction)
def test_set_attribute(self):
element = ET.Element('tag')
self.assertEqual(element.tag, 'tag')
element.tag = 'Tag'
self.assertEqual(element.tag, 'Tag')
element.tag = 'TAG'
self.assertEqual(element.tag, 'TAG')
self.assertIsNone(element.text)
element.text = 'Text'
self.assertEqual(element.text, 'Text')
element.text = 'TEXT'
self.assertEqual(element.text, 'TEXT')
self.assertIsNone(element.tail)
element.tail = 'Tail'
self.assertEqual(element.tail, 'Tail')
element.tail = 'TAIL'
self.assertEqual(element.tail, 'TAIL')
self.assertEqual(element.attrib, {})
element.attrib = {'a': 'b', 'c': 'd'}
self.assertEqual(element.attrib, {'a': 'b', 'c': 'd'})
element.attrib = {'A': 'B', 'C': 'D'}
self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})
def test_simpleops(self): def test_simpleops(self):
# Basic method sanity checks. # Basic method sanity checks.
@ -2350,6 +2377,7 @@ class ElementSlicingTest(unittest.TestCase):
self.assertEqual(e[-2].tag, 'a8') self.assertEqual(e[-2].tag, 'a8')
self.assertRaises(IndexError, lambda: e[12]) self.assertRaises(IndexError, lambda: e[12])
self.assertRaises(IndexError, lambda: e[-12])
def test_getslice_range(self): def test_getslice_range(self):
e = self._make_elem_with_children(6) e = self._make_elem_with_children(6)
@ -2368,12 +2396,17 @@ class ElementSlicingTest(unittest.TestCase):
self.assertEqual(self._elem_tags(e[::3]), ['a0', 'a3', 'a6', 'a9']) self.assertEqual(self._elem_tags(e[::3]), ['a0', 'a3', 'a6', 'a9'])
self.assertEqual(self._elem_tags(e[::8]), ['a0', 'a8']) self.assertEqual(self._elem_tags(e[::8]), ['a0', 'a8'])
self.assertEqual(self._elem_tags(e[1::8]), ['a1', 'a9']) self.assertEqual(self._elem_tags(e[1::8]), ['a1', 'a9'])
self.assertEqual(self._elem_tags(e[3::sys.maxsize]), ['a3'])
self.assertEqual(self._elem_tags(e[3::sys.maxsize<<64]), ['a3'])
def test_getslice_negative_steps(self): def test_getslice_negative_steps(self):
e = self._make_elem_with_children(4) e = self._make_elem_with_children(4)
self.assertEqual(self._elem_tags(e[::-1]), ['a3', 'a2', 'a1', 'a0']) self.assertEqual(self._elem_tags(e[::-1]), ['a3', 'a2', 'a1', 'a0'])
self.assertEqual(self._elem_tags(e[::-2]), ['a3', 'a1']) self.assertEqual(self._elem_tags(e[::-2]), ['a3', 'a1'])
self.assertEqual(self._elem_tags(e[3::-sys.maxsize]), ['a3'])
self.assertEqual(self._elem_tags(e[3::-sys.maxsize-1]), ['a3'])
self.assertEqual(self._elem_tags(e[3::-sys.maxsize<<64]), ['a3'])
def test_delslice(self): def test_delslice(self):
e = self._make_elem_with_children(4) e = self._make_elem_with_children(4)
@ -2400,6 +2433,75 @@ class ElementSlicingTest(unittest.TestCase):
del e[::2] del e[::2]
self.assertEqual(self._subelem_tags(e), ['a1']) self.assertEqual(self._subelem_tags(e), ['a1'])
def test_setslice_single_index(self):
e = self._make_elem_with_children(4)
e[1] = ET.Element('b')
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
e[-2] = ET.Element('c')
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3'])
with self.assertRaises(IndexError):
e[5] = ET.Element('d')
with self.assertRaises(IndexError):
e[-5] = ET.Element('d')
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3'])
def test_setslice_range(self):
e = self._make_elem_with_children(4)
e[1:3] = [ET.Element('b%s' % i) for i in range(2)]
self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'a3'])
e = self._make_elem_with_children(4)
e[1:3] = [ET.Element('b')]
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a3'])
e = self._make_elem_with_children(4)
e[1:3] = [ET.Element('b%s' % i) for i in range(3)]
self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'b2', 'a3'])
def test_setslice_steps(self):
e = self._make_elem_with_children(6)
e[1:5:2] = [ET.Element('b%s' % i) for i in range(2)]
self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'a2', 'b1', 'a4', 'a5'])
e = self._make_elem_with_children(6)
with self.assertRaises(ValueError):
e[1:5:2] = [ET.Element('b')]
with self.assertRaises(ValueError):
e[1:5:2] = [ET.Element('b%s' % i) for i in range(3)]
with self.assertRaises(ValueError):
e[1:5:2] = []
self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3', 'a4', 'a5'])
e = self._make_elem_with_children(4)
e[1::sys.maxsize] = [ET.Element('b')]
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
e[1::sys.maxsize<<64] = [ET.Element('c')]
self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3'])
def test_setslice_negative_steps(self):
e = self._make_elem_with_children(4)
e[2:0:-1] = [ET.Element('b%s' % i) for i in range(2)]
self.assertEqual(self._subelem_tags(e), ['a0', 'b1', 'b0', 'a3'])
e = self._make_elem_with_children(4)
with self.assertRaises(ValueError):
e[2:0:-1] = [ET.Element('b')]
with self.assertRaises(ValueError):
e[2:0:-1] = [ET.Element('b%s' % i) for i in range(3)]
with self.assertRaises(ValueError):
e[2:0:-1] = []
self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3'])
e = self._make_elem_with_children(4)
e[1::-sys.maxsize] = [ET.Element('b')]
self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
e[1::-sys.maxsize-1] = [ET.Element('c')]
self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3'])
e[1::-sys.maxsize<<64] = [ET.Element('d')]
self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3'])
class IOTest(unittest.TestCase): class IOTest(unittest.TestCase):
def tearDown(self): def tearDown(self):

View file

@ -22,6 +22,38 @@ class MiscTests(unittest.TestCase):
finally: finally:
data = None data = None
def test_del_attribute(self):
element = cET.Element('tag')
element.tag = 'TAG'
with self.assertRaises(AttributeError):
del element.tag
self.assertEqual(element.tag, 'TAG')
with self.assertRaises(AttributeError):
del element.text
self.assertIsNone(element.text)
element.text = 'TEXT'
with self.assertRaises(AttributeError):
del element.text
self.assertEqual(element.text, 'TEXT')
with self.assertRaises(AttributeError):
del element.tail
self.assertIsNone(element.tail)
element.tail = 'TAIL'
with self.assertRaises(AttributeError):
del element.tail
self.assertEqual(element.tail, 'TAIL')
with self.assertRaises(AttributeError):
del element.attrib
self.assertEqual(element.attrib, {})
element.attrib = {'A': 'B', 'C': 'D'}
with self.assertRaises(AttributeError):
del element.attrib
self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})
@unittest.skipUnless(cET, 'requires _elementtree') @unittest.skipUnless(cET, 'requires _elementtree')
class TestAliasWorking(unittest.TestCase): class TestAliasWorking(unittest.TestCase):

View file

@ -1444,7 +1444,9 @@ class ZipFile:
arcname += '/' arcname += '/'
zinfo = ZipInfo(arcname, date_time) zinfo = ZipInfo(arcname, date_time)
zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
if compress_type is None: if isdir:
zinfo.compress_type = ZIP_STORED
elif compress_type is None:
zinfo.compress_type = self.compression zinfo.compress_type = self.compression
else: else:
zinfo.compress_type = compress_type zinfo.compress_type = compress_type

View file

@ -1518,6 +1518,7 @@ Richard Walker
Larry Wall Larry Wall
Kevin Walzer Kevin Walzer
Rodrigo Steinmuller Wanderley Rodrigo Steinmuller Wanderley
Dingyuan Wang
Ke Wang Ke Wang
Greg Ward Greg Ward
Tom Wardill Tom Wardill

View file

@ -2,6 +2,23 @@
Python News Python News
+++++++++++ +++++++++++
What's New in Python 3.5.2 release candidate 1?
===============================================
Release date: XXXX-XX-XX
Core and Builtins
-----------------
Library
-------
- Issue #25691: Fixed crash on deleting ElementTree.Element attributes.
- Issue #25624: ZipFile now always writes a ZIP_STORED header for directory
entries. Patch by Dingyuan Wang.
What's New in Python 3.5.1 final? What's New in Python 3.5.1 final?
================================= =================================

View file

@ -1711,7 +1711,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
Py_ssize_t start, stop, step, slicelen, newlen, cur, i; Py_ssize_t start, stop, step, slicelen, newlen, cur, i;
PyObject* recycle = NULL; PyObject* recycle = NULL;
PyObject* seq = NULL; PyObject* seq;
if (!self->extra) { if (!self->extra) {
if (create_extra(self, NULL) < 0) if (create_extra(self, NULL) < 0)
@ -1790,7 +1790,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
Py_XDECREF(recycle); Py_XDECREF(recycle);
return 0; return 0;
} }
else {
/* A new slice is actually being assigned */ /* A new slice is actually being assigned */
seq = PySequence_Fast(value, ""); seq = PySequence_Fast(value, "");
if (!seq) { if (!seq) {
@ -1801,10 +1801,10 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
return -1; return -1;
} }
newlen = PySequence_Size(seq); newlen = PySequence_Size(seq);
}
if (step != 1 && newlen != slicelen) if (step != 1 && newlen != slicelen)
{ {
Py_DECREF(seq);
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"attempt to assign sequence of size %zd " "attempt to assign sequence of size %zd "
"to extended slice of size %zd", "to extended slice of size %zd",
@ -1816,9 +1816,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
/* Resize before creating the recycle bin, to prevent refleaks. */ /* Resize before creating the recycle bin, to prevent refleaks. */
if (newlen > slicelen) { if (newlen > slicelen) {
if (element_resize(self, newlen - slicelen) < 0) { if (element_resize(self, newlen - slicelen) < 0) {
if (seq) {
Py_DECREF(seq); Py_DECREF(seq);
}
return -1; return -1;
} }
} }
@ -1829,9 +1827,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
we're done modifying the element */ we're done modifying the element */
recycle = PyList_New(slicelen); recycle = PyList_New(slicelen);
if (!recycle) { if (!recycle) {
if (seq) {
Py_DECREF(seq); Py_DECREF(seq);
}
return -1; return -1;
} }
for (cur = start, i = 0; i < slicelen; for (cur = start, i = 0; i < slicelen;
@ -1859,9 +1855,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
self->extra->length += newlen - slicelen; self->extra->length += newlen - slicelen;
if (seq) {
Py_DECREF(seq); Py_DECREF(seq);
}
/* discard the recycle bin, and everything in it */ /* discard the recycle bin, and everything in it */
Py_XDECREF(recycle); Py_XDECREF(recycle);
@ -1927,6 +1921,12 @@ static int
element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value) element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value)
{ {
char *name = ""; char *name = "";
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError,
"can't delete attribute");
return -1;
}
if (PyUnicode_Check(nameobj)) if (PyUnicode_Check(nameobj))
name = _PyUnicode_AsString(nameobj); name = _PyUnicode_AsString(nameobj);
if (name == NULL) if (name == NULL)

View file

@ -18,7 +18,7 @@
<!-- See Tools/msi/buildrelease.bat for help on configuring the download URL --> <!-- See Tools/msi/buildrelease.bat for help on configuring the download URL -->
<DownloadUrl Condition="'$(DownloadUrl)' == '' and '$(DownloadUrlBase)' != ''">$(DownloadUrlBase.TrimEnd(`/`))/{version}/{arch}{releasename}/{msi}</DownloadUrl> <DownloadUrl Condition="'$(DownloadUrl)' == '' and '$(DownloadUrlBase)' != ''">$(DownloadUrlBase.TrimEnd(`/`))/{version}/{arch}{releasename}/{msi}</DownloadUrl>
<DefineConstants Condition="'$(DownloadUrl)' != ''">$(DefineConstants);DownloadUrl=$(DownloadUrl.Replace(`{version}`, `$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)`).Replace(`{arch}`, `$(ArchName)`).Replace(`{releasename}`, `$(ReleaseName)`).Replace(`{msi}`, `{2}`))</DefineConstants> <DefineConstants Condition="'$(DownloadUrl)' != ''">$(DefineConstants);DownloadUrl=$(DownloadUrl.Replace(`{version}`, `$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)`).Replace(`{arch}`, `$(ArchName)`).Replace(`{releasename}`, `$(ReleaseLevelName)`).Replace(`{msi}`, `{2}`))</DefineConstants>
<DefineConstants Condition="'$(DownloadUrl)' == ''">$(DefineConstants);DownloadUrl={2}</DefineConstants> <DefineConstants Condition="'$(DownloadUrl)' == ''">$(DefineConstants);DownloadUrl={2}</DefineConstants>
</PropertyGroup> </PropertyGroup>

View file

@ -16,7 +16,7 @@
<PropertyGroup> <PropertyGroup>
<EXETarget>$(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)</EXETarget> <EXETarget>$(DownloadUrlBase.TrimEnd(`/`))/$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)</EXETarget>
<MSITarget>$(DownloadUrl.TrimEnd(`/`))</MSITarget> <MSITarget>$(DownloadUrl.Replace(`{version}`, `$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)`).Replace(`{arch}`, `$(ArchName)`).Replace(`{releasename}`, `$(ReleaseLevelName)`).Replace(`{msi}`, ``).TrimEnd(`/`))</MSITarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>