rename @service to @injectable & add factory argument
Finistere opened this issue · 4 comments
@injectable
is less specific than @service
The factory argument would only allow class/static method names:
from antidote import injectable
@injectable(factory='build')
class Element:
@classmethod
def build(cls) -> Element:
return Element()
This would make it easier to use other injectables only for build purposes without interfering with __init__
which can be typically generated when using @dataclass
. Another advantage is allowing to use a stateful factory:
from antidote import injectable, inject
@injectable
class ElementFactory:
def create(self) -> Element:
return Element()
@injectable(factory='build')
class Element:
@classmethod
def build(cls, factory: ElementFactory = inject.me()) -> Element:
return factory.create()
Now one may ask why only static/class methods and not directly the function? The purpose is to avoid abusive use of @injectable
on class which one doesn't own:
# redis library
class Redis:
pass
from antidote import injectable, inject
# Forcing a method makes declaring a factory for Redis impossible without it being there already.
injectable(Redis, factory='???')
Regarding without interfering with __init__
... I believe __post_init__
plays this role. Differences: __post_init__
isn't actually the initializer, it does work after instantiation and (b) perhaps you want to allow injection on build
.
Minor DX note...in wired
we looked for a specially-named __wired_factory__
class method. Perhaps you could eliminate need for factory=build
for most cases?
Differences: post_init isn't actually the initializer, it does work after instantiation
Yes, which means you can't use an external factory to build the class, which is useful if you want to keep some state to build non-singleton injectables typically.
and (b) perhaps you want to allow injection on build.
All methods, including __post_init__()
and build()
if defined, are injected by default with @injectable
/@service
. Controlled by the wiring
argument. Using @inject
directly overrides anything declared by wiring
.
Minor DX note...in wired we looked for a specially-named wired_factory class method. Perhaps you could eliminate need for factory=build for most cases?
Good point! It would probably be named __antidote_factory__()
. But unsure about it, it feels long as a name a bit intrusive in the sense that it's more tightly coupled with the Antidote framework, even though there's nothing specific about it. Contrary to predicates typically. As a user, I'll probably test the factory directly and as such would probably prefer writing and using a name that makes the most sense to me rather than __antidote_factory__()
. So for now I'll avoid it as it's easier to add than remove.
Released in 1.3.0