Repository: mondeja/mkdocs-include-markdown-plugin (python)

Issue:
Log warning when failing to find `start` or `end`
Currently, if a `start` or `end` delimiter is not detected, the include tag silently handles this. This really ought to be logged via warning.

Pull request:
Fix warnings not shown sometimes with missing `end` and `start` delimiters
Fixes #92 (regression at v6.0.0)

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bd0abca..7de2bc9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -44,7 +44,7 @@ jobs:
             python-version: "3.11"
             py: py311
           - platform: ubuntu-latest
-            python-version: 3.12.0-beta.4
+            python-version: 3.12.0-rc.1
             py: py312
           - platform: macos-latest
             python-version: 3.8
@@ -53,7 +53,7 @@ jobs:
             python-version: "3.11"
             py: py311
           - platform: macos-latest
-            python-version: 3.12.0-beta.4
+            python-version: 3.12.0-rc.1
             py: py312
           - platform: windows-latest
             python-version: 3.8
@@ -62,7 +62,7 @@ jobs:
             python-version: "3.11"
             py: py311
           - platform: windows-latest
-            python-version: 3.12.0-beta.4
+            python-version: 3.12.0-rc.1
             py: py312
     steps:
       - uses: actions/checkout@v3
diff --git a/pyproject.toml b/pyproject.toml
index 8fe2724..e903630 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "mkdocs-include-markdown-plugin"
-version = "6.0.0"
+version = "6.0.1"
 description = "Mkdocs Markdown includer plugin."
 readme = "README.md"
 license = "Apache-2.0"
diff --git a/src/mkdocs_include_markdown_plugin/process.py b/src/mkdocs_include_markdown_plugin/process.py
index e4cd940..2102726 100644
--- a/src/mkdocs_include_markdown_plugin/process.py
+++ b/src/mkdocs_include_markdown_plugin/process.py
@@ -284,8 +284,8 @@ def interpret_escapes(value: str) -> str:
 
 
 def filter_inclusions(
-        new_start: str | None,
-        new_end: str | None,
+        start: str | None,
+        end: str | None,
         text_to_include: str,
 ) -> tuple[str, bool, bool]:
     """Filter inclusions in a text.
@@ -294,48 +294,48 @@ def filter_inclusions(
     arguments.
     """
     expected_start_not_found, expected_end_not_found = (False, False)
+    new_text_to_include = ''
 
-    if new_start is not None:
-        start = interpret_escapes(new_start)
-        end = interpret_escapes(new_end) if new_end is not None else None
-
-        new_text_to_include = ''
-
-        if end is not None:
-            end_found = False
-            start_split = text_to_include.split(start)[1:]
-            if not start_split:
-                expected_start_not_found = True
-            else:
-                for start_text in start_split:
-                    for i, end_text in enumerate(start_text.split(end)):
-                        if not i % 2:
-                            new_text_to_include += end_text
-                            end_found = True
-            if not end_found:
-                expected_end_not_found = True
+    if start is not None and end is None:
+        start = interpret_escapes(start)
+        if start not in text_to_include:
+            expected_start_not_found = True
         else:
-            if start in text_to_include:
-                new_text_to_include = text_to_include.split(
-                    start,
-                    maxsplit=1,
-                )[1]
-            else:
-                expected_start_not_found = True
-        text_to_include = new_text_to_include
-
-    elif new_end is not None:  # pragma: no branch
-        end = interpret_escapes(new_end)
-        if end in text_to_include:
-            text_to_include = text_to_include.split(
+            new_text_to_include = text_to_include.split(
+                start,
+                maxsplit=1,
+            )[1]
+    elif start is None and end is not None:
+        end = interpret_escapes(end)
+        if end not in text_to_include:
+            expected_end_not_found = True
+            new_text_to_include = text_to_include
+        else:
+            new_text_to_include = text_to_include.split(
                 end,
                 maxsplit=1,
             )[0]
-        else:
+    elif start is not None and end is not None:
+        start, end = interpret_escapes(start), interpret_escapes(end)
+        if start not in text_to_include:
+            expected_start_not_found = True
+        if end not in text_to_include:
             expected_end_not_found = True
 
+        text_parts = (
+            text_to_include.split(start)[1:]
+            if start in text_to_include else [text_to_include]
+        )
+
+        for start_text in text_parts:
+            for i, end_text in enumerate(start_text.split(end)):
+                if not i % 2:
+                    new_text_to_include += end_text
+    else:  # pragma: no cover
+        new_text_to_include = text_to_include
+
     return (
-        text_to_include,
+        new_text_to_include,
         expected_start_not_found,
         expected_end_not_found,
     )


Test patch:
diff --git a/tests/test_unit/test_config.py b/tests/test_unit/test_config.py
index 98bed45..f626b95 100644
--- a/tests/test_unit/test_config.py
+++ b/tests/test_unit/test_config.py
@@ -23,30 +23,30 @@ def _run_test(
     caplog,
     tmp_path,
 ):
-    included_filepath = tmp_path / 'included.md'
-    includer_filepath = tmp_path / 'includer.md'
+    included_file = tmp_path / 'included.md'
+    includer_file = tmp_path / 'includer.md'
 
-    included_filepath.write_text(content_to_include)
-    includer_filepath.write_text(
-        content_to_include.replace('{filepath}', included_filepath.as_posix()),
+    included_file.write_text(content_to_include)
+    includer_file.write_text(
+        content_to_include.replace('{filepath}', included_file.as_posix()),
     )
 
     # assert content
     page_content = includer_schema.replace(
         '{filepath}',
-        included_filepath.as_posix(),
+        included_file.as_posix(),
     )
-    includer_filepath.write_text(page_content)
+    includer_file.write_text(page_content)
 
     expected_result = expected_result.replace(
         '{filepath}',
-        included_filepath.as_posix(),
+        included_file.as_posix(),
     )
 
     assert (
         on_page_markdown(
             page_content,
-            page(includer_filepath),
+            page(includer_file),
             tmp_path,
             config,
         )
diff --git a/tests/test_unit/test_exclude.py b/tests/test_unit/test_exclude.py
index 6953010..16f583d 100644
--- a/tests/test_unit/test_exclude.py
+++ b/tests/test_unit/test_exclude.py
@@ -81,7 +81,7 @@ def test_exclude(
     }
 
     exclude_prefix = f'{tmp_path}{os.sep}' if exclude_prefix else ''
-    includer_filepath_content = f'''{{%
+    includer_file_content = f'''{{%
   {directive} "{tmp_path}{os.sep}content/*"
   exclude='{exclude_prefix}{exclude}'
   comments=false
@@ -89,11 +89,11 @@ def test_exclude(
     for basename, file in files.items():
         file.write_text(f'{basename}\n')
 
-    includer_file.write_text(includer_filepath_content)
+    includer_file.write_text(includer_file_content)
 
     func = functools.partial(
         on_page_markdown,
-        includer_filepath_content,
+        includer_file_content,
         page(includer_file),
         includer_folder,
     )
diff --git a/tests/test_unit/test_glob_include.py b/tests/test_unit/test_glob_include.py
index ed72909..dd57799 100644
--- a/tests/test_unit/test_glob_include.py
+++ b/tests/test_unit/test_glob_include.py
@@ -14,7 +14,7 @@ def test_glob_include_absolute(page, tmp_path):
     included_01_file = tmp_path / 'included_01.txt'
     included_02_file = tmp_path / 'included_02.txt'
 
-    includer_filepath_content = f'''foo
+    includer_file_content = f'''foo
 
 {{%
   include "./included*.txt"
@@ -29,7 +29,7 @@ def test_glob_include_absolute(page, tmp_path):
     included_01_content = 'bar'
     included_02_content = 'baz'
 
-    includer_file.write_text(includer_filepath_content)
+    includer_file.write_text(includer_file_content)
     included_01_file.write_text(included_01_content)
     included_02_file.write_text(included_02_content)
 
@@ -42,7 +42,7 @@ barbaz
 '''
 
     assert on_page_markdown(
-        includer_filepath_content, page(includer_file), tmp_path,
+        includer_file_content, page(includer_file), tmp_path,
     ) == expected_result
 
 
@@ -50,7 +50,6 @@ barbaz
 @pytest.mark.parametrize(
     (
         'includer_content',
-        'expected_result',
         'expected_warnings_schemas',
     ),
     (
@@ -68,14 +67,6 @@ barbaz
   end="<!-- end-1 -->"
   comments=false
 %}
-''',
-            '''
-baz
-
-
-
-bar
-
 ''',
             [],
             id='start-end',
@@ -86,18 +77,6 @@ bar
   end="<!-- end-2 -->"
   comments=false
 %}
-''',
-            # if aren't both``end`` and ``start`` specified, produces
-            # a strange but expected output
-            '''This 01 must appear only without specifying start.
-<!-- start-1 -->
-bar
-<!-- end-1 -->
-This 01 must appear only without specifying end.
-This 02 must appear only without specifying start.
-<!-- start-2 -->
-baz
-
 ''',
             [],
             id='end',
@@ -119,7 +98,6 @@ baz
   comments=false
 %}
 ''',
-            '\n\n\n',
             [
                 (
                     "Delimiter end '<!-- end-not-found-1 -->'"
@@ -153,7 +131,6 @@ baz
 def test_glob_include(
     includer_content,
     directive,
-    expected_result,
     expected_warnings_schemas,
     page,
     caplog,
@@ -163,7 +140,7 @@ def test_glob_include(
     included_01_file = tmp_path / 'included_01.txt'
     included_02_file = tmp_path / 'included_02.txt'
 
-    includer_filepath_content = f'''foo
+    includer_file_content = f'''foo
 
 {includer_content.replace('{directive}', directive)}
 '''
@@ -181,19 +158,13 @@ baz
 This 02 must appear only without specifying end.
 '''
 
-    includer_file.write_text(includer_filepath_content)
+    includer_file.write_text(includer_file_content)
     included_01_file.write_text(included_01_content)
     included_02_file.write_text(included_02_content)
 
-    # assert content
-    expected_result = f'''foo
-
-{expected_result}
-'''
-
-    assert on_page_markdown(
-        includer_filepath_content, page(includer_file), tmp_path,
-    ) == expected_result
+    on_page_markdown(
+        includer_file_content, page(includer_file), tmp_path,
+    )
 
     # assert warnings
     expected_warnings_schemas = expected_warnings_schemas or []
diff --git a/tests/test_unit/test_include.py b/tests/test_unit/test_include.py
index 0771fcb..022e360 100644
--- a/tests/test_unit/test_include.py
+++ b/tests/test_unit/test_include.py
@@ -195,7 +195,7 @@ Some text
                 (
                     "Delimiter start '<!--start-->' of 'include'"
                     ' directive at {filepath}:3'
-                    ' not detected in the file {included_filepath}'
+                    ' not detected in the file {included_file}'
                 ),
             ],
             id='start=foo (not found)-end=None',
@@ -220,7 +220,7 @@ Some text
                 (
                     "Delimiter end '<!--end-->' of 'include'"
                     ' directive at {filepath}:2'
-                    ' not detected in the file {included_filepath}'
+                    ' not detected in the file {included_file}'
                 ),
             ],
             id='start=None-end=foo (not found)',
@@ -368,22 +368,22 @@ def test_include(
     caplog,
     tmp_path,
 ):
-    included_filepath = tmp_path / 'included.md'
-    includer_filepath = tmp_path / 'includer.md'
+    included_file = tmp_path / 'included.md'
+    includer_file = tmp_path / 'includer.md'
 
-    included_filepath.write_text(content_to_include)
-    includer_filepath.write_text(
-        content_to_include.replace('{filepath}', included_filepath.as_posix()),
+    included_file.write_text(content_to_include)
+    includer_file.write_text(
+        content_to_include.replace('{filepath}', included_file.as_posix()),
     )
 
     # assert content
     page_content = includer_schema.replace(
-        '{filepath}', included_filepath.as_posix(),
+        '{filepath}', included_file.as_posix(),
     )
-    includer_filepath.write_text(page_content)
+    includer_file.write_text(page_content)
 
     assert on_page_markdown(
-        page_content, page(includer_filepath), tmp_path,
+        page_content, page(includer_file), tmp_path,
     ) == expected_result
 
     # assert warnings
@@ -391,10 +391,10 @@ def test_include(
     expected_warnings = [
         msg_schema.replace(
             '{filepath}',
-            str(includer_filepath.relative_to(tmp_path)),
+            str(includer_file.relative_to(tmp_path)),
         ).replace(
-            '{included_filepath}',
-            str(included_filepath.relative_to(tmp_path)),
+            '{included_file}',
+            str(included_file.relative_to(tmp_path)),
         ) for msg_schema in expected_warnings_schemas
     ]
 
diff --git a/tests/test_unit/test_include_markdown.py b/tests/test_unit/test_include_markdown.py
index 5240244..6064553 100644
--- a/tests/test_unit/test_include_markdown.py
+++ b/tests/test_unit/test_include_markdown.py
@@ -284,7 +284,7 @@ Some text
                 (
                     "Delimiter start '<!--start-->' of 'include-markdown'"
                     ' directive at {filepath}:2 not detected in the file'
-                    ' {included_filepath}'
+                    ' {included_file}'
                 ),
             ],
             id='start=foo (not found)-end=None',
@@ -309,7 +309,7 @@ Some text
                 (
                     "Delimiter end '<!--end-->' of 'include-markdown'"
                     ' directive at {filepath}:2'
-                    ' not detected in the file {included_filepath}'
+                    ' not detected in the file {included_file}'
                 ),
             ],
             id='start=None-end=foo (not found)',
@@ -769,28 +769,28 @@ def test_include_markdown(
     caplog,
     tmp_path,
 ):
-    included_filepath = tmp_path / 'included.md'
-    includer_filepath = tmp_path / 'includer.md'
+    included_file = tmp_path / 'included.md'
+    includer_file = tmp_path / 'includer.md'
 
-    included_filepath.write_text(content_to_include, encoding='utf-8')
-    includer_filepath.write_text(
-        content_to_include.replace('{filepath}', included_filepath.as_posix()),
+    included_file.write_text(content_to_include, encoding='utf-8')
+    includer_file.write_text(
+        content_to_include.replace('{filepath}', included_file.as_posix()),
         encoding='utf-8',
     )
 
     page_content = includer_schema.replace(
-        '{filepath}', included_filepath.as_posix(),
+        '{filepath}', included_file.as_posix(),
     )
-    includer_filepath.write_text(page_content, encoding='utf-8')
+    includer_file.write_text(page_content, encoding='utf-8')
 
     # assert content
     expected_result = expected_result_schema.replace(
-        '{filepath}', included_filepath.as_posix(),
+        '{filepath}', included_file.as_posix(),
     )
 
     assert on_page_markdown(
         page_content,
-        page(includer_filepath),
+        page(includer_file),
         tmp_path,
     ) == expected_result
 
@@ -799,10 +799,10 @@ def test_include_markdown(
     expected_warnings = [
         msg_schema.replace(
             '{filepath}',
-            str(includer_filepath.relative_to(tmp_path)),
+            str(includer_file.relative_to(tmp_path)),
         ).replace(
-            '{included_filepath}',
-            str(included_filepath.relative_to(tmp_path)),
+            '{included_file}',
+            str(included_file.relative_to(tmp_path)),
         ) for msg_schema in expected_warnings_schemas
     ]
 
@@ -892,7 +892,7 @@ Here's a [reference link][ref-link].
 def test_multiple_includes(page, tmp_path):
     snippet_filepath = tmp_path / 'snippet.md'
     another_filepath = tmp_path / 'another.md'
-    includer_filepath = tmp_path / 'includer.md'
+    includer_file = tmp_path / 'includer.md'
 
     includer_content = f'''# Heading
 
@@ -915,7 +915,7 @@ def test_multiple_includes(page, tmp_path):
     snippet_content = 'Snippet'
     another_content = 'Another'
 
-    includer_filepath.write_text(includer_content)
+    includer_file.write_text(includer_content)
     snippet_filepath.write_text(snippet_content)
     another_filepath.write_text(another_content)
 
@@ -932,5 +932,5 @@ Another
 Another
 '''
     assert on_page_markdown(
-        includer_content, page(includer_filepath), tmp_path,
+        includer_content, page(includer_file), tmp_path,
     ) == expected_result
diff --git a/tests/test_unit/test_logging.py b/tests/test_unit/test_logging.py
new file mode 100644
index 0000000..c92826a
--- /dev/null
+++ b/tests/test_unit/test_logging.py
@@ -0,0 +1,51 @@
+import pytest
+from testing_helpers import parametrize_directives
+
+from mkdocs_include_markdown_plugin.event import on_page_markdown
+
+
+@parametrize_directives
+@pytest.mark.parametrize('missing_argument', ('start', 'end'))
+def test_start_end_arguments_not_found(
+    directive,
+    missing_argument,
+    page,
+    tmp_path,
+    caplog,
+):
+    included_file_name = 'included.md'
+    includer_file_name = 'includer.md'
+    included_file = tmp_path / included_file_name
+    includer_file = tmp_path / includer_file_name
+
+    includer_content = f'''# Heading
+
+{{%
+  {directive} "{included_file}"
+  comments=false
+  start="<!--start-->"
+  end="<!--end-->"
+%}}
+'''
+    if missing_argument == 'end':
+        included_content = '<!--start-->Included content'
+    else:
+        included_content = 'Included content<!--end-->'
+
+    includer_file.write_text(includer_content)
+    included_file.write_text(included_content)
+
+    expected_result = '''# Heading
+
+Included content
+'''
+
+    assert on_page_markdown(
+        includer_content, page(includer_file), tmp_path,
+    ) == expected_result
+
+    assert (
+        f"Delimiter {missing_argument} '<!--{missing_argument}-->' of"
+        f" '{directive}' directive at {includer_file_name}:3"
+        f' not detected in the file {included_file_name}'
+    ) in caplog.text
diff --git a/tests/test_unit/test_nested_includes.py b/tests/test_unit/test_nested_includes.py
index 9588145..0e81e99 100644
--- a/tests/test_unit/test_nested_includes.py
+++ b/tests/test_unit/test_nested_includes.py
@@ -167,17 +167,19 @@ Some test from final included.
 ''',
             '''# Header
 
+# Header 2
+
 ''',
             [
                 (
                     "Delimiter start '<!--start-->' of 'include-markdown'"
-                    ' directive at {first_includer_filepath}:3 not detected'
-                    ' in the file {second_includer_filepath}'
+                    ' directive at {first_includer_file}:3 not detected'
+                    ' in the file {second_includer_file}'
                 ),
                 (
                     "Delimiter end '<!--end-->' of 'include-markdown'"
-                    ' directive at {first_includer_filepath}:3 not detected'
-                    ' in the file {second_includer_filepath}'
+                    ' directive at {first_includer_file}:3 not detected'
+                    ' in the file {second_includer_file}'
                 ),
             ],
             id='start-end-not-found (first-level)',
@@ -206,17 +208,20 @@ Included content
 
 # Header 2
 
+# Header 3
+
+Included content
 ''',
             [
                 (
                     "Delimiter start '<!--start-->' of 'include-markdown'"
-                    ' directive at {second_includer_filepath}:3 not detected'
-                    ' in the file {included_filepath}'
+                    ' directive at {second_includer_file}:3 not detected'
+                    ' in the file {included_file}'
                 ),
                 (
                     "Delimiter end '<!--end-->' of 'include-markdown'"
-                    ' directive at {second_includer_filepath}:3 not detected'
-                    ' in the file {included_filepath}'
+                    ' directive at {second_includer_file}:3 not detected'
+                    ' in the file {included_file}'
                 ),
             ],
             id='start-end-not-found (second-level)',
@@ -233,38 +238,38 @@ def test_nested_include(
     caplog,
     tmp_path,
 ):
-    first_includer_filepath = tmp_path / 'first-includer.txt'
-    second_includer_filepath = tmp_path / 'second-includer.txt'
-    included_filepath = tmp_path / 'included.txt'
+    first_includer_file = tmp_path / 'first-includer.txt'
+    second_includer_file = tmp_path / 'second-includer.txt'
+    included_file = tmp_path / 'included.txt'
 
     first_includer_content = first_includer_content.replace(
-        '{filepath}', second_includer_filepath.as_posix(),
+        '{filepath}', second_includer_file.as_posix(),
     )
     second_includer_content = second_includer_content.replace(
-        '{filepath}', included_filepath.as_posix(),
+        '{filepath}', included_file.as_posix(),
     )
 
-    first_includer_filepath.write_text(first_includer_content)
-    second_includer_filepath.write_text(second_includer_content)
-    included_filepath.write_text(included_content)
+    first_includer_file.write_text(first_includer_content)
+    second_includer_file.write_text(second_includer_content)
+    included_file.write_text(included_content)
 
     # assert content
     assert on_page_markdown(
-        first_includer_content, page(first_includer_filepath), tmp_path,
+        first_includer_content, page(first_includer_file), tmp_path,
     ) == expected_result
 
     # assert warnings
     expected_warnings_schemas = expected_warnings_schemas or []
     expected_warnings = [
         msg_schema.replace(
-            '{first_includer_filepath}',
-            str(first_includer_filepath.relative_to(tmp_path)),
+            '{first_includer_file}',
+            str(first_includer_file.relative_to(tmp_path)),
         ).replace(
-            '{second_includer_filepath}',
-            str(second_includer_filepath.relative_to(tmp_path)),
+            '{second_includer_file}',
+            str(second_includer_file.relative_to(tmp_path)),
         ).replace(
-            '{included_filepath}',
-            str(included_filepath.relative_to(tmp_path)),
+            '{included_file}',
+            str(included_file.relative_to(tmp_path)),
         ) for msg_schema in expected_warnings_schemas
     ]
 
@@ -277,9 +282,9 @@ def test_nested_include_relpath(page, tmp_path):
     docs_dir = tmp_path / 'docs'
     docs_dir.mkdir()
 
-    first_includer_filepath = tmp_path / 'first-includer.txt'
-    second_includer_filepath = docs_dir / 'second-includer.txt'
-    included_filepath = tmp_path / 'included.txt'
+    first_includer_file = tmp_path / 'first-includer.txt'
+    second_includer_file = docs_dir / 'second-includer.txt'
+    included_file = tmp_path / 'included.txt'
 
     first_includer_content = '''# Header
 
@@ -288,7 +293,7 @@ def test_nested_include_relpath(page, tmp_path):
   comments=false
 %}
 '''
-    first_includer_filepath.write_text(first_includer_content)
+    first_includer_file.write_text(first_includer_content)
 
     second_includer_content = '''Text from second includer.
 
@@ -297,9 +302,9 @@ def test_nested_include_relpath(page, tmp_path):
   comments=false
 %}
 '''
-    second_includer_filepath.write_text(second_includer_content)
+    second_includer_file.write_text(second_includer_content)
 
-    included_filepath.write_text('Included content.')
+    included_file.write_text('Included content.')
 
     expected_result = '''# Header
 
@@ -311,6 +316,6 @@ Included content.
 
     assert on_page_markdown(
         first_includer_content,
-        page(first_includer_filepath),
+        page(first_includer_file),
         docs_dir,
     ) == expected_result