Skip to content

Commit 16e6868

Browse files
committed
Add support for multiple containers.
1 parent 63f8b27 commit 16e6868

File tree

17 files changed

+180
-77
lines changed

17 files changed

+180
-77
lines changed

Makefile

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ help:
2929

3030
.PHONY: test
3131
test: ## run test suite
32-
PYTHONPATH=./src:./tests pipenv run pytest $(TESTS)
32+
PYTHONPATH=./src:./tests pipenv run pytest -n 1 $(TESTS)
3333

3434
################################################################################
3535
# RELEASE
3636
################################################################################
3737

3838
.PHONY: build
3939
build: ## build the python package
40-
python setup.py sdist bdist_wheel
40+
pipenv run python setup.py sdist bdist_wheel
4141

4242
.PHONY: clean
4343
clean: ## clean the build
@@ -47,27 +47,27 @@ clean: ## clean the build
4747

4848
.PHONY: upload-test
4949
upload-test: ## upload package to testpypi repository
50-
TWINE_USERNAME=$(PYPI_USERNAME_TEST) TWINE_PASSWORD=$(PYPI_PASSWORD_TEST) twine upload --repository testpypi --skip-existing --repository-url https://test.pypi.org/legacy/ dist/*
50+
TWINE_USERNAME=$(PYPI_USERNAME_TEST) TWINE_PASSWORD=$(PYPI_PASSWORD_TEST) pipenv run twine upload --repository testpypi --skip-existing --repository-url https://test.pypi.org/legacy/ dist/*
5151

5252
.PHONY: upload
5353
upload: ## upload package to pypi repository
54-
TWINE_USERNAME=$(PYPI_USERNAME) TWINE_PASSWORD=$(PYPI_PASSWORD) twine upload --skip-existing dist/*
54+
TWINE_USERNAME=$(PYPI_USERNAME) TWINE_PASSWORD=$(PYPI_PASSWORD) pipenv run twine upload --skip-existing dist/*
5555

5656
.PHONY: sphinx-quickstart
5757
sphinx-quickstart: ## run the sphinx quickstart
58-
docker run -it --rm -v $(PWD)/docs:/docs sphinxdoc/sphinx sphinx-quickstart
58+
pipenv run docker run -it --rm -v $(PWD)/docs:/docs sphinxdoc/sphinx sphinx-quickstart
5959

6060
.PHONY: sphinx-html
6161
sphinx-html: ## build the sphinx html
62-
make -C docs html
62+
pipenv run make -C docs html
6363

6464
.PHONY: sphinx-rebuild
6565
sphinx-rebuild: ## re-build the sphinx docs
6666
make -C docs clean && make -C docs html
6767

6868
.PHONY: sphinx-autobuild
6969
sphinx-autobuild: ## activate autobuild of docs
70-
sphinx-autobuild docs docs/_build/html --watch $(SRC)
70+
pipenv run sphinx-autobuild docs docs/_build/html --watch $(SRC)
7171

7272
################################################################################
7373
# PIPENV

Pipfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ sphinx-rtd-theme = "2.0.0"
1212
sphinx-autobuild = "2021.3.14"
1313
sphinxcontrib-napoleon = "0.7"
1414
wheel = "0.41.2"
15+
pytest-xdist = "*"
1516

1617
[requires]
1718
python_version = ">=3.7"

Pipfile.lock

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,81 @@
11
[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.html)
22
![First Principles Software](https://img.shields.io/badge/Powered_by-First_Principles_Software-blue)
3+
[![Push on master](https://github.com/runemalm/py-dependency-injection/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/runemalm/py-dependency-injection/actions/workflows/master.yml)
34

4-
## py-dependency-injection
5+
# py-dependency-injection
56

6-
This is a simple and lightweight dependency injection library for python.
7+
A dependency injection library for Python.
78

8-
### Features:
9+
## Features:
910

1011
- Dependency Container
1112
- Dependency Scopes
1213
- Constructor Injection
1314
- Method Injection
1415

15-
### Python Compatibility
16-
17-
This library is compatible and tested with the following Python versions:
16+
## Python Compatibility
1817

19-
- Python 3.7
20-
- Python 3.8
21-
- Python 3.9
22-
- Python 3.10
23-
- Python 3.11
24-
- Python 3.12
18+
This library is compatible with the following Python versions:
2519

26-
[![Push on master](https://github.com/runemalm/py-dependency-injection/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/runemalm/py-dependency-injection/actions/workflows/master.yml)
20+
- 3.7, 3.8, 3.9, 3.10, 3.11, 3.12
2721

28-
### Installation:
22+
## Installation:
2923

3024
```bash
3125
$ pip install py-dependency-injection
3226
```
33-
34-
### Example - Getting a dependency container:
27+
28+
## Usage:
29+
30+
### Example: Obtaining the Default Dependency Container
3531

3632
```python
37-
# While you can create multiple containers, it's typically recommended to use one per application.
38-
# For this purpose, you can easily obtain the default container.
33+
# Retrieve the default container, typically recommended for a single-application setup.
3934

4035
from dependency_injection.container import DependencyContainer
4136

4237

4338
dependency_container = DependencyContainer.get_instance()
4439
```
4540

46-
### Example - Registering dependencies:
41+
### Example: Obtaining a Second Dependency Container
4742

4843
```python
49-
# You can register using one of three scopes - transient, scoped or singleton.
44+
# Create additional containers if needed, especially for multi-application scenarios.
45+
46+
from dependency_injection.container import DependencyContainer
47+
48+
49+
a_second_dependency_container = DependencyContainer.get_instance(name="a_second_dependency_container")
50+
```
51+
52+
### Example: Registering Dependencies
53+
54+
```python
55+
# Register dependencies with three available scopes: transient, scoped, or singleton.
5056

5157
dependency_container.register_transient(SomeInterface, SomeClass)
5258
dependency_container.register_scoped(AnotherInterface, AnotherClass)
5359
dependency_container.register_singleton(ThirdInterface, ThirdClass)
5460
```
5561

56-
### Example - Resolving dependencies:
62+
### Example: Resolving Dependencies
5763

5864
```python
59-
# Resolving dependencies from the dependency container.
60-
61-
# Resolving a transient instance, which is created anew for each resolution.
65+
# Resolve transient instance (created anew for each call).
6266
transient_instance = dependency_container.resolve(SomeInterface)
6367

64-
# Resolving a scoped instance with an optional scope name.
65-
# A scope is often created for each application service action invocation.
66-
# This scope creation typically happens inside the application framework,
67-
# upon entry into the application layer via primary adapters in the infrastructure layer.
68-
# Provide a scope name, such as the auto-created scope, for scoped instances.
69-
scoped_instance = dependency_container.resolve(AnotherInterface, scope_name="auto-created-scope-name")
68+
# Resolve scoped instance (consistent within a specific scope, e.g. a scope for the application action being run).
69+
scoped_instance = dependency_container.resolve(AnotherInterface, scope_name="application_action_scope")
7070

71-
# Resolving a singleton instance, which remains the same across the entire application.
71+
# Resolve singleton instance (consistent across the entire application).
7272
singleton_instance = dependency_container.resolve(ThirdInterface)
7373
```
7474

75-
### Example - Constructor injection:
75+
### Example: Constructor Injection
7676

7777
```python
78-
# As long as the class is resolved using the dependency container,
79-
# dependencies are injected into it's constructor at resolution time.
78+
# Class instances resolved through the container have dependencies injected into their constructors.
8079

8180
class Foo:
8281

@@ -86,12 +85,12 @@ class Foo:
8685
self._singleton_instance = singleton_instance
8786
```
8887

89-
### Example - Method injection:
88+
### Example: Method Injection
9089

9190
```python
92-
# Dependencies can be injected into an instance method using the `@inject` decorator.
93-
# The dependency container and scope name can be provided as arguments to the decorator.
94-
# If none are provided, the default container and scope are applied.
91+
# Inject dependencies into instance methods using the `@inject` decorator.
92+
# You may pass 'container_name' and 'scope_name' as decorator arguments.
93+
9594
from dependency_injection.decorator import inject
9695

9796

@@ -104,25 +103,24 @@ class Foo:
104103
singleton_instance.do_something()
105104
```
106105

107-
### Documentation:
106+
## Documentation:
108107

109-
You can find the latest documentation at [readthedocs](https://py-dependency-injection.readthedocs.io/en/latest/).
108+
For the latest documentation, visit [readthedocs](https://py-dependency-injection.readthedocs.io/en/latest/).
110109

111-
### Contribution:
112-
113-
If you want to contribute to the code base, create a pull request on the develop branch.
110+
## Contribution:
114111

115-
We follow the [git flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
112+
To contribute, create a pull request on the develop branch following the [git flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
116113

117-
### Release Notes
114+
## Release Notes
118115

119-
#### [1.0.0-alpha.2](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.2) (2024-02-xx)
116+
### [1.0.0-alpha.2](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.2) (2024-02-27)
120117

121118
- Python Version Support: Added support for Python versions 3.7, 3.9, 3.10, 3.11, and 3.12.
122119
- New Feature: Method Injection with Decorator: Introduced a new feature allowing method injection using the @inject decorator. Dependencies can now be injected into an instance method, providing more flexibility in managing dependencies within class instance methods.
120+
- New Feature: Multiple Containers: Enhanced the library to support multiple containers. Users can now create and manage multiple dependency containers, enabling better organization and separation of dependencies for different components or modules.
123121
- Documentation Update: Expanded and improved the documentation to include details about the newly added method injection feature and additional usage examples. Users can refer to the latest documentation at readthedocs for comprehensive guidance.
124122

125-
#### [1.0.0-alpha.1](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.1) (2024-02-25)
123+
### [1.0.0-alpha.1](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.1) (2024-02-25)
126124

127125
- Initial alpha release.
128126
- Added Dependency Container: The library includes a dependency container for managing object dependencies.

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
author = 'David Runemalm'
3232

3333
# The full version, including alpha/beta/rc tags
34-
release = '1.0.0-alpha.1'
34+
release = '1.0.0-alpha.2'
3535

3636

3737
# -- General configuration ---------------------------------------------------

docs/modules/decorator.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
:mod:`dependency_injection.decorator`
2+
=====================================
3+
4+
.. automodule:: dependency_injection.decorator
5+
6+
.. autofunction:: inject
7+
:members:
8+
:undoc-members:
9+
:show-inheritance:

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
sphinx==7.1.2
1+
sphinx==5.3.0
22
sphinx-rtd-theme==2.0.0
33
sphinx-autobuild==2021.3.14
44
sphinxcontrib-napoleon==0.7

docs/versionhistory.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
Version history
33
###############
44

5-
**1.0.0-alpha.2 (2024-02-xx)**
5+
**1.0.0-alpha.2 (2024-02-27)**
66

77
- Python Version Support: Added support for Python versions 3.7, 3.9, 3.10, 3.11, and 3.12.
88
- New Feature: Method Injection with Decorator: Introduced a new feature allowing method injection using the @inject decorator. Dependencies can now be injected into an instance method, providing more flexibility in managing dependencies within class instance methods.
9+
- New Feature: Multiple Containers: Enhanced the library to support multiple containers. Users can now create and manage multiple dependency containers, enabling better organization and separation of dependencies for different components or modules.
910
- Documentation Update: Expanded and improved the documentation to include details about the newly added method injection feature and additional usage examples. Users can refer to the latest documentation at readthedocs for comprehensive guidance.
1011

1112
`View release on GitHub <https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.2>`_

setup.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
setup(
88
name='py-dependency-injection',
9-
version='1.0.0-alpha.1',
9+
version='1.0.0-alpha.2',
1010
author='David Runemalm, 2024',
1111
author_email='david.runemalm@gmail.com',
1212
description=
@@ -31,5 +31,18 @@
3131
tests_require=[
3232
'pytest',
3333
],
34-
python_requires='>=3.8',
34+
python_requires='>=3.7',
35+
classifiers=[
36+
'Development Status :: 3 - Alpha',
37+
'Intended Audience :: Developers',
38+
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
39+
'Programming Language :: Python :: 3.7',
40+
'Programming Language :: Python :: 3.8',
41+
'Programming Language :: Python :: 3.9',
42+
'Programming Language :: Python :: 3.10',
43+
'Programming Language :: Python :: 3.11',
44+
'Programming Language :: Python :: 3.12',
45+
'Topic :: Software Development :: Libraries :: Dependency Injection',
46+
'Topic :: Software Development :: Libraries :: Python Modules',
47+
],
3548
)

src/dependency_injection/container.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,25 @@
55
from dependency_injection.utils.singleton_meta import SingletonMeta
66

77

8+
DEFAULT_CONTAINER_NAME = "default_container"
9+
810
class DependencyContainer(metaclass=SingletonMeta):
911

10-
def __init__(self):
12+
def __init__(self, name=None):
13+
self.name = name if name is not None else DEFAULT_CONTAINER_NAME
1114
self._registrations = {}
1215
self._singleton_instances = {}
1316
self._scoped_instances = {}
1417

1518
@classmethod
16-
def get_instance(cls):
17-
return cls()
19+
def get_instance(cls, name=None):
20+
if name is None:
21+
name = DEFAULT_CONTAINER_NAME
22+
23+
if (cls, name) not in cls._instances:
24+
cls._instances[(cls, name)] = cls(name)
25+
26+
return cls._instances[(cls, name)]
1827

1928
def register_transient(self, interface, class_):
2029
if interface in self._registrations:

0 commit comments

Comments
 (0)