Compare commits

..

10 Commits

Author SHA1 Message Date
5edabbf8c1 Removed docs from sources
All checks were successful
Build on push / prepare (push) Successful in 10s
Build on push / core (push) Successful in 17s
Build on push / query (push) Successful in 18s
Build on push / translation (push) Successful in 15s
Build on push / mail (push) Successful in 16s
2025-09-15 23:08:17 +02:00
62b6435470 Improved logging closes #180
All checks were successful
Build on push / prepare (push) Successful in 9s
Build on push / query (push) Successful in 17s
Build on push / core (push) Successful in 18s
Build on push / mail (push) Successful in 17s
Build on push / translation (push) Successful in 18s
2025-09-15 23:06:38 +02:00
d9d7802f33 Fixed translation build
All checks were successful
Build on push / prepare (push) Successful in 9s
Build on push / query (push) Successful in 19s
Build on push / core (push) Successful in 20s
Build on push / mail (push) Successful in 15s
Build on push / translation (push) Successful in 18s
2025-09-15 21:08:40 +02:00
25b4ca0696 Added cpl-mail
Some checks failed
Build on push / prepare (push) Successful in 9s
Build on push / core (push) Successful in 18s
Build on push / query (push) Successful in 25s
Build on push / translation (push) Failing after 8s
Build on push / mail (push) Successful in 14s
2025-09-15 20:56:07 +02:00
3b120370b8 Added cpl-mail
All checks were successful
Build on push / prepare (push) Successful in 9s
Build on push / translation (push) Successful in 20s
Build on push / mail (push) Successful in 21s
Build on push / query (push) Successful in 21s
Build on push / core (push) Successful in 21s
2025-09-15 18:38:34 +02:00
aac038ef63 Added cpl-mail
Some checks failed
Build on push / core (push) Failing after 9s
Build on push / mail (push) Has been cancelled
Build on push / translation (push) Has been cancelled
Build on push / prepare (push) Has been cancelled
Build on push / query (push) Has been cancelled
2025-09-15 18:35:36 +02:00
784632a0b4 Updated ci
Some checks failed
Build on push / core (push) Has been cancelled
Build on push / query (push) Has been cancelled
Build on push / translation (push) Has been cancelled
Build on push / prepare (push) Has been cancelled
2025-09-15 18:17:23 +02:00
4719c32457 Updated ci
Some checks failed
Build on push / prepare (push) Successful in 9s
Build on push / query (push) Failing after 18s
Build on push / core (push) Successful in 15s
2025-09-15 16:55:57 +02:00
516fa3fb7e Updated ci
Some checks failed
Build on push / prepare (push) Successful in 8s
Build on push / query (push) Successful in 18s
Build on push / core (push) Failing after 18s
2025-09-15 15:28:09 +02:00
2d2bb86720 First update towards cpl2
Some checks failed
Build on push / prepare (push) Failing after 6s
Build on push / build (push) Has been skipped
2025-09-15 15:02:47 +02:00
489 changed files with 1935 additions and 10731 deletions

View File

@@ -0,0 +1,41 @@
name: Build on push
run-name: Build on push
on:
push:
branches:
- dev
jobs:
prepare:
uses: ./.gitea/workflows/prepare.yaml
with:
version_suffix: 'dev'
secrets: inherit
core:
uses: ./.gitea/workflows/package.yaml
needs: [prepare]
with:
working_directory: src/cpl-core
secrets: inherit
query:
uses: ./.gitea/workflows/package.yaml
needs: [prepare]
with:
working_directory: src/cpl-query
secrets: inherit
translation:
uses: ./.gitea/workflows/package.yaml
needs: [ prepare, core ]
with:
working_directory: src/cpl-translation
secrets: inherit
mail:
uses: ./.gitea/workflows/package.yaml
needs: [ prepare, core ]
with:
working_directory: src/cpl-mail
secrets: inherit

View File

@@ -0,0 +1,39 @@
name: Build on push
run-name: Build on push
on:
push:
branches:
- master
jobs:
prepare:
uses: ./.gitea/workflows/prepare.yaml
secrets: inherit
core:
uses: ./.gitea/workflows/package.yaml
needs: [prepare]
with:
working_directory: src/cpl-core
secrets: inherit
query:
uses: ./.gitea/workflows/package.yaml
needs: [prepare]
with:
working_directory: src/cpl-query
secrets: inherit
translation:
uses: ./.gitea/workflows/package.yaml
needs: [ prepare, core ]
with:
working_directory: src/cpl-translation
secrets: inherit
mail:
uses: ./.gitea/workflows/package.yaml
needs: [ prepare, core ]
with:
working_directory: src/cpl-mail
secrets: inherit

View File

