Skip to content

no-dict-return-annotation (BTDM004)

Added in 0.8.0 · Stable · Enabled by default (error)

Family: data-models · Standard: CES-79 · Languages: python

Directive

A boundary function returns a typed structure, never a raw dict: a @dataclass for internal boundaries, or a pydantic BaseModel where validation or serialization is needed (a FastAPI endpoint, for one). An error by default.

A boundary function is a function of a module or a method of a class, whose name and whose class name do not start with _, and that is not defined inside another function. The rule skips private and nested functions.

This rule catches a function (def or async def) annotated to return dict or dict[...].

A lookup table, whose keys are data and not field names, is declared with an alias whose name ends in Table (StatusTable = dict[str, str]); the rule accepts it.

Why

  • The type checker cannot check the keys of a dict[str, Any], so a renamed key breaks its callers at run time.
  • A @dataclass or BaseModel declares the fields, and the type checker checks them.

Do

from dataclasses import dataclass


@dataclass
class Point:
    x: int
    y: int


def origin() -> Point:
    return Point(x=0, y=0)

Don't

def payload() -> dict:
    return load()

Suppression

A comment on the def line silences it.

def payload() -> dict:  # botica: ignore[no-dict-return-annotation]
def payload() -> dict:  # noqa: BTDM004 -- reason

References

Discussion