mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-13 18:46:37 +00:00
fix(fonts): resolve relative asset paths from the install root, not the cwd
resolve_asset_path checked os.path.exists(relative_path) unconditionally, so a relative asset path was still resolved against the process cwd first -- exactly the dependency this module exists to remove. An unrelated working directory that happens to contain assets/fonts/4x6-font.ttf (a stale checkout, a copied assets folder, another project) would shadow the real bundled font instead of the install root ever being consulted. Only an absolute path is now returned as-is; a relative path always resolves against _INSTALL_ROOT first, matching the docstring's stated contract. FontManager._resolve_asset_path delegates to this function, so it's covered by the same fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -77,7 +77,7 @@ def resolve_asset_path(relative_path: str) -> str:
|
|||||||
file written without ``WorkingDirectory``) silently loses every font and
|
file written without ``WorkingDirectory``) silently loses every font and
|
||||||
degrades to PIL's default face.
|
degrades to PIL's default face.
|
||||||
"""
|
"""
|
||||||
if os.path.exists(relative_path):
|
if os.path.isabs(relative_path) and os.path.exists(relative_path):
|
||||||
return relative_path
|
return relative_path
|
||||||
candidate = _INSTALL_ROOT / relative_path
|
candidate = _INSTALL_ROOT / relative_path
|
||||||
if candidate.exists():
|
if candidate.exists():
|
||||||
|
|||||||
@@ -98,6 +98,30 @@ class TestAssetPathsIgnoreTheWorkingDirectory:
|
|||||||
)
|
)
|
||||||
assert out.stdout.strip() == "True", out.stderr
|
assert out.stdout.strip() == "True", out.stderr
|
||||||
|
|
||||||
|
def test_a_same_named_file_in_the_cwd_does_not_shadow_the_bundled_asset(
|
||||||
|
self, tmp_path,
|
||||||
|
):
|
||||||
|
# A relative path is a repo-relative asset name, not a cwd-relative
|
||||||
|
# one: an unrelated decoy that happens to sit at the same relative
|
||||||
|
# path in whatever directory the process was started from must not
|
||||||
|
# be preferred over the real bundled font.
|
||||||
|
decoy_dir = tmp_path / "assets" / "fonts"
|
||||||
|
decoy_dir.mkdir(parents=True)
|
||||||
|
decoy = decoy_dir / FOUR_BY_SIX
|
||||||
|
decoy.write_bytes(b"not a real font")
|
||||||
|
code = (
|
||||||
|
"from src.common.font_layout import resolve_asset_path;"
|
||||||
|
"print(resolve_asset_path('assets/fonts/4x6-font.ttf'))"
|
||||||
|
)
|
||||||
|
env = dict(os.environ, PYTHONPATH=str(PROJECT_ROOT))
|
||||||
|
out = subprocess.run( # nosec B603 - fixed argv, no shell
|
||||||
|
[sys.executable, "-c", code],
|
||||||
|
cwd=tmp_path, env=env, capture_output=True, text=True, timeout=120,
|
||||||
|
)
|
||||||
|
resolved = out.stdout.strip()
|
||||||
|
assert resolved != str(decoy), out.stderr
|
||||||
|
assert resolved == str(PROJECT_ROOT / "assets" / "fonts" / FOUR_BY_SIX)
|
||||||
|
|
||||||
def test_an_absolute_path_is_returned_untouched(self):
|
def test_an_absolute_path_is_returned_untouched(self):
|
||||||
absolute = str(PROJECT_ROOT / "assets" / "fonts" / FOUR_BY_SIX)
|
absolute = str(PROJECT_ROOT / "assets" / "fonts" / FOUR_BY_SIX)
|
||||||
assert resolve_asset_path(absolute) == absolute
|
assert resolve_asset_path(absolute) == absolute
|
||||||
|
|||||||
Reference in New Issue
Block a user