mirror of https://github.com/pypa/hatch.git
108 lines
3.0 KiB
Python
108 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
from collections import defaultdict
|
|
from functools import cache
|
|
from typing import Any
|
|
|
|
from markdown.preprocessors import Preprocessor
|
|
|
|
MARKER_VERSION = '<HATCH_RUFF_VERSION>'
|
|
MARKER_SELECTED_RULES = '<HATCH_RUFF_SELECTED_RULES>'
|
|
MARKER_PER_FILE_IGNORED_RULES = '<HATCH_RUFF_PER_FILE_IGNORED_RULES>'
|
|
RULE_URLS = {'S': 'https://docs.astral.sh/ruff/rules/#flake8-bandit-s'}
|
|
|
|
|
|
def read_constants(path: str, start: str) -> dict[str, Any]:
|
|
with open(path, encoding='utf-8') as f:
|
|
lines = f.read().splitlines()
|
|
|
|
for i, line in enumerate(lines):
|
|
if line.startswith(start):
|
|
block_start = i
|
|
break
|
|
else:
|
|
message = f'Could not find {start} in {path}'
|
|
raise RuntimeError(message)
|
|
|
|
data = {}
|
|
exec('\n'.join(lines[block_start:]), None, data) # noqa: S102
|
|
return data
|
|
|
|
|
|
@cache
|
|
def ruff_data():
|
|
root = os.getcwd()
|
|
data = {}
|
|
for path, start in (
|
|
(os.path.join(root, 'src', 'hatch', 'cli', 'fmt', 'core.py'), 'STABLE_RULES'),
|
|
(os.path.join(root, 'src', 'hatch', 'env', 'internal', 'static_analysis.py'), 'RUFF_DEFAULT_VERSION'),
|
|
):
|
|
data.update(read_constants(path, start))
|
|
|
|
return data
|
|
|
|
|
|
@cache
|
|
def get_ruff_version():
|
|
return ruff_data()['RUFF_DEFAULT_VERSION']
|
|
|
|
|
|
@cache
|
|
def get_selected_rules():
|
|
selected_rules = defaultdict(list)
|
|
separator = re.compile(r'^(\D+)(\d+)$')
|
|
|
|
data = ruff_data()
|
|
for rules, preview in ((data['STABLE_RULES'], False), (data['PREVIEW_RULES'], True)):
|
|
for rule in rules:
|
|
match = separator.search(rule)
|
|
if match is None:
|
|
message = f'Could not parse rule {rule}'
|
|
raise RuntimeError(message)
|
|
|
|
group, number = match.groups()
|
|
selected_rules[group].append((number, preview))
|
|
|
|
lines = []
|
|
for group, rule_data in sorted(selected_rules.items()):
|
|
rule_data.sort(key=lambda x: int(x[0]))
|
|
|
|
parts = []
|
|
for number, preview in rule_data:
|
|
rule = f'{group}{number}'
|
|
part = f'[{rule}](https://docs.astral.sh/ruff/rules/{rule})'
|
|
if preview:
|
|
part += '^P^'
|
|
parts.append(part)
|
|
|
|
lines.append(f'- {", ".join(parts)}')
|
|
|
|
return '\n'.join(lines)
|
|
|
|
|
|
@cache
|
|
def get_per_file_ignored_rules():
|
|
lines = []
|
|
for glob, rules in sorted(ruff_data()['PER_FILE_IGNORED_RULES'].items()):
|
|
parts = []
|
|
for rule in rules:
|
|
url = RULE_URLS.get(rule) or f'https://docs.astral.sh/ruff/rules/{rule}'
|
|
parts.append(f'[{rule}]({url})')
|
|
|
|
lines.append(f'- `{glob}`: {", ".join(parts)}')
|
|
|
|
return '\n'.join(lines)
|
|
|
|
|
|
class RuffDefaultsPreprocessor(Preprocessor):
|
|
def run(self, lines): # noqa: PLR6301
|
|
return (
|
|
'\n'.join(lines)
|
|
.replace(MARKER_VERSION, get_ruff_version())
|
|
.replace(MARKER_SELECTED_RULES, get_selected_rules())
|
|
.replace(MARKER_PER_FILE_IGNORED_RULES, get_per_file_ignored_rules())
|
|
.splitlines()
|
|
)
|