https://github.com/python/cpython/commit/8d62df60d8733d0fa9aee14ef746d0009a…
commit: 8d62df60d8733d0fa9aee14ef746d0009a7a9726
branch: master
author: Daniel Hillier <daniel.hillier(a)gmail.com>
committer: Serhiy Storchaka <storchaka(a)gmail.com>
date: 2019-11-30T10:30:47+02:00
summary:
bpo-37523: Raise ValueError for I/O operations on a closed zipfile.ZipExtFile. (GH-14658)
Raises ValueError when calling the following on a closed zipfile.ZipExtFile: read, readable, seek, seekable, tell.
files:
A Misc/NEWS.d/next/Library/2019-10-02-02-55-37.bpo-37523.GguwJ6.rst
M Lib/test/test_zipfile.py
M Lib/zipfile.py
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 1e1854be7109b..66f05ac1f3aef 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -571,6 +571,20 @@ def test_write_default_name(self):
with open(TESTFN, "rb") as f:
self.assertEqual(zipfp.read(TESTFN), f.read())
+ def test_io_on_closed_zipextfile(self):
+ fname = "somefile.txt"
+ with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
+ zipfp.writestr(fname, "bogus")
+
+ with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
+ with zipfp.open(fname) as fid:
+ fid.close()
+ self.assertRaises(ValueError, fid.read)
+ self.assertRaises(ValueError, fid.seek, 0)
+ self.assertRaises(ValueError, fid.tell)
+ self.assertRaises(ValueError, fid.readable)
+ self.assertRaises(ValueError, fid.seekable)
+
def test_write_to_readonly(self):
"""Check that trying to call write() on a readonly ZipFile object
raises a ValueError."""
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index b0afb9da942b1..e1d07f2a5237b 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -889,12 +889,16 @@ def peek(self, n=1):
return self._readbuffer[self._offset: self._offset + 512]
def readable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return True
def read(self, n=-1):
"""Read and return up to n bytes.
If the argument is omitted, None, or negative, data is read and returned until EOF is reached.
"""
+ if self.closed:
+ raise ValueError("read from closed file.")
if n is None or n < 0:
buf = self._readbuffer[self._offset:]
self._readbuffer = b''
@@ -1031,9 +1035,13 @@ def close(self):
super().close()
def seekable(self):
+ if self.closed:
+ raise ValueError("I/O operation on closed file.")
return self._seekable
def seek(self, offset, whence=0):
+ if self.closed:
+ raise ValueError("seek on closed file.")
if not self._seekable:
raise io.UnsupportedOperation("underlying stream is not seekable")
curr_pos = self.tell()
@@ -1082,6 +1090,8 @@ def seek(self, offset, whence=0):
return self.tell()
def tell(self):
+ if self.closed:
+ raise ValueError("tell on closed file.")
if not self._seekable:
raise io.UnsupportedOperation("underlying stream is not seekable")
filepos = self._orig_file_size - self._left - len(self._readbuffer) + self._offset
diff --git a/Misc/NEWS.d/next/Library/2019-10-02-02-55-37.bpo-37523.GguwJ6.rst b/Misc/NEWS.d/next/Library/2019-10-02-02-55-37.bpo-37523.GguwJ6.rst
new file mode 100644
index 0000000000000..5711969ff38cf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-10-02-02-55-37.bpo-37523.GguwJ6.rst
@@ -0,0 +1 @@
+Change :class:`zipfile.ZipExtFile` to raise ``ValueError`` when trying to access the underlying file object after it has been closed. This new behavior is consistent with how accessing closed files is handled in other parts of Python.
\ No newline at end of file
https://github.com/python/cpython/commit/1df65f7c6c00dfae9286c7a58e1b3803e3…
commit: 1df65f7c6c00dfae9286c7a58e1b3803e3af33e5
branch: master
author: Brett Cannon <54418+brettcannon(a)users.noreply.github.com>
committer: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
date: 2019-11-29T15:37:08-08:00
summary:
Fix old mention of virtualenv (GH-17417)
Automerge-Triggered-By: @brettcannon
files:
M Lib/venv/scripts/posix/activate.fish
diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish
index d213b9060a687..cb1ba1c301ede 100644
--- a/Lib/venv/scripts/posix/activate.fish
+++ b/Lib/venv/scripts/posix/activate.fish
@@ -1,7 +1,7 @@
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (http://fishshell.org); you cannot run it directly.
-function deactivate -d "Exit virtualenv and return to normal shell environment"
+function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
https://github.com/python/cpython/commit/305189ecdc8322c22879a04564cad5989f…
commit: 305189ecdc8322c22879a04564cad5989f937462
branch: 3.8
author: Jules Lasne (jlasne) <jules.lasne(a)gmail.com>
committer: Benjamin Peterson <benjamin(a)python.org>
date: 2019-11-28T22:47:45-06:00
summary:
[3.8] Added missing coma after end of list in subprocess.rst (GH-17389)
(cherry picked from commit f25875af425a3480e557aaedf49c3bb867bcbd5d)
files:
M Doc/library/subprocess.rst
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 954e0fec11828..ea12cd133a6ff 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -596,7 +596,7 @@ functions.
Popen and the other functions in this module that use it raise an
:ref:`auditing event <auditing>` ``subprocess.Popen`` with arguments
- ``executable``, ``args``, ``cwd``, ``env``. The value for ``args``
+ ``executable``, ``args``, ``cwd``, and ``env``. The value for ``args``
may be a single string or a list of strings, depending on platform.
.. versionchanged:: 3.2
https://github.com/python/cpython/commit/18d8edbbb6626ac9cdf1152a720811beb2…
commit: 18d8edbbb6626ac9cdf1152a720811beb2230b33
branch: 3.8
author: Tzu-ping Chung <uranusjr(a)gmail.com>
committer: Vinay Sajip <vinay_sajip(a)yahoo.co.uk>
date: 2019-11-28T15:44:08Z
summary:
bpo-38928: Remove upgrade_dependencies() from venv doc (GH-17410)
files:
M Doc/library/venv.rst
diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst
index 3483ef36a2c33..31a3f41e4724c 100644
--- a/Doc/library/venv.rst
+++ b/Doc/library/venv.rst
@@ -186,14 +186,6 @@ creation according to their needs, the :class:`EnvBuilder` class.
Installs activation scripts appropriate to the platform into the virtual
environment.
- .. method:: upgrade_dependencies(context)
-
- Upgrades the core venv dependency packages (currently ``pip`` and
- ``setuptools``) in the environment. This is done by shelling out to the
- ``pip`` executable in the environment.
-
- .. versionadded:: 3.8
-
.. method:: post_setup(context)
A placeholder method which can be overridden in third party
https://github.com/python/cpython/commit/c0db88f6abbace79644b2aca2290bf41b1…
commit: c0db88f6abbace79644b2aca2290bf41b1a37174
branch: 3.8
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: GitHub <noreply(a)github.com>
date: 2019-11-27T21:29:02-08:00
summary:
bpo-38524: clarify example a bit and improve formatting (GH-17406)
(cherry picked from commit 02519f75d15b063914a11351da30178ca4ceb54b)
Co-authored-by: Tal Einat <taleinat+github(a)gmail.com>
files:
M Doc/reference/datamodel.rst
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index ae24adeacb167..46d50ad600ff5 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1657,13 +1657,16 @@ class' :attr:`~object.__dict__`.
.. note::
- ``__set_name__`` is only called implicitly as part of the ``type`` constructor, so
- it will need to be called explicitly with the appropriate parameters when a
- descriptor is added to a class after initial creation::
+ :meth:`__set_name__` is only called implicitly as part of the
+ :class:`type` constructor, so it will need to be called explicitly with
+ the appropriate parameters when a descriptor is added to a class after
+ initial creation::
+ class A:
+ pass
descr = custom_descriptor()
- cls.attr = descr
- descr.__set_name__(cls, 'attr')
+ A.attr = descr
+ descr.__set_name__(A, 'attr')
See :ref:`class-object-creation` for more details.
https://github.com/python/cpython/commit/7e9bbbe51e74e5928e6a6c3e70434d8249…
commit: 7e9bbbe51e74e5928e6a6c3e70434d824970ef58
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: GitHub <noreply(a)github.com>
date: 2019-11-27T21:28:37-08:00
summary:
bpo-38524: clarify example a bit and improve formatting (GH-17406)
(cherry picked from commit 02519f75d15b063914a11351da30178ca4ceb54b)
Co-authored-by: Tal Einat <taleinat+github(a)gmail.com>
files:
M Doc/reference/datamodel.rst
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 7a99e1e5220bb..b4f9ddc1194cb 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1643,13 +1643,16 @@ class' :attr:`~object.__dict__`.
.. note::
- ``__set_name__`` is only called implicitly as part of the ``type`` constructor, so
- it will need to be called explicitly with the appropriate parameters when a
- descriptor is added to a class after initial creation::
+ :meth:`__set_name__` is only called implicitly as part of the
+ :class:`type` constructor, so it will need to be called explicitly with
+ the appropriate parameters when a descriptor is added to a class after
+ initial creation::
+ class A:
+ pass
descr = custom_descriptor()
- cls.attr = descr
- descr.__set_name__(cls, 'attr')
+ A.attr = descr
+ descr.__set_name__(A, 'attr')
See :ref:`class-object-creation` for more details.
https://github.com/python/cpython/commit/e65b3fa9f16537d20f5f37c25673ac899f…
commit: e65b3fa9f16537d20f5f37c25673ac899fcd7099
branch: 3.7
author: Inada Naoki <songofacandy(a)gmail.com>
committer: GitHub <noreply(a)github.com>
date: 2019-11-28T14:23:58+09:00
summary:
bpo-26730: Fix SpooledTemporaryFile data corruption (GH-17400)
SpooledTemporaryFile.rollback() might cause data corruption
when it is in text mode.
Co-Authored-By: Serhiy Storchaka <storchaka(a)gmail.com>.
(cherry picked from commit ea9835c5d154ab6a54eed627958473b6768b28cc)
files:
A Misc/NEWS.d/next/Library/2019-11-27-16-30-02.bpo-26730.56cdBn.rst
M Doc/library/tempfile.rst
M Lib/tempfile.py
M Lib/test/test_tempfile.py
diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst
index dd24a1c6f4ffd..00acf4b179237 100644
--- a/Doc/library/tempfile.rst
+++ b/Doc/library/tempfile.rst
@@ -95,8 +95,8 @@ The module defines the following user-callable items:
causes the file to roll over to an on-disk file regardless of its size.
The returned object is a file-like object whose :attr:`_file` attribute
- is either an :class:`io.BytesIO` or :class:`io.StringIO` object (depending on
- whether binary or text *mode* was specified) or a true file
+ is either an :class:`io.BytesIO` or :class:`io.TextIOWrapper` object
+ (depending on whether binary or text *mode* was specified) or a true file
object, depending on whether :func:`rollover` has been called. This
file-like object can be used in a :keyword:`with` statement, just like
a normal file.
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 214322416963c..24f673c64aa8d 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -637,10 +637,8 @@ def __init__(self, max_size=0, mode='w+b', buffering=-1,
if 'b' in mode:
self._file = _io.BytesIO()
else:
- # Setting newline="\n" avoids newline translation;
- # this is important because otherwise on Windows we'd
- # get double newline translation upon rollover().
- self._file = _io.StringIO(newline="\n")
+ self._file = _io.TextIOWrapper(_io.BytesIO(),
+ encoding=encoding, newline=newline)
self._max_size = max_size
self._rolled = False
self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
@@ -660,8 +658,12 @@ def rollover(self):
newfile = self._file = TemporaryFile(**self._TemporaryFileArgs)
del self._TemporaryFileArgs
- newfile.write(file.getvalue())
- newfile.seek(file.tell(), 0)
+ pos = file.tell()
+ if hasattr(newfile, 'buffer'):
+ newfile.buffer.write(file.detach().getvalue())
+ else:
+ newfile.write(file.getvalue())
+ newfile.seek(pos, 0)
self._rolled = True
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 931312831616c..c0464200a3aa3 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -1119,7 +1119,8 @@ def test_properties(self):
def test_text_mode(self):
# Creating a SpooledTemporaryFile with a text mode should produce
# a file object reading and writing (Unicode) text strings.
- f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10)
+ f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10,
+ encoding="utf-8")
f.write("abc\n")
f.seek(0)
self.assertEqual(f.read(), "abc\n")
@@ -1129,8 +1130,8 @@ def test_text_mode(self):
self.assertFalse(f._rolled)
self.assertEqual(f.mode, 'w+')
self.assertIsNone(f.name)
- self.assertIsNone(f.newlines)
- self.assertIsNone(f.encoding)
+ self.assertEqual(f.newlines, os.linesep)
+ self.assertEqual(f.encoding, "utf-8")
f.write("xyzzy\n")
f.seek(0)
@@ -1143,7 +1144,7 @@ def test_text_mode(self):
self.assertEqual(f.mode, 'w+')
self.assertIsNotNone(f.name)
self.assertEqual(f.newlines, os.linesep)
- self.assertIsNotNone(f.encoding)
+ self.assertEqual(f.encoding, "utf-8")
def test_text_newline_and_encoding(self):
f = tempfile.SpooledTemporaryFile(mode='w+', max_size=10,
@@ -1154,12 +1155,14 @@ def test_text_newline_and_encoding(self):
self.assertFalse(f._rolled)
self.assertEqual(f.mode, 'w+')
self.assertIsNone(f.name)
- self.assertIsNone(f.newlines)
- self.assertIsNone(f.encoding)
+ self.assertIsNotNone(f.newlines)
+ self.assertEqual(f.encoding, "utf-8")
- f.write("\u039B" * 20 + "\r\n")
+ f.write("\u039C" * 10 + "\r\n")
+ f.write("\u039D" * 20)
f.seek(0)
- self.assertEqual(f.read(), "\u039B\r\n" + ("\u039B" * 20) + "\r\n")
+ self.assertEqual(f.read(),
+ "\u039B\r\n" + ("\u039C" * 10) + "\r\n" + ("\u039D" * 20))
self.assertTrue(f._rolled)
self.assertEqual(f.mode, 'w+')
self.assertIsNotNone(f.name)
diff --git a/Misc/NEWS.d/next/Library/2019-11-27-16-30-02.bpo-26730.56cdBn.rst b/Misc/NEWS.d/next/Library/2019-11-27-16-30-02.bpo-26730.56cdBn.rst
new file mode 100644
index 0000000000000..a92b90a495605
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-11-27-16-30-02.bpo-26730.56cdBn.rst
@@ -0,0 +1,2 @@
+Fix ``SpooledTemporaryFile.rollover()`` might corrupt the file when it is in
+text mode. Patch by Serhiy Storchaka.