Ruff
en hurtig linter og formatter til Python
Hvad det er
Ruff er et enkelt kommandolinjeprogram, skrevet i Rust, der holder
Python-kildekode op mod et katalog af lintregler og omskriver dens layout til én
ensartet stil. Bag det står Astral, firmaet bag uv og ty, og to af
underkommandoerne klarer det daglige arbejde: ruff check er linteren, og
ruff format er formatteren. Ruff hævder at køre 10 til 100 gange hurtigere end
Flake8 og Black, gemmer en cache, så uændrede filer ikke bliver analyseret igen,
og kan træde i stedet for Flake8 med snesevis af plugins, Black, isort,
pydocstyle, pyupgrade og autoflake.
Linteren har over 900 regler, mange af dem genskrevet fra populære
Flake8-plugins. Hver regel har en kode af et kort præfiks og tre cifre, og
præfikset fortæller, hvor reglen kommer fra: F401, en ubrugt import, stammer fra
Pyflakes, og E501, en linje der er for lang, fra pycodestyle. En konfiguration
vælger regler ud fra koderne, én ad gangen eller efter præfiks, så
select = ["E", "F"] slår hver regel til, hvis kode begynder med E eller F, og
den særlige vælger ALL slår alt til. Mange regler har en rettelse med, delt op
i sikre rettelser, der skal bevare adfærden ved kørsel, og usikre, der kan ændre
den; ruff check --fix anvender kun den sikre slags, medmindre --unsafe-fixes
også er angivet.
Formatteren er bygget som en direkte erstatning for Black. På kodebaser som
Django og Zulip kommer over 99,9 % af linjerne ud identisk, men dokumentationen
siger ligeud, at de to ikke er beregnet til at blive skiftet frem og tilbage på
den samme kode. Ligesom Black springer den områder over, der er indrammet af
# fmt: off og # fmt: on.
Begge halvdele læser den samme konfiguration, som ligger under [tool.ruff] i
pyproject.toml eller i en ruff.toml- eller .ruff.toml-fil. Hver Python-fil
tjekkes mod den nærmeste konfigurationsfil over den, og den fil bruges hel: Ruff
fletter intet ind fra overliggende mapper, medmindre den nærmeste fil peger på
sin forælder med extend. Indstillinger på kommandolinjen går forud for alle
filer. Uden indstillinger må en linje være 88 tegn, som i Black, og den
Python-version, reglerne går ud fra, hentes fra projektets
requires-python-felt, når ingen konfiguration angiver en.
Hvorfor det betyder noget
Hastighed afgør, hvor et tjek får lov at køre. En linter, der er så langsom, at den afbryder folk, bliver skubbet ud i continuous integration, hvor den melder sig, efter at forfatteren er gået videre. En, der svarer hurtigt, kan køre i editoren og i en commit-hook, mens ændringen stadig er frisk.
Samling fjerner uenighed mellem værktøjer. Et projekt, der linter med Flake8 og plugins, sorterer imports med isort og formaterer med Black, skal holde flere konfigurationer og versionslåse i takt. Ruff giver én konfiguration, én version at låse og én nummerering af regler, og projektet offentliggør listen over de lintregler, der strides med dets egen formatter, så de to kan bringes til at stemme overens med vilje.
Exitkoderne gør Ruff til en kvalitetsport uden indpakning. ruff check
afslutter med 0, når der ikke er nogen overtrædelser tilbage, eller alle blev
rettet, med 1, når der stadig er overtrædelser, og med 2, når konfigurationen
eller kommandolinjen er ugyldig, eller Ruff selv går ned, ligesom ESLint og
Prettier gør. ruff format --check afslutter med 1, når en fil ville blive
omformateret. En regel er enten valgt eller slået fra, og enhver valgt regel,
der slår ud, sætter exitkoden til 1.
Prisen er, at regelsættet er en beslutning, som nogen skal eje. Ruffs egne råd
er at liste reglerne eksplicit med select i stedet for at stable
extend-select, at starte med E og F og tilføje én gruppe ad gangen og at bruge
ALL med omtanke, fordi den slår nye regler til ved hver opgradering.
Sådan ser det ud i praksis
Ruff dækkede Python i
en zero-warnings-standard på tværs af seks sprog,
hvor hvert sprog havde sin egen linter. Hver diagnostik talte som en fejl, og
inline-undertrykkelser var forbudt, hvilket for Ruff udelukker
# noqa-kommentaren: et fund i Python kunne rettes i koden og på ingen anden
måde. Pre-commit- og pre-push-hooks kørte linterne og testene, så tjekket kørte,
før en commit fandtes.
Dette site giver Ruff en mindre opgave: de 22 hjælpescripts ved siden af
Hugo-buildet. Kolofonen nævner Ruff blandt de værktøjer, der
holder kilden ærlig. Regelsættet i pyproject.toml er målt frem for valgt. Hver
af Ruffs 54 regelfamilier blev den 15. oktober 2026 kørt mod scriptene, 39 af
dem meldte intet, og de tavse familier, hvis emne er netop denne kode, blev
føjet til de oprindelige elleve, så udvalget nu tæller 33. Sikkerhedsfamilien,
S, er slået til med fem regler ignoreret efter kode, hver med en kommentar om,
hvorfor det mønster, der slår ud her, er den sikre tvilling til et farligt, så
familiens øvrige regler stadig kan stoppe en commit. Tre Ruff-specifikke regler
om tvetydige Unicode-tegn er ignoreret, fordi sitets tekst med vilje bruger
rigtige tankestreger og danske bogstaver.
Pre-commit-konfigurationen kører ruff check og ruff format --check på hver
Python-fil under scripts/, som en commit rører, og projektets fix-task kører
de samme to kommandoer i deres rettende form. Ved siden af Ruff står
basedpyright, en typechecker, med en kommentar, der trækker grænsen mellem dem:
en linter følger ikke en værdi på tværs af en funktionsgrænse, og ved sin første
kørsel fandt typecheckeren to reelle fejl, som Ruff havde godkendt.
Hvor det går galt
Det meste besvær med Ruff kommer af en konfiguration, der er mere bogstavelig end de mennesker, der skrev den.
En opgradering får en urørt branch til at fejle. Kode, der bestod i går,
melder nye overtrædelser, efter at Ruff er blevet opdateret. Den sædvanlige
årsag er select = ["ALL"], der tager hver regel med, som en udgivelse
tilføjer, sammen med en version, der flyder. Lås Ruff-versionen, så en
opgradering er en commit, som nogen reviewer, og list de familier, projektet vil
have, i stedet for ALL, så en ny familie først kommer med, når nogen tilføjer
den.
Én mappe holder op med at følge projektets regler. Overtrædelser, som
rodkonfigurationen forbyder, slipper igennem i en undermappe, eller en regel,
teamet slog fra, slår ud dér. En ruff.toml eller en pyproject.toml med en
[tool.ruff]-tabel ligger i mappen, og fordi Ruff bruger den nærmeste fil hel,
holder alle rodindstillinger op med at gælde under den.
ruff check --show-settings på en fil dér udskriver stien til de indstillinger,
den endte med. Slet den indlejrede fil, eller lad den arve med
extend = "../pyproject.toml".
En undertrykkelse overlever sin grund. En # noqa-kommentar kom ind af en
god grund, koden ændrede sig, og nu skjuler kommentaren ingenting eller det
næste problem på linjen. En bar # noqa er værre: den gør alle regler på linjen
tavse. Vælg RUF100, der melder noqa-kommentarer, som ikke længere undertrykker
noget, og PGH004, der kræver en bestemt kode, og lad --fix fjerne de døde. Her
er importen siden kommet i brug, så kommentaren beskytter ingenting, og RUF100
melder den:
import json # noqa: F401
print(json.dumps({"ok": True}))
Formatteren og linteren er uenige. ruff format omskriver en fil, og
ruff check markerer bagefter resultatet. Nogle lintregler kontrollerer det,
formatteren bestemmer, som afsluttende kommaer (COM812), indrykning (W191, E111)
og anførselstegn (Q-reglerne), og formatteren gør kun et bedste forsøg på
linjelængden, så E501 kan stadig slå ud på formateret kode. Læs de advarsler,
ruff format skriver ud, for en kørsel uden dem er dokumentationens egen prøve
på, at de to er enige, ignorér enhver regel, en advarsel nævner, og tag E501 som
et signal til at bygge linjen om.
En samlet rettelse ændrer adfærd. Efter ruff check --fix --unsafe-fixes
over hele træet fejler testene, eller en fejlhåndtering holder op med at fange
det, den plejede. Usikre rettelser må gerne ændre adfærden ved kørsel eller
fjerne kommentarer, og dokumentationens eget eksempel ændrer, hvilken undtagelse
et stykke kode kaster. Hold --unsafe-fixes ude af hooks og scripts, anvend
usikre rettelser én regel ad gangen med --select og læs diffen, og forfrem kun
en regel med extend-safe-fixes, når teamet har tjekket den.
Læs mere
- Ruff — hvad Ruff erstatter, hvor hurtigt det hævder at være, og hvem der vedligeholder det.
- The Ruff Linter — regelvalg og forrang,
sikre og usikre rettelser,
noqa-kommentarer og exitkoder. - The Ruff Formatter — kompatibilitet med Black og de lintregler, der strides med formateringen.
- Rules — hver regel efter kode, dens oprindelse, og om den kan rettes automatisk.
- Configuring Ruff — hvordan
filerne findes, reglen om den nærmeste fil,
extendog kommandolinjens indstillinger.