Skip to main content

Ruff Score 🎯

A Pylint-style scoring system for Ruff linter output. Get a numerical quality score (0-10) for your Python code based on Ruff's analysis, using a rule-category mapping that covers every prefix in Ruff's rule set.

Features

  • 🎯 Pylint-style scoring: Familiar 0-10 quality score system, using Pylint's own formula
  • 🔧 Ruff integration: Built on top of the fast Ruff linter
  • 🗂️ Full rule coverage: Every Ruff prefix (E, F, PLE/PLC/PLR/PLW, ASYNC, S, TRY, RUF, and 40+ more) is mapped to a Pylint-style category and severity weight — not just a handful of common ones
  • ⚖️ Two-level weighting: Issues are bucketed into error / warning / convention / refactor, and within a category, individual rules can carry different weights (e.g. a SQL-injection finding counts for more than a stray print)
  • 📊 Detailed reports: Categorized issue breakdown with a printable summary
  • 📁 File & directory support: Analyze single files or entire projects
  • ⚙️ Configurable: Use your existing Ruff configuration file, and override weights/categories in Python

Installation

pip install ruff-score

Quick Start

from pathlib import Path
from ruff_score import RuffScorer

scorer = RuffScorer()

# Score a single file
result = scorer.score_file(Path("myfile.py"))
print(f"Score: {result['score']:.2f}/10.00")

# Score a directory
result = scorer.score_directory(Path("src/"))
scorer.print_report(result)

# Score against a specific Ruff config
result = scorer.score_directory(Path("src/"), config_file=Path("pyproject.toml"))

How It Works

Ruff Score uses the same scoring formula as Pylint:

Score = 10.0 - ((5*errors + warnings + refactor + convention) / statements * 10)

statements is the number of AST statement nodes in the analyzed file(s), and errors / warnings / refactor / convention are the weighted issue totals for each category — not just raw counts. So a category's contribution to the score is the sum of each issue's individual rule weight, which means two "warning"-category issues aren't necessarily worth the same amount if one rule is riskier than another.

Rule Categories & Weights

Every Ruff prefix is mapped to one of four Pylint-style categories, based on Ruff's documented rule set:

Category Meaning Example prefixes Typical weight
Error Real bugs / correctness issues E (pycodestyle), F (Pyflakes), PLE (Pylint errors), AIR (Airflow) 3–5
Warning Security risks and likely-bug patterns S (bandit/security), B (bugbear), ASYNC, TRY, PERF, T20/T10, DTZ, PLW 1–4
Convention Naming, docs, style, imports N (naming), D (docstrings), ANN, I (isort), Q, COM, PLC 1
Refactor Modernization / simplification UP (pyupgrade), SIM (simplify), PLR, PTH, C4, RUF 1

The full mapping (RULE_CATEGORIES and RULE_WEIGHTS) lives at the top of ruff_scorer.py and covers ~50 rule prefixes, including ones that embed a digit in the prefix itself (e.g. C4, C90, T10, T20) and multi-letter prefixes (e.g. PLE, ASYNC, TRY). Any prefix Ruff adds in the future that isn't in the table falls back to default_weight / default_category.

Score Interpretation

  • 9.0-10.0: Excellent code quality
  • 7.0-8.9: Good code quality
  • 5.0-6.9: Needs improvement
  • 0.0-4.9: Poor code quality

Example Output

==================================================
RUFF QUALITY SCORE REPORT
==================================================
Target: src/
Score: 8.45/10.00
Statements analyzed: 1,247
Files analyzed: 23
Total issues: 12

Issues by category:
  Error: 0
  Warning: 3
  Convention: 8
  Refactor: 1

Good code quality

Advanced Usage

Custom Weights and Categories

from ruff_scorer import RuffScorer

# Change the fallback used for any rule prefix not in RULE_WEIGHTS/RULE_CATEGORIES
scorer = RuffScorer(default_weight=2, default_category="warning")

# Override the weight or category for a specific prefix
scorer.RULE_WEIGHTS["D"] = 1        # docstring issues
scorer.RULE_CATEGORIES["D"] = "convention"

# Inspect how a given rule code resolves
scorer.get_rule_weight("S608")      # -> 4
scorer.get_rule_category("S608")    # -> "warning"

Integration with CI/CD

# check_quality.py
import sys
from pathlib import Path
from ruff_scorer import RuffScorer

scorer = RuffScorer()
result = scorer.score_directory(Path("src/"))
scorer.print_report(result)

THRESHOLD = 7.0
sys.exit(0 if result["score"] >= THRESHOLD else 1)
python check_quality.py && echo "Quality check passed!" || echo "Quality check failed!"

Configuration

Ruff Score respects your existing Ruff configuration by passing it straight through to ruff check --config. Place your settings in:

  • pyproject.toml
  • ruff.toml
  • .ruff.toml

Example configuration:

[tool.ruff]
line-length = 88
target-version = "py38"

[tool.ruff.lint]
select = ["E", "F", "W", "C", "N", "D", "S", "B"]
ignore = ["E501", "D100"]

Requirements

  • Python 3.8+
  • Ruff installed and available on your PATH

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  • Ruff - The fast Python linter
  • Pylint - The original Python code quality tool

Metadata

Release files for ruff-score 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ruff-score 0.4.0
File Size Uploaded
ruff_score-0.4.0.tar.gz 43.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ruff-score 0.4.0
File Interpreter ABI Platform
ruff_score-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.3 kB

Release files / ruff_score-0.4.0.tar.gz

Download URL ruff_score-0.4.0.tar.gz
Size 43.7 kB
Tags Source
SHA-256 checksum
How to use checksums
befeee358e5f55f4b4ef20445a980c4c31d4f489a37ba48ed396126c8dde0c66
BLAKE2b-256 checksum
How to use checksums
4e1373fb8f42bb49229b1114d416a1ac64914dc000356df89f2cb103b84ff69e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / ruff_score-0.4.0-py3-none-any.whl

Download URL ruff_score-0.4.0-py3-none-any.whl
Size 10.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
36bcab78035fc2fbd63bc9a91b268c57e2107b388507108c65db7ee0c1e9a505
BLAKE2b-256 checksum
How to use checksums
6868444a9e6f2f6ac4fbca0b5624c43a5db8d5e9f691eef6a7d1ffea0813e788
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.4.1

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page