From 5f1d322c0b09aa41fc9e4f7e7a9a31ee94e7cb3a Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 12 Aug 2024 15:27:56 +0200 Subject: [PATCH 1/7] Remove set- & get-registrations and serializer. --- src/dependency_injection/container.py | 10 --- src/dependency_injection/serialization.py | 15 ----- .../register/test_get_registrations.py | 32 ---------- .../register/test_set_registrations.py | 43 ------------- tests/unit_test/serialization/__init__.py | 0 .../test_registration_serializer.py | 63 ------------------- 6 files changed, 163 deletions(-) delete mode 100644 src/dependency_injection/serialization.py delete mode 100644 tests/unit_test/container/register/test_get_registrations.py delete mode 100644 tests/unit_test/container/register/test_set_registrations.py delete mode 100644 tests/unit_test/serialization/__init__.py delete mode 100644 tests/unit_test/serialization/test_registration_serializer.py diff --git a/src/dependency_injection/container.py b/src/dependency_injection/container.py index ab035f4..2f788db 100644 --- a/src/dependency_injection/container.py +++ b/src/dependency_injection/container.py @@ -33,16 +33,6 @@ def get_instance(cls, name: str = None) -> Self: return cls._instances[(cls, name)] - def get_registrations(self) -> Dict[Type, Registration]: - return self._registrations - - def set_registrations(self, registrations) -> None: - if self._has_resolved: - raise Exception( - "You can't set registrations after a dependency has been resolved." - ) - self._registrations = registrations - def register_transient( self, dependency: Type, diff --git a/src/dependency_injection/serialization.py b/src/dependency_injection/serialization.py deleted file mode 100644 index 2bfbad0..0000000 --- a/src/dependency_injection/serialization.py +++ /dev/null @@ -1,15 +0,0 @@ -import pickle - -from typing import Dict, Type - -from dependency_injection.registration import Registration - - -class RegistrationSerializer: - @staticmethod - def serialize(registrations) -> bytes: - return pickle.dumps(registrations) - - @staticmethod - def deserialize(serialized_state) -> Dict[Type, Registration]: - return pickle.loads(serialized_state) diff --git a/tests/unit_test/container/register/test_get_registrations.py b/tests/unit_test/container/register/test_get_registrations.py deleted file mode 100644 index 5d9d50c..0000000 --- a/tests/unit_test/container/register/test_get_registrations.py +++ /dev/null @@ -1,32 +0,0 @@ -from dependency_injection.container import DependencyContainer -from dependency_injection.scope import Scope -from unit_test.unit_test_case import UnitTestCase - - -class TestGetRegistrations(UnitTestCase): - def test_get_registrations_returns_empty_dict_initially(self): - # arrange - dependency_container = DependencyContainer.get_instance() - - # act - registrations = dependency_container.get_registrations() - - # assert - self.assertEqual(registrations, {}) - - def test_get_registrations_returns_correct_registrations(self): - # arrange - class Vehicle: - pass - - dependency_container = DependencyContainer.get_instance() - dependency_container.register_transient(Vehicle) - - # act - registrations = dependency_container.get_registrations() - - # assert - self.assertIn(Vehicle, registrations) - self.assertEqual(registrations[Vehicle].dependency, Vehicle) - self.assertEqual(registrations[Vehicle].implementation, Vehicle) - self.assertEqual(registrations[Vehicle].scope, Scope.TRANSIENT) diff --git a/tests/unit_test/container/register/test_set_registrations.py b/tests/unit_test/container/register/test_set_registrations.py deleted file mode 100644 index 04d6b46..0000000 --- a/tests/unit_test/container/register/test_set_registrations.py +++ /dev/null @@ -1,43 +0,0 @@ -from dependency_injection.container import DependencyContainer -from unit_test.unit_test_case import UnitTestCase - - -class TestSetRegistrations(UnitTestCase): - def test_set_registrations_before_first_resolution(self): - # arrange - class Vehicle: - pass - - dummy_container = DependencyContainer.get_instance("dummy_container") - dummy_container.register_transient(Vehicle) - new_registrations = dummy_container.get_registrations() - - container = DependencyContainer.get_instance() - - # act - container.set_registrations(new_registrations) # no exception - - def test_not_allowed_to_set_registrations_after_first_resolution(self): - # arrange - class Vehicle: - pass - - class Fruit: - pass - - dummy_container = DependencyContainer.get_instance("dummy_container") - dummy_container.register_transient(Vehicle) - new_registrations = dummy_container.get_registrations() - - container = DependencyContainer.get_instance() - container.register_transient(Fruit) - container.resolve(Fruit) - - # act & assert - with self.assertRaises(Exception) as context: - container.set_registrations(new_registrations) - - self.assertIn( - "You can't set registrations after a dependency has been resolved.", - str(context.exception), - ) diff --git a/tests/unit_test/serialization/__init__.py b/tests/unit_test/serialization/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit_test/serialization/test_registration_serializer.py b/tests/unit_test/serialization/test_registration_serializer.py deleted file mode 100644 index 9be563d..0000000 --- a/tests/unit_test/serialization/test_registration_serializer.py +++ /dev/null @@ -1,63 +0,0 @@ -import pickle - -from unit_test.unit_test_case import UnitTestCase - -from dependency_injection.serialization import RegistrationSerializer -from dependency_injection.registration import Registration -from dependency_injection.scope import Scope - - -class Vehicle: - pass - - -class Car: - def __init__(self, vehicle: Vehicle): - self.vehicle = vehicle - - -class TestRegistrationSerializer(UnitTestCase): - def test_serialize_and_deserialize(self): - # arrange - registrations = { - Vehicle: Registration( - dependency=Vehicle, - implementation=Car, - scope=Scope.TRANSIENT, - tags={"example_tag"}, - constructor_args={"vehicle": Vehicle()}, - factory=None, - factory_args={}, - ) - } - - # act - serialized = RegistrationSerializer.serialize(registrations) - deserialized = RegistrationSerializer.deserialize(serialized) - - # assert - self.assertEqual(deserialized.keys(), registrations.keys()) - self.assertEqual( - deserialized[Vehicle].dependency, registrations[Vehicle].dependency - ) - self.assertEqual( - deserialized[Vehicle].implementation, registrations[Vehicle].implementation - ) - self.assertEqual(deserialized[Vehicle].scope, registrations[Vehicle].scope) - self.assertEqual(deserialized[Vehicle].tags, registrations[Vehicle].tags) - self.assertEqual( - deserialized[Vehicle].constructor_args.keys(), - registrations[Vehicle].constructor_args.keys(), - ) - self.assertEqual(deserialized[Vehicle].factory, registrations[Vehicle].factory) - self.assertEqual( - deserialized[Vehicle].factory_args, registrations[Vehicle].factory_args - ) - - def test_deserialize_invalid_data(self): - # arrange - invalid_data = b"not a valid pickle" - - # act & assert - with self.assertRaises(pickle.UnpicklingError): - RegistrationSerializer.deserialize(invalid_data) From 864938ffd20ceb7fb6eb61050d8537fe95054a1f Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Wed, 25 Sep 2024 18:17:57 +0200 Subject: [PATCH 2/7] Start on next release notes in readme. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 14a40d0..3be485a 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,10 @@ You can find the source code for `py-dependency-injection` on [GitHub](https://g ## Release Notes +### [1.0.0-alpha.11](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.11) (2024-08-xx) + +- **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. + ### [1.0.0-alpha.10](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.10) (2024-08-11) - **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. From 6374a7d2a7dc4400ea21c3869bc30d01b9f13dd1 Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 6 Jan 2025 13:40:15 +0100 Subject: [PATCH 3/7] Make default scope name configurable. --- Makefile | 4 ++++ src/dependency_injection/container.py | 30 +++++++++++++++++++++++---- src/dependency_injection/decorator.py | 8 +++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index a7b533d..b159f65 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,10 @@ pre-commit-run: ## run the pre-commit hooks # PIPENV ################################################################################ +.PHONY: pipenv-rm +pipenv-rm: ## remove the virtual environment + pipenv --rm + .PHONY: pipenv-install pipenv-install: ## setup the virtual environment pipenv install --dev diff --git a/src/dependency_injection/container.py b/src/dependency_injection/container.py index 2f788db..1b3dec8 100644 --- a/src/dependency_injection/container.py +++ b/src/dependency_injection/container.py @@ -1,7 +1,7 @@ import inspect from dataclasses import is_dataclass -from typing import Any, Callable, Dict, List, Optional, TypeVar, Type +from typing import Any, Callable, Dict, List, Optional, TypeVar, Type, Union from dependency_injection.tags.all_tagged import AllTagged from dependency_injection.tags.any_tagged import AnyTagged @@ -17,6 +17,8 @@ class DependencyContainer(metaclass=SingletonMeta): + _default_scope_name: Union[str, Callable[[], str]] = DEFAULT_SCOPE_NAME + def __init__(self, name: str = None): self.name = name if name is not None else DEFAULT_CONTAINER_NAME self._registrations = {} @@ -24,6 +26,20 @@ def __init__(self, name: str = None): self._scoped_instances = {} self._has_resolved = False + @classmethod + def configure_default_scope_name( + cls, default_scope_name: Union[str, Callable[[], str]] + ) -> None: + """Configure the global default scope name, which can be string or callable.""" + cls._default_scope_name = default_scope_name + + @classmethod + def get_default_scope_name(cls) -> str: + """Return the default scope name. If it's callable, call it to get the value.""" + if callable(cls._default_scope_name): + return cls._default_scope_name() + return cls._default_scope_name + @classmethod def get_instance(cls, name: str = None) -> Self: name = name or DEFAULT_CONTAINER_NAME @@ -99,8 +115,9 @@ def _register( dependency, implementation, scope, tags, constructor_args ) - def resolve(self, dependency: Type, scope_name: str = DEFAULT_SCOPE_NAME) -> Any: + def resolve(self, dependency: Type, scope_name: Optional[str] = None) -> Any: self._has_resolved = True + scope_name = scope_name or self.get_default_scope_name() if scope_name not in self._scoped_instances: self._scoped_instances[scope_name] = {} @@ -114,8 +131,11 @@ def resolve(self, dependency: Type, scope_name: str = DEFAULT_SCOPE_NAME) -> Any return self._resolve_by_scope(registration, scope_name) - def _resolve_by_scope(self, registration: Registration, scope_name: str) -> Any: + def _resolve_by_scope( + self, registration: Registration, scope_name: Optional[str] = None + ) -> Any: scope = registration.scope + scope_name = scope_name or self.get_default_scope_name() if scope == Scope.TRANSIENT: return self._inject_dependencies( @@ -200,9 +220,11 @@ def _validate_registration(self, dependency: Type) -> None: def _inject_dependencies( self, implementation: Type, - scope_name: str = None, + scope_name: Optional[str] = None, constructor_args: Optional[Dict[str, Any]] = None, ) -> Type: + scope_name = scope_name or self.get_default_scope_name() + if is_dataclass(implementation): return implementation() # Do not inject into dataclasses diff --git a/src/dependency_injection/decorator.py b/src/dependency_injection/decorator.py index 0a820b0..c668149 100644 --- a/src/dependency_injection/decorator.py +++ b/src/dependency_injection/decorator.py @@ -1,15 +1,14 @@ import functools import inspect -from typing import Any, Callable, TypeVar +from typing import Any, Callable, Optional, TypeVar from dependency_injection.container import DEFAULT_CONTAINER_NAME, DependencyContainer -from dependency_injection.scope import DEFAULT_SCOPE_NAME F = TypeVar("F", bound=Callable[..., Any]) def inject( - container_name=DEFAULT_CONTAINER_NAME, scope_name=DEFAULT_SCOPE_NAME + container_name=DEFAULT_CONTAINER_NAME, scope_name: Optional[str] = None ) -> Callable[[F], F]: def is_instance_method(func: Callable[..., Any]) -> bool: parameters = inspect.signature(func).parameters @@ -30,10 +29,11 @@ def wrapper_inject(*args: Any, **kwargs: Any) -> Any: if parameter_name != "cls" and parameter_name not in kwargs: # get container container = DependencyContainer.get_instance(container_name) + actual_scope_name = scope_name or container.get_default_scope_name() # Resolve the dependency based on the parameter name dependency_type = sig.parameters[parameter_name].annotation kwargs[parameter_name] = container.resolve( - dependency_type, scope_name=scope_name + dependency_type, scope_name=actual_scope_name ) # Call the original function with the injected dependencies From 86070ff6220d3c1715b00fbc4805bf5335ca7608 Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 6 Jan 2025 13:45:03 +0100 Subject: [PATCH 4/7] Add release notes and bump version. --- README.md | 3 ++- docs/releases.rst | 7 +++++++ setup.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3be485a..01c548a 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,10 @@ You can find the source code for `py-dependency-injection` on [GitHub](https://g ## Release Notes -### [1.0.0-alpha.11](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.11) (2024-08-xx) +### [1.0.0-alpha.11](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.11) (2025-01-06) - **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. +- **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name. ### [1.0.0-alpha.10](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.10) (2024-08-11) diff --git a/docs/releases.rst b/docs/releases.rst index 03c715b..926f156 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -6,6 +6,13 @@ Version History ############### +**1.0.0-alpha.11 (2025-01-06)** + +- **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. +- **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name. + +`View release on GitHub `_ + **1.0.0-alpha.10 (2024-08-11)** - **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. diff --git a/setup.py b/setup.py index 809a8aa..1ec3308 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="py-dependency-injection", - version="1.0.0-alpha.10", + version="1.0.0-alpha.11", author="David Runemalm, 2024", author_email="david.runemalm@gmail.com", description="A dependency injection library for Python.", From 2bca9d1ea543dd2bc55a00f542ea65e9844c24d0 Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 6 Jan 2025 13:49:15 +0100 Subject: [PATCH 5/7] Cleanup unused doc files. --- docs/community.rst | 9 --------- docs/index.rst | 7 ------- docs/modules/container.rst | 9 --------- docs/modules/decorator.rst | 9 --------- docs/modules/scope.rst | 9 --------- docs/py-modindex.rst | 2 -- 6 files changed, 45 deletions(-) delete mode 100644 docs/community.rst delete mode 100644 docs/modules/container.rst delete mode 100644 docs/modules/decorator.rst delete mode 100644 docs/modules/scope.rst delete mode 100644 docs/py-modindex.rst diff --git a/docs/community.rst b/docs/community.rst deleted file mode 100644 index eccf973..0000000 --- a/docs/community.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. community: - -############ -Contribution -############ - -You are welcome to suggest changes and to submit bug reports at the github repository. - -We also look forward to seeing user guides as this project is being adopted. diff --git a/docs/index.rst b/docs/index.rst index 23cf62d..5529664 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,11 +42,4 @@ Key Advantages releases -.. apireference-docs: -.. toctree:: - :maxdepth: 1 - :caption: API Reference - - py-modindex - You can find the source code for `py-dependency-injection` in our `GitHub repository `_. diff --git a/docs/modules/container.rst b/docs/modules/container.rst deleted file mode 100644 index 0cc5661..0000000 --- a/docs/modules/container.rst +++ /dev/null @@ -1,9 +0,0 @@ -:mod:`dependency_injection.container` -=============================================================== - -.. automodule:: dependency_injection.container - -.. autoclass:: DependencyContainer - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/modules/decorator.rst b/docs/modules/decorator.rst deleted file mode 100644 index 7c1b5e3..0000000 --- a/docs/modules/decorator.rst +++ /dev/null @@ -1,9 +0,0 @@ -:mod:`dependency_injection.decorator` -===================================== - -.. automodule:: dependency_injection.decorator - -.. autofunction:: inject - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/modules/scope.rst b/docs/modules/scope.rst deleted file mode 100644 index 6020380..0000000 --- a/docs/modules/scope.rst +++ /dev/null @@ -1,9 +0,0 @@ -:mod:`dependency_injection.scope` -=============================================================== - -.. automodule:: dependency_injection.scope - -.. autoclass:: Scope - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/py-modindex.rst b/docs/py-modindex.rst deleted file mode 100644 index bcb43b4..0000000 --- a/docs/py-modindex.rst +++ /dev/null @@ -1,2 +0,0 @@ -API Reference -============= From e0216d3160250fe646d43ab4d92e269303f55942 Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 6 Jan 2025 14:03:59 +0100 Subject: [PATCH 6/7] Transition to beta. --- README.md | 3 ++- docs/conf.py | 2 +- docs/index.rst | 5 +++-- docs/releases.rst | 10 ++++++---- setup.py | 4 ++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 01c548a..d88f2ed 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,9 @@ You can find the source code for `py-dependency-injection` on [GitHub](https://g ## Release Notes -### [1.0.0-alpha.11](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.11) (2025-01-06) +### [1.0.0-beta.1](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-beta.1) (2025-01-06) +- **Transition to Beta**: Transitioned from alpha to beta. Features have been stabilized and are ready for broader testing. - **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. - **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name. diff --git a/docs/conf.py b/docs/conf.py index 7329242..f44e7ca 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,7 @@ version = "1.0" # The full version, including alpha/beta/rc tags -release = "1.0.0-alpha.10" +release = "1.0.0-beta.1" # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index 5529664..3608fce 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,7 @@ -.. warning:: +.. note:: - This library is currently in the alpha stage of development. Expect changes and improvements as we work towards a stable release. + This library is currently in the beta stage of development. + While features are stable, some minor adjustments may occur before the final release. py-dependency-injection ======================= diff --git a/docs/releases.rst b/docs/releases.rst index 926f156..b55df2c 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -1,17 +1,19 @@ -.. warning:: +.. note:: - This library is currently in the alpha stage of development. Expect changes and improvements as we work towards a stable release. + This library is currently in the beta stage of development. + While features are stable, some minor adjustments may occur before the final release. ############### Version History ############### -**1.0.0-alpha.11 (2025-01-06)** +**1.0.0-beta.1 (2025-01-06)** +- **Transition to Beta**: Transitioned from alpha to beta. Features have been stabilized and are ready for broader testing. - **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. - **Enhancement**: Added suppprt for configuring default scope name. Either a static string value, or a callable that returns the name. -`View release on GitHub `_ +`View release on GitHub `_ **1.0.0-alpha.10 (2024-08-11)** diff --git a/setup.py b/setup.py index 1ec3308..aebf618 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="py-dependency-injection", - version="1.0.0-alpha.11", + version="1.0.0-beta.1", author="David Runemalm, 2024", author_email="david.runemalm@gmail.com", description="A dependency injection library for Python.", @@ -34,7 +34,7 @@ ], python_requires=">=3.7", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python :: 3.7", From 9d2b5afab966e0bff8086b6a03e6ee035ee186b6 Mon Sep 17 00:00:00 2001 From: David Runemalm Date: Mon, 6 Jan 2025 15:51:55 +0100 Subject: [PATCH 7/7] Extend user guide. --- docs/userguide.rst | 86 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/docs/userguide.rst b/docs/userguide.rst index 0463dd5..cae5c35 100644 --- a/docs/userguide.rst +++ b/docs/userguide.rst @@ -2,9 +2,91 @@ Getting Started ############### +.. note:: + `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. + +############ +Introduction +############ + +`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. + +This guide will help you understand the key concepts and how to start using the library. For detailed examples, see the `Examples` section. + +############ Installation ---------------- +############ -Install using `pip `_:: +Install the library using pip: + +.. code-block:: bash $ pip install py-dependency-injection + +The library supports Python versions 3.7 through 3.12. + +########################## +Core Concepts and Features +########################## + +`py-dependency-injection` offers: + +- **Scoped Dependency Management**: Define lifetimes for your dependencies (e.g., transient, scoped, singleton). +- **Flexible Registrations**: Use constructors, factories, or predefined instances for dependency registration. +- **Tag-Based Organization**: Categorize and resolve dependencies using tags. +- **Multiple Containers**: Isolate dependencies for different parts of your application. + +Refer to the `Examples` section for detailed usage scenarios. + +#################### +Quick Start Overview +#################### + +1. **Create a Dependency Container**: + - The `DependencyContainer` is the core object for managing dependencies. + +2. **Register Dependencies**: + - Dependencies can be registered with different lifetimes: transient, scoped, or singleton. + +3. **Resolve Dependencies**: + - Use the container to resolve dependencies where needed. + +Basic workflow: + +.. code-block:: python + + from dependency_injection.container import DependencyContainer + + class Connection: + pass + + class PostgresConnection(Connection): + pass + + # Create a container + container = DependencyContainer.get_instance() + + # Register and resolve dependencies + container.register_singleton(Connection, PostgresConnection) + connection = container.resolve(Connection) + print(type(connection).__name__) # Output: PostgresConnection + +############## +Best Practices +############## + +- **Use Constructor Injection**: Preferred for most cases as it promotes clear and testable designs. +- **Leverage Tags for Organization**: Group dependencies logically using tags. +- **Choose the Right Scope**: Use scoped or singleton lifetimes to optimize performance and resource usage. +- **Keep Dependencies Decoupled**: Avoid tightly coupling your components to the container. +- **Isolate Contexts with Containers**: Use multiple containers to manage dependencies for separate modules or contexts. + +################# +Where to Go Next? +################# + +- **Examples**: + Explore detailed examples of how to register, resolve, and manage dependencies effectively in the `Examples` section. + +- **Community and Support**: + Join our community on GitHub to ask questions, report issues, or contribute to the project.