Introduction
effecton is a typed effect system for Python, inspired by Effect-TS. It is early stage and experimental.
The core type is Effect[A, E, R]: a description of a computation that succeeds with A, fails with a typed error E, and requires R dependencies. Building an effect performs no work. You get a plain value that you can compose, pass around and test, and a runner executes it at the edge of your program.
Installation
effecton requires Python 3.14 or later.
uv add effecton
# or
pip install effectonA first program
Consumer code imports the package once as E and reaches everything through it. Hover any name in the snippet to see the type ty infers for it.
from dataclasses import
from typing import
import effecton as E
# Custom errors extend EffectonError and are final: one leaf class per cause
@
@(frozen=True)
class (E.):
:
# Succeeds with str, fails with SecretInvalidError or an HTTP error,
# and requires an HttpClient
@E.
def () -> E.[
,
| E.HttpClient. | E.HttpClient.,
E.HttpClient.,
]:
= yield from E.(E.HttpClient.)
= yield from .("https://example.com/secret")
= yield from E.HttpClient.()
if . != "hunter2":
yield from E.((.))
return .
# The program can only run once its requirements are provided
program = ().(E.HttpClient.)(E.HttpClient.())
match E.():
case E.(value):
() # "hunter2"
case E.(cause):
() # Fail(SecretInvalidError(...)) or Fail(StatusError(...))Three things happen here:
- Errors are typed. The signature lists every way
check_secretcan fail.catchhandles one error class at a time and removes it from the type, so the checker knows what is left. - Requirements are visible.
E.requireputsHttpClient.Protocolinto theRchannel. Forgetting to provide it is a type error, not a runtime surprise, and a test can provideE.HttpClient.Testinstead of the live client. - Nothing runs until you say so.
programis a value.run_sync_exitinterprets it and returns anExitto match on.run_syncreturns the value and raises on failure.
What you get
- Type-safe errors. One frozen
EffectonErrordataclass per failure cause, precise unions in signatures, andcatch/catch_allto handle them. - Dependency injection. Requirements are part of the type. Provide them one at a time with
provide(T)(impl). - Resource management.
on_exitfinalizers andScoperelease resources in reverse order, on success and failure alike. - Generator syntax.
@E.genwithyield fromreads like ordinary sequential code while staying fully typed. - A standard library. Logger,
Clock,Random,FileSystem,ProcessandHttpClientservices, each with a live and a test implementation, plus fibers, racing, timeouts and retries. - Sync and async runners. The same effect runs under
run_syncorrun_async.run_mainis the entry point for CLIs and reports failures with proper exit codes.
Where next
The docs are being written. Until they cover more ground, the README on GitHub walks through every feature with examples, and skills-cli is a small CLI built entirely on effecton services.