Skip to content

Instantly share code, notes, and snippets.

@vskrachkov
Last active February 22, 2020 21:12
Show Gist options
  • Save vskrachkov/02ecc12cc38b1a55057d492ea8881854 to your computer and use it in GitHub Desktop.
Save vskrachkov/02ecc12cc38b1a55057d492ea8881854 to your computer and use it in GitHub Desktop.
Simple dependency injection sample. Python. Framework agnostic
import inspect
class Value:
__slots__ = ('name', 'default')
def __init__(self, name, default=None):
self.name = name
self.default = default
def create_provider():
registry = {}
def provide(abstract, concrete):
if abstract in registry:
raise Exception(
f'Implementation for {abstract} is already provided'
)
registry[abstract] = concrete
def provided(abstract):
if abstract not in registry:
raise Exception(f'Implementation for {abstract} is not provided')
concrete = registry[abstract]
def resolve_dependencies(thing):
params = {}
for name, param in inspect.signature(thing).parameters.items():
if isinstance(param.default, Value):
if param.default.name in registry:
params[name] = registry[param.default.name]
else:
params[name] = param.default.default
if param.annotation in registry:
dependency = registry[param.annotation]
params[name] = resolve_dependencies(dependency)
return params
if inspect.isfunction(concrete):
return concrete(**resolve_dependencies(concrete))
if inspect.isclass(concrete):
return concrete(**resolve_dependencies(concrete.__init__))
return concrete
def clear(abstract) -> None:
if abstract in registry:
del registry[abstract]
return provide, provided, clear
def main():
class SmsSender:
def __init__(self, message=Value('message')):
self.message = message
def send(self):
raise NotImplementedError()
class SmsSenderAAA(SmsSender):
def send(self):
print(f'sms sender SmsSenderAAA --> {self.message}')
class SmsSenderBBB(SmsSender):
def send(self):
print(f'sms sender SmsSenderBBB: {self.message}')
provide, provided, clear = create_provider()
provide(SmsSender, SmsSenderAAA)
sms_sender = provided(SmsSender)
sms_sender.send()
clear(SmsSender)
provide(SmsSender, SmsSenderBBB)
sms_sender = provided(SmsSender)
sms_sender.send()
provide('token', 12)
print(provided('token'))
provide('message', 'some message text')
clear(SmsSender)
provide(SmsSender, SmsSenderBBB)
sms_sender = provided(SmsSender)
sms_sender.send()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment