Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ repos:
hooks:
- id: absolufy-imports
- repo: https://github.com/PyCQA/isort
rev: c235f5e450b4b84e58d114ed4c589cbf454175a3 # frozen: 5.13.2
rev: 0a0b7a830386ba6a31c2ec8316849ae4d1b8240d # frozen: 6.0.0
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 1b2427a2b785cc4aac97c19bb4b9a0de063f9547 # frozen: 24.10.0
rev: 8a737e727ac5ab2f1d4cf5876720ed276dc8dc4b # frozen: 25.1.0
hooks:
- id: black
- repo: https://github.com/hukkin/docformatter
Expand All @@ -43,6 +43,6 @@ repos:
- flake8-builtins
- flake8-comprehensions
- repo: https://github.com/pre-commit/pre-commit
rev: cc4a52241565440ce200666799eef70626457488 # frozen: v4.0.1
rev: b152e922ef11a97efe22ca7dc4f90011f0d1711c # frozen: v4.1.0
hooks:
- id: validate_manifest
6 changes: 5 additions & 1 deletion src/mdformat/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ def run(cli_args: Sequence[str], cache_toml: bool = True) -> int: # noqa: C901
print_error(str(e))
return 1

opts: Mapping = {**DEFAULT_OPTS, **toml_opts, **cli_core_opts}
opts = {**DEFAULT_OPTS, **toml_opts, **cli_core_opts}

# Merge plugin options from CLI.
# Make a copy of opts["plugin"] to not mutate DEFAULT_OPTS or cached TOML.
opts["plugin"] = dict(opts["plugin"])
for plugin_id, plugin_opts in cli_plugin_opts.items():
if plugin_id in opts["plugin"]:
opts["plugin"][plugin_id] |= plugin_opts
Expand Down
24 changes: 14 additions & 10 deletions src/mdformat/_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@

import functools
from pathlib import Path
from types import MappingProxyType
from typing import Mapping

from mdformat._compat import tomllib
from mdformat._util import EMPTY_MAP

DEFAULT_OPTS = {
"wrap": "keep",
"number": False,
"end_of_line": "lf",
"validate": True,
"exclude": [],
"plugin": {},
"extensions": None,
"codeformatters": None,
}
DEFAULT_OPTS = MappingProxyType(
{
"wrap": "keep",
"number": False,
"end_of_line": "lf",
"validate": True,
"exclude": (),
"plugin": EMPTY_MAP,
"extensions": None,
"codeformatters": None,
}
)


class InvalidConfError(Exception):
Expand Down
47 changes: 35 additions & 12 deletions src/mdformat/plugins.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from __future__ import annotations

import argparse
from collections.abc import Callable, Mapping
from typing import TYPE_CHECKING, Any, Protocol

from mdformat._compat import importlib_metadata

if TYPE_CHECKING:
import argparse
from collections.abc import Callable, Mapping

from markdown_it import MarkdownIt

from mdformat.renderer.typing import Postprocess, Render
Expand All @@ -31,13 +32,6 @@ def _load_entrypoints(
return loaded_ifaces, dist_versions


CODEFORMATTERS: Mapping[str, Callable[[str, str], str]]
_CODEFORMATTER_DISTS: Mapping[str, tuple[str, list[str]]]
CODEFORMATTERS, _CODEFORMATTER_DISTS = _load_entrypoints(
importlib_metadata.entry_points(group="mdformat.codeformatter")
)


class ParserExtensionInterface(Protocol):
"""An interface for parser extension plugins."""

Expand Down Expand Up @@ -86,8 +80,37 @@ def update_mdit(mdit: MarkdownIt) -> None:
"""Update the parser, e.g. by adding a plugin: `mdit.use(myplugin)`"""


CODEFORMATTERS: Mapping[str, Callable[[str, str], str]]
_CODEFORMATTER_DISTS: Mapping[str, tuple[str, list[str]]]
PARSER_EXTENSIONS: Mapping[str, ParserExtensionInterface]
_PARSER_EXTENSION_DISTS: Mapping[str, tuple[str, list[str]]]
PARSER_EXTENSIONS, _PARSER_EXTENSION_DISTS = _load_entrypoints(
importlib_metadata.entry_points(group="mdformat.parser_extension")
)


def __getattr__(name: str) -> Mapping[str, Any]:
"""Attribute getter fallback.

Used to lazy load CODEFORMATTERS and PARSER_EXTENSIONS. It'd
probably be more readable to use `@functools.cache` decorated
functions, but `__getattr__` is used now for back compatibility.
"""
if name in {"CODEFORMATTERS", "_CODEFORMATTER_DISTS"}:
formatters, formatter_dists = _load_entrypoints(
importlib_metadata.entry_points(group="mdformat.codeformatter")
)
# Cache the values in this module for next time, so that `__getattr__`
# is only called once per `name`.
global CODEFORMATTERS, _CODEFORMATTER_DISTS
CODEFORMATTERS = formatters
_CODEFORMATTER_DISTS = formatter_dists
return formatters if name == "CODEFORMATTERS" else formatter_dists
if name in {"PARSER_EXTENSIONS", "_PARSER_EXTENSION_DISTS"}:
extensions, extension_dists = _load_entrypoints(
importlib_metadata.entry_points(group="mdformat.parser_extension")
)
# Cache the value in this module for next time, so that `__getattr__`
# is only called once per `name`.
global PARSER_EXTENSIONS, _PARSER_EXTENSION_DISTS
PARSER_EXTENSIONS = extensions
_PARSER_EXTENSION_DISTS = extension_dists
return extensions if name == "PARSER_EXTENSIONS" else extension_dists
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")