DEV Community

Cover image for Best Python Code Quality Tools : Linters, Formatters & Analyzers to Prevent Technical Debt
djinn-soul
djinn-soul

Posted on • Edited on

Best Python Code Quality Tools : Linters, Formatters & Analyzers to Prevent Technical Debt

Python Code Quality Tools: Stop Technical Debt Before It Starts

Technical debt sneaks in through sloppy code: vulnerabilities that bite later, tangled imports that slow onboarding, or functions so complex they become black boxes. This guide cuts through the noise with nine battle-tested Python tools. Each one targets a specific pain point—security, complexity, cohesion, coupling, and more—helping you enforce standards early. We'll cover what it does, quick install/usage, and why it pays off. No fluff; just actionable steps.

Focus on integration: Hook these into pre-commit, CI/CD (e.g., GitHub Actions), or your IDE. Start small—pick 2-3 for your workflow—and scale.

1. Safety CLI: Vulnerability Scanning

What it does: Scans Python dependencies for known vulnerabilities and malicious packages using a massive DB (3x more coverage than free alternatives). Outputs fixes, JSON/SBOM/HTML reports, and integrates with CI/CD.

Install: pip install safety

Quick usage:

  • Authenticate: safety auth
  • Scan project: safety scan
  • Fix deps: safety scan --apply-fixes
  • System-wide: safety system-scan

Prevents debt by: Catching supply-chain risks before deployment. Legacy deps? It auto-updates to safe versions per your policy. Free tier for solos; paid ($25/seat/mo) for teams.

Pro tip: GitHub Action: Add to .github/workflows for PR scans.

2. Bandit: Security Issue Detector

What it does: Analyzes Python AST for common security flaws (e.g., hardcoded secrets, unsafe eval). Plugin-based; generates reports in text, JSON, HTML, or XML.

Install: pip install bandit

Quick usage:

  • Basic scan: bandit -r .
  • Config file: bandit -c .bandit.yml -r .
  • CI output: bandit -f json -r . > security.json

Prevents debt by: Flags injection risks and weak crypto early, reducing breach costs. Extensible for custom rules; integrates with pre-commit or Jenkins.

Pro tip: Ignore false positives via config; pair with Safety for full dep+code coverage.

3. LCOM: Lack of Cohesion of Methods

What it does: Measures class cohesion (LCOM4 metric). Low scores mean classes juggle unrelated responsibilities—split 'em. Ignores constructors/inherited methods.

Install: pip install lcom

Quick usage:

  • Scan module: lcom src
  • Single file: lcom src/command.py
  • Output: Table of LCOM scores per class (0-1; aim for 1).

Prevents debt by: Exposes god classes that resist refactoring. High cohesion = easier tests/maintenance; refactor >2 scores.

Pro tip: Use in CI: Fail builds if average >1.5. Simple CLI; no heavy deps.

4. Cohesion: Class Cohesion Metrics

What it does: Tracks variable usage across class methods (e.g., 66% cohesion if 2/3 vars used). Verbose mode shows per-function breakdowns.

Install: pip install cohesion

Quick usage:

  • Scan file: cohesion --files example.py --verbose
  • Threshold: cohesion --files . --below 50 (shows low-cohesion classes)
  • Flake8 integration: flake8 . (flags H601 low cohesion)

Prevents debt by: Highlights underused vars/methods, curbing "kitchen sink" classes. Boosts reusability; clean code stays clean.

Pro tip: Pre-commit hook: hooks: - id: cohesion args: [--below=70]. Poetry for dev setup.

5. Module Coupling Metrics: Instability & Abstractness

What it does: Computes SDP/SAP metrics (Instability I = Fan-out/(Fan-in+out); Abstractness A = abstract classes/total). Plots A/I graph in PNG/CSV.

Install: pip install module_coupling_metrics

Quick usage:

  • Scan package: module_coupling_metrics /path/to/root
  • Output: CSV per module + PNG graph (ideal zone: high A, low I).

Prevents debt by: Enforces stable abstractions; unstable modules drag down scalability. Duck-typing friendly—treats inherited classes as abstract.

Pro tip: For monorepos; run post-refactor to validate splits. AGPL license; PyPI publish via GitHub Actions.

6. Complexipy: Cognitive Complexity

