# finjet
[![PyPI version](https://badge.fury.io/py/finjet.svg)](https://badge.fury.io/py/finjet)
[![codecov](https://codecov.io/gh/elda27/finjet/branch/master/graph/badge.svg?token=Lnx3ZA0VKg)](https://codecov.io/gh/elda27/finjet)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/0ccb2ee2bed64adb8c2e96a9b45aba95)](https://www.codacy.com/gh/elda27/finjet/dashboard?utm_source=github.com&utm_medium=referral&utm_content=elda27/finjet&utm_campaign=Badge_Grade)
Simple dependency injection library like fastapi.
It can be used to turn your modules to loosely coupled parts. and configurations to allow you to easily re-use and test your code.
Dependency injection is performed on the arguments given with the `Depends` function as the default argument.
The inserted value will be given values of NamedTuple via `Container.configure` or the return value of the function.
## Installation
Latest PyPI stable release
```bash
pip install finjet
```
## Example
```python
from typing import NamedTuple
from finjet import Container, Depends, Singleton, inject
class Config(NamedTuple):
gear_ratio: int
tire_r: int = 100
class Engine:
# gear_ratio will be obtained from `Config`
def __init__(self, gear_ratio: int = Depends()) -> None:
self.gear_ratio = gear_ratio
class Tire:
count = 0
def __init__(self, tire_r: int = Depends()) -> None:
Tire.count += 1
# Actually tire_r is multiplied by instanced number of times.
self.tire_r = tire_r * Tire.count
def get_rotation_speed(engine: Engine = Depends(Engine)) -> int:
# Arguments of `Engine` class will inject from dependencies.
# In this example, the gear_ratio is configured 100 or 50
return engine.gear_ratio
@inject
def get_tire_speed(
tire: Tire = Singleton(Tire),
rpm: int = Depends(get_rotation_speed)
) -> float:
# Depends is always created such as factory pattern
# Singleton is only generate at once such as singleton pattern.
# The singleton object is shared in the Container class.
return tire.tire_r * rpm
def main():
container = Container()
# Configuration of container
container.configure(Config(100, 100))
with container:
print('Speed:', get_tire_speed()) # 10000
print('#Tire:', Tire.count) # 1
# If the configuration value is changed, the displaying value is difference.
# But `Tire.count` is same so that a second argument, the Tire object is re-used.
container.configure(Config(20, 100))
with container:
print('Speed:', get_tire_speed()) # 2000
print('#Tire:', Tire.count) # 1
# If the configuration value is changed, the displaying value is difference.
# The `Tire` object is updated.
container.configure(Config(20, 10))
with container:
print('Speed:', get_tire_speed()) # 400
print('#Tire:', Tire.count) # 2
if __name__ == '__main__':
main()
```