1111from referencing import Resource , Specification
1212
1313if TYPE_CHECKING :
14+ from importlib .resources .abc import Traversable
15+
1416 from referencing .typing import URI
1517
1618
@@ -22,21 +24,55 @@ def from_path(root: Path) -> Iterable[tuple[URI, Resource[Any]]]:
2224 the root) -- though it still is often a good idea to explicitly indicate
2325 what specification every resource is written for internally.
2426 """
25- specification : Specification [Any ] | None = None
26- for dir , _ , files in _walk (root ):
27- for file in files :
28- path = dir / file
29- contents = json .loads (path .read_text ())
30- if specification is None :
31- specification = Specification .detect (contents ) # type: ignore[reportUnknownMemberType]
32- resource = specification .detect (contents ).create_resource (contents )
33- yield path .as_uri (), resource
27+ return _from_walked (_walk (root ))
3428
3529
36- def _walk (path : Path ) -> Iterable [tuple [ Path , Iterable [ str ], Iterable [ str ]] ]:
30+ def _walk (path : Path ) -> Iterable [Path ]:
3731 walk = getattr (path , "walk" , None )
38- if walk is not None :
39- yield from walk ()
40- return
41- for root , dirs , files in os .walk (path ): # pragma: no cover
42- yield Path (root ), dirs , files
32+ if walk is None :
33+ for dir , _ , files in os .walk (path ): # pragma: no cover
34+ for file in files :
35+ yield Path (dir ) / file
36+ else :
37+ for dir , _ , files in walk ():
38+ for file in files :
39+ yield dir / file
40+
41+
42+ def _walk_traversable (root : Traversable ) -> Iterable [Traversable ]:
43+ """
44+ .walk() for importlib resources paths, which don't have the method :/
45+ """ # noqa: D415
46+ walking = [root ]
47+ while walking :
48+ path = walking .pop ()
49+ for each in path .iterdir ():
50+ if each .is_dir ():
51+ walking .append (each )
52+ else :
53+ yield each
54+
55+
56+ def from_traversable (root : Traversable ) -> Iterable [tuple [URI , Resource [Any ]]]:
57+ """
58+ Load some resources from a given `importlib.resources` traversable.
59+
60+ (I.e. load schemas from data within a Python package.)
61+ """
62+ return _from_walked (
63+ each
64+ for each in _walk_traversable (root )
65+ if not each .name .endswith (".py" )
66+ )
67+
68+
69+ def _from_walked (
70+ paths : Iterable [Path | Traversable ],
71+ ) -> Iterable [tuple [URI , Resource [Any ]]]:
72+ specification : Specification [Any ] | None = None
73+ for path in paths :
74+ contents = json .loads (path .read_text ())
75+ if specification is None :
76+ specification = Specification .detect (contents ) # type: ignore[reportUnknownMemberType]
77+ resource = specification .detect (contents ).create_resource (contents )
78+ yield getattr (path , "as_uri" , lambda : "" )(), resource
0 commit comments