Skip to content

Commit 9fcb692

Browse files
committed
Add PathFinder to help with locating files
1 parent 3b26710 commit 9fcb692

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

src/mads/lib/path.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,55 @@ def current_repo() -> str:
2424
return repo.parent.name
2525
else:
2626
return Path.cwd().name
27+
28+
29+
class PathFinder:
30+
"""A class to search across multiple paths
31+
32+
Given either an environment variable name, or a list of paths, provide access
33+
methods to search for files across all of them."""
34+
35+
__slots__ = ("paths",)
36+
37+
paths: list[Path]
38+
39+
def __init__(self, paths: str | list[str] | list[Path]):
40+
if isinstance(paths, str):
41+
import os
42+
43+
paths = os.environ.get(paths.replace("$", ""), ".").split(":")
44+
45+
self.paths = [Path(p) for p in paths]
46+
47+
def __repr__(self) -> str:
48+
return f"PathFinder({self.paths})"
49+
50+
def __rich_repr__(self):
51+
for path in self.paths:
52+
yield str(path)
53+
54+
def find(self, name: str) -> Path:
55+
"""Find a file within the paths, or raise an error if it's not found"""
56+
57+
if path := self.get(name):
58+
return path
59+
60+
raise FileNotFoundError(
61+
f"Could not find '{name}'. Searched within the following paths:\n"
62+
+ "\n".join([" - " + str(p) for p in self.paths])
63+
)
64+
65+
def get(self, name: str) -> Path | None:
66+
"""Find a file within the paths, or return None if it's not found"""
67+
68+
for path in self.paths:
69+
path = path.joinpath(name)
70+
if path.exists():
71+
return path
72+
73+
return None
74+
75+
def __truediv__(self, other: str) -> Path:
76+
"""Find files as if the finder was a Path: finder / 'file.txt'"""
77+
78+
return self.find(other)

0 commit comments

Comments
 (0)