mmerickel / wired

A service locator implementation for Python.
https://wired.readthedocs.io
MIT License
17 stars 9 forks source link

Support injecting with passed-in-props #34

Closed pauleveritt closed 5 years ago

pauleveritt commented 5 years ago

Replaces #31 and supports PR #33

It is with great pleasure that I demonstrate @mmerickel is wrong. 😄 Or at least, demonstrate a use case for something he correctly pointed out couldn't work.

In #33 I made a small change to let the Injector be passed in some args which would be used before the container when looking stuff up. This is to support my wired_components: in a template, you might do {{ Breadcrumb(label='Hello') }} and label would be passed into the dataclass factory.

@mmerickel pointed out two flaws:

Michael asked for an example to justify a change supporting the second bullet. Here goes.

wired_components

I have a project wired_components with a branch component_decorator that copies in a private injector.py file with the changes I made in the PR.

I made two flavors of my component creation, one without the injector-props change that shows I have to manually provide things:

... and one where I can just use injection:

The second is shorter, but that's less important: it lets me use the features of injection and components can access things in the container other than my hardwired list.

Double Partial

How do the props get there? This is kind of a freaky setup, due to Jinja2. I register partial functions corresponding to each component. The partial function has the container. It points to a function which is callable with the parameters.

So, a double partial, so to speak, with both container and props in scope. I can then pass both into Injector.__call__.

Recommendation

This shows that the Injector is useful beyond just a service container. It can be used, for example, when sniffing standalone functions that might want arguments injected.

At a minimum, it makes my use case much better. I recommend accepting my change (which breaks nothing) and putting Injector in wired.dataclasses.__all__ as part of the public API.

Sidenote: At some point in the future I might resurrect my Jinja2 extension that would eliminate one of those partials. But that's painful and low on the list.

pauleveritt commented 5 years ago

@mmerickel For now I've copied injector.py into my project and I'll use a private copy.

mmerickel commented 5 years ago

I was under the impression originally that you were trying to use the wired.dataclasses.factory and add extra features to it but that doesn't appear to be the case. The injector really only exists to support that api.

I think you just need to vendor the injector for now. You've already written a custom factory that is a superset of features supported in wired. I'm not sure it's the right time to expose the injector publicly just to avoid rewriting that code in your custom extension.