Skip to content

Commit

Permalink
Merge pull request #288 from python/debt/zip-fixtures
Browse files Browse the repository at this point in the history
Convert static zip fixtures to proper fixtures derived from disk-based fixtures.
  • Loading branch information
jaraco authored Sep 19, 2023
2 parents e540919 + d3a7f69 commit 0f89eb3
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 158 deletions.
6 changes: 2 additions & 4 deletions importlib_resources/tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,13 @@ class ReadDiskTests(ReadTests, unittest.TestCase):

class ReadZipTests(ReadTests, util.ZipSetup, unittest.TestCase):
def test_read_submodule_resource(self):
submodule = import_module('ziptestdata.subdirectory')
submodule = import_module('data01.subdirectory')
result = resources.files(submodule).joinpath('binary.file').read_bytes()
self.assertEqual(result, b'\0\1\2\3')

def test_read_submodule_resource_by_name(self):
result = (
resources.files('ziptestdata.subdirectory')
.joinpath('binary.file')
.read_bytes()
resources.files('data01.subdirectory').joinpath('binary.file').read_bytes()
)
self.assertEqual(result, b'\0\1\2\3')

Expand Down
101 changes: 31 additions & 70 deletions importlib_resources/tests/test_resource.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import contextlib
import sys
import unittest
import importlib_resources as resources
import uuid
import pathlib

from . import data01
from . import zipdata01, zipdata02
from . import util
from importlib import import_module
from ._compat import import_helper, os_helper, unlink


class ResourceTests:
Expand Down Expand Up @@ -89,136 +85,89 @@ def test_package_has_no_reader_fallback(self):


class ResourceFromZipsTest01(util.ZipSetupBase, unittest.TestCase):
ZIP_MODULE = zipdata01 # type: ignore
ZIP_MODULE = 'data01'

def test_is_submodule_resource(self):
submodule = import_module('ziptestdata.subdirectory')
submodule = import_module('data01.subdirectory')
self.assertTrue(resources.files(submodule).joinpath('binary.file').is_file())

def test_read_submodule_resource_by_name(self):
self.assertTrue(
resources.files('ziptestdata.subdirectory')
.joinpath('binary.file')
.is_file()
resources.files('data01.subdirectory').joinpath('binary.file').is_file()
)

def test_submodule_contents(self):
submodule = import_module('ziptestdata.subdirectory')
submodule = import_module('data01.subdirectory')
self.assertEqual(
names(resources.files(submodule)), {'__init__.py', 'binary.file'}
)

def test_submodule_contents_by_name(self):
self.assertEqual(
names(resources.files('ziptestdata.subdirectory')),
names(resources.files('data01.subdirectory')),
{'__init__.py', 'binary.file'},
)

def test_as_file_directory(self):
with resources.as_file(resources.files('ziptestdata')) as data:
assert data.name == 'ziptestdata'
with resources.as_file(resources.files('data01')) as data:
assert data.name == 'data01'
assert data.is_dir()
assert data.joinpath('subdirectory').is_dir()
assert len(list(data.iterdir()))
assert not data.parent.exists()


class ResourceFromZipsTest02(util.ZipSetupBase, unittest.TestCase):
ZIP_MODULE = zipdata02 # type: ignore
ZIP_MODULE = 'data02'

def test_unrelated_contents(self):
"""
Test thata zip with two unrelated subpackages return
distinct resources. Ref python/importlib_resources#44.
"""
self.assertEqual(
names(resources.files('ziptestdata.one')),
names(resources.files('data02.one')),
{'__init__.py', 'resource1.txt'},
)
self.assertEqual(
names(resources.files('ziptestdata.two')),
names(resources.files('data02.two')),
{'__init__.py', 'resource2.txt'},
)


@contextlib.contextmanager
def zip_on_path(dir):
data_path = pathlib.Path(zipdata01.__file__)
source_zip_path = data_path.parent.joinpath('ziptestdata.zip')
zip_path = pathlib.Path(dir) / f'{uuid.uuid4()}.zip'
zip_path.write_bytes(source_zip_path.read_bytes())
sys.path.append(str(zip_path))
import_module('ziptestdata')

try:
yield
finally:
with contextlib.suppress(ValueError):
sys.path.remove(str(zip_path))

with contextlib.suppress(KeyError):
del sys.path_importer_cache[str(zip_path)]
del sys.modules['ziptestdata']

with contextlib.suppress(OSError):
unlink(zip_path)


class DeletingZipsTest(unittest.TestCase):
class DeletingZipsTest(util.ZipSetupBase, unittest.TestCase):
"""Having accessed resources in a zip file should not keep an open
reference to the zip.
"""

def setUp(self):
self.fixtures = contextlib.ExitStack()
self.addCleanup(self.fixtures.close)

modules = import_helper.modules_setup()
self.addCleanup(import_helper.modules_cleanup, *modules)

temp_dir = self.fixtures.enter_context(os_helper.temp_dir())
self.fixtures.enter_context(zip_on_path(temp_dir))

def test_iterdir_does_not_keep_open(self):
[item.name for item in resources.files('ziptestdata').iterdir()]
[item.name for item in resources.files('data01').iterdir()]

def test_is_file_does_not_keep_open(self):
resources.files('ziptestdata').joinpath('binary.file').is_file()
resources.files('data01').joinpath('binary.file').is_file()

