From 31d2f29147685da7c8ff6c9b6bf1462d8eb3153d Mon Sep 17 00:00:00 2001 From: Yaniv Golan Date: Mon, 30 Mar 2026 19:48:52 +0300 Subject: [PATCH] fix: show placeholder for missing resources instead of silently dropping When an en-media tag references a resource not included in the ENEX export, replace the block with a visible text marker containing the MD5 hash instead of silently removing it. Log at WARNING level. --- .../note_post_process_resources.py | 16 +++++++++-- tests/test_note_parser.py | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/enex2notion/note_parser/note_post_process_resources.py b/enex2notion/note_parser/note_post_process_resources.py index cef4be2..cbaa420 100644 --- a/enex2notion/note_parser/note_post_process_resources.py +++ b/enex2notion/note_parser/note_post_process_resources.py @@ -1,19 +1,29 @@ import logging from enex2notion.enex_types import EvernoteNote +from enex2notion.notion_blocks.text import NotionTextBlock, TextProp from enex2notion.notion_blocks.uploadable import NotionUploadableBlock logger = logging.getLogger(__name__) def resolve_resources(note_blocks, note: EvernoteNote): - for block in note_blocks.copy(): + for i, block in enumerate(note_blocks): # Resolve resource hash to actual resource if isinstance(block, NotionUploadableBlock) and block.resource is None: block.resource = note.resource_by_md5(block.md5_hash) if block.resource is None: - logger.debug(f"Failed to resolve resource in '{note.title}'") - note_blocks.remove(block) + logger.warning( + f"Missing resource in '{note.title}'" + f" (hash: {block.md5_hash})" + ) + note_blocks[i] = NotionTextBlock( + TextProp( + f"[Missing resource: hash {block.md5_hash}" + f" — not included in ENEX export]" + ) + ) + continue if block.children: resolve_resources(block.children, note) diff --git a/tests/test_note_parser.py b/tests/test_note_parser.py index 52d4599..5adde6f 100644 --- a/tests/test_note_parser.py +++ b/tests/test_note_parser.py @@ -1116,3 +1116,31 @@ def test_text_prop_strip_props(): ["\ntest2\n"], ["\n2", [["b"]]], ] + + +def test_resolve_resources_missing_replaced_with_placeholder(caplog): + from enex2notion.note_parser.note_post_process_resources import resolve_resources + from enex2notion.notion_blocks.uploadable import NotionImageBlock + + note = EvernoteNote( + title="test", + created=datetime(2021, 1, 1, tzinfo=tzutc()), + updated=datetime(2021, 1, 1, tzinfo=tzutc()), + content="", + tags=[], + author="", + url="", + is_webclip=False, + resources=[], + ) + + blocks = [NotionImageBlock(md5_hash="abc123")] + + with caplog.at_level(logging.WARNING, logger="enex2notion"): + resolve_resources(blocks, note) + + assert len(blocks) == 1 + assert "abc123" in blocks[0].attrs["title_plaintext"] + assert "Missing resource" in blocks[0].attrs["title_plaintext"] + assert "Missing resource in 'test'" in caplog.text + assert "abc123" in caplog.text