Skip to content

Static Analysis — mypy, Pyright, wemake-python-styleguide

mypy — Static Type Checker (CI Standard)

uv add --dev mypy
uv run mypy .
uv run mypy src/ --strict

Configuration

[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_any_generics = true
no_implicit_reexport = true

[[tool.mypy.overrides]]
module = ["tests.*"]
disallow_untyped_defs = false

Common Type Stubs

uv add --dev types-requests types-PyYAML types-redis types-toml

Useful Flags

Flag Purpose
--strict Enable all strict checks
--ignore-missing-imports Skip untyped third-party libs
--show-error-codes Show error codes like [arg-type]
--no-implicit-optional None must be explicit in Optional
--warn-unreachable Detect dead code after return/raise

Pyright — IDE Type Checker (Real-Time)

Best for VS Code / Pylance integration with very fast feedback and solid type inference.

Install (Standalone)

uv add --dev pyright
uv run pyright

Configuration (pyproject.toml)

[tool.pyright]
pythonVersion = "3.12"
typeCheckingMode = "strict"
reportMissingTypeStubs = "warning"
reportUnusedImport = "error"

mypy vs Pyright

mypy Pyright
Speed Slower (daemon helps) Usually faster on large projects
Conformance Mature and stable Very good typing-spec support
IDE integration Basic Excellent (Pylance)
Plugin ecosystem SQLAlchemy, Django, Pydantic Limited
Best for CI pipelines IDE real-time feedback

Best practice: Use both — Pyright in IDE, mypy in CI.


wemake-python-styleguide — Strictest Linter

Flake8 plugin with strict WPS rules. Complements Ruff with additional constraints.

Install

uv add --dev wemake-python-styleguide flake8

Run

uv run flake8 . --select=WPS     # only WPS rules (Ruff handles the rest)

Configuration (setup.cfg)

[flake8]
select = WPS
max-line-length = 100
max-cognitive-score = 12
max-function-score = 8
max-module-members = 10
max-local-variables = 8
max-returns = 5

per-file-ignores =
    tests/*.py: WPS226, WPS432

What WPS Commonly Catches

Rule Example
WPS110 Wrong variable name (data, item, info)
WPS125 Builtin shadowing (list = [1, 2])
WPS226 String constant overuse
WPS231 Too high cognitive complexity
WPS432 Magic number in code

Workflow: Ruff + WPS Together

uv run ruff check . --fix && uv run ruff format .
uv run flake8 . --select=WPS
uv run mypy .

Ruff handles speed-critical linting + formatting; WPS adds strictness layer on top.