From 675ed83b53187f3602e4bfc3b579c46978c1e5e0 Mon Sep 17 00:00:00 2001 From: Mario Taddeucci Date: Mon, 11 Nov 2024 21:36:17 -0300 Subject: [PATCH] Injector improvements --- src/gyjd/__init__.py | 23 +++++++++-- src/gyjd/core/simple_injector.py | 4 ++ tests/conftest.py | 7 ++++ .../injector/reuse_n_time_injection_test.py | 40 +++++++++++++++++++ .../core/injector/singleton_injection_test.py | 31 ++++++++++++++ .../core/injector/transient_injection_test.py | 29 ++++++++++++++ 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/core/injector/reuse_n_time_injection_test.py create mode 100644 tests/core/injector/singleton_injection_test.py create mode 100644 tests/core/injector/transient_injection_test.py diff --git a/src/gyjd/__init__.py b/src/gyjd/__init__.py index 79538ec..9125413 100644 --- a/src/gyjd/__init__.py +++ b/src/gyjd/__init__.py @@ -7,11 +7,25 @@ from gyjd.core.config_loader import load_config_file from gyjd.core.gyjd_callable import GYJDCallable from gyjd.core.logger import GYJDLogger, get_default_logger -from gyjd.core.simple_injector import inject_dependencies, register_dependency +from gyjd.core.simple_injector import clear_registered_dependencies, inject_dependencies, register_dependency -register_dependency(get_default_logger, cls=GYJDLogger, reuse_times=-1, if_exists="skip") -register_dependency(get_default_logger, cls=logging.Logger, reuse_times=-1, if_exists="skip") -register_dependency(LoggerConfig, reuse_times=-1, if_exists="skip") + +def setup_defaults(clear_dependencies: bool = False): + """ + Register default dependencies: + - GYJDLogger + - logging.Logger + - LoggerConfig + + If clear_dependencies is True, clear all registered dependencies before registering the default ones. + """ + + if clear_dependencies: + clear_registered_dependencies() + + register_dependency(get_default_logger, cls=GYJDLogger, reuse_times=-1, if_exists="skip") + register_dependency(get_default_logger, cls=logging.Logger, reuse_times=-1, if_exists="skip") + register_dependency(LoggerConfig, reuse_times=-1, if_exists="skip") class gyjd: @@ -98,4 +112,5 @@ def register_config_file( ) +setup_defaults() __all__ = ["gyjd"] diff --git a/src/gyjd/core/simple_injector.py b/src/gyjd/core/simple_injector.py index fdeb9ee..11d3021 100644 --- a/src/gyjd/core/simple_injector.py +++ b/src/gyjd/core/simple_injector.py @@ -86,3 +86,7 @@ def register_dependency( def get_registered_dependencies() -> set[Type]: return set(_DEPENDENCIES_REGISTER) + + +def clear_registered_dependencies(): + _DEPENDENCIES_REGISTER.clear() diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..9fa244a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,7 @@ +import pytest +from gyjd import setup_defaults + + +@pytest.fixture(scope="function") +def reset_injector(): + setup_defaults(clear_dependencies=True) diff --git a/tests/core/injector/reuse_n_time_injection_test.py b/tests/core/injector/reuse_n_time_injection_test.py new file mode 100644 index 0000000..f262c8f --- /dev/null +++ b/tests/core/injector/reuse_n_time_injection_test.py @@ -0,0 +1,40 @@ +from dataclasses import dataclass, field +from uuid import uuid4 + +from gyjd import gyjd + + +@dataclass +class MockConfig: + mock_id: str = field(default_factory=lambda: str(uuid4())) + + +def gen_mock() -> MockConfig: + return MockConfig() + + +@gyjd +def get_mock(mock: MockConfig = None) -> str: + for _ in range(10): + # Ensure that instance is reused on each attribute access + mock.mock_id + + return mock.mock_id + + +def test_reuse_25_times_injection(): + gyjd.register_dependency(gen_mock, reuse_times=25) + + assert len(set([get_mock() for _ in range(100)])) == 4 + + +def test_reuse_10_times_injection(): + gyjd.register_dependency(gen_mock, reuse_times=10) + + assert len(set([get_mock() for _ in range(100)])) == 10 + + +def test_reuse_05_times_injection(): + gyjd.register_dependency(gen_mock, reuse_times=5) + + assert len(set([get_mock() for _ in range(100)])) == 20 diff --git a/tests/core/injector/singleton_injection_test.py b/tests/core/injector/singleton_injection_test.py new file mode 100644 index 0000000..1a0db5d --- /dev/null +++ b/tests/core/injector/singleton_injection_test.py @@ -0,0 +1,31 @@ +from dataclasses import dataclass, field +from uuid import uuid4 + +from gyjd import gyjd + + +@dataclass +class MockConfig: + mock_id: str = field(default_factory=lambda: str(uuid4())) + + +def gen_mock() -> MockConfig: + return MockConfig() + + +@gyjd +def get_mock(mock: MockConfig = None) -> str: + for _ in range(10): + # Ensure that instance is reused on each attribute access + mock.mock_id + + return mock.mock_id + + +def test_singleton_injection(): + gyjd.register_dependency(gen_mock) + + first_mock_id = get_mock() + + for _ in range(10): + assert get_mock() == first_mock_id diff --git a/tests/core/injector/transient_injection_test.py b/tests/core/injector/transient_injection_test.py new file mode 100644 index 0000000..5194003 --- /dev/null +++ b/tests/core/injector/transient_injection_test.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass, field +from uuid import uuid4 + +from gyjd import gyjd + + +@dataclass +class MockConfig: + mock_id: str = field(default_factory=lambda: str(uuid4())) + + +def gen_mock() -> MockConfig: + return MockConfig() + + +@gyjd +def get_mock(mock: MockConfig = None) -> str: + for _ in range(10): + # Ensure that instance is reused on each attribute access + mock.mock_id + + return mock.mock_id + + +def test_transient_injection(): + gyjd.register_dependency(gen_mock, reuse_times=0) + + # Ensure that each instance is unique + assert len(set([get_mock() for _ in range(100)])) == 100