InitO#

A zero-dependency Python library that eliminates data-class boilerplate.

Decorate a class and InitO writes the mechanical methods it needs — constructor, repr, equality, hashing, accessors, and builders — as real methods, generated once when the class is defined, never at construction or attribute-access time. Your objects stay ordinary Python instances and run as fast as code you’d write by hand.

from inito import Data


@Data
class User:
    name: str
    age: int = 0


user = User("Ada", age=30)
print(user)                      # User(name='Ada', age=30)
print(user.get_name())           # Ada
user.set_age(31)
print(user == User("Ada", 31))   # True

By hand, User is ~20 lines of __init__, __repr__, __eq__, __hash__, and accessors. With InitO it’s the three lines above — and the generated methods are the same code you’d have written, benchmarked at parity with handwritten classes and dataclasses.

pip install inito       # or:  uv add inito

Requires Python 3.9+ (tested through 3.14). No runtime dependencies.

Quick start

Install InitO and tour every decorator in a few minutes.

Quick start
Concepts

The boilerplate problem InitO solves — and how it stays fast.

Concepts: the problem InitO solves
User Guide

A dedicated page per decorator, plus DI, recipes, and migration.

User Guide
Dependency injection

Wire object graphs with @Service/@Singleton/@Inject and a Container.

Dependency injection
Recipes

Real-world, copy-pasteable patterns combining several decorators.

Recipes
API reference

Every decorator, option, and exception, generated from the source.

API reference

Why InitO#

  • Real methods, generated once. Each decorator builds true Python functions from your fields at decoration time and attaches them — no __getattr__, proxies, descriptors, or runtime interception. At runtime your objects are ordinary instances, so construction, attribute access, ==, and hash() run at handwritten speed.

  • Zero runtime dependencies. InitO imports nothing outside the standard library, so it installs cleanly into any project and any environment.

  • À la carte. @Data is the all-in-one, but every capability is also a standalone decorator (@Getter, @ToString, @EqualsAndHashCode, …) — you never pay for what you don’t ask for.

  • Typed for both checkers. A bundled mypy plugin makes mypy --strict see every generated member, and inito-stubgen does the same for pyright / Pylance.

  • Batteries included. Genuine immutability (@Value), fluent builders (@Builder), environment-backed configuration (@Config), and a small dependency-injection layer — same generate-once, zero-dependency design throughout.

Decorators at a glance#

Decorator

Generates

Guide

@Data

constructor · __repr__ · __eq__ · get_x/set_x — the all-in-one (__hash__ when frozen)

@Data

@Value

like @Data but immutable and setter-free

@Value

@Getter / @Setter

get_x() / set_x(value) accessors only

Accessors

@ToString

__repr__ only

@ToString

@EqualsAndHashCode

__eq__ + __hash__ only

@EqualsAndHashCode

@NoArgsConstructor · @AllArgsConstructor · @RequiredArgsConstructor

an __init__ and nothing else

Constructors

@Builder / builder

fluent Cls.builder().x(1).build(), optional .to_builder()

@Builder

@Config

load fields from environment variables, autowired by type

@Config

@Jsonize

to_dict()/to_json() serializing every field (datetime, UUID, Decimal, …)

@Jsonize

@Service / @Singleton / @Inject

dependency injection via a Container

DI

Every PascalCase decorator has a lowercase alias (data, builder, value, …) bound to the same object — use whichever reads better.

Dependency injection#

A small, lazy, thread-safe DI layer: declare a class’s dependencies as fields, and a Container wires them — no markers, no provider objects. @RequiredArgsConstructor even writes the constructor for you.

from inito import Inject, RequiredArgsConstructor, Service, Singleton


@Singleton
class Database:
    rows = {1: "Ada"}


@Service
@RequiredArgsConstructor
class UserService:
    db: Database                      # autowired from the container


@Inject
def main(service: UserService) -> None:
    print(service.db.rows[1])         # Ada


main()

It also supports scopes (singleton, transient, thread-local), qualifiers for multiple implementations, config injection, factories for on-demand construction with call-time arguments, resource lifecycle with ordered teardown (@Resource, with container), scopes (Scope.SCOPED + container.scope()), async resolution (await container.aget()), FastAPI Injected[T], and test overrides.

Type checking#

InitO attaches members at decoration time, so type-checkers need a hint — and it ships one for both. Enable the mypy plugin for mypy --strict, or run inito-stubgen to generate .pyi stubs that give pyright / Pylance the same full visibility.

Works with your framework#

Zero dependencies and plain methods on plain classes mean InitO drops into any project. On a Pydantic / SQLAlchemy / Django model, use the additive decorators and let the framework own construction; the DI layer resolves safely from async handlers. See Using InitO with your framework — with runnable examples for FastAPI, Django, Sanic, aiohttp, Redis, boto3, and more.

When to use InitO#

Reach for InitO on the classes that are mostly data — DTOs, domain/value objects, configuration, and service objects. It removes the mechanical methods they need without changing what they are: after decoration they’re still plain Python classes you can subclass, pickle, and construct directly. It composes with, rather than replaces, validation/ORM layers like Pydantic and SQLAlchemy.