Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

16 Commits

Repository files navigation

quickd

Decorator type-based dependency injection for Python

GitHub Workflow StatusGitHub release (latest by date)GitHubPyPI - Downloads

📦 Installation

The package quickd supports Python >= 3.5. You can install it by doing:

$ pip install quickd

📜 Example

Here is a quick example:

fromquickdimportinject, factoryclassDatabase:
passclassPostgreSQL(Database):
def__str__(self):
return'PostgreSQL'classMySQL(Database):
def__str__(self):
return'MySQL'@injectdefprint_database(database: Database):
returnprint(database)
@factorydefchoose_database() ->Database:
returnPostgreSQL()
print_database() # Prints: PostgreSQLprint_database(MySQL()) # Prints: MySQL

🚀 Usage

There are only 3 decorators that compose the whole framework

@factory

  • Registers an instance for a specific type for later use with @inject
  • Is mandatory to annotate the function with the return type of the class that you want to inject later
  • It is not dynamic, so the implementation can only be chosen once
fromquickdimportfactory@factorydefchoose_database() ->Database:
returnPostgreSQL()

@inject

  • Injects dependencies to a function by matching its arguments types with what has been registered
  • As you can see below, it also works with constructors
fromquickdimportinject@injectdefprint_database(database: Database):
returnprint(database)
classUserService:
@injectdef__init__(self, database: Database): pass

@service

  • Registers a class to be later injectable without using @factory
  • It also applies @inject to its constructor
fromquickdimportservice, inject@serviceclassUserService:
def__init__(self):
self.users= ['Bob', 'Tom']
defall(self):
returnself.usersdefadd(self, user):
self.users.append(user)
@injectdefget_users(service: UserService):
returnservice.all()
@injectdefadd_user(service: UserService):
returnservice.add("Pol")
get_users() # ['Bob', 'Tom']add_user()
get_users() # ['Bob', 'Tom', 'Pol']

👨‍🍳 Recipes

Here are some common solutions to scenarios you will face.

Interfaces

fromabcimportabstractmethodfromquickdimportinject, factoryclassUserRepository:
@abstractmethoddefsave(self, user):
pass@abstractmethoddefsearch(self, id):
passclassUserCreator:
@injectdef__int__(self, repository: UserRepository):
self.repository=repositorydefcreate(self, user):
self.repository.save(user)
classMySQLUserRepository(UserRepository):
def__int__(self, host, password):
self.sql=MySQLConnection(host, password)
defsave(self, user):
self.sql.execute('INSERT ...')
defsearch(self, id):
self.sql.execute('SELECT ...')
@factorydefchoose_user_repository() ->UserRepository: # Notice super class is being usedreturnMySQLUserRepository('user', '123')

Testing

Following the above example we can create a unit test mocking the persistance, which will make our tests easier and faster.

fake_user= {'id': 1, 'name': 'Tom'}
classFakeUserRepository(UserRepository):
defsave(self, user):
assertuser==fake_userrepository=FakeUserRepository()
user_creator=UserCreator(repository)
user_creator.create(fake_user)

Configuration

There are multiple ways to configure your classes. A simple approach is to use environment variables on your factory annotated methods.

importosfromquickdimportfactory@factorydefchoose_database() ->Database:
username=os.environ.get("POSTGRES_USER")
password=os.environ.get("POSTGRES_PASS")
returnPostgreSQL(username, password)

🧠 Motivation

Dependency injection provides a great way to decouple your classes in order to improve testability and maintainability.

Frameworks like Spring or Symfony are loved by the community.

I will just add a parameter to the constructor and Spring will fill with a global instance of the class

These frameworks rely heavy on the type system, to know which class should go where.

From Python 3.5 we have the typing package. This addition allows us to have the dependency injection framework that Python deserves.

About

🐍💉 Decorator type-based dependency injection for Python

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages