WIP: dev into master #184

Draft
edraft wants to merge 121 commits from dev into master
97 changed files with 266 additions and 266 deletions
Showing only changes of commit 55a727c482 - Show all commits

View File

@@ -2,6 +2,7 @@ from starlette.responses import JSONResponse
from cpl import api from cpl import api
from cpl.api.application.web_app import WebApp from cpl.api.application.web_app import WebApp
from cpl.api_module import ApiModule
from cpl.application import ApplicationBuilder from cpl.application import ApplicationBuilder
from cpl.auth.permission.permissions import Permissions from cpl.auth.permission.permissions import Permissions
from cpl.auth.schema import AuthUser, Role 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.console import Console
from cpl.core.environment import Environment from cpl.core.environment import Environment
from cpl.core.utils.cache import Cache from cpl.core.utils.cache import Cache
from cpl.database.mysql.mysql_module import MySQLModule
from scoped_service import ScopedService from scoped_service import ScopedService
from service import PingService from service import PingService
@@ -23,7 +25,8 @@ def main():
# builder.services.add_logging() # builder.services.add_logging()
builder.services.add_structured_logging() builder.services.add_structured_logging()
builder.services.add_transient(PingService) 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) builder.services.add_scoped(ScopedService)

View File

@@ -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": {}
}
}

View File

@@ -1,9 +0,0 @@
{
"Workspace": {
"DefaultProject": "di",
"Projects": {
"di": "src/di/di.json"
},
"Scripts": {}
}
}

View File

@@ -1,8 +0,0 @@
{
"Workspace": {
"DefaultProject": "general",
"Projects": {
"general": "src/general/general.json"
}
}
}

View File

@@ -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": []
}
}

View File

@@ -1,3 +0,0 @@
class Custom:
def __init__(self):
print("hello")

View File

@@ -4,7 +4,8 @@ from cpl.core.configuration import Configuration
from cpl.core.environment import Environment from cpl.core.environment import Environment
from cpl.core.pipes import IPAddressPipe from cpl.core.pipes import IPAddressPipe
from cpl.dependency import ServiceCollection 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 scoped_service import ScopedService
from test_service import TestService from test_service import TestService
@@ -20,7 +21,7 @@ class Startup(StartupABC):
@staticmethod @staticmethod
def configure_services(services: ServiceCollection): def configure_services(services: ServiceCollection):
services.add_logging() services.add_logging()
services.add_module(mail) services.add_module(MailModule)
services.add_transient(IPAddressPipe) services.add_transient(IPAddressPipe)
services.add_singleton(TestService) services.add_singleton(TestService)
services.add_scoped(ScopedService) services.add_scoped(ScopedService)

View File

@@ -1,36 +1,4 @@
from cpl.dependency.service_collection import ServiceCollection as _ServiceCollection
from .error import APIError, AlreadyExists, EndpointNotImplemented, Forbidden, NotFound, Unauthorized from .error import APIError, AlreadyExists, EndpointNotImplemented, Forbidden, NotFound, Unauthorized
from .logger import APILogger from .logger import APILogger
from .settings import ApiSettings 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__)

View File

@@ -25,7 +25,10 @@ from cpl.api.registry.route import RouteRegistry
from cpl.api.router import Router from cpl.api.router import Router
from cpl.api.settings import ApiSettings from cpl.api.settings import ApiSettings
from cpl.api.typing import HTTPMethods, PartialMiddleware, PolicyResolver from cpl.api.typing import HTTPMethods, PartialMiddleware, PolicyResolver
from cpl.api_module import ApiModule
from cpl.application.abc.application_abc import ApplicationABC 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.core.configuration import Configuration
from cpl.dependency.inject import inject from cpl.dependency.inject import inject
from cpl.dependency.service_provider import ServiceProvider from cpl.dependency.service_provider import ServiceProvider
@@ -35,7 +38,7 @@ PolicyInput = Union[dict[str, PolicyResolver], Policy]
class WebApp(ApplicationABC): class WebApp(ApplicationABC):
def __init__(self, services: ServiceProvider): def __init__(self, services: ServiceProvider):
super().__init__(services, [auth, api]) super().__init__(services, [AuthModule, PermissionsModule, ApiModule])
self._app: Starlette | None = None self._app: Starlette | None = None
self._logger = services.get_service(APILogger) self._logger = services.get_service(APILogger)

View File

@@ -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)

View File

