From 55a727c482ea98745470bd06a77853cd9705bc57 Mon Sep 17 00:00:00 2001 From: edraft Date: Thu, 25 Sep 2025 09:42:07 +0200 Subject: [PATCH] Modularization --- .../api/src/appsettings.development.json | 0 .../api/src/appsettings.edrafts-pc.json | 0 example/{custom => }/api/src/appsettings.json | 0 example/{custom => }/api/src/main.py | 5 +- .../{custom => }/api/src/routes/__init__.py | 0 example/{custom => }/api/src/routes/ping.py | 0 .../{custom => }/api/src/scoped_service.py | 0 example/{custom => }/api/src/service.py | 0 example/{custom => }/console/main.py | 0 example/custom/database/cpl.json | 40 ------------ example/custom/di/cpl-workspace.json | 9 --- example/custom/general/cpl-workspace.json | 8 --- example/custom/general/src/general.json | 51 --------------- example/custom/general/test/__init__.py | 0 example/custom/general/test/custom.py | 3 - .../custom/translation/src/tests/__init__.py | 0 .../translation/src/translation/__init__.py | 0 example/{custom => }/database/LICENSE | 0 example/{custom => }/database/README.md | 0 .../{custom => }/database/src/application.py | 0 .../database/src/appsettings.development.json | 0 .../src/appsettings.edrafts-lapi.json | 0 .../database/src/appsettings.edrafts-pc.json | 0 .../database/src/appsettings.json | 0 .../database/src/custom_permissions.py | 0 example/{custom => }/database/src/main.py | 0 .../database/src/main_simplified.py | 0 .../database/src/model/__init__.py | 0 .../{custom => }/database/src/model/city.py | 0 .../database/src/model/city_dao.py | 0 .../{custom => }/database/src/model/user.py | 0 .../database/src/model/user_dao.py | 0 .../database/src/scripts/0-initial.sql | 0 example/{custom => }/database/src/startup.py | 0 .../database/src/tests/__init__.py | 0 example/{custom => }/di/LICENSE | 0 example/{custom => }/di/README.md | 0 example/{custom => }/di/appsettings.json | 0 .../{custom/di/src/di => di/src}/__init__.py | 0 .../di/src/di => di/src}/application.py | 0 example/{custom/di/src/di => di/src}/di.json | 0 .../di/src/di => di/src}/di_tester_service.py | 0 example/{custom/di/src/di => di/src}/main.py | 0 .../{custom/di/src/di => di/src}/startup.py | 0 .../di/src/di => di/src}/static_test.py | 0 .../di/src/di => di/src}/test1_service.py | 0 .../di/src/di => di/src}/test2_service.py | 0 .../{custom/di/src/di => di/src}/test_abc.py | 0 .../di/src/di => di/src}/test_service.py | 0 .../{custom/di/src/di => di/src}/tester.py | 0 .../general/.cpl/schematic_custom.py | 0 .../di/src/tests => general/src}/__init__.py | 0 .../{custom => }/general/src/application.py | 0 .../general/src/appsettings.development.json | 0 .../general/src/appsettings.edrafts-lapi.json | 0 .../general/src/appsettings.edrafts-pc.json | 0 .../{custom => }/general/src/appsettings.json | 0 .../{custom => }/general/src/db/__init__.py | 0 .../general/src/hosted_service.py | 0 example/{custom => }/general/src/main.py | 0 .../general/src/scoped_service.py | 0 example/{custom => }/general/src/startup.py | 5 +- .../general/src/test_extension.py | 0 .../{custom => }/general/src/test_service.py | 0 .../{custom => }/general/src/test_settings.py | 0 .../general/src/test_startup_extension.py | 0 example/{custom => }/query/main.py | 0 example/{custom => }/translation/LICENSE | 0 example/{custom => }/translation/README.md | 0 .../translation/cpl-workspace.json | 0 .../general => translation}/src/__init__.py | 0 .../src}/application.py | 0 .../src}/appsettings.json | 0 .../translation => translation/src}/main.py | 0 .../src}/startup.py | 0 .../src}/translation.json | 0 .../src}/translation/de.json | 0 .../src}/translation/en.json | 0 src/cpl-api/cpl/api/__init__.py | 32 --------- src/cpl-api/cpl/api/application/web_app.py | 5 +- src/cpl-api/cpl/api_module.py | 26 ++++++++ .../cpl/application/application_builder.py | 1 + src/cpl-auth/cpl/auth/__init__.py | 65 +------------------ src/cpl-auth/cpl/auth/auth_module.py | 44 +++++++++++++ .../cpl/auth/permission/permission_module.py | 34 ++++++++++ .../{ => permission}/permission_seeder.py | 0 src/cpl-core/cpl/core/errors.py | 15 ++++- src/cpl-database/cpl/database/__init__.py | 40 ------------ .../cpl/database/database_module.py | 22 +++++++ .../cpl/database/model/server_type.py | 5 ++ .../cpl/database/mysql/mysql_module.py | 19 ++++++ .../cpl/database/postgres/postgres_module.py | 20 ++++++ src/cpl-dependency/cpl/dependency/module.py | 14 ++++ .../cpl/dependency/service_collection.py | 25 ++++--- src/cpl-mail/cpl/mail/mail_module.py | 15 +++++ .../cpl/translation/translate_pipe.py | 15 +++-- .../cpl/translation/translation_module.py | 14 ++++ 97 files changed, 266 insertions(+), 266 deletions(-) rename example/{custom => }/api/src/appsettings.development.json (100%) rename example/{custom => }/api/src/appsettings.edrafts-pc.json (100%) rename example/{custom => }/api/src/appsettings.json (100%) rename example/{custom => }/api/src/main.py (92%) rename example/{custom => }/api/src/routes/__init__.py (100%) rename example/{custom => }/api/src/routes/ping.py (100%) rename example/{custom => }/api/src/scoped_service.py (100%) rename example/{custom => }/api/src/service.py (100%) rename example/{custom => }/console/main.py (100%) delete mode 100644 example/custom/database/cpl.json delete mode 100644 example/custom/di/cpl-workspace.json delete mode 100644 example/custom/general/cpl-workspace.json delete mode 100644 example/custom/general/src/general.json delete mode 100644 example/custom/general/test/__init__.py delete mode 100644 example/custom/general/test/custom.py delete mode 100644 example/custom/translation/src/tests/__init__.py delete mode 100644 example/custom/translation/src/translation/__init__.py rename example/{custom => }/database/LICENSE (100%) rename example/{custom => }/database/README.md (100%) rename example/{custom => }/database/src/application.py (100%) rename example/{custom => }/database/src/appsettings.development.json (100%) rename example/{custom => }/database/src/appsettings.edrafts-lapi.json (100%) rename example/{custom => }/database/src/appsettings.edrafts-pc.json (100%) rename example/{custom => }/database/src/appsettings.json (100%) rename example/{custom => }/database/src/custom_permissions.py (100%) rename example/{custom => }/database/src/main.py (100%) rename example/{custom => }/database/src/main_simplified.py (100%) rename example/{custom => }/database/src/model/__init__.py (100%) rename example/{custom => }/database/src/model/city.py (100%) rename example/{custom => }/database/src/model/city_dao.py (100%) rename example/{custom => }/database/src/model/user.py (100%) rename example/{custom => }/database/src/model/user_dao.py (100%) rename example/{custom => }/database/src/scripts/0-initial.sql (100%) rename example/{custom => }/database/src/startup.py (100%) rename example/{custom => }/database/src/tests/__init__.py (100%) rename example/{custom => }/di/LICENSE (100%) rename example/{custom => }/di/README.md (100%) rename example/{custom => }/di/appsettings.json (100%) rename example/{custom/di/src/di => di/src}/__init__.py (100%) rename example/{custom/di/src/di => di/src}/application.py (100%) rename example/{custom/di/src/di => di/src}/di.json (100%) rename example/{custom/di/src/di => di/src}/di_tester_service.py (100%) rename example/{custom/di/src/di => di/src}/main.py (100%) rename example/{custom/di/src/di => di/src}/startup.py (100%) rename example/{custom/di/src/di => di/src}/static_test.py (100%) rename example/{custom/di/src/di => di/src}/test1_service.py (100%) rename example/{custom/di/src/di => di/src}/test2_service.py (100%) rename example/{custom/di/src/di => di/src}/test_abc.py (100%) rename example/{custom/di/src/di => di/src}/test_service.py (100%) rename example/{custom/di/src/di => di/src}/tester.py (100%) rename example/{custom => }/general/.cpl/schematic_custom.py (100%) rename example/{custom/di/src/tests => general/src}/__init__.py (100%) rename example/{custom => }/general/src/application.py (100%) rename example/{custom => }/general/src/appsettings.development.json (100%) rename example/{custom => }/general/src/appsettings.edrafts-lapi.json (100%) rename example/{custom => }/general/src/appsettings.edrafts-pc.json (100%) rename example/{custom => }/general/src/appsettings.json (100%) rename example/{custom => }/general/src/db/__init__.py (100%) rename example/{custom => }/general/src/hosted_service.py (100%) rename example/{custom => }/general/src/main.py (100%) rename example/{custom => }/general/src/scoped_service.py (100%) rename example/{custom => }/general/src/startup.py (88%) rename example/{custom => }/general/src/test_extension.py (100%) rename example/{custom => }/general/src/test_service.py (100%) rename example/{custom => }/general/src/test_settings.py (100%) rename example/{custom => }/general/src/test_startup_extension.py (100%) rename example/{custom => }/query/main.py (100%) rename example/{custom => }/translation/LICENSE (100%) rename example/{custom => }/translation/README.md (100%) rename example/{custom => }/translation/cpl-workspace.json (100%) rename example/{custom/general => translation}/src/__init__.py (100%) rename example/{custom/translation/src/translation => translation/src}/application.py (100%) rename example/{custom/translation/src/translation => translation/src}/appsettings.json (100%) rename example/{custom/translation/src/translation => translation/src}/main.py (100%) rename example/{custom/translation/src/translation => translation/src}/startup.py (100%) rename example/{custom/translation/src/translation => translation/src}/translation.json (100%) rename example/{custom/translation/src/translation => translation/src}/translation/de.json (100%) rename example/{custom/translation/src/translation => translation/src}/translation/en.json (100%) create mode 100644 src/cpl-api/cpl/api_module.py create mode 100644 src/cpl-auth/cpl/auth/auth_module.py create mode 100644 src/cpl-auth/cpl/auth/permission/permission_module.py rename src/cpl-auth/cpl/auth/{ => permission}/permission_seeder.py (100%) create mode 100644 src/cpl-database/cpl/database/database_module.py create mode 100644 src/cpl-database/cpl/database/mysql/mysql_module.py create mode 100644 src/cpl-database/cpl/database/postgres/postgres_module.py create mode 100644 src/cpl-dependency/cpl/dependency/module.py create mode 100644 src/cpl-mail/cpl/mail/mail_module.py create mode 100644 src/cpl-translation/cpl/translation/translation_module.py diff --git a/example/custom/api/src/appsettings.development.json b/example/api/src/appsettings.development.json similarity index 100% rename from example/custom/api/src/appsettings.development.json rename to example/api/src/appsettings.development.json diff --git a/example/custom/api/src/appsettings.edrafts-pc.json b/example/api/src/appsettings.edrafts-pc.json similarity index 100% rename from example/custom/api/src/appsettings.edrafts-pc.json rename to example/api/src/appsettings.edrafts-pc.json diff --git a/example/custom/api/src/appsettings.json b/example/api/src/appsettings.json similarity index 100% rename from example/custom/api/src/appsettings.json rename to example/api/src/appsettings.json diff --git a/example/custom/api/src/main.py b/example/api/src/main.py similarity index 92% rename from example/custom/api/src/main.py rename to example/api/src/main.py index 3b2d8157..cc102694 100644 --- a/example/custom/api/src/main.py +++ b/example/api/src/main.py @@ -2,6 +2,7 @@ from starlette.responses import JSONResponse from cpl import api from cpl.api.application.web_app import WebApp +from cpl.api_module import ApiModule from cpl.application import ApplicationBuilder from cpl.auth.permission.permissions import Permissions from cpl.auth.schema import AuthUser, Role @@ -9,6 +10,7 @@ from cpl.core.configuration import Configuration from cpl.core.console import Console from cpl.core.environment import Environment from cpl.core.utils.cache import Cache +from cpl.database.mysql.mysql_module import MySQLModule from scoped_service import ScopedService from service import PingService @@ -23,7 +25,8 @@ def main(): # builder.services.add_logging() builder.services.add_structured_logging() builder.services.add_transient(PingService) - builder.services.add_module(api) + builder.services.add_module(MySQLModule) + builder.services.add_module(ApiModule) builder.services.add_scoped(ScopedService) diff --git a/example/custom/api/src/routes/__init__.py b/example/api/src/routes/__init__.py similarity index 100% rename from example/custom/api/src/routes/__init__.py rename to example/api/src/routes/__init__.py diff --git a/example/custom/api/src/routes/ping.py b/example/api/src/routes/ping.py similarity index 100% rename from example/custom/api/src/routes/ping.py rename to example/api/src/routes/ping.py diff --git a/example/custom/api/src/scoped_service.py b/example/api/src/scoped_service.py similarity index 100% rename from example/custom/api/src/scoped_service.py rename to example/api/src/scoped_service.py diff --git a/example/custom/api/src/service.py b/example/api/src/service.py similarity index 100% rename from example/custom/api/src/service.py rename to example/api/src/service.py diff --git a/example/custom/console/main.py b/example/console/main.py similarity index 100% rename from example/custom/console/main.py rename to example/console/main.py diff --git a/example/custom/database/cpl.json b/example/custom/database/cpl.json deleted file mode 100644 index 2915ba1f..00000000 --- a/example/custom/database/cpl.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "Project": { - "Name": "database", - "Version": { - "Major": "0", - "Minor": "0", - "Micro": "0" - }, - "Author": "", - "AuthorEmail": "", - "Description": "", - "LongDescription": "", - "URL": "", - "CopyrightDate": "", - "CopyrightName": "", - "LicenseName": "", - "LicenseDescription": "", - "Dependencies": [ - "sh_cpl==2021.4.2.dev1" - ], - "PythonVersion": ">=3.9.2", - "PythonPath": {}, - "Classifiers": [] - }, - "Build": { - "ProjectType": "console", - "SourcePath": "src", - "OutputPath": "dist", - "Main": "main", - "EntryPoint": "database", - "IncludePackageData": false, - "Included": [], - "Excluded": [ - "*/__pycache__", - "*/logs", - "*/tests" - ], - "PackageData": {} - } -} \ No newline at end of file diff --git a/example/custom/di/cpl-workspace.json b/example/custom/di/cpl-workspace.json deleted file mode 100644 index 44506c16..00000000 --- a/example/custom/di/cpl-workspace.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Workspace": { - "DefaultProject": "di", - "Projects": { - "di": "src/di/di.json" - }, - "Scripts": {} - } -} \ No newline at end of file diff --git a/example/custom/general/cpl-workspace.json b/example/custom/general/cpl-workspace.json deleted file mode 100644 index 3b5ae16f..00000000 --- a/example/custom/general/cpl-workspace.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Workspace": { - "DefaultProject": "general", - "Projects": { - "general": "src/general/general.json" - } - } -} \ No newline at end of file diff --git a/example/custom/general/src/general.json b/example/custom/general/src/general.json deleted file mode 100644 index c0367c2e..00000000 --- a/example/custom/general/src/general.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "Project": { - "Name": "general", - "Version": { - "Major": "2021", - "Minor": "04", - "Micro": "01" - }, - "Author": "Sven Heidemann", - "AuthorEmail": "sven.heidemann@sh-edraft.de", - "Description": "sh-edraft Common Python library", - "LongDescription": "sh-edraft Common Python library", - "URL": "https://www.sh-edraft.de", - "CopyrightDate": "2020 - 2021", - "CopyrightName": "sh-edraft.de", - "LicenseName": "MIT", - "LicenseDescription": "MIT, see LICENSE for more details.", - "Dependencies": [ - "cpl-core==2022.10.0.post9", - "cpl-translation==2022.10.0.post2", - "cpl-query==2022.10.0.post2" - ], - "DevDependencies": [ - "cpl-cli==2022.10" - ], - "PythonVersion": ">=3.10", - "PythonPath": { - "linux": "../../venv/bin/python", - "win32": "" - }, - "Classifiers": [] - }, - "Build": { - "ProjectType": "console", - "SourcePath": "", - "OutputPath": "dist", - "Main": "main", - "EntryPoint": "", - "IncludePackageData": true, - "Included": [ - "*/templates" - ], - "Excluded": [ - "*/__pycache__", - "*/logs", - "*/tests" - ], - "PackageData": {}, - "ProjectReferences": [] - } -} \ No newline at end of file diff --git a/example/custom/general/test/__init__.py b/example/custom/general/test/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/example/custom/general/test/custom.py b/example/custom/general/test/custom.py deleted file mode 100644 index 1a833fc1..00000000 --- a/example/custom/general/test/custom.py +++ /dev/null @@ -1,3 +0,0 @@ -class Custom: - def __init__(self): - print("hello") diff --git a/example/custom/translation/src/tests/__init__.py b/example/custom/translation/src/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/example/custom/translation/src/translation/__init__.py b/example/custom/translation/src/translation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/example/custom/database/LICENSE b/example/database/LICENSE similarity index 100% rename from example/custom/database/LICENSE rename to example/database/LICENSE diff --git a/example/custom/database/README.md b/example/database/README.md similarity index 100% rename from example/custom/database/README.md rename to example/database/README.md diff --git a/example/custom/database/src/application.py b/example/database/src/application.py similarity index 100% rename from example/custom/database/src/application.py rename to example/database/src/application.py diff --git a/example/custom/database/src/appsettings.development.json b/example/database/src/appsettings.development.json similarity index 100% rename from example/custom/database/src/appsettings.development.json rename to example/database/src/appsettings.development.json diff --git a/example/custom/database/src/appsettings.edrafts-lapi.json b/example/database/src/appsettings.edrafts-lapi.json similarity index 100% rename from example/custom/database/src/appsettings.edrafts-lapi.json rename to example/database/src/appsettings.edrafts-lapi.json diff --git a/example/custom/database/src/appsettings.edrafts-pc.json b/example/database/src/appsettings.edrafts-pc.json similarity index 100% rename from example/custom/database/src/appsettings.edrafts-pc.json rename to example/database/src/appsettings.edrafts-pc.json diff --git a/example/custom/database/src/appsettings.json b/example/database/src/appsettings.json similarity index 100% rename from example/custom/database/src/appsettings.json rename to example/database/src/appsettings.json diff --git a/example/custom/database/src/custom_permissions.py b/example/database/src/custom_permissions.py similarity index 100% rename from example/custom/database/src/custom_permissions.py rename to example/database/src/custom_permissions.py diff --git a/example/custom/database/src/main.py b/example/database/src/main.py similarity index 100% rename from example/custom/database/src/main.py rename to example/database/src/main.py diff --git a/example/custom/database/src/main_simplified.py b/example/database/src/main_simplified.py similarity index 100% rename from example/custom/database/src/main_simplified.py rename to example/database/src/main_simplified.py diff --git a/example/custom/database/src/model/__init__.py b/example/database/src/model/__init__.py similarity index 100% rename from example/custom/database/src/model/__init__.py rename to example/database/src/model/__init__.py diff --git a/example/custom/database/src/model/city.py b/example/database/src/model/city.py similarity index 100% rename from example/custom/database/src/model/city.py rename to example/database/src/model/city.py diff --git a/example/custom/database/src/model/city_dao.py b/example/database/src/model/city_dao.py similarity index 100% rename from example/custom/database/src/model/city_dao.py rename to example/database/src/model/city_dao.py diff --git a/example/custom/database/src/model/user.py b/example/database/src/model/user.py similarity index 100% rename from example/custom/database/src/model/user.py rename to example/database/src/model/user.py diff --git a/example/custom/database/src/model/user_dao.py b/example/database/src/model/user_dao.py similarity index 100% rename from example/custom/database/src/model/user_dao.py rename to example/database/src/model/user_dao.py diff --git a/example/custom/database/src/scripts/0-initial.sql b/example/database/src/scripts/0-initial.sql similarity index 100% rename from example/custom/database/src/scripts/0-initial.sql rename to example/database/src/scripts/0-initial.sql diff --git a/example/custom/database/src/startup.py b/example/database/src/startup.py similarity index 100% rename from example/custom/database/src/startup.py rename to example/database/src/startup.py diff --git a/example/custom/database/src/tests/__init__.py b/example/database/src/tests/__init__.py similarity index 100% rename from example/custom/database/src/tests/__init__.py rename to example/database/src/tests/__init__.py diff --git a/example/custom/di/LICENSE b/example/di/LICENSE similarity index 100% rename from example/custom/di/LICENSE rename to example/di/LICENSE diff --git a/example/custom/di/README.md b/example/di/README.md similarity index 100% rename from example/custom/di/README.md rename to example/di/README.md diff --git a/example/custom/di/appsettings.json b/example/di/appsettings.json similarity index 100% rename from example/custom/di/appsettings.json rename to example/di/appsettings.json diff --git a/example/custom/di/src/di/__init__.py b/example/di/src/__init__.py similarity index 100% rename from example/custom/di/src/di/__init__.py rename to example/di/src/__init__.py diff --git a/example/custom/di/src/di/application.py b/example/di/src/application.py similarity index 100% rename from example/custom/di/src/di/application.py rename to example/di/src/application.py diff --git a/example/custom/di/src/di/di.json b/example/di/src/di.json similarity index 100% rename from example/custom/di/src/di/di.json rename to example/di/src/di.json diff --git a/example/custom/di/src/di/di_tester_service.py b/example/di/src/di_tester_service.py similarity index 100% rename from example/custom/di/src/di/di_tester_service.py rename to example/di/src/di_tester_service.py diff --git a/example/custom/di/src/di/main.py b/example/di/src/main.py similarity index 100% rename from example/custom/di/src/di/main.py rename to example/di/src/main.py diff --git a/example/custom/di/src/di/startup.py b/example/di/src/startup.py similarity index 100% rename from example/custom/di/src/di/startup.py rename to example/di/src/startup.py diff --git a/example/custom/di/src/di/static_test.py b/example/di/src/static_test.py similarity index 100% rename from example/custom/di/src/di/static_test.py rename to example/di/src/static_test.py diff --git a/example/custom/di/src/di/test1_service.py b/example/di/src/test1_service.py similarity index 100% rename from example/custom/di/src/di/test1_service.py rename to example/di/src/test1_service.py diff --git a/example/custom/di/src/di/test2_service.py b/example/di/src/test2_service.py similarity index 100% rename from example/custom/di/src/di/test2_service.py rename to example/di/src/test2_service.py diff --git a/example/custom/di/src/di/test_abc.py b/example/di/src/test_abc.py similarity index 100% rename from example/custom/di/src/di/test_abc.py rename to example/di/src/test_abc.py diff --git a/example/custom/di/src/di/test_service.py b/example/di/src/test_service.py similarity index 100% rename from example/custom/di/src/di/test_service.py rename to example/di/src/test_service.py diff --git a/example/custom/di/src/di/tester.py b/example/di/src/tester.py similarity index 100% rename from example/custom/di/src/di/tester.py rename to example/di/src/tester.py diff --git a/example/custom/general/.cpl/schematic_custom.py b/example/general/.cpl/schematic_custom.py similarity index 100% rename from example/custom/general/.cpl/schematic_custom.py rename to example/general/.cpl/schematic_custom.py diff --git a/example/custom/di/src/tests/__init__.py b/example/general/src/__init__.py similarity index 100% rename from example/custom/di/src/tests/__init__.py rename to example/general/src/__init__.py diff --git a/example/custom/general/src/application.py b/example/general/src/application.py similarity index 100% rename from example/custom/general/src/application.py rename to example/general/src/application.py diff --git a/example/custom/general/src/appsettings.development.json b/example/general/src/appsettings.development.json similarity index 100% rename from example/custom/general/src/appsettings.development.json rename to example/general/src/appsettings.development.json diff --git a/example/custom/general/src/appsettings.edrafts-lapi.json b/example/general/src/appsettings.edrafts-lapi.json similarity index 100% rename from example/custom/general/src/appsettings.edrafts-lapi.json rename to example/general/src/appsettings.edrafts-lapi.json diff --git a/example/custom/general/src/appsettings.edrafts-pc.json b/example/general/src/appsettings.edrafts-pc.json similarity index 100% rename from example/custom/general/src/appsettings.edrafts-pc.json rename to example/general/src/appsettings.edrafts-pc.json diff --git a/example/custom/general/src/appsettings.json b/example/general/src/appsettings.json similarity index 100% rename from example/custom/general/src/appsettings.json rename to example/general/src/appsettings.json diff --git a/example/custom/general/src/db/__init__.py b/example/general/src/db/__init__.py similarity index 100% rename from example/custom/general/src/db/__init__.py rename to example/general/src/db/__init__.py diff --git a/example/custom/general/src/hosted_service.py b/example/general/src/hosted_service.py similarity index 100% rename from example/custom/general/src/hosted_service.py rename to example/general/src/hosted_service.py diff --git a/example/custom/general/src/main.py b/example/general/src/main.py similarity index 100% rename from example/custom/general/src/main.py rename to example/general/src/main.py diff --git a/example/custom/general/src/scoped_service.py b/example/general/src/scoped_service.py similarity index 100% rename from example/custom/general/src/scoped_service.py rename to example/general/src/scoped_service.py diff --git a/example/custom/general/src/startup.py b/example/general/src/startup.py similarity index 88% rename from example/custom/general/src/startup.py rename to example/general/src/startup.py index 18ddfba6..1e6271c2 100644 --- a/example/custom/general/src/startup.py +++ b/example/general/src/startup.py @@ -4,7 +4,8 @@ from cpl.core.configuration import Configuration from cpl.core.environment import Environment from cpl.core.pipes import IPAddressPipe from cpl.dependency import ServiceCollection -from example.custom.general.src.hosted_service import Hosted +from cpl.mail.mail_module import MailModule +from hosted_service import Hosted from scoped_service import ScopedService from test_service import TestService @@ -20,7 +21,7 @@ class Startup(StartupABC): @staticmethod def configure_services(services: ServiceCollection): services.add_logging() - services.add_module(mail) + services.add_module(MailModule) services.add_transient(IPAddressPipe) services.add_singleton(TestService) services.add_scoped(ScopedService) diff --git a/example/custom/general/src/test_extension.py b/example/general/src/test_extension.py similarity index 100% rename from example/custom/general/src/test_extension.py rename to example/general/src/test_extension.py diff --git a/example/custom/general/src/test_service.py b/example/general/src/test_service.py similarity index 100% rename from example/custom/general/src/test_service.py rename to example/general/src/test_service.py diff --git a/example/custom/general/src/test_settings.py b/example/general/src/test_settings.py similarity index 100% rename from example/custom/general/src/test_settings.py rename to example/general/src/test_settings.py diff --git a/example/custom/general/src/test_startup_extension.py b/example/general/src/test_startup_extension.py similarity index 100% rename from example/custom/general/src/test_startup_extension.py rename to example/general/src/test_startup_extension.py diff --git a/example/custom/query/main.py b/example/query/main.py similarity index 100% rename from example/custom/query/main.py rename to example/query/main.py diff --git a/example/custom/translation/LICENSE b/example/translation/LICENSE similarity index 100% rename from example/custom/translation/LICENSE rename to example/translation/LICENSE diff --git a/example/custom/translation/README.md b/example/translation/README.md similarity index 100% rename from example/custom/translation/README.md rename to example/translation/README.md diff --git a/example/custom/translation/cpl-workspace.json b/example/translation/cpl-workspace.json similarity index 100% rename from example/custom/translation/cpl-workspace.json rename to example/translation/cpl-workspace.json diff --git a/example/custom/general/src/__init__.py b/example/translation/src/__init__.py similarity index 100% rename from example/custom/general/src/__init__.py rename to example/translation/src/__init__.py diff --git a/example/custom/translation/src/translation/application.py b/example/translation/src/application.py similarity index 100% rename from example/custom/translation/src/translation/application.py rename to example/translation/src/application.py diff --git a/example/custom/translation/src/translation/appsettings.json b/example/translation/src/appsettings.json similarity index 100% rename from example/custom/translation/src/translation/appsettings.json rename to example/translation/src/appsettings.json diff --git a/example/custom/translation/src/translation/main.py b/example/translation/src/main.py similarity index 100% rename from example/custom/translation/src/translation/main.py rename to example/translation/src/main.py diff --git a/example/custom/translation/src/translation/startup.py b/example/translation/src/startup.py similarity index 100% rename from example/custom/translation/src/translation/startup.py rename to example/translation/src/startup.py diff --git a/example/custom/translation/src/translation/translation.json b/example/translation/src/translation.json similarity index 100% rename from example/custom/translation/src/translation/translation.json rename to example/translation/src/translation.json diff --git a/example/custom/translation/src/translation/translation/de.json b/example/translation/src/translation/de.json similarity index 100% rename from example/custom/translation/src/translation/translation/de.json rename to example/translation/src/translation/de.json diff --git a/example/custom/translation/src/translation/translation/en.json b/example/translation/src/translation/en.json similarity index 100% rename from example/custom/translation/src/translation/translation/en.json rename to example/translation/src/translation/en.json diff --git a/src/cpl-api/cpl/api/__init__.py b/src/cpl-api/cpl/api/__init__.py index 16c78038..fe594c7a 100644 --- a/src/cpl-api/cpl/api/__init__.py +++ b/src/cpl-api/cpl/api/__init__.py @@ -1,36 +1,4 @@ -from cpl.dependency.service_collection import ServiceCollection as _ServiceCollection - from .error import APIError, AlreadyExists, EndpointNotImplemented, Forbidden, NotFound, Unauthorized from .logger import APILogger from .settings import ApiSettings - -def add_api(collection: _ServiceCollection): - try: - from cpl.database import mysql - - collection.add_module(mysql) - except ImportError as e: - from cpl.core.errors import dependency_error - - dependency_error("cpl-database", e) - - try: - from cpl import auth - from cpl.auth import permission - - collection.add_module(auth) - collection.add_module(permission) - except ImportError as e: - from cpl.core.errors import dependency_error - - dependency_error("cpl-auth", e) - - from cpl.api.registry.policy import PolicyRegistry - from cpl.api.registry.route import RouteRegistry - - collection.add_singleton(PolicyRegistry) - collection.add_singleton(RouteRegistry) - - -_ServiceCollection.with_module(add_api, __name__) diff --git a/src/cpl-api/cpl/api/application/web_app.py b/src/cpl-api/cpl/api/application/web_app.py index cc9d8dce..867c20b1 100644 --- a/src/cpl-api/cpl/api/application/web_app.py +++ b/src/cpl-api/cpl/api/application/web_app.py @@ -25,7 +25,10 @@ from cpl.api.registry.route import RouteRegistry from cpl.api.router import Router from cpl.api.settings import ApiSettings from cpl.api.typing import HTTPMethods, PartialMiddleware, PolicyResolver +from cpl.api_module import ApiModule from cpl.application.abc.application_abc import ApplicationABC +from cpl.auth.auth_module import AuthModule +from cpl.auth.permission.permission_module import PermissionsModule from cpl.core.configuration import Configuration from cpl.dependency.inject import inject from cpl.dependency.service_provider import ServiceProvider @@ -35,7 +38,7 @@ PolicyInput = Union[dict[str, PolicyResolver], Policy] class WebApp(ApplicationABC): def __init__(self, services: ServiceProvider): - super().__init__(services, [auth, api]) + super().__init__(services, [AuthModule, PermissionsModule, ApiModule]) self._app: Starlette | None = None self._logger = services.get_service(APILogger) diff --git a/src/cpl-api/cpl/api_module.py b/src/cpl-api/cpl/api_module.py new file mode 100644 index 00000000..2732c69c --- /dev/null +++ b/src/cpl-api/cpl/api_module.py @@ -0,0 +1,26 @@ +from cpl.api.registry.policy import PolicyRegistry +from cpl.api.registry.route import RouteRegistry +from cpl.auth.auth_module import AuthModule +from cpl.auth.permission.permission_module import PermissionsModule +from cpl.core.errors import dependency_error +from cpl.database.database_module import DatabaseModule +from cpl.database.model.server_type import ServerType, ServerTypes +from cpl.database.mysql.mysql_module import MySQLModule +from cpl.dependency.module import Module, TModule + + +class ApiModule(Module): + + @staticmethod + def dependencies() -> list[TModule]: + return [AuthModule, DatabaseModule, PermissionsModule] + + @staticmethod + def register(collection: "ServiceCollection"): + collection.add_module(DatabaseModule) + + collection.add_module(AuthModule) + collection.add_module(PermissionsModule) + + collection.add_singleton(PolicyRegistry) + collection.add_singleton(RouteRegistry) diff --git a/src/cpl-application/cpl/application/application_builder.py b/src/cpl-application/cpl/application/application_builder.py index dc2a9caf..5d7ee4bd 100644 --- a/src/cpl-application/cpl/application/application_builder.py +++ b/src/cpl-application/cpl/application/application_builder.py @@ -49,6 +49,7 @@ class ApplicationBuilder(Generic[TApp]): continue dependency_error( + type(app).__name__, module, ImportError( f"Required module '{module}' for application '{app.__class__.__name__}' is not loaded. Load using 'add_module({module})' method." diff --git a/src/cpl-auth/cpl/auth/__init__.py b/src/cpl-auth/cpl/auth/__init__.py index 5e9d5c87..3fe8834d 100644 --- a/src/cpl-auth/cpl/auth/__init__.py +++ b/src/cpl-auth/cpl/auth/__init__.py @@ -5,10 +5,8 @@ from cpl.application.abc import ApplicationABC as _ApplicationABC from cpl.auth import permission as _permission from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin from cpl.auth.keycloak.keycloak_client import KeycloakClient as _KeycloakClient -from cpl.dependency.service_collection import ServiceCollection as _ServiceCollection -from .logger import AuthLogger from .keycloak_settings import KeycloakSettings -from .permission_seeder import PermissionSeeder +from .logger import AuthLogger def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _ApplicationABC: @@ -19,66 +17,5 @@ def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _Appli return self -def _add_daos(collection: _ServiceCollection): - from .schema._administration.auth_user_dao import AuthUserDao - from .schema._administration.api_key_dao import ApiKeyDao - from .schema._permission.api_key_permission_dao import ApiKeyPermissionDao - from .schema._permission.permission_dao import PermissionDao - from .schema._permission.role_dao import RoleDao - from .schema._permission.role_permission_dao import RolePermissionDao - from .schema._permission.role_user_dao import RoleUserDao - collection.add_singleton(AuthUserDao) - collection.add_singleton(ApiKeyDao) - collection.add_singleton(ApiKeyPermissionDao) - collection.add_singleton(PermissionDao) - collection.add_singleton(RoleDao) - collection.add_singleton(RolePermissionDao) - collection.add_singleton(RoleUserDao) - - -def add_auth(collection: _ServiceCollection): - import os - - try: - from cpl.database.service.migration_service import MigrationService - from cpl.database.model.server_type import ServerType, ServerTypes - - collection.add_singleton(_KeycloakClient) - collection.add_singleton(_KeycloakAdmin) - - _add_daos(collection) - - provider = collection.build() - migration_service: MigrationService = provider.get_service(MigrationService) - if ServerType.server_type == ServerTypes.POSTGRES: - migration_service.with_directory( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/postgres") - ) - elif ServerType.server_type == ServerTypes.MYSQL: - migration_service.with_directory(os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/mysql")) - except ImportError as e: - from cpl.core.console import Console - - Console.error("cpl-database is not installed", str(e)) - - -def add_permission(collection: _ServiceCollection): - from .permission_seeder import PermissionSeeder - from .permission.permissions_registry import PermissionsRegistry - from .permission.permissions import Permissions - - try: - from cpl.database.abc.data_seeder_abc import DataSeederABC - - collection.add_singleton(DataSeederABC, PermissionSeeder) - PermissionsRegistry.with_enum(Permissions) - except ImportError as e: - from cpl.core.console import Console - - Console.error("cpl-database is not installed", str(e)) - - -_ServiceCollection.with_module(add_auth, __name__) -_ServiceCollection.with_module(add_permission, _permission.__name__) _ApplicationABC.extend(_ApplicationABC.with_permissions, _with_permissions) diff --git a/src/cpl-auth/cpl/auth/auth_module.py b/src/cpl-auth/cpl/auth/auth_module.py new file mode 100644 index 00000000..660650ef --- /dev/null +++ b/src/cpl-auth/cpl/auth/auth_module.py @@ -0,0 +1,44 @@ +import os + +from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin +from cpl.auth.keycloak.keycloak_client import KeycloakClient as _KeycloakClient +from cpl.database.database_module import DatabaseModule +from cpl.database.model.server_type import ServerType, ServerTypes +from cpl.database.service.migration_service import MigrationService +from cpl.dependency.module import Module, TModule +from cpl.dependency.service_collection import ServiceCollection +from .schema._administration.api_key_dao import ApiKeyDao +from .schema._administration.auth_user_dao import AuthUserDao +from .schema._permission.api_key_permission_dao import ApiKeyPermissionDao +from .schema._permission.permission_dao import PermissionDao +from .schema._permission.role_dao import RoleDao +from .schema._permission.role_permission_dao import RolePermissionDao +from .schema._permission.role_user_dao import RoleUserDao + + +class AuthModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + return [DatabaseModule] + + @staticmethod + def register(collection: ServiceCollection): + collection.add_singleton(_KeycloakClient) + collection.add_singleton(_KeycloakAdmin) + + collection.add_singleton(AuthUserDao) + collection.add_singleton(ApiKeyDao) + collection.add_singleton(ApiKeyPermissionDao) + collection.add_singleton(PermissionDao) + collection.add_singleton(RoleDao) + collection.add_singleton(RolePermissionDao) + collection.add_singleton(RoleUserDao) + + provider = collection.build() + migration_service: MigrationService = provider.get_service(MigrationService) + if ServerType.server_type == ServerTypes.POSTGRES: + migration_service.with_directory( + os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/postgres") + ) + elif ServerType.server_type == ServerTypes.MYSQL: + migration_service.with_directory(os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/mysql")) diff --git a/src/cpl-auth/cpl/auth/permission/permission_module.py b/src/cpl-auth/cpl/auth/permission/permission_module.py new file mode 100644 index 00000000..6096d2b9 --- /dev/null +++ b/src/cpl-auth/cpl/auth/permission/permission_module.py @@ -0,0 +1,34 @@ +from cpl.auth.permission.permission_seeder import PermissionSeeder +from cpl.auth.permission.permissions import Permissions +from cpl.auth.permission.permissions_registry import PermissionsRegistry +from cpl.database.abc.data_seeder_abc import DataSeederABC +from cpl.database.model.server_type import ServerType, ServerTypes +from cpl.dependency.module import Module, TModule +from cpl.dependency.service_collection import ServiceCollection + + +class PermissionsModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + from cpl.database.database_module import DatabaseModule + + r = [DatabaseModule] + + match ServerType.server_type: + case ServerTypes.POSTGRES: + from cpl.database.postgres.postgres_module import PostgresModule + + r.append(PostgresModule) + case ServerTypes.MYSQL: + from cpl.database.mysql.mysql_module import MySQLModule + + r.append(MySQLModule) + case _: + raise Exception(f"Unsupported database type: {ServerType.server_type}") + + return r + + @staticmethod + def register(collection: ServiceCollection): + collection.add_singleton(DataSeederABC, PermissionSeeder) + PermissionsRegistry.with_enum(Permissions) diff --git a/src/cpl-auth/cpl/auth/permission_seeder.py b/src/cpl-auth/cpl/auth/permission/permission_seeder.py similarity index 100% rename from src/cpl-auth/cpl/auth/permission_seeder.py rename to src/cpl-auth/cpl/auth/permission/permission_seeder.py diff --git a/src/cpl-core/cpl/core/errors.py b/src/cpl-core/cpl/core/errors.py index 493ca1af..e91c349c 100644 --- a/src/cpl-core/cpl/core/errors.py +++ b/src/cpl-core/cpl/core/errors.py @@ -3,8 +3,8 @@ import traceback from cpl.core.console import Console -def dependency_error(package_name: str, e: ImportError) -> None: - Console.error(f"'{package_name}' is required to use this feature. Please install it and try again.") +def dependency_error(src: str, package_name: str, e: ImportError = None) -> None: + Console.error(f"'{package_name}' is required to use feature: {src}. Please install it and try again.") tb = traceback.format_exc() if not tb.startswith("NoneType: None"): Console.write_line("->", tb) @@ -13,3 +13,14 @@ def dependency_error(package_name: str, e: ImportError) -> None: Console.write_line("->", str(e)) exit(1) + +def module_dependency_error(src: str, module: str, e: ImportError = None) -> None: + Console.error(f"'{module}' is required to use feature: {src}. Please initialize it with `add_module({module})`.") + tb = traceback.format_exc() + if not tb.startswith("NoneType: None"): + Console.write_line("->", tb) + + elif e is not None: + Console.write_line("->", str(e)) + + exit(1) \ No newline at end of file diff --git a/src/cpl-database/cpl/database/__init__.py b/src/cpl-database/cpl/database/__init__.py index 184b398e..280bd06a 100644 --- a/src/cpl-database/cpl/database/__init__.py +++ b/src/cpl-database/cpl/database/__init__.py @@ -1,8 +1,6 @@ import os -from typing import Type from cpl.application.abc import ApplicationABC as _ApplicationABC -from cpl.dependency import ServiceCollection as _ServiceCollection from . import mysql as _mysql from . import postgres as _postgres from .table_manager import TableManager @@ -32,43 +30,5 @@ def _with_seeders(self: _ApplicationABC) -> _ApplicationABC: return self -def _add(collection: _ServiceCollection, db_context: Type, default_port: int, server_type: str): - from cpl.core.console import Console - from cpl.core.configuration import Configuration - from cpl.database.abc.db_context_abc import DBContextABC - from cpl.database.model.server_type import ServerTypes, ServerType - from cpl.database.model.database_settings import DatabaseSettings - from cpl.database.service.migration_service import MigrationService - from cpl.database.service.seeder_service import SeederService - from cpl.database.schema.executed_migration_dao import ExecutedMigrationDao - - try: - ServerType.set_server_type(ServerTypes(server_type)) - Configuration.set("DB_DEFAULT_PORT", default_port) - - collection.add_singleton(DBContextABC, db_context) - collection.add_singleton(ExecutedMigrationDao) - collection.add_singleton(MigrationService) - collection.add_singleton(SeederService) - except ImportError as e: - Console.error("cpl-database is not installed", str(e)) - - -def add_mysql(collection: _ServiceCollection): - from cpl.database.mysql.db_context import DBContext - from cpl.database.model import ServerTypes - - _add(collection, DBContext, 3306, ServerTypes.MYSQL.value) - - -def add_postgres(collection: _ServiceCollection): - from cpl.database.mysql.db_context import DBContext - from cpl.database.model import ServerTypes - - _add(collection, DBContext, 5432, ServerTypes.POSTGRES.value) - - -_ServiceCollection.with_module(add_mysql, _mysql.__name__) -_ServiceCollection.with_module(add_postgres, _postgres.__name__) _ApplicationABC.extend(_ApplicationABC.with_migrations, _with_migrations) _ApplicationABC.extend(_ApplicationABC.with_seeders, _with_seeders) diff --git a/src/cpl-database/cpl/database/database_module.py b/src/cpl-database/cpl/database/database_module.py new file mode 100644 index 00000000..f3eed8a6 --- /dev/null +++ b/src/cpl-database/cpl/database/database_module.py @@ -0,0 +1,22 @@ +from cpl.core.errors import module_dependency_error +from cpl.database.model.server_type import ServerType +from cpl.database.schema.executed_migration_dao import ExecutedMigrationDao +from cpl.database.service.migration_service import MigrationService +from cpl.database.service.seeder_service import SeederService +from cpl.dependency.module import Module, TModule +from cpl.dependency.service_collection import ServiceCollection + + +class DatabaseModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + if not ServerType.has_server_type: + module_dependency_error(__name__, "MySQLModule or PostgresModule") + + return [] + + @staticmethod + def register(collection: ServiceCollection): + collection.add_singleton(ExecutedMigrationDao) + collection.add_singleton(MigrationService) + collection.add_singleton(SeederService) diff --git a/src/cpl-database/cpl/database/model/server_type.py b/src/cpl-database/cpl/database/model/server_type.py index 54dfa123..396ddae2 100644 --- a/src/cpl-database/cpl/database/model/server_type.py +++ b/src/cpl-database/cpl/database/model/server_type.py @@ -15,6 +15,11 @@ class ServerType: assert isinstance(server_type, ServerTypes), f"Expected ServerType but got {type(server_type)}" cls._server_type = server_type + @classmethod + @property + def has_server_type(cls) -> bool: + return cls._server_type is not None + @classmethod @property def server_type(cls) -> ServerTypes: diff --git a/src/cpl-database/cpl/database/mysql/mysql_module.py b/src/cpl-database/cpl/database/mysql/mysql_module.py new file mode 100644 index 00000000..faf80d31 --- /dev/null +++ b/src/cpl-database/cpl/database/mysql/mysql_module.py @@ -0,0 +1,19 @@ +from cpl.core.configuration.configuration import Configuration +from cpl.database.abc.db_context_abc import DBContextABC +from cpl.database.model.server_type import ServerTypes, ServerType +from cpl.database.mysql.db_context import DBContext +from cpl.dependency.module import Module, TModule +from cpl.dependency.service_collection import ServiceCollection + + +class MySQLModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + return [] + + @staticmethod + def register(collection: ServiceCollection): + ServerType.set_server_type(ServerTypes(ServerTypes.MYSQL.value)) + Configuration.set("DB_DEFAULT_PORT", 3306) + + collection.add_singleton(DBContextABC, DBContext) diff --git a/src/cpl-database/cpl/database/postgres/postgres_module.py b/src/cpl-database/cpl/database/postgres/postgres_module.py new file mode 100644 index 00000000..38e6d12e --- /dev/null +++ b/src/cpl-database/cpl/database/postgres/postgres_module.py @@ -0,0 +1,20 @@ +from cpl.core.configuration.configuration import Configuration +from cpl.database.abc.db_context_abc import DBContextABC +from cpl.database.database_module import DatabaseModule +from cpl.database.model.server_type import ServerTypes, ServerType +from cpl.database.postgres.db_context import DBContext +from cpl.dependency.module import Module, TModule +from cpl.dependency.service_collection import ServiceCollection + + +class PostgresModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + return [DatabaseModule] + + @staticmethod + def register(collection: ServiceCollection): + ServerType.set_server_type(ServerTypes(ServerTypes.POSTGRES.value)) + Configuration.set("DB_DEFAULT_PORT", 5432) + + collection.add_singleton(DBContextABC, DBContext) diff --git a/src/cpl-dependency/cpl/dependency/module.py b/src/cpl-dependency/cpl/dependency/module.py new file mode 100644 index 00000000..0fe9f0c3 --- /dev/null +++ b/src/cpl-dependency/cpl/dependency/module.py @@ -0,0 +1,14 @@ +from abc import abstractmethod, ABC +from typing import Type + +TModule = Type["Module"] + +class Module(ABC): + + @staticmethod + @abstractmethod + def dependencies() -> list[TModule]: ... + + @staticmethod + @abstractmethod + def register(collection: "ServiceCollection"): ... diff --git a/src/cpl-dependency/cpl/dependency/service_collection.py b/src/cpl-dependency/cpl/dependency/service_collection.py index 0ab9e17b..c8ae7e75 100644 --- a/src/cpl-dependency/cpl/dependency/service_collection.py +++ b/src/cpl-dependency/cpl/dependency/service_collection.py @@ -1,9 +1,11 @@ +from inspect import isclass from typing import Union, Type, Callable, Self from cpl.core.log.logger_abc import LoggerABC from cpl.core.typing import T, Service from cpl.core.utils.cache import Cache from cpl.dependency.hosted.startup_task import StartupTask +from cpl.dependency.module import Module from cpl.dependency.service_descriptor import ServiceDescriptor from cpl.dependency.service_lifetime import ServiceLifetimeEnum from cpl.dependency.service_provider import ServiceProvider @@ -16,7 +18,7 @@ class ServiceCollection: @classmethod def with_module(cls, func: Callable, name: str = None) -> type[Self]: - cls._modules[func.__name__ if name is None else name] = func + # cls._modules[func.__name__ if name is None else name] = func return cls def __init__(self): @@ -74,16 +76,23 @@ class ServiceCollection: sp = ServiceProvider(self._service_descriptors) return sp - def add_module(self, module: str | object) -> Self: - if not isinstance(module, str): - module = module.__name__ + def add_module(self, module: Type[Module]) -> Self: + assert isclass(module), "Module must be a Module" + assert issubclass(module, Module), f"Module must be subclass of {Module.__name__}" - if module not in self._modules: + name = module.__name__ + if module in self._modules: raise ValueError(f"Module {module} not found") - self._modules[module](self) - if module not in self._loaded_modules: - self._loaded_modules.add(module) + for dependency in module.dependencies(): + if dependency.__name__ not in self._loaded_modules: + self.add_module(dependency) + + module().register(self) + + if name not in self._loaded_modules: + self._loaded_modules.add(name) + return self def add_logging(self) -> Self: diff --git a/src/cpl-mail/cpl/mail/mail_module.py b/src/cpl-mail/cpl/mail/mail_module.py new file mode 100644 index 00000000..91d3925d --- /dev/null +++ b/src/cpl-mail/cpl/mail/mail_module.py @@ -0,0 +1,15 @@ +from cpl.dependency import ServiceCollection +from cpl.dependency.module import Module, TModule +from cpl.mail.email_client import EMailClient +from cpl.mail.abc.email_client_abc import EMailClientABC + + +class MailModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + return [] + + + @staticmethod + def register(collection: ServiceCollection): + collection.add_singleton(EMailClientABC, EMailClient) \ No newline at end of file diff --git a/src/cpl-translation/cpl/translation/translate_pipe.py b/src/cpl-translation/cpl/translation/translate_pipe.py index 20fad862..b511a341 100644 --- a/src/cpl-translation/cpl/translation/translate_pipe.py +++ b/src/cpl-translation/cpl/translation/translate_pipe.py @@ -1,15 +1,20 @@ from cpl.core.console import Console from cpl.core.pipes.pipe_abc import PipeABC +from cpl.core.typing import T +from cpl.dependency import get_provider from cpl.translation.translation_service_abc import TranslationServiceABC class TranslatePipe(PipeABC): - def __init__(self, translation: TranslationServiceABC): - self._translation = translation - - def transform(self, value: any, *args): + @staticmethod + def to_str(value: T, *args) -> str: try: - return self._translation.translate(value) + translations = get_provider().get_service(TranslationServiceABC) + return translations.translate(value) except KeyError: Console.error(f"Translation {value} not found") return "" + + @staticmethod + def from_str(value: str, *args) -> T: + pass diff --git a/src/cpl-translation/cpl/translation/translation_module.py b/src/cpl-translation/cpl/translation/translation_module.py new file mode 100644 index 00000000..b580e651 --- /dev/null +++ b/src/cpl-translation/cpl/translation/translation_module.py @@ -0,0 +1,14 @@ +from cpl.dependency import ServiceCollection +from cpl.dependency.module import Module, TModule +from cpl.translation.translation_service import TranslationService +from cpl.translation.translation_service_abc import TranslationServiceABC + + +class TranslationModule(Module): + @staticmethod + def dependencies() -> list[TModule]: + return [] + + @staticmethod + def register(collection: ServiceCollection): + collection.add_singleton(TranslationServiceABC, TranslationService)