Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create lazy loading lookup class to support pickling #82

Merged
merged 12 commits into from Oct 8, 2022
7 changes: 7 additions & 0 deletions CHANGES.rst
@@ -1,3 +1,10 @@
v3.9.0
======

* #81: ``Path`` objects are now pickleable if they've been
constructed from pickleable objects. Any restored objects
will re-construct the zip file with the original arguments.

v3.8.1
======

Expand Down
32 changes: 25 additions & 7 deletions test_zipp.py
Expand Up @@ -6,6 +6,8 @@
import tempfile
import shutil
import string
import pickle
import itertools

import jaraco.itertools
import func_timeout
Expand Down Expand Up @@ -74,13 +76,12 @@ def temp_dir():
shutil.rmtree(tmpdir)


pass_alpharep = parameterize(
['alpharep'],
[
Invoked.wrap(build_alpharep_fixture),
Invoked.wrap(compose(add_dirs, build_alpharep_fixture)),
],
)
alpharep_generators = [
Invoked.wrap(build_alpharep_fixture),
Invoked.wrap(compose(add_dirs, build_alpharep_fixture)),
]

pass_alpharep = parameterize(['alpharep'], alpharep_generators)


class TestPath(unittest.TestCase):
Expand Down Expand Up @@ -407,3 +408,20 @@ def test_inheritance(self, alpharep):
cls = type('PathChild', (zipp.Path,), {})
file = cls(alpharep).joinpath('some dir').parent
assert isinstance(file, cls)

@parameterize(
['alpharep', 'path_type', 'subpath'],
itertools.product(
alpharep_generators,
[str, pathlib.Path],
['', 'b/'],
),
)
def test_pickle(self, alpharep, path_type, subpath):
print(alpharep, path_type, subpath)
zipfile_ondisk = path_type(self.zipfile_ondisk(alpharep))

saved_1 = pickle.dumps(zipp.Path(zipfile_ondisk, at=subpath))
restored_1 = pickle.loads(saved_1)
first, *rest = restored_1.iterdir()
assert first.read_text().startswith('content of ')
20 changes: 19 additions & 1 deletion zipp.py
Expand Up @@ -62,7 +62,25 @@ def _difference(minuend, subtrahend):
return itertools.filterfalse(set(subtrahend).__contains__, minuend)


class CompleteDirs(zipfile.ZipFile):
class InitializedState:
"""
Mix-in to save the initialization state for pickling.
"""

def __init__(self, *args, **kwargs):
self.__args = args
self.__kwargs = kwargs
super().__init__(*args, **kwargs)

def __getstate__(self):
return self.__args, self.__kwargs

def __setstate__(self, state):
args, kwargs = state
super().__init__(*args, **kwargs)


class CompleteDirs(InitializedState, zipfile.ZipFile):
"""
A ZipFile subclass that ensures that implied directories
are always included in the namelist.
Expand Down