Skip to content

Commit

Permalink
Support zip files for open()
Browse files Browse the repository at this point in the history
  • Loading branch information
brettcannon committed Oct 27, 2017
1 parent d99bcd0 commit a9bafd0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 9 deletions.
14 changes: 8 additions & 6 deletions importlib_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,18 @@ def open(package: Package, file_name: FileName) -> BinaryIO:
package = _get_package(package)
package_path = os.path.dirname(os.path.abspath(package.__spec__.origin))
full_path = os.path.join(package_path, file_name)
if not os.path.exists(full_path):
package_name = package.__spec__.name
message = "{!r} does not exist"
raise FileNotFoundError(message.format(full_path))
# Just assume the loader is a resource loader; all the relevant
# importlib.machinery loaders are and an AttributeError for get_data() will
# make it clear what is needed from the loader.
loader = typing.cast(importlib.abc.ResourceLoader, package.__spec__.loader)
data = loader.get_data(full_path)
return io.BytesIO(data)
try:
data = loader.get_data(full_path)
except OSError:
package_name = package.__spec__.name
message = f'{file_name!r} resource not found in {package_name!r}'
raise FileNotFoundError(message)
else:
return io.BytesIO(data)


def read(package: Package, file_name: FileName, encoding: str = 'utf-8',
Expand Down
Binary file added importlib_resources/tests/data/ziptestdata.zip
Binary file not shown.
46 changes: 43 additions & 3 deletions importlib_resources/tests/test_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@
from importlib_resources.tests import data


ZIP_DATA_PATH = None # type: Optional[pathlib.Path]
zip_data = None # type: Optional[]
def setUpModule():
global ZIP_DATA_PATH, zip_data
data_path = pathlib.Path(data.__spec__.origin)
data_dir = data_path.parent
ZIP_DATA_PATH = data_dir / 'ziptestdata.zip'
sys.path.append(str(ZIP_DATA_PATH))
import ziptestdata
zip_data = ziptestdata


def tearDownModule():
global zip_data
del zip_data
try:
sys.path.remove(str(ZIP_DATA_PATH))
except ValueError:
pass


class CommonTests(unittest.TestCase):

def test_package_name(self):
Expand Down Expand Up @@ -60,19 +81,38 @@ def test_non_package(self):
pass


class OpenTests(unittest.TestCase):
class OpenTests:

# Subclasses are expected to set the 'data' attribute.

def test_opened_for_reading(self):
# The file-like object is ready for reading.
with resources.open(data, 'utf-8.file') as file:
with resources.open(self.data, 'utf-8.file') as file:
self.assertEqual(b"Hello, UTF-8 world!\n", file.read())

def test_wrap_for_text(self):
# The file-like object can be wrapped for text reading.
with resources.open(data, 'utf-8.file') as file:
with resources.open(self.data, 'utf-8.file') as file:
text_file = io.TextIOWrapper(file, encoding='utf-8')
self.assertEqual('Hello, UTF-8 world!\n', text_file.read())

def test_FileNotFoundError(self):
with self.assertRaises(FileNotFoundError):
with resources.open(self.data, 'does-not-exist') as file:
pass


class OpenDiskTests(OpenTests, unittest.TestCase):

def setUp(self):
self.data = data


class OpenZipTests(OpenTests, unittest.TestCase):

def setUp(self):
self.data = zip_data


if __name__ == '__main__':
unittest.main()

0 comments on commit a9bafd0

Please sign in to comment.