@@ -0,0 +1,65 @@
name: Build Package
run-name: Build Python Package
on:
workflow_call:
inputs:
version_suffix:
description: 'Suffix for version (z.B. "dev", "alpha", "beta")'
required: false
type: string
working_directory:
required: true
type: string
jobs:
build:
runs-on: [ runner ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
defaults:
run:
working-directory: ${{ inputs.working_directory }}
steps:
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Download build version artifact
uses: actions/download-artifact@v3
with:
name: version
- name: Set version
run: |
sed -i -E "s/^version = \".*\"/version = \"$(cat /workspace/sh-edraft.de/cpl/version.txt)\"/" pyproject.toml
echo "Set version to $(cat /workspace/sh-edraft.de/cpl/version.txt)"
cat pyproject.toml
- name: Set pip conf
run: |
cat > .pip.conf <<'EOF'
[global]
extra-index-url = https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/
EOF
- name: Install Dependencies
run: |
export PIP_CONFIG_FILE=".pip.conf"
pip install build
- name: Build Package
run: |
python -m build --outdir dist
- name: Login to registry git.sh-edraft.de
uses: https://github.com/docker/login-action@v1
with:
registry: git.sh-edraft.de
username: ${{ secrets.CI_USERNAME }}
password: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Push image
run: |
pip install twine
python -m twine upload --repository-url https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi -u ${{ secrets.CI_USERNAME }} -p ${{ secrets.CI_ACCESS_TOKEN }} ./dist/*

View File

@@ -0,0 +1,54 @@
name: Prepare Build
run-name: Prepare Build Version
on:
workflow_call:
inputs:
version_suffix:
description: 'Suffix for version (z.B. "dev", "alpha", "beta")'
required: false
type: string
jobs:
prepare:
runs-on: [ runner ]
container: git.sh-edraft.de/sh-edraft.de/act-runner:latest
steps:
- name: Clone Repository
uses: https://github.com/actions/checkout@v3
with:
token: ${{ secrets.CI_ACCESS_TOKEN }}
- name: Get Date and Build Number
run: |
git fetch --tags
git tag
DATE=$(date +'%Y.%m.%d')
TAG_COUNT=$(git tag -l "${DATE}.*" | wc -l)
BUILD_NUMBER=$(($TAG_COUNT + 1))
VERSION_SUFFIX=${{ inputs.version_suffix }}
if [ -n "$VERSION_SUFFIX" ] && [ "$VERSION_SUFFIX" = "dev" ]; then
BUILD_VERSION="${DATE}.dev${BUILD_NUMBER}"
elif [ -n "$VERSION_SUFFIX" ]; then
BUILD_VERSION="${DATE}.${BUILD_NUMBER}${VERSION_SUFFIX}"
else
BUILD_VERSION="${DATE}.${BUILD_NUMBER}"
fi
echo "$BUILD_VERSION" > version.txt
echo "VERSION $BUILD_VERSION"
- name: Create Git Tag for Build
run: |
git config user.name "ci"
git config user.email "dev@sh-edraft.de"
echo "tag $(cat version.txt)"
git tag $(cat version.txt)
git push origin --tags
- name: Upload build version artifact
uses: actions/upload-artifact@v3
with:
name: version
path: version.txt

2
.pip.conf Normal file
View File

@@ -0,0 +1,2 @@
[global]
extra-index-url = https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/

View File

@@ -1,151 +0,0 @@
{
"WorkspaceSettings": {
"DefaultProject": "cpl-core",
"Projects": {
"cpl-cli": "src/cpl_cli/cpl-cli.json",
"cpl-core": "src/cpl_core/cpl-core.json",
"cpl-discord": "src/cpl_discord/cpl-discord.json",
"cpl-query": "src/cpl_query/cpl-query.json",
"cpl-translation": "src/cpl_translation/cpl-translation.json",
"set-version": "tools/set_version/set-version.json",
"set-pip-urls": "tools/set_pip_urls/set-pip-urls.json",
"unittests": "unittests/unittests/unittests.json",
"unittests_cli": "unittests/unittests_cli/unittests_cli.json",
"unittests_core": "unittests/unittests_core/unittests_core.json",
"unittests_query": "unittests/unittests_query/unittests_query.json",
"unittests_shared": "unittests/unittests_shared/unittests_shared.json",
"unittests_translation": "unittests/unittests_translation/unittests_translation.json"
},
"Scripts": {
"hello-world": "echo 'Hello World'",
"format": "echo 'Formatting:'; black ./",
"sv": "cpl set-version",
"set-version": "cpl run set-version --dev $ARGS; echo '';",
"spu": "cpl set-pip-urls",
"set-pip-urls": "cpl run set-pip-urls --dev $ARGS; echo '';",
"docs-build": "cpl format; echo 'Build Documentation'; cpl db-core; cpl db-discord; cpl db-query; cpl db-translation; cd docs/; make clean; make html;",
"db-core": "cd docs/; sphinx-apidoc -o source/ ../src/cpl_core; cd ../",
"db-discord": "cd docs/; sphinx-apidoc -o source/ ../src/cpl_discord; cd ../",
"db-query": "cd docs/; sphinx-apidoc -o source/ ../src/cpl_query; cd ../",
"db-translation": "cd docs/; sphinx-apidoc -o source/ ../src/cpl_translation; cd ../",
"db": "cpl docs-build",
"docs-open": "xdg-open $PWD/docs/build/html/index.html &",
"do": "cpl docs-open",
"test": "cpl run unittests",
"pre-build-all": "cpl sv $ARGS; cpl spu $ARGS;",
"build-all": "cpl build-cli; cpl build-core; cpl build-discord; cpl build-query; cpl build-translation; cpl build-set-pip-urls; cpl build-set-version",
"ba": "cpl build-all $ARGS",
"build-cli": "echo 'Build cpl-cli'; cd ./src/cpl_cli; cpl build; cd ../../;",
"build-core": "echo 'Build cpl-core'; cd ./src/cpl_core; cpl build; cd ../../;",
"build-discord": "echo 'Build cpl-discord'; cd ./src/cpl_discord; cpl build; cd ../../;",
"build-query": "echo 'Build cpl-query'; cd ./src/cpl_query; cpl build; cd ../../;",
"build-translation": "echo 'Build cpl-translation'; cd ./src/cpl_translation; cpl build; cd ../../;",
"build-set-pip-urls": "echo 'Build set-pip-urls'; cd ./tools/set_pip_urls; cpl build; cd ../../;",
"build-set-version": "echo 'Build set-version'; cd ./tools/set_version; cpl build; cd ../../;",
"pre-publish-all": "cpl sv $ARGS; cpl spu $ARGS;",
"publish-all": "cpl publish-cli; cpl publish-core; cpl publish-discord; cpl publish-query; cpl publish-translation;",
"pa": "cpl publish-all $ARGS",
"publish-cli": "echo 'Publish cpl-cli'; cd ./src/cpl_cli; cpl publish; cd ../../;",
"publish-core": "echo 'Publish cpl-core'; cd ./src/cpl_core; cpl publish; cd ../../;",
"publish-discord": "echo 'Publish cpl-discord'; cd ./src/cpl_discord; cpl publish; cd ../../;",
"publish-query": "echo 'Publish cpl-query'; cd ./src/cpl_query; cpl publish; cd ../../;",
"publish-translation": "echo 'Publish cpl-translation'; cd ./src/cpl_translation; cpl publish; cd ../../;",
"upload-prod-cli": "echo 'PROD Upload cpl-cli'; cpl upl-prod-cli;",
"upl-prod-cli": "twine upload -r pip.sh-edraft.de dist/cpl-cli/publish/setup/*",
"upload-prod-core": "echo 'PROD Upload cpl-core'; cpl upl-prod-core;",
"upl-prod-core": "twine upload -r pip.sh-edraft.de dist/cpl-core/publish/setup/*",
"upload-prod-discord": "echo 'PROD Upload cpl-discord'; cpl upl-prod-discord;",
"upl-prod-discord": "twine upload -r pip.sh-edraft.de dist/cpl-discord/publish/setup/*",
"upload-prod-query": "echo 'PROD Upload cpl-query'; cpl upl-prod-query;",
"upl-prod-query": "twine upload -r pip.sh-edraft.de dist/cpl-query/publish/setup/*",
"upload-prod-translation": "echo 'PROD Upload cpl-translation'; cpl upl-prod-translation;",
"upl-prod-translation": "twine upload -r pip.sh-edraft.de dist/cpl-translation/publish/setup/*",
"upload-exp-cli": "echo 'EXP Upload cpl-cli'; cpl upl-exp-cli;",
"upl-exp-cli": "twine upload -r pip-exp.sh-edraft.de dist/cpl-cli/publish/setup/*",
"upload-exp-core": "echo 'EXP Upload cpl-core'; cpl upl-exp-core;",
"upl-exp-core": "twine upload -r pip-exp.sh-edraft.de dist/cpl-core/publish/setup/*",
"upload-exp-discord": "echo 'EXP Upload cpl-discord'; cpl upl-exp-discord;",
"upl-exp-discord": "twine upload -r pip-exp.sh-edraft.de dist/cpl-discord/publish/setup/*",
"upload-exp-query": "echo 'EXP Upload cpl-query'; cpl upl-exp-query;",
"upl-exp-query": "twine upload -r pip-exp.sh-edraft.de dist/cpl-query/publish/setup/*",
"upload-exp-translation": "echo 'EXP Upload cpl-translation'; cpl upl-exp-translation;",
"upl-exp-translation": "twine upload -r pip-exp.sh-edraft.de dist/cpl-translation/publish/setup/*",
"upload-dev-cli": "echo 'DEV Upload cpl-cli'; cpl upl-dev-cli;",
"upl-dev-cli": "twine upload -r pip-dev.sh-edraft.de dist/cpl-cli/publish/setup/*",
"upload-dev-core": "echo 'DEV Upload cpl-core'; cpl upl-dev-core;",
"upl-dev-core": "twine upload -r pip-dev.sh-edraft.de dist/cpl-core/publish/setup/*",
"upload-dev-discord": "echo 'DEV Upload cpl-discord'; cpl upl-dev-discord;",
"upl-dev-discord": "twine upload -r pip-dev.sh-edraft.de dist/cpl-discord/publish/setup/*",
"upload-dev-query": "echo 'DEV Upload cpl-query'; cpl upl-dev-query;",
"upl-dev-query": "twine upload -r pip-dev.sh-edraft.de dist/cpl-query/publish/setup/*",
"upload-dev-translation": "echo 'DEV Upload cpl-translation'; cpl upl-dev-translation;",
"upl-dev-translation": "twine upload -r pip-dev.sh-edraft.de dist/cpl-translation/publish/setup/*",
"pre-deploy-prod": "cpl sv $ARGS; cpl spu --environment=production;",
"deploy-prod": "cpl deploy-prod-cli; cpl deploy-prod-core; cpl deploy-prod-discord; cpl deploy-prod-query; cpl deploy-prod-translation;",
"dp": "cpl deploy-prod $ARGS",
"deploy-prod-cli": "cpl publish-cli; cpl upload-prod-cli",
"deploy-prod-core": "cpl publish-core; cpl upload-prod-core",
"deploy-prod-query": "cpl publish-query; cpl upload-prod-query",
"deploy-prod-discord": "cpl publish-discord; cpl upload-prod-discord",
"deploy-prod-translation": "cpl publish-translation; cpl upload-prod-translation",
"pre-deploy-exp": "cpl sv $ARGS; cpl spu --environment=staging;",
"deploy-exp": "cpl deploy-exp-cli; cpl deploy-exp-core; cpl deploy-exp-discord; cpl deploy-exp-query; cpl deploy-exp-translation;",
"de": "cpl deploy-exp $ARGS",
"deploy-exp-cli": "cpl publish-cli; cpl upload-exp-cli",
"deploy-exp-core": "cpl publish-core; cpl upload-exp-core",
"deploy-exp-discord": "cpl publish-discord; cpl upload-exp-discord",
"deploy-exp-query": "cpl publish-query; cpl upload-exp-query",
"deploy-exp-translation": "cpl publish-translation; cpl upload-exp-translation",
"pre-deploy-dev": "cpl sv $ARGS; cpl spu --environment=development;",
"deploy-dev": "cpl deploy-dev-cli; cpl deploy-dev-core; cpl deploy-dev-discord; cpl deploy-dev-query; cpl deploy-dev-translation;",
"dd": "cpl deploy-dev $ARGS",
"deploy-dev-cli": "cpl publish-cli; cpl upload-dev-cli",
"deploy-dev-core": "cpl publish-core; cpl upload-dev-core",
"deploy-dev-discord": "cpl publish-discord; cpl upload-dev-discord",
"deploy-dev-query": "cpl publish-query; cpl upload-dev-query",
"deploy-dev-translation": "cpl publish-query; cpl upload-dev-translation",
"dev-install": "cpl di-core; cpl di-cli; cpl di-query; cpl di-translation;",
"di": "cpl dev-install",
"di-core": "pip install cpl-core --pre --upgrade --extra-index-url https://pip-dev.sh-edraft.de",
"di-cli": "pip install cpl-cli --pre --upgrade --extra-index-url https://pip-dev.sh-edraft.de",
"di-discord": "pip install cpl-discord --pre --upgrade --extra-index-url https://pip-dev.sh-edraft.de",
"di-query": "pip install cpl-query --pre --upgrade --extra-index-url https://pip-dev.sh-edraft.de",
"di-translation": "pip install cpl-translation --pre --upgrade --extra-index-url https://pip-dev.sh-edraft.de",
"prod-install": "cpl pi-core; cpl pi-cli; cpl pi-query; cpl pi-translation;",
"pi": "cpl prod-install",
"pi-core": "pip install cpl-core --pre --upgrade --extra-index-url https://pip.sh-edraft.de",
"pi-cli": "pip install cpl-cli --pre --upgrade --extra-index-url https://pip.sh-edraft.de",
"pi-discord": "pip install cpl-discord --pre --upgrade --extra-index-url https://pip.sh-edraft.de",
"pi-query": "pip install cpl-query --pre --upgrade --extra-index-url https://pip.sh-edraft.de",
"pi-translation": "pip install cpl-translation --pre --upgrade --extra-index-url https://pip.sh-edraft.de"
}
}
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,6 @@
from .application_abc import ApplicationABC
from .application_builder import ApplicationBuilder
from .application_builder_abc import ApplicationBuilderABC
from .application_extension_abc import ApplicationExtensionABC
from .startup_abc import StartupABC
from .startup_extension_abc import StartupExtensionABC

View File

@@ -1,19 +1,19 @@
from abc import ABC, abstractmethod
from typing import Optional
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.console.console import Console
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.console.console import Console
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
class ApplicationABC(ABC):
r"""ABC for the Application class
Parameters:
config: :class:`cpl_core.configuration.configuration_abc.ConfigurationABC`
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
Contains object loaded from appsettings
services: :class:`cpl_core.dependency_injection.service_provider_abc.ServiceProviderABC`
services: :class:`cpl.core.dependency_injection.service_provider_abc.ServiceProviderABC`
Contains instances of prepared objects
"""
@@ -49,14 +49,12 @@ class ApplicationABC(ABC):
def configure(self):
r"""Configure the application
Called by :class:`cpl_core.application.application_abc.ApplicationABC.run`
Called by :class:`cpl.core.application.application_abc.ApplicationABC.run`
"""
pass
@abstractmethod
def main(self):
r"""Custom entry point
Called by :class:`cpl_core.application.application_abc.ApplicationABC.run`
Called by :class:`cpl.core.application.application_abc.ApplicationABC.run`
"""
pass

View File

@@ -0,0 +1,91 @@
from typing import Type, Optional, Callable, Union
from cpl.core.application.application_abc import ApplicationABC
from cpl.core.application.application_builder_abc import ApplicationBuilderABC
from cpl.core.application.application_extension_abc import ApplicationExtensionABC
from cpl.core.application.async_application_extension_abc import AsyncApplicationExtensionABC
from cpl.core.application.async_startup_abc import AsyncStartupABC
from cpl.core.application.async_startup_extension_abc import AsyncStartupExtensionABC
from cpl.core.application.startup_abc import StartupABC
from cpl.core.application.startup_extension_abc import StartupExtensionABC
from cpl.core.configuration.configuration import Configuration
from cpl.core.dependency_injection.service_collection import ServiceCollection
class ApplicationBuilder(ApplicationBuilderABC):
r"""This is class is used to build an object of :class:`cpl.core.application.application_abc.ApplicationABC`
Parameter:
app: Type[:class:`cpl.core.application.application_abc.ApplicationABC`]
Application to build
"""
def __init__(self, app: Type[ApplicationABC]):
ApplicationBuilderABC.__init__(self)
self._app = app
self._startup: Optional[StartupABC | AsyncStartupABC] = None
self._configuration = Configuration()
self._environment = self._configuration.environment
self._services = ServiceCollection(self._configuration)
self._app_extensions: list[Type[ApplicationExtensionABC | AsyncApplicationExtensionABC]] = []
self._startup_extensions: list[Type[StartupExtensionABC | AsyncStartupABC]] = []
def use_startup(self, startup: Type[StartupABC | AsyncStartupABC]) -> "ApplicationBuilder":
self._startup = startup()
return self
def use_extension(
self, extension: Type[ApplicationExtensionABC | AsyncApplicationExtensionABC | StartupExtensionABC | AsyncStartupExtensionABC]
) -> "ApplicationBuilder":
if (issubclass(extension, ApplicationExtensionABC) or issubclass(extension, AsyncApplicationExtensionABC)) and extension not in self._app_extensions:
self._app_extensions.append(extension)
elif (issubclass(extension, StartupExtensionABC) or issubclass(extension, AsyncStartupExtensionABC)) and extension not in self._startup_extensions:
self._startup_extensions.append(extension)
return self
def _build_startup(self):
for ex in self._startup_extensions:
extension = ex()
extension.configure_configuration(self._configuration, self._environment)
extension.configure_services(self._services, self._environment)
if self._startup is not None:
self._startup.configure_configuration(self._configuration, self._environment)
self._startup.configure_services(self._services, self._environment)
async def _build_async_startup(self):
for ex in self._startup_extensions:
extension = ex()
await extension.configure_configuration(self._configuration, self._environment)
await extension.configure_services(self._services, self._environment)
if self._startup is not None:
await self._startup.configure_configuration(self._configuration, self._environment)
await self._startup.configure_services(self._services, self._environment)
def build(self) -> ApplicationABC:
self._build_startup()
config = self._configuration
services = self._services.build_service_provider()
for ex in self._app_extensions:
extension = ex()
extension.run(config, services)
return self._app(config, services)
async def build_async(self) -> ApplicationABC:
await self._build_async_startup()
config = self._configuration
services = self._services.build_service_provider()
for ex in self._app_extensions:
extension = ex()
await extension.run(config, services)
return self._app(config, services)

View File

@@ -1,12 +1,12 @@
from abc import ABC, abstractmethod
from typing import Type
from cpl_core.application.application_abc import ApplicationABC
from cpl_core.application.startup_abc import StartupABC
from cpl.core.application.application_abc import ApplicationABC
from cpl.core.application.startup_abc import StartupABC
class ApplicationBuilderABC(ABC):
r"""ABC for the :class:`cpl_core.application.application_builder.ApplicationBuilder`"""
r"""ABC for the :class:`cpl.core.application.application_builder.ApplicationBuilder`"""
@abstractmethod
def __init__(self, *args):
@@ -17,35 +17,31 @@ class ApplicationBuilderABC(ABC):
r"""Sets the custom startup class to use
Parameter:
startup: Type[:class:`cpl_core.application.startup_abc.StartupABC`]
startup: Type[:class:`cpl.core.application.startup_abc.StartupABC`]
Startup class to use
"""
pass
@abstractmethod
async def use_startup(self, startup: Type[StartupABC]):
r"""Sets the custom startup class to use async
Parameter:
startup: Type[:class:`cpl_core.application.startup_abc.StartupABC`]
startup: Type[:class:`cpl.core.application.startup_abc.StartupABC`]
Startup class to use
"""
pass
@abstractmethod
def build(self) -> ApplicationABC:
r"""Creates custom application object
Returns:
Object of :class:`cpl_core.application.application_abc.ApplicationABC`
Object of :class:`cpl.core.application.application_abc.ApplicationABC`
"""
pass
@abstractmethod
async def build_async(self) -> ApplicationABC:
r"""Creates custom application object async
Returns:
Object of :class:`cpl_core.application.application_abc.ApplicationABC`
Object of :class:`cpl.core.application.application_abc.ApplicationABC`
"""
pass

View File

@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceProviderABC
from cpl.core.configuration import ConfigurationABC
from cpl.core.dependency_injection import ServiceProviderABC
class ApplicationExtensionABC(ABC):
@@ -12,7 +12,3 @@ class ApplicationExtensionABC(ABC):
@abstractmethod
def run(self, config: ConfigurationABC, services: ServiceProviderABC):
pass
@abstractmethod
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
pass

View File

@@ -0,0 +1,14 @@
from abc import ABC, abstractmethod
from cpl.core.configuration import ConfigurationABC
from cpl.core.dependency_injection import ServiceProviderABC
class AsyncApplicationExtensionABC(ABC):
@abstractmethod
def __init__(self):
pass
@abstractmethod
async def run(self, config: ConfigurationABC, services: ServiceProviderABC):
pass

View File

@@ -0,0 +1,32 @@
from abc import ABC, abstractmethod
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
class AsyncStartupABC(ABC):
r"""ABC for the startup class"""
@abstractmethod
def __init__(self):
pass
@abstractmethod
async def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
r"""Creates configuration of application
Parameter:
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
env: :class:`cpl.core.environment.application_environment_abc`
"""
@abstractmethod
async def configure_services(self, service: ServiceCollectionABC, env: ApplicationEnvironmentABC):
r"""Creates service provider
Parameter:
services: :class:`cpl.core.dependency_injection.service_collection_abc`
env: :class:`cpl.core.environment.application_environment_abc`
"""

View File

@@ -0,0 +1,31 @@
from abc import ABC, abstractmethod
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
class AsyncStartupExtensionABC(ABC):
r"""ABC for startup extension classes"""
@abstractmethod
def __init__(self):
pass
@abstractmethod
async def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
r"""Creates configuration of application
Parameter:
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
env: :class:`cpl.core.environment.application_environment_abc`
"""
@abstractmethod
async def configure_services(self, service: ServiceCollectionABC, env: ApplicationEnvironmentABC):
r"""Creates service provider
Parameter:
services: :class:`cpl.core.dependency_injection.service_collection_abc`
env: :class:`cpl.core.environment.application_environment_abc`
"""

View File

@@ -0,0 +1,32 @@
from abc import ABC, abstractmethod
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
class StartupABC(ABC):
r"""ABC for the startup class"""
@abstractmethod
def __init__(self):
pass
@abstractmethod
def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC):
r"""Creates configuration of application
Parameter:
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
env: :class:`cpl.core.environment.application_environment_abc`
"""
@abstractmethod
def configure_services(self, service: ServiceCollectionABC, env: ApplicationEnvironmentABC):
r"""Creates service provider
Parameter:
services: :class:`cpl.core.dependency_injection.service_collection_abc`
env: :class:`cpl.core.environment.application_environment_abc`
"""

View File

@@ -1,8 +1,8 @@
from abc import ABC, abstractmethod
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
class StartupExtensionABC(ABC):
@@ -17,17 +17,15 @@ class StartupExtensionABC(ABC):
r"""Creates configuration of application
Parameter:
config: :class:`cpl_core.configuration.configuration_abc.ConfigurationABC`
env: :class:`cpl_core.environment.application_environment_abc`
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
env: :class:`cpl.core.environment.application_environment_abc`
"""
pass
@abstractmethod
def configure_services(self, service: ServiceCollectionABC, env: ApplicationEnvironmentABC):
r"""Creates service provider
Parameter:
services: :class:`cpl_core.dependency_injection.service_collection_abc`
env: :class:`cpl_core.environment.application_environment_abc`
services: :class:`cpl.core.dependency_injection.service_collection_abc`
env: :class:`cpl.core.environment.application_environment_abc`
"""
pass

View File

@@ -1,26 +1,3 @@
# -*- coding: utf-8 -*-
"""
cpl-core CPL core
~~~~~~~~~~~~~~~~~~~
CPL core package
:copyright: (c) 2020 - 2024 sh-edraft.de
:license: MIT, see LICENSE for more details.
"""
__title__ = "cpl_core.configuration"
__author__ = "Sven Heidemann"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2020 - 2024 sh-edraft.de"
__version__ = "2024.6.0"
from collections import namedtuple
# imports:
from .argument_abc import ArgumentABC
from .argument_builder import ArgumentBuilder
from .argument_executable_abc import ArgumentExecutableABC
@@ -33,6 +10,3 @@ from .executable_argument import ExecutableArgument
from .flag_argument import FlagArgument
from .validator_abc import ValidatorABC
from .variable_argument import VariableArgument
VersionInfo = namedtuple("VersionInfo", "major minor micro")
version_info = VersionInfo(major="2024", minor="6", micro="0")

View File

@@ -1,6 +1,6 @@
from abc import ABC, abstractmethod
from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl.core.configuration.argument_type_enum import ArgumentTypeEnum
class ArgumentABC(ABC):
@@ -19,7 +19,7 @@ class ArgumentABC(ABC):
token: :class:`str`
name: :class:`str`
aliases: list[:class:`str`]
console_arguments: List[:class:`cpl_core.configuration.console_argument.ConsoleArgument`]
console_arguments: List[:class:`cpl.core.configuration.console_argument.ConsoleArgument`]
"""
self._token = token
self._name = name
@@ -55,9 +55,9 @@ class ArgumentABC(ABC):
Specifies the specific type of the argument
Returns:
self :class:`cpl_core.configuration.console_argument.ConsoleArgument` not created argument!
self :class:`cpl.core.configuration.console_argument.ConsoleArgument` not created argument!
"""
from cpl_core.configuration.argument_builder import ArgumentBuilder
from cpl.core.configuration.argument_builder import ArgumentBuilder
argument = ArgumentBuilder.build_argument(arg_type, *args, *kwargs)
self._console_arguments.append(argument)

View File

@@ -1,10 +1,10 @@
from typing import Union
from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl_core.configuration.executable_argument import ExecutableArgument
from cpl_core.configuration.flag_argument import FlagArgument
from cpl_core.configuration.variable_argument import VariableArgument
from cpl_core.console import Console
from cpl.core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl.core.configuration.executable_argument import ExecutableArgument
from cpl.core.configuration.flag_argument import FlagArgument
from cpl.core.configuration.variable_argument import VariableArgument
from cpl.core.console import Console
class ArgumentBuilder:

View File

@@ -3,29 +3,27 @@ import os
import sys
import traceback
from collections.abc import Callable
from typing import Union, Type, Optional
from typing import Union, Optional
from cpl_core.configuration.argument_abc import ArgumentABC
from cpl_core.configuration.argument_builder import ArgumentBuilder
from cpl_core.configuration.argument_executable_abc import ArgumentExecutableABC
from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.configuration.configuration_variable_name_enum import (
from cpl.core.configuration.argument_abc import ArgumentABC
from cpl.core.configuration.argument_builder import ArgumentBuilder
from cpl.core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.configuration.configuration_variable_name_enum import (
ConfigurationVariableNameEnum,
)
from cpl_core.configuration.executable_argument import ExecutableArgument
from cpl_core.configuration.flag_argument import FlagArgument
from cpl_core.configuration.validator_abc import ValidatorABC
from cpl_core.configuration.variable_argument import VariableArgument
from cpl_core.console.console import Console
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.environment.application_environment import ApplicationEnvironment
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.environment.environment_name_enum import EnvironmentNameEnum
from cpl_core.type import T, R
from cpl_core.utils.json_processor import JSONProcessor
from cpl.core.configuration.executable_argument import ExecutableArgument
from cpl.core.configuration.flag_argument import FlagArgument
from cpl.core.configuration.variable_argument import VariableArgument
from cpl.core.console.console import Console
from cpl.core.console.foreground_color_enum import ForegroundColorEnum
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.environment.application_environment import ApplicationEnvironment
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.environment.environment_name_enum import EnvironmentNameEnum
from cpl.core.typing import T, R
from cpl.core.utils.json_processor import JSONProcessor
class Configuration(ConfigurationABC):
@@ -64,7 +62,7 @@ class Configuration(ConfigurationABC):
return self._argument_types
@staticmethod
def _print_info(name: str, message: str):
def _print_info(message: str):
r"""Prints an info message
Parameter:
@@ -74,11 +72,11 @@ class Configuration(ConfigurationABC):
Info message
"""
Console.set_foreground_color(ForegroundColorEnum.green)
Console.write_line(f"[{name}] {message}")
Console.write_line(f"[CONF] {message}")
Console.set_foreground_color(ForegroundColorEnum.default)
@staticmethod
def _print_warn(name: str, message: str):
def _print_warn(message: str):
r"""Prints a warning
Parameter:
@@ -88,11 +86,11 @@ class Configuration(ConfigurationABC):
Warning message
"""
Console.set_foreground_color(ForegroundColorEnum.yellow)
Console.write_line(f"[{name}] {message}")
Console.write_line(f"[CONF] {message}")
Console.set_foreground_color(ForegroundColorEnum.default)
@staticmethod
def _print_error(name: str, message: str):
def _print_error(message: str):
r"""Prints an error
Parameter:
@@ -102,7 +100,7 @@ class Configuration(ConfigurationABC):
Error message
"""
Console.set_foreground_color(ForegroundColorEnum.red)
Console.write_line(f"[{name}] {message}")
Console.write_line(f"[CONF] {message}")
Console.set_foreground_color(ForegroundColorEnum.default)
def _set_variable(self, name: str, value: any):
@@ -144,40 +142,13 @@ class Configuration(ConfigurationABC):
# load json
json_cfg = json.load(cfg)
if output:
self._print_info(__name__, f"Loaded config file: {file}")
self._print_info(f"Loaded config file: {file}")
return json_cfg
except Exception as e:
self._print_error(__name__, f"Cannot load config file: {file}! -> {e}")
self._print_error(f"Cannot load config file: {file}! -> {e}")
return {}
def _handle_pre_or_post_executables(self, pre: bool, argument: ExecutableArgument, services: ServiceProviderABC):
script_type = "pre-" if pre else "post-"
from cpl_cli.configuration.workspace_settings import WorkspaceSettings
workspace: Optional[WorkspaceSettings] = self.get_configuration(WorkspaceSettings)
if workspace is None or len(workspace.scripts) == 0:
return
for script in workspace.scripts:
if script_type not in script and not script.startswith(script_type):
continue
# split in two ifs to prevent exception
if script.split(script_type)[1] != argument.name:
continue
from cpl_cli.command.custom_script_service import CustomScriptService
css: CustomScriptService = services.get_service(CustomScriptService)
if css is None:
continue
Console.write_line()
self._set_variable("ACTIVE_EXECUTABLE", script)
css.run(self._additional_arguments)
def _parse_arguments(
self,
executables: list[ArgumentABC],
@@ -266,7 +237,7 @@ class Configuration(ConfigurationABC):
if not os.path.isfile(file_path):
if optional is not True:
if output:
self._print_error(__name__, f"File not found: {file_path}")
self._print_error(f"File not found: {file_path}")
sys.exit()
@@ -344,7 +315,7 @@ class Configuration(ConfigurationABC):
arg_list = sys.argv[1:]
executables: list[ExecutableArgument] = []
self._parse_arguments(executables, arg_list, self._argument_types)
except Exception as e:
except Exception:
Console.error("An error occurred while parsing arguments.", traceback.format_exc())
sys.exit()
@@ -380,7 +351,7 @@ class Configuration(ConfigurationABC):
self._handle_pre_or_post_executables(False, exe, services)
prevent = exe.prevent_next_executable
success = True
except Exception as e:
except Exception:
Console.error("An error occurred while executing arguments.", traceback.format_exc())
sys.exit()

View File

@@ -1,19 +1,17 @@
from abc import abstractmethod, ABC
from collections.abc import Callable
from typing import Type, Union, Optional
from typing import Optional
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.configuration.argument_abc import ArgumentABC
from cpl_core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.type import T, R
from cpl.core.configuration.argument_abc import ArgumentABC
from cpl.core.configuration.argument_type_enum import ArgumentTypeEnum
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.typing import T, R
class ConfigurationABC(ABC):
@abstractmethod
def __init__(self):
r"""ABC for the :class:`cpl_core.configuration.configuration.Configuration`"""
pass
r"""ABC for the :class:`cpl.core.configuration.configuration.Configuration`"""
@property
@abstractmethod
@@ -48,17 +46,15 @@ class ConfigurationABC(ABC):
prefix: :class:`str`
Prefix of the variables
"""
pass
@abstractmethod
def add_console_argument(self, argument: ArgumentABC):
r"""Adds console argument to known console arguments
Parameter:
argument: :class:`cpl_core.configuration.console_argument.ConsoleArgumentABC`
argument: :class:`cpl.core.configuration.console_argument.ConsoleArgumentABC`
Specifies the console argument
"""
pass
@abstractmethod
def add_json_file(self, name: str, optional: bool = None, output: bool = True, path: str = None):
@@ -74,19 +70,17 @@ class ConfigurationABC(ABC):
path: :class:`str`
Path in which the file should be stored
"""
pass
@abstractmethod
def add_configuration(self, key_type: T, value: any):
r"""Add configuration object
Parameter:
key_type: :class:`cpl_core.type.T`
key_type: :class:`cpl.core.type.T`
Type of the value
value: any
Object of the value
"""
pass
@abstractmethod
def create_console_argument(
@@ -105,13 +99,12 @@ class ConfigurationABC(ABC):
Specifies were the value begins
is_value_token_optional :class:`bool`
Specifies if values are optional
runnable: :class:`cpl_core.configuration.console_argument.ConsoleArgumentABC`
runnable: :class:`cpl.core.configuration.console_argument.ConsoleArgumentABC`
Specifies class to run when called if value is not None
Returns:
Object of :class:`cpl_core.configuration.console_argument.ConsoleArgumentABC`
Object of :class:`cpl.core.configuration.console_argument.ConsoleArgumentABC`
"""
pass
@abstractmethod
def for_each_argument(self, call: Callable):
@@ -121,20 +114,18 @@ class ConfigurationABC(ABC):
call: :class:`Callable`
Call for each argument
"""
pass
@abstractmethod
def get_configuration(self, search_type: T) -> Optional[R]:
r"""Returns value from configuration by given type
Parameter:
search_type: :class:`cpl_core.type.T`
search_type: :class:`cpl.core.type.T`
Type to search for
Returns:
Object of Union[:class:`str`, :class:`cpl_core.configuration.configuration_model_abc.ConfigurationModelABC`]
Object of Union[:class:`str`, :class:`cpl.core.configuration.configuration_model_abc.ConfigurationModelABC`]
"""
pass
@abstractmethod
def parse_console_arguments(self, services: "ServiceProviderABC", error: bool = None) -> bool:
@@ -147,4 +138,3 @@ class ConfigurationABC(ABC):
Returns:
Bool to specify if executables were executed or not.
"""
pass

View File

@@ -10,7 +10,6 @@ class ConfigurationModelABC(ABC):
@abstractmethod
def __init__(self):
r"""ABC for settings representation"""
pass
@base_func
def from_dict(self, settings: dict):
@@ -20,4 +19,3 @@ class ConfigurationModelABC(ABC):
Parameter:
settings: :class:`dict`
"""
pass

View File

@@ -1,8 +1,8 @@
from typing import Type, Optional
from cpl_core.configuration.argument_executable_abc import ArgumentExecutableABC
from cpl_core.configuration.argument_abc import ArgumentABC
from cpl_core.configuration.validator_abc import ValidatorABC
from cpl.core.configuration.argument_executable_abc import ArgumentExecutableABC
from cpl.core.configuration.argument_abc import ArgumentABC
from cpl.core.configuration.validator_abc import ValidatorABC
class ExecutableArgument(ArgumentABC):

View File

@@ -1,4 +1,4 @@
from cpl_core.configuration.argument_abc import ArgumentABC
from cpl.core.configuration.argument_abc import ArgumentABC
class FlagArgument(ArgumentABC):

View File

@@ -1,4 +1,4 @@
from cpl_core.configuration.argument_abc import ArgumentABC
from cpl.core.configuration.argument_abc import ArgumentABC
class VariableArgument(ArgumentABC):

View File

@@ -0,0 +1,5 @@
from .background_color_enum import BackgroundColorEnum
from .console import Console
from .console_call import ConsoleCall
from .foreground_color_enum import ForegroundColorEnum
from .spinner_thread import SpinnerThread

View File

@@ -9,14 +9,15 @@ import colorama
from tabulate import tabulate
from termcolor import colored
from cpl_core.console.background_color_enum import BackgroundColorEnum
from cpl_core.console.console_call import ConsoleCall
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl_core.console.spinner_thread import SpinnerThread
from cpl.core.console.background_color_enum import BackgroundColorEnum
from cpl.core.console.console_call import ConsoleCall
from cpl.core.console.foreground_color_enum import ForegroundColorEnum
from cpl.core.console.spinner_thread import SpinnerThread
class Console:
r"""Useful functions for handling with input and output"""
colorama.init()
_is_first_write = True
@@ -61,7 +62,7 @@ class Console:
r"""Sets the background color
Parameter:
color: Union[:class:`cpl_core.console.background_color_enum.BackgroundColorEnum`, :class:`str`]
color: Union[:class:`cpl.core.console.background_color_enum.BackgroundColorEnum`, :class:`str`]
Background color of the console
"""
if type(color) is str:
@@ -74,7 +75,7 @@ class Console:
r"""Sets the foreground color
Parameter:
color: Union[:class:`cpl_core.console.background_color_enum.BackgroundColorEnum`, :class:`str`]
color: Union[:class:`cpl.core.console.background_color_enum.BackgroundColorEnum`, :class:`str`]
Foreground color of the console
"""
if type(color) is str:
@@ -365,17 +366,17 @@ class Console:
Message or header of the selection
options: List[:class:`str`]
Selectable options
header_foreground_color: Union[:class:`str`, :class:`cpl_core.console.foreground_color_enum.ForegroundColorEnum`]
header_foreground_color: Union[:class:`str`, :class:`cpl.core.console.foreground_color_enum.ForegroundColorEnum`]
Foreground color of the header
header_background_color: Union[:class:`str`, :class:`cpl_core.console.background_color_enum.BackgroundColorEnum`]
header_background_color: Union[:class:`str`, :class:`cpl.core.console.background_color_enum.BackgroundColorEnum`]
Background color of the header
option_foreground_color: Union[:class:`str`, :class:`cpl_core.console.foreground_color_enum.ForegroundColorEnum`]
option_foreground_color: Union[:class:`str`, :class:`cpl.core.console.foreground_color_enum.ForegroundColorEnum`]
Foreground color of the options
option_background_color: Union[:class:`str`, :class:`cpl_core.console.background_color_enum.BackgroundColorEnum`]
option_background_color: Union[:class:`str`, :class:`cpl.core.console.background_color_enum.BackgroundColorEnum`]
Background color of the options
cursor_foreground_color: Union[:class:`str`, :class:`cpl_core.console.foreground_color_enum.ForegroundColorEnum`]
cursor_foreground_color: Union[:class:`str`, :class:`cpl.core.console.foreground_color_enum.ForegroundColorEnum`]
Foreground color of the cursor
cursor_background_color: Union[:class:`str`, :class:`cpl_core.console.background_color_enum.BackgroundColorEnum`]
cursor_background_color: Union[:class:`str`, :class:`cpl.core.console.background_color_enum.BackgroundColorEnum`]
Background color of the cursor
Returns:
@@ -429,13 +430,13 @@ class Console:
Function to call
args: :class:`list`
Arguments of the function
text_foreground_color: Union[:class:`str`, :class:`cpl_core.console.foreground_color_enum.ForegroundColorEnum`]
text_foreground_color: Union[:class:`str`, :class:`cpl.core.console.foreground_color_enum.ForegroundColorEnum`]
Foreground color of the text
spinner_foreground_color: Union[:class:`str`, :class:`cpl_core.console.foreground_color_enum.ForegroundColorEnum`]
spinner_foreground_color: Union[:class:`str`, :class:`cpl.core.console.foreground_color_enum.ForegroundColorEnum`]
Foreground color of the spinner
text_background_color: Union[:class:`str`, :class:`cpl_core.console.background_color_enum.BackgroundColorEnum`]
text_background_color: Union[:class:`str`, :class:`cpl.core.console.background_color_enum.BackgroundColorEnum`]
Background color of the text
spinner_background_color: Union[:class:`str`, :class:`cpl_core.console.background_color_enum.BackgroundColorEnum`]
spinner_background_color: Union[:class:`str`, :class:`cpl.core.console.background_color_enum.BackgroundColorEnum`]
Background color of the spinner
kwargs: :class:`dict`
Keyword arguments of the call

View File

@@ -5,8 +5,8 @@ import time
from termcolor import colored
from cpl_core.console.background_color_enum import BackgroundColorEnum
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl.core.console.background_color_enum import BackgroundColorEnum
from cpl.core.console.foreground_color_enum import ForegroundColorEnum
class SpinnerThread(threading.Thread):
@@ -15,9 +15,9 @@ class SpinnerThread(threading.Thread):
Parameter:
msg_len: :class:`int`
Length of the message
foreground_color: :class:`cpl_core.console.foreground_color.ForegroundColorEnum`
foreground_color: :class:`cpl.core.console.foreground_color.ForegroundColorEnum`
Foreground color of the spinner
background_color: :class:`cpl_core.console.background_color.BackgroundColorEnum`
background_color: :class:`cpl.core.console.background_color.BackgroundColorEnum`
Background color of the spinner
"""

View File

@@ -0,0 +1,3 @@
from .database_settings_name_enum import DatabaseSettingsNameEnum
from .database_settings import DatabaseSettings
from .table_abc import TableABC

View File

@@ -0,0 +1,2 @@
from .database_connection import DatabaseConnection
from .database_connection_abc import DatabaseConnectionABC

View File

@@ -4,9 +4,9 @@ import mysql.connector as sql
from mysql.connector.abstracts import MySQLConnectionAbstract
from mysql.connector.cursor import MySQLCursorBuffered
from cpl_core.database.connection.database_connection_abc import DatabaseConnectionABC
from cpl_core.database.database_settings import DatabaseSettings
from cpl_core.utils.credential_manager import CredentialManager
from cpl.core.database.connection.database_connection_abc import DatabaseConnectionABC
from cpl.core.database.database_settings import DatabaseSettings
from cpl.core.utils.credential_manager import CredentialManager
class DatabaseConnection(DatabaseConnectionABC):

View File

@@ -1,12 +1,12 @@
from abc import ABC, abstractmethod
from cpl_core.database.database_settings import DatabaseSettings
from cpl.core.database.database_settings import DatabaseSettings
from mysql.connector.abstracts import MySQLConnectionAbstract
from mysql.connector.cursor import MySQLCursorBuffered
class DatabaseConnectionABC(ABC):
r"""ABC for the :class:`cpl_core.database.connection.database_connection.DatabaseConnection`"""
r"""ABC for the :class:`cpl.core.database.connection.database_connection.DatabaseConnection`"""
@abstractmethod
def __init__(self):
@@ -30,4 +30,3 @@ class DatabaseConnectionABC(ABC):
connection_string: :class:`str`
Database connection string, see: https://docs.sqlalchemy.org/en/14/core/engines.html
"""
pass

View File

@@ -0,0 +1,2 @@
from .database_context import DatabaseContext
from .database_context_abc import DatabaseContextABC

View File

@@ -1,12 +1,10 @@
from typing import Optional
import mysql
from cpl_core.database.connection.database_connection import DatabaseConnection
from cpl_core.database.connection.database_connection_abc import DatabaseConnectionABC
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.database.database_settings import DatabaseSettings
from cpl_core.database.table_abc import TableABC
from cpl.core.database.connection.database_connection import DatabaseConnection
from cpl.core.database.connection.database_connection_abc import DatabaseConnectionABC
from cpl.core.database.context.database_context_abc import DatabaseContextABC
from cpl.core.database.database_settings import DatabaseSettings
from mysql.connector.cursor import MySQLCursorBuffered
@@ -14,7 +12,7 @@ class DatabaseContext(DatabaseContextABC):
r"""Representation of the database context
Parameter:
database_settings: :class:`cpl_core.database.database_settings.DatabaseSettings`
database_settings: :class:`cpl.core.database.database_settings.DatabaseSettings`
"""
def __init__(self):
@@ -31,7 +29,7 @@ class DatabaseContext(DatabaseContextABC):
def _ping_and_reconnect(self):
try:
self._db.server.ping(reconnect=True, attempts=3, delay=5)
except Exception as err:
except Exception:
# reconnect your cursor as you did in __init__ or wherever
if self._settings is None:
raise Exception("Call DatabaseContext.connect first")

View File

@@ -1,11 +1,11 @@
from abc import ABC, abstractmethod
from cpl_core.database.database_settings import DatabaseSettings
from cpl.core.database.database_settings import DatabaseSettings
from mysql.connector.cursor import MySQLCursorBuffered
class DatabaseContextABC(ABC):
r"""ABC for the :class:`cpl_core.database.context.database_context.DatabaseContext`"""
r"""ABC for the :class:`cpl.core.database.context.database_context.DatabaseContext`"""
@abstractmethod
def __init__(self, *args):
@@ -21,14 +21,12 @@ class DatabaseContextABC(ABC):
r"""Connects to a database by connection settings
Parameter:
database_settings :class:`cpl_core.database.database_settings.DatabaseSettings`
database_settings :class:`cpl.core.database.database_settings.DatabaseSettings`
"""
pass
@abstractmethod
def save_changes(self):
r"""Saves changes of the database"""
pass
@abstractmethod
def select(self, statement: str) -> list[tuple]:
@@ -40,4 +38,3 @@ class DatabaseContextABC(ABC):
Returns:
list: Fetched list of selected elements
"""
pass

View File

@@ -1,6 +1,6 @@
from typing import Optional
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
class DatabaseSettings(ConfigurationModelABC):

View File

@@ -0,0 +1,8 @@
from cpl.core.log import Logger
from cpl.core.typing import Source
class DBLogger(Logger):
def __init__(self, source: Source):
Logger.__init__(self, source, "db")

View File

@@ -0,0 +1,8 @@
from .scope import Scope
from .scope_abc import ScopeABC
from .service_collection import ServiceCollection
from .service_collection_abc import ServiceCollectionABC
from .service_descriptor import ServiceDescriptor
from .service_lifetime_enum import ServiceLifetimeEnum
from .service_provider import ServiceProvider
from .service_provider_abc import ServiceProviderABC

View File

@@ -1,6 +1,5 @@
from cpl_core.console.console import Console
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.dependency_injection.scope_abc import ScopeABC
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
class Scope(ScopeABC):

View File

@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
class ScopeABC(ABC):
r"""ABC for the class :class:`cpl_core.dependency_injection.scope.Scope`"""
r"""ABC for the class :class:`cpl.core.dependency_injection.scope.Scope`"""
def __init__(self):
pass
@@ -13,11 +13,9 @@ class ScopeABC(ABC):
r"""Returns to service provider of scope
Returns:
Object of type :class:`cpl_core.dependency_injection.service_provider_abc.ServiceProviderABC`
Object of type :class:`cpl.core.dependency_injection.service_provider_abc.ServiceProviderABC`
"""
pass
@abstractmethod
def dispose(self):
r"""Sets service_provider to None"""
pass

View File

@@ -1,10 +1,10 @@
from cpl_core.dependency_injection.scope import Scope
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.dependency_injection.scope import Scope
from cpl.core.dependency_injection.scope_abc import ScopeABC
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
class ScopeBuilder:
r"""Class to build :class:`cpl_core.dependency_injection.scope.Scope`"""
r"""Class to build :class:`cpl.core.dependency_injection.scope.Scope`"""
def __init__(self, service_provider: ServiceProviderABC) -> None:
self._service_provider = service_provider
@@ -13,6 +13,6 @@ class ScopeBuilder:
r"""Returns scope
Returns:
Object of type :class:`cpl_core.dependency_injection.scope.Scope`
Object of type :class:`cpl.core.dependency_injection.scope.Scope`
"""
return Scope(self._service_provider)

View File

@@ -1,17 +1,17 @@
from typing import Union, Type, Callable, Optional
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.database.database_settings import DatabaseSettings
from cpl_core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl_core.dependency_injection.service_descriptor import ServiceDescriptor
from cpl_core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
from cpl_core.dependency_injection.service_provider import ServiceProvider
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.logging.logger_abc import LoggerABC
from cpl_core.logging.logger_service import Logger
from cpl_core.pipes.pipe_abc import PipeABC
from cpl_core.type import T
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.database.context.database_context_abc import DatabaseContextABC
from cpl.core.database.database_settings import DatabaseSettings
from cpl.core.dependency_injection.service_collection_abc import ServiceCollectionABC
from cpl.core.dependency_injection.service_descriptor import ServiceDescriptor
from cpl.core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
from cpl.core.dependency_injection.service_provider import ServiceProvider
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.log.logger import Logger
from cpl.core.log.logger_abc import LoggerABC
from cpl.core.pipes.pipe_abc import PipeABC
from cpl.core.typing import T, Service
class ServiceCollection(ServiceCollectionABC):
@@ -53,7 +53,7 @@ class ServiceCollection(ServiceCollectionABC):
self._database_context.connect(db_settings)
def add_logging(self):
self.add_singleton(LoggerABC, Logger)
self.add_transient(LoggerABC, Logger)
return self
def add_pipes(self):
@@ -61,15 +61,15 @@ class ServiceCollection(ServiceCollectionABC):
self.add_transient(PipeABC, pipe)
return self
def add_singleton(self, service_type: T, service: T = None):
def add_singleton(self, service_type: T, service: Service = None):
self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.singleton, service)
return self
def add_scoped(self, service_type: T, service: T = None):
def add_scoped(self, service_type: T, service: Service = None):
self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.scoped, service)
return self
def add_transient(self, service_type: T, service: T = None):
def add_transient(self, service_type: T, service: Service = None):
self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.transient, service)
return self

View File

@@ -1,15 +1,14 @@
from abc import abstractmethod, ABC
from collections.abc import Callable
from typing import Type
from cpl_core.database.database_settings import DatabaseSettings
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.type import T
from cpl.core.database.context.database_context_abc import DatabaseContextABC
from cpl.core.database.database_settings import DatabaseSettings
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.typing import T, Source
class ServiceCollectionABC(ABC):
r"""ABC for the class :class:`cpl_core.dependency_injection.service_collection.ServiceCollection`"""
r"""ABC for the class :class:`cpl.core.dependency_injection.service_collection.ServiceCollection`"""
@abstractmethod
def __init__(self):
@@ -20,30 +19,25 @@ class ServiceCollectionABC(ABC):
r"""Adds database context
Parameter:
db_context: Type[:class:`cpl_core.database.context.database_context_abc.DatabaseContextABC`]
db_context: Type[:class:`cpl.core.database.context.database_context_abc.DatabaseContextABC`]
Database context
"""
pass
@abstractmethod
def add_logging(self):
r"""Adds the CPL internal logger"""
pass
@abstractmethod
def add_pipes(self):
r"""Adds the CPL internal pipes as transient"""
pass
def add_discord(self):
r"""Adds the CPL discord"""
raise NotImplementedError("You should install and use the cpl-discord package")
pass
def add_translation(self):
r"""Adds the CPL translation"""
raise NotImplementedError("You should install and use the cpl-translation package")
pass
def add_mail(self):
r"""Adds the CPL mail"""
raise NotImplementedError("You should install and use the cpl-mail package")
@abstractmethod
def add_transient(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
@@ -56,9 +50,8 @@ class ServiceCollectionABC(ABC):
Object of the service
Returns:
self: :class:`cpl_core.dependency_injection.service_collection_abc.ServiceCollectionABC`
self: :class:`cpl.core.dependency_injection.service_collection_abc.ServiceCollectionABC`
"""
pass
@abstractmethod
def add_scoped(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
@@ -71,9 +64,8 @@ class ServiceCollectionABC(ABC):
Object of the service
Returns:
self: :class:`cpl_core.dependency_injection.service_collection_abc.ServiceCollectionABC`
self: :class:`cpl.core.dependency_injection.service_collection_abc.ServiceCollectionABC`
"""
pass
@abstractmethod
def add_singleton(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
@@ -86,15 +78,13 @@ class ServiceCollectionABC(ABC):
Object of the service
Returns:
self: :class:`cpl_core.dependency_injection.service_collection_abc.ServiceCollectionABC`
self: :class:`cpl.core.dependency_injection.service_collection_abc.ServiceCollectionABC`
"""
pass
@abstractmethod
def build_service_provider(self) -> ServiceProviderABC:
r"""Creates instance of the service provider
Returns:
Object of type :class:`cpl_core.dependency_injection.service_provider_abc.ServiceProviderABC`
Object of type :class:`cpl.core.dependency_injection.service_provider_abc.ServiceProviderABC`
"""
pass

View File

@@ -1,7 +1,6 @@
from typing import Union, Optional
from cpl_core.console import Console
from cpl_core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
from cpl.core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
class ServiceDescriptor:
@@ -10,7 +9,7 @@ class ServiceDescriptor:
Parameter:
implementation: Union[:class:`type`, Optional[:class:`object`]]
Object or type of service
lifetime: :class:`cpl_core.dependency_injection.service_lifetime_enum.ServiceLifetimeEnum`
lifetime: :class:`cpl.core.dependency_injection.service_lifetime_enum.ServiceLifetimeEnum`
Lifetime of the service
"""

View File

@@ -3,16 +3,16 @@ import typing
from inspect import signature, Parameter, Signature
from typing import Optional
from cpl_core.configuration.configuration_abc import ConfigurationABC
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.database.context.database_context_abc import DatabaseContextABC
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.dependency_injection.scope_builder import ScopeBuilder
from cpl_core.dependency_injection.service_descriptor import ServiceDescriptor
from cpl_core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
from cpl_core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.type import T, R
from cpl.core.configuration.configuration_abc import ConfigurationABC
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.database.context.database_context_abc import DatabaseContextABC
from cpl.core.dependency_injection.scope_abc import ScopeABC
from cpl.core.dependency_injection.scope_builder import ScopeBuilder
from cpl.core.dependency_injection.service_descriptor import ServiceDescriptor
from cpl.core.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
from cpl.core.dependency_injection.service_provider_abc import ServiceProviderABC
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.typing import T, R, Source
class ServiceProvider(ServiceProviderABC):
@@ -20,11 +20,11 @@ class ServiceProvider(ServiceProviderABC):
Parameter
---------
service_descriptors: list[:class:`cpl_core.dependency_injection.service_descriptor.ServiceDescriptor`]
service_descriptors: list[:class:`cpl.core.dependency_injection.service_descriptor.ServiceDescriptor`]
Descriptor of the service
config: :class:`cpl_core.configuration.configuration_abc.ConfigurationABC`
config: :class:`cpl.core.configuration.configuration_abc.ConfigurationABC`
CPL Configuration
db_context: Optional[:class:`cpl_core.database.context.database_context_abc.DatabaseContextABC`]
db_context: Optional[:class:`cpl.core.database.context.database_context_abc.DatabaseContextABC`]
Database representation
"""
@@ -48,7 +48,7 @@ class ServiceProvider(ServiceProviderABC):
return None
def _get_service(self, parameter: Parameter) -> Optional[object]:
def _get_service(self, parameter: Parameter, origin_service_type: type = None) -> Optional[object]:
for descriptor in self._service_descriptors:
if descriptor.service_type == parameter.annotation or issubclass(
descriptor.service_type, parameter.annotation
@@ -56,7 +56,7 @@ class ServiceProvider(ServiceProviderABC):
if descriptor.implementation is not None:
return descriptor.implementation
implementation = self.build_service(descriptor.service_type)
implementation = self._build_service(descriptor.service_type, origin_service_type=origin_service_type)
if descriptor.lifetime == ServiceLifetimeEnum.singleton:
descriptor.implementation = implementation
@@ -64,7 +64,7 @@ class ServiceProvider(ServiceProviderABC):
# raise Exception(f'Service {parameter.annotation} not found')
def _get_services(self, t: type, *args, **kwargs) -> list[Optional[object]]:
def _get_services(self, t: type, *args, service_type: type = None, **kwargs) -> list[Optional[object]]:
implementations = []
for descriptor in self._service_descriptors:
if descriptor.service_type == t or issubclass(descriptor.service_type, t):
@@ -72,7 +72,7 @@ class ServiceProvider(ServiceProviderABC):
implementations.append(descriptor.implementation)
continue
implementation = self.build_service(descriptor.service_type, *args, **kwargs)
implementation = self._build_service(descriptor.service_type, *args, service_type, **kwargs)
if descriptor.lifetime == ServiceLifetimeEnum.singleton:
descriptor.implementation = implementation
@@ -80,13 +80,16 @@ class ServiceProvider(ServiceProviderABC):
return implementations
def build_by_signature(self, sig: Signature) -> list[R]:
def _build_by_signature(self, sig: Signature, origin_service_type: type) -> list[R]:
params = []
for param in sig.parameters.items():
parameter = param[1]
if parameter.name != "self" and parameter.annotation != Parameter.empty:
if typing.get_origin(parameter.annotation) == list:
params.append(self._get_services(typing.get_args(parameter.annotation)[0]))
params.append(self._get_services(typing.get_args(parameter.annotation)[0], origin_service_type))
elif parameter.annotation == Source:
params.append(origin_service_type.__name__)
elif issubclass(parameter.annotation, ServiceProviderABC):
params.append(self)
@@ -104,11 +107,15 @@ class ServiceProvider(ServiceProviderABC):
params.append(self._configuration)
else:
params.append(self._get_service(parameter))
params.append(self._get_service(parameter, origin_service_type))
return params
def build_service(self, service_type: type, *args, **kwargs) -> object:
def _build_service(self, service_type: type, *args, origin_service_type: type = None, **kwargs) -> object:
if origin_service_type is None:
origin_service_type = service_type
for descriptor in self._service_descriptors:
if descriptor.service_type == service_type or issubclass(descriptor.service_type, service_type):
if descriptor.implementation is not None:
@@ -119,7 +126,7 @@ class ServiceProvider(ServiceProviderABC):
break
sig = signature(service_type.__init__)
params = self.build_by_signature(sig)
params = self._build_by_signature(sig, origin_service_type)
return service_type(*params, *args, **kwargs)
@@ -147,7 +154,7 @@ class ServiceProvider(ServiceProviderABC):
if result.implementation is not None:
return result.implementation
implementation = self.build_service(service_type, *args, **kwargs)
implementation = self._build_service(service_type, *args, **kwargs)
if (
result.lifetime == ServiceLifetimeEnum.singleton
or result.lifetime == ServiceLifetimeEnum.scoped

View File

@@ -1,14 +1,14 @@
import functools
from abc import abstractmethod, ABC
from inspect import Signature, signature
from typing import Optional, Type
from typing import Optional
from cpl_core.dependency_injection.scope_abc import ScopeABC
from cpl_core.type import T, R
from cpl.core.dependency_injection.scope_abc import ScopeABC
from cpl.core.typing import T, R
class ServiceProviderABC(ABC):
r"""ABC for the class :class:`cpl_core.dependency_injection.service_provider.ServiceProvider`"""
r"""ABC for the class :class:`cpl.core.dependency_injection.service_provider.ServiceProvider`"""
_provider: Optional["ServiceProviderABC"] = None
@@ -21,11 +21,11 @@ class ServiceProviderABC(ABC):
cls._provider = provider
@abstractmethod
def build_by_signature(self, sig: Signature) -> list[R]:
def _build_by_signature(self, sig: Signature, origin_service_type: type) -> list[R]:
pass
@abstractmethod
def build_service(self, service_type: type, *args, **kwargs) -> object:
def _build_service(self, service_type: type, *args, **kwargs) -> object:
r"""Creates instance of given type
Parameter
@@ -37,7 +37,6 @@ class ServiceProviderABC(ABC):
-------
Object of the given type
"""
pass
@abstractmethod
def set_scope(self, scope: ScopeABC):
@@ -45,10 +44,9 @@ class ServiceProviderABC(ABC):
Parameter
---------
Object of type :class:`cpl_core.dependency_injection.scope_abc.ScopeABC`
Object of type :class:`cpl.core.dependency_injection.scope_abc.ScopeABC`
Service scope
"""
pass
@abstractmethod
def create_scope(self) -> ScopeABC:
@@ -56,9 +54,8 @@ class ServiceProviderABC(ABC):
Returns
-------
Object of type :class:`cpl_core.dependency_injection.scope_abc.ScopeABC`
Object of type :class:`cpl.core.dependency_injection.scope_abc.ScopeABC`
"""
pass
@abstractmethod
def get_service(self, instance_type: T, *args, **kwargs) -> Optional[R]:
@@ -66,14 +63,13 @@ class ServiceProviderABC(ABC):
Parameter
---------
instance_type: :class:`cpl_core.type.T`
instance_type: :class:`cpl.core.type.T`
The type of the searched instance
Returns
-------
Object of type Optional[:class:`cpl_core.type.T`]
Object of type Optional[:class:`cpl.core.type.T`]
"""
pass
@abstractmethod
def get_services(self, service_type: T, *args, **kwargs) -> list[Optional[R]]:
@@ -81,14 +77,13 @@ class ServiceProviderABC(ABC):
Parameter
---------
service_type: :class:`cpl_core.type.T`
service_type: :class:`cpl.core.type.T`
The type of the searched instance
Returns
-------
Object of type list[Optional[:class:`cpl_core.type.T`]
Object of type list[Optional[:class:`cpl.core.type.T`]
"""
pass
@classmethod
def inject(cls, f=None):
@@ -110,7 +105,7 @@ class ServiceProviderABC(ABC):
if cls._provider is None:
raise Exception(f"{cls.__name__} not build!")
injection = [x for x in cls._provider.build_by_signature(signature(f)) if x is not None]
injection = [x for x in cls._provider._build_by_signature(signature(f)) if x is not None]
return f(*args, *injection, **kwargs)
return inner

View File

@@ -0,0 +1,3 @@
from .application_environment_abc import ApplicationEnvironmentABC
from .environment_name_enum import EnvironmentNameEnum
from .application_environment import ApplicationEnvironment

View File

@@ -3,15 +3,15 @@ from datetime import datetime
from socket import gethostname
from typing import Optional
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.environment.environment_name_enum import EnvironmentNameEnum
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.environment.environment_name_enum import EnvironmentNameEnum
class ApplicationEnvironment(ApplicationEnvironmentABC):
r"""Represents environment of the application
Parameter:
name: :class:`cpl_core.environment.environment_name_enum.EnvironmentNameEnum`
name: :class:`cpl.core.environment.environment_name_enum.EnvironmentNameEnum`
"""
def __init__(self, name: EnvironmentNameEnum = EnvironmentNameEnum.production):

View File

@@ -3,7 +3,7 @@ from datetime import datetime
class ApplicationEnvironmentABC(ABC):
r"""ABC of the class :class:`cpl_core.environment.application_environment.ApplicationEnvironment`"""
r"""ABC of the class :class:`cpl.core.environment.application_environment.ApplicationEnvironment`"""
@abstractmethod
def __init__(self):
@@ -87,7 +87,6 @@ class ApplicationEnvironmentABC(ABC):
runtime_directory: :class:`str`
Path of the runtime directory
"""
pass
@abstractmethod
def set_working_directory(self, working_directory: str):
@@ -97,4 +96,3 @@ class ApplicationEnvironmentABC(ABC):
working_directory: :class:`str`
Path of the current working directory
"""
pass

View File

@@ -0,0 +1,32 @@
import os
from typing import Optional, Type
from cpl.core.typing import T
from cpl.core.utils.get_value import get_value
class Environment:
_environment = "production"
@classmethod
def get_environment(cls):
return cls._environment
@classmethod
def set_environment(cls, environment: str):
if environment not in ["development", "staging", "production"]:
raise ValueError("Invalid environment")
Environment._environment = environment
@staticmethod
def get(key: str, cast_type: Type[T], default: Optional[T] = None) -> Optional[T]:
"""
Get an environment variable and cast it to a specified type.
:param str key: The name of the environment variable.
:param Type[T] cast_type: A callable to cast the variable's value.
:param Optional[T] default: The default value to return if the variable is not found. Defaults to None.The default value to return if the variable is not found. Defaults to None.
:return: The casted value, or None if the variable is not found.
:rtype: Optional[T]
"""
return get_value(dict(os.environ), key, cast_type, default)

View File

@@ -0,0 +1,4 @@
from .logger import Logger
from .logger_abc import LoggerABC
from .log_level_enum import LogLevelEnum
from .logging_settings import LogSettings

View File

@@ -0,0 +1,94 @@
import multiprocessing
import os
from datetime import datetime
from typing import Self
from cpl.core.console import Console
from cpl.core.log.log_level_enum import LogLevelEnum
class LogWriter:
_instance = None
# ANSI color codes for different log levels
_COLORS = {
LogLevelEnum.trace: "\033[37m", # Light Gray
LogLevelEnum.debug: "\033[94m", # Blue
LogLevelEnum.info: "\033[92m", # Green
LogLevelEnum.warning: "\033[93m", # Yellow
LogLevelEnum.error: "\033[91m", # Red
LogLevelEnum.fatal: "\033[95m", # Magenta
}
def __init__(self, file_prefix: str, level: LogLevelEnum = LogLevelEnum.info):
self._file_prefix = file_prefix
self._level = level
self._queue = multiprocessing.Queue()
self._process = multiprocessing.Process(target=self._log_worker, daemon=True)
self._create_log_dir()
self._process.start()
@property
def level(self) -> LogLevelEnum:
return self._level
@level.setter
def level(self, value: LogLevelEnum):
assert isinstance(value, LogLevelEnum), "Log level must be an instance of LogLevelEnum"
self._level = value
@classmethod
def get_instance(cls, file_prefix: str, level: LogLevelEnum = LogLevelEnum.info) -> Self:
if cls._instance is None:
cls._instance = LogWriter(file_prefix, level)
return cls._instance
@staticmethod
def _create_log_dir():
if os.path.exists("logs"):
return
os.makedirs("logs")
def _log_worker(self):
"""Worker process that writes log messages from the queue to the file."""
while True:
content = self._queue.get()
if content is None: # Shutdown signal
break
self._write_log_to_file(content)
Console.write_line(
f"{self._COLORS.get(self._level, '\033[0m')}{content}\033[0m"
)
@property
def log_file(self):
return f"logs/{self._file_prefix}_{datetime.now().strftime('%Y-%m-%d')}.log"
def _ensure_file_size(self):
log_file = self.log_file
if not os.path.exists(log_file) or os.path.getsize(log_file) <= 0.5 * 1024 * 1024:
return
# if exists and size is greater than 300MB, create a new file
os.rename(
log_file,
f"{log_file.split('.log')[0]}_{datetime.now().strftime('%H-%M-%S')}.log",
)
def _write_log_to_file(self, content: str):
self._ensure_file_size()
with open(self.log_file, "a") as log_file:
log_file.write(content + "\n")
log_file.close()
def log(self, content: str):
"""Enqueue log message without blocking main app."""
self._queue.put(content)
def close(self):
"""Gracefully stop the logging process."""
self._queue.put(None)
self._process.join()

View File

@@ -0,0 +1,11 @@
from enum import Enum
class LogLevelEnum(Enum):
off = "OFF" # Nothing
trace = "TRC" # Detailed app information's
debug = "DEB" # Detailed app state
info = "INF" # Normal information's
warning = "WAR" # Error that can later be fatal
error = "ERR" # Non fatal error
fatal = "FAT" # Error that cause exit

View File

@@ -0,0 +1,78 @@
import os
import traceback
from datetime import datetime
from cpl.core.console import Console
from cpl.core.log._log_writer import LogWriter
from cpl.core.log.log_level_enum import LogLevelEnum
from cpl.core.log.logger_abc import LoggerABC
from cpl.core.typing import Messages, Source
class Logger(LoggerABC):
_level = LogLevelEnum.info
_levels = [x for x in LogLevelEnum]
def __init__(self, source: Source, file_prefix: str = None):
LoggerABC.__init__(self)
assert source is not None and source != "", "Source cannot be None or empty"
self._source = source
if file_prefix is None:
file_prefix = "app"
self._file_prefix = file_prefix
self._writer = LogWriter.get_instance(self._file_prefix)
@classmethod
def set_level(cls, level: LogLevelEnum):
if level in cls._levels:
cls._level = level
else:
raise ValueError(f"Invalid log level: {level}")
def _log(self, level: LogLevelEnum, *messages: Messages):
try:
if self._levels.index(level) < self._levels.index(self._level):
return
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
formatted_message = self._format_message(level.value, timestamp, *messages)
self._writer.log(formatted_message)
except Exception as e:
print(f"Error while logging: {e} -> {traceback.format_exc()}")
def _format_message(self, level: str, timestamp, *messages: Messages) -> str:
if isinstance(messages, tuple):
messages = list(messages)
if not isinstance(messages, list):
messages = [messages]
messages = [str(message) for message in messages if message is not None]
return f"<{timestamp}> [{level.upper():^3}] [{self._file_prefix}] - [{self._source}]: {' '.join(messages)}"
def header(self, string: str):
self._log(LogLevelEnum.info, string)
def trace(self, *messages: Messages):
self._log(LogLevelEnum.trace, *messages)
def debug(self, *messages: Messages):
self._log(LogLevelEnum.debug, *messages)
def info(self, *messages: Messages):
self._log(LogLevelEnum.info, *messages)
def warning(self, *messages: Messages):
self._log(LogLevelEnum.warning, *messages)
def error(self, message, e: Exception = None):
self._log(LogLevelEnum.error, message, f"{e} -> {traceback.format_exc()}" if e else None)
def fatal(self, message, e: Exception = None, prevent_quit: bool = False):
self._log(LogLevelEnum.fatal, message, f"{e} -> {traceback.format_exc()}" if e else None)
if not prevent_quit:
exit(-1)

View File

@@ -1,12 +1,18 @@
from abc import abstractmethod, ABC
from cpl.core.typing import Messages
class LoggerABC(ABC):
r"""ABC for :class:`cpl_core.logging.logger_service.Logger`"""
r"""ABC for :class:`cpl.core.log.logger_service.Logger`"""
@abstractmethod
def __init__(self):
ABC.__init__(self)
def set_level(self, level: str):
pass
@abstractmethod
def _format_message(self, level: str, timestamp, *messages: Messages) -> str:
pass
@abstractmethod
def header(self, string: str):
@@ -16,10 +22,9 @@ class LoggerABC(ABC):
string: :class:`str`
String to write as header
"""
pass
@abstractmethod
def trace(self, name: str, message: str):
def trace(self, *messages: Messages):
r"""Writes a trace message
Parameter:
@@ -28,10 +33,9 @@ class LoggerABC(ABC):
message: :class:`str`
Message string
"""
pass
@abstractmethod
def debug(self, name: str, message: str):
def debug(self, *messages: Messages):
r"""Writes a debug message
Parameter:
@@ -40,10 +44,9 @@ class LoggerABC(ABC):
message: :class:`str`
Message string
"""
pass
@abstractmethod
def info(self, name: str, message: str):
def info(self, *messages: Messages):
r"""Writes an information
Parameter:
@@ -52,10 +55,9 @@ class LoggerABC(ABC):
message: :class:`str`
Message string
"""
pass
@abstractmethod
def warn(self, name: str, message: str):
def warning(self, *messages: Messages):
r"""Writes an warning
Parameter:
@@ -64,10 +66,9 @@ class LoggerABC(ABC):
message: :class:`str`
Message string
"""
pass
@abstractmethod
def error(self, name: str, message: str, ex: Exception = None):
def error(self, messages: str, e: Exception = None):
r"""Writes an error
Parameter:
@@ -78,10 +79,9 @@ class LoggerABC(ABC):
ex: :class:`Exception`
Thrown exception
"""
pass
@abstractmethod
def fatal(self, name: str, message: str, ex: Exception = None):
def fatal(self, messages: str, e: Exception = None):
r"""Writes an error and ends the program
Parameter:
@@ -92,4 +92,3 @@ class LoggerABC(ABC):
ex: :class:`Exception`
Thrown exception
"""
pass

View File

@@ -1,28 +1,24 @@
import traceback
from typing import Optional
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console.console import Console
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl_core.logging.logging_level_enum import LoggingLevelEnum
from cpl_core.logging.logging_settings_name_enum import LoggingSettingsNameEnum
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.log.log_level_enum import LogLevelEnum
class LoggingSettings(ConfigurationModelABC):
class LogSettings(ConfigurationModelABC):
r"""Representation of logging settings"""
def __init__(
self,
path: str = None,
filename: str = None,
console_log_level: LoggingLevelEnum = None,
file_log_level: LoggingLevelEnum = None,
console_log_level: LogLevelEnum = None,
file_log_level: LogLevelEnum = None,
):
ConfigurationModelABC.__init__(self)
self._path: Optional[str] = path
self._filename: Optional[str] = filename
self._console: Optional[LoggingLevelEnum] = console_log_level
self._level: Optional[LoggingLevelEnum] = file_log_level
self._console: Optional[LogLevelEnum] = console_log_level
self._level: Optional[LogLevelEnum] = file_log_level
@property
def path(self) -> str:
@@ -41,17 +37,17 @@ class LoggingSettings(ConfigurationModelABC):
self._filename = filename
@property
def console(self) -> LoggingLevelEnum:
def console(self) -> LogLevelEnum:
return self._console
@console.setter
def console(self, console: LoggingLevelEnum) -> None:
def console(self, console: LogLevelEnum) -> None:
self._console = console
@property
def level(self) -> LoggingLevelEnum:
def level(self) -> LogLevelEnum:
return self._level
@level.setter
def level(self, level: LoggingLevelEnum) -> None:
def level(self, level: LogLevelEnum) -> None:
self._level = level

View File

@@ -0,0 +1,3 @@
from .bool_pipe import BoolPipe
from .ip_address_pipe import IPAddressPipe
from .pipe_abc import PipeABC

View File

@@ -1,4 +1,4 @@
from cpl_core.pipes.pipe_abc import PipeABC
from cpl.core.pipes.pipe_abc import PipeABC
class BoolPipe(PipeABC):

View File

@@ -1,4 +1,4 @@
from cpl_core.pipes.pipe_abc import PipeABC
from cpl.core.pipes.pipe_abc import PipeABC
class IPAddressPipe(PipeABC):

View File

@@ -1,5 +1,5 @@
from cpl_cli.configuration import VersionSettingsNameEnum
from cpl_core.pipes.pipe_abc import PipeABC
from cpl.core.pipes.pipe_abc import PipeABC
class VersionPipe(PipeABC):

View File

@@ -0,0 +1,2 @@
from .time_format_settings import TimeFormatSettings
from .time_format_settings_names_enum import TimeFormatSettingsNamesEnum

View File

@@ -1,10 +1,6 @@
import traceback
from typing import Optional
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl_core.console.console import Console
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl_core.time.time_format_settings_names_enum import TimeFormatSettingsNamesEnum
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
class TimeFormatSettings(ConfigurationModelABC):

View File

@@ -0,0 +1,9 @@
from typing import TypeVar, Any
T = TypeVar("T")
R = TypeVar("R")
Service = TypeVar("Service")
Source = TypeVar("Source")
Messages = list[Any] | Any

View File

@@ -0,0 +1,3 @@
from .credential_manager import CredentialManager
from .string import String
from .pip import Pip

View File

@@ -0,0 +1,63 @@
from typing import Type, Optional
from cpl.core.typing import T
def get_value(
source: dict,
key: str,
cast_type: Type[T],
default: Optional[T] = None,
list_delimiter: str = ",",
) -> Optional[T]:
"""
Get value from source dictionary and cast it to a specified type.
:param dict source: The source dictionary.
:param str key: The name of the environment variable.
:param Type[T] cast_type: A callable to cast the variable's value.
:param Optional[T] default: The default value to return if the variable is not found. Defaults to None.
:param str list_delimiter: The delimiter to split the value into a list. Defaults to ",".
:return: The casted value, or None if the key is not found.
:rtype: Optional[T]
"""
if key not in source:
return default
value = source[key]
if isinstance(
value,
cast_type if not hasattr(cast_type, "__origin__") else cast_type.__origin__,
):
# Handle list[int] case explicitly
if hasattr(cast_type, "__origin__") and cast_type.__origin__ == list:
subtype = cast_type.__args__[0] if hasattr(cast_type, "__args__") else None
if subtype is not None:
return [subtype(item) for item in value]
return value
try:
if cast_type == bool:
return value.lower() in ["true", "1"]
if (
cast_type if not hasattr(cast_type, "__origin__") else cast_type.__origin__
) == list:
if (
not (value.startswith("[") and value.endswith("]"))
and list_delimiter not in value
):
raise ValueError(
"List values must be enclosed in square brackets or use a delimiter."
)
if value.startswith("[") and value.endswith("]"):
value = value[1:-1]
value = value.split(list_delimiter)
subtype = cast_type.__args__[0] if hasattr(cast_type, "__args__") else None
return [subtype(item) if subtype is not None else item for item in value]
return cast_type(value)
except (ValueError, TypeError):
return default

View File

@@ -1,7 +1,7 @@
import enum
from inspect import signature, Parameter
from cpl_core.utils import String
from cpl.core.utils import String
class JSONProcessor:

View File

@@ -4,11 +4,10 @@ import sys
from contextlib import suppress
from typing import Optional
from cpl_core.console import Console
class Pip:
r"""Executes pip commands"""
_executable = sys.executable
_env = os.environ

View File

@@ -0,0 +1,29 @@
[build-system]
requires = ["setuptools>=70.1.0", "wheel>=0.43.0"]
build-backend = "setuptools.build_meta"
[project]
name = "cpl-core"
version = "2024.7.0"
description = "CPL core"
readme = "CPL core package"
requires-python = ">=3.12"
license = "MIT"
authors = [
{ name = "Sven Heidemann", email = "sven.heidemann@sh-edraft.de" }
]
keywords = ["cpl", "core", "backend", "shared", "library"]
dynamic = ["dependencies", "optional-dependencies"]
[project.urls]
Homepage = "https://www.sh-edraft.de"
[tool.setuptools.packages.find]
where = ["."]
include = ["cpl*"]
[tool.setuptools.dynamic]
dependencies = { file = ["requirements.txt"] }
optional-dependencies.dev = { file = ["requirements.dev.txt"] }

View File

@@ -0,0 +1 @@
black==25.1.0

View File

@@ -0,0 +1,5 @@
art==6.5
colorama==0.4.6
tabulate==0.9.0
termcolor==3.1.0
mysql-connector-python==9.4.0

View File

@@ -0,0 +1,26 @@
from .abc.email_client_abc import EMailClientABC
from .email_client import EMailClient
from .email_client_settings import EMailClientSettings
from .email_client_settings_name_enum import EMailClientSettingsNameEnum
from .email_model import EMail
from .mail_logger import MailLogger
def add_mail(self):
from cpl.core.console import Console
from cpl.core.log import LoggerABC
try:
self.add_singleton(EMailClientABC, EMailClient)
self.add_transient(LoggerABC, MailLogger)
except ImportError as e:
Console.error("cpl-translation is not installed", str(e))
def init():
from cpl.core.dependency_injection import ServiceCollection
ServiceCollection.add_mail = add_mail
init()

View File

@@ -1,10 +1,10 @@
from abc import abstractmethod, ABC
from cpl_core.mailing.email import EMail
from cpl.mail.email_model import EMail
class EMailClientABC(ABC):
"""ABC of :class:`cpl_core.mailing.email_client_service.EMailClient`"""
"""ABC of :class:`cpl.mail.email_client_service.EMailClient`"""
@abstractmethod
def __init__(self):
@@ -13,14 +13,12 @@ class EMailClientABC(ABC):
@abstractmethod
def connect(self):
r"""Connects to server"""
pass
@abstractmethod
def send_mail(self, email: EMail):
r"""Sends email
Parameter:
email: :class:`cpl_core.mailing.email.EMail`
email: :class:`cpl.mail.email.EMail`
Object of the E-Mail to send
"""
pass

View File

@@ -0,0 +1,88 @@
import ssl
from smtplib import SMTP
from typing import Optional
from cpl.core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl.core.utils.credential_manager import CredentialManager
from cpl.mail.abc.email_client_abc import EMailClientABC
from cpl.mail.email_client_settings import EMailClientSettings
from cpl.mail.email_model import EMail
from cpl.mail.mail_logger import MailLogger
class EMailClient(EMailClientABC):
r"""Service to send emails
Parameter:
environment: :class:`cpl.core.environment.application_environment_abc.ApplicationEnvironmentABC`
Environment of the application
logger: :class:`cpl.core.log.logger_abc.LoggerABC`
The logger to use
mail_settings: :class:`cpl.mail.email_client_settings.EMailClientSettings`
Settings for mailing
"""
def __init__(self, environment: ApplicationEnvironmentABC, logger: MailLogger, mail_settings: EMailClientSettings):
EMailClientABC.__init__(self)
self._environment = environment
self._mail_settings = mail_settings
self._logger = logger
self._server: Optional[SMTP] = None
self.create()
def create(self):
r"""Creates connection"""
self._logger.trace(f"Started {__name__}.create")
self.connect()
self._logger.trace(f"Stopped {__name__}.create")
def connect(self):
self._logger.trace(f"Started {__name__}.connect")
try:
self._logger.debug(f"Try to connect to {self._mail_settings.host}:{self._mail_settings.port}")
self._server = SMTP(self._mail_settings.host, self._mail_settings.port)
self._logger.info(f"Connected to {self._mail_settings.host}:{self._mail_settings.port}")
self._logger.debug("Try to start tls")
self._server.starttls(context=ssl.create_default_context())
self._logger.info("Started tls")
except Exception as e:
self._logger.error("Cannot connect to mail server", e)
self._logger.trace(f"Stopped {__name__}.connect")
def login(self):
r"""Login to server"""
self._logger.trace(f"Started {__name__}.login")
try:
self._logger.debug(
__name__,
f"Try to login {self._mail_settings.user_name}@{self._mail_settings.host}:{self._mail_settings.port}",
)
self._server.login(
self._mail_settings.user_name, CredentialManager.decrypt(self._mail_settings.credentials)
)
self._logger.info(
__name__,
f"Logged on as {self._mail_settings.user_name} to {self._mail_settings.host}:{self._mail_settings.port}",
)
except Exception as e:
self._logger.error("Cannot login to mail server", e)
self._logger.trace(f"Stopped {__name__}.login")
def send_mail(self, email: EMail):
self._logger.trace(f"Started {__name__}.send_mail")
try:
self.login()
self._logger.debug(f"Try to send email to {email.receiver_list}")
self._server.sendmail(
self._mail_settings.user_name, email.receiver_list, email.get_content(self._mail_settings.user_name)
)
self._logger.info(f"Sent email to {email.receiver_list}")
except Exception as e:
self._logger.error(f"Cannot send mail to {email.receiver_list}", e)
self._logger.trace(f"Stopped {__name__}.send_mail")

View File

@@ -1,4 +1,4 @@
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
class EMailClientSettings(ConfigurationModelABC):

View File

@@ -0,0 +1,8 @@
from cpl.core.log.logger import Logger
from cpl.core.typing import Source
class MailLogger(Logger):
def __init__(self, source: Source):
Logger.__init__(self, source, "mail")

View File

@@ -0,0 +1,29 @@
[build-system]
requires = ["setuptools>=70.1.0", "wheel>=0.43.0"]
build-backend = "setuptools.build_meta"
[project]
name = "cpl-mail"
version = "2024.7.0"
description = "CPL mail"
readme = "CPL mail package"
requires-python = ">=3.12"
license = { text = "MIT" }
authors = [
{ name = "Sven Heidemann", email = "sven.heidemann@sh-edraft.de" }
]
keywords = ["cpl", "mail", "backend", "shared", "library"]
dynamic = ["dependencies", "optional-dependencies"]
[project.urls]
Homepage = "https://www.sh-edraft.de"
[tool.setuptools.packages.find]
where = ["."]
include = ["cpl*"]
[tool.setuptools.dynamic]
dependencies = { file = ["requirements.txt"] }
optional-dependencies.dev = { file = ["requirements.dev.txt"] }

View File

@@ -0,0 +1 @@
black==25.1.0

View File

@@ -0,0 +1 @@
cpl-core

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,5 @@
from .default_lambda import default_lambda
from .ordered_queryable import OrderedQueryable
from .sequence import Sequence
from .ordered_queryable_abc import OrderedQueryableABC
from .queryable_abc import QueryableABC

Some files were not shown because too many files have changed in this diff Show More