-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update andi.plan
to support a function/class signature in dict
#23
Comments
andi.plan
which supports dictandi.plan
to support a function/class signature in dict
I think another way to solve this problem without modifying andi would be something like: import attrs
import andi
class BaseDep:
pass
@attrs.define
class Foo:
dep: BaseDep
@attrs.define
class Bar:
dep: BaseDep and then calling >>> is_injectable = lambda x: True
>>> andi.plan(Foo, is_injectable=is_injectable)
[(__main__.BaseDep, {}), (__main__.Foo, {'dep': __main__.BaseDep})]
>>> andi.plan(Bar, is_injectable=is_injectable)
[(__main__.BaseDep, {}), (__main__.Bar, {'dep': __main__.BaseDep})] But we have to be careful to deduplicate any base dependencies that are shared. Having a modified [(__main__.BaseDep, {}),
(__main__.Foo, {'dep': __main__.BaseDep}),
(__main__.Bar, {'dep': __main__.BaseDep}),
(<function __main__.combine(foo: __main__.Foo, bar: __main__.Bar)>,
{'foo': __main__.Foo, 'bar': __main__.Bar})] |
I found a way to prevent modifying andi but still create dynamic class signature using dataclasses.make_dataclass. 🎉 import andi
import attrs
from dataclasses import make_dataclass
class BaseDep:
pass
@attrs.define
class Foo:
dep: BaseDep
@attrs.define
class Bar:
dep: BaseDep
Tmp = make_dataclass("Tmp", [('f', Foo), ('b', Bar)])
is_injectable = lambda x: True
andi.plan(Tmp, is_injectable=is_injectable)
#[(__main__.BaseDep, {}),
# (__main__.Foo, {'dep': __main__.BaseDep}),
# (__main__.Bar, {'dep': __main__.BaseDep}),
# (types.Tmp, {'f': __main__.Foo, 'b': __main__.Bar})] |
Allowing andi to accept I'd probably avoid calling it "signature" or "blueprint", because it enables other possibilities, not tied to signatures. Just an API to create a plan on how to create dependencies, which you can use anywhere. |
Currently,
andi.plan()
works by passing a function or class. This requires them to have their signatures already established:However, there are use cases where we might want to create different types of cars which means that the car signatures could be dynamic which is only determined during runtime.
For example, during runtime the car's wheels could be electric, or the wheels could become tank treads. We could solve this by defining an
ElectricCar
orTankCar
. Yet, this solution doesn't cover all the other permutation of car types, especially when its signature changes if it adds an arbitrary amount of attachments:engine: Engine, wheels: Wheels, top_carrier: RoofCarrier
engine: Engine, wheels: Wheels, top_carrier: BikeRack
engine: Engine, wheels: Wheels, back_carrier: BikeRack, top_carrier: RoofCarrier
We could list down all of the possible dependencies in the signature but that wouldn't be efficient since it takes some effort to fulfill all of them but at the end, only a handful of them will be used.
I'm proposing to update the API to allow such arbitrary signatures to used. This allows something like this to be possible:
andi.plan()
largely remains the same except that it now supports a mapping representing any arbitrary function/class signature.The text was updated successfully, but these errors were encountered: