Skip to content

Commit fea5c4d

Browse files
authored
Merge pull request #9 from runemalm/feature/next-version
Feature/next version
2 parents ca58b47 + 9d2b5af commit fea5c4d

File tree

19 files changed

+141
-225
lines changed

19 files changed

+141
-225
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ pre-commit-run: ## run the pre-commit hooks
106106
# PIPENV
107107
################################################################################
108108

109+
.PHONY: pipenv-rm
110+
pipenv-rm: ## remove the virtual environment
111+
pipenv --rm
112+
109113
.PHONY: pipenv-install
110114
pipenv-install: ## setup the virtual environment
111115
pipenv install --dev

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ You can find the source code for `py-dependency-injection` on [GitHub](https://g
8383

8484
## Release Notes
8585

86+
### [1.0.0-beta.1](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-beta.1) (2025-01-06)
87+
88+
- **Transition to Beta**: Transitioned from alpha to beta. Features have been stabilized and are ready for broader testing.
89+
- **Removal**: We have removed the dependency container getter and setter functions, as well as the RegistrationSerializer class, which were first introduced in v1.0.0-alpha.9. This decision reflects our focus on maintaining a streamlined library that emphasizes core functionality. These features, which would not be widely used, added unnecessary complexity without offering significant value. By removing them, we are reinforcing our commitment to our design principles.
90+
- **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name.
91+
8692
### [1.0.0-alpha.10](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.10) (2024-08-11)
8793

8894
- **Tagged Constructor Injection**: Introduced support for constructor injection using the `Tagged`, `AnyTagged`, and `AllTagged` classes. This allows for seamless injection of dependencies that have been registered with specific tags, enhancing flexibility and control in managing your application's dependencies.

docs/community.rst

Lines changed: 0 additions & 9 deletions
This file was deleted.

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
version = "1.0"
3636

3737
# The full version, including alpha/beta/rc tags
38-
release = "1.0.0-alpha.10"
38+
release = "1.0.0-beta.1"
3939

4040

4141
# -- General configuration ---------------------------------------------------

docs/index.rst

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
.. warning::
1+
.. note::
22

3-
This library is currently in the alpha stage of development. Expect changes and improvements as we work towards a stable release.
3+
This library is currently in the beta stage of development.
4+
While features are stable, some minor adjustments may occur before the final release.
45

56
py-dependency-injection
67
=======================
@@ -42,11 +43,4 @@ Key Advantages
4243

4344
releases
4445

45-
.. apireference-docs:
46-
.. toctree::
47-
:maxdepth: 1
48-
:caption: API Reference
49-
50-
py-modindex
51-
5246
You can find the source code for `py-dependency-injection` in our `GitHub repository <https://github.com/runemalm/py-dependency-injection>`_.

docs/modules/container.rst

Lines changed: 0 additions & 9 deletions
This file was deleted.

docs/modules/decorator.rst

Lines changed: 0 additions & 9 deletions
This file was deleted.

docs/modules/scope.rst

Lines changed: 0 additions & 9 deletions
This file was deleted.

docs/py-modindex.rst

Lines changed: 0 additions & 2 deletions
This file was deleted.

docs/releases.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
.. warning::
1+
.. note::
22

3-
This library is currently in the alpha stage of development. Expect changes and improvements as we work towards a stable release.
3+
This library is currently in the beta stage of development.
4+
While features are stable, some minor adjustments may occur before the final release.
45

56
###############
67
Version History
78
###############
89

10+
**1.0.0-beta.1 (2025-01-06)**
11+
12+
- **Transition to Beta**: Transitioned from alpha to beta. Features have been stabilized and are ready for broader testing.
13+
- **Removal**: We have removed the dependency container getter and setter functions, as well as the RegistrationSerializer class, which were first introduced in v1.0.0-alpha.9. This decision reflects our focus on maintaining a streamlined library that emphasizes core functionality. These features, which would not be widely used, added unnecessary complexity without offering significant value. By removing them, we are reinforcing our commitment to our design principles.
14+
- **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name.
15+
16+
`View release on GitHub <https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-beta.1>`_
17+
918
**1.0.0-alpha.10 (2024-08-11)**
1019

1120
- **Tagged Constructor Injection**: Introduced support for constructor injection using the `Tagged`, `AnyTagged`, and `AllTagged` classes. This allows for seamless injection of dependencies that have been registered with specific tags, enhancing flexibility and control in managing your application's dependencies.

docs/userguide.rst

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,91 @@
22
Getting Started
33
###############
44

5+
.. note::
6+
`py-dependency-injection` has transitioned to beta! Features are now stable and ready for broader testing. Feedback is encouraged to help refine the library for its final release.
7+
8+
############
9+
Introduction
10+
############
11+
12+
`py-dependency-injection` is a lightweight and flexible dependency injection library for Python. It simplifies managing dependencies in your applications, promoting cleaner and more testable code.
13+
14+
This guide will help you understand the key concepts and how to start using the library. For detailed examples, see the `Examples` section.
15+
16+
############
517
Installation
6-
---------------
18+
############
719

8-
Install using `pip <http://pypi.python.org/pypi/pip/>`_::
20+
Install the library using pip:
21+
22+
.. code-block:: bash
923
1024
$ pip install py-dependency-injection
25+
26+
The library supports Python versions 3.7 through 3.12.
27+
28+
##########################
29+
Core Concepts and Features
30+
##########################
31+
32+
`py-dependency-injection` offers:
33+
34+
- **Scoped Dependency Management**: Define lifetimes for your dependencies (e.g., transient, scoped, singleton).
35+
- **Flexible Registrations**: Use constructors, factories, or predefined instances for dependency registration.
36+
- **Tag-Based Organization**: Categorize and resolve dependencies using tags.
37+
- **Multiple Containers**: Isolate dependencies for different parts of your application.
38+
39+
Refer to the `Examples` section for detailed usage scenarios.
40+
41+
####################
42+
Quick Start Overview
43+
####################
44+
45+
1. **Create a Dependency Container**:
46+
- The `DependencyContainer` is the core object for managing dependencies.
47+
48+
2. **Register Dependencies**:
49+
- Dependencies can be registered with different lifetimes: transient, scoped, or singleton.
50+
51+
3. **Resolve Dependencies**:
52+
- Use the container to resolve dependencies where needed.
53+
54+
Basic workflow:
55+
56+
.. code-block:: python
57+
58+
from dependency_injection.container import DependencyContainer
59+
60+
class Connection:
61+
pass
62+
63+
class PostgresConnection(Connection):
64+
pass
65+
66+
# Create a container
67+
container = DependencyContainer.get_instance()
68+
69+
# Register and resolve dependencies
70+
container.register_singleton(Connection, PostgresConnection)
71+
connection = container.resolve(Connection)
72+
print(type(connection).__name__) # Output: PostgresConnection
73+
74+
##############
75+
Best Practices
76+
##############
77+
78+
- **Use Constructor Injection**: Preferred for most cases as it promotes clear and testable designs.
79+
- **Leverage Tags for Organization**: Group dependencies logically using tags.
80+
- **Choose the Right Scope**: Use scoped or singleton lifetimes to optimize performance and resource usage.
81+
- **Keep Dependencies Decoupled**: Avoid tightly coupling your components to the container.
82+
- **Isolate Contexts with Containers**: Use multiple containers to manage dependencies for separate modules or contexts.
83+
84+
#################
85+
Where to Go Next?
86+
#################
87+
88+
- **Examples**:
89+
Explore detailed examples of how to register, resolve, and manage dependencies effectively in the `Examples` section.
90+
91+
- **Community and Support**:
92+
Join our community on GitHub to ask questions, report issues, or contribute to the project.

setup.py

Lines changed: 2 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.10",
9+
version="1.0.0-beta.1",
1010
author="David Runemalm, 2024",
1111
author_email="david.runemalm@gmail.com",
1212
description="A dependency injection library for Python.",
@@ -34,7 +34,7 @@
3434
],
3535
python_requires=">=3.7",
3636
classifiers=[
37-
"Development Status :: 3 - Alpha",
37+
"Development Status :: 4 - Beta",
3838
"Intended Audience :: Developers",
3939
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
4040
"Programming Language :: Python :: 3.7",

src/dependency_injection/container.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import inspect
22
from dataclasses import is_dataclass
33

4-
from typing import Any, Callable, Dict, List, Optional, TypeVar, Type
4+
from typing import Any, Callable, Dict, List, Optional, TypeVar, Type, Union
55

66
from dependency_injection.tags.all_tagged import AllTagged
77
from dependency_injection.tags.any_tagged import AnyTagged
@@ -17,13 +17,29 @@
1717

1818

1919
class DependencyContainer(metaclass=SingletonMeta):
20+
_default_scope_name: Union[str, Callable[[], str]] = DEFAULT_SCOPE_NAME
21+
2022
def __init__(self, name: str = None):
2123
self.name = name if name is not None else DEFAULT_CONTAINER_NAME
2224
self._registrations = {}
2325
self._singleton_instances = {}
2426
self._scoped_instances = {}
2527
self._has_resolved = False
2628

29+
@classmethod
30+
def configure_default_scope_name(
31+
cls, default_scope_name: Union[str, Callable[[], str]]
32+
) -> None:
33+
"""Configure the global default scope name, which can be string or callable."""
34+
cls._default_scope_name = default_scope_name
35+
36+
@classmethod
37+
def get_default_scope_name(cls) -> str:
38+
"""Return the default scope name. If it's callable, call it to get the value."""
39+
if callable(cls._default_scope_name):
40+
return cls._default_scope_name()
41+
return cls._default_scope_name
42+
2743
@classmethod
2844
def get_instance(cls, name: str = None) -> Self:
2945
name = name or DEFAULT_CONTAINER_NAME
@@ -33,16 +49,6 @@ def get_instance(cls, name: str = None) -> Self:
3349

3450
return cls._instances[(cls, name)]
3551

36-
def get_registrations(self) -> Dict[Type, Registration]:
37-
return self._registrations
38-
39-
def set_registrations(self, registrations) -> None:
40-
if self._has_resolved:
41-
raise Exception(
42-
"You can't set registrations after a dependency has been resolved."
43-
)
44-
self._registrations = registrations
45-
4652
def register_transient(
4753
self,
4854
dependency: Type,
@@ -109,8 +115,9 @@ def _register(
109115
dependency, implementation, scope, tags, constructor_args
110116
)
111117

112-
def resolve(self, dependency: Type, scope_name: str = DEFAULT_SCOPE_NAME) -> Any:
118+
def resolve(self, dependency: Type, scope_name: Optional[str] = None) -> Any:
113119
self._has_resolved = True
120+
scope_name = scope_name or self.get_default_scope_name()
114121

115122
if scope_name not in self._scoped_instances:
116123
self._scoped_instances[scope_name] = {}
@@ -124,8 +131,11 @@ def resolve(self, dependency: Type, scope_name: str = DEFAULT_SCOPE_NAME) -> Any
124131

125132
return self._resolve_by_scope(registration, scope_name)
126133

127-
def _resolve_by_scope(self, registration: Registration, scope_name: str) -> Any:
134+
def _resolve_by_scope(
135+
self, registration: Registration, scope_name: Optional[str] = None
136+
) -> Any:
128137
scope = registration.scope
138+
scope_name = scope_name or self.get_default_scope_name()
129139

130140
if scope == Scope.TRANSIENT:
131141
return self._inject_dependencies(
@@ -210,9 +220,11 @@ def _validate_registration(self, dependency: Type) -> None:
210220
def _inject_dependencies(
211221
self,
212222
implementation: Type,
213-
scope_name: str = None,
223+
scope_name: Optional[str] = None,
214224
constructor_args: Optional[Dict[str, Any]] = None,
215225
) -> Type:
226+
scope_name = scope_name or self.get_default_scope_name()
227+
216228
if is_dataclass(implementation):
217229
return implementation() # Do not inject into dataclasses
218230

src/dependency_injection/decorator.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import functools
22
import inspect
3-
from typing import Any, Callable, TypeVar
3+
from typing import Any, Callable, Optional, TypeVar
44

55
from dependency_injection.container import DEFAULT_CONTAINER_NAME, DependencyContainer
6-
from dependency_injection.scope import DEFAULT_SCOPE_NAME
76

87
F = TypeVar("F", bound=Callable[..., Any])
98

109

1110
def inject(
12-
container_name=DEFAULT_CONTAINER_NAME, scope_name=DEFAULT_SCOPE_NAME
11+
container_name=DEFAULT_CONTAINER_NAME, scope_name: Optional[str] = None
1312
) -> Callable[[F], F]:
1413
def is_instance_method(func: Callable[..., Any]) -> bool:
1514
parameters = inspect.signature(func).parameters
@@ -30,10 +29,11 @@ def wrapper_inject(*args: Any, **kwargs: Any) -> Any:
3029
if parameter_name != "cls" and parameter_name not in kwargs:
3130
# get container
3231
container = DependencyContainer.get_instance(container_name)
32+
actual_scope_name = scope_name or container.get_default_scope_name()
3333
# Resolve the dependency based on the parameter name
3434
dependency_type = sig.parameters[parameter_name].annotation
3535
kwargs[parameter_name] = container.resolve(
36-
dependency_type, scope_name=scope_name
36+
dependency_type, scope_name=actual_scope_name
3737
)
3838

3939
# Call the original function with the injected dependencies

src/dependency_injection/serialization.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)