From 1c713c472cd9470d77dabcb2657710f976d486ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=81=E4=BA=8C=E6=9C=88=E4=BD=9C=E6=9B=B2=E5=AE=B6?= Date: Thu, 18 Jun 2026 23:00:18 +0800 Subject: [PATCH 1/2] fix: make non-base64 media paths relative to report location When extra media content is a file path (not base64), it was previously used as-is in the HTML, creating absolute paths that break when the report is moved. Now resolves relative to the report's parent directory. --- src/pytest_html/report.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pytest_html/report.py b/src/pytest_html/report.py index 22ef7e14..dfe211d2 100644 --- a/src/pytest_html/report.py +++ b/src/pytest_html/report.py @@ -32,8 +32,13 @@ def _media_content(self, content, asset_name, *args, **kwargs): media_data = base64.b64decode(content.encode("utf-8"), validate=True) return self._write_content(media_data, asset_name) except binascii.Error: - # if not base64 content, just return as it's a file or link - return content + # if not base64 content, try to make it relative to the report + try: + abs_path = Path(content).resolve() + return str(abs_path.relative_to(self._report_path.parent.resolve())) + except (ValueError, OSError): + # On different drives (Windows) or unresolvable, return as-is + return content def _write_content(self, content, asset_name): content_relative_path = Path(self._assets_path, asset_name) From 0888e6fa6e1649f3e306f3178226ad94660380a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=81=E4=BA=8C=E6=9C=88=E4=BD=9C=E6=9B=B2=E5=AE=B6?= Date: Thu, 18 Jun 2026 23:16:14 +0800 Subject: [PATCH 2/2] fix: add explicit stacklevel to all warnings.warn() calls B028: 7 warnings.warn() calls lacked explicit stacklevel, making deprecation warnings point to the warning call site instead of the caller's code. --- src/pytest_html/basereport.py | 3 +++ src/pytest_html/fixtures.py | 1 + src/pytest_html/plugin.py | 1 + src/pytest_html/report_data.py | 1 + src/pytest_html/selfcontained_report.py | 3 ++- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pytest_html/basereport.py b/src/pytest_html/basereport.py index cfcc74b2..eea6284d 100644 --- a/src/pytest_html/basereport.py +++ b/src/pytest_html/basereport.py @@ -81,6 +81,7 @@ def _generate_environment(self): warnings.warn( "'pytest-metadata < 3.0.0' is deprecated and support will be dropped in next major version", DeprecationWarning, + stacklevel=2, ) for key in metadata.keys(): @@ -214,6 +215,7 @@ def pytest_runtest_logreport(self, report): "'duration_formatter' has been removed and no longer has any effect!" "Please use the 'pytest_html_duration_format' hook instead.", DeprecationWarning, + stacklevel=2, ) # "reruns" makes this code a mess. @@ -370,6 +372,7 @@ def _fix_py(cells): "The 'py' module is deprecated and support " "will be removed in a future release.", DeprecationWarning, + stacklevel=2, ) html = str(html) html = html.replace("col=", "data-column-type=") diff --git a/src/pytest_html/fixtures.py b/src/pytest_html/fixtures.py index 88ce828d..2e97f0b8 100644 --- a/src/pytest_html/fixtures.py +++ b/src/pytest_html/fixtures.py @@ -24,6 +24,7 @@ def test_foo(extra): "The 'extra' fixture is deprecated and will be removed in a future release" ", use 'extras' instead.", DeprecationWarning, + stacklevel=2, ) pytestconfig.stash[extras_stash_key] = [] yield pytestconfig.stash[extras_stash_key] diff --git a/src/pytest_html/plugin.py b/src/pytest_html/plugin.py index 949a6ffa..7d224b20 100644 --- a/src/pytest_html/plugin.py +++ b/src/pytest_html/plugin.py @@ -134,6 +134,7 @@ def pytest_runtest_makereport(item, call): "The 'report.extra' attribute is deprecated and will be removed in a future release" ", use 'report.extras' instead.", DeprecationWarning, + stacklevel=2, ) fixture_extras = item.config.stash.get(extras_stash_key, []) plugin_extras = getattr(report, "extras", []) diff --git a/src/pytest_html/report_data.py b/src/pytest_html/report_data.py index 3dc0ea21..88ef07af 100644 --- a/src/pytest_html/report_data.py +++ b/src/pytest_html/report_data.py @@ -53,6 +53,7 @@ def __init__(self, config): "will be removed in the next major release. " "Please use 'render_collapsed = all' instead.", DeprecationWarning, + stacklevel=2, ) collapsed = "all" diff --git a/src/pytest_html/selfcontained_report.py b/src/pytest_html/selfcontained_report.py index ecc44600..8c5931bb 100644 --- a/src/pytest_html/selfcontained_report.py +++ b/src/pytest_html/selfcontained_report.py @@ -31,7 +31,8 @@ def _media_content(self, content, mime_type, *args, **kwargs): warnings.warn( "Self-contained HTML report " "includes link to external " - f"resource: {content}" + f"resource: {content}", + stacklevel=2, ) return content