injector icon indicating copy to clipboard operation
injector copied to clipboard

Question about the example code and intended use

Open chriscoindeskindices opened this issue 1 year ago • 2 comments

The example code on the main page:

>>> def configure_for_testing(binder):
...     configuration = Configuration(':memory:')
...     binder.bind(Configuration, to=configuration, scope=singleton)

and

>>> injector = Injector([configure_for_testing, DatabaseModule()])
>>> handler = injector.get(RequestHandler)
>>> tuple(map(str, handler.get()[0]))  # py3/py2 compatibility hack
('hello', 'world')

etc etc.

In this example it looks like we use binding through a global function, we create a module, and we create a class with an @inject annotation.

Was this simply to illustrate all the ways that are possible to use this package and not a realistic example? For me, I've done everything in a module so my classes being injected are decoupled from the injector package and annotations. I view the module almost like a docker container + factory + builder pattern where everything is encapsulated and I use it as a black box by just saying "give me object" and it does the rest.

To me this is preferable for my use case, but I just want to make sure I'm not missing something I should be doing. Thanks.

chriscoindeskindices avatar Aug 26 '23 15:08 chriscoindeskindices

Hey,

While I'm tempted to actually get rid of that example now or at least rewrite it I think it's reasonably realistic.

I feel I don't fully understand your question, however – do you maybe have an example that would illustrate what you're unsure about and what you're doing differently?

jstasiak avatar Sep 05 '23 23:09 jstasiak

For my purposes, which may be very very simple, I am only extending Module. So my application looks something like this:

class MyModule(Module):
  @provider
  def foo():
    return Foo()

  @provider
  def bar():
    return Bar()
    
  @provider
  def FooBar(foo, bar):
    return FooBar(foo, bar)
    
if __name__ == "__main__":
  injector = Injector(MyModule())

  fb = injector.get(FooBar)
  fb.run()

So this fits my purpose and it's great because I can create a base version of MyModule and extend that class, override or add other provider functions to create different versions of FooBar or FooBar's descendants, of which there are many. I've written my code in a way so that I can create, configure, and inject all variations at the module level. It works great for unit testing as well if I need to stub out providers with a mock provider that, for example returns some hardcoded value instead of actually querying a database.

My project is probably pretty small where this makes sense. I suppose I like it in this manner, and not using @inject in any class because then the only class coupled to a framework is MyModule. If I had to for whatever reason, I could duplicate what MyModule does with vanilla python, but it would look a bit messy.

Perhaps, I am missing some of the benefits of doing injection with the other methods.

chriscoindeskindices avatar Oct 07 '23 04:10 chriscoindeskindices