Skip to content
Draft
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
16 changes: 14 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,27 @@ repos:
args: [--fix]
- id: ruff-format

- repo: https://github.com/ulgens/ruffen-docs
rev: 1def1ebbc1bd7f6b9934121948d0d06515f71e3f
- repo: .
rev: 7ed7e55de4a6515a97ee8c2202db2842d00b2b6c
hooks:
- id: blacken-docs
language: python
additional_dependencies:
- black==25.12.0
files: \.rst$

- id: ruffen-docs-check
language: python
additional_dependencies:
- ruff==0.14.10
files: \.rst$

- id: ruffen-docs-format
language: python
additional_dependencies:
- ruff==0.14.10
files: \.rst$

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
hooks:
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
files: \.(rst|md|markdown|py|tex)$

- id: ruffen-docs-check
name: ruffen-docs-check
name: ruffen-docs check
description: Run `ruff check` on Python code blocks in documentation files
entry: ruffen-docs-check
language: python
files: \.(rst|md|markdown|py|tex)$

- id: ruffen-docs-format
name: ruffen-docs-format
name: ruffen-docs format
description: Run `ruff format` on Python code blocks in documentation files
entry: ruffen-docs-format
language: python
Expand Down
65 changes: 60 additions & 5 deletions src/ruffen_docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from black.const import DEFAULT_LINE_LENGTH
from black.mode import TargetVersion

from .formatters import BlackFormatter
from .processors import BlackFormatter, RuffChecker, RuffFormatter


def run_black(argv: Sequence[str] | None = None) -> int:
Expand Down Expand Up @@ -68,6 +68,7 @@ def run_black(argv: Sequence[str] | None = None) -> int:

retv = 0
for filename in args.filenames:
print(filename)
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This debug print statement should be removed. It appears to have been added during development and will output filenames to stdout during normal operation, which could interfere with the tool's output and usage in automated environments.

Suggested change
print(filename)

Copilot uses AI. Check for mistakes.
formatter = BlackFormatter(**formatter_kwargs)
retv |= formatter.format_file(
filename,
Expand All @@ -79,10 +80,64 @@ def run_black(argv: Sequence[str] | None = None) -> int:


def run_check(argv: Sequence[str] | None = None) -> int:
...
return 1
parser = argparse.ArgumentParser()
parser.add_argument(
"-l",
"--line-length",
type=int,
default=DEFAULT_LINE_LENGTH,
)
parser.add_argument(
"-S",
"--skip-string-normalization",
action="store_true",
)
parser.add_argument("-E", "--skip-errors", action="store_true")
parser.add_argument("filenames", nargs="*")
args = parser.parse_args(argv)
Comment on lines +83 to +97
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run_check and run_format functions accept line-length and skip-string-normalization arguments that are parsed but never used. These parameters should either be passed to the RuffChecker and RuffFormatter constructors (if they support configuration), or the argument parsing should be removed to avoid misleading users.

Copilot uses AI. Check for mistakes.

retv = 0

for filename in args.filenames:
formatter = RuffChecker()
retv |= formatter.format_file(
Comment on lines +102 to +103
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'formatter' is misleading when the instance is actually a RuffChecker, not a formatter. Consider renaming to 'checker' for clarity and consistency with the class name.

Suggested change
formatter = RuffChecker()
retv |= formatter.format_file(
checker = RuffChecker()
retv |= checker.format_file(

Copilot uses AI. Check for mistakes.
filename,
skip_errors=args.skip_errors,
# rst_literal_blocks=args.rst_literal_blocks,
# check_only=args.check,
)
Comment on lines +106 to +108
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commented-out lines should either be removed if they're not needed, or uncommented and implemented if they are. Leaving commented code in the codebase reduces clarity about what the intended behavior should be.

Copilot uses AI. Check for mistakes.

return retv


def run_format(argv: Sequence[str] | None = None) -> int:
...
return 1
parser = argparse.ArgumentParser()
parser.add_argument(
"-l",
"--line-length",
type=int,
default=DEFAULT_LINE_LENGTH,
)
parser.add_argument(
"-S",
"--skip-string-normalization",
action="store_true",
)
parser.add_argument("-E", "--skip-errors", action="store_true")
parser.add_argument("filenames", nargs="*")
args = parser.parse_args(argv)
Comment on lines +83 to +128
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The argument parsing code in run_check and run_format is largely duplicated from run_black. Consider extracting this into a shared helper function to reduce code duplication and improve maintainability.

Copilot uses AI. Check for mistakes.

filenames = []

retv = 0

for filename in filenames:
Comment on lines +130 to +134
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filenames list is initialized as empty but is never populated with args.filenames. This means the loop will never execute, and no files will be processed. You should use args.filenames directly in the loop, similar to how run_check and run_black are implemented.

Suggested change
filenames = []
retv = 0
for filename in filenames:
retv = 0
for filename in args.filenames:

Copilot uses AI. Check for mistakes.
formatter = RuffFormatter()
retv |= formatter.format_file(
filename,
skip_errors=args.skip_errors,
# rst_literal_blocks=args.rst_literal_blocks,
# check_only=args.check,
)
Comment on lines +139 to +141
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commented-out lines should either be removed if they're not needed, or uncommented and implemented if they are. Leaving commented code in the codebase reduces clarity about what the intended behavior should be.

Copilot uses AI. Check for mistakes.

return retv
48 changes: 45 additions & 3 deletions src/ruffen_docs/formatters.py → src/ruffen_docs/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import contextlib
import re
import subprocess
import textwrap
from abc import ABC, abstractmethod
from bisect import bisect
Expand All @@ -13,6 +14,7 @@
from black import Mode
from black.const import DEFAULT_LINE_LENGTH
from black.mode import TargetVersion
from ruff.__main__ import find_ruff_bin

from .constants import PYGMENTS_PY_LANGS
from .errors import CodeBlockError
Expand All @@ -33,7 +35,11 @@
TRAILING_NL_RE,
)

__all__ = ("BlackFormatter",)
__all__ = (
"BlackFormatter",
"RuffChecker",
"RuffFormatter",
)


class BaseProcessor(ABC):
Expand Down Expand Up @@ -264,8 +270,8 @@ def format_file(
self,
filename: str,
skip_errors: bool,
rst_literal_blocks: bool,
check_only: bool,
rst_literal_blocks: bool = True,
check_only: bool = False,
) -> int:
with Path(filename).open(encoding="UTF-8") as f:
contents = f.read()
Expand Down Expand Up @@ -324,3 +330,39 @@ def __init__(

def process_code_block(self, code_block: str) -> str:
return black.format_str(code_block, mode=self.mode)


class RuffChecker(BaseProcessor):
def __init__(self) -> None:
super().__init__()

def process_code_block(self, code_block: str) -> str:
# https://gist.github.com/jorenham/63942278b01515ffdeb0c7d4d1895684
result = subprocess.run(
[find_ruff_bin(), "check", "-"],
input=code_block,
text=True,
capture_output=True,
# check=True,
cwd=Path.cwd(),
)
result.check_returncode()
return result.stdout


class RuffFormatter(BaseProcessor):
def __init__(self) -> None:
super().__init__()

def process_code_block(self, code_block: str) -> str:
# https://gist.github.com/jorenham/63942278b01515ffdeb0c7d4d1895684
result = subprocess.run(
[find_ruff_bin(), "format", "-"],
input=code_block,
text=True,
capture_output=True,
# check=True,
cwd=Path.cwd(),
)
result.check_returncode()
return result.stdout
2 changes: 1 addition & 1 deletion tests/test_ruffen_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
__main__, # noqa: F401
run_black,
)
from ruffen_docs.formatters import BlackFormatter as Formatter
from ruffen_docs.processors import BlackFormatter as Formatter

BLACK_MODE = Mode()

Expand Down
Loading