Skip to content

Commit 47f57fb

Browse files
Add new recursive argument to include directive (#208)
* '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 <[email protected]>
1 parent eb65645 commit 47f57fb

File tree

10 files changed

+106
-49
lines changed

10 files changed

+106
-49
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ plugins:
5959
heading_offset: 0
6060
start: <!--start-->
6161
end: <!--end-->
62+
recursive: true
6263
```
6364
6465
#### `opening_tag` and `closing_tag`
@@ -245,6 +246,9 @@ Includes the content of a file or a group of files.
245246
- <a name="include_encoding" href="#include_encoding">#</a>
246247
**encoding** (_utf-8_): Specify the encoding of the included file.
247248
If not defined `utf-8` will be used.
249+
- <a name="recursive" href="#include_recursive">#</a>
250+
**recursive** (_true_): When this option is disabled, included files are not
251+
processed for recursive includes. Possible values are `true` and `false`.
248252

249253
##### Examples
250254

locale/es/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ plugins:
4848
heading_offset: 0
4949
start: <!--start-->
5050
end: <!--end-->
51+
recursive: true
5152
```
5253
5354
#### `opening_tag` y `closing_tag`
@@ -236,6 +237,10 @@ Los valores posibles son `true` y `false`.
236237
- <a name="include_encoding" href="#include_encoding">#</a> **encoding**
237238
(*utf-8*): Especifica la codificación del archivo incluído. Si no se define,
238239
se usará `utf-8`.
240+
- <a name="recursive" href="#include_recursive">#</a> **recursive** (*true*):
241+
Cuando esta opción está deshabilitada, los archivos incluidos no son
242+
procesados para incluir de forma recursiva. Los valores posibles son `true` y
243+
`false`.
239244

240245
##### Ejemplos
241246

locale/es/README.md.po

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,13 @@ msgstr ""
406406

407407
msgid "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin"
408408
msgstr "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin"
409+
410+
msgid ""
411+
"<a name=\"recursive\" href=\"#include_recursive\">#</a> **recursive** "
412+
"(*true*): When this option is disabled, included files are not processed for"
413+
" recursive includes. Possible values are `true` and `false`."
414+
msgstr ""
415+
"<a name=\"recursive\" href=\"#include_recursive\">#</a> **recursive** "
416+
"(*true*): Cuando esta opción está deshabilitada, los archivos incluidos no "
417+
"son procesados para incluir de forma recursiva. Los valores posibles son "
418+
"`true` y `false`."

locale/fr/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ plugins:
4747
heading_offset: 0
4848
start: <!--start-->
4949
end: <!--end-->
50+
recursive: true
5051
```
5152
5253
#### `opening_tag` et `closing_tag`
@@ -235,6 +236,9 @@ valeurs possibles sont `true` et `false`.
235236
- <a name="include_encoding" href="#include_encoding">#</a> **encoding**
236237
(*utf-8*): Spécifiez l'encodage du fichier inclus. S'il n'est pas défini,
237238
`utf-8` sera utilisé.
239+
- <a name="recursive" href="#include_recursive">#</a> **recursive** (*true*):
240+
Lorsque cette option est désactivée, les fichiers inclus ne sont pas traités
241+
pour des inclusions récursives. Les valeurs possibles sont `true` et `false`.
238242

239243
##### Exemples
240244

locale/fr/README.md.po

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,15 @@ msgid ""
402402
msgstr ""
403403
"[Globs génériques Bash]: https://facelessuser.github.io/wcmatch/glob/#syntax"
404404

405-
#, fuzzy
406405
msgid "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin"
407406
msgstr "[pypi-link]: https://pypi.org/project/mkdocs-include-markdown-plugin"
407+
408+
msgid ""
409+
"<a name=\"recursive\" href=\"#include_recursive\">#</a> **recursive** "
410+
"(*true*): When this option is disabled, included files are not processed for"
411+
" recursive includes. Possible values are `true` and `false`."
412+
msgstr ""
413+
"<a name=\"recursive\" href=\"#include_recursive\">#</a> **recursive** "
414+
"(*true*): Lorsque cette option est désactivée, les fichiers inclus ne sont "
415+
"pas traités pour des inclusions récursives. Les valeurs possibles sont "
416+
"`true` et `false`."

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mkdocs-include-markdown-plugin"
3-
version = "6.0.7"
3+
version = "6.1.0"
44
description = "Mkdocs Markdown includer plugin."
55
readme = "README.md"
66
license = "Apache-2.0"

src/mkdocs_include_markdown_plugin/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ class PluginConfig(Config): # noqa: D101
2424
end = Optional(MkType(str))
2525
exclude = ListOfItems(MkType(str), default=[])
2626
cache = MkType(int, default=0)
27+
recursive = MkType(bool, default=True)

src/mkdocs_include_markdown_plugin/directive.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class DirectiveBoolArgument: # noqa: D101
3434
'comments': bool,
3535
'rewrite-relative-urls': bool,
3636
'heading-offset': int,
37+
'recursive': bool,
3738
'start': str | None,
3839
'end': str | None,
3940
},
@@ -96,6 +97,7 @@ def str_arg(arg: str) -> re.Pattern[str]:
9697
'dedent': arg('dedent'),
9798
'trailing-newlines': arg('trailing-newlines'),
9899
'rewrite-relative-urls': arg('rewrite-relative-urls'),
100+
'recursive': arg('recursive'),
99101

100102
# int
101103
'heading-offset': arg('heading-offset'),

src/mkdocs_include_markdown_plugin/event.py

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ def get_file_content( # noqa: PLR0913, PLR0915
103103
http_cache: Cache | None = None,
104104
) -> str:
105105
"""Return the content of the file to include."""
106+
settings_ignore_paths = []
107+
if settings.exclude is not None:
108+
for path in glob.glob(
109+
[
110+
os.path.join(docs_dir, fp)
111+
if not os.path.isabs(fp)
112+
else fp for fp in settings.exclude
113+
],
114+
flags=GLOB_FLAGS,
115+
root_dir=docs_dir,
116+
):
117+
if path not in settings_ignore_paths:
118+
settings_ignore_paths.append(path)
119+
if page_src_path in settings_ignore_paths:
120+
return markdown
121+
106122
def found_include_tag( # noqa: PLR0912, PLR0915
107123
match: re.Match[str],
108124
) -> str:
@@ -125,19 +141,7 @@ def found_include_tag( # noqa: PLR0912, PLR0915
125141
arguments_string = match['arguments']
126142

127143
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
128-
ignore_paths = []
129-
if settings.exclude:
130-
ignore_paths.extend(
131-
glob.glob(
132-
[
133-
os.path.join(docs_dir, fp)
134-
if not os.path.isabs(fp)
135-
else fp for fp in settings.exclude
136-
],
137-
flags=GLOB_FLAGS,
138-
root_dir=docs_dir,
139-
),
140-
)
144+
ignore_paths = [*settings_ignore_paths]
141145
if exclude_match is not None:
142146
exclude_string = parse_string_argument(exclude_match)
143147
if exclude_string is None:
@@ -151,14 +155,13 @@ def found_include_tag( # noqa: PLR0912, PLR0915
151155
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
152156
)
153157

154-
ignore_paths.extend(
155-
resolve_file_paths_to_exclude(
158+
for path in resolve_file_paths_to_exclude(
156159
exclude_string,
157160
page_src_path,
158161
docs_dir,
159-
),
160-
)
161-
ignore_paths = list(set(ignore_paths))
162+
):
163+
if path not in ignore_paths:
164+
ignore_paths.append(path)
162165

163166
file_paths_to_include, is_url = resolve_file_paths_to_include(
164167
filename,
@@ -181,7 +184,8 @@ def found_include_tag( # noqa: PLR0912, PLR0915
181184
files_watcher.included_files.extend(file_paths_to_include)
182185

183186
bool_options, invalid_bool_args = parse_bool_options(
184-
['preserve-includer-indent', 'dedent', 'trailing-newlines'],
187+
['preserve-includer-indent', 'dedent',
188+
'trailing-newlines', 'recursive'],
185189
defaults,
186190
arguments_string,
187191
)
@@ -264,16 +268,17 @@ def found_include_tag( # noqa: PLR0912, PLR0915
264268
expected_but_any_found[i] = False
265269

266270
# nested includes
267-
new_text_to_include = get_file_content(
268-
new_text_to_include,
269-
file_path,
270-
docs_dir,
271-
tags,
272-
defaults,
273-
settings,
274-
files_watcher=files_watcher,
275-
http_cache=http_cache,
276-
)
271+
if bool_options['recursive'].value:
272+
new_text_to_include = get_file_content(
273+
new_text_to_include,
274+
file_path,
275+
docs_dir,
276+
tags,
277+
defaults,
278+
settings,
279+
files_watcher=files_watcher,
280+
http_cache=http_cache,
281+
)
277282

278283
# trailing newlines right stripping
279284
if not bool_options['trailing-newlines'].value:
@@ -349,19 +354,7 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915
349354
arguments_string = match['arguments']
350355

351356
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
352-
ignore_paths = []
353-
if settings.exclude is not None:
354-
ignore_paths.extend(
355-
glob.glob(
356-
[
357-
os.path.join(docs_dir, fp)
358-
if not os.path.isabs(fp)
359-
else fp for fp in settings.exclude
360-
],
361-
flags=GLOB_FLAGS,
362-
root_dir=docs_dir,
363-
),
364-
)
357+
ignore_paths = [*settings_ignore_paths]
365358
if exclude_match is not None:
366359
exclude_string = parse_string_argument(exclude_match)
367360
if exclude_string is None:
@@ -374,14 +367,13 @@ def found_include_markdown_tag( # noqa: PLR0912, PLR0915
374367
f' directive at'
375368
f' {file_lineno_message(page_src_path, docs_dir, lineno)}',
376369
)
377-
ignore_paths.extend(
378-
resolve_file_paths_to_exclude(
370+
for path in resolve_file_paths_to_exclude(
379371
exclude_string,
380372
page_src_path,
381373
docs_dir,
382-
),
383-
)
384-
ignore_paths = list(set(ignore_paths))
374+
):
375+
if path not in ignore_paths:
376+
ignore_paths.append(path)
385377

386378
file_paths_to_include, is_url = resolve_file_paths_to_include(
387379
filename,
@@ -667,6 +659,7 @@ def on_page_markdown(
667659
'comments': config.comments,
668660
'rewrite-relative-urls': config.rewrite_relative_urls,
669661
'heading-offset': config.heading_offset,
662+
'recursive': config.recursive,
670663
'start': config.start,
671664
'end': config.end,
672665
},

tests/test_unit/test_nested_includes.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,32 @@
226226
],
227227
id='start-end-not-found (second-level)',
228228
),
229+
# recursive inclusion disabled with `include` directive
230+
pytest.param(
231+
'''# Header
232+
233+
{%
234+
include "{filepath}"
235+
comments=false
236+
recursive=false
237+
%}''',
238+
'''# Header 2
239+
240+
{% include "{filepath}" %}
241+
''',
242+
'''# Header 3
243+
244+
This content must not be included.
245+
''',
246+
'''# Header
247+
248+
# Header 2
249+
250+
{% include "{filepath}" %}
251+
''',
252+
[],
253+
id='include-recursive=false',
254+
),
229255
),
230256
)
231257
def test_nested_include(
@@ -249,6 +275,9 @@ def test_nested_include(
249275
second_includer_content = second_includer_content.replace(
250276
'{filepath}', included_file.as_posix(),
251277
)
278+
expected_result = expected_result.replace(
279+
'{filepath}', included_file.as_posix(),
280+
)
252281

253282
first_includer_file.write_text(first_includer_content)
254283
second_includer_file.write_text(second_includer_content)

0 commit comments

Comments
 (0)