diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 71c79a3..5085062 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.6' + python-version: '3.8' - name: Install dependencies run: | diff --git a/setup.py b/setup.py index 7da9e54..38f7aa4 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ def read_requirements(file): setup( name="simple_dependency_injector", - version="0.1.0", + version="0.2.0", description="A simple dependency injection framework for Python", long_description=open("README.md").read(), long_description_content_type="text/markdown", diff --git a/tests/config/another_services.json b/tests/config/another_services.json new file mode 100644 index 0000000..78c33f7 --- /dev/null +++ b/tests/config/another_services.json @@ -0,0 +1,25 @@ +{ + "services": { + "another_service": { + "class": "tests/services/my_module.py#AnotherService", + "arguments": [ + "@core_service", + "!tagged service", + "!context" + ] + }, + "core_service": { + "class": "tests/services/my_module.py#CoreService", + "tags": [ + "service" + ] + }, + "base_service": { + "class": "tests/services/my_module.py#BaseService", + "tags": [ + "service" + ] + } + }, + "imports": [] +} diff --git a/tests/config/another_services.py b/tests/config/another_services.py new file mode 100644 index 0000000..44d38f4 --- /dev/null +++ b/tests/config/another_services.py @@ -0,0 +1,14 @@ +services = { + "another_service": { + "class": "tests/services/my_module.py#AnotherService", + "arguments": [ + "@core_service", + "!tagged service", + "!context", + ], + }, + "core_service": {"class": "tests/services/my_module.py#CoreService", "tags": ["service"]}, + "base_service": {"class": "tests/services/my_module.py#BaseService", "tags": ["service"]}, +} + +imports = [] diff --git a/tests/config/another_services.yaml b/tests/config/another_services.yaml index ad59cb4..3376684 100644 --- a/tests/config/another_services.yaml +++ b/tests/config/another_services.yaml @@ -1,4 +1,15 @@ services: another_service: class: 'tests/services/my_module.py#AnotherService' - scope: singleton + arguments: + - '@core_service' + - '!tagged service' + - '!context' + core_service: + class: 'tests/services/my_module.py#CoreService' + tags: + - 'service' + base_service: + class: 'tests/services/my_module.py#BaseService' + tags: + - 'service' diff --git a/tests/config/another_services_python.py b/tests/config/another_services_python.py deleted file mode 100644 index 2cf0c82..0000000 --- a/tests/config/another_services_python.py +++ /dev/null @@ -1,8 +0,0 @@ -services = { - "another_service": { - "class": "tests/services/my_module.py#AnotherService", - "scope": "singleton", - } -} - -imports = [] diff --git a/tests/config/invalid_class_python.py b/tests/config/invalid_class_python.py deleted file mode 100644 index b3acb20..0000000 --- a/tests/config/invalid_class_python.py +++ /dev/null @@ -1,7 +0,0 @@ -services = { - "invalid_class": { - "class": "tests/services/my_module.py#NonExistentClass", - }, -} - -imports = [] diff --git a/tests/config/invalid_factory_method_python.py b/tests/config/invalid_factory_method_python.py deleted file mode 100644 index d56d2aa..0000000 --- a/tests/config/invalid_factory_method_python.py +++ /dev/null @@ -1,10 +0,0 @@ -services = { - "invalid_factory_method": { - "factory": { - "class": "tests/services/my_module.py#MyFactory", - "method": "non_existent_method", - } - }, -} - -imports = [] diff --git a/tests/config/invalid_scope_python.py b/tests/config/invalid_scope_python.py deleted file mode 100644 index 514f1c5..0000000 --- a/tests/config/invalid_scope_python.py +++ /dev/null @@ -1,8 +0,0 @@ -services = { - "invalid_scope": { - "class": "tests/services/my_module.py#MyService", - "scope": "invalid_scope", - }, -} - -imports = [] diff --git a/tests/config/missing_class_parameter_python.py b/tests/config/missing_class_parameter_python.py deleted file mode 100644 index 4286ed6..0000000 --- a/tests/config/missing_class_parameter_python.py +++ /dev/null @@ -1,5 +0,0 @@ -services = { - "missing_class_parameter": {"class": 123}, -} - -imports = [] diff --git a/tests/config/missing_instance_parameter_python.py b/tests/config/missing_instance_parameter_python.py deleted file mode 100644 index df60e6e..0000000 --- a/tests/config/missing_instance_parameter_python.py +++ /dev/null @@ -1,3 +0,0 @@ -services = {"missing_instance_parameter": {"instance": 123}} - -imports = [] diff --git a/tests/config/services.json b/tests/config/services.json new file mode 100644 index 0000000..ab29f80 --- /dev/null +++ b/tests/config/services.json @@ -0,0 +1,26 @@ +{ + "services": { + "my_singleton_service": { + "class": "tests/services/my_module.py#MyService", + "scope": "singleton" + }, + "my_service": { + "class": "tests/services/my_module.py#MyService" + }, + "my_factory_service": { + "factory": { + "class": "tests/services/my_module.py#MyFactory", + "method": "create_service" + }, + "scope": "request" + }, + "my_instance_service": { + "instance": "tests/services/my_module.py#MyInstance" + } + }, + "imports": [ + { + "resource": "another_services.py" + } + ] +} diff --git a/tests/config/services_python.py b/tests/config/services.py similarity index 74% rename from tests/config/services_python.py rename to tests/config/services.py index 7a27668..d349709 100644 --- a/tests/config/services_python.py +++ b/tests/config/services.py @@ -1,8 +1,11 @@ services = { - "my_service": { + "my_singleton_service": { "class": "tests/services/my_module.py#MyService", "scope": "singleton", }, + "my_service": { + "class": "tests/services/my_module.py#MyService", + }, "my_factory_service": { "factory": { "class": "tests/services/my_module.py#MyFactory", @@ -15,4 +18,4 @@ }, } -imports = [{"resource": "another_services_python.py"}] +imports = [{"resource": "another_services.py"}] diff --git a/tests/config/services.yaml b/tests/config/services.yaml index 608ea35..605e631 100644 --- a/tests/config/services.yaml +++ b/tests/config/services.yaml @@ -1,8 +1,11 @@ services: - my_service: + my_singleton_service: class: 'tests/services/my_module.py#MyService' scope: singleton + my_service: + class: 'tests/services/my_module.py#MyService' + my_factory_service: factory: class: 'tests/services/my_module.py#MyFactory' diff --git a/tests/services/my_module.py b/tests/services/my_module.py index b373ec4..93509ef 100644 --- a/tests/services/my_module.py +++ b/tests/services/my_module.py @@ -1,3 +1,6 @@ +from typing import Any, List + + class MyService: def __init__(self): self.name = "Service" @@ -17,6 +20,19 @@ def __init__(self): MyInstance = MyInstanceGenerator() -class AnotherService: +class CoreService: def __init__(self): + self.name = "Core Service" + + +class BaseService: + def __init__(self): + self.name = "Base Service" + + +class AnotherService: + def __init__(self, core: CoreService, services: List[Any], context: Any): self.name = "Another Service" + self.core = core + self.services = services + self.context = context diff --git a/tests/test_class_services.py b/tests/test_class_services.py deleted file mode 100644 index 5807c43..0000000 --- a/tests/test_class_services.py +++ /dev/null @@ -1,25 +0,0 @@ -import os.path -import unittest - -from simple_dependency_injector import DependencyInjector - - -class TestClassServices(unittest.TestCase): - def setUp(self): - self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) - - def test_load_yaml_class_service(self): - self.injector.load("tests/config/services.yaml") - self.injector.compile() - service = self.injector.get("my_service") - self.assertEqual(service.name, "Service") - - def test_load_python_class_service(self): - self.injector.load("tests/config/services_python.py") - self.injector.compile() - service = self.injector.get("my_service") - self.assertEqual(service.name, "Service") - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_contexts.py b/tests/test_contexts.py index 0992bff..5d3cbb2 100644 --- a/tests/test_contexts.py +++ b/tests/test_contexts.py @@ -1,5 +1,5 @@ -import unittest import os.path +import unittest from simple_dependency_injector import DependencyInjector @@ -9,12 +9,17 @@ def setUp(self): self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) def test_create_context(self): - self.injector.load("tests/config/services_python.py") + self.injector.load("tests/config/services.yaml") self.injector.compile() - context = self.injector.create_context() + context1 = self.injector.create_context() + context2 = self.injector.create_context() + + service1 = context1.get("my_service") + service2 = context2.get("my_service") - service = context.get("my_service") - self.assertEqual(service.name, "Service") + self.assertEqual(service1.name, "Service") + self.assertEqual(service2.name, "Service") + self.assertNotEqual(service1, service2) if __name__ == "__main__": diff --git a/tests/test_failures.py b/tests/test_failures.py index 73a766d..44471d8 100644 --- a/tests/test_failures.py +++ b/tests/test_failures.py @@ -1,10 +1,10 @@ -import unittest import os.path +import unittest from simple_dependency_injector import DependencyInjector -class TestFailureCases(unittest.TestCase): +class TestFailures(unittest.TestCase): def setUp(self): self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) @@ -58,53 +58,6 @@ def test_missing_instance_parameter_yaml(self): str(context.exception), ) - def test_invalid_class_python(self): - with self.assertRaises(AttributeError) as context: - self.injector.load("tests/config/invalid_class_python.py") - self.injector.compile() - self.injector.get("invalid_class") - self.assertEqual( - "module 'module.name' has no attribute 'NonExistentClass'", - str(context.exception), - ) - - def test_invalid_factory_method_python(self): - with self.assertRaises(AttributeError) as context: - self.injector.load("tests/config/invalid_factory_method_python.py") - self.injector.compile() - self.injector.get("invalid_factory_method") - self.assertIn("non_existent_method", str(context.exception)) - - def test_missing_class_parameter_python(self): - with self.assertRaises(ValueError) as context: - self.injector.load("tests/config/missing_class_parameter_python.py") - self.injector.compile() - self.injector.get("missing_class_parameter") - self.assertEqual( - "Service 'missing_class_parameter' has an invalid class name: 123", - str(context.exception), - ) - - def test_invalid_scope_python(self): - with self.assertRaises(ValueError) as context: - self.injector.load("tests/config/invalid_scope_python.py") - self.injector.compile() - self.injector.get("invalid_scope") - self.assertEqual( - "Service 'invalid_scope' has an invalid scope: invalid_scope", - str(context.exception), - ) - - def test_missing_instance_parameter_python(self): - with self.assertRaises(ValueError) as context: - self.injector.load("tests/config/missing_instance_parameter_python.py") - self.injector.compile() - self.injector.get("missing_instance_parameter") - self.assertEqual( - "Service 'missing_instance_parameter' has an invalid instance: 123", - str(context.exception), - ) - if __name__ == "__main__": unittest.main() diff --git a/tests/test_imported_services.py b/tests/test_imported_services.py index 3dec2ef..da748c4 100644 --- a/tests/test_imported_services.py +++ b/tests/test_imported_services.py @@ -1,5 +1,5 @@ -import unittest import os.path +import unittest from simple_dependency_injector import DependencyInjector @@ -15,7 +15,7 @@ def test_load_yaml_imported_service(self): self.assertEqual(another_service.name, "Another Service") def test_load_python_imported_service(self): - self.injector.load("tests/config/services_python.py") + self.injector.load("tests/config/services.py") self.injector.compile() another_service = self.injector.get("another_service") self.assertEqual(another_service.name, "Another Service") diff --git a/tests/test_instance_services.py b/tests/test_instance_services.py deleted file mode 100644 index 4d2b222..0000000 --- a/tests/test_instance_services.py +++ /dev/null @@ -1,25 +0,0 @@ -import unittest -import os.path - -from simple_dependency_injector import DependencyInjector - - -class TestInstanceServices(unittest.TestCase): - def setUp(self): - self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) - - def test_load_yaml_instance_service(self): - self.injector.load("tests/config/services.yaml") - self.injector.compile() - instance = self.injector.get("my_instance_service") - self.assertEqual(instance.name, "Instance") - - def test_load_python_instance_service(self): - self.injector.load("tests/config/services_python.py") - self.injector.compile() - instance = self.injector.get("my_instance_service") - self.assertEqual(instance.name, "Instance") - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_factory_services.py b/tests/test_instantiation.py similarity index 56% rename from tests/test_factory_services.py rename to tests/test_instantiation.py index cad94fe..2cc0fc5 100644 --- a/tests/test_factory_services.py +++ b/tests/test_instantiation.py @@ -1,10 +1,10 @@ -import unittest import os.path +import unittest from simple_dependency_injector import DependencyInjector -class TestFactoryServices(unittest.TestCase): +class TestInstantiation(unittest.TestCase): def setUp(self): self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) @@ -14,12 +14,18 @@ def test_load_yaml_factory_service(self): service = self.injector.get("my_factory_service") self.assertEqual(service.name, "Service") - def test_load_python_factory_service(self): - self.injector.load("tests/config/services_python.py") + def test_load_yaml_class_service(self): + self.injector.load("tests/config/services.yaml") self.injector.compile() - service = self.injector.get("my_factory_service") + service = self.injector.get("my_service") self.assertEqual(service.name, "Service") + def test_load_yaml_instance_service(self): + self.injector.load("tests/config/services.yaml") + self.injector.compile() + instance = self.injector.get("my_instance_service") + self.assertEqual(instance.name, "Instance") + if __name__ == "__main__": unittest.main() diff --git a/tests/test_load_supported_files.py b/tests/test_load_supported_files.py new file mode 100644 index 0000000..83b62bc --- /dev/null +++ b/tests/test_load_supported_files.py @@ -0,0 +1,31 @@ +import os.path +import unittest + +from simple_dependency_injector import DependencyInjector + + +class TestLoadSupportedFiles(unittest.TestCase): + def setUp(self): + self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) + + def test_load_yaml_class_service(self): + self.injector.load("tests/config/services.yaml") + self.injector.compile() + service = self.injector.get("base_service") + self.assertEqual(service.name, "Base Service") + + def test_load_python_class_service(self): + self.injector.load("tests/config/services.py") + self.injector.compile() + service = self.injector.get("base_service") + self.assertEqual(service.name, "Base Service") + + def test_load_json_class_service(self): + self.injector.load("tests/config/services.json") + self.injector.compile() + service = self.injector.get("base_service") + self.assertEqual(service.name, "Base Service") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_scopes.py b/tests/test_scopes.py deleted file mode 100644 index f3bb5fe..0000000 --- a/tests/test_scopes.py +++ /dev/null @@ -1,49 +0,0 @@ -import os.path -import unittest - -from simple_dependency_injector import DependencyInjector - - -class TestScopes(unittest.TestCase): - def setUp(self): - self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) - - def test_singleton_scope(self): - self.injector.load("tests/config/services.yaml") - self.injector.compile() - - service1 = self.injector.get("my_service") - service2 = self.injector.get("my_service") - - self.assertIs(service1, service2) - - def test_request_scope(self): - self.injector.load("tests/config/services.yaml") - self.injector.compile() - - service1 = self.injector.get("my_factory_service") - service2 = self.injector.get("my_factory_service") - - self.assertIsNot(service1, service2) - - def test_transient_scope(self): - self.injector.load("tests/config/services_python.py") - self.injector.compile() - - service1 = self.injector.get("my_factory_service") - service2 = self.injector.get("my_factory_service") - - self.assertIsNot(service1, service2) - - def test_ambivalent_scope(self): - self.injector.load("tests/config/services_python.py") - self.injector.compile() - - service1 = self.injector.get("my_factory_service") - service2 = self.injector.get("my_factory_service") - - self.assertIsNot(service1, service2) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_special_arguments.py b/tests/test_special_arguments.py new file mode 100644 index 0000000..78927e6 --- /dev/null +++ b/tests/test_special_arguments.py @@ -0,0 +1,47 @@ +import os.path +import unittest + +from simple_dependency_injector import DependencyInjector + + +class TestSpecialArguments(unittest.TestCase): + def setUp(self): + self.injector = DependencyInjector(base_path=os.path.dirname(os.path.dirname(__file__))) + + def test_get_dependency_injector(self): + self.injector.load("tests/config/services.yaml") + self.injector.compile() + service = self.injector.get("another_service") + self.assertEqual(service.context, self.injector) + + def test_get_context(self): + self.injector.load("tests/config/services.yaml") + self.injector.compile() + context = self.injector.create_context() + service = context.get("another_service") + self.assertEqual(service.context, context) + + def test_get_other_service(self): + self.injector.load("tests/config/services.yaml") + self.injector.compile() + service = self.injector.get("another_service") + self.assertEqual(service.name, "Another Service") + self.assertEqual(service.core.name, "Core Service") + + def test_get_tag_list(self): + self.injector.load("tests/config/services.py") + self.injector.compile() + service = self.injector.get("another_service") + self.assertEqual(service.name, "Another Service") + self.assertEqual(service.services[0].name, "Core Service") + self.assertEqual(service.services[1].name, "Base Service") + + def test_load_json_class_service(self): + self.injector.load("tests/config/services.json") + self.injector.compile() + service = self.injector.get("my_service") + self.assertEqual(service.name, "Service") + + +if __name__ == "__main__": + unittest.main()