What it does: Rust-powered analyzer for human-readability (e.g., nested loops/if-else). Unlike CCN, it forgives simple nests. Thresholds, snapshots for legacy code.

Install: pip install complexipy (or uv add complexipy)

Quick usage:

  • Scan dir: complexipy . --max-complexity-allowed 10
  • API: from complexipy import file_complexity; result = file_complexity("app.py")
  • Snapshot: complexipy . --snapshot-create (baseline violations)

Prevents debt by: Spots "brain-melting" code before reviews. Inline ignores (# noqa: complexipy); VS Code extension for real-time feedback.

Pro tip: TOML config in pyproject.toml; pre-commit for zero regressions. Blazing fast—handles large codebases.

7. Lizard: Cyclomatic Complexity & Clones

What it does: Multi-language CCN (McCabe), param counts, NLOC, duplicates. Warnings for thresholds; XML/CSV/HTML output. Whitelists generated code.

Install: pip install lizard

Quick usage:

  • Scan: lizard . -C 10 (CCN >10 warns)
  • Duplicates: lizard -Eduplicate .
  • Exclude: lizard . -x "tests/*"
  • Gitignore auto-use.

Prevents debt by: Quantifies branching hell; clone detection cuts copy-paste bugs. 20+ languages; no headers/imports needed.

Pro tip: -T nloc=50 for length limits; Jenkins Checkstyle XML. Python 3.8+; Nix/Flake for reproducible envs.

8. Import Linter: Dependency Rules

What it does: Enforces import contracts (e.g., no cycles, forbidden deps). Custom types for acyclic graphs; checks intra/inter-package flows.

Install: pip install import-linter

Quick usage:

  • Config .importlinter: Define contracts (e.g., forbidden: foo → bar).
  • Lint: lint-imports
  • Custom: Extend via plugins.

Prevents debt by: Locks in layered architectures; breaks circular imports that hide bugs. Team-scale: Fail CI on violations.

Pro tip: Acyclic contract for DAGs; screenshot errors for docs. BSD license; Justfile for tasks.

9. Xenon: Complexity Monitoring

What it does: Radon-based thresholds for average/module/block complexity (A-F ranks). Fails builds on breaches; pre-commit friendly.

Install: pip install xenon

Quick usage:

  • Scan: xenon -a A -m B -b C . (fail if avg >A, etc.)
  • Exclude: xenon -e "*.test.py" .
  • Pre-commit: Args like ['--max-absolute=B'].

Prevents debt by: Commits never introduce complexity spikes; tracks trends in CI. Simple ranks align with "maintainable" intuition.

Pro tip: Travis/GitHub examples in repo; Python 3.6-3.12. Pair with Lizard for deeper dives.

Comparison Table: At a Glance

Comparison Table: At a Glance

Tool Focus Metrics/Output CI Ease Free Tier? Best For
Safety Vulnerabilities Fixes, JSON/SBOM High Yes (limited) Dep scanning
Bandit Security flaws AST plugins, XML High Yes Code security
LCOM Class cohesion LCOM4 scores (table) Med Yes OOP refactoring
Cohesion Var/method usage % cohesion, Flake8 High Yes Class design
Module Coupling Metrics Coupling/Abstractness I/A graph, CSV Med Yes Architecture stability
Complexipy Cognitive complexity Thresholds, snapshots High Yes Readability reviews
Lizard CCN & clones Warnings, duplicates High Yes Multi-lang complexity
Import Linter Import rules Contracts, errors High Yes Dependency hygiene
Xenon Overall complexity A-F ranks, thresholds High Yes Commit/CI gates

Next Steps: Build Your Stack

  1. Audit: Run Lizard + Complexipy on your repo—fix top offenders.
  2. Secure: Add Safety/Bandit to CI.
  3. Architect: Use Import Linter + Module Metrics for layers.
  4. Maintain: Cohesion/LCOM/Xenon in pre-commit.
  5. Scale: Snapshots (Complexipy) for legacy; whitelists (Lizard) for quick wins.

These tools aren't silver bullets, but they enforce discipline where humans falter. Track metrics over time—debt drops, velocity rises. Questions? Dive into docs (linked in each section) or ping the repos. Code clean, ship fast.

Top comments (0)