Compare commits
12 Commits
2025.09.24
...
2025.09.26
| Author | SHA1 | Date | |
|---|---|---|---|
| c410a692be | |||
| 56a16cbeba | |||
| d05d947d54 | |||
| 0529269747 | |||
| e3e1703ff8 | |||
| cf4aa8291f | |||
| 55a727c482 | |||
| ecb92fca3e | |||
| 0ca5e5757a | |||
| 75417966eb | |||
| 15d3c59f02 | |||
| 6a3fdb3ebd |
@@ -25,7 +25,11 @@ jobs:
|
|||||||
git tag
|
git tag
|
||||||
DATE=$(date +'%Y.%m.%d')
|
DATE=$(date +'%Y.%m.%d')
|
||||||
TAG_COUNT=$(git tag -l "${DATE}.*" | wc -l)
|
TAG_COUNT=$(git tag -l "${DATE}.*" | wc -l)
|
||||||
|
if [ "$TAG_COUNT" -eq 0 ]; then
|
||||||
|
BUILD_NUMBER=0
|
||||||
|
else
|
||||||
BUILD_NUMBER=$(($TAG_COUNT + 1))
|
BUILD_NUMBER=$(($TAG_COUNT + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION_SUFFIX=${{ inputs.version_suffix }}
|
VERSION_SUFFIX=${{ inputs.version_suffix }}
|
||||||
if [ -n "$VERSION_SUFFIX" ] && [ "$VERSION_SUFFIX" = "dev" ]; then
|
if [ -n "$VERSION_SUFFIX" ] && [ "$VERSION_SUFFIX" = "dev" ]; then
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
from cpl import api
|
from cpl.api.api_module import ApiModule
|
||||||
from cpl.api.application.web_app import WebApp
|
from cpl.api.application.web_app import WebApp
|
||||||
from cpl.application import ApplicationBuilder
|
from cpl.application.application_builder import ApplicationBuilder
|
||||||
|
from cpl.auth import AuthModule
|
||||||
from cpl.auth.permission.permissions import Permissions
|
from cpl.auth.permission.permissions import Permissions
|
||||||
from cpl.auth.schema import AuthUser, Role
|
from cpl.auth.schema import AuthUser, Role
|
||||||
from cpl.core.configuration import Configuration
|
from cpl.core.configuration import Configuration
|
||||||
from cpl.core.console import Console
|
from cpl.core.console import Console
|
||||||
from cpl.core.environment import Environment
|
from cpl.core.environment import Environment
|
||||||
from cpl.core.utils.cache import Cache
|
from cpl.core.utils.cache import Cache
|
||||||
from custom.api.src.scoped_service import ScopedService
|
from cpl.database.mysql.mysql_module import MySQLModule
|
||||||
|
from scoped_service import ScopedService
|
||||||
from service import PingService
|
from service import PingService
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +25,8 @@ def main():
|
|||||||
# builder.services.add_logging()
|
# builder.services.add_logging()
|
||||||
builder.services.add_structured_logging()
|
builder.services.add_structured_logging()
|
||||||
builder.services.add_transient(PingService)
|
builder.services.add_transient(PingService)
|
||||||
builder.services.add_module(api)
|
builder.services.add_module(MySQLModule)
|
||||||
|
builder.services.add_module(ApiModule)
|
||||||
|
|
||||||
builder.services.add_scoped(ScopedService)
|
builder.services.add_scoped(ScopedService)
|
||||||
|
|
||||||
@@ -32,12 +35,17 @@ def main():
|
|||||||
|
|
||||||
app = builder.build()
|
app = builder.build()
|
||||||
app.with_logging()
|
app.with_logging()
|
||||||
app.with_database()
|
|
||||||
|
|
||||||
app.with_authentication()
|
app.with_authentication()
|
||||||
app.with_authorization()
|
app.with_authorization()
|
||||||
|
|
||||||
app.with_route(path="/route1", fn=lambda r: JSONResponse("route1"), method="GET", authentication=True, permissions=[Permissions.administrator])
|
app.with_route(
|
||||||
|
path="/route1",
|
||||||
|
fn=lambda r: JSONResponse("route1"),
|
||||||
|
method="GET",
|
||||||
|
authentication=True,
|
||||||
|
permissions=[Permissions.administrator],
|
||||||
|
)
|
||||||
app.with_routes_directory("routes")
|
app.with_routes_directory("routes")
|
||||||
|
|
||||||
provider = builder.service_provider
|
provider = builder.service_provider
|
||||||
@@ -7,7 +7,7 @@ from cpl.api import APILogger
|
|||||||
from cpl.api.router import Router
|
from cpl.api.router import Router
|
||||||
from cpl.core.console import Console
|
from cpl.core.console import Console
|
||||||
from cpl.dependency import ServiceProvider
|
from cpl.dependency import ServiceProvider
|
||||||
from custom.api.src.scoped_service import ScopedService
|
from scoped_service import ScopedService
|
||||||
|
|
||||||
|
|
||||||
@Router.authenticate()
|
@Router.authenticate()
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"Project": {
|
|
||||||
"Name": "database",
|
|
||||||
"Version": {
|
|
||||||
"Major": "0",
|
|
||||||
"Minor": "0",
|
|
||||||
"Micro": "0"
|
|
||||||
},
|
|
||||||
"Author": "",
|
|
||||||
"AuthorEmail": "",
|
|
||||||
"Description": "",
|
|
||||||
"LongDescription": "",
|
|
||||||
"URL": "",
|
|
||||||
"CopyrightDate": "",
|
|
||||||
"CopyrightName": "",
|
|
||||||
"LicenseName": "",
|
|
||||||
"LicenseDescription": "",
|
|
||||||
"Dependencies": [
|
|
||||||
"sh_cpl==2021.4.2.dev1"
|
|
||||||
],
|
|
||||||
"PythonVersion": ">=3.9.2",
|
|
||||||
"PythonPath": {},
|
|
||||||
"Classifiers": []
|
|
||||||
},
|
|
||||||
"Build": {
|
|
||||||
"ProjectType": "console",
|
|
||||||
"SourcePath": "src",
|
|
||||||
"OutputPath": "dist",
|
|
||||||
"Main": "main",
|
|
||||||
"EntryPoint": "database",
|
|
||||||
"IncludePackageData": false,
|
|
||||||
"Included": [],
|
|
||||||
"Excluded": [
|
|
||||||
"*/__pycache__",
|
|
||||||
"*/logs",
|
|
||||||
"*/tests"
|
|
||||||
],
|
|
||||||
"PackageData": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Workspace": {
|
|
||||||
"DefaultProject": "di",
|
|
||||||
"Projects": {
|
|
||||||
"di": "src/di/di.json"
|
|
||||||
},
|
|
||||||
"Scripts": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from cpl.core.console.console import Console
|
|
||||||
from di.test_abc import TestABC
|
|
||||||
|
|
||||||
|
|
||||||
class Tester:
|
|
||||||
def __init__(self, t1: TestABC, t2: TestABC, t3: list[TestABC]):
|
|
||||||
Console.write_line("Tester:")
|
|
||||||
Console.write_line(t1, t2, t3)
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Workspace": {
|
|
||||||
"DefaultProject": "general",
|
|
||||||
"Projects": {
|
|
||||||
"general": "src/general/general.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"Project": {
|
|
||||||
"Name": "general",
|
|
||||||
"Version": {
|
|
||||||
"Major": "2021",
|
|
||||||
"Minor": "04",
|
|
||||||
"Micro": "01"
|
|
||||||
},
|
|
||||||
"Author": "Sven Heidemann",
|
|
||||||
"AuthorEmail": "sven.heidemann@sh-edraft.de",
|
|
||||||
"Description": "sh-edraft Common Python library",
|
|
||||||
"LongDescription": "sh-edraft Common Python library",
|
|
||||||
"URL": "https://www.sh-edraft.de",
|
|
||||||
"CopyrightDate": "2020 - 2021",
|
|
||||||
"CopyrightName": "sh-edraft.de",
|
|
||||||
"LicenseName": "MIT",
|
|
||||||
"LicenseDescription": "MIT, see LICENSE for more details.",
|
|
||||||
"Dependencies": [
|
|
||||||
"cpl-core==2022.10.0.post9",
|
|
||||||
"cpl-translation==2022.10.0.post2",
|
|
||||||
"cpl-query==2022.10.0.post2"
|
|
||||||
],
|
|
||||||
"DevDependencies": [
|
|
||||||
"cpl-cli==2022.10"
|
|
||||||
],
|
|
||||||
"PythonVersion": ">=3.10",
|
|
||||||
"PythonPath": {
|
|
||||||
"linux": "../../venv/bin/python",
|
|
||||||
"win32": ""
|
|
||||||
},
|
|
||||||
"Classifiers": []
|
|
||||||
},
|
|
||||||
"Build": {
|
|
||||||
"ProjectType": "console",
|
|
||||||
"SourcePath": "",
|
|
||||||
"OutputPath": "dist",
|
|
||||||
"Main": "main",
|
|
||||||
"EntryPoint": "",
|
|
||||||
"IncludePackageData": true,
|
|
||||||
"Included": [
|
|
||||||
"*/templates"
|
|
||||||
],
|
|
||||||
"Excluded": [
|
|
||||||
"*/__pycache__",
|
|
||||||
"*/logs",
|
|
||||||
"*/tests"
|
|
||||||
],
|
|
||||||
"PackageData": {},
|
|
||||||
"ProjectReferences": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
class Custom:
|
|
||||||
def __init__(self):
|
|
||||||
print("hello")
|
|
||||||
@@ -4,6 +4,7 @@ from cpl.core.console import Console
|
|||||||
from cpl.core.environment import Environment
|
from cpl.core.environment import Environment
|
||||||
from cpl.core.log import LoggerABC
|
from cpl.core.log import LoggerABC
|
||||||
from cpl.dependency import ServiceProvider
|
from cpl.dependency import ServiceProvider
|
||||||
|
from cpl.dependency.typing import Modules
|
||||||
from model.city import City
|
from model.city import City
|
||||||
from model.city_dao import CityDao
|
from model.city_dao import CityDao
|
||||||
from model.user import User
|
from model.user import User
|
||||||
@@ -11,8 +12,8 @@ from model.user_dao import UserDao
|
|||||||
|
|
||||||
|
|
||||||
class Application(ApplicationABC):
|
class Application(ApplicationABC):
|
||||||
def __init__(self, services: ServiceProvider):
|
def __init__(self, services: ServiceProvider, modules: Modules):
|
||||||
ApplicationABC.__init__(self, services)
|
ApplicationABC.__init__(self, services, modules)
|
||||||
|
|
||||||
self._logger = services.get_service(LoggerABC)
|
self._logger = services.get_service(LoggerABC)
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ from cpl.application import ApplicationBuilder
|
|||||||
from cpl.auth.permission.permissions_registry import PermissionsRegistry
|
from cpl.auth.permission.permissions_registry import PermissionsRegistry
|
||||||
from cpl.core.console import Console
|
from cpl.core.console import Console
|
||||||
from cpl.core.log import LogLevel
|
from cpl.core.log import LogLevel
|
||||||
|
from cpl.database import DatabaseModule
|
||||||
from custom_permissions import CustomPermissions
|
from custom_permissions import CustomPermissions
|
||||||
from startup import Startup
|
from startup import Startup
|
||||||
|
|
||||||
@@ -10,13 +11,12 @@ from startup import Startup
|
|||||||
def main():
|
def main():
|
||||||
builder = ApplicationBuilder(Application).with_startup(Startup)
|
builder = ApplicationBuilder(Application).with_startup(Startup)
|
||||||
builder.services.add_logging()
|
builder.services.add_logging()
|
||||||
|
|
||||||
app = builder.build()
|
app = builder.build()
|
||||||
|
|
||||||
app.with_logging(LogLevel.trace)
|
app.with_logging(LogLevel.trace)
|
||||||
app.with_permissions(CustomPermissions)
|
app.with_permissions(CustomPermissions)
|
||||||
app.with_migrations("./scripts")
|
app.with_migrations("./scripts")
|
||||||
app.with_seeders()
|
# app.with_seeders()
|
||||||
|
|
||||||
Console.write_line(CustomPermissions.test.value in PermissionsRegistry.get())
|
Console.write_line(CustomPermissions.test.value in PermissionsRegistry.get())
|
||||||
app.run()
|
app.run()
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
from cpl import auth
|
from cpl import auth
|
||||||
from cpl.application.abc.startup_abc import StartupABC
|
from cpl.application.abc.startup_abc import StartupABC
|
||||||
from cpl.auth import permission
|
from cpl.auth import permission
|
||||||
|
from cpl.auth.auth_module import AuthModule
|
||||||
|
from cpl.auth.permission.permission_module import PermissionsModule
|
||||||
from cpl.core.configuration import Configuration
|
from cpl.core.configuration import Configuration
|
||||||
from cpl.core.environment import Environment
|
from cpl.core.environment import Environment
|
||||||
from cpl.core.log import Logger, LoggerABC
|
from cpl.core.log import Logger, LoggerABC
|
||||||
from cpl.database import mysql
|
from cpl.database import mysql, DatabaseModule
|
||||||
from cpl.database.abc.data_access_object_abc import DataAccessObjectABC
|
from cpl.database.abc.data_access_object_abc import DataAccessObjectABC
|
||||||
|
from cpl.database.mysql.mysql_module import MySQLModule
|
||||||
from cpl.dependency import ServiceCollection
|
from cpl.dependency import ServiceCollection
|
||||||
from model.city_dao import CityDao
|
from model.city_dao import CityDao
|
||||||
from model.user_dao import UserDao
|
from model.user_dao import UserDao
|
||||||
@@ -21,9 +24,10 @@ class Startup(StartupABC):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def configure_services(services: ServiceCollection):
|
async def configure_services(services: ServiceCollection):
|
||||||
services.add_module(mysql)
|
services.add_module(MySQLModule)
|
||||||
services.add_module(auth)
|
services.add_module(DatabaseModule)
|
||||||
services.add_module(permission)
|
services.add_module(AuthModule)
|
||||||
|
services.add_module(PermissionsModule)
|
||||||
|
|
||||||
services.add_transient(DataAccessObjectABC, UserDao)
|
services.add_transient(DataAccessObjectABC, UserDao)
|
||||||
services.add_transient(DataAccessObjectABC, CityDao)
|
services.add_transient(DataAccessObjectABC, CityDao)
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
from cpl.application.abc import ApplicationABC
|
from cpl.application.abc import ApplicationABC
|
||||||
from cpl.core.console.console import Console
|
from cpl.core.console.console import Console
|
||||||
from cpl.dependency import ServiceProvider
|
from cpl.dependency import ServiceProvider
|
||||||
from di.static_test import StaticTest
|
from test_abc import TestABC
|
||||||
from di.test_abc import TestABC
|
from test_service import TestService
|
||||||
from di.test_service import TestService
|
from di_tester_service import DITesterService
|
||||||
from di.di_tester_service import DITesterService
|
from tester import Tester
|
||||||
from di.tester import Tester
|
|
||||||
|
|
||||||
|
|
||||||
class Application(ApplicationABC):
|
class Application(ApplicationABC):
|
||||||
@@ -39,7 +38,8 @@ class Application(ApplicationABC):
|
|||||||
|
|
||||||
Console.write_line("Global")
|
Console.write_line("Global")
|
||||||
self._part_of_scoped()
|
self._part_of_scoped()
|
||||||
StaticTest.test()
|
#from static_test import StaticTest
|
||||||
|
#StaticTest.test()
|
||||||
|
|
||||||
self._services.get_service(Tester)
|
self._services.get_service(Tester)
|
||||||
Console.write_line(self._services.get_services(TestABC))
|
Console.write_line(self._services.get_services(TestABC))
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from cpl.core.console.console import Console
|
from cpl.core.console.console import Console
|
||||||
from di.test_service import TestService
|
from test_service import TestService
|
||||||
|
|
||||||
|
|
||||||
class DITesterService:
|
class DITesterService:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from cpl.application import ApplicationBuilder
|
from cpl.application import ApplicationBuilder
|
||||||
|
|
||||||
from di.application import Application
|
from application import Application
|
||||||
from di.startup import Startup
|
from startup import Startup
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
from cpl.application.abc import StartupABC
|
from cpl.application.abc import StartupABC
|
||||||
from cpl.dependency import ServiceProvider, ServiceCollection
|
from cpl.dependency import ServiceProvider, ServiceCollection
|
||||||
from di.di_tester_service import DITesterService
|
from di_tester_service import DITesterService
|
||||||
from di.test1_service import Test1Service
|
from test1_service import Test1Service
|
||||||
from di.test2_service import Test2Service
|
from test2_service import Test2Service
|
||||||
from di.test_abc import TestABC
|
from test_abc import TestABC
|
||||||
from di.test_service import TestService
|
from test_service import TestService
|
||||||
from di.tester import Tester
|
from tester import Tester
|
||||||
|
|
||||||
|
|
||||||
class Startup(StartupABC):
|
class Startup(StartupABC):
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from cpl.dependency import ServiceProvider, ServiceProvider
|
from cpl.dependency import ServiceProvider, ServiceProvider
|
||||||
from cpl.dependency.inject import inject
|
from cpl.dependency.inject import inject
|
||||||
from di.test_service import TestService
|
from test_service import TestService
|
||||||
|
|
||||||
|
|
||||||
class StaticTest:
|
class StaticTest:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import string
|
import string
|
||||||
from cpl.core.console.console import Console
|
from cpl.core.console.console import Console
|
||||||
from cpl.core.utils.string import String
|
from cpl.core.utils.string import String
|
||||||
from di.test_abc import TestABC
|
from test_abc import TestABC
|
||||||
|
|
||||||
|
|
||||||
class Test1Service(TestABC):
|
class Test1Service(TestABC):
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import string
|
import string
|
||||||
from cpl.core.console.console import Console
|
from cpl.core.console.console import Console
|
||||||
from cpl.core.utils.string import String
|
from cpl.core.utils.string import String
|
||||||
from di.test_abc import TestABC
|
from test_abc import TestABC
|
||||||
|
|
||||||
|
|
||||||
class Test2Service(TestABC):
|
class Test2Service(TestABC):
|
||||||
7
example/di/src/tester.py
Normal file
7
example/di/src/tester.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from cpl.core.console.console import Console
|
||||||
|
from test_abc import TestABC
|
||||||
|
|
||||||
|
|
||||||
|
class Tester:
|
||||||
|
def __init__(self, t1: TestABC, t2: TestABC, t3: TestABC, t: list[TestABC]):
|
||||||
|
Console.write_line("Tester:", t, t1, t2, t3)
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import time
|
import time
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from cpl.application.abc import ApplicationABC
|
from cpl.application.abc import ApplicationABC
|
||||||
from cpl.core.configuration import Configuration
|
from cpl.core.configuration import Configuration
|
||||||
from cpl.core.console import Console
|
from cpl.core.console import Console
|
||||||
from cpl.dependency import ServiceProvider
|
|
||||||
from cpl.core.environment import Environment
|
from cpl.core.environment import Environment
|
||||||
from cpl.core.log import LoggerABC
|
from cpl.core.log import LoggerABC
|
||||||
from cpl.core.pipes import IPAddressPipe
|
from cpl.core.pipes import IPAddressPipe
|
||||||
|
from cpl.dependency import ServiceProvider
|
||||||
from cpl.mail import EMail, EMailClientABC
|
from cpl.mail import EMail, EMailClientABC
|
||||||
from cpl.query import List
|
from cpl.query import List
|
||||||
from general.scoped_service import ScopedService
|
from scoped_service import ScopedService
|
||||||
from test_service import TestService
|
from test_service import TestService
|
||||||
from test_settings import TestSettings
|
from test_settings import TestSettings
|
||||||
|
|
||||||
@@ -74,3 +73,9 @@ class Application(ApplicationABC):
|
|||||||
test_settings1 = Configuration.get(TestSettings)
|
test_settings1 = Configuration.get(TestSettings)
|
||||||
Console.write_line(test_settings1.value)
|
Console.write_line(test_settings1.value)
|
||||||
# self.test_send_mail()
|
# self.test_send_mail()
|
||||||
|
|
||||||
|
x = 0
|
||||||
|
while x < 5:
|
||||||
|
Console.write_line("Running...")
|
||||||
|
x += 1
|
||||||
|
time.sleep(5)
|
||||||
20
example/general/src/hosted_service.py
Normal file
20
example/general/src/hosted_service.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
|
||||||
|
from cpl.core.console import Console
|
||||||
|
from cpl.dependency.hosted.hosted_service import HostedService
|
||||||
|
|
||||||
|
|
||||||
|
class Hosted(HostedService):
|
||||||
|
def __init__(self):
|
||||||
|
self._stopped = False
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
Console.write_line("Hosted Service Started")
|
||||||
|
while not self._stopped:
|
||||||
|
Console.write_line("Hosted Service Running")
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
Console.write_line("Hosted Service Stopped")
|
||||||
|
self._stopped = True
|
||||||
@@ -4,7 +4,9 @@ from cpl.core.configuration import Configuration
|
|||||||
from cpl.core.environment import Environment
|
from cpl.core.environment import Environment
|
||||||
from cpl.core.pipes import IPAddressPipe
|
from cpl.core.pipes import IPAddressPipe
|
||||||
from cpl.dependency import ServiceCollection
|
from cpl.dependency import ServiceCollection
|
||||||
from general.scoped_service import ScopedService
|
from cpl.mail.mail_module import MailModule
|
||||||
|
from hosted_service import Hosted
|
||||||
|
from scoped_service import ScopedService
|
||||||
from test_service import TestService
|
from test_service import TestService
|
||||||
|
|
||||||
|
|
||||||
@@ -19,7 +21,8 @@ class Startup(StartupABC):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def configure_services(services: ServiceCollection):
|
def configure_services(services: ServiceCollection):
|
||||||
services.add_logging()
|
services.add_logging()
|
||||||
services.add_module(mail)
|
services.add_module(MailModule)
|
||||||
services.add_transient(IPAddressPipe)
|
services.add_transient(IPAddressPipe)
|
||||||
services.add_singleton(TestService)
|
services.add_singleton(TestService)
|
||||||
services.add_scoped(ScopedService)
|
services.add_scoped(ScopedService)
|
||||||
|
services.add_hosted_service(Hosted)
|
||||||
@@ -48,9 +48,9 @@ def t_benchmark(data: list):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
N = 10_000_000
|
N = 1_000_000
|
||||||
data = list(range(N))
|
data = list(range(N))
|
||||||
#t_benchmark(data)
|
t_benchmark(data)
|
||||||
|
|
||||||
Console.write_line()
|
Console.write_line()
|
||||||
_default()
|
_default()
|
||||||
@@ -1,36 +1,4 @@
|
|||||||
from cpl.dependency.service_collection import ServiceCollection as _ServiceCollection
|
|
||||||
|
|
||||||
from .error import APIError, AlreadyExists, EndpointNotImplemented, Forbidden, NotFound, Unauthorized
|
from .error import APIError, AlreadyExists, EndpointNotImplemented, Forbidden, NotFound, Unauthorized
|
||||||
from .logger import APILogger
|
from .logger import APILogger
|
||||||
from .settings import ApiSettings
|
from .settings import ApiSettings
|
||||||
|
from .api_module import ApiModule
|
||||||
|
|
||||||
def add_api(collection: _ServiceCollection):
|
|
||||||
try:
|
|
||||||
from cpl.database import mysql
|
|
||||||
|
|
||||||
collection.add_module(mysql)
|
|
||||||
except ImportError as e:
|
|
||||||
from cpl.core.errors import dependency_error
|
|
||||||
|
|
||||||
dependency_error("cpl-database", e)
|
|
||||||
|
|
||||||
try:
|
|
||||||
from cpl import auth
|
|
||||||
from cpl.auth import permission
|
|
||||||
|
|
||||||
collection.add_module(auth)
|
|
||||||
collection.add_module(permission)
|
|
||||||
except ImportError as e:
|
|
||||||
from cpl.core.errors import dependency_error
|
|
||||||
|
|
||||||
dependency_error("cpl-auth", e)
|
|
||||||
|
|
||||||
from cpl.api.registry.policy import PolicyRegistry
|
|
||||||
from cpl.api.registry.route import RouteRegistry
|
|
||||||
|
|
||||||
collection.add_singleton(PolicyRegistry)
|
|
||||||
collection.add_singleton(RouteRegistry)
|
|
||||||
|
|
||||||
|
|
||||||
_ServiceCollection.with_module(add_api, __name__)
|
|
||||||
|
|||||||
22
src/cpl-api/cpl/api/api_module.py
Normal file
22
src/cpl-api/cpl/api/api_module.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from cpl.api import ApiSettings
|
||||||
|
from cpl.api.registry.policy import PolicyRegistry
|
||||||
|
from cpl.api.registry.route import RouteRegistry
|
||||||
|
from cpl.auth.auth_module import AuthModule
|
||||||
|
from cpl.auth.permission.permission_module import PermissionsModule
|
||||||
|
from cpl.database.database_module import DatabaseModule
|
||||||
|
from cpl.dependency import ServiceCollection
|
||||||
|
from cpl.dependency.module.module import Module
|
||||||
|
|
||||||
|
|
||||||
|
class ApiModule(Module):
|
||||||
|
config = [ApiSettings]
|
||||||
|
singleton = [
|
||||||
|
PolicyRegistry,
|
||||||
|
RouteRegistry,
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def register(collection: ServiceCollection):
|
||||||
|
collection.add_module(DatabaseModule)
|
||||||
|
collection.add_module(AuthModule)
|
||||||
|
collection.add_module(PermissionsModule)
|
||||||
@@ -10,7 +10,7 @@ from starlette.requests import Request
|
|||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
from starlette.types import ExceptionHandler
|
from starlette.types import ExceptionHandler
|
||||||
|
|
||||||
from cpl import api, auth
|
from cpl.api.api_module import ApiModule
|
||||||
from cpl.api.error import APIError
|
from cpl.api.error import APIError
|
||||||
from cpl.api.logger import APILogger
|
from cpl.api.logger import APILogger
|
||||||
from cpl.api.middleware.authentication import AuthenticationMiddleware
|
from cpl.api.middleware.authentication import AuthenticationMiddleware
|
||||||
@@ -26,16 +26,19 @@ from cpl.api.router import Router
|
|||||||
from cpl.api.settings import ApiSettings
|
from cpl.api.settings import ApiSettings
|
||||||
from cpl.api.typing import HTTPMethods, PartialMiddleware, PolicyResolver
|
from cpl.api.typing import HTTPMethods, PartialMiddleware, PolicyResolver
|
||||||
from cpl.application.abc.application_abc import ApplicationABC
|
from cpl.application.abc.application_abc import ApplicationABC
|
||||||
from cpl.core.configuration import Configuration
|
from cpl.auth.auth_module import AuthModule
|
||||||
|
from cpl.auth.permission.permission_module import PermissionsModule
|
||||||
|
from cpl.core.configuration.configuration import Configuration
|
||||||
from cpl.dependency.inject import inject
|
from cpl.dependency.inject import inject
|
||||||
from cpl.dependency.service_provider import ServiceProvider
|
from cpl.dependency.service_provider import ServiceProvider
|
||||||
|
from cpl.dependency.typing import Modules
|
||||||
|
|
||||||
PolicyInput = Union[dict[str, PolicyResolver], Policy]
|
PolicyInput = Union[dict[str, PolicyResolver], Policy]
|
||||||
|
|
||||||
|
|
||||||
class WebApp(ApplicationABC):
|
class WebApp(ApplicationABC):
|
||||||
def __init__(self, services: ServiceProvider):
|
def __init__(self, services: ServiceProvider, modules: Modules):
|
||||||
super().__init__(services, [auth, api])
|
super().__init__(services, modules, [AuthModule, PermissionsModule, ApiModule])
|
||||||
self._app: Starlette | None = None
|
self._app: Starlette | None = None
|
||||||
|
|
||||||
self._logger = services.get_service(APILogger)
|
self._logger = services.get_service(APILogger)
|
||||||
@@ -75,11 +78,6 @@ class WebApp(ApplicationABC):
|
|||||||
self._logger.debug(f"Allowed origins: {origins}")
|
self._logger.debug(f"Allowed origins: {origins}")
|
||||||
return origins.split(",")
|
return origins.split(",")
|
||||||
|
|
||||||
def with_database(self) -> Self:
|
|
||||||
self.with_migrations()
|
|
||||||
self.with_seeders()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def with_app(self, app: Starlette) -> Self:
|
def with_app(self, app: Starlette) -> Self:
|
||||||
assert app is not None, "app must not be None"
|
assert app is not None, "app must not be None"
|
||||||
assert isinstance(app, Starlette), "app must be an instance of Starlette"
|
assert isinstance(app, Starlette), "app must be an instance of Starlette"
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
from .application_builder import ApplicationBuilder
|
from .application_builder import ApplicationBuilder
|
||||||
|
from .host import Host
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ from abc import ABC, abstractmethod
|
|||||||
from typing import Callable, Self
|
from typing import Callable, Self
|
||||||
|
|
||||||
from cpl.application.host import Host
|
from cpl.application.host import Host
|
||||||
|
from cpl.core.errors import module_dependency_error
|
||||||
from cpl.core.log.log_level import LogLevel
|
from cpl.core.log.log_level import LogLevel
|
||||||
from cpl.core.log.log_settings import LogSettings
|
from cpl.core.log.log_settings import LogSettings
|
||||||
from cpl.core.log.logger_abc import LoggerABC
|
from cpl.core.log.logger_abc import LoggerABC
|
||||||
from cpl.dependency.service_provider import ServiceProvider
|
from cpl.dependency.service_provider import ServiceProvider
|
||||||
|
from cpl.dependency.typing import TModule
|
||||||
|
|
||||||
|
|
||||||
def __not_implemented__(package: str, func: Callable):
|
def __not_implemented__(package: str, func: Callable):
|
||||||
@@ -20,17 +22,6 @@ class ApplicationABC(ABC):
|
|||||||
Contains instances of prepared objects
|
Contains instances of prepared objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def __init__(self, services: ServiceProvider, required_modules: list[str | object] = None):
|
|
||||||
self._services = services
|
|
||||||
self._required_modules = (
|
|
||||||
[x.__name__ if not isinstance(x, str) else x for x in required_modules] if required_modules else []
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def required_modules(self) -> list[str]:
|
|
||||||
return self._required_modules
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extend(cls, name: str | Callable, func: Callable[[Self], Self]):
|
def extend(cls, name: str | Callable, func: Callable[[Self], Self]):
|
||||||
r"""Extend the Application with a custom method
|
r"""Extend the Application with a custom method
|
||||||
@@ -47,6 +38,30 @@ class ApplicationABC(ABC):
|
|||||||
setattr(cls, name, func)
|
setattr(cls, name, func)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(
|
||||||
|
self, services: ServiceProvider, loaded_modules: set[TModule], required_modules: list[str | object] = None
|
||||||
|
):
|
||||||
|
self._services = services
|
||||||
|
self._modules = loaded_modules
|
||||||
|
self._required_modules = (
|
||||||
|
[x.__name__ if not isinstance(x, str) else x for x in required_modules] if required_modules else []
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_app_required_modules(self):
|
||||||
|
modules_names = {x.__name__ for x in self._modules}
|
||||||
|
for module in self._required_modules:
|
||||||
|
if module in modules_names:
|
||||||
|
continue
|
||||||
|
|
||||||
|
module_dependency_error(
|
||||||
|
type(self).__name__,
|
||||||
|
module.__name__,
|
||||||
|
ImportError(
|
||||||
|
f"Required module '{module}' for application '{self.__class__.__name__}' is not loaded. Load using 'add_module({module})' method."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def with_logging(self, level: LogLevel = None):
|
def with_logging(self, level: LogLevel = None):
|
||||||
if level is None:
|
if level is None:
|
||||||
from cpl.core.configuration.configuration import Configuration
|
from cpl.core.configuration.configuration import Configuration
|
||||||
@@ -57,14 +72,21 @@ class ApplicationABC(ABC):
|
|||||||
logger = self._services.get_service(LoggerABC)
|
logger = self._services.get_service(LoggerABC)
|
||||||
logger.set_level(level)
|
logger.set_level(level)
|
||||||
|
|
||||||
def with_permissions(self, *args, **kwargs):
|
def with_permissions(self, *args):
|
||||||
|
try:
|
||||||
|
from cpl.auth import AuthModule
|
||||||
|
|
||||||
|
AuthModule.with_permissions(*args)
|
||||||
|
except ImportError:
|
||||||
__not_implemented__("cpl-auth", self.with_permissions)
|
__not_implemented__("cpl-auth", self.with_permissions)
|
||||||
|
|
||||||
def with_migrations(self, *args, **kwargs):
|
def with_migrations(self, *args):
|
||||||
__not_implemented__("cpl-database", self.with_migrations)
|
try:
|
||||||
|
from cpl.database.database_module import DatabaseModule
|
||||||
|
|
||||||
def with_seeders(self, *args, **kwargs):
|
DatabaseModule.with_migrations(self._services, *args)
|
||||||
__not_implemented__("cpl-database", self.with_seeders)
|
except ImportError:
|
||||||
|
__not_implemented__("cpl-database", self.with_migrations)
|
||||||
|
|
||||||
def with_extension(self, func: Callable[[Self, ...], None], *args, **kwargs):
|
def with_extension(self, func: Callable[[Self, ...], None], *args, **kwargs):
|
||||||
r"""Extend the Application with a custom method
|
r"""Extend the Application with a custom method
|
||||||
@@ -84,7 +106,12 @@ class ApplicationABC(ABC):
|
|||||||
Called by custom Application.main
|
Called by custom Application.main
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Host.run(self.main)
|
for module in self._modules:
|
||||||
|
if not hasattr(module, "configure") and not callable(getattr(module, "configure")):
|
||||||
|
continue
|
||||||
|
module.configure(self._services)
|
||||||
|
|
||||||
|
Host.run_app(self.main)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -43,18 +43,6 @@ class ApplicationBuilder(Generic[TApp]):
|
|||||||
|
|
||||||
return provider
|
return provider
|
||||||
|
|
||||||
def validate_app_required_modules(self, app: ApplicationABC):
|
|
||||||
for module in app.required_modules:
|
|
||||||
if module in self._services.loaded_modules:
|
|
||||||
continue
|
|
||||||
|
|
||||||
dependency_error(
|
|
||||||
module,
|
|
||||||
ImportError(
|
|
||||||
f"Required module '{module}' for application '{app.__class__.__name__}' is not loaded. Load using 'add_module({module})' method."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def with_startup(self, startup: Type[StartupABC]) -> "ApplicationBuilder":
|
def with_startup(self, startup: Type[StartupABC]) -> "ApplicationBuilder":
|
||||||
self._startup = startup
|
self._startup = startup
|
||||||
return self
|
return self
|
||||||
@@ -82,6 +70,7 @@ class ApplicationBuilder(Generic[TApp]):
|
|||||||
for extension in self._app_extensions:
|
for extension in self._app_extensions:
|
||||||
Host.run(extension.run, self.service_provider)
|
Host.run(extension.run, self.service_provider)
|
||||||
|
|
||||||
app = self._app(self.service_provider)
|
use_root_provider(self._services.build())
|
||||||
self.validate_app_required_modules(app)
|
app = self._app(self.service_provider, self._services.loaded_modules)
|
||||||
|
app.validate_app_required_modules()
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -1,17 +1,80 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
|
from cpl.dependency import get_provider
|
||||||
|
from cpl.dependency.hosted.startup_task import StartupTask
|
||||||
|
|
||||||
|
|
||||||
class Host:
|
class Host:
|
||||||
_loop = asyncio.get_event_loop()
|
_loop: asyncio.AbstractEventLoop | None = None
|
||||||
|
_tasks: dict = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_loop(cls):
|
def get_loop(cls) -> asyncio.AbstractEventLoop:
|
||||||
|
if cls._loop is None:
|
||||||
|
cls._loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(cls._loop)
|
||||||
return cls._loop
|
return cls._loop
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_start_tasks(cls):
|
||||||
|
provider = get_provider()
|
||||||
|
tasks = provider.get_services(StartupTask)
|
||||||
|
loop = cls.get_loop()
|
||||||
|
|
||||||
|
for task in tasks:
|
||||||
|
if asyncio.iscoroutinefunction(task.run):
|
||||||
|
loop.run_until_complete(task.run())
|
||||||
|
else:
|
||||||
|
task.run()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_hosted_services(cls):
|
||||||
|
provider = get_provider()
|
||||||
|
services = provider.get_hosted_services()
|
||||||
|
loop = cls.get_loop()
|
||||||
|
|
||||||
|
for service in services:
|
||||||
|
if asyncio.iscoroutinefunction(service.start):
|
||||||
|
cls._tasks[service] = loop.create_task(service.start())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def _stop_all(cls):
|
||||||
|
for service in cls._tasks.keys():
|
||||||
|
if asyncio.iscoroutinefunction(service.stop):
|
||||||
|
await service.stop()
|
||||||
|
|
||||||
|
for task in cls._tasks.values():
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
cls._tasks.clear()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_app(cls, func: Callable, *args, **kwargs):
|
||||||
|
cls.run_start_tasks()
|
||||||
|
cls.run_hosted_services()
|
||||||
|
|
||||||
|
async def runner():
|
||||||
|
try:
|
||||||
|
if asyncio.iscoroutinefunction(func):
|
||||||
|
app_task = asyncio.create_task(func(*args, **kwargs))
|
||||||
|
else:
|
||||||
|
app_task = cls.get_loop().run_in_executor(None, func, *args, **kwargs)
|
||||||
|
|
||||||
|
await asyncio.wait(
|
||||||
|
[app_task, *cls._tasks.values()],
|
||||||
|
return_when=asyncio.FIRST_COMPLETED,
|
||||||
|
)
|
||||||
|
except (KeyboardInterrupt, asyncio.CancelledError):
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
await cls._stop_all()
|
||||||
|
|
||||||
|
cls.get_loop().run_until_complete(runner())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls, func: Callable, *args, **kwargs):
|
def run(cls, func: Callable, *args, **kwargs):
|
||||||
if asyncio.iscoroutinefunction(func):
|
if asyncio.iscoroutinefunction(func):
|
||||||
return cls._loop.run_until_complete(func(*args, **kwargs))
|
return cls.get_loop().run_until_complete(func(*args, **kwargs))
|
||||||
|
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|||||||
@@ -1,84 +1,6 @@
|
|||||||
from enum import Enum
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
from cpl.application.abc import ApplicationABC as _ApplicationABC
|
|
||||||
from cpl.auth import permission as _permission
|
from cpl.auth import permission as _permission
|
||||||
from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin
|
from cpl.auth.keycloak.keycloak_admin import KeycloakAdmin as _KeycloakAdmin
|
||||||
from cpl.auth.keycloak.keycloak_client import KeycloakClient as _KeycloakClient
|
from cpl.auth.keycloak.keycloak_client import KeycloakClient as _KeycloakClient
|
||||||
from cpl.dependency.service_collection import ServiceCollection as _ServiceCollection
|
from .auth_module import AuthModule
|
||||||
from .logger import AuthLogger
|
|
||||||
from .keycloak_settings import KeycloakSettings
|
from .keycloak_settings import KeycloakSettings
|
||||||
from .permission_seeder import PermissionSeeder
|
from .logger import AuthLogger
|
||||||
|
|
||||||
|
|
||||||
def _with_permissions(self: _ApplicationABC, *permissions: Type[Enum]) -> _ApplicationABC:
|
|
||||||
from cpl.auth.permission.permissions_registry import PermissionsRegistry
|
|
||||||
|
|
||||||
for perm in permissions:
|
|
||||||
PermissionsRegistry.with_enum(perm)
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def _add_daos(collection: _ServiceCollection):
|
|
||||||
from .schema._administration.auth_user_dao import AuthUserDao
|
|
||||||
from .schema._administration.api_key_dao import ApiKeyDao
|
|
||||||
from .schema._permission.api_key_permission_dao import ApiKeyPermissionDao
|
|
||||||
from .schema._permission.permission_dao import PermissionDao
|
|
||||||
from .schema._permission.role_dao import RoleDao
|
|
||||||
from .schema._permission.role_permission_dao import RolePermissionDao
|
|
||||||
from .schema._permission.role_user_dao import RoleUserDao
|
|
||||||
|
|
||||||
collection.add_singleton(AuthUserDao)
|
|
||||||
collection.add_singleton(ApiKeyDao)
|
|
||||||
collection.add_singleton(ApiKeyPermissionDao)
|
|
||||||
collection.add_singleton(PermissionDao)
|
|
||||||
collection.add_singleton(RoleDao)
|
|
||||||
collection.add_singleton(RolePermissionDao)
|
|
||||||
collection.add_singleton(RoleUserDao)
|
|
||||||
|
|
||||||
|
|
||||||
def add_auth(collection: _ServiceCollection):
|
|
||||||
import os
|
|
||||||
|
|
||||||
try:
|
|
||||||
from cpl.database.service.migration_service import MigrationService
|
|
||||||
from cpl.database.model.server_type import ServerType, ServerTypes
|
|
||||||
|
|
||||||
collection.add_singleton(_KeycloakClient)
|
|
||||||
collection.add_singleton(_KeycloakAdmin)
|
|
||||||
|
|
||||||
_add_daos(collection)
|
|
||||||
|
|
||||||
provider = collection.build()
|
|
||||||
migration_service: MigrationService = provider.get_service(MigrationService)
|
|
||||||
if ServerType.server_type == ServerTypes.POSTGRES:
|
|
||||||
migration_service.with_directory(
|
|
||||||
os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/postgres")
|
|
||||||
)
|
|
||||||
elif ServerType.server_type == ServerTypes.MYSQL:
|
|
||||||
migration_service.with_directory(os.path.join(os.path.dirname(os.path.realpath(__file__)), "scripts/mysql"))
|
|
||||||
except ImportError as e:
|
|
||||||
from cpl.core.console import Console
|
|
||||||
|
|
||||||
Console.error("cpl-database is not installed", str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def add_permission(collection: _ServiceCollection):
|
|
||||||
from .permission_seeder import PermissionSeeder
|
|
||||||
from .permission.permissions_registry import PermissionsRegistry
|
|
||||||
from .permission.permissions import Permissions
|
|
||||||
|
|
||||||
try:
|
|
||||||
from cpl.database.abc.data_seeder_abc import DataSeederABC
|
|
||||||
|
|
||||||
collection.add_singleton(DataSeederABC, PermissionSeeder)
|
|
||||||
PermissionsRegistry.with_enum(Permissions)
|
|
||||||
except ImportError as e:
|
|
||||||
from cpl.core.console import Console
|
|
||||||
|
|
||||||
Console.error("cpl-database is not installed", str(e))
|
|
||||||
|
|
||||||
|
|
||||||
_ServiceCollection.with_module(add_auth, __name__)
|
|
||||||
_ServiceCollection.with_module(add_permission, _permission.__name__)
|
|
||||||
_ApplicationABC.extend(_ApplicationABC.with_permissions, _with_permissions)
|
|
||||||
|
|||||||
56
src/cpl-auth/cpl/auth/auth_module.py
Normal file
56
src/cpl-auth/cpl/auth/auth_module.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import os
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
|
from cpl.auth.keycloak_settings import KeycloakSettings
|
||||||
|
from cpl.database.database_module import DatabaseModule
|
||||||
|
from cpl.database.model.server_type import ServerType, ServerTypes
|
||||||
|
from cpl.database.mysql.mysql_module import MySQLModule
|
||||||
|
from cpl.database.postgres.postgres_module import PostgresModule
|
||||||
|
from cpl.dependency.module.module import Module
|
||||||
|
from cpl.dependency.service_provider import ServiceProvider
|
||||||
|
from .keycloak.keycloak_admin import KeycloakAdmin
|
||||||
|
from .keycloak.keycloak_client import KeycloakClient
|
||||||
|
from .schema._administration.api_key_dao import ApiKeyDao
|
||||||
|
from .schema._administration.auth_user_dao import AuthUserDao
|
||||||
|
from .schema._permission.api_key_permission_dao import ApiKeyPermissionDao
|
||||||
|
from .schema._permission.permission_dao import PermissionDao
|
||||||
|
from .schema._permission.role_dao import RoleDao
|
||||||
|
from .schema._permission.role_permission_dao import RolePermissionDao
|
||||||
|
from .schema._permission.role_user_dao import RoleUserDao
|
||||||
|
|
||||||
|
|
||||||
|
class AuthModule(Module):
|
||||||
|
dependencies = [DatabaseModule, (MySQLModule, PostgresModule)]
|
||||||
|
config = [KeycloakSettings]
|
||||||
|
singleton = [
|
||||||
|
KeycloakClient,
|
||||||
|
KeycloakAdmin,
|
||||||
|
AuthUserDao,
|
||||||
|
ApiKeyDao,
|
||||||
|
ApiKeyPermissionDao,
|
||||||
|
PermissionDao,
|
||||||
|
RoleDao,
|
||||||
|
RolePermissionDao,
|
||||||
|
RoleUserDao,
|
||||||
|
]
|
||||||
|
scoped = []
|
||||||
|
transient = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def configure(provider: ServiceProvider):
|
||||||
|
paths = {
|
||||||
|
ServerTypes.POSTGRES: "scripts/postgres",
|
||||||
|
ServerTypes.MYSQL: "scripts/mysql",
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseModule.with_migrations(
|
||||||
|
provider, str(os.path.join(os.path.dirname(os.path.realpath(__file__)), paths[ServerType.server_type]))
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def with_permissions(*permissions: Type[Enum]):
|
||||||
|
from cpl.auth.permission.permissions_registry import PermissionsRegistry
|
||||||
|
|
||||||
|
for perm in permissions:
|
||||||
|
PermissionsRegistry.with_enum(perm)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from .permission_module import PermissionsModule
|
||||||
|
from .permission_seeder import PermissionSeeder
|
||||||
|
from .permissions import Permissions
|
||||||
|
from .permissions_registry import PermissionsRegistry
|
||||||
|
|||||||
17
src/cpl-auth/cpl/auth/permission/permission_module.py
Normal file
17
src/cpl-auth/cpl/auth/permission/permission_module.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from cpl.auth.auth_module import AuthModule
|
||||||
|
from cpl.auth.permission.permission_seeder import PermissionSeeder
|
||||||
|
from cpl.auth.permission.permissions import Permissions
|
||||||
|
from cpl.auth.permission.permissions_registry import PermissionsRegistry
|
||||||
|
from cpl.database.abc.data_seeder_abc import DataSeederABC
|
||||||
|
from cpl.database.database_module import DatabaseModule
|
||||||
|
from cpl.dependency.module.module import Module
|
||||||
|
from cpl.dependency.service_collection import ServiceCollection
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsModule(Module):
|
||||||
|
dependencies = [DatabaseModule, AuthModule]
|
||||||
|
singleton = [(DataSeederABC, PermissionSeeder)]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def register(collection: ServiceCollection):
|
||||||
|
PermissionsRegistry.with_enum(Permissions)
|
||||||
@@ -3,13 +3,25 @@ import traceback
|
|||||||
from cpl.core.console import Console
|
from cpl.core.console import Console
|
||||||
|
|
||||||
|
|
||||||
def dependency_error(package_name: str, e: ImportError) -> None:
|
def dependency_error(src: str, package_name: str, e: ImportError = None) -> None:
|
||||||
Console.error(f"'{package_name}' is required to use this feature. Please install it and try again.")
|
Console.error(f"'{package_name}' is required to use feature: {src}. Please install it and try again.")
|
||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
if not tb.startswith("NoneType: None"):
|
if not tb.startswith("NoneType: None"):
|
||||||
Console.write_line("->", tb)
|
Console.error("->", tb)
|
||||||
|
|
||||||
elif e is not None:
|
elif e is not None:
|
||||||
Console.write_line("->", str(e))
|
Console.error(f"-> {str(e)}")
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def module_dependency_error(src: str, module: str, e: ImportError = None) -> None:
|
||||||
|
Console.error(f"'{module}' is required by '{src}'. Please initialize it with `add_module({module})`.")
|
||||||
|
tb = traceback.format_exc()
|
||||||
|
if not tb.startswith("NoneType: None"):
|
||||||
|
Console.error("->", tb)
|
||||||
|
|
||||||
|
elif e is not None:
|
||||||
|
Console.error(f"-> {str(e)}")
|
||||||
|
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -1,77 +1,5 @@
|
|||||||
import os
|
|
||||||
from typing import Type
|
|
||||||
|
|
||||||
from cpl.application.abc import ApplicationABC as _ApplicationABC
|
|
||||||
from cpl.dependency import ServiceCollection as _ServiceCollection
|
|
||||||
from . import mysql as _mysql
|
from . import mysql as _mysql
|
||||||
from . import postgres as _postgres
|
from . import postgres as _postgres
|
||||||
|
from .database_module import DatabaseModule
|
||||||
|
from .logger import DBLogger
|
||||||
from .table_manager import TableManager
|
from .table_manager import TableManager
|
||||||
|
|
||||||
|
|
||||||
def _with_migrations(self: _ApplicationABC, *paths: str | list[str]) -> _ApplicationABC:
|
|
||||||
from cpl.application.host import Host
|
|
||||||
from cpl.database.service.migration_service import MigrationService
|
|
||||||
|
|
||||||
migration_service = self._services.get_service(MigrationService)
|
|
||||||
migration_service.with_directory(os.path.join(os.path.dirname(os.path.abspath(__file__)), "scripts"))
|
|
||||||
|
|
||||||
if isinstance(paths, str):
|
|
||||||
paths = [paths]
|
|
||||||
|
|
||||||
for path in paths:
|
|
||||||
migration_service.with_directory(path)
|
|
||||||
|
|
||||||
Host.run(migration_service.migrate)
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def _with_seeders(self: _ApplicationABC) -> _ApplicationABC:
|
|
||||||
from cpl.database.service.seeder_service import SeederService
|
|
||||||
from cpl.application.host import Host
|
|
||||||
|
|
||||||
seeder_service: SeederService = self._services.get_service(SeederService)
|
|
||||||
Host.run(seeder_service.seed)
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def _add(collection: _ServiceCollection, db_context: Type, default_port: int, server_type: str):
|
|
||||||
from cpl.core.console import Console
|
|
||||||
from cpl.core.configuration import Configuration
|
|
||||||
from cpl.database.abc.db_context_abc import DBContextABC
|
|
||||||
from cpl.database.model.server_type import ServerTypes, ServerType
|
|
||||||
from cpl.database.model.database_settings import DatabaseSettings
|
|
||||||
from cpl.database.service.migration_service import MigrationService
|
|
||||||
from cpl.database.service.seeder_service import SeederService
|
|
||||||
from cpl.database.schema.executed_migration_dao import ExecutedMigrationDao
|
|
||||||
|
|
||||||
try:
|
|
||||||
ServerType.set_server_type(ServerTypes(server_type))
|
|
||||||
Configuration.set("DB_DEFAULT_PORT", default_port)
|
|
||||||
|
|
||||||
collection.add_singleton(DBContextABC, db_context)
|
|
||||||
collection.add_singleton(ExecutedMigrationDao)
|
|
||||||
collection.add_singleton(MigrationService)
|
|
||||||
collection.add_singleton(SeederService)
|
|
||||||
except ImportError as e:
|
|
||||||
Console.error("cpl-database is not installed", str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def add_mysql(collection: _ServiceCollection):
|
|
||||||
from cpl.database.mysql.db_context import DBContext
|
|
||||||
from cpl.database.model import ServerTypes
|
|
||||||
|
|
||||||
_add(collection, DBContext, 3306, ServerTypes.MYSQL.value)
|
|
||||||
|
|
||||||
|
|
||||||
def add_postgres(collection: _ServiceCollection):
|
|
||||||
from cpl.database.mysql.db_context import DBContext
|
|
||||||
from cpl.database.model import ServerTypes
|
|
||||||
|
|
||||||
_add(collection, DBContext, 5432, ServerTypes.POSTGRES.value)
|
|
||||||
|
|
||||||
|
|
||||||
_ServiceCollection.with_module(add_mysql, _mysql.__name__)
|
|
||||||
_ServiceCollection.with_module(add_postgres, _postgres.__name__)
|
|
||||||
_ApplicationABC.extend(_ApplicationABC.with_migrations, _with_migrations)
|
|
||||||
_ApplicationABC.extend(_ApplicationABC.with_seeders, _with_seeders)
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from .connection_abc import ConnectionABC
|
from .connection_abc import ConnectionABC
|
||||||
|
from .data_access_object_abc import DataAccessObjectABC
|
||||||
|
from .data_seeder_abc import DataSeederABC
|
||||||
from .db_context_abc import DBContextABC
|
from .db_context_abc import DBContextABC
|
||||||
from .db_join_model_abc import DbJoinModelABC
|
from .db_join_model_abc import DbJoinModelABC
|
||||||
from .db_model_abc import DbModelABC
|
from .db_model_abc import DbModelABC
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ from cpl.database.abc.db_context_abc import DBContextABC
|
|||||||
from cpl.database.const import DATETIME_FORMAT
|
from cpl.database.const import DATETIME_FORMAT
|
||||||
from cpl.database.external_data_temp_table_builder import ExternalDataTempTableBuilder
|
from cpl.database.external_data_temp_table_builder import ExternalDataTempTableBuilder
|
||||||
from cpl.database.logger import DBLogger
|
from cpl.database.logger import DBLogger
|
||||||
|
from cpl.database.model.server_type import ServerType, ServerTypes
|
||||||
from cpl.database.postgres.sql_select_builder import SQLSelectBuilder
|
from cpl.database.postgres.sql_select_builder import SQLSelectBuilder
|
||||||
from cpl.database.typing import T_DBM, Attribute, AttributeFilters, AttributeSorts
|
from cpl.database.typing import T_DBM, Attribute, AttributeFilters, AttributeSorts
|
||||||
from cpl.dependency import get_provider
|
from cpl.dependency.context import get_provider
|
||||||
|
|
||||||
|
|
||||||
class DataAccessObjectABC(ABC, Generic[T_DBM]):
|
class DataAccessObjectABC(ABC, Generic[T_DBM]):
|
||||||
@@ -356,7 +357,7 @@ class DataAccessObjectABC(ABC, Generic[T_DBM]):
|
|||||||
) VALUES (
|
) VALUES (
|
||||||
{values}
|
{values}
|
||||||
)
|
)
|
||||||
RETURNING {self.__primary_key};
|
{"RETURNING {self.__primary_key};" if ServerType.server_type == ServerTypes.POSTGRES else ";SELECT LAST_INSERT_ID();"}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def create(self, obj: T_DBM, skip_editor=False) -> int:
|
async def create(self, obj: T_DBM, skip_editor=False) -> int:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from abc import abstractmethod
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
from cpl.database import TableManager
|
from cpl.database.table_manager import TableManager
|
||||||
from cpl.database.abc.data_access_object_abc import DataAccessObjectABC
|
from cpl.database.abc.data_access_object_abc import DataAccessObjectABC
|
||||||
from cpl.database.abc.db_model_abc import DbModelABC
|
from cpl.database.abc.db_model_abc import DbModelABC
|
||||||
|
|
||||||
|
|||||||
33
src/cpl-database/cpl/database/database_module.py
Normal file
33
src/cpl-database/cpl/database/database_module.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from cpl.database.model.database_settings import DatabaseSettings
|
||||||
|
from cpl.database.mysql.mysql_module import MySQLModule
|
||||||
|
from cpl.database.postgres.postgres_module import PostgresModule
|
||||||
|
from cpl.database.schema.executed_migration_dao import ExecutedMigrationDao
|
||||||
|
from cpl.database.service.migration_service import MigrationService
|
||||||
|
from cpl.database.service.seeder_service import SeederService
|
||||||
|
from cpl.dependency.module.module import Module
|
||||||
|
from cpl.dependency.service_provider import ServiceProvider
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseModule(Module):
|
||||||
|
dependencies = [(MySQLModule, PostgresModule)]
|
||||||
|
config = [DatabaseSettings]
|
||||||
|
singleton = [
|
||||||
|
ExecutedMigrationDao,
|
||||||
|
MigrationService,
|
||||||
|
SeederService,
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def configure(cls, provider: ServiceProvider): ...
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def with_migrations(services: ServiceProvider, *paths: str | list[str]):
|
||||||
|
from cpl.database.service.migration_service import MigrationService
|
||||||
|
|
||||||
|
migration_service = services.get_service(MigrationService)
|
||||||
|
|
||||||
|
if isinstance(paths, str):
|
||||||
|
paths = [paths]
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
migration_service.with_directory(path)
|
||||||
@@ -15,6 +15,11 @@ class ServerType:
|
|||||||
assert isinstance(server_type, ServerTypes), f"Expected ServerType but got {type(server_type)}"
|
assert isinstance(server_type, ServerTypes), f"Expected ServerType but got {type(server_type)}"
|
||||||
cls._server_type = server_type
|
cls._server_type = server_type
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@property
|
||||||
|
def has_server_type(cls) -> bool:
|
||||||
|
return cls._server_type is not None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@property
|
@property
|
||||||
def server_type(cls) -> ServerTypes:
|
def server_type(cls) -> ServerTypes:
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from .connection import DatabaseConnection
|
||||||
|
from .db_context import DBContext
|
||||||
|
from .mysql_module import MySQLModule
|
||||||
|
from .mysql_pool import MySQLPool
|
||||||
|
|||||||
17
src/cpl-database/cpl/database/mysql/mysql_module.py
Normal file
17
src/cpl-database/cpl/database/mysql/mysql_module.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from cpl.core.configuration.configuration import Configuration
|
||||||
|
from cpl.database.abc.db_context_abc import DBContextABC
|
||||||
|
from cpl.database.model.database_settings import DatabaseSettings
|
||||||
|
from cpl.database.model.server_type import ServerTypes, ServerType
|
||||||
|
from cpl.database.mysql.db_context import DBContext
|
||||||
|
from cpl.dependency.module.module import Module
|
||||||
|
from cpl.dependency.service_collection import ServiceCollection
|
||||||
|
|
||||||
|
|
||||||
|
class MySQLModule(Module):
|
||||||
|
config = [DatabaseSettings]
|
||||||
|
singleton = [(DBContextABC, DBContext)]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def register(collection: ServiceCollection):
|
||||||
|
ServerType.set_server_type(ServerTypes(ServerTypes.MYSQL.value))
|
||||||
|
Configuration.set("DB_DEFAULT_PORT", 3306)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user