Documentation Index
Fetch the complete documentation index at: https://mintlify.com/home-assistant/core/llms.txt
Use this file to discover all available pages before exploring further.
Home Assistant maintains high code quality standards through automated linting, formatting, and type checking.
Ruff
Ruff is a fast Python linter and formatter that enforces code style and catches common issues.
Running Ruff
# Check for issues
ruff check .
# Check and automatically fix issues
ruff check --fix .
# Format code
ruff format .
# Check only changed files
prek run ruff-check
Configuration
Ruff is configured in pyproject.toml:
[tool.ruff]
required-version = ">=0.15.1"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes/autoflake
"W", # pycodestyle warnings
"I", # isort (import sorting)
"UP", # pyupgrade (modern Python syntax)
"ASYNC", # flake8-async
"B", # flake8-bugbear
"SIM", # flake8-simplify
"PL", # pylint
"RUF", # ruff-specific rules
# ... and many more
]
Pylint
Pylint provides deeper code analysis with custom Home Assistant plugins.
Running Pylint
# Lint a specific file
pylint homeassistant/components/light/init.py
# Lint changed files
script/lint
# Lint via pre-commit
prek run pylint
Custom Plugins
Home Assistant includes custom pylint plugins in pylint/plugins/:
- hass_async_load_fixtures - Validates fixture loading patterns
- hass_decorator - Checks decorator usage
- hass_enforce_class_module - Ensures classes are in correct modules
- hass_enforce_sorted_platforms - Enforces platform sorting
- hass_enforce_type_hints - Requires type hints
- hass_imports - Validates import patterns
- hass_logger - Checks logger usage
Configuration
Pylint is configured in pyproject.toml:
[tool.pylint.MAIN]
py-version = "3.14"
jobs = 2
load-plugins = [
"pylint.extensions.code_style",
"pylint.extensions.typing",
"hass_async_load_fixtures",
"hass_decorator",
# ... custom plugins
]
Mypy
Mypy performs static type checking to catch type-related bugs.
Running Mypy
# Check all files
mypy homeassistant/
# Check specific file
mypy homeassistant/components/light/__init__.py
# Via pre-commit
prek run mypy
Type Hints
All new code must include type hints:
from homeassistant.core import HomeAssistant
from homeassistant.config_entries import ConfigEntry
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
) -> bool:
"""Set up from a config entry."""
return True
Strict Typing
Certain modules enforce strict typing. These are tracked in the .strict-typing file.
Codespell
Catches spelling mistakes in code, comments, and documentation.
# Check spelling
codespell
# Via pre-commit
prek run codespell
Configuration in .pre-commit-config.yaml:
- id: codespell
args:
- --ignore-words-list=aiport,astroid,checkin,currenty,hass,iif,incomfort,lookin,nam,NotIn
- --skip="./.*,*.csv,*.json,*.ambr"
- --quiet-level=2
Hassfest
Validates integration metadata, manifests, and configurations.
# Run hassfest checks
python3 -m script.hassfest
# Via pre-commit
prek run hassfest
Hashfest validates:
- Integration manifests (
manifest.json)
- Service definitions (
services.yaml)
- String translations (
strings.json)
- Icons (
icons.json)
- Requirements and dependencies
Pre-commit Hooks
Home Assistant uses prek (a pre-commit hook manager) to run quality checks automatically.
Install Hooks
Hook Configuration
Hooks are defined in .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
- repo: https://github.com/codespell-project/codespell
hooks:
- id: codespell
- repo: local
hooks:
- id: mypy
entry: script/run-in-env.sh mypy
- id: pylint
entry: script/run-in-env.sh pylint --ignore-missing-annotations=y
- id: hassfest
entry: script/run-in-env.sh python3 -m script.hassfest
Running Hooks Manually
# Run all hooks on all files
prek run --all-files
# Run specific hook
prek run ruff-check --all-files
# Run hooks on specific files
prek run --files path/to/file.py
Code Style Guidelines
Imports
Imports should be organized and sorted:
"""Module docstring."""
# Standard library imports
import asyncio
import logging
from typing import Any
# Third-party imports
import voluptuous as vol
# Home Assistant imports
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
Ruff’s isort integration handles this automatically:
[tool.ruff.lint.isort]
force-sort-within-sections = true
known-first-party = ["homeassistant"]
combine-as-imports = true
Docstrings
Use Google-style docstrings:
def my_function(param1: str, param2: int) -> bool:
"""Brief description of function.
Longer description if needed.
Args:
param1: Description of param1.
param2: Description of param2.
Returns:
Description of return value.
Raises:
ValueError: When parameter is invalid.
"""
return True
Configuration:
[tool.ruff.lint.pydocstyle]
convention = "google"
Line Length
Maximum line length is not strictly enforced (E501 is disabled), but keep lines reasonable for readability. Ruff’s formatter will handle most cases.
Naming Conventions
- Variables and functions:
snake_case
- Classes:
PascalCase
- Constants:
UPPER_CASE
- Private methods:
_leading_underscore
Async Code
Prefix async functions with async_:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from config entry."""
await async_initialize()
return True
Common Issues and Fixes
Import Sorting
If imports are out of order:
ruff check --select I --fix path/to/file.py
Type Hint Issues
Add missing type hints:
# Before
def my_function(hass, config):
pass
# After
def my_function(hass: HomeAssistant, config: dict[str, Any]) -> None:
pass
Pylint: Too Many Arguments
Refactor functions with too many parameters:
# Before: Too many arguments
def setup(hass, config, arg1, arg2, arg3, arg4, arg5, arg6):
pass
# After: Use a config object or dataclass
from dataclasses import dataclass
@dataclass
class SetupConfig:
arg1: str
arg2: int
# ...
def setup(hass: HomeAssistant, config: SetupConfig) -> None:
pass
Complexity Issues
If code is too complex (McCabe complexity > 25), refactor:
# Break complex functions into smaller ones
def complex_function():
result = _step_one()
result = _step_two(result)
return _step_three(result)
def _step_one():
pass
def _step_two(data):
pass
def _step_three(data):
pass
Integration Quality Scale
Home Assistant uses a quality scale for integrations:
- Platinum - Highest quality, exemplary code
- Gold - High quality, good example to follow
- Silver - Good quality
- Bronze - Basic quality requirements met
Quality level is indicated in manifest.json:
{
"domain": "example",
"quality_scale": "gold"
}
When looking for code examples, refer to Platinum or Gold-level integrations.
Automated Checks
All checks run automatically in CI/CD:
On Pre-commit
- Ruff formatting and linting
- Codespell
- Mypy type checking (for changed files)
- Pylint (for changed files)
- Hassfest validation
On Pull Request
- All pre-commit checks
- Full test suite
- Coverage report
- Additional validation checks
Best Practices
Write Clean Code
- Keep it simple - Avoid unnecessary complexity
- Be consistent - Follow existing patterns
- Use type hints - Makes code self-documenting
- Add docstrings - Explain what and why, not how
- Handle errors - Don’t let exceptions crash Home Assistant
- Avoid blocking I/O - Use async for I/O operations
- Cache when appropriate - Don’t repeat expensive operations
- Clean up resources - Implement proper shutdown handlers
Security
- Validate input - Never trust user input
- Use constants - Avoid hardcoded secrets
- Handle credentials safely - Use config entries for sensitive data
Resources