def test_is_file_failure_does_not_keep_open(self):
resources.files('ziptestdata').joinpath('not-present').is_file()
resources.files('data01').joinpath('not-present').is_file()

@unittest.skip("Desired but not supported.")
def test_as_file_does_not_keep_open(self): # pragma: no cover
resources.as_file(resources.files('ziptestdata') / 'binary.file')
resources.as_file(resources.files('data01') / 'binary.file')

def test_entered_path_does_not_keep_open(self):
"""
Mimic what certifi does on import to make its bundle
available for the process duration.
"""
resources.as_file(resources.files('ziptestdata') / 'binary.file').__enter__()
resources.as_file(resources.files('data01') / 'binary.file').__enter__()

def test_read_binary_does_not_keep_open(self):
resources.files('ziptestdata').joinpath('binary.file').read_bytes()
resources.files('data01').joinpath('binary.file').read_bytes()

def test_read_text_does_not_keep_open(self):
resources.files('ziptestdata').joinpath('utf-8.file').read_text(
encoding='utf-8'
)

resources.files('data01').joinpath('utf-8.file').read_text(encoding='utf-8')

class ResourceFromNamespaceTest01(unittest.TestCase):
site_dir = str(pathlib.Path(__file__).parent)

@classmethod
def setUpClass(cls):
sys.path.append(cls.site_dir)

@classmethod
def tearDownClass(cls):
sys.path.remove(cls.site_dir)

class ResourceFromNamespaceTests:
def test_is_submodule_resource(self):
self.assertTrue(
resources.files(import_module('namespacedata01'))
Expand Down Expand Up @@ -248,5 +197,17 @@ def test_submodule_contents_by_name(self):
self.assertEqual(contents, {'binary.file', 'utf-8.file', 'utf-16.file'})


class ResourceFromNamespaceDiskTests(ResourceFromNamespaceTests, unittest.TestCase):
site_dir = str(pathlib.Path(__file__).parent)

@classmethod
def setUpClass(cls):
sys.path.append(cls.site_dir)

@classmethod
def tearDownClass(cls):
sys.path.remove(cls.site_dir)


if __name__ == '__main__':
unittest.main()
53 changes: 0 additions & 53 deletions importlib_resources/tests/update-zips.py

This file was deleted.

48 changes: 17 additions & 31 deletions importlib_resources/tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import sys
import types
import pathlib
import contextlib

from . import data01
from . import zipdata01
from ..abc import ResourceReader
from ._compat import import_helper
from ._compat import import_helper, os_helper
from . import zip as zip_


from importlib.machinery import ModuleSpec
Expand Down Expand Up @@ -141,39 +142,24 @@ def test_useless_loader(self):


class ZipSetupBase:
ZIP_MODULE = None

@classmethod
def setUpClass(cls):
data_path = pathlib.Path(cls.ZIP_MODULE.__file__)
data_dir = data_path.parent
cls._zip_path = str(data_dir / 'ziptestdata.zip')
sys.path.append(cls._zip_path)
cls.data = importlib.import_module('ziptestdata')

@classmethod
def tearDownClass(cls):
try:
sys.path.remove(cls._zip_path)
except ValueError:
pass

try:
del sys.path_importer_cache[cls._zip_path]
del sys.modules[cls.data.__name__]
except KeyError:
pass

try:
del cls.data
del cls._zip_path
except AttributeError:
pass
ZIP_MODULE = 'data01'

def setUp(self):
self.fixtures = contextlib.ExitStack()
self.addCleanup(self.fixtures.close)

modules = import_helper.modules_setup()
self.addCleanup(import_helper.modules_cleanup, *modules)

temp_dir = self.fixtures.enter_context(os_helper.temp_dir())
modules = pathlib.Path(temp_dir) / 'zipped modules.zip'
src_path = pathlib.Path(__file__).parent.joinpath(self.ZIP_MODULE)
self.fixtures.enter_context(
import_helper.DirsOnSysPath(str(zip_.make_zip_file(src_path, modules)))
)

self.data = importlib.import_module(self.ZIP_MODULE)


class ZipSetup(ZipSetupBase):
ZIP_MODULE = zipdata01 # type: ignore
pass
32 changes: 32 additions & 0 deletions importlib_resources/tests/zip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Generate zip test data files.
"""

import contextlib
import os
import pathlib
import zipfile

import zipp


def make_zip_file(src, dst):
"""
Zip the files in src into a new zipfile at dst.
"""
with zipfile.ZipFile(dst, 'w') as zf:
for src_path, rel in walk(src):
dst_name = src.name / pathlib.PurePosixPath(rel.as_posix())
zf.write(src_path, dst_name)
zipp.CompleteDirs.inject(zf)
return dst


def walk(datapath):
for dirpath, dirnames, filenames in os.walk(datapath):
with contextlib.suppress(ValueError):
dirnames.remove('__pycache__')
for filename in filenames:
res = pathlib.Path(dirpath) / filename
rel = res.relative_to(datapath)
yield res, rel
Empty file.
Binary file removed importlib_resources/tests/zipdata01/ziptestdata.zip
Binary file not shown.
Empty file.
Binary file removed importlib_resources/tests/zipdata02/ziptestdata.zip
Binary file not shown.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ testing =
pytest-ruff

# local
zipp >= 3.17

docs =
# upstream
Expand Down

0 comments on commit 0f89eb3

Please sign in to comment.