injector icon indicating copy to clipboard operation
injector copied to clipboard

Default provider

Open comtihon opened this issue 6 years ago • 5 comments

Case:

class TokenService(metaclass=ABCMeta):
    @abstractmethod
    def authorize_token(self, auth_header: str) :
        pass

@singleton
class JWTTokenService(TokenService):
...

JWTTokenService is the default implementation for TokenService, even if it has multiple implementations. For now I have to do:

def set_up_injector():
    def token_provider(binder):
        binder.bind(TokenService, JWTTokenService)

    return Injector([token_provider])

It would be nice to have something like @ImplementedBy(JWTTokenService) instead.

Regards, Val

comtihon avatar Sep 14 '18 13:09 comtihon

Can you provide an example of how would you like your code to look?

jstasiak avatar Sep 14 '18 13:09 jstasiak

Sure. Java-like parent annotation, but with string:

@implemented_by('JWTTokenService')
class TokenService(metaclass=ABCMeta):
    @abstractmethod
    def authorize_token(self, auth_header: str) :
        pass

@singleton
class JWTTokenService(TokenService):
...

or Child annotation:

class TokenService(metaclass=ABCMeta):
    @abstractmethod
    def authorize_token(self, auth_header: str) :
        pass

@singleton
@default
class JWTTokenService(TokenService):
...

comtihon avatar Sep 14 '18 14:09 comtihon

I believe the second form is preferable - better editor support (no need to put class name in string form) and easier to provide errors.

I'd change the @default annotation to @default_for(TokenService) - without the explicit interface figuring out what the binding should be can be tricky (in case of multiple inheritance or deep inheritance). @alecthomas do you have opinion on this? I'm still not entirely sure if it's worth it.

The patch introducing this would need to:

  • raise errors when two classes try to register themselves as default implementations for a single interface
  • provide extensive test coverage, handle edge cases and various Injector configurations that could affect the dependency injection correctness

jstasiak avatar Sep 16 '18 11:09 jstasiak

I like the convenience, it would probably eradicate the need for modules at all in many cases.

I think it would be better as an annotation on the interface, as it makes grokking the bindings much simpler. Without it, tracking down which class is bound to the interface could be quite involved, or even magic depending on imports.

alecthomas avatar Sep 18 '18 01:09 alecthomas

While having the interface reference the implementation via an annotation is simpler to do, it does result in a circular dependency between the abstraction and the concretion (hence the need for using a string to defer the resolution of the implementing type). I would personally never do something like that. An abstraction should know nothing about its concretions.

eirikur-grid avatar Jun 24 '19 20:06 eirikur-grid