Repository: mondeja/mkdocs-include-markdown-plugin
Pull request #180 (2023-10-13 14:39:22)

Refactor to use new static type checking features
* Use class-based config and attributes from MkDocs 1.4
* Use dataclass from Python 3.8
* Refactor: put runtime attributes onto the plugin rather than onto the config - also statically typed

Extra: actually depend on MkDocs, it is a dependency



Patch:
diff --git a/README.md b/README.md
index ee959a5..e03d046 100644
--- a/README.md
+++ b/README.md
@@ -277,8 +277,8 @@ Includes the content of a file or a group of files.
 [license-image]: https://img.shields.io/pypi/l/mkdocs-include-markdown-plugin?color=light-green&logo=apache&logoColor=white
 [license-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/LICENSE
 [platformdirs]: https://pypi.org/project/platformdirs/
-[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470
-[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel
+[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470
+[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel
 [es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/es/README.md
 [fr-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/fr/README.md
 [Bash wildcard globs]: https://facelessuser.github.io/wcmatch/glob/#syntax
diff --git a/locale/es/README.md b/locale/es/README.md
index 71e6460..d6e6970 100644
--- a/locale/es/README.md
+++ b/locale/es/README.md
@@ -266,8 +266,8 @@ separar este plugin de la documentación de
 [license-image]: https://img.shields.io/pypi/l/mkdocs-include-markdown-plugin?color=light-green&logo=apache&logoColor=white
 [license-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/LICENSE
 [platformdirs]: https://pypi.org/project/platformdirs/
-[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470
-[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel
+[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470
+[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel
 [es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/es/README.md
 [fr-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/fr/README.md
 [Bash wildcard globs]: https://facelessuser.github.io/wcmatch/glob/#syntax
diff --git a/locale/es/README.md.po b/locale/es/README.md.po
index 8aead37..91d6bf7 100644
--- a/locale/es/README.md.po
+++ b/locale/es/README.md.po
@@ -56,12 +56,11 @@ msgstr ""
 "[tests-link]: https://github.com/mondeja/mkdocs-include-markdown-"
 "plugin/actions?query=workflow%3ACI"
 
-msgid "[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470"
-msgstr ""
-"[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470"
+msgid "[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470"
+msgstr "[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470"
 
-msgid "[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel"
-msgstr "[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel"
+msgid "[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel"
+msgstr "[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel"
 
 msgid "Read this document in other languages:"
 msgstr "Lee este documento en otros idiomas:"
diff --git a/locale/fr/README.md b/locale/fr/README.md
index d9fba28..967ea62 100644
--- a/locale/fr/README.md
+++ b/locale/fr/README.md
@@ -263,8 +263,8 @@ autorisations][cibuildwheel-470] pour séparer ce plugin de la documentation de
 [license-image]: https://img.shields.io/pypi/l/mkdocs-include-markdown-plugin?color=light-green&logo=apache&logoColor=white
 [license-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/LICENSE
 [platformdirs]: https://pypi.org/project/platformdirs/
-[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470
-[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel
+[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470
+[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel
 [es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/es/README.md
 [fr-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-plugin/blob/master/locale/fr/README.md
 [Bash wildcard globs]: https://facelessuser.github.io/wcmatch/glob/#syntax
diff --git a/locale/fr/README.md.po b/locale/fr/README.md.po
index 7752807..5717d02 100644
--- a/locale/fr/README.md.po
+++ b/locale/fr/README.md.po
@@ -69,12 +69,11 @@ msgstr ""
 "[tests-link]: https://github.com/mondeja/mkdocs-include-markdown-"
 "plugin/actions?query=workflow%3ACI"
 
-msgid "[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470"
-msgstr ""
-"[cibuildwheel-470]: https://github.com/joerick/cibuildwheel/issues/470"
+msgid "[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470"
+msgstr "[cibuildwheel-470]: https://github.com/pypa/cibuildwheel/issues/470"
 
-msgid "[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel"
-msgstr "[cibuildwheel-repo-link]: https://github.com/joerick/cibuildwheel"
+msgid "[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel"
+msgstr "[cibuildwheel-repo-link]: https://github.com/pypa/cibuildwheel"
 
 msgid ""
 "[es-readme-link]: https://github.com/mondeja/mkdocs-include-markdown-"
diff --git a/pyproject.toml b/pyproject.toml
index 9dc10b0..1a02bb8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,7 +22,10 @@ classifiers = [
   "Programming Language :: Python :: 3.12"
 ]
 keywords = ["markdown", "mkdocs", "includer", "plugin"]
-dependencies = ["wcmatch>=8,<9"]
+dependencies = [
+  "mkdocs>=1.4",
+  "wcmatch>=8,<9"
+]
 
 [[project.authors]]
 name = "Joe Rickerby"
diff --git a/src/mkdocs_include_markdown_plugin/config.py b/src/mkdocs_include_markdown_plugin/config.py
index 6bd5d58..251f55c 100644
--- a/src/mkdocs_include_markdown_plugin/config.py
+++ b/src/mkdocs_include_markdown_plugin/config.py
@@ -2,6 +2,7 @@
 
 from __future__ import annotations
 
+from mkdocs.config.base import Config
 from mkdocs.config.config_options import (
     ListOfItems,
     Optional,
@@ -9,73 +10,17 @@ from mkdocs.config.config_options import (
 )
 
 
-CONFIG_DEFAULTS = {
-    'opening-tag': '{%',
-    'closing-tag': '%}',
-    'encoding': 'utf-8',
-    'preserve-includer-indent': True,
-    'dedent': False,
-    'trailing-newlines': True,
-    'comments': True,
-    'rewrite-relative-urls': True,
-    'heading-offset': 0,
-    'start': None,
-    'end': None,
-    'exclude': None,
-    'cache': 0,
-}
-
-CONFIG_SCHEME = (
-    (
-        'opening_tag',
-        MkType(str, default=CONFIG_DEFAULTS['opening-tag']),
-    ),
-    (
-        'closing_tag',
-        MkType(str, default=CONFIG_DEFAULTS['closing-tag']),
-    ),
-    (
-        'encoding',
-        MkType(str, default=CONFIG_DEFAULTS['encoding']),
-    ),
-    (
-        'preserve_includer_indent',
-        MkType(bool, default=CONFIG_DEFAULTS['preserve-includer-indent']),
-    ),
-    (
-        'dedent',
-        MkType(bool, default=CONFIG_DEFAULTS['dedent']),
-    ),
-    (
-        'trailing_newlines',
-        MkType(bool, default=CONFIG_DEFAULTS['trailing-newlines']),
-    ),
-    (
-        'comments',
-        MkType(bool, default=CONFIG_DEFAULTS['comments']),
-    ),
-    (
-        'rewrite_relative_urls',
-        MkType(bool, default=CONFIG_DEFAULTS['rewrite-relative-urls']),
-    ),
-    (
-        'heading_offset',
-        MkType(int, default=CONFIG_DEFAULTS['heading-offset']),
-    ),
-    (
-        'start',
-        MkType(str, default=CONFIG_DEFAULTS['start']),
-    ),
-    (
-        'end',
-        MkType(str, default=CONFIG_DEFAULTS['end']),
-    ),
-    (
-        'exclude',
-        Optional(ListOfItems(MkType(str))),
-    ),
-    (
-        'cache',
-        MkType(int, default=CONFIG_DEFAULTS['cache']),
-    ),
-)
+class PluginConfig(Config):  # noqa: D101
+    opening_tag = MkType(str, default='{%')
+    closing_tag = MkType(str, default='%}')
+    encoding = MkType(str, default='utf-8')
+    preserve_includer_indent = MkType(bool, default=True)
+    dedent = MkType(bool, default=False)
+    trailing_newlines = MkType(bool, default=True)
+    comments = MkType(bool, default=True)
+    rewrite_relative_urls = MkType(bool, default=True)
+    heading_offset = MkType(int, default=0)
+    start = Optional(MkType(str))
+    end = Optional(MkType(str))
+    exclude = ListOfItems(MkType(str), default=[])
+    cache = MkType(int, default=0)
diff --git a/src/mkdocs_include_markdown_plugin/directive.py b/src/mkdocs_include_markdown_plugin/directive.py
index f14ec7a..c1efaba 100644
--- a/src/mkdocs_include_markdown_plugin/directive.py
+++ b/src/mkdocs_include_markdown_plugin/directive.py
@@ -5,6 +5,7 @@ from __future__ import annotations
 import os
 import re
 import string
+from dataclasses import dataclass
 from typing import TYPE_CHECKING
 
 from wcmatch import glob
@@ -12,13 +13,15 @@ from wcmatch import glob
 from mkdocs_include_markdown_plugin import process
 
 
+@dataclass
+class DirectiveBoolArgument:  # noqa: D101
+    value: bool
+    regex: re.Pattern[str]
+
+
 if TYPE_CHECKING:
     from typing import TypedDict
 
-    class DirectiveBoolArgument(TypedDict):  # noqa: D101
-        value: bool
-        regex: re.Pattern[str]
-
     DirectiveBoolArgumentsDict = dict[str, DirectiveBoolArgument]
 
     DefaultValues = TypedDict(
@@ -30,8 +33,8 @@ if TYPE_CHECKING:
             'comments': bool,
             'rewrite-relative-urls': bool,
             'heading-offset': int,
-            'start': str,
-            'end': str,
+            'start': str | None,
+            'end': str | None,
         },
     )
 
@@ -102,9 +105,9 @@ def parse_filename_argument(
         match: re.Match[str],
 ) -> tuple[str | None, str | None]:
     """Return filename argument matched by ``match``."""
-    raw_filename = match.group('double_quoted_filename')
+    raw_filename = match['double_quoted_filename']
     if raw_filename is None:
-        raw_filename = match.group('single_quoted_filename')
+        raw_filename = match['single_quoted_filename']
         if raw_filename is None:
             filename = None
         else:
@@ -116,9 +119,9 @@ def parse_filename_argument(
 
 def parse_string_argument(match: re.Match[str]) -> str | None:
     """Return the string argument matched by ``match``."""
-    value = match.group(1)
+    value = match[1]
     if value is None:
-        value = match.group(3)
+        value = match[3]
         if value is not None:
             value = value.replace("\\'", "'")
     else:
@@ -152,20 +155,18 @@ def parse_bool_options(
 
     bool_options: dict[str, DirectiveBoolArgument] = {}
     for option_name in option_names:
-        bool_options[option_name] = {
-            'value': defaults[option_name],  # type: ignore
-            'regex': ARGUMENT_REGEXES[option_name],
-        }
+        bool_options[option_name] = DirectiveBoolArgument(
+            value=defaults[option_name],  # type: ignore
+            regex=ARGUMENT_REGEXES[option_name],
+        )
 
     for arg_name, arg in bool_options.items():
-        bool_arg_match = arg['regex'].search(arguments_string)
+        bool_arg_match = arg.regex.search(arguments_string)
         if bool_arg_match is None:
             continue
         try:
-            bool_options[arg_name]['value'] = TRUE_FALSE_STR_BOOL[
-                bool_arg_match.group(
-                    1,
-                ) or TRUE_FALSE_BOOL_STR[arg['value']]
+            bool_options[arg_name].value = TRUE_FALSE_STR_BOOL[
+                bool_arg_match[1] or TRUE_FALSE_BOOL_STR[arg.value]
             ]
         except KeyError:
             invalid_args.append(arg_name)
diff --git a/src/mkdocs_include_markdown_plugin/event.py b/src/mkdocs_include_markdown_plugin/event.py
index 99b19fd..0867642 100644
--- a/src/mkdocs_include_markdown_plugin/event.py
+++ b/src/mkdocs_include_markdown_plugin/event.py
@@ -7,19 +7,17 @@ import logging
 import os
 import re
 import textwrap
-from collections.abc import MutableMapping
-from typing import TYPE_CHECKING, Any
+from dataclasses import dataclass
+from typing import TYPE_CHECKING
 
 from mkdocs.exceptions import PluginError
 from wcmatch import glob
 
 from mkdocs_include_markdown_plugin import process
 from mkdocs_include_markdown_plugin.cache import Cache
-from mkdocs_include_markdown_plugin.config import CONFIG_DEFAULTS
 from mkdocs_include_markdown_plugin.directive import (
     ARGUMENT_REGEXES,
     GLOB_FLAGS,
-    create_include_tag,
     parse_bool_options,
     parse_filename_argument,
     parse_string_argument,
@@ -35,6 +33,7 @@ if TYPE_CHECKING:  # remove this for mypyc compiling
     from mkdocs.structure.pages import Page
 
     from mkdocs_include_markdown_plugin.directive import DefaultValues
+    from mkdocs_include_markdown_plugin.plugin import IncludeMarkdownPlugin
 
     IncludeTags = TypedDict(
         'IncludeTags', {
@@ -43,8 +42,10 @@ if TYPE_CHECKING:  # remove this for mypyc compiling
         },
     )
 
-    class Settings(TypedDict):  # noqa: D101
-        exclude: list[str] | None
+
+@dataclass
+class Settings:  # noqa: D101
+    exclude: list[str] | None
 
 
 logger = logging.getLogger('mkdocs.plugins.mkdocs_include_markdown_plugin')
@@ -72,7 +73,7 @@ def get_file_content(  # noqa: PLR0913, PLR0915
     ) -> str:
         directive_match_start = match.start()
 
-        includer_indent = match.group('_includer_indent')
+        includer_indent = match['_includer_indent']
 
         filename, raw_filename = parse_filename_argument(match)
         if filename is None:
@@ -86,17 +87,17 @@ def get_file_content(  # noqa: PLR0913, PLR0915
                 f':{lineno}',
             )
 
-        arguments_string = match.group('arguments')
+        arguments_string = match['arguments']
 
         exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
         ignore_paths = []
-        if settings['exclude'] is not None:
+        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']
+                        else fp for fp in settings.exclude
                     ],
                     flags=GLOB_FLAGS,
                     root_dir=docs_dir,
@@ -240,16 +241,16 @@ def get_file_content(  # noqa: PLR0913, PLR0915
             )
 
             # trailing newlines right stripping
-            if not bool_options['trailing-newlines']['value']:
+            if not bool_options['trailing-newlines'].value:
                 new_text_to_include = process.rstrip_trailing_newlines(
                     new_text_to_include,
                 )
 
-            if bool_options['dedent']['value']:
+            if bool_options['dedent'].value:
                 new_text_to_include = textwrap.dedent(new_text_to_include)
 
             # includer indentation preservation
-            if bool_options['preserve-includer-indent']['value']:
+            if bool_options['preserve-includer-indent'].value:
                 new_text_to_include = ''.join(
                     includer_indent + line
                     for line in (
@@ -304,7 +305,7 @@ def get_file_content(  # noqa: PLR0913, PLR0915
     ) -> str:
         directive_match_start = match.start()
 
-        includer_indent = match.group('_includer_indent')
+        includer_indent = match['_includer_indent']
         empty_includer_indent = ' ' * len(includer_indent)
 
         filename, raw_filename = parse_filename_argument(match)
@@ -319,17 +320,17 @@ def get_file_content(  # noqa: PLR0913, PLR0915
                 f':{lineno}',
             )
 
-        arguments_string = match.group('arguments')
+        arguments_string = match['arguments']
 
         exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
         ignore_paths = []
-        if settings['exclude'] is not None:
+        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']
+                        else fp for fp in settings.exclude
                     ],
                     flags=GLOB_FLAGS,
                     root_dir=docs_dir,
@@ -452,7 +453,7 @@ def get_file_content(  # noqa: PLR0913, PLR0915
             arguments_string,
         )
         if offset_match:
-            offset = offset_match.group(1)
+            offset = offset_match[1]
             if offset == '':
                 lineno = lineno_from_content_start(
                     markdown,
@@ -478,7 +479,7 @@ def get_file_content(  # noqa: PLR0913, PLR0915
         else:
             offset = defaults['heading-offset']
 
-        separator = '\n' if bool_options['trailing-newlines']['value'] else ''
+        separator = '\n' if bool_options['trailing-newlines'].value else ''
         if not start and not end:
             start_end_part = ''
         else:
@@ -524,13 +525,13 @@ def get_file_content(  # noqa: PLR0913, PLR0915
             )
 
             # trailing newlines right stripping
-            if not bool_options['trailing-newlines']['value']:
+            if not bool_options['trailing-newlines'].value:
                 new_text_to_include = process.rstrip_trailing_newlines(
                     new_text_to_include,
                 )
 
             # relative URLs rewriting
-            if bool_options['rewrite-relative-urls']['value']:
+            if bool_options['rewrite-relative-urls'].value:
                 new_text_to_include = process.rewrite_relative_urls(
                     new_text_to_include,
                     source_path=file_path,
@@ -538,7 +539,7 @@ def get_file_content(  # noqa: PLR0913, PLR0915
                 )
 
             # comments
-            if bool_options['comments']['value']:
+            if bool_options['comments'].value:
                 new_text_to_include = (
                     f'{includer_indent}'
                     f'<!-- BEGIN INCLUDE {html.escape(filename)}'
@@ -551,11 +552,11 @@ def get_file_content(  # noqa: PLR0913, PLR0915
                 )
 
             # dedent
-            if bool_options['dedent']['value']:
+            if bool_options['dedent'].value:
                 new_text_to_include = textwrap.dedent(new_text_to_include)
 
             # includer indentation preservation
-            if bool_options['preserve-includer-indent']['value']:
+            if bool_options['preserve-includer-indent'].value:
                 new_text_to_include = ''.join(
                     (empty_includer_indent if i > 0 else '') + line
                     for i, line in enumerate(
@@ -623,64 +624,33 @@ def on_page_markdown(
         markdown: str,
         page: Page,
         docs_dir: str,
-        config: MutableMapping[str, Any] | None = None,
+        plugin: IncludeMarkdownPlugin,
         http_cache: Cache | None = None,
 ) -> str:
     """Process markdown content of a page."""
-    if config is None:
-        config = {
-            '_files_watcher': None,
-        }
-    elif '_files_watcher' not in config:
-        config['_files_watcher'] = None
-
+    config = plugin.config
     return get_file_content(
         markdown,
         page.file.abs_src_path,
         docs_dir,
         {
-            'include': config.get(
-                '_include_tag',
-                create_include_tag(
-                    config.get('opening_tag', CONFIG_DEFAULTS['opening-tag']),
-                    config.get('closing_tag', CONFIG_DEFAULTS['closing-tag']),
-                ),
-            ),
-            'include-markdown': config.get(
-                '_include_markdown_tag',
-                create_include_tag(
-                    config.get('opening_tag', CONFIG_DEFAULTS['opening-tag']),
-                    config.get('closing_tag', CONFIG_DEFAULTS['closing-tag']),
-                    tag='include-markdown',
-                ),
-            ),
-        },
-        {
-            'encoding': config.get('encoding', CONFIG_DEFAULTS['encoding']),
-            'preserve-includer-indent': config.get(
-                'preserve_includer_indent',
-                CONFIG_DEFAULTS['preserve-includer-indent'],
-            ),
-            'dedent': config.get('dedent', CONFIG_DEFAULTS['dedent']),
-            'trailing-newlines': config.get(
-                'trailing_newlines',
-                CONFIG_DEFAULTS['trailing-newlines'],
-            ),
-            'comments': config.get('comments', CONFIG_DEFAULTS['comments']),
-            'rewrite-relative-urls': config.get(
-                'rewrite_relative_urls',
-                CONFIG_DEFAULTS['rewrite-relative-urls'],
-            ),
-            'heading-offset': config.get(
-                'heading_offset',
-                CONFIG_DEFAULTS['heading-offset'],
-            ),
-            'start': config.get('start', CONFIG_DEFAULTS['start']),
-            'end': config.get('end', CONFIG_DEFAULTS['end']),
+            'include': plugin._include_tag,
+            'include-markdown': plugin._include_markdown_tag,
         },
         {
-            'exclude': config.get('exclude', CONFIG_DEFAULTS['exclude']),
+            'encoding': config.encoding,
+            'preserve-includer-indent': config.preserve_includer_indent,
+            'dedent': config.dedent,
+            'trailing-newlines': config.trailing_newlines,
+            'comments': config.comments,
+            'rewrite-relative-urls': config.rewrite_relative_urls,
+            'heading-offset': config.heading_offset,
+            'start': config.start,
+            'end': config.end,
         },
-        files_watcher=config['_files_watcher'],
-        http_cache=config.get('_cache', http_cache),
+        Settings(
+            exclude=config.exclude,
+        ),
+        files_watcher=plugin._files_watcher,
+        http_cache=plugin._cache or http_cache,
     )
diff --git a/src/mkdocs_include_markdown_plugin/plugin.py b/src/mkdocs_include_markdown_plugin/plugin.py
index db90e25..65eabe0 100644
--- a/src/mkdocs_include_markdown_plugin/plugin.py
+++ b/src/mkdocs_include_markdown_plugin/plugin.py
@@ -3,6 +3,7 @@
 from __future__ import annotations
 
 from collections.abc import Callable
+from functools import cached_property
 from typing import TYPE_CHECKING, Any
 
 from mkdocs.exceptions import PluginError
@@ -11,12 +12,14 @@ from mkdocs.plugins import BasePlugin, event_priority
 
 
 if TYPE_CHECKING:
+    import re
+
     from mkdocs.config.defaults import MkDocsConfig
     from mkdocs.structure.files import Files
     from mkdocs.structure.pages import Page
 
-from mkdocs_include_markdown_plugin.cache import initialize_cache
-from mkdocs_include_markdown_plugin.config import CONFIG_SCHEME
+from mkdocs_include_markdown_plugin.cache import Cache, initialize_cache
+from mkdocs_include_markdown_plugin.config import PluginConfig
 from mkdocs_include_markdown_plugin.directive import create_include_tag
 from mkdocs_include_markdown_plugin.event import (
     on_page_markdown as _on_page_markdown,
@@ -24,23 +27,13 @@ from mkdocs_include_markdown_plugin.event import (
 from mkdocs_include_markdown_plugin.files_watcher import FilesWatcher
 
 
-class IncludeMarkdownPlugin(BasePlugin):
-    config_scheme = CONFIG_SCHEME
+class IncludeMarkdownPlugin(BasePlugin[PluginConfig]):
+    _cache: Cache | None = None
+    _server: LiveReloadServer | None = None
 
     def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
-        self.config['_include_tag'] = create_include_tag(
-            self.config['opening_tag'],
-            self.config['closing_tag'],
-        )
-
-        self.config['_include_markdown_tag'] = create_include_tag(
-            self.config['opening_tag'],
-            self.config['closing_tag'],
-            tag='include-markdown',
-        )
-
-        if self.config['cache'] > 0:
-            cache = initialize_cache(self.config['cache'])
+        if self.config.cache > 0:
+            cache = initialize_cache(self.config.cache)
             if cache is None:
                 raise PluginError(
                     'The "platformdirs" package is required to use the'
@@ -49,26 +42,44 @@ class IncludeMarkdownPlugin(BasePlugin):
                     ' extra to install it.',
                 )
             cache.clean()
-            self.config['_cache'] = cache
-
-        self.config['_files_watcher'] = None
-        self.config['_server'] = None
+            self._cache = cache
 
         return config
 
+    @cached_property
+    def _include_tag(self) -> re.Pattern[str]:
+        return create_include_tag(
+            self.config.opening_tag,
+            self.config.closing_tag,
+        )
+
+    @cached_property
+    def _include_markdown_tag(self) -> re.Pattern[str]:
+        return create_include_tag(
+            self.config.opening_tag,
+            self.config.closing_tag,
+            tag='include-markdown',
+        )
+
+    @cached_property
+    def _files_watcher(self) -> FilesWatcher:
+        return FilesWatcher()
+
     def _watch_included_files(self) -> None:  # pragma: no cover
+        assert self._server is not None
+
         # unwatch previous watched files not needed anymore
-        for filepath in self.config['_files_watcher'].prev_included_files:
-            if filepath not in self.config['_files_watcher'].included_files:
-                self.config['_server'].unwatch(filepath)
-        self.config['_files_watcher'].prev_included_files = (
-            self.config['_files_watcher'].included_files[:]
+        for filepath in self._files_watcher.prev_included_files:
+            if filepath not in self._files_watcher.included_files:
+                self._server.unwatch(filepath)
+        self._files_watcher.prev_included_files = (
+            self._files_watcher.included_files[:]
         )
 
         # watch new included files
-        for filepath in self.config['_files_watcher'].included_files:
-            self.config['_server'].watch(filepath, recursive=False)
-        self.config['_files_watcher'].included_files = []
+        for filepath in self._files_watcher.included_files:
+            self._server.watch(filepath, recursive=False)
+        self._files_watcher.included_files = []
 
     def on_page_content(
             self,
@@ -77,7 +88,7 @@ class IncludeMarkdownPlugin(BasePlugin):
             config: MkDocsConfig,  # noqa: ARG002
             files: Files,  # noqa: ARG002
     ) -> str:
-        if self.config['_server'] is not None:  # pragma: no cover
+        if self._server is not None:  # pragma: no cover
             self._watch_included_files()
         return html
 
@@ -87,8 +98,8 @@ class IncludeMarkdownPlugin(BasePlugin):
             config: MkDocsConfig,  # noqa: ARG002
             builder: Callable[[Any], Any],  # noqa: ARG002
     ) -> None:
-        if self.config['_server'] is None:  # pragma: no cover
-            self.config['_server'] = server
+        if self._server is None:  # pragma: no cover
+            self._server = server
             self._watch_included_files()
 
     @event_priority(100)
@@ -99,11 +110,9 @@ class IncludeMarkdownPlugin(BasePlugin):
             config: MkDocsConfig,
             files: Files,  # noqa: ARG002
     ) -> str:
-        if self.config['_files_watcher'] is None:
-            self.config['_files_watcher'] = FilesWatcher()
         return _on_page_markdown(
             markdown,
             page,
-            config['docs_dir'],
-            config=self.config,
+            config.docs_dir,
+            plugin=self,
         )
diff --git a/src/mkdocs_include_markdown_plugin/process.py b/src/mkdocs_include_markdown_plugin/process.py
index 6b471c0..d5fd066 100644
--- a/src/mkdocs_include_markdown_plugin/process.py
+++ b/src/mkdocs_include_markdown_plugin/process.py
@@ -240,7 +240,7 @@ def rewrite_relative_urls(
 
     def found_href(m: re.Match[str], url_group_index: int = -1) -> str:
         match_start, match_end = m.span(0)
-        href = m.group(url_group_index)
+        href = m[url_group_index]
         href_start, href_end = m.span(url_group_index)
         rewritten_url = rewrite_url(href)
         return (


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 9da7950..e45aed6 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2,6 +2,7 @@ import os
 import sys
 
 import pytest
+from mkdocs_include_markdown_plugin.plugin import IncludeMarkdownPlugin
 
 
 TESTS_DIR = os.path.abspath(os.path.dirname(__file__))
@@ -23,3 +24,13 @@ def page():
             },
         )
     return _page
+
+
+@pytest.fixture
+def plugin(request):
+    """Populate a plugin, with optional indirect config parameter."""
+    plugin = IncludeMarkdownPlugin()
+    errors, warnings = plugin.load_config(getattr(request, 'param', {}))
+    assert errors == []
+    assert warnings == []
+    return plugin
diff --git a/tests/test_integration/test_cache_integration.py b/tests/test_integration/test_cache_integration.py
index 862d26d..b825316 100644
--- a/tests/test_integration/test_cache_integration.py
+++ b/tests/test_integration/test_cache_integration.py
@@ -41,6 +41,7 @@ def test_page_included_by_url_is_cached(
     expected_result,
     page,
     tmp_path,
+    plugin,
 ):
     cache_dir = get_cache_directory()
     if not CACHE_AVAILABLE:
@@ -64,6 +65,7 @@ def test_page_included_by_url_is_cached(
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
             http_cache=cache,
         )
 
diff --git a/tests/test_unit/test_arguments.py b/tests/test_unit/test_arguments.py
index a8234b4..0d56f18 100644
--- a/tests/test_unit/test_arguments.py
+++ b/tests/test_unit/test_arguments.py
@@ -33,7 +33,14 @@ from testing_helpers import parametrize_directives, unix_only
         ),
     ),
 )
-def test_invalid_bool_arguments(directive, arguments, page, tmp_path, caplog):
+def test_invalid_bool_arguments(
+    directive,
+    arguments,
+    page,
+    tmp_path,
+    plugin,
+    caplog,
+):
     for argument_name in arguments:
         page_to_include_filepath = tmp_path / 'included.md'
         page_to_include_filepath.write_text('Included\n')
@@ -48,6 +55,7 @@ def test_invalid_bool_arguments(directive, arguments, page, tmp_path, caplog):
     %}}''',
                 page(tmp_path / filename),
                 tmp_path,
+                plugin,
             )
         assert str(exc.value) == (
             f"Invalid value for '{argument_name}' argument of '{directive}'"
@@ -57,7 +65,7 @@ def test_invalid_bool_arguments(directive, arguments, page, tmp_path, caplog):
 
 
 @parametrize_directives
-def test_start_end_mixed_quotes(directive, page, caplog, tmp_path):
+def test_start_end_mixed_quotes(directive, page, caplog, tmp_path, plugin):
     page_to_include_filepath = tmp_path / 'included.md'
     page_to_include_filepath.write_text('''Content that should be ignored
 <!-- "s'tar't" -->
@@ -75,6 +83,7 @@ More content that should be ignored
 %}}''',
         page(tmp_path / 'includer.md'),
         tmp_path,
+        plugin,
     )
     assert result == '\nContent to include\n'
 
@@ -89,6 +98,7 @@ def test_invalid_start_end_arguments(
     page,
     caplog,
     tmp_path,
+    plugin,
 ):
     page_to_include_filepath = tmp_path / 'included.md'
     included_content = '''Content that should be ignored
@@ -109,6 +119,7 @@ More content that should be ignored
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
     assert str(exc.value) == (
         f"Invalid empty '{argument}' argument in '{directive}'"
@@ -120,7 +131,7 @@ More content that should be ignored
 
 @unix_only
 @parametrize_directives
-def test_exclude_double_quote_escapes(directive, page, tmp_path):
+def test_exclude_double_quote_escapes(directive, page, tmp_path, plugin):
     drectory_to_include = tmp_path / 'exclude_double_quote_escapes'
     drectory_to_include.mkdir()
 
@@ -142,13 +153,14 @@ def test_exclude_double_quote_escapes(directive, page, tmp_path):
 %}}''',
         page(tmp_path / 'includer.md'),
         tmp_path,
+        plugin,
     )
     assert result == 'Content that should be included\n'
 
 
 @unix_only
 @parametrize_directives
-def test_invalid_exclude_argument(directive, page, tmp_path, caplog):
+def test_invalid_exclude_argument(directive, page, tmp_path, caplog, plugin):
     drectory_to_include = tmp_path / 'exclude_double_quote_escapes'
     drectory_to_include.mkdir()
 
@@ -168,6 +180,7 @@ def test_invalid_exclude_argument(directive, page, tmp_path, caplog):
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
 
     assert len(caplog.records) == 0
@@ -178,7 +191,7 @@ def test_invalid_exclude_argument(directive, page, tmp_path, caplog):
 
 
 @parametrize_directives
-def test_empty_encoding_argument(directive, page, tmp_path, caplog):
+def test_empty_encoding_argument(directive, page, tmp_path, plugin, caplog):
     page_to_include_filepath = tmp_path / 'included.md'
     page_to_include_filepath.write_text('Content to include')
 
@@ -191,6 +204,7 @@ def test_empty_encoding_argument(directive, page, tmp_path, caplog):
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
 
     assert len(caplog.records) == 0
@@ -224,6 +238,7 @@ def test_invalid_heading_offset_arguments(
     exception_message,
     page,
     tmp_path,
+    plugin,
     caplog,
 ):
     page_to_include_filepath = tmp_path / 'included.md'
@@ -238,6 +253,7 @@ def test_invalid_heading_offset_arguments(
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
 
     assert len(caplog.records) == 0
@@ -256,7 +272,7 @@ class TestFilename:
     @parametrize_directives
     @pytest.mark.parametrize('filename', double_quoted_filenames)
     def test_not_escaped_double_quotes(
-        self, directive, filename, page, tmp_path, caplog,
+        self, directive, filename, page, tmp_path, plugin, caplog,
     ):
         page_to_include_filepath = tmp_path / filename
         page_to_include_filepath.write_text('Foo\n')
@@ -266,6 +282,7 @@ class TestFilename:
                 f'{{% {directive} "{page_to_include_filepath}" %}}',
                 page(tmp_path / 'includer.md'),
                 tmp_path,
+                plugin,
             )
 
         assert len(caplog.records) == 0
@@ -278,7 +295,7 @@ class TestFilename:
     @parametrize_directives
     @pytest.mark.parametrize('filename', double_quoted_filenames)
     def test_escaped_double_quotes(
-        self, directive, filename, page, tmp_path,
+        self, directive, filename, page, tmp_path, plugin,
     ):
         included_content = 'Foo\n'
         page_to_include_filepath = tmp_path / filename
@@ -295,13 +312,14 @@ class TestFilename:
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
         assert result == included_content
 
     @parametrize_directives
     @pytest.mark.parametrize('filename', single_quoted_filenames)
     def test_escaped_single_quotes(
-        self, filename, directive, page, tmp_path,
+        self, filename, directive, page, tmp_path, plugin,
     ):
         included_content = 'Foo\n'
         page_to_include_filepath = tmp_path / filename
@@ -318,6 +336,7 @@ class TestFilename:
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
         assert result == included_content
 
@@ -325,7 +344,7 @@ class TestFilename:
     @parametrize_directives
     @pytest.mark.parametrize('filename', double_quoted_filenames)
     def test_unescaped_double_quotes(
-        self, filename, directive, page, tmp_path,
+        self, filename, directive, page, tmp_path, plugin,
     ):
         included_content = 'Foo\n'
         page_to_include_filepath = tmp_path / filename
@@ -338,13 +357,14 @@ class TestFilename:
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
         assert result == included_content
 
     @parametrize_directives
     @pytest.mark.parametrize('filename', single_quoted_filenames)
     def test_unescaped_single_quotes(
-        self, filename, directive, page, tmp_path,
+        self, filename, directive, page, tmp_path, plugin,
     ):
         included_content = 'Foo\n'
         page_to_include_filepath = tmp_path / filename
@@ -357,6 +377,7 @@ class TestFilename:
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
         assert result == included_content
 
@@ -372,7 +393,15 @@ class TestFilename:
         'escape', (True, False), ids=('escape=True', 'escape=False'),
     )
     def test_mixed_quotes(
-        self, filename, quote, escape, directive, page, tmp_path, caplog,
+        self,
+        filename,
+        quote,
+        escape,
+        directive,
+        page,
+        tmp_path,
+        plugin,
+        caplog,
     ):
         included_content = 'Foo\n'
         page_to_include_filepath = tmp_path / filename
@@ -395,6 +424,7 @@ class TestFilename:
             markdown,
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
 
         if escape:
@@ -409,7 +439,7 @@ class TestFilename:
         assert len(caplog.records) == 0
 
     @parametrize_directives
-    def test_no_filename(self, directive, page, tmp_path, caplog):
+    def test_no_filename(self, directive, page, tmp_path, plugin, caplog):
         filename = 'includer.md'
 
         with pytest.raises(PluginError) as exc:
@@ -417,6 +447,7 @@ class TestFilename:
                 f'\n\n{{% {directive} %}}',
                 page(tmp_path / filename),
                 tmp_path,
+                plugin,
             )
 
         assert str(exc.value) == (
@@ -426,7 +457,14 @@ class TestFilename:
         assert len(caplog.records) == 0
 
     @parametrize_directives
-    def test_non_existent_filename(self, directive, page, tmp_path, caplog):
+    def test_non_existent_filename(
+        self,
+        directive,
+        page,
+        tmp_path,
+        plugin,
+        caplog,
+    ):
         page_content = f'''{{%
     {directive} "/path/to/file/that/does/not/exists"
     start="<!--start-here-->"
@@ -441,6 +479,7 @@ class TestFilename:
                 page_content,
                 page(page_filepath),
                 tmp_path,
+                plugin,
             )
 
         assert len(caplog.records) == 0
diff --git a/tests/test_unit/test_config.py b/tests/test_unit/test_config.py
index 54e7079..b93bca7 100644
--- a/tests/test_unit/test_config.py
+++ b/tests/test_unit/test_config.py
@@ -9,7 +9,7 @@ TESTS_ARGUMENTS = (
     'includer_schema',
     'content_to_include',
     'expected_result',
-    'config',
+    'plugin',
 )
 
 
@@ -17,7 +17,7 @@ def _run_test(
     includer_schema,
     content_to_include,
     expected_result,
-    config,
+    plugin,
     page,
     caplog,
     tmp_path,
@@ -47,7 +47,7 @@ def _run_test(
             page_content,
             page(includer_file),
             tmp_path,
-            config,
+            plugin,
         )
         == expected_result
     )
@@ -152,12 +152,13 @@ def _run_test(
             id='custom-comments',
         ),
     ),
+    indirect=['plugin'],
 )
 def test_config_options(
     includer_schema,
     content_to_include,
     expected_result,
-    config,
+    plugin,
     page,
     caplog,
     tmp_path,
@@ -166,7 +167,7 @@ def test_config_options(
         includer_schema,
         content_to_include,
         expected_result,
-        config,
+        plugin,
         page,
         caplog,
         tmp_path,
@@ -193,12 +194,13 @@ def test_config_options(
             id='custom-encoding',
         ),
     ),
+    indirect=['plugin'],
 )
 def test_config_encoding_option(
     includer_schema,
     content_to_include,
     expected_result,
-    config,
+    plugin,
     page,
     caplog,
     tmp_path,
@@ -207,7 +209,7 @@ def test_config_encoding_option(
         includer_schema,
         content_to_include,
         expected_result,
-        config,
+        plugin,
         page,
         caplog,
         tmp_path,
diff --git a/tests/test_unit/test_encoding.py b/tests/test_unit/test_encoding.py
index 932c4a9..65c4e52 100644
--- a/tests/test_unit/test_encoding.py
+++ b/tests/test_unit/test_encoding.py
@@ -4,7 +4,7 @@ from testing_helpers import parametrize_directives, unix_only
 
 
 @parametrize_directives
-def test_encoding(directive, page, tmp_path):
+def test_encoding(directive, page, tmp_path, plugin):
     page_to_include_file = tmp_path / 'included.md'
     page_to_include_file.write_text('''Á
 <!-- start -->
@@ -24,12 +24,13 @@ Content to include
 %}}''',
             page(tmp_path / 'includer.md'),
             tmp_path,
+            plugin,
         )
 
 
 @unix_only
 @parametrize_directives
-def test_default_encoding(directive, page, tmp_path):
+def test_default_encoding(directive, page, tmp_path, plugin):
     page_to_include_file = tmp_path / 'included.md'
     page_to_include_file.write_text('''Á
 <!-- start -->
@@ -47,13 +48,14 @@ Content to include
 %}}''',
         page(tmp_path / 'includer.md'),
         tmp_path,
+        plugin,
     )
     assert result == '\nContent to include\n'
 
 
 @unix_only
 @parametrize_directives
-def test_explicit_default_encoding(directive, page, tmp_path):
+def test_explicit_default_encoding(directive, page, tmp_path, plugin):
     page_to_include_file = tmp_path / 'included.md'
     page_to_include_file.write_text('''Á
 <!-- start -->
@@ -72,5 +74,6 @@ Content to include
 %}}''',
         page(tmp_path / 'includer.md'),
         tmp_path,
+        plugin,
     )
     assert result == '\nContent to include\n'
diff --git a/tests/test_unit/test_exclude.py b/tests/test_unit/test_exclude.py
index 398d2ee..8117588 100644
--- a/tests/test_unit/test_exclude.py
+++ b/tests/test_unit/test_exclude.py
@@ -62,6 +62,7 @@ from testing_helpers import parametrize_directives, unix_only
 def test_exclude(
     page,
     tmp_path,
+    plugin,
     caplog,
     directive,
     filenames,
@@ -95,6 +96,7 @@ def test_exclude(
         includer_file_content,
         page(includer_file),
         includer_folder,
+        plugin,
     )
 
     if expected_result is None:
diff --git a/tests/test_unit/test_glob_include.py b/tests/test_unit/test_glob_include.py
index c6299d2..11aecc9 100644
--- a/tests/test_unit/test_glob_include.py
+++ b/tests/test_unit/test_glob_include.py
@@ -8,7 +8,7 @@ from testing_helpers import parametrize_directives, unix_only
 
 
 @unix_only
-def test_glob_include_absolute(page, tmp_path):
+def test_glob_include_absolute(page, tmp_path, plugin):
     includer_file = tmp_path / 'includer.txt'
     included_01_file = tmp_path / 'included_01.txt'
     included_02_file = tmp_path / 'included_02.txt'
@@ -41,7 +41,7 @@ barbaz
 '''
 
     assert on_page_markdown(
-        includer_file_content, page(includer_file), tmp_path,
+        includer_file_content, page(includer_file), tmp_path, plugin,
     ) == expected_result
 
 
@@ -150,6 +150,7 @@ def test_glob_include(
     page,
     caplog,
     tmp_path,
+    plugin,
 ):
     includer_file = tmp_path / 'includer.txt'
     included_01_file = tmp_path / 'included_01.txt'
@@ -178,7 +179,7 @@ This 02 must appear only without specifying end.
     included_02_file.write_text(included_02_content)
 
     on_page_markdown(
-        includer_file_content, page(includer_file), tmp_path,
+        includer_file_content, page(includer_file), tmp_path, plugin,
     )
 
     # assert warnings
diff --git a/tests/test_unit/test_include.py b/tests/test_unit/test_include.py
index ce69ae0..b77ad27 100644
--- a/tests/test_unit/test_include.py
+++ b/tests/test_unit/test_include.py
@@ -371,6 +371,7 @@ def test_include(
     page,
     caplog,
     tmp_path,
+    plugin,
 ):
     included_file = tmp_path / 'included.md'
     includer_file = tmp_path / 'includer.md'
@@ -387,7 +388,7 @@ def test_include(
     includer_file.write_text(page_content)
 
     assert on_page_markdown(
-        page_content, page(includer_file), tmp_path,
+        page_content, page(includer_file), tmp_path, plugin,
     ) == expected_result
 
     # assert warnings
diff --git a/tests/test_unit/test_include_markdown.py b/tests/test_unit/test_include_markdown.py
index 3302878..5b5e305 100644
--- a/tests/test_unit/test_include_markdown.py
+++ b/tests/test_unit/test_include_markdown.py
@@ -772,6 +772,7 @@ def test_include_markdown(
     page,
     caplog,
     tmp_path,
+    plugin,
 ):
     included_file = tmp_path / 'included.md'
     includer_file = tmp_path / 'includer.md'
@@ -796,6 +797,7 @@ def test_include_markdown(
         page_content,
         page(includer_file),
         tmp_path,
+        plugin,
     ) == expected_result
 
     # assert warnings
@@ -823,6 +825,7 @@ def test_include_markdown(
 def test_include_markdown_relative_rewrite(
     page,
     tmp_path,
+    plugin,
     rewrite_relative_urls,
 ):
     option_value = '' if rewrite_relative_urls is None else (
@@ -864,6 +867,7 @@ Here's a [reference link][ref-link].
         includer_path.read_text(),
         page(str(includer_path)),
         docs_dir,
+        plugin,
     )
 
     if rewrite_relative_urls in ['true', None]:
@@ -897,7 +901,7 @@ Here's a [reference link][ref-link].
 '''
 
 
-def test_multiple_includes(page, tmp_path):
+def test_multiple_includes(page, tmp_path, plugin):
     snippet_filepath = tmp_path / 'snippet.md'
     another_filepath = tmp_path / 'another.md'
     includer_file = tmp_path / 'includer.md'
@@ -940,5 +944,5 @@ Another
 Another
 '''
     assert on_page_markdown(
-        includer_content, page(includer_file), tmp_path,
+        includer_content, page(includer_file), tmp_path, plugin,
     ) == expected_result
diff --git a/tests/test_unit/test_logging.py b/tests/test_unit/test_logging.py
index 297acd0..85249f3 100644
--- a/tests/test_unit/test_logging.py
+++ b/tests/test_unit/test_logging.py
@@ -12,6 +12,7 @@ def test_start_end_arguments_not_found(
     missing_argument,
     page,
     tmp_path,
+    plugin,
     caplog,
 ):
     included_file_name = 'included.md'
@@ -42,7 +43,7 @@ Included content
 '''
 
     assert on_page_markdown(
-        includer_content, page(includer_file), tmp_path,
+        includer_content, page(includer_file), tmp_path, plugin,
     ) == expected_result
 
     rec = caplog.records[0]
diff --git a/tests/test_unit/test_nested_includes.py b/tests/test_unit/test_nested_includes.py
index eac0af0..1da91f5 100644
--- a/tests/test_unit/test_nested_includes.py
+++ b/tests/test_unit/test_nested_includes.py
@@ -248,6 +248,7 @@ def test_nested_include(
     page,
     caplog,
     tmp_path,
+    plugin,
 ):
     first_includer_file = tmp_path / 'first-includer.txt'
     second_includer_file = tmp_path / 'second-includer.txt'
@@ -266,7 +267,7 @@ def test_nested_include(
 
     # assert content
     assert on_page_markdown(
-        first_includer_content, page(first_includer_file), tmp_path,
+        first_includer_content, page(first_includer_file), tmp_path, plugin,
     ) == expected_result
 
     # assert warnings
@@ -292,7 +293,7 @@ def test_nested_include(
     assert len(expected_warnings_schemas) == len(caplog.records)
 
 
-def test_nested_include_relpath(page, tmp_path):
+def test_nested_include_relpath(page, tmp_path, plugin):
     docs_dir = tmp_path / 'docs'
     docs_dir.mkdir()
 
@@ -332,4 +333,5 @@ Included content.
         first_includer_content,
         page(first_includer_file),
         docs_dir,
+        plugin,
     ) == expected_result