Skip to content

Commit 3f4c57d

Browse files
committed
Merge branch 'feature/traversable-protocol' into 'master'
Convert Traversable from abstract base class to a runtime-checkable protocol See merge request python-devs/importlib_resources!97
2 parents f11d299 + 2682b94 commit 3f4c57d

File tree

4 files changed

+29
-2
lines changed

4 files changed

+29
-2
lines changed

docs/changelog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
v1.5.0
66
======
7+
8+
* Traversable is now a Protocol instead of an Abstract Base
9+
Class (Python 2.7 and Python 3.8+).
10+
711
* Traversable objects now require a ``.name`` property.
812

913
v1.4.0

importlib_resources/_compat.py

+13
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ class ABC(object): # type: ignore
4747
from zipp import Path as ZipPath # type: ignore
4848

4949

50+
try:
51+
from typing import runtime_checkable # type: ignore
52+
except ImportError:
53+
def runtime_checkable(cls): # type: ignore
54+
return cls
55+
56+
57+
try:
58+
from typing import Protocol # type: ignore
59+
except ImportError:
60+
Protocol = ABC # type: ignore
61+
62+
5063
class PackageSpec(object):
5164
def __init__(self, **kwargs):
5265
vars(self).update(kwargs)

importlib_resources/abc.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import abc
44

5-
from ._compat import ABC, FileNotFoundError
5+
from ._compat import ABC, FileNotFoundError, runtime_checkable, Protocol
66

77
# Use mypy's comment syntax for Python 2 compatibility
88
try:
@@ -57,7 +57,8 @@ def contents(self):
5757
raise FileNotFoundError
5858

5959

60-
class Traversable(ABC):
60+
@runtime_checkable
61+
class Traversable(Protocol):
6162
"""
6263
An object with a subset of pathlib.Path methods suitable for
6364
traversing directories and opening files.

importlib_resources/tests/test_files.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import typing
12
import unittest
23

34
import importlib_resources as resources
5+
from importlib_resources.abc import Traversable
46
from . import data01
57
from . import util
68

@@ -16,6 +18,13 @@ def test_read_text(self):
1618
actual = files.joinpath('utf-8.file').read_text()
1719
assert actual == 'Hello, UTF-8 world!\n'
1820

21+
@unittest.skipUnless(
22+
hasattr(typing, 'runtime_checkable'),
23+
"Only suitable when typing supports runtime_checkable",
24+
)
25+
def test_traversable(self):
26+
assert isinstance(resources.files(self.data), Traversable)
27+
1928

2029
class OpenDiskTests(FilesTests, unittest.TestCase):
2130
def setUp(self):

0 commit comments

Comments
 (0)