diff --git a/n2y/plugins/internallinks.py b/n2y/plugins/internallinks.py index 1253a3a..bb6375a 100644 --- a/n2y/plugins/internallinks.py +++ b/n2y/plugins/internallinks.py @@ -63,7 +63,13 @@ class NotionInternalLink(TextRichText): def __init__(self, client, notion_data, block=None): super().__init__(client, notion_data, block) - if block is None or not is_internal_link(self.href, self.block.page.notion_id): + # Rich text can appear in contexts without a page (e.g. property + # values); only same-page links inside a page's blocks are resolvable. + if ( + block is None + or block.page is None + or not is_internal_link(self.href, self.block.page.notion_id) + ): raise UseNextClass def to_pandoc(self): diff --git a/tests/test_plugin_internallinks.py b/tests/test_plugin_internallinks.py index 7a2fce4..784e809 100644 --- a/tests/test_plugin_internallinks.py +++ b/tests/test_plugin_internallinks.py @@ -1,5 +1,9 @@ from unittest.mock import Mock, patch +import pytest + +from n2y.errors import UseNextClass + from n2y.blocks import ChildPageBlock, DividerBlock, HeadingOneBlock, ParagraphBlock from n2y.notion import Client from n2y.notion_mocks import ( @@ -12,6 +16,7 @@ ) from n2y.page import Page from n2y.plugins.internallinks import ( + NotionInternalLink, find_target_block, get_notion_id_from_href, is_internal_link, @@ -151,6 +156,17 @@ def mock_page_with_link_to_divider(wrap_notion_user, link_text: str = "see below return page, href +@patch("n2y.notion.Client.wrap_notion_user") +def test_internal_link_in_block_without_page_uses_next_class(wrap_notion_user): + # Rich text can appear in contexts whose block has no page (e.g. property + # values); the plugin must defer instead of crashing on block.page. + client = Client("", plugins=["n2y.plugins.internallinks"]) + wrap_notion_user.return_value = User(client, mock_user()) + rich_text = mock_rich_text(text="x", href="/1234#5678") + with pytest.raises(UseNextClass): + NotionInternalLink(client, rich_text, block=Mock(page=None)) + + def test_internal_link_to_textless_block_left_unresolved(): # Links can target blocks with no rich_text (images, dividers); the plugin # must not crash and should leave the link unchanged.