[Python-checkins] cpython (merge 3.5 -> 3.5): Merge 3.5.1rc1 release changes back into main 3.5 branch.

larry.hastings python-checkins at python.org
Mon Nov 23 02:29:40 EST 2015


https://hg.python.org/cpython/rev/a077bab36ae4
changeset: 99303:a077bab36ae4
branch: 3.5
parent: 99302:afc0ad583808
parent: 99296:3a44f06907f1
user: Larry Hastings <larry at hastings.org>
date: Sun Nov 22 23:27:07 2015 -0800
summary:
 Merge 3.5.1rc1 release changes back into main 3.5 branch.
files:
 Lib/test/test_shutil.py | 23 ++++
 Lib/test/test_xml_etree.py | 102 ++++++++++++++++++++
 Lib/test/test_xml_etree_c.py | 32 ++++++
 Lib/zipfile.py | 4 +-
 Misc/ACKS | 1 +
 Misc/NEWS | 17 +++
 Modules/_elementtree.c | 42 ++++----
 Tools/msi/bundle/bundle.targets | 2 +-
 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
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -1105,6 +1105,29 @@
 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
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -244,6 +244,33 @@
 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 @@
 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 @@
 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 @@
 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
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -22,6 +22,38 @@
 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
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -1444,7 +1444,9 @@
 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
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1518,6 +1518,7 @@
 Larry Wall
 Kevin Walzer
 Rodrigo Steinmuller Wanderley
+Dingyuan Wang
 Ke Wang
 Greg Ward
 Tom Wardill
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -1711,7 +1711,7 @@
 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 @@
 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 @@
 /* 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 @@
 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 @@
 
 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 @@
 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
--- 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
--- 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>
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /