https://github.com/bobthemighty/punq
An IoC container for Python 3.8+
https://github.com/bobthemighty/punq
Last synced: 22 days ago
JSON representation
An IoC container for Python 3.8+
- Host: GitHub
- URL: https://github.com/bobthemighty/punq
- Owner: bobthemighty
- License: mit
- Created: 2017-09-07T08:38:38.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2025-01-14T15:34:35.000Z (3 months ago)
- Last Synced: 2025-03-16T13:17:49.842Z (30 days ago)
- Language: Python
- Homepage:
- Size: 813 KB
- Stars: 345
- Watchers: 1
- Forks: 15
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.rst
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
- awesome-dependency-injection-in-python - Punq - An IoC container for Python 3.6+. [🐍, MIT License]. (Software / DI Frameworks / Containers)
README
# Punq
[](https://img.shields.io/github/v/release/bobthemighty/punq)
[](https://github.com/bobthemighty/punq/actions/workflows/main.yml?query=branch%3Amain)
[](https://codecov.io/github/bobthemighty/punq)
[](https://img.shields.io/github/commit-activity/m/bobthemighty/punq)
[](https://img.shields.io/github/license/bobthemighty/punq)An unintrusive library for dependency injection in modern Python.
Inspired by [Funq][1], Punq is a dependency injection library you can understand.- No global state
- No decorators
- No weird syntax applied to arguments
- Small and simple code base with 100% test coverage and developer-friendly comments.## Installation
Punq is available on the [cheese shop][2]
```shell
pip install punq
```Documentation is available on [Github pages][3].
## Quick Start
Punq avoids global state, so you must explicitly create a container in the entrypoint of your application:
```python
import punqcontainer = punq.Container()
```Once you have a container, you can register your application's dependencies. In the simplest case, we can register any arbitrary object with some key:
```python
container.register("connection_string", instance="postgresql://...")
```We can then request that object back from the container:
```python
conn_str = container.resolve("connection_string")
```Usually, though, we want to register some object that implements a useful service.:
```python
class ConfigReader:
def get_config(self):
passclass EnvironmentConfigReader(ConfigReader):
def get_config(self):
return {
"logging": {
"level": os.env.get("LOGGING_LEVEL", "debug")
},
"greeting": os.env.get("GREETING", "Hello world")
}container.register(ConfigReader, EnvironmentConfigReader)
```Now we can `resolve` the `ConfigReader` service, and receive a concrete implementation:
```python
config = container.resolve(ConfigReader).get_config()
```If our application's dependencies have their _own_ dependencies, Punq will inject those, too:
```python
class Greeter:
def greet(self):
passclass ConsoleGreeter(Greeter):
def __init__(self, config_reader: ConfigReader):
self.config = config_reader.get_config()def greet(self):
print(self.config['greeting'])container.register(Greeter, ConsoleGreeter)
container.resolve(Greeter).greet()```
If you just want to resolve an object without having any base class, that's okay:
```python
class Greeter:
def __init__(self, config_reader: ConfigReader):
self.config = config_reader.get_config()def greet(self):
print(self.config['greeting'])container.register(Greeter)
container.resolve(Greeter).greet()
```And if you need to have a singleton object for some reason, we can tell punq to register a specific instance of an object:
```python
class FileWritingGreeter:
def __init__(self, path, greeting):
self.path = path
self.message = greeting
self.file = open(self.path, 'w')def greet(self):
self.file.write(self.message)one_true_greeter = FileWritingGreeter("/tmp/greetings", "Hello world")
container.register(Greeter, instance=one_true_greeter)
```You might not know all of your arguments at registration time, but you can provide them later:
```python
container.register(Greeter, FileWritingGreeter)
greeter = container.resolve(Greeter, path="/tmp/foo", greeting="Hello world")```
Conversely, you might want to provide arguments at registration time, without adding them to the container:
```python
container.register(Greeter, FileWritingGreeter, path="/tmp/foo", greeting="Hello world")
```[1]: https://github.com/jlyonsmith/Funq
[2]: https://pypi.org/project/punq/
[3]: https://bobthemighty.github.io/punq/
[4]: https://github.com/fpgmaas/cookiecutter-uvFuller documentation is available on [Github pages][3]
Github workflows, nox configuration, and linting gratefully stolen from [CookieCutter UV][4]