Skip to content

Commit

Permalink
fix: Make extension paths relative to config file
Browse files Browse the repository at this point in the history
PR #112: #112
Co-authored-by: Timothée Mazzucotelli <pawamoy@pm.me>
  • Loading branch information
waylan authored Oct 31, 2023
1 parent f747ecb commit 5035e92
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
34 changes: 32 additions & 2 deletions src/mkdocstrings_handlers/python/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import sys
from collections import ChainMap
from contextlib import suppress
from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, Iterator, Mapping
from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, Iterator, Mapping, Sequence

from griffe.collections import LinesCollection, ModulesCollection
from griffe.docstrings.parsers import Parser
Expand Down Expand Up @@ -265,8 +265,9 @@ def collect(self, identifier: str, config: Mapping[str, Any]) -> CollectorItem:
parser = parser_name and Parser(parser_name)

if unknown_module:
extensions = self.normalize_extension_paths(final_config.get("extensions", []))
loader = GriffeLoader(
extensions=load_extensions(final_config.get("extensions", [])),
extensions=load_extensions(extensions),
search_paths=self._paths,
docstring_parser=parser,
docstring_options=parser_options,
Expand Down Expand Up @@ -369,6 +370,35 @@ def get_anchors(self, data: CollectorItem) -> tuple[str, ...]: # noqa: D102 (ig
return tuple(anchors)
return tuple(anchors)

def normalize_extension_paths(self, extensions: Sequence) -> Sequence:
"""Resolve extension paths relative to config file."""
if self._config_file_path is None:
return extensions

base_path = os.path.dirname(self._config_file_path)
normalized = []

for ext in extensions:
if isinstance(ext, dict):
pth, options = next(iter(ext.items()))
pth = str(pth)
else:
pth = str(ext)
options = None

if pth.endswith(".py") or ".py:" in pth or "/" in pth or "\\" in pth: # noqa: SIM102
# This is a sytem path. Normalize it.
if not os.path.isabs(pth):
# Make path absolute relative to config file path.
pth = os.path.normpath(os.path.join(base_path, pth))

if options is not None:
normalized.append({pth: options})
else:
normalized.append(pth)

return normalized


def get_handler(
*,
Expand Down
40 changes: 40 additions & 0 deletions tests/test_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,43 @@ def test_expand_globs_without_changing_directory() -> None:
)
for path in list(glob(os.path.abspath(".") + "/*.md")):
assert path in handler._paths


@pytest.mark.parametrize(
("expect_change", "extension"),
[
(True, "extension.py"),
(True, "extension.py:SomeExtension"),
(True, "path/to/extension.py"),
(True, "path/to/extension.py:SomeExtension"),
(True, {"extension.py": {"option": "value"}}),
(True, {"extension.py:SomeExtension": {"option": "value"}}),
(True, {"path/to/extension.py": {"option": "value"}}),
(True, {"path/to/extension.py:SomeExtension": {"option": "value"}}),
(False, "/absolute/path/to/extension.py"),
(False, "/absolute/path/to/extension.py:SomeExtension"),
(False, {"/absolute/path/to/extension.py": {"option": "value"}}),
(False, {"/absolute/path/to/extension.py:SomeExtension": {"option": "value"}}),
(False, "dot.notation.path.to.extension"),
(False, "dot.notation.path.to.pyextension"),
(False, {"dot.notation.path.to.extension": {"option": "value"}}),
(False, {"dot.notation.path.to.pyextension": {"option": "value"}}),
],
)
def test_extension_paths(tmp_path: Path, expect_change: bool, extension: str | dict) -> None:
"""Assert extension paths are resolved relative to config file."""
handler = get_handler(
theme="material",
config_file_path=str(tmp_path.joinpath("mkdocs.yml")),
)
normalized = handler.normalize_extension_paths([extension])[0]
if expect_change:
if isinstance(normalized, str) and isinstance(extension, str):
assert normalized == str(tmp_path.joinpath(extension))
elif isinstance(normalized, dict) and isinstance(extension, dict):
pth, options = next(iter(extension.items()))
assert normalized == {str(tmp_path.joinpath(pth)): options}
else:
raise ValueError("Normalization must not change extension items type")
else:
assert normalized == extension

0 comments on commit 5035e92

Please sign in to comment.