Closed NikiTsv closed 8 months ago
Hi!
Could you explain, why you chose to use allow_override
at the configuration level, and not override
as a flag in binder.bind(BaseLogger, JobRunLogger, override=True)
.
Do you think allow_override
better suits your current needs?
Hi!
Could you explain, why you chose to use
allow_override
at the configuration level, and notoverride
as a flag inbinder.bind(BaseLogger, JobRunLogger, override=True)
.Do you think
allow_override
better suits your current needs?
Hey, Yes there are a few reasons I had in mind:
override
in Binder
methods, we have to pollute all methods and pass the override
arg to _check_class
to avoid theDuplicate binding check
.binder.bind(..., ..., override=True)
binder.bind_to_constructor(..., ..., override=True)
binder.bind_to_provider(..., ..., override=True)
override=True
and duplicating code so you are safe.
def workflow_module_config(binder):
binder.install(core_module_config)
binder.bind(Logger, SpecialWorkflowLogger) # crashes if core_config decides to add default logger logger
And generally I think it's more clear that when configuring you just set the global behavior during configuration so you are not bothered to think about every line if you need override or not, you just register your service and it works, even if you duplicate it or it gets removed from parent config etc.
What are your thoughts do you think this approach has some drawbacks?
recommendation to points 1 and 2 - when overriding, wrap the Binder with a proxy with the same interface which handles this case ? that way you don't have to spread override=True all over the place, and still allow the override to be as an argument to the binding methods
recommendation to points 1 and 2 - when overriding, wrap the Binder with a proxy with the same interface which handles this case ? that way you don't have to spread override=True all over the place, and still allow the override to be as an argument to the binding methods
Can you elaborate? Do you mean applying changes with the current approach - "allow_override" or the approach for "override" in Binder methods? Can you simple code example?
@NikiTsv
And probably the most important reason is that if you install a configuration like this in another module/environment it "doesn't know" if the base configuration has this binding OR if the base configuration later on adds this binding without you knowing and crashes your configuration.
Ok, so the main reason is you have different composable configurations which can override some bindings in some cases.
I see, I get it.
I'll merge it today.
Might be an over-complication, but allows for both suggested methods in the discussion.
Instead of self.allow_override (which given self._bindings should probably be self._allow_override to denote it is internal property) change bind method on Binder to be
def bind(self, cls: Binding, instance: T, override:bool=False) -> 'Binder':
and add the class
class OverrideBinder(object):
def __init__(self, binder:Binder):
self._binder = binder
def bind(self, cls: Binding, instance: T, override:bool=False) -> 'Binder':
return self._binder.bind(cls, instance ,override=True)
... # the other binding methods
And when wanting to override:
override_binder = OverrideBinder(binder)
override_binder.bind(Klass, instance)
Relates to (https://github.com/ivankorobkov/python-inject/issues/65 discussion).
Preface When configuring injector for different environments often times you need to use a the same core configuration and swap only a few dependencies. This also happens for specific tests when you need to mock something or tweak some service's configuration. The current implementation only allows for installing an exising config with
binder.install
and then build up upon it without overriding dependencies. This unflexibility forces developers to always create configurations from scratch for every environment or for specific tests which leads to code duplications and when introducing new dependencies in your core configuration, you have to specify them in every other config as well.Solution With the following changes configurations are composable with the ability to allow overriding of dependencies for example: