diff options
author | Larry Hastings <larry@hastings.org> | 2015-11-23 07:27:07 (GMT) |
---|---|---|
committer | Larry Hastings <larry@hastings.org> | 2015-11-23 07:27:07 (GMT) |
commit | 3715cab3cb6bc689c66e7aaaeb86fbf953fe0262 (patch) | |
tree | 2135159f044b692a6b8d22eef78b18d8b8e7cd43 | |
parent | ba11daa4e880e16d56ed02e7e14d95f3b2c44eaf (diff) | |
parent | 3987fefd6f7309a36fb093cbfe229afe7b39406b (diff) | |
download | cpython-3715cab3cb6bc689c66e7aaaeb86fbf953fe0262.zip cpython-3715cab3cb6bc689c66e7aaaeb86fbf953fe0262.tar.gz cpython-3715cab3cb6bc689c66e7aaaeb86fbf953fe0262.tar.bz2 |
Merge 3.5.1rc1 release changes back into main 3.5 branch.
-rw-r--r-- | Lib/test/test_shutil.py | 23 | ||||
-rw-r--r-- | Lib/test/test_xml_etree.py | 102 | ||||
-rw-r--r-- | Lib/test/test_xml_etree_c.py | 32 | ||||
-rw-r--r-- | Lib/zipfile.py | 4 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 17 | ||||
-rw-r--r-- | Modules/_elementtree.c | 42 | ||||
-rw-r--r-- | Tools/msi/bundle/bundle.targets | 2 | ||||
-rw-r--r-- | Tools/msi/uploadrelease.proj | 2 |
9 files changed, 201 insertions, 24 deletions
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 62036dd..ca1d006 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1105,6 +1105,29 @@ class TestShutil(unittest.TestCase): names2 = zf.namelist() 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): tmpdir = self.mkdtemp() base_name = os.path.join(tmpdir, 'archive') diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index d09b969..0a2c7bc 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -244,6 +244,33 @@ class ElementTreeTest(unittest.TestCase): self.assertEqual(ET.XML, ET.fromstring) 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): # Basic method sanity checks. @@ -2350,6 +2377,7 @@ class ElementSlicingTest(unittest.TestCase): self.assertEqual(e[-2].tag, 'a8') self.assertRaises(IndexError, lambda: e[12]) + self.assertRaises(IndexError, lambda: e[-12]) def test_getslice_range(self): 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[::8]), ['a0', 'a8']) 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): e = self._make_elem_with_children(4) 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[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): e = self._make_elem_with_children(4) @@ -2400,6 +2433,75 @@ class ElementSlicingTest(unittest.TestCase): del e[::2] 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): def tearDown(self): diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py index d0df38d..96b446e 100644 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -22,6 +22,38 @@ class MiscTests(unittest.TestCase): finally: 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') class TestAliasWorking(unittest.TestCase): diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 2bd1007..bee00d0 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1444,7 +1444,9 @@ class ZipFile: arcname += '/' zinfo = ZipInfo(arcname, date_time) 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 else: zinfo.compress_type = compress_type @@ -1518,6 +1518,7 @@ Richard Walker Larry Wall Kevin Walzer Rodrigo Steinmuller Wanderley +Dingyuan Wang Ke Wang Greg Ward Tom Wardill @@ -2,6 +2,23 @@ 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? ================================= diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 911b5ac..744e833 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1711,7 +1711,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value) Py_ssize_t start, stop, step, slicelen, newlen, cur, i; PyObject* recycle = NULL; - PyObject* seq = NULL; + PyObject* seq; if (!self->extra) { if (create_extra(self, NULL) < 0) @@ -1790,21 +1790,21 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value) Py_XDECREF(recycle); return 0; } - else { - /* A new slice is actually being assigned */ - seq = PySequence_Fast(value, ""); - if (!seq) { - PyErr_Format( - PyExc_TypeError, - "expected sequence, not \"%.200s\"", Py_TYPE(value)->tp_name - ); - return -1; - } - newlen = PySequence_Size(seq); + + /* A new slice is actually being assigned */ + seq = PySequence_Fast(value, ""); + if (!seq) { + PyErr_Format( + PyExc_TypeError, + "expected sequence, not \"%.200s\"", Py_TYPE(value)->tp_name + ); + return -1; } + newlen = PySequence_Size(seq); if (step != 1 && newlen != slicelen) { + Py_DECREF(seq); PyErr_Format(PyExc_ValueError, "attempt to assign sequence 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. */ if (newlen > slicelen) { if (element_resize(self, newlen - slicelen) < 0) { - if (seq) { - Py_DECREF(seq); - } + Py_DECREF(seq); return -1; } } @@ -1829,9 +1827,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value) we're done modifying the element */ recycle = PyList_New(slicelen); if (!recycle) { - if (seq) { - Py_DECREF(seq); - } + Py_DECREF(seq); return -1; } 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; - if (seq) { - Py_DECREF(seq); - } + Py_DECREF(seq); /* discard the recycle bin, and everything in it */ Py_XDECREF(recycle); @@ -1927,6 +1921,12 @@ static int element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value) { char *name = ""; + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "can't delete attribute"); + return -1; + } if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); if (name == NULL) diff --git a/Tools/msi/bundle/bundle.targets b/Tools/msi/bundle/bundle.targets index 57ca1dc..aeeff3b 100644 --- a/Tools/msi/bundle/bundle.targets +++ b/Tools/msi/bundle/bundle.targets @@ -18,7 +18,7 @@ <!-- See Tools/msi/buildrelease.bat for help on configuring the download URL --> <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> </PropertyGroup> diff --git a/Tools/msi/uploadrelease.proj b/Tools/msi/uploadrelease.proj index ec4ede5..0d472de 100644 --- a/Tools/msi/uploadrelease.proj +++ b/Tools/msi/uploadrelease.proj @@ -16,7 +16,7 @@ <PropertyGroup> <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> <ItemGroup> |