Skip to content

Commit be38279

Browse files
authored
Merge pull request python#9 from brettcannon/implement-read
Implement read()
2 parents 61c76ef + 53747f5 commit be38279

File tree

5 files changed

+90
-4
lines changed

5 files changed

+90
-4
lines changed

importlib_resources/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,21 @@ def open(package: Package, file_name: Path) -> BinaryIO:
5454
loader = typing.cast(importlib.abc.ResourceLoader, package.__spec__.loader)
5555
data = loader.get_data(full_path)
5656
return io.BytesIO(data)
57+
58+
59+
def read(package: Package, file_name: Path, encoding: str = 'utf-8',
60+
errors: str = 'strict') -> str:
61+
"""Return the decoded string of the resource.
62+
63+
The decoding-related arguments have the same semantics as those of
64+
bytes.decode().
65+
"""
66+
file_name = _normalize_path(file_name)
67+
package = _get_package(package)
68+
# Note this is **not** builtins.open()!
69+
with open(package, file_name) as binary_file:
70+
# Decoding from io.TextIOWrapper() instead of str.decode() in hopes that
71+
# the former will be smarter about memory usage.
72+
text_file = io.TextIOWrapper(binary_file, encoding=encoding,
73+
errors=errors)
74+
return text_file.read()
44 Bytes
Binary file not shown.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Hello, world!
1+
Hello, UTF-8 world!

importlib_resources/tests/test_open.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_pathlib_path(self):
3535

3636
def test_absolute_path(self):
3737
# An absolute path is a ValueError.
38-
path = pathlib.Path(__spec__.origin)
38+
path = pathlib.Path(__file__)
3939
full_path = path.parent/'utf-8.file'
4040
with self.assertRaises(ValueError):
4141
with resources.open(data, str(full_path)) as file:
@@ -65,13 +65,13 @@ class OpenTests(unittest.TestCase):
6565
def test_opened_for_reading(self):
6666
# The file-like object is ready for reading.
6767
with resources.open(data, 'utf-8.file') as file:
68-
self.assertEqual(b"Hello, world!\n", file.read())
68+
self.assertEqual(b"Hello, UTF-8 world!\n", file.read())
6969

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

7676

7777
if __name__ == '__main__':
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import io
2+
import os.path
3+
import pathlib
4+
import sys
5+
import unittest
6+
7+
import importlib_resources as resources
8+
from importlib_resources.tests import data
9+
10+
11+
class CommonTests(unittest.TestCase):
12+
13+
def test_package_name(self):
14+
# Passing in the package name should succeed.
15+
resources.read(data.__name__, 'utf-8.file')
16+
17+
def test_package_object(self):
18+
# Passing in the package itself should succeed.
19+
resources.read(data, 'utf-8.file')
20+
21+
def test_string_path(self):
22+
path = 'utf-8.file'
23+
# Passing in a string for the path should succeed.
24+
resources.read(data, path)
25+
26+
@unittest.skipIf(sys.version_info < (3, 6), 'requires os.PathLike support')
27+
def test_pathlib_path(self):
28+
# Passing in a pathlib.PurePath object for the path should succeed.
29+
path = pathlib.PurePath('utf-8.file')
30+
resources.read(data, path)
31+
32+
def test_absolute_path(self):
33+
# An absolute path is a ValueError.
34+
path = pathlib.Path(__file__)
35+
full_path = path.parent/'utf-8.file'
36+
with self.assertRaises(ValueError):
37+
resources.read(data, str(full_path))
38+
39+
def test_relative_path(self):
40+
# A reative path is a ValueError.
41+
with self.assertRaises(ValueError):
42+
resources.read(data, '../data/utf-8.file')
43+
44+
def test_importing_module_as_side_effect(self):
45+
# The anchor package can already be imported.
46+
del sys.modules[data.__name__]
47+
resources.read(data.__name__, 'utf-8.file')
48+
49+
def test_non_package(self):
50+
# The anchor package cannot be a module.
51+
with self.assertRaises(TypeError):
52+
resources.read(__spec__.name, 'utf-8.file')
53+
54+
55+
class ReadTests(unittest.TestCase):
56+
57+
def test_default_encoding(self):
58+
result = resources.read(data, 'utf-8.file')
59+
self.assertEqual("Hello, UTF-8 world!\n", result)
60+
61+
def test_encoding(self):
62+
result = resources.read(data, 'utf-16.file', encoding='utf-16')
63+
self.assertEqual("Hello, UTF-16 world!\n", result)
64+
65+
def test_errors(self):
66+
# Raises UnicodeError without the 'errors' argument.
67+
result = resources.read(data, 'utf-16.file', encoding='utf-8',
68+
errors='ignore')

0 commit comments

Comments
 (0)