Skip to content

Commit fda2e06

Browse files
committed
Add a parameter create to resolve() to create the directory/file if it doesn't exist.
1 parent 9c90129 commit fda2e06

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

arcade/resources/__init__.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,19 @@ def resolve_resource_path(path: str | Path) -> Path:
5050
return resolve(path)
5151

5252

53-
def resolve(path: str | Path) -> Path:
53+
def create_path(path: Path) -> None:
54+
"""
55+
Create a file or directory at the given path.
56+
If the path has a suffix, it's treated as a file, otherwise, as a directory.
57+
"""
58+
if path.suffix:
59+
path.parent.mkdir(parents=True, exist_ok=True)
60+
path.touch(exist_ok=True)
61+
else:
62+
path.mkdir(parents=True, exist_ok=True)
63+
64+
65+
def resolve(path: str | Path, *, create: bool = False) -> Path:
5466
"""
5567
Attempts to resolve a path to a resource including resource handles.
5668
@@ -67,6 +79,7 @@ def resolve(path: str | Path) -> Path:
6779
6880
Args:
6981
path: A Path or string
82+
create: If True, create the path if it doesn't exist.
7083
"""
7184
# Convert to a Path object and resolve resource handle
7285
if isinstance(path, str):
@@ -87,22 +100,30 @@ def resolve(path: str | Path) -> Path:
87100
# match. This allows for overriding of resources.
88101
paths = get_resource_handle_paths(handle)
89102
for handle_path in reversed(paths):
90-
path = handle_path / resource
91-
if path.exists():
103+
candidate_path = handle_path / resource
104+
if candidate_path.exists():
105+
path = candidate_path
92106
break
93107
else:
94-
searched_paths = "\n".join(f"-> {p}" for p in reversed(paths))
95-
raise FileNotFoundError(
96-
f"Cannot locate resource '{resource}' using handle "
97-
f"'{handle}' in any of the following paths:\n"
98-
f"{searched_paths}"
99-
)
108+
if create:
109+
path = paths[-1] / resource
110+
create_path(path)
111+
else:
112+
searched_paths = "\n".join(f"-> {p}" for p in reversed(paths))
113+
raise FileNotFoundError(
114+
f"Cannot locate resource '{resource}' using handle "
115+
f"'{handle}' in any of the following paths:\n"
116+
f"{searched_paths}"
117+
)
100118

101119
# Always convert into a Path object
102-
path = Path(handle_path / resource)
120+
path = Path(path)
103121
else:
104122
path = Path(path)
105123

124+
if create:
125+
create_path(path)
126+
106127
try:
107128
path = Path(path.resolve(strict=True))
108129
except AttributeError:

tests/unit/resources/test_handles.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,36 @@ def test_default_handles():
1818
resources.resolve(":system:images/cards/cardBack_blue1.png")
1919

2020

21+
def test_resolve_create(tmp_path):
22+
"""Test if we can create directories and files using the resolve."""
23+
# Test directory creation
24+
new_dir = tmp_path / "created_dir"
25+
assert not new_dir.exists()
26+
result_dir = resources.resolve(new_dir, create=True)
27+
assert result_dir == new_dir.resolve()
28+
assert new_dir.exists() and new_dir.is_dir()
29+
30+
# Test file creation
31+
new_file = tmp_path / "created_file.txt"
32+
assert not new_file.exists()
33+
result_file = resources.resolve(new_file, create=True)
34+
assert result_file == new_file.resolve()
35+
assert new_file.exists() and new_file.is_file()
36+
37+
38+
def test_default_handle_create():
39+
"""Test if we can create directories and files using the default handle."""
40+
handle_dir = ":resources:new_dir"
41+
with pytest.raises(FileNotFoundError):
42+
resources.resolve(handle_dir)
43+
result_dir = resources.resolve(handle_dir, create=True)
44+
assert result_dir.exists() and result_dir.is_dir()
45+
for base_path in resources.get_resource_handle_paths("resources"):
46+
dir_path = base_path / "new_dir"
47+
if dir_path.exists() and dir_path.is_dir():
48+
dir_path.rmdir()
49+
50+
2151
def test_add_handles(monkeypatch):
2252
monkeypatch.setattr(resources, "handles", {})
2353

0 commit comments

Comments
 (0)