From 21b2a2d86efa4d05cad05a6f0014e11ea31ee8a2 Mon Sep 17 00:00:00 2001 From: Sean Doherty Date: Sat, 16 May 2026 20:32:38 -0500 Subject: [PATCH] Limit generated filename prefixes --- src/py/kaleido/_utils/path_tools.py | 5 ++++- src/py/tests/test_path_tools.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/py/kaleido/_utils/path_tools.py b/src/py/kaleido/_utils/path_tools.py index 062e9392..54d4de7d 100644 --- a/src/py/kaleido/_utils/path_tools.py +++ b/src/py/kaleido/_utils/path_tools.py @@ -14,10 +14,13 @@ _logger = logistro.getLogger(__name__) +_MAX_GENERATED_FILENAME_PREFIX_LENGTH = 80 + def _next_filename(path: Path | str, prefix: str, ext: str) -> str: """Figure out proper suffix for generated file name.""" path = path if isinstance(path, Path) else Path(path) + prefix = prefix[:_MAX_GENERATED_FILENAME_PREFIX_LENGTH] default = 1 if (path / f"{prefix}.{ext}").exists() else 0 re_number = re.compile( r"^" + re.escape(prefix) + r"\-(\d+)\." + re.escape(ext) + r"$", @@ -60,7 +63,7 @@ def determine_path( prefix = re.sub(r"[ \-]", "_", prefix) prefix = re.sub(r"[^a-zA-Z0-9_]", "", prefix) prefix = prefix or "fig" - prefix = prefix[:80] # in case of long titles + prefix = prefix[:_MAX_GENERATED_FILENAME_PREFIX_LENGTH] _logger.debug(f"Found: {prefix}") name = _next_filename(directory, prefix, ext) full_path = directory / name diff --git a/src/py/tests/test_path_tools.py b/src/py/tests/test_path_tools.py index e3c9ad1c..7b1e99cd 100644 --- a/src/py/tests/test_path_tools.py +++ b/src/py/tests/test_path_tools.py @@ -69,6 +69,15 @@ def test_next_filename_only_numbered_files(tmp_path): assert result == "test-11.png" # Should be max + 1 +def test_next_filename_caps_long_prefix_before_filesystem_lookup(tmp_path): + """Test _next_filename avoids probing overlong generated filenames.""" + prefix = "a" * 500 + + result = path_tools._next_filename(tmp_path, prefix, "png") # noqa: SLF001 + + assert result == f"{'a' * 80}.png" + + # Fixtures for determine_path tests - testing various title scenarios @pytest.fixture( params=[ @@ -137,6 +146,16 @@ def test_determine_path_directory_with_suffix(tmp_path, fig_fixture): assert result.name == f"{expected_prefix}.ext" +def test_determine_path_caps_long_title_prefix(tmp_path): + """Test determine_path keeps generated filenames within path length limits.""" + fig_dict = {"layout": {"title": {"text": "a" * 500}}} + + result = path_tools.determine_path(tmp_path, fig_dict, "png") + + assert result.parent == tmp_path + assert result.name == f"{'a' * 80}.png" + + def test_determine_path_file_with_suffix(tmp_path, fig_fixture): """Test determine_path with file path having suffix.""" fig_dict, _expected_prefix = fig_fixture