Skip to content

Commit

Permalink
feat: Allow ruff to be used as a formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkaMaul committed Dec 13, 2024
1 parent cea4996 commit 709aedc
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
53 changes: 48 additions & 5 deletions src/mkdocstrings_handlers/python/rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
from __future__ import annotations

import enum
import importlib
import random
import re
import string
import subprocess
import sys
import warnings
from functools import lru_cache
Expand Down Expand Up @@ -83,7 +85,7 @@ def do_format_code(code: str, line_length: int) -> str:
code = code.strip()
if len(code) < line_length:
return code
formatter = _get_black_formatter()
formatter = _get_formatter()
return formatter(code, line_length)


Expand Down Expand Up @@ -118,7 +120,7 @@ def _format_signature(name: Markup, signature: str, line_length: int) -> str:
# Black cannot format names with dots, so we replace
# the whole name with a string of equal length
name_length = len(name)
formatter = _get_black_formatter()
formatter = _get_formatter()
formatable = f"def {'x' * name_length}{signature}: pass"
formatted = formatter(formatable, line_length)

Expand Down Expand Up @@ -434,12 +436,53 @@ def do_filter_objects(


@lru_cache(maxsize=1)
def _get_black_formatter() -> Callable[[str, int], str]:
def _get_formatter() -> Callable[[str, int], str]:
for formatter_function in [
_get_black_formatter,
_get_ruff_formatter,
]:
if (formatter := formatter_function()) is not None:
return formatter

logger.info("Formatting signatures requires either Black or ruff to be installed.")
return lambda text, _: text


@lru_cache(maxsize=1)
def _get_ruff_formatter() -> Callable[[str, int], str] | None:
if importlib.util.find_spec("ruff") is None:
return None

def formatter(code: str, line_length: int) -> str:
try:
completed_process = subprocess.run( # noqa: S603
[ # noqa: S607
"ruff",
"format",
f'--config "line-length={line_length}"',
"--stdin-filename",
"file.py",
"-",
],
check=True,
capture_output=True,
text=True,
input=code,
)
except subprocess.CalledProcessError:
return code
else:
return completed_process.stdout

return formatter


@lru_cache(maxsize=1)
def _get_black_formatter() -> Callable[[str, int], str] | None:
try:
from black import InvalidInput, Mode, format_str
except ModuleNotFoundError:
logger.info("Formatting signatures requires Black to be installed.")
return lambda text, _: text
return None

def formatter(code: str, line_length: int) -> str:
mode = Mode(line_length=line_length)
Expand Down
14 changes: 11 additions & 3 deletions tests/test_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import re
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Callable

import pytest
from griffe import ModulesCollection, temporary_visited_module
Expand All @@ -22,14 +22,22 @@
"aaaaa(bbbbb, ccccc=1) + ddddd.eeeee[ffff] or {ggggg: hhhhh, iiiii: jjjjj}",
],
)
def test_format_code(code: str) -> None:
@pytest.mark.parametrize(
"formatter",
[
rendering._get_black_formatter(),
rendering._get_ruff_formatter(),
rendering._get_formatter(),
],
)
def test_format_code(code: str, formatter: Callable[[str, int], str]) -> None:
"""Assert code can be Black-formatted.
Parameters:
code: Code to format.
"""
for length in (5, 100):
assert rendering.do_format_code(code, length)
assert formatter(code, length)


@pytest.mark.parametrize(
Expand Down

0 comments on commit 709aedc

Please sign in to comment.