From c2250b58a78735bc50668d9383de5f60bd16147c Mon Sep 17 00:00:00 2001 From: VectorSophie Date: Fri, 22 May 2026 02:30:39 +0900 Subject: [PATCH] fix windows file links in RichHandler using Path.as_uri() Co-Authored-By: Claude Sonnet 4.6 --- rich/_log_render.py | 6 ++++-- tests/test_logging.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/rich/_log_render.py b/rich/_log_render.py index e8810100b3..5013767afc 100644 --- a/rich/_log_render.py +++ b/rich/_log_render.py @@ -1,4 +1,5 @@ from datetime import datetime +from pathlib import Path from typing import Iterable, List, Optional, TYPE_CHECKING, Union, Callable @@ -71,14 +72,15 @@ def __call__( row.append(Renderables(renderables)) if self.show_path and path: path_text = Text() + link_uri = Path(link_path).as_uri() if link_path else "" path_text.append( - path, style=f"link file://{link_path}" if link_path else "" + path, style=f"link {link_uri}" if link_path else "" ) if line_no: path_text.append(":") path_text.append( f"{line_no}", - style=f"link file://{link_path}#{line_no}" if link_path else "", + style=f"link {link_uri}#{line_no}" if link_path else "", ) row.append(path_text) diff --git a/tests/test_logging.py b/tests/test_logging.py index 388dcc1088..7154742852 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -1,12 +1,15 @@ import io import os import logging +from pathlib import Path from typing import Optional import pytest from rich.console import Console from rich.logging import RichHandler +from rich._log_render import LogRender +from rich.text import Text handler = RichHandler( console=Console( @@ -122,6 +125,33 @@ def mock_handle_error(record): assert "message" in actual_record.msg +def test_link_path_uri_format(): + """link_path must use file:/// (3 slashes) and forward slashes. + Regression test for https://github.com/Textualize/rich/issues/4093 + """ + console = Console(file=io.StringIO(), _environ={}) + render = LogRender() + abs_path = str(Path(__file__).resolve()) + table = render( + console, + renderables=[Text("msg")], + path="test_logging.py", + line_no=1, + link_path=abs_path, + ) + expected_uri = Path(abs_path).as_uri() + + path_cell = table.columns[-1]._cells[0] + assert isinstance(path_cell, Text) + link_styles = [span.style for span in path_cell._spans if "link" in str(span.style)] + assert any(expected_uri in str(s) for s in link_styles), ( + f"Expected {expected_uri!r} in link styles, got {link_styles!r}" + ) + assert not any("file://" + abs_path in str(s) for s in link_styles), ( + "file:// (two slashes) should not appear in link styles" + ) + + def test_markup_and_highlight(): console = Console( file=io.StringIO(),