Skip to content

0.78.0

Choose a tag to compare

@antonrh antonrh released this 28 Jul 08:28
· 59 commits to main since this release

Faster resolution

CodSpeed reports a 19.86% overall improvement, with all 15 benchmarks faster: transient scopes by ~38%, request scopes by ~15%, singletons by ~13%.

Behaviour is unchanged. The override check no longer runs on every resolution, cached singletons skip the compiled resolver, generated resolvers lost the checks that are known at compile time, and scoped contexts are a class instead of nested generators.

Isolated scope re-entry

Entering an active scope reuses its context. Pass isolated=True to open a fresh one that is restored on exit:

async def handle(item: Item) -> None:
    async with container.ascoped_context("db", isolated=True):
        session = await container.aresolve(Session)
        await session.execute(insert_result(item))

Without it, concurrent tasks share the parent session and can commit its transaction.

See Re-entering an active scope.

Fixes

  • A scope is now left correctly when its body raises. The context variable was not reset, so the next request in the same task reused the failed request's context.
  • In test mode, an instance resolves the scoped dependencies of the context it was created in, not of the context active when the attribute is read.
  • unregister() drops the compiled resolvers, so resolving an unregistered dependency raises LookupError instead of building it from the removed provider. Unregistering by alias releases the instance too.
  • sniffio is no longer a dependency. The Typer extension uses it when available and falls back to asyncio detection.

What's Changed

Full Changelog: 0.77.0...0.78.0