Skip to content

Developer Code Standards

Jason Rhubottom edited this page Apr 20, 2026 · 1 revision

Developer Code Standards

Python Style Guide

We use Ruff for linting and formatting, configured in pyproject.toml.

Configuration:

  • Select: ["ALL"] - Enable all rules by default
  • Specific ignores for formatter conflicts and false positives
  • Home Assistant import conventions: cv, dr, er, ir, vol
  • Force sorting within sections for imports

Run linting:

./scripts/lint

Import Order

Imports are organized into sections:

"""Module docstring."""
# 1. Future imports
from __future__ import annotations

# 2. Standard library
import logging
from typing import Any

# 3. Third-party libraries
import voluptuous as vol
from astral import LocationInfo

# 4. Home Assistant core
from homeassistant.core import HomeAssistant, callback
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers import config_validation as cv

# 5. Local imports
from .const import DOMAIN, CONF_SENSOR_TYPE
from .coordinator import AdaptiveDataUpdateCoordinator

Async Best Practices

This integration uses Home Assistant's async architecture:

DO:

async def async_my_function():
    """Async function."""
    result = await some_async_call()
    return result

@callback
def _sync_callback():
    """Callback function (no I/O)."""
    return value

DON'T:

def blocking_function():
    """This blocks the event loop!"""
    time.sleep(1)  # ❌ Never block!
    return requests.get(url)  # ❌ Use aiohttp!

Rules:

  • Never block the event loop
  • Use async/await for I/O operations
  • Use @callback decorator for sync callbacks
  • Use hass.async_add_executor_job() for blocking calls

Logging

Use the logging adapter with context:

from .config_context_adapter import get_adapter

_LOGGER = logging.getLogger(__name__)

# In your class
self._adapter = get_adapter(_LOGGER, self._name)

# Log with context
self._adapter.debug("Message here")

Log levels:

  • debug() - Detailed diagnostic information
  • info() - General informational messages
  • warning() - Warning messages (recoverable issues)
  • error() - Error messages (serious problems)

Entity Naming

Follow Home Assistant conventions:

# Entity ID format
entity_id = f"{domain}.{type}_{description}_{name}"

# Examples
"sensor.adaptive_cover_position_living_room"
"switch.adaptive_cover_control_bedroom"
"binary_sensor.adaptive_cover_sun_in_window_office"

Configuration Validation

Use Home Assistant's voluptuous integration:

import voluptuous as vol
from homeassistant.helpers import config_validation as cv

CONFIG_SCHEMA = vol.Schema({
    vol.Required(CONF_NAME): cv.string,
    vol.Optional(CONF_FOV, default=90): vol.All(
        vol.Coerce(int),
        vol.Range(min=1, max=180)
    ),
})

Clone this wiki locally