injector
injector copied to clipboard
Support eager singleton
There doesn't seem to be a way to bind eager singletons. The only reference is in the Module's provides method, but this is unreferenced.
def provides(interface, scope=None, eager=False):
Yes, I should remove that from the method signature. I don't think it will be added at this stage.
Not added because it's not under active development or a time issue? Or not useful/practical?
BTW, are you still actively developing the project? Is there a better alternative?
Thanks.
Mostly the latter; not useful enough to warrant the effort IMO.
Yes, Injector is still being developed, it's just mostly stable so there's not much activity.
You can have a look at pinject, but it hasn't been touched in two years and IMO is not as nice as Injector anyway ;)
I can confirm that the lack of activity is due to the code just working.
Fair enough :).
I find myself in a minority of Python developers who can't live without DI, so thanks for this package.
I do however, think eager singletons are important. As would like to see Sequence and Map keys support instantiation by class (rather than by instance). I'll try to send a pull request for the workarounds that I have created.
On Thu, Sep 17, 2015 at 6:14 PM Jakub Stasiak [email protected] wrote:
I can confirm that the lack of activity is due to the code just working.
— Reply to this email directly or view it on GitHub https://github.com/alecthomas/injector/issues/44#issuecomment-141251598.
On a similar note, I'd like to be able instantiate all singletons when my server starts, something analogous to Guice's Stage.PRODUCTION. Any particular reasons why it's not supported? Would you mind if I added it? I'd probably do it as a stage
parameter to Injector
.
I completely forgot this issue was still open :) I wouldn't be against it in principle, I'm just wondering what the actual implementation would look like.
@jstasiak It is used to catch configuration errors on startup, when spawning all singleton services. F.e. I've introduced a breaking change (configuration/compilation error/broke all injections by binding unknown/wrong module). Then I start the service and it is ok till any of injected services will be used.
Another issue is - run some things, like loading and configuring some RO model (~400MB) before spawning workers, so they won't make memory copies of this model.
Yeah I'm not saying it's not useful, it's the implementation I wondered about, the general case seems tricky. For example:
@singleton
SomeClass:
pass
injector = Injector()
eagerly_instantiate_singletons(injector)
With auto_bind
enabled (the default) Injector doesn't know anything about SomeClass
until it's instantiated so the eager instantiation mechanism would need to actively look for classes (All loaded classes? Classes in a particular module?).
Depending on the application the easiest and the most helpful could be to do
for t in [list, of, some, known, singletons, that, can, cause, trouble]:
injector.get(t)
at the start of your program.
BTW not sure if memory saving would work in the scenario you describe, see https://instagram-engineering.com/dismissing-python-garbage-collection-at-instagram-4dca40b29172
So for Guice it only knows about the singletons mentioned in the module or through dependencies. It would be a great start to instantiate those.
I found myself wanting this feature quite badly. I use Injector to inject my service layer in my flask (flask-rebar to be precise) controllers. Some services need to fetch external dependencies, so the first call to the API takes a big hit in performances. I will try the trick of forcing the injector to get the type, but an eager
parameter in the @singleton
decorator would be much cleaner.
I would like to request a feature like this as well. I would like to be able to annotate singletons so that they are automatically instantiated upon creation of the injector.
The reason is that I have a module that is to be included by many injectors that have different set of modules, and it would be nice to not need to do injector.get(MySingleton)
from all the places where injectors are created.
+1 for this feature
in the meantime, I would like to share my solution:
from typing import Callable
from injector import Binder
def eager_initialize(eager_modules: list):
def decorate_function(configure: Callable):
def wrapper(self, binder: Binder, *args, **kwargs):
result = configure(self, binder, *args, **kwargs)
for module in eager_modules:
binder.injector.get(module)
return result
return wrapper
return decorate_function
You can use it as a decorator in your configure Module
method, like this:
class RequestedManufacturerNameModule(Module):
@eager_initialize([RequestedManufacturerNameService])
def configure(self, binder: Binder) -> None:
binder.bind(RequestedManufacturerNameService, scope=singleton)
# ...
You can pass a list of eager classes to it and it should work. But, in any case, it would be way better doing so in the binder
directly.