From 47f57fb27b4ea57c28dae240edf3ebe1d9f7ecd6 Mon Sep 17 00:00:00 2001 From: carlocastoldi <34198340+carlocastoldi@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:27:38 +0200 Subject: [PATCH] Add new `recursive` argument to `include` directive (#208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 'recursive' option added * exclude directive now avoids processing the desired files all together * add recursive description in README * Add translations * Add test * Refactor * Revert change in order of execution of directives * Add recursive to global config in documentation * Bump version --------- Co-authored-by: Álvaro Mondéjar Rubio --- README.md | 4 + locale/es/README.md | 5 ++ locale/es/README.md.po | 10 +++ locale/fr/README.md | 4 + locale/fr/README.md.po | 11 ++- pyproject.toml | 2 +- src/mkdocs_include_markdown_plugin/config.py | 1 + .../directive.py | 2 + src/mkdocs_include_markdown_plugin/event.py | 87 +++++++++---------- tests/test_unit/test_nested_includes.py | 29 +++++++ 10 files changed, 106 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index a4130eb..6393c7f 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ plugins: heading_offset: 0 start: end: + recursive: true ``` #### `opening_tag` and `closing_tag` @@ -245,6 +246,9 @@ Includes the content of a file or a group of files. - # **encoding** (_utf-8_): Specify the encoding of the included file. If not defined `utf-8` will be used. +- # + **recursive** (_true_): When this option is disabled, included files are not + processed for recursive includes. Possible values are `true` and `false`. ##### Examples diff --git a/locale/es/README.md b/locale/es/README.md index 006c8af..fd93fa1 100644 --- a/locale/es/README.md +++ b/locale/es/README.md @@ -48,6 +48,7 @@ plugins: heading_offset: 0 start: end: + recursive: true ``` #### `opening_tag` y `closing_tag` @@ -236,6 +237,10 @@ Los valores posibles son `true` y `false`. - # **encoding** (*utf-8*): Especifica la codificación del archivo incluído. Si no se define, se usará `utf-8`. +- # **recursive** (*true*): +Cuando esta opción está deshabilitada, los archivos incluidos no son +procesados para incluir de forma recursiva. Los valores posibles son `true` y +`false`. ##### Ejemplos diff --git a/locale/es/README.md.po b/locale/es/README.md.po index 6cb4a9e..fa593f6 100644 --- a/locale/es/README.md.po +++ b/locale/es/README.md.po @@ -406,3 +406,13 @@ msgstr "" msgid "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin" msgstr "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin" + +msgid "" +"# **recursive** " +"(*true*): When this option is disabled, included files are not processed for" +" recursive includes. Possible values are `true` and `false`." +msgstr "" +"# **recursive** " +"(*true*): Cuando esta opción está deshabilitada, los archivos incluidos no " +"son procesados para incluir de forma recursiva. Los valores posibles son " +"`true` y `false`." diff --git a/locale/fr/README.md b/locale/fr/README.md index 2caeee1..6237c73 100644 --- a/locale/fr/README.md +++ b/locale/fr/README.md @@ -47,6 +47,7 @@ plugins: heading_offset: 0 start: end: + recursive: true ``` #### `opening_tag` et `closing_tag` @@ -235,6 +236,9 @@ valeurs possibles sont `true` et `false`. - # **encoding** (*utf-8*): Spécifiez l'encodage du fichier inclus. S'il n'est pas défini, `utf-8` sera utilisé. +- # **recursive** (*true*): +Lorsque cette option est désactivée, les fichiers inclus ne sont pas traités +pour des inclusions récursives. Les valeurs possibles sont `true` et `false`. ##### Exemples diff --git a/locale/fr/README.md.po b/locale/fr/README.md.po index 20c3964..dd59dfa 100644 --- a/locale/fr/README.md.po +++ b/locale/fr/README.md.po @@ -402,6 +402,15 @@ msgid "" msgstr "" "[Globs génériques Bash]: https://facelessuser.github.io/wcmatch/glob/#syntax" -#, fuzzy msgid "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin" msgstr "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin" + +msgid "" +"# **recursive** " +"(*true*): When this option is disabled, included files are not processed for" +" recursive includes. Possible values are `true` and `false`." +msgstr "" +"# **recursive** " +"(*true*): Lorsque cette option est désactivée, les fichiers inclus ne sont " +"pas traités pour des inclusions récursives. Les valeurs possibles sont " +"`true` et `false`." diff --git a/pyproject.toml b/pyproject.toml index 32ddb17..573a040 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mkdocs-include-markdown-plugin" -version = "6.0.7" +version = "6.1.0" description = "Mkdocs Markdown includer plugin." readme = "README.md" license = "Apache-2.0" diff --git a/src/mkdocs_include_markdown_plugin/config.py b/src/mkdocs_include_markdown_plugin/config.py index 251f55c..a633428 100644 --- a/src/mkdocs_include_markdown_plugin/config.py +++ b/src/mkdocs_include_markdown_plugin/config.py @@ -24,3 +24,4 @@ class PluginConfig(Config): # noqa: D101 end = Optional(MkType(str)) exclude = ListOfItems(MkType(str), default=[]) cache = MkType(int, default=0) + recursive = MkType(bool, default=True) diff --git a/src/mkdocs_include_markdown_plugin/directive.py b/src/mkdocs_include_markdown_plugin/directive.py index 4c8a432..89e0f17 100644 --- a/src/mkdocs_include_markdown_plugin/directive.py +++ b/src/mkdocs_include_markdown_plugin/directive.py @@ -34,6 +34,7 @@ class DirectiveBoolArgument: # noqa: D101 'comments': bool, 'rewrite-relative-urls': bool, 'heading-offset': int, + 'recursive': bool, 'start': str | None, 'end': str | None, }, @@ -96,6 +97,7 @@ def str_arg(arg: str) -> re.Pattern[str]: 'dedent': arg('dedent'), 'trailing-newlines': arg('trailing-newlines'), 'rewrite-relative-urls': arg('rewrite-relative-urls'), + 'recursive': arg('recursive'), # int 'heading-offset': arg('heading-offset'), diff --git a/src/mkdocs_include_markdown_plugin/event.py b/src/mkdocs_include_markdown_plugin/event.py index f390c92..d284ac1 100644 --- a/src/mkdocs_include_markdown_plugin/event.py +++ b/src/mkdocs_include_markdown_plugin/event.py @@ -103,6 +103,22 @@ def get_file_content( # noqa: PLR0913, PLR0915 http_cache: Cache | None = None, ) -> str: """Return the content of the file to include.""" + settings_ignore_paths = [] + if settings.exclude is not None: + for path in glob.glob( + [ + os.path.join(docs_dir, fp) + if not os.path.isabs(fp) + else fp for fp in settings.exclude + ], + flags=GLOB_FLAGS, + root_dir=docs_dir, + ): + if path not in settings_ignore_paths: + settings_ignore_paths.append(path) + if page_src_path in settings_ignore_paths: + return markdown + def found_include_tag( # noqa: PLR0912, PLR0915 match: re.Match[str], ) -> str: @@ -125,19 +141,7 @@ def found_include_tag( # noqa: PLR0912, PLR0915 arguments_string = match['arguments'] exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string) - ignore_paths = [] - if settings.exclude: - ignore_paths.extend( - glob.glob( - [ - os.path.join(docs_dir, fp) - if not os.path.isabs(fp) - else fp for fp in settings.exclude - ], - flags=GLOB_FLAGS, - root_dir=docs_dir, - ), - ) + ignore_paths = [*settings_ignore_paths] if exclude_match is not None: exclude_string = parse_string_argument(exclude_match) if exclude_string is None: @@ -151,14 +155,13 @@ def found_include_tag( # noqa: PLR0912, PLR0915 f' {file_lineno_message(page_src_path, docs_dir, lineno)}', ) - ignore_paths.extend( - resolve_file_paths_to_exclude( + for path in resolve_file_paths_to_exclude( exclude_string, page_src_path, docs_dir, - ), - ) - ignore_paths = list(set(ignore_paths)) + ): + if path not in ignore_paths: + ignore_paths.append(path) file_paths_to_include, is_url = resolve_file_paths_to_include( filename, @@ -181,7 +184,8 @@ def found_include_tag( # noqa: PLR0912, PLR0915 files_watcher.included_files.extend(file_paths_to_include) bool_options, invalid_bool_args = parse_bool_options( - ['preserve-includer-indent', 'dedent', 'trailing-newlines'], + ['preserve-includer-indent', 'dedent', + 'trailing-newlines', 'recursive'], defaults, arguments_string, ) @@ -264,16 +268,17 @@ def found_include_tag( # noqa: PLR0912, PLR0915 expected_but_any_found[i] = False # nested includes - new_text_to_include = get_file_content( - new_text_to_include, - file_path, - docs_dir, - tags, - defaults, - settings, - files_watcher=files_watcher, - http_cache=http_cache, - ) + if bool_options['recursive'].value: + new_text_to_include = get_file_content( + new_text_to_include, + file_path, + docs_dir, + tags, + defaults, + settings, + files_watcher=files_watcher, + http_cache=http_cache, + ) # trailing newlines right stripping if not bool_options['trailing-newlines'].value: @@ -349,19 +354,7 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915 arguments_string = match['arguments'] exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string) - ignore_paths = [] - if settings.exclude is not None: - ignore_paths.extend( - glob.glob( - [ - os.path.join(docs_dir, fp) - if not os.path.isabs(fp) - else fp for fp in settings.exclude - ], - flags=GLOB_FLAGS, - root_dir=docs_dir, - ), - ) + ignore_paths = [*settings_ignore_paths] if exclude_match is not None: exclude_string = parse_string_argument(exclude_match) if exclude_string is None: @@ -374,14 +367,13 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915 f' directive at' f' {file_lineno_message(page_src_path, docs_dir, lineno)}', ) - ignore_paths.extend( - resolve_file_paths_to_exclude( + for path in resolve_file_paths_to_exclude( exclude_string, page_src_path, docs_dir, - ), - ) - ignore_paths = list(set(ignore_paths)) + ): + if path not in ignore_paths: + ignore_paths.append(path) file_paths_to_include, is_url = resolve_file_paths_to_include( filename, @@ -667,6 +659,7 @@ def on_page_markdown( 'comments': config.comments, 'rewrite-relative-urls': config.rewrite_relative_urls, 'heading-offset': config.heading_offset, + 'recursive': config.recursive, 'start': config.start, 'end': config.end, }, diff --git a/tests/test_unit/test_nested_includes.py b/tests/test_unit/test_nested_includes.py index c2689c4..bd77777 100644 --- a/tests/test_unit/test_nested_includes.py +++ b/tests/test_unit/test_nested_includes.py @@ -226,6 +226,32 @@ ], id='start-end-not-found (second-level)', ), + # recursive inclusion disabled with `include` directive + pytest.param( + '''# Header + +{% + include "{filepath}" + comments=false + recursive=false +%}''', + '''# Header 2 + +{% include "{filepath}" %} +''', + '''# Header 3 + +This content must not be included. +''', + '''# Header + +# Header 2 + +{% include "{filepath}" %} +''', + [], + id='include-recursive=false', + ), ), ) def test_nested_include( @@ -249,6 +275,9 @@ def test_nested_include( second_includer_content = second_includer_content.replace( '{filepath}', included_file.as_posix(), ) + expected_result = expected_result.replace( + '{filepath}', included_file.as_posix(), + ) first_includer_file.write_text(first_includer_content) second_includer_file.write_text(second_includer_content)