@@ -49,6 +49,7 @@ class ApplicationBuilder(Generic[TApp]):
continue continue
dependency_error( dependency_error(
type(app).__name__,
module, module,
ImportError( ImportError(
f"Required module '{module}' for application '{app.__class__.__name__}' is not loaded. Load using 'add_module({module})' method." f"Required module '{module}' for application '{app.__class__.__name__}' is not loaded. Load using 'add_module({module})' method."

View File

@@ -5,10 +5,8 @@ from cpl.application.abc import ApplicationABC as _ApplicationABC
from cpl.auth import permission as _permission from cpl.auth import permission as _permission
from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin
from cpl.auth.keycloak.keycloak_client import KeycloakClient as _KeycloakClient 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 .keycloak_settings import KeycloakSettings
from .permission_seeder import PermissionSeeder from .logger import AuthLogger
def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _ApplicationABC: def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _ApplicationABC:
@@ -19,66 +17,5 @@ def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _Appli
return self 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) _ApplicationABC.extend(_ApplicationABC.with_permissions, _with_permissions)

View File

@@ -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"))

View File

@@ -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)

View File

@@ -3,8 +3,19 @@ import traceback
from cpl.core.console import Console from cpl.core.console import Console
def dependency_error(package_name: str, e: ImportError) -> None: def dependency_error(src: str, package_name: str, e: ImportError = None) -> None:
Console.error(f"'{package_name}' is required to use this feature. Please install it and try again.") 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)
elif e is not 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() tb = traceback.format_exc()
if not tb.startswith("NoneType: None"): if not tb.startswith("NoneType: None"):
Console.write_line("->", tb) Console.write_line("->", tb)

View File

@@ -1,8 +1,6 @@
import os import os
from typing import Type
from cpl.application.abc import ApplicationABC as _ApplicationABC from cpl.application.abc import ApplicationABC as _ApplicationABC
from cpl.dependency import ServiceCollection as _ServiceCollection
from . import mysql as _mysql from . import mysql as _mysql
from . import postgres as _postgres from . import postgres as _postgres
from .table_manager import TableManager from .table_manager import TableManager
@@ -32,43 +30,5 @@ def _with_seeders(self: _ApplicationABC) -> _ApplicationABC:
return self 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_migrations, _with_migrations)
_ApplicationABC.extend(_ApplicationABC.with_seeders, _with_seeders) _ApplicationABC.extend(_ApplicationABC.with_seeders, _with_seeders)

View File

@@ -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)

View File

@@ -15,6 +15,11 @@ class ServerType:
assert isinstance(server_type, ServerTypes), f"Expected ServerType but got {type(server_type)}" assert isinstance(server_type, ServerTypes), f"Expected ServerType but got {type(server_type)}"
cls._server_type = server_type cls._server_type = server_type
@classmethod
@property
def has_server_type(cls) -> bool:
return cls._server_type is not None
@classmethod @classmethod
@property @property
def server_type(cls) -> ServerTypes: def server_type(cls) -> ServerTypes:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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"): ...

View File

@@ -1,9 +1,11 @@
from inspect import isclass
from typing import Union, Type, Callable, Self from typing import Union, Type, Callable, Self
from cpl.core.log.logger_abc import LoggerABC from cpl.core.log.logger_abc import LoggerABC
from cpl.core.typing import T, Service from cpl.core.typing import T, Service
from cpl.core.utils.cache import Cache from cpl.core.utils.cache import Cache
from cpl.dependency.hosted.startup_task import StartupTask 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_descriptor import ServiceDescriptor
from cpl.dependency.service_lifetime import ServiceLifetimeEnum from cpl.dependency.service_lifetime import ServiceLifetimeEnum
from cpl.dependency.service_provider import ServiceProvider from cpl.dependency.service_provider import ServiceProvider
@@ -16,7 +18,7 @@ class ServiceCollection:
@classmethod @classmethod
def with_module(cls, func: Callable, name: str = None) -> type[Self]: 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 return cls
def __init__(self): def __init__(self):
@@ -74,16 +76,23 @@ class ServiceCollection:
sp = ServiceProvider(self._service_descriptors) sp = ServiceProvider(self._service_descriptors)
return sp return sp
def add_module(self, module: str | object) -> Self: def add_module(self, module: Type[Module]) -> Self:
if not isinstance(module, str): assert isclass(module), "Module must be a Module"
module = module.__name__ 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") raise ValueError(f"Module {module} not found")
self._modules[module](self) for dependency in module.dependencies():
if module not in self._loaded_modules: if dependency.__name__ not in self._loaded_modules:
self._loaded_modules.add(module) self.add_module(dependency)
module().register(self)
if name not in self._loaded_modules:
self._loaded_modules.add(name)
return self return self
def add_logging(self) -> Self: def add_logging(self) -> Self:

View File

@@ -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)

View File

@@ -1,15 +1,20 @@
from cpl.core.console import Console from cpl.core.console import Console
from cpl.core.pipes.pipe_abc import PipeABC 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 from cpl.translation.translation_service_abc import TranslationServiceABC
class TranslatePipe(PipeABC): class TranslatePipe(PipeABC):
def __init__(self, translation: TranslationServiceABC): @staticmethod
self._translation = translation def to_str(value: T, *args) -> str:
def transform(self, value: any, *args):
try: try:
return self._translation.translate(value) translations = get_provider().get_service(TranslationServiceABC)
return translations.translate(value)
except KeyError: except KeyError:
Console.error(f"Translation {value} not found") Console.error(f"Translation {value} not found")
return "" return ""
@staticmethod
def from_str(value: str, *args) -> T:
pass

View File

@@ -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)