From 389012e883d6a1f04d6aa6472b2b5ec30a5c37cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E4=BD=99=E6=BD=87?= <1298704923@qq.com> Date: Mon, 7 Sep 2026 15:23:38 +0800 Subject: [PATCH] Fix asset filename truncation to account for assets/ prefix Reserve the assets directory prefix when truncating extra filenames so relative paths stay within max_asset_filename_length. Co-authored-by: Cursor --- src/pytest_html/basereport.py | 12 ++++++++++-- testing/legacy_test_pytest_html.py | 3 ++- testing/test_unit.py | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/pytest_html/basereport.py b/src/pytest_html/basereport.py index cfcc74b2..a27bf143 100644 --- a/src/pytest_html/basereport.py +++ b/src/pytest_html/basereport.py @@ -42,12 +42,20 @@ def css(self): return def _asset_filename(self, test_id, extra_index, test_index, file_extension): - return "{}_{}_{}.{}".format( + filename = "{}_{}_{}.{}".format( re.sub(r"[^\w.]", "_", test_id), str(extra_index), str(test_index), file_extension, - )[-self._max_asset_filename_length :] + ) + max_length = self._max_asset_filename_length + assets_dir = getattr(self, "_assets_path", None) + if assets_dir is not None: + # Files are written under this directory (see Report._write_content). + # Reserve the directory name plus separator so the relative path + # stays within max_asset_filename_length on path-limited systems. + max_length -= len(assets_dir.name) + 1 + return filename[-max(1, max_length) :] def _generate_report(self, self_contained=False): generated = datetime.datetime.now() diff --git a/testing/legacy_test_pytest_html.py b/testing/legacy_test_pytest_html.py index 08ad208d..f2fe3db4 100644 --- a/testing/legacy_test_pytest_html.py +++ b/testing/legacy_test_pytest_html.py @@ -681,8 +681,9 @@ def {test_name}(): """ ) result, html = run(testdir, "report.html") + truncated_length = max(1, max_asset_filename_length - len("assets/")) file_name = f"test_very_long_test_name.py__{test_name}_0_0.png"[ - -max_asset_filename_length: + -truncated_length: ] src = "assets/" + file_name link = f'' diff --git a/testing/test_unit.py b/testing/test_unit.py index 1ea945ea..eaef969c 100644 --- a/testing/test_unit.py +++ b/testing/test_unit.py @@ -5,6 +5,8 @@ import pytest from assertpy import assert_that +from pytest_html.basereport import BaseReport + pytest_plugins = ("pytester",) @@ -146,3 +148,24 @@ def test_custom_css_selfcontained(pytester, css_file_path, expandvar): with open(pytester.path / "report.html") as f: html = f.read() assert_that(html).contains("* " + str(css_file_path)).contains("* two.css") + + +def test_asset_filename_accounts_for_assets_directory_prefix(): + """Relative asset paths must stay within max_asset_filename_length (#906).""" + + class _Report: + _max_asset_filename_length = 255 + _assets_path = Path("report_dir") / "assets" + + filename = BaseReport._asset_filename( + _Report(), + "test_" + "a" * 300, + extra_index=0, + test_index=0, + file_extension="png", + ) + relative_path = str(Path("assets") / filename).replace("\\", "/") + assert_that(len(filename)).is_less_than_or_equal_to(255 - len("assets/")) + assert_that(len(relative_path)).is_less_than_or_equal_to(255) + assert_that(relative_path).starts_with("assets/") + assert_that(filename).ends_with(".png")