Ididi

Latest version: v1.5.4

Safety actively analyzes 722491 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 11

1.5.3

- `Factory method`,
python

class InfraBuilder:

dg.factory
def repo_maker(self) -> UserRepo:
return UserRepo

as well as

dg.factory(InfraBuilder().repo_maker)

1.5.2

- ~~Make both `Graph` and `Scope` self-injectable, when resolve `Resolver` within a graph, return the graph, if resolve it within a scope, return the scope~~

Cancel, this would scope circular reference itself,
and user can use `dg.use_scope` to get the current scope, this is not worthy it.


- remove `UnsolvableDependencyError` error, which means that we no longer try to analyze builtin types

1.5.1

- support extra params to dependencies and overrides-reuse, this allows us to do complex dependency resolution,

python
dg = Graph()

def dep3(e: int) -> Ignore[str]:
return "ok"

def dependency(a: int, a2: Annotated[str, use(dep3)]) -> Ignore[int]:
return a

def dep2(k: str, g: Annotated[int, use(dependency)]) -> Ignore[str]:
assert g == 1
return k

def main(
a: int,
b: int,
c: Annotated[int, use(dependency)],
d: Annotated[str, use(dep2)],
) -> Ignore[float]:
assert d == "f"
return a + b + c

assert dg.resolve(main, a=1, b=2, k="f", e="e") == 4


the downside is that now `Graph.resolve` is 1.3x slower, we might find a way to reduce this in next few patches, but this feature is really needy right now.


- `Graph.entry` no longer ignore builtin-types by default, now user should specifically ignore builtin params. This is mainly for
1. resolve and entry to have similar behaviors
2. user might be confused by what will be automatically ignored, Ignore[T] is more explicit

- rollback a behavior introduced in `version 1.4.3`, where Ignored params were not considered as dependencies, now they are dependencies again.

- `Graph.resolve` no longer maintain ParamSpec, since for a factory `Callable[P, T]`, `Graph.resolve` can accept either more params than P, less params P, or no params P at all, it does not make much sense to maintain paramspec anymore

1.5.0

- consider switch to anyio[cancel]
- rewrite ididi in cython
- make ididi resolve overhead < 100%. make it as fast as hard-coded
factories as possible.

- support return dependency[cancel]

python
def json_encode(r: Any) -> bytes:
return orjson.dumps(r)

type Json[T] = Annotated[T, use(json_encode)]

async def create_user(user_id: str = "u") -> Json[User]:
return User(user_id=user_id)

assert isinstance(dg.resolve(create_user), bytes)



here we will serialize the result of `create_user`
we can also refactor how we deal with resource right now
by applying `scope.enter_context` to result, so instead of

python
async def get_conn() -> AsyncGenerator[Connection, None, None]
...


user can write

pythpn

def enter_ctx(scope: Scope):
await scope.resolve()


Scoped = Annotated[T, scope_factory]




python
from ididi import Scoped



class Connection:
...

async def aget_conn() -> Scoped[Connection]:
conn = Connection()
yield conn


def get_conn() -> Scoped[Connection]:
conn = Connection()
yield conn

1.4.4

- refactor scope, now user can create a new scope using `scope.scope`

python
def test_scope_graph_share_methods():
dg = Graph()

with dg.scope() as s1:
with s1.scope() as s2:
...


- `Graph.get` / `Scope.get`


*create scope from graph* vs *crate scope from scope*

the created scope will `inherit` resolved instances and registered singletons from its creator, thus

- when create from graph, scope inherit resolved instances and registered singletons from graph

- when create from scope, scope inherit resolved instances and registered singletons from the parent scope.

Example
python
dg = Graph()

class User: ...
class Cache: ...

dg_u = dg.resolve(User)

with dg.scope() as s1:
s1_u = s1.resolve(User)
assert s1_u is dg_u
s1_cache = s1.resolve(Cache)
dg_cache = dg.resolve(Cache)
assert s1_cache is not dg_cache

with s1.scope() as s12:
assert s12.resolve(User) is dg_u
s12_cache = s12.resolve(Cache)
assert s12_cache is s1_cache
assert s12_cache is not dg_cache

with dg.scope() as s2:
s2_u = s2.resolve(User)
assert s2_u is dg_u
s2_cache = s2.resolve(Cache)
assert s2_cache is not s1_cache




versio 1.4.5(plan)

- [x] support resolve from class method

python
class Book:
classmethod
def from_article(cls, a: str) -> "Book":
return Book()


pytest.mark.debug
def test_resolve_classmethod():
dg = Graph()
b = dg.resolve(Book.from_article, a="5")
assert isinstance(b, Book)


- [x] make `Mark` public, user can use it with `typing.Annotated`

python
Ignore = Annotated[T, IGNORE_PARAM_MARK]

so this works:

python
def get_conn(url: Annotated[str, IGNORE_PARAM_MARK]):
...


python
def get_repo(conn: Annotated[Connection, USE_FACTORY_MARK, get_conn, NodeConfig]):
...


- [x] provide a more non-intrusive way to node config, where user only need to add new code, no modifying current code, not even decorator.

python
class AuthRepo: ...
class TokenRegistry: ...

def get_auth() -> AuthRepo: ...
def get_registry() -> TokenRegistry: ...

class AuthService:
def __init__(self, auth_repo: AuthRepo, token: TokenRegistry): ...

dg = Graph()
dg.add_nodes(
get_conn,
(get_auth, {"reuse": False, "ignore":"name"})
)


- make a re-use params version of `Graph.resolve`,

python
from typing import Any, NewType

class Request: ...

RequestParams = NewType("RequestParams", dict[str, Any])


async def test_resolve_request():
dg = Graph()

async def resolve_request(r: Request) -> RequestParams:
return RequestParams({"a": 1})

dg.node(resolve_request)
await dg.shared_resolve(resolve_request, r=Request())

1.4.3

Improvements:

50% performance boost for `Graph.resolve/aresolve/entry`

Features:

- `Graph` now receives `workers: concurrent.futures.ThreadPoolExecutor` in constructor

- send entering and exiting of `contextmanager` in a diffrent thread when using `AsyncScope`, to avoid blocking.

python
def get_session() -> Generator[Session, None, None]:
session = Session()
with session.begin():
yield session

async with dg.ascope() as scope:
ss = await scope.resolve(get_session)

Here, entering and exiting `get_session` will be executed in a different thread.

- `Graph` now create a default scope, `Graph.use_scope` should always returns a scope.
- Split `Graph.scope` to `Graph.scope` and `Graph.ascope`.
- Deprecate `DependencyGraph`, `DependencyGraph.static_resolve`, `DependencyGraph.static_resolve_all`
- variadic arguments, such as `*args` or `**kwargs` without `typing.UnPack`, are no longer considered as dependencies.
- Builtin types with provided default are no longer considered as dependencies.
- `Dependency.unresolvabale` is now an attribute, instead of a property.

Page 1 of 11

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.