diff --git a/importlib_resources/_py2.py b/importlib_resources/_py2.py index d1282af42178431..670ffc05781a3ff 100644 --- a/importlib_resources/_py2.py +++ b/importlib_resources/_py2.py @@ -73,7 +73,10 @@ def read(package, file_name, encoding='utf-8', errors='strict'): package = _get_package(package) # Note this is **not** builtins.open()! with open(package, file_name) as binary_file: - return binary_file.read().decode(encoding=encoding, errors=errors) + contents = binary_file.read() + if encoding is None: + return contents + return contents.decode(encoding=encoding, errors=errors) @contextmanager diff --git a/importlib_resources/_py3.py b/importlib_resources/_py3.py index 3b5044c9b06c6d6..6b5721c252ee8ed 100644 --- a/importlib_resources/_py3.py +++ b/importlib_resources/_py3.py @@ -77,8 +77,10 @@ def open(package: Package, file_name: FileName) -> BinaryIO: return BytesIO(data) -def read(package: Package, file_name: FileName, encoding: str = 'utf-8', - errors: str = 'strict') -> str: +def read(package: Package, + file_name: FileName, + encoding: str = 'utf-8', + errors: str = 'strict') -> Union[str, bytes]: """Return the decoded string of the resource. The decoding-related arguments have the same semantics as those of @@ -88,6 +90,8 @@ def read(package: Package, file_name: FileName, encoding: str = 'utf-8', package = _get_package(package) # Note this is **not** builtins.open()! with open(package, file_name) as binary_file: + if encoding is None: + return binary_file.read() # Decoding from io.TextIOWrapper() instead of str.decode() in hopes # that the former will be smarter about memory usage. text_file = TextIOWrapper( diff --git a/importlib_resources/tests/data/binary.file b/importlib_resources/tests/data/binary.file new file mode 100644 index 000000000000000..eaf36c1daccfdf3 Binary files /dev/null and b/importlib_resources/tests/data/binary.file differ diff --git a/importlib_resources/tests/data/ziptestdata.zip b/importlib_resources/tests/data/ziptestdata.zip index a6889a76f6a9f4d..49a89215d1f7e7c 100644 Binary files a/importlib_resources/tests/data/ziptestdata.zip and b/importlib_resources/tests/data/ziptestdata.zip differ diff --git a/importlib_resources/tests/test_read.py b/importlib_resources/tests/test_read.py index 7487c8bb0d2c262..98d770e8674bba0 100644 --- a/importlib_resources/tests/test_read.py +++ b/importlib_resources/tests/test_read.py @@ -15,17 +15,21 @@ class ReadTests: def test_default_encoding(self): result = resources.read(self.data, 'utf-8.file') - self.assertEqual("Hello, UTF-8 world!\n", result) + self.assertEqual('Hello, UTF-8 world!\n', result) def test_encoding(self): result = resources.read(self.data, 'utf-16.file', encoding='utf-16') - self.assertEqual("Hello, UTF-16 world!\n", result) + self.assertEqual('Hello, UTF-16 world!\n', result) def test_errors(self): # Raises UnicodeError without the 'errors' argument. resources.read( self.data, 'utf-16.file', encoding='utf-8', errors='ignore') + def test_no_encoding(self): + result = resources.read(self.data, 'binary.file', encoding=None) + self.assertEqual(b'\0\1\2\3', result) + class ReadDiskTests(ReadTests, unittest.TestCase): diff --git a/update-tests.py b/update-tests.py new file mode 100755 index 000000000000000..2fec92767e8ca4e --- /dev/null +++ b/update-tests.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +"""Remake the ziptestdata.zip file. + +Run this to rebuild the importlib_resources/tests/data/ziptestdata.zip file, +e.g. if you want to add a new file to the zip. + +This will replace the file with the new build, but it won't commit anything to +git. +""" + +import os +from zipfile import ZipFile + +RELPATH = 'importlib_resources/tests/data' +CONTENTS = [ + # filenames - the source will always be prepended by + # importlib_resources/tests/data/ziptestdata.zip and the destination will + # always be prepended by ziptestdata/ + '__init__.py', + 'binary.file', + 'utf-16.file', + 'utf-8.file', + ] + + +zip_file_path = os.path.join(RELPATH, 'ziptestdata.zip') + +with ZipFile(zip_file_path, 'w') as zf: + for filename in CONTENTS: + src = os.path.join(RELPATH, filename) + dst = os.path.join('ziptestdata', filename) + zf.write(src, dst)