File Doc/library/zipfile.rst changed (mode: 100644) (index a0de10cae3..4cde1dd76a) |
... |
... |
ZipFile Objects |
132 |
132 |
|
|
133 |
133 |
.. class:: ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True) |
.. class:: ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True) |
134 |
134 |
|
|
135 |
|
Open a ZIP file, where *file* can be either a path to a file (a string) or a |
|
136 |
|
file-like object. The *mode* parameter should be ``'r'`` to read an existing |
|
|
135 |
|
Open a ZIP file, where *file* can be a path to a file (a string), a |
|
136 |
|
file-like object or a :term:`path-like object`. |
|
137 |
|
The *mode* parameter should be ``'r'`` to read an existing |
137 |
138 |
file, ``'w'`` to truncate and write a new file, ``'a'`` to append to an |
file, ``'w'`` to truncate and write a new file, ``'a'`` to append to an |
138 |
139 |
existing file, or ``'x'`` to exclusively create and write a new file. |
existing file, or ``'x'`` to exclusively create and write a new file. |
139 |
140 |
If *mode* is ``'x'`` and *file* refers to an existing file, |
If *mode* is ``'x'`` and *file* refers to an existing file, |
|
... |
... |
ZipFile Objects |
183 |
184 |
Previously, a plain :exc:`RuntimeError` was raised for unrecognized |
Previously, a plain :exc:`RuntimeError` was raised for unrecognized |
184 |
185 |
compression values. |
compression values. |
185 |
186 |
|
|
|
187 |
|
.. versionchanged:: 3.6.2 |
|
188 |
|
The *file* parameter accepts a :term:`path-like object`. |
|
189 |
|
|
186 |
190 |
|
|
187 |
191 |
.. method:: ZipFile.close() |
.. method:: ZipFile.close() |
188 |
192 |
|
|
|
... |
... |
ZipFile Objects |
284 |
288 |
Calling :meth:`extract` on a closed ZipFile will raise a |
Calling :meth:`extract` on a closed ZipFile will raise a |
285 |
289 |
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised. |
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised. |
286 |
290 |
|
|
|
291 |
|
.. versionchanged:: 3.6.2 |
|
292 |
|
The *path* parameter accepts a :term:`path-like object`. |
|
293 |
|
|
287 |
294 |
|
|
288 |
295 |
.. method:: ZipFile.extractall(path=None, members=None, pwd=None) |
.. method:: ZipFile.extractall(path=None, members=None, pwd=None) |
289 |
296 |
|
|
|
... |
... |
ZipFile Objects |
304 |
311 |
Calling :meth:`extractall` on a closed ZipFile will raise a |
Calling :meth:`extractall` on a closed ZipFile will raise a |
305 |
312 |
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised. |
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised. |
306 |
313 |
|
|
|
314 |
|
.. versionchanged:: 3.6.2 |
|
315 |
|
The *path* parameter accepts a :term:`path-like object`. |
|
316 |
|
|
307 |
317 |
|
|
308 |
318 |
.. method:: ZipFile.printdir() |
.. method:: ZipFile.printdir() |
309 |
319 |
|
|
|
... |
... |
ZipFile Objects |
403 |
413 |
|
|
404 |
414 |
The following data attributes are also available: |
The following data attributes are also available: |
405 |
415 |
|
|
|
416 |
|
.. attribute:: ZipFile.filename |
|
417 |
|
|
|
418 |
|
Name of the ZIP file. |
406 |
419 |
|
|
407 |
420 |
.. attribute:: ZipFile.debug |
.. attribute:: ZipFile.debug |
408 |
421 |
|
|
|
... |
... |
The :class:`PyZipFile` constructor takes the same parameters as the |
488 |
501 |
.. versionadded:: 3.4 |
.. versionadded:: 3.4 |
489 |
502 |
The *filterfunc* parameter. |
The *filterfunc* parameter. |
490 |
503 |
|
|
|
504 |
|
.. versionchanged:: 3.6.2 |
|
505 |
|
The *pathname* parameter accepts a :term:`path-like object`. |
|
506 |
|
|
491 |
507 |
|
|
492 |
508 |
.. _zipinfo-objects: |
.. _zipinfo-objects: |
493 |
509 |
|
|
|
... |
... |
file: |
514 |
530 |
|
|
515 |
531 |
.. versionadded:: 3.6 |
.. versionadded:: 3.6 |
516 |
532 |
|
|
|
533 |
|
.. versionchanged:: 3.6.2 |
|
534 |
|
The *filename* parameter accepts a :term:`path-like object`. |
|
535 |
|
|
|
536 |
|
|
517 |
537 |
Instances have the following methods and attributes: |
Instances have the following methods and attributes: |
518 |
538 |
|
|
519 |
539 |
.. method:: ZipInfo.is_dir() |
.. method:: ZipInfo.is_dir() |
File Lib/test/test_zipfile.py changed (mode: 100644) (index 0a19d76f42..f3d993608f) |
... |
... |
import contextlib |
2 |
2 |
import io |
import io |
3 |
3 |
import os |
import os |
4 |
4 |
import importlib.util |
import importlib.util |
|
5 |
|
import pathlib |
5 |
6 |
import posixpath |
import posixpath |
6 |
7 |
import time |
import time |
7 |
8 |
import struct |
import struct |
|
... |
... |
from tempfile import TemporaryFile |
13 |
14 |
from random import randint, random, getrandbits |
from random import randint, random, getrandbits |
14 |
15 |
|
|
15 |
16 |
from test.support import script_helper |
from test.support import script_helper |
16 |
|
from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, |
|
|
17 |
|
from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, temp_cwd, |
17 |
18 |
requires_zlib, requires_bz2, requires_lzma, |
requires_zlib, requires_bz2, requires_lzma, |
18 |
19 |
captured_stdout, check_warnings) |
captured_stdout, check_warnings) |
19 |
20 |
|
|
|
... |
... |
class AbstractTestsWithSourceFile: |
148 |
149 |
for f in get_files(self): |
for f in get_files(self): |
149 |
150 |
self.zip_open_test(f, self.compression) |
self.zip_open_test(f, self.compression) |
150 |
151 |
|
|
|
152 |
|
def test_open_with_pathlike(self): |
|
153 |
|
path = pathlib.Path(TESTFN2) |
|
154 |
|
self.zip_open_test(path, self.compression) |
|
155 |
|
with zipfile.ZipFile(path, "r", self.compression) as zipfp: |
|
156 |
|
self.assertIsInstance(zipfp.filename, str) |
|
157 |
|
|
151 |
158 |
def zip_random_open_test(self, f, compression): |
def zip_random_open_test(self, f, compression): |
152 |
159 |
self.make_test_archive(f, compression) |
self.make_test_archive(f, compression) |
153 |
160 |
|
|
|
... |
... |
class PyZipFileTests(unittest.TestCase): |
906 |
913 |
finally: |
finally: |
907 |
914 |
rmtree(TESTFN2) |
rmtree(TESTFN2) |
908 |
915 |
|
|
|
916 |
|
def test_write_pathlike(self): |
|
917 |
|
os.mkdir(TESTFN2) |
|
918 |
|
try: |
|
919 |
|
with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp: |
|
920 |
|
fp.write("print(42)\n") |
|
921 |
|
|
|
922 |
|
with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: |
|
923 |
|
zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py") |
|
924 |
|
names = zipfp.namelist() |
|
925 |
|
self.assertCompiledIn('mod1.py', names) |
|
926 |
|
finally: |
|
927 |
|
rmtree(TESTFN2) |
|
928 |
|
|
909 |
929 |
|
|
910 |
930 |
class ExtractTests(unittest.TestCase): |
class ExtractTests(unittest.TestCase): |
911 |
|
def test_extract(self): |
|
|
931 |
|
|
|
932 |
|
def make_test_file(self): |
912 |
933 |
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: |
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: |
913 |
934 |
for fpath, fdata in SMALL_TEST_DATA: |
for fpath, fdata in SMALL_TEST_DATA: |
914 |
935 |
zipfp.writestr(fpath, fdata) |
zipfp.writestr(fpath, fdata) |
915 |
936 |
|
|
|
937 |
|
def test_extract(self): |
|
938 |
|
with temp_cwd(): |
|
939 |
|
self.make_test_file() |
|
940 |
|
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
|
941 |
|
for fpath, fdata in SMALL_TEST_DATA: |
|
942 |
|
writtenfile = zipfp.extract(fpath) |
|
943 |
|
|
|
944 |
|
# make sure it was written to the right place |
|
945 |
|
correctfile = os.path.join(os.getcwd(), fpath) |
|
946 |
|
correctfile = os.path.normpath(correctfile) |
|
947 |
|
|
|
948 |
|
self.assertEqual(writtenfile, correctfile) |
|
949 |
|
|
|
950 |
|
# make sure correct data is in correct file |
|
951 |
|
with open(writtenfile, "rb") as f: |
|
952 |
|
self.assertEqual(fdata.encode(), f.read()) |
|
953 |
|
|
|
954 |
|
unlink(writtenfile) |
|
955 |
|
|
|
956 |
|
def _test_extract_with_target(self, target): |
|
957 |
|
self.make_test_file() |
916 |
958 |
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
917 |
959 |
for fpath, fdata in SMALL_TEST_DATA: |
for fpath, fdata in SMALL_TEST_DATA: |
918 |
|
writtenfile = zipfp.extract(fpath) |
|
|
960 |
|
writtenfile = zipfp.extract(fpath, target) |
919 |
961 |
|
|
920 |
962 |
# make sure it was written to the right place |
# make sure it was written to the right place |
921 |
|
correctfile = os.path.join(os.getcwd(), fpath) |
|
|
963 |
|
correctfile = os.path.join(target, fpath) |
922 |
964 |
correctfile = os.path.normpath(correctfile) |
correctfile = os.path.normpath(correctfile) |
923 |
|
|
|
924 |
|
self.assertEqual(writtenfile, correctfile) |
|
|
965 |
|
self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target)) |
925 |
966 |
|
|
926 |
967 |
# make sure correct data is in correct file |
# make sure correct data is in correct file |
927 |
968 |
with open(writtenfile, "rb") as f: |
with open(writtenfile, "rb") as f: |
|
... |
... |
class ExtractTests(unittest.TestCase): |
929 |
970 |
|
|
930 |
971 |
unlink(writtenfile) |
unlink(writtenfile) |
931 |
972 |
|
|
932 |
|
# remove the test file subdirectories |
|
933 |
|
rmtree(os.path.join(os.getcwd(), 'ziptest2dir')) |
|
|
973 |
|
unlink(TESTFN2) |
|
974 |
|
|
|
975 |
|
def test_extract_with_target(self): |
|
976 |
|
with temp_dir() as extdir: |
|
977 |
|
self._test_extract_with_target(extdir) |
|
978 |
|
|
|
979 |
|
def test_extract_with_target_pathlike(self): |
|
980 |
|
with temp_dir() as extdir: |
|
981 |
|
self._test_extract_with_target(pathlib.Path(extdir)) |
934 |
982 |
|
|
935 |
983 |
def test_extract_all(self): |
def test_extract_all(self): |
936 |
|
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: |
|
937 |
|
for fpath, fdata in SMALL_TEST_DATA: |
|
938 |
|
zipfp.writestr(fpath, fdata) |
|
|
984 |
|
with temp_cwd(): |
|
985 |
|
self.make_test_file() |
|
986 |
|
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
|
987 |
|
zipfp.extractall() |
|
988 |
|
for fpath, fdata in SMALL_TEST_DATA: |
|
989 |
|
outfile = os.path.join(os.getcwd(), fpath) |
|
990 |
|
|
|
991 |
|
with open(outfile, "rb") as f: |
|
992 |
|
self.assertEqual(fdata.encode(), f.read()) |
939 |
993 |
|
|
|
994 |
|
unlink(outfile) |
|
995 |
|
|
|
996 |
|
def _test_extract_all_with_target(self, target): |
|
997 |
|
self.make_test_file() |
940 |
998 |
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
with zipfile.ZipFile(TESTFN2, "r") as zipfp: |
941 |
|
zipfp.extractall() |
|
|
999 |
|
zipfp.extractall(target) |
942 |
1000 |
for fpath, fdata in SMALL_TEST_DATA: |
for fpath, fdata in SMALL_TEST_DATA: |
943 |
|
outfile = os.path.join(os.getcwd(), fpath) |
|
|
1001 |
|
outfile = os.path.join(target, fpath) |
944 |
1002 |
|
|
945 |
1003 |
with open(outfile, "rb") as f: |
with open(outfile, "rb") as f: |
946 |
1004 |
self.assertEqual(fdata.encode(), f.read()) |
self.assertEqual(fdata.encode(), f.read()) |
947 |
1005 |
|
|
948 |
1006 |
unlink(outfile) |
unlink(outfile) |
949 |
1007 |
|
|
950 |
|
# remove the test file subdirectories |
|
951 |
|
rmtree(os.path.join(os.getcwd(), 'ziptest2dir')) |
|
|
1008 |
|
unlink(TESTFN2) |
|
1009 |
|
|
|
1010 |
|
def test_extract_all_with_target(self): |
|
1011 |
|
with temp_dir() as extdir: |
|
1012 |
|
self._test_extract_all_with_target(extdir) |
|
1013 |
|
|
|
1014 |
|
def test_extract_all_with_target_pathlike(self): |
|
1015 |
|
with temp_dir() as extdir: |
|
1016 |
|
self._test_extract_all_with_target(pathlib.Path(extdir)) |
952 |
1017 |
|
|
953 |
1018 |
def check_file(self, filename, content): |
def check_file(self, filename, content): |
954 |
1019 |
self.assertTrue(os.path.isfile(filename)) |
self.assertTrue(os.path.isfile(filename)) |
|
... |
... |
class OtherTests(unittest.TestCase): |
1188 |
1253 |
with open(TESTFN, "w") as fp: |
with open(TESTFN, "w") as fp: |
1189 |
1254 |
fp.write("this is not a legal zip file\n") |
fp.write("this is not a legal zip file\n") |
1190 |
1255 |
self.assertFalse(zipfile.is_zipfile(TESTFN)) |
self.assertFalse(zipfile.is_zipfile(TESTFN)) |
|
1256 |
|
# - passing a path-like object |
|
1257 |
|
self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN))) |
1191 |
1258 |
# - passing a file object |
# - passing a file object |
1192 |
1259 |
with open(TESTFN, "rb") as fp: |
with open(TESTFN, "rb") as fp: |
1193 |
1260 |
self.assertFalse(zipfile.is_zipfile(fp)) |
self.assertFalse(zipfile.is_zipfile(fp)) |
|
... |
... |
class ZipInfoTests(unittest.TestCase): |
2033 |
2100 |
zi = zipfile.ZipInfo.from_file(__file__) |
zi = zipfile.ZipInfo.from_file(__file__) |
2034 |
2101 |
self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py') |
self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py') |
2035 |
2102 |
self.assertFalse(zi.is_dir()) |
self.assertFalse(zi.is_dir()) |
|
2103 |
|
self.assertEqual(zi.file_size, os.path.getsize(__file__)) |
|
2104 |
|
|
|
2105 |
|
def test_from_file_pathlike(self): |
|
2106 |
|
zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__)) |
|
2107 |
|
self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py') |
|
2108 |
|
self.assertFalse(zi.is_dir()) |
|
2109 |
|
self.assertEqual(zi.file_size, os.path.getsize(__file__)) |
|
2110 |
|
|
|
2111 |
|
def test_from_file_bytes(self): |
|
2112 |
|
zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test') |
|
2113 |
|
self.assertEqual(posixpath.basename(zi.filename), 'test') |
|
2114 |
|
self.assertFalse(zi.is_dir()) |
|
2115 |
|
self.assertEqual(zi.file_size, os.path.getsize(__file__)) |
|
2116 |
|
|
|
2117 |
|
def test_from_file_fileno(self): |
|
2118 |
|
with open(__file__, 'rb') as f: |
|
2119 |
|
zi = zipfile.ZipInfo.from_file(f.fileno(), 'test') |
|
2120 |
|
self.assertEqual(posixpath.basename(zi.filename), 'test') |
|
2121 |
|
self.assertFalse(zi.is_dir()) |
|
2122 |
|
self.assertEqual(zi.file_size, os.path.getsize(__file__)) |
2036 |
2123 |
|
|
2037 |
2124 |
def test_from_dir(self): |
def test_from_dir(self): |
2038 |
2125 |
dirpath = os.path.dirname(os.path.abspath(__file__)) |
dirpath = os.path.dirname(os.path.abspath(__file__)) |
File Lib/zipfile.py changed (mode: 100644) (index 93171358e4..b5c16dbc12) |
... |
... |
class ZipInfo (object): |
478 |
478 |
this will be the same as filename, but without a drive letter and with |
this will be the same as filename, but without a drive letter and with |
479 |
479 |
leading path separators removed). |
leading path separators removed). |
480 |
480 |
""" |
""" |
|
481 |
|
if isinstance(filename, os.PathLike): |
|
482 |
|
filename = os.fspath(filename) |
481 |
483 |
st = os.stat(filename) |
st = os.stat(filename) |
482 |
484 |
isdir = stat.S_ISDIR(st.st_mode) |
isdir = stat.S_ISDIR(st.st_mode) |
483 |
485 |
mtime = time.localtime(st.st_mtime) |
mtime = time.localtime(st.st_mtime) |
|
... |
... |
class ZipFile: |
1069 |
1071 |
self._comment = b'' |
self._comment = b'' |
1070 |
1072 |
|
|
1071 |
1073 |
# Check if we were passed a file-like object |
# Check if we were passed a file-like object |
|
1074 |
|
if isinstance(file, os.PathLike): |
|
1075 |
|
file = os.fspath(file) |
1072 |
1076 |
if isinstance(file, str): |
if isinstance(file, str): |
1073 |
1077 |
# No, it's a filename |
# No, it's a filename |
1074 |
1078 |
self._filePassed = 0 |
self._filePassed = 0 |
|
... |
... |
class ZipFile: |
1469 |
1473 |
as possible. `member' may be a filename or a ZipInfo object. You can |
as possible. `member' may be a filename or a ZipInfo object. You can |
1470 |
1474 |
specify a different directory using `path'. |
specify a different directory using `path'. |
1471 |
1475 |
""" |
""" |
1472 |
|
if not isinstance(member, ZipInfo): |
|
1473 |
|
member = self.getinfo(member) |
|
1474 |
|
|
|
1475 |
1476 |
if path is None: |
if path is None: |
1476 |
1477 |
path = os.getcwd() |
path = os.getcwd() |
|
1478 |
|
else: |
|
1479 |
|
path = os.fspath(path) |
1477 |
1480 |
|
|
1478 |
1481 |
return self._extract_member(member, path, pwd) |
return self._extract_member(member, path, pwd) |
1479 |
1482 |
|
|
|
... |
... |
class ZipFile: |
1486 |
1489 |
if members is None: |
if members is None: |
1487 |
1490 |
members = self.namelist() |
members = self.namelist() |
1488 |
1491 |
|
|
|
1492 |
|
if path is None: |
|
1493 |
|
path = os.getcwd() |
|
1494 |
|
else: |
|
1495 |
|
path = os.fspath(path) |
|
1496 |
|
|
1489 |
1497 |
for zipinfo in members: |
for zipinfo in members: |
1490 |
|
self.extract(zipinfo, path, pwd) |
|
|
1498 |
|
self._extract_member(zipinfo, path, pwd) |
1491 |
1499 |
|
|
1492 |
1500 |
@classmethod |
@classmethod |
1493 |
1501 |
def _sanitize_windows_name(cls, arcname, pathsep): |
def _sanitize_windows_name(cls, arcname, pathsep): |
|
... |
... |
class ZipFile: |
1508 |
1516 |
"""Extract the ZipInfo object 'member' to a physical |
"""Extract the ZipInfo object 'member' to a physical |
1509 |
1517 |
file on the path targetpath. |
file on the path targetpath. |
1510 |
1518 |
""" |
""" |
|
1519 |
|
if not isinstance(member, ZipInfo): |
|
1520 |
|
member = self.getinfo(member) |
|
1521 |
|
|
1511 |
1522 |
# build the destination pathname, replacing |
# build the destination pathname, replacing |
1512 |
1523 |
# forward slashes to platform specific separators. |
# forward slashes to platform specific separators. |
1513 |
1524 |
arcname = member.filename.replace('/', os.path.sep) |
arcname = member.filename.replace('/', os.path.sep) |
|
... |
... |
class PyZipFile(ZipFile): |
1800 |
1811 |
If filterfunc(pathname) is given, it is called with every argument. |
If filterfunc(pathname) is given, it is called with every argument. |
1801 |
1812 |
When it is False, the file or directory is skipped. |
When it is False, the file or directory is skipped. |
1802 |
1813 |
""" |
""" |
|
1814 |
|
pathname = os.fspath(pathname) |
1803 |
1815 |
if filterfunc and not filterfunc(pathname): |
if filterfunc and not filterfunc(pathname): |
1804 |
1816 |
if self.debug: |
if self.debug: |
1805 |
1817 |
label = 'path' if os.path.isdir(pathname) else 'file' |
label = 'path' if os.path.isdir(pathname) else 'file' |