Skip to content

Commit

Permalink
ci: Quality
Browse files Browse the repository at this point in the history
  • Loading branch information
pawamoy committed Jun 29, 2023
1 parent 6a45da8 commit a92e884
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 64 deletions.
4 changes: 4 additions & 0 deletions src/mkdocs_autorefs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
Automatically link across pages in MkDocs.
"""

from __future__ import annotations

__all__: list[str] = []
44 changes: 24 additions & 20 deletions src/mkdocs_autorefs/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,24 @@
and fixes them using the previously stored identifier-URL mapping.
"""

from __future__ import annotations

import contextlib
import functools
import logging
from typing import Callable, Dict, Optional, Sequence
from typing import TYPE_CHECKING, Any, Callable, Sequence
from urllib.parse import urlsplit

from mkdocs.config import Config
from mkdocs.plugins import BasePlugin
from mkdocs.structure.pages import Page
from mkdocs.structure.toc import AnchorLink
from mkdocs.utils import warning_filter

from mkdocs_autorefs.references import AutorefsExtension, fix_refs, relative_url

if TYPE_CHECKING:
from mkdocs.config import Config
from mkdocs.structure.pages import Page
from mkdocs.structure.toc import AnchorLink

log = logging.getLogger(f"mkdocs.plugins.{__name__}")
log.addFilter(warning_filter)

