Python SDK migration guide: v0.4 to v0.5
This guide will help you migrate your Inngest Python SDK from v0.4 to v0.5.
New features
- First-class Pydantic support in step and function output (docs)
- Python 3.13 support
- Function singletons (docs)
- Function timeouts (docs)
- Experimental step.infer (docs)
- Improved parallel step performance
Breaking changes
Move step
into ctx
The step
object will be moved to ctx.step
.
Before:
@inngest_client.create_function(
fn_id="provision-user",
trigger=inngest.TriggerEvent(event="user.signup"),
)
async def fn(ctx: inngest.Context, step: inngest.Step) -> None:
await step.run("create-user", create_db_user)
After:
@inngest_client.create_function(
fn_id="provision-user",
trigger=inngest.TriggerEvent(event="user.signup"),
)
async def fn(ctx: inngest.Context) -> None:
await ctx.step.run("create-user", create_db_user)
Parallel steps
step.parallel
will be removed in favor of a new ctx.group.parallel
method. This method will behave the same way, so it's a drop-in replacement for step.parallel
.
@client.create_function(
fn_id="my-fn",
trigger=inngest.TriggerEvent(event="my-event"),
)
async def fn(
ctx: inngest.Context,
step: inngest.Step,
) -> None:
user_id = ctx.event.data["user_id"]
await ctx.group.parallel(
(
lambda: step.run("update-user", update_user, user_id),
lambda: step.run("send-email", send_email, user_id),
)
)
Remove event.user
We're sunsetting event.user
. It's already incompatible with some features (e.g. function run replay).
Disallow mixed async-ness within Inngest functions
Setting an async on_failure
on a non-async Inngest function will throw an error:
async def on_failure(ctx: inngest.Context) -> None:
pass
@client.create_function(
fn_id="foo",
trigger=inngest.TriggerEvent(event="foo"),
on_failure=on_failure,
)
def fn(ctx: inngest.ContextSync) -> None:
pass
Setting a non-async on_failure
on an async Inngest function will throw an error:
def on_failure(ctx: inngest.ContextSync) -> None:
pass
@client.create_function(
fn_id="foo",
trigger=inngest.TriggerEvent(event="foo"),
on_failure=on_failure,
)
async def fn(ctx: inngest.Context) -> None:
pass
Static error when passing a non-async callback to an async step.run
When passing a non-async callback to an async step.run
, it will work at runtime but there will be a static type error.
@client.create_function(
fn_id="foo",
trigger=inngest.TriggerEvent(event="foo"),
)
async def fn(ctx: inngest.Context) -> None:
# Type error because `lambda: "hello"` is non-async.
msg = await step.run("step", lambda: "hello")
# Runtime value is "hello", as expected.
print(msg)
inngest.Function
is generic
The inngest.Function
class is now a generic that represents the return type. So if an Inngest function returns str
then it would be inngest.Function[str]
.
Middleware order
Use LIFO for the "after" hooks. In other words, when multiple middleware is specified then the "after" hooks are run in reverse order.
For example, let's say the following middleware is defined and used:
class A(inngest.MiddlewareSync):
def before_execution(self) -> None:
# ...
def after_execution(self) -> None:
# ...
class B(inngest.MiddlewareSync):
def before_execution(self) -> None:
# ...
def after_execution(self) -> None:
# ...
inngest.Inngest(
app_id="my-app",
middleware=[A, B],
)
The middleware will be executed in the following order for each hook:
before_execution
--A
thenB
.after_execution
--B
thenA
.
The "before" hooks are:
before_execution
before_response
before_send_events
transform_input
The "after" hooks are:
after_execution
after_send_events
transform_output
Remove middleware hooks
before_memoization
after_memoization
Remove experimental stuff
inngest.experimental.encryption_middleware
(it's now the inngest-encryption package).experimental_execution
option on functions. We won't support nativeasyncio
methods (e.g.asyncio.gather
) going forward.
Dependencies
Drop support for Python 3.9
.
Bump dependency minimum versions:
httpx>=0.26.0
pydantic>=2.11.0
typing-extensions>=4.13.0
Bump peer dependency minimum versions:
Django>=5.0
Flask>=3.0.0
fastapi>=0.110.0
tornado>=6.4