A command-line tool that statically analyzes Drupal 10 / 11 themes and generates a detailed, scored quality report — with concrete suggestions for fixing every issue it finds.
$ theme-inspector analyze themes/custom/olivero_child
╭──────────────── Drupal Theme Inspector — Olivero Child ─────────────────╮
│ 78/100 (Grade C) │
│ 42 files scanned │
│ 1 critical 4 warning 6 info │
╰───────────────────────────────────────────────────────────────────────╯
Reviewing a Drupal theme by hand — checking *.info.yml fields,
hunting for deprecated drupal_get_path() calls, spotting stray
{{ dump() }} left in a template, verifying every asset a
*.libraries.yml file references actually exists — is repetitive and
easy to get wrong. Drupal Theme Inspector automates that review and
turns it into a single, shareable score.
| # | Feature |
|---|---|
| 1 | Detects and parses theme metadata from *.info.yml |
| 2 | Validates required/recommended *.info.yml fields |
| 3 | Detects deprecated Drupal PHP/YAML syntax |
| 4 | Checks Twig templates (debug statements, |raw, naming, inline styles) |
| 5 | Detects missing or undeclared libraries and assets |
| 6 | Checks CSS/JS file organization |
| 7 | Analyzes overall file/directory structure |
| 8 | Generates HTML and Markdown reports |
| 9 | Produces a 0–100 quality score with a letter grade |
| 10 | Suggests concrete improvements for every issue |
Requires Python 3.12+.
pip install drupal-theme-inspectorOr, from source:
git clone https://github.com/example/drupal-theme-inspector.git
cd drupal-theme-inspector
pip install -e .# Analyze a theme and print a report to the terminal
theme-inspector analyze path/to/theme
# Also write HTML and/or Markdown reports
theme-inspector analyze path/to/theme --html report.html --markdown report.md
# Only print the summary panel, skip the detailed tables
theme-inspector analyze path/to/theme --quiet
# CI mode: exit non-zero if the score is below a threshold
theme-inspector analyze path/to/theme --fail-under 80
theme-inspector --versionTerminal output (Rich):
╭──────────────── Drupal Theme Inspector — Sample Theme ──────────────────╮
│ 61/100 (Grade D) │
│ 9 files scanned │
│ 2 critical 3 warning 2 info │
╰───────────────────────────────────────────────────────────────────────╯
twig
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Severity ┃ Location ┃ Message ┃ Suggestion ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ critical │ templates/node--BAD-Name...:2 │ Debug statement left… │ Remove dump() calls before… │
└──────────┴────────────────────────────────┴────────────────────────┴───────────────────────────────┘
HTML report: a self-contained, dependency-free HTML file with a
score card and per-category issue tables — open report.html in any
browser (see examples/ for a generated sample).
Markdown report: the same content as GitHub-flavored Markdown tables, ideal for pasting into a pull request description.
Generate your own copies with:
theme-inspector analyze examples/sample_theme --html docs/example-report.html --markdown docs/example-report.mdPre-generated copies for the bundled
examples/sample_themefixture are checked intodocs/example-report.htmlanddocs/example-report.md.
from drupal_theme_inspector.core.scanner import ThemeScanner
result = ThemeScanner("path/to/theme").scan()
print(result.score, result.grade)
for issue in result.issues:
print(issue.severity, issue.category, issue.message)Every theme starts at a perfect 100. Each issue deducts points based on its severity:
| Severity | Points deducted | Meaning |
|---|---|---|
| 🔴 critical | 12 | Broken or deprecated in a way that will error, or ship a bug |
| 🟡 warning | 5 | Works today but goes against current best practice |
| 🔵 info | 1 | Style / polish suggestion |
See core/scorer.py for
the full (deliberately simple) implementation.
src/drupal_theme_inspector/
├── analyzers/ # One module per check: info_yml, deprecated, twig,
│ # libraries, assets, structure. Each returns list[Issue].
├── core/ # models.py (Issue, ThemeInfo, AnalysisResult),
│ # scanner.py (orchestrates analyzers), scorer.py
├── reports/ # html_report.py, markdown_report.py
├── utils/ # console.py — Rich terminal rendering
└── cli.py # Typer application
Adding a new check means writing one new analyzer function that
returns list[Issue] and wiring it into ThemeScanner.scan() — the
scorer and both report renderers work generically over Issue
objects and need no changes. See docs/architecture.md
and CONTRIBUTING.md for details.
pip install -e ".[dev]"
pytest # run tests with coverage
ruff check src tests # lint
mypy # type-check