Expand All @@ -42,16 +46,16 @@ class AutorefsPlugin(BasePlugin):
"""

scan_toc: bool = True
current_page: Optional[str] = None
current_page: str | None = None

def __init__(self) -> None:
"""Initialize the object."""
super().__init__()
self._url_map: Dict[str, str] = {}
self._abs_url_map: Dict[str, str] = {}
self.get_fallback_anchor: Optional[Callable[[str], Optional[str]]] = None # noqa: WPS234
self._url_map: dict[str, str] = {}
self._abs_url_map: dict[str, str] = {}
self.get_fallback_anchor: Callable[[str], str | None] | None = None

def register_anchor(self, page: str, identifier: str):
def register_anchor(self, page: str, identifier: str) -> None:
"""Register that an anchor corresponding to an identifier was encountered when rendering the page.
Arguments:
Expand All @@ -60,7 +64,7 @@ def register_anchor(self, page: str, identifier: str):
"""
self._url_map[identifier] = f"{page}#{identifier}"

def register_url(self, identifier: str, url: str):
def register_url(self, identifier: str, url: str) -> None:
"""Register that the identifier should be turned into a link to this URL.
Arguments:
Expand All @@ -69,10 +73,10 @@ def register_url(self, identifier: str, url: str):
"""
self._abs_url_map[identifier] = url

def _get_item_url( # noqa: WPS234
def _get_item_url(
self,
identifier: str,
fallback: Optional[Callable[[str], Sequence[str]]] = None,
fallback: Callable[[str], Sequence[str]] | None = None,
) -> str:
try:
return self._url_map[identifier]
Expand All @@ -88,11 +92,11 @@ def _get_item_url( # noqa: WPS234
return url
raise

def get_item_url( # noqa: WPS234
def get_item_url(
self,
identifier: str,
from_url: Optional[str] = None,
fallback: Optional[Callable[[str], Sequence[str]]] = None,
from_url: str | None = None,
fallback: Callable[[str], Sequence[str]] | None = None,
) -> str:
"""Return a site-relative URL with anchor to the identifier, if it's present anywhere.
Expand All @@ -111,7 +115,7 @@ def get_item_url( # noqa: WPS234
return relative_url(from_url, url)
return url

def on_config(self, config: Config, **kwargs) -> Config: # noqa: W0613,R0201 (unused arguments, cannot be static)
def on_config(self, config: Config, **kwargs: Any) -> Config: # noqa: ARG002
"""Instantiate our Markdown extension.
Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config).
Expand All @@ -129,7 +133,7 @@ def on_config(self, config: Config, **kwargs) -> Config: # noqa: W0613,R0201 (u
config["markdown_extensions"].append(AutorefsExtension())
return config

def on_page_markdown(self, markdown: str, page: Page, **kwargs) -> str: # noqa: W0613 (unused arguments)
def on_page_markdown(self, markdown: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
"""Remember which page is the current one.
Arguments:
Expand All @@ -140,10 +144,10 @@ def on_page_markdown(self, markdown: str, page: Page, **kwargs) -> str: # noqa:
Returns:
The same Markdown. We only use this hook to map anchors to URLs.
"""
self.current_page = page.url # noqa: WPS601
self.current_page = page.url
return markdown

def on_page_content(self, html: str, page: Page, **kwargs) -> str: # noqa: W0613 (unused arguments)
def on_page_content(self, html: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
"""Map anchors to URLs.
Hook for the [`on_page_content` event](https://www.mkdocs.org/user-guide/plugins/#on_page_content).
Expand Down Expand Up @@ -178,7 +182,7 @@ def map_urls(self, base_url: str, anchor: AnchorLink) -> None:
for child in anchor.children:
self.map_urls(base_url, child)

def on_post_page(self, output: str, page: Page, **kwargs) -> str: # noqa: W0613 (unused arguments)
def on_post_page(self, output: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
"""Fix cross-references.
Hook for the [`on_post_page` event](https://www.mkdocs.org/user-guide/plugins/#on_post_page).
Expand Down
32 changes: 18 additions & 14 deletions src/mkdocs_autorefs/references.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
"""Cross-references module."""

from __future__ import annotations

import re
from html import escape, unescape
from typing import Any, Callable, List, Match, Tuple, Union
from typing import TYPE_CHECKING, Any, Callable, Match, Tuple
from urllib.parse import urlsplit
from xml.etree.ElementTree import Element

from markdown import Markdown
from markdown.extensions import Extension
from markdown.inlinepatterns import REFERENCE_RE, ReferenceInlineProcessor
from markdown.util import INLINE_PLACEHOLDER_RE

if TYPE_CHECKING:
from markdown import Markdown

AUTO_REF_RE = re.compile(
r"<span data-(?P<kind>autorefs-identifier|autorefs-optional|autorefs-optional-hover)="
r'("?)(?P<identifier>[^"<>]*)\2>(?P<title>.*?)</span>'
r'("?)(?P<identifier>[^"<>]*)\2>(?P<title>.*?)</span>',
)
"""A regular expression to match mkdocs-autorefs' special reference markers
in the [`on_post_page` hook][mkdocs_autorefs.plugin.AutorefsPlugin.on_post_page].
Expand All @@ -25,13 +29,13 @@
class AutoRefInlineProcessor(ReferenceInlineProcessor):
"""A Markdown extension."""

def __init__(self, *args, **kwargs): # noqa: D107
def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: D107
super().__init__(REFERENCE_RE, *args, **kwargs)

# Code based on
# https://github.com/Python-Markdown/markdown/blob/8e7528fa5c98bf4652deb13206d6e6241d61630b/markdown/inlinepatterns.py#L780

def handleMatch(self, m, data) -> Union[Element, EvalIDType]: # type: ignore[override] # noqa: N802,WPS111
def handleMatch(self, m: Match[str], data: Any) -> Element | EvalIDType: # type: ignore[override] # noqa: N802
"""Handle an element that matched.
Arguments:
Expand Down Expand Up @@ -71,7 +75,7 @@ def evalId(self, data: str, index: int, text: str) -> EvalIDType: # noqa: N802
Returns:
A tuple containing the identifier, its end position, and whether it matched.
"""
m = self.RE_LINK.match(data, pos=index) # noqa: WPS111
m = self.RE_LINK.match(data, pos=index)
if not m:
return None, index, False

Expand All @@ -87,7 +91,7 @@ def evalId(self, data: str, index: int, text: str) -> EvalIDType: # noqa: N802
end = m.end(0)
return identifier, end, True

def makeTag(self, identifier: str, text: str) -> Element: # type: ignore[override] # noqa: N802,W0221
def makeTag(self, identifier: str, text: str) -> Element: # type: ignore[override] # noqa: N802
"""Create a tag that can be matched by `AUTO_REF_RE`.
Arguments:
Expand Down Expand Up @@ -124,12 +128,12 @@ def relative_url(url_a: str, url_b: str) -> str:

# go up as many times as remaining a parts' depth
levels = len(parts_a) - 1
parts_relative = [".."] * levels + parts_b # noqa: WPS435
parts_relative = [".."] * levels + parts_b
relative = "/".join(parts_relative)
return f"{relative}#{anchor}"


def fix_ref(url_mapper: Callable[[str], str], unmapped: List[str]) -> Callable: # noqa: WPS212,WPS231
def fix_ref(url_mapper: Callable[[str], str], unmapped: list[str]) -> Callable:
"""Return a `repl` function for [`re.sub`](https://docs.python.org/3/library/re.html#re.sub).
In our context, we match Markdown references and replace them with HTML links.
Expand All @@ -148,7 +152,7 @@ def fix_ref(url_mapper: Callable[[str], str], unmapped: List[str]) -> Callable:
and returning the replacement strings.
"""

def inner(match: Match): # noqa: WPS212,WPS430
def inner(match: Match) -> str:
identifier = match["identifier"]
title = match["title"]
kind = match["kind"]
Expand All @@ -158,7 +162,7 @@ def inner(match: Match): # noqa: WPS212,WPS430
except KeyError:
if kind == "autorefs-optional":
return title
elif kind == "autorefs-optional-hover":
if kind == "autorefs-optional-hover":
return f'<span title="{identifier}">{title}</span>'
unmapped.append(identifier)
if title == identifier:
Expand All @@ -176,7 +180,7 @@ def inner(match: Match): # noqa: WPS212,WPS430
return inner


def fix_refs(html: str, url_mapper: Callable[[str], str]) -> Tuple[str, List[str]]:
def fix_refs(html: str, url_mapper: Callable[[str], str]) -> tuple[str, list[str]]:
"""Fix all references in the given HTML text.
Arguments:
Expand All @@ -187,7 +191,7 @@ def fix_refs(html: str, url_mapper: Callable[[str], str]) -> Tuple[str, List[str
Returns:
The fixed HTML.
"""
unmapped = [] # type: ignore
unmapped: list[str] = []
html = AUTO_REF_RE.sub(fix_ref(url_mapper, unmapped), html)
return html, unmapped

Expand All @@ -206,5 +210,5 @@ def extendMarkdown(self, md: Markdown) -> None: # noqa: N802 (casing: parent me
md.inlinePatterns.register(
AutoRefInlineProcessor(md),
"mkdocs-autorefs",
priority=168, # noqa: WPS432 # Right after markdown.inlinepatterns.ReferenceInlineProcessor
priority=168, # Right after markdown.inlinepatterns.ReferenceInlineProcessor
)
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the mkdocs-autorefs package."""
11 changes: 7 additions & 4 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
"""Tests for the plugin module."""

from __future__ import annotations

import pytest

from mkdocs_autorefs.plugin import AutorefsPlugin


def test_url_registration():
def test_url_registration() -> None:
"""Check that URLs can be registered, then obtained."""
plugin = AutorefsPlugin()
plugin.register_anchor(identifier="foo", page="foo1.html")
Expand All @@ -16,7 +19,7 @@ def test_url_registration():
plugin.get_item_url("baz")


def test_url_registration_with_from_url():
def test_url_registration_with_from_url() -> None:
"""Check that URLs can be registered, then obtained, relative to a page."""
plugin = AutorefsPlugin()
plugin.register_anchor(identifier="foo", page="foo1.html")
Expand All @@ -28,7 +31,7 @@ def test_url_registration_with_from_url():
plugin.get_item_url("baz", from_url="a/b.html")


def test_url_registration_with_fallback():
def test_url_registration_with_fallback() -> None:
"""Check that URLs can be registered, then obtained through a fallback."""
plugin = AutorefsPlugin()
plugin.register_anchor(identifier="foo", page="foo1.html")
Expand All @@ -47,7 +50,7 @@ def test_url_registration_with_fallback():
plugin.get_item_url("foobar", fallback=lambda _: ())


def test_dont_make_relative_urls_relative_again():
def test_dont_make_relative_urls_relative_again() -> None:
"""Check that URLs are not made relative more than once."""
plugin = AutorefsPlugin()
plugin.register_anchor(identifier="foo.bar.baz", page="foo/bar/baz.html")
Expand Down
Loading

0 comments on commit a92e884

Please sign in to comment.