I was in market for a simple Python library for my dependency injection needs. I had a very basic criteria.
- Python 3 support. (Duh!)
- It should be as simple as possible to understand and use.
- It should work with my existing code base without significant refactoring and redesigning.
- Minimal dependencies. Better if there are none.
- There shouldn’t be a lock in. Should I choose to move to a different library/framework in future, it should be a seamless process.
Unfortunately, I couldn’t find anything that fit this criteria. While some options do come close, most of them require the classes to be annotated, decorated, etc. That violates points 3 and 4 right away.
After writing hacky in-project implementations for a while, I decided to roll my own library. Enter Pychkari!
What’s with the Name
What is in the name!
Anyway, Pychkari is a pun on Pichkari, which is Marathi (and Hindi) word for water guns used on the festival of Holi. Pichkari, in turn, is basically a huge injection. So, Pychkari, you see, is a huge injection for Python.
Note: I have been made aware that there’s a similar sounding word in Tamil that has a meaning along lines of ‘beggar’. This is not intended. Any resemblance is purely coincidental.
Now that the joke in the name has been explained beyond the point of humor, let me move on to the technical bits.
Installation and Usage
# Class definitions for reference
depOne, # casing support
second_dep: "DepTwo", # annotations support
const_dep=3): # not a dependency
self.dep1 = depOne
self.dep2 = second_dep
self.const_d = const_dep
self.timestamp = datetime.now()
self.timestamp = datetime.now()
def __init__(self, a, dep_one):
self.a = a
self.dep1 = dep_one
container = Container.instance()
container.register("MyAwesomeService", B) # explicitly named registration
container.register_class(A) # service name "A" implicit
container.register_class(DepOne) # service name "DepOne" implicit
container.register_class(DepTwo) # service name "DepTwo" implicit
service = container.get("MyAwesomeService") # creates instance of "B" with dependencies injected
I am pleased to say that the goals were met without a lot of effort. And then some.
Constructor Based Injection: This is arguably the most common type of DI used. Pychkari fully relies on it. Constructor based DI ensures that the services are fully constructed with their dependencies. No more dependencies resolving to
Convention Based Resolution: Pychkari resolves dependencies based on dependency names. Provided that you are already using proper naming conventions (if not, why the hell not?) Pychkari will magically link services with constructor arguments.
For example, if constructor argument is called
http_client the service registered as
HttpClient will automatically be injected. No need for weird class decorations.
Python 3 Support: Pychkari is written in Python 3 for Python 3. It should support anything above Python 3.4.
Ease of Use: Pychkari has two step operation. Register and consume. What could be simpler than this!
Code Compatibility: If you wrote your code keeping DI in mind, chances are that you are already using constructor based DI. At this point, all a developer needs to do is to ensure that constructor argument names properly match the registered service names.
For example, to inject an instance of service
HttpClient either name your constructor parameter
httpClient – we support multiple conventions) or annotate it with type annotations like so:
Since no class decorations are needed, Pychkari works out of the box with the existing code base.
Small Size: The Pychkari wheel is well under 20 kB. Zipped source is barely 5 kB. And there are no dependencies.
No Commitment: Since we don’t have to make any code changes in service classes for using Pychkari, we are free to move to any other framework as and when needed.
All the development happens at the Pychkari’s GitHub repository. A CI/CD pipeline has been set up using Travis CI.
Stop by, leave a star and say hello!