-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Open
Description
Following this example, I have added a link inside the markdown.
import textual.app
import textual.widgets
class MarkdownExampleApp(textual.app.App):
def compose(self):
yield textual.widgets.MarkdownViewer('[LINK](https://pypi.org/)')
MarkdownExampleApp().run()Starting this and clicking the LINK text, opens my browser, but the app also crashes with:
╭───────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────╮
│ /home/user123/.local/lib/python3.12/site-packages/textual/widgets/_markdown.py:1632 in _on_markdown_link_clicked │
│ │
│ 1629 │ │
│ 1630 │ async def _on_markdown_link_clicked(self, message: Markdown.LinkClicked) -> None: │
│ 1631 │ │ message.stop() │
│ ❱ 1632 │ │ await self.go(message.href) │
│ 1633 │ │
│ 1634 │ def watch_show_table_of_contents(self, show_table_of_contents: bool) -> None: │
│ 1635 │ │ self.set_class(show_table_of_contents, "-show-table-of-contents") │
│ │
│ ╭────────────────────────── locals ───────────────────────────╮ │
│ │ message = LinkClicked() │ │
│ │ self = MarkdownViewer(classes='-show-table-of-contents') │ │
│ ╰─────────────────────────────────────────────────────────────╯ │
│ │
│ /home/user123/.local/lib/python3.12/site-packages/textual/widgets/_markdown.py:1615 in go │
│ │
│ 1612 │ │ │ self.document.goto_anchor(anchor) │
│ 1613 │ │ else: │
│ 1614 │ │ │ # We've been asked to go to a file, optionally with an anchor. │
│ ❱ 1615 │ │ │ await self.document.load(self.navigator.go(location)) │
│ 1616 │ │ │ self.post_message(self.NavigatorUpdated()) │
│ 1617 │ │
│ 1618 │ async def back(self) -> None: │
│ │
│ ╭─────────────────────────── locals ───────────────────────────╮ │
│ │ anchor = '' │ │
│ │ location = 'https://pypi.org/' │ │
│ │ path = PosixPath('https:/pypi.org') │ │
│ │ self = MarkdownViewer(classes='-show-table-of-contents') │ │
│ ╰──────────────────────────────────────────────────────────────╯ │
│ │
│ /home/user123/.local/lib/python3.12/site-packages/textual/widgets/_markdown.py:1188 in load │
│ │
│ 1185 │ │ │ those that can be raised by calling [`Path.read_text`][pathlib.Path.read_tex │
│ 1186 │ │ """ │
│ 1187 │ │ path, anchor = self.sanitize_location(str(path)) │
│ ❱ 1188 │ │ data = await asyncio.get_running_loop().run_in_executor( │
│ 1189 │ │ │ None, partial(path.read_text, encoding="utf-8") │
│ 1190 │ │ ) │
│ 1191 │ │ await self.update(data) │
│ │
│ ╭───────────────────────────────── locals ──────────────────────────────────╮ │
│ │ anchor = '' │ │
│ │ path = PosixPath('/projects/projects-10001/ratarmount/https:/pypi.org') │ │
│ │ self = Markdown() │ │
│ ╰───────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.12/concurrent/futures/thread.py:58 in run │
│ │
│ 55 │ │ │ return ╭── locals ───╮ │
│ 56 │ │ │ self = None │ │
│ 57 │ │ try: ╰─────────────╯ │
│ ❱ 58 │ │ │ result = self.fn(*self.args, **self.kwargs) │
│ 59 │ │ except BaseException as exc: │
│ 60 │ │ │ self.future.set_exception(exc) │
│ 61 │ │ │ # Break a reference cycle with the exception 'exc' │
│ │
│ /usr/lib/python3.12/pathlib.py:1029 in read_text │
│ │
│ 1026 │ │ Open the file in text mode, read it, and close the file. │
│ 1027 │ │ """ │
│ 1028 │ │ encoding = io.text_encoding(encoding) │
│ ❱ 1029 │ │ with self.open(mode='r', encoding=encoding, errors=errors) as f: │
│ 1030 │ │ │ return f.read() │
│ 1031 │ │
│ 1032 │ def write_bytes(self, data): │
│ │
│ ╭────────────────────────────────── locals ───────────────────────────────────╮ │
│ │ encoding = 'utf-8' │ │
│ │ errors = None │ │
│ │ self = PosixPath('/projects/projects-10001/ratarmount/https:/pypi.org') │ │
│ ╰─────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.12/pathlib.py:1015 in open │
│ │
│ 1012 │ │ """ │
│ 1013 │ │ if "b" not in mode: │
│ 1014 │ │ │ encoding = io.text_encoding(encoding) │
│ ❱ 1015 │ │ return io.open(self, mode, buffering, encoding, errors, newline) │
│ 1016 │ │
│ 1017 │ def read_bytes(self): │
│ 1018 │ │ """ │
│ │
│ ╭─────────────────────────────────── locals ───────────────────────────────────╮ │
│ │ buffering = -1 │ │
│ │ encoding = 'utf-8' │ │
│ │ errors = None │ │
│ │ mode = 'r' │ │
│ │ newline = None │ │
│ │ self = PosixPath('/projects/projects-10001/ratarmount/https:/pypi.org') │ │
│ ╰──────────────────────────────────────────────────────────────────────────────╯ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
FileNotFoundError: [Errno 2] No such file or directory: '/projects/projects-10001/ratarmount/https:/pypi.org'
- When calling
MarkdownViewerwithopen_links=False, I get only the crash, without any browser being opened. - When using an anchor link to a section
[LINK](#section), it scrolls to that section but also tries to open it as a URL, so that I get a popup dialog "Unable to detect the URI-scheme of "#section" - When using an anchor to a section and
open_links=False, it works, i.e., simply scrolls to that section and no error system dialog pops up.
Textual Diagnostics
Versions
| Name | Value |
|---|---|
| Textual | 5.3.0 |
| Rich | 13.7.1 |
Python
| Name | Value |
|---|---|
| Version | 3.12.3 |
| Implementation | CPython |
| Compiler | GCC 13.3.0 |
| Executable | /usr/bin/python3 |
Operating System
| Name | Value |
|---|---|
| System | Linux |
| Release | 6.8.0-64-generic |
| Version | #67-Ubuntu SMP PREEMPT_DYNAMIC Sun Jun 15 20:23:31 UTC 2025 |
Terminal
| Name | Value |
|---|---|
| Terminal Application | Unknown |
| TERM | xterm-256color |
| COLORTERM | truecolor |
| FORCE_COLOR | Not set |
| NO_COLOR | Not set |
Rich Console options
| Name | Value |
|---|---|
| size | width=177, height=50 |
| legacy_windows | False |
| min_width | 1 |
| max_width | 177 |
| is_terminal | True |
| encoding | utf-8 |
| max_height | 50 |
| justify | None |
| overflow | None |
| no_wrap | False |
| highlight | None |
| markup | None |
| height | None |
TomJGooding
Metadata
Metadata
Assignees
Labels
No labels