bpo-36832: add zipfile.Path (#13153)

* bpo-36832: add zipfile.Path

* bpo-36832: add documentation for zipfile.Path

* 📜🤖 Added by blurb_it.

* Remove module reference from blurb.

* Sort the imports

* Update docstrings and docs per recommendations.

* Rely on test.support.temp_dir

* Signal that 'root' is the parameter.

* Correct spelling of 'mod'

* Convert docstring to comment for brevity.

* Fix more errors in the docs
This commit is contained in:
Jason R. Coombs 2019-05-08 09:45:06 -04:00 committed by Barry Warsaw
parent 70b80541bb
commit b2758ff955
4 changed files with 320 additions and 8 deletions

View file

@ -1,13 +1,15 @@
import contextlib
import importlib.util
import io
import os
import importlib.util
import pathlib
import posixpath
import time
import shutil
import struct
import zipfile
import tempfile
import time
import unittest
import zipfile
from tempfile import TemporaryFile
@ -2392,5 +2394,113 @@ class CommandLineTest(unittest.TestCase):
with open(path, 'rb') as f:
self.assertEqual(f.read(), zf.read(zi))
# Poor man's technique to consume a (smallish) iterable.
consume = tuple
def add_dirs(zipfile):
"""
Given a writable zipfile, inject directory entries for
any directories implied by the presence of children.
"""
names = zipfile.namelist()
consume(
zipfile.writestr(name + "/", b"")
for name in map(posixpath.dirname, names)
if name and name + "/" not in names
)
return zipfile
def build_abcde_files():
"""
Create a zip file with this structure:
.
a.txt
b
c.txt
d
e.txt
"""
data = io.BytesIO()
zf = zipfile.ZipFile(data, "w")
zf.writestr("a.txt", b"content of a")
zf.writestr("b/c.txt", b"content of c")
zf.writestr("b/d/e.txt", b"content of e")
zf.filename = "abcde.zip"
return zf
class TestPath(unittest.TestCase):
def setUp(self):
self.fixtures = contextlib.ExitStack()
self.addCleanup(self.fixtures.close)
def zipfile_abcde(self):
with self.subTest():
yield build_abcde_files()
with self.subTest():
yield add_dirs(build_abcde_files())
def zipfile_ondisk(self):
tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
for zipfile_abcde in self.zipfile_abcde():
buffer = zipfile_abcde.fp
zipfile_abcde.close()
path = tmpdir / zipfile_abcde.filename
with path.open("wb") as strm:
strm.write(buffer.getvalue())
yield path
def test_iterdir_istype(self):
for zipfile_abcde in self.zipfile_abcde():
root = zipfile.Path(zipfile_abcde)
assert root.is_dir()
a, b = root.iterdir()
assert a.is_file()
assert b.is_dir()
c, d = b.iterdir()
assert c.is_file()
e, = d.iterdir()
assert e.is_file()
def test_open(self):
for zipfile_abcde in self.zipfile_abcde():
root = zipfile.Path(zipfile_abcde)
a, b = root.iterdir()
with a.open() as strm:
data = strm.read()
assert data == b"content of a"
def test_read(self):
for zipfile_abcde in self.zipfile_abcde():
root = zipfile.Path(zipfile_abcde)
a, b = root.iterdir()
assert a.read_text() == "content of a"
assert a.read_bytes() == b"content of a"
def test_traverse_truediv(self):
for zipfile_abcde in self.zipfile_abcde():
root = zipfile.Path(zipfile_abcde)
a = root / "a"
assert a.is_file()
e = root / "b" / "d" / "e.txt"
assert e.read_text() == "content of e"
def test_pathlike_construction(self):
"""
zipfile.Path should be constructable from a path-like object
"""
for zipfile_ondisk in self.zipfile_ondisk():
pathlike = pathlib.Path(str(zipfile_ondisk))
zipfile.Path(pathlike)
def test_traverse_pathlike(self):
for zipfile_abcde in self.zipfile_abcde():
root = zipfile.Path(zipfile_abcde)
root / pathlib.Path("a")
if __name__ == "__main__":
unittest.main()