Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Fixes
not exist, as ``rm_file`` and the other filesystems do, so deleting a missing
key from a memory-backed mapper raises ``KeyError``

- Create missing ZIP archives in append mode without truncating existing archives

- Allow filesystem implementations to assign ``protocol`` per instance

- Avoid mutating live ``BlockCache`` and ``BackgroundBlockCache`` instances
Expand Down
19 changes: 19 additions & 0 deletions fsspec/implementations/tests/test_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ def test_zip_glob_star(m):
assert len(outfiles) == 1


@pytest.mark.parametrize("backend", ["memory", "local"])
def test_append_creates_archive(m, tmp_path, backend):
path = "memory://new.zip" if backend == "memory" else tmp_path / "new.zip"
for name, content in [("first", b"original"), ("second", b"appended")]:
fs = ZipFileSystem(fo=path, mode="a")
try:
fs.pipe_file(name, content)
finally:
fs.close()

fs = ZipFileSystem(fo=path)
try:
assert fs.cat("first") == b"original"
assert fs.cat("second") == b"appended"
assert fs.find("") == ["first", "second"]
finally:
fs.close()


def test_append(m, tmpdir):
fs = fsspec.filesystem("zip", fo="memory://out.zip", mode="w")
with fs.open("afile", "wb") as f:
Expand Down
11 changes: 9 additions & 2 deletions fsspec/implementations/zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def __init__(
Parameters
----------
fo: str or file-like
Contains ZIP, and must exist. If a str, will fetch file using
Contains ZIP. In append mode, a missing archive is created.
If a str, will fetch file using
:meth:`~fsspec.open_files`, which must return one file exactly.
mode: str
Accept: "r", "w", "a"
Expand All @@ -59,7 +60,13 @@ def __init__(
)
self.force_zip_64 = allowZip64
self.of = fo
self.fo = fo.__enter__() # the whole instance is a context
try:
self.fo = fo.__enter__() # the whole instance is a context
except FileNotFoundError:
if mode != "a" or not isinstance(fo, fsspec.core.OpenFile):
raise
fo.mode = "w+b"
self.fo = fo.__enter__()
self.zip = zipfile.ZipFile(
self.fo,
mode=mode,
Expand Down
Loading