Merge pull request '2020.12.7' (#4) from 2020.12.7 into 2020.12

Reviewed-on: http://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib/pulls/4
This commit is contained in:
Sven Heidemann 2020-11-29 17:31:30 +01:00
commit 6e10e5418e
58 changed files with 791 additions and 286 deletions

View File

@ -20,6 +20,7 @@ __version__ = '2020.12.5'
from collections import namedtuple from collections import namedtuple
# imports: # imports:
from .configuration import Configuration
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major=2020, minor=12, micro=5) version_info = VersionInfo(major=2020, minor=12, micro=5)

View File

@ -20,6 +20,7 @@ __version__ = '2020.12.5'
from collections import namedtuple from collections import namedtuple
# imports: # imports:
from .configuration_base import ConfigurationBase
from .configuration_model_base import ConfigurationModelBase from .configuration_model_base import ConfigurationModelBase
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')

View File

@ -1,23 +1,34 @@
from abc import abstractmethod from abc import abstractmethod, ABC
from collections import Callable from collections import Callable
from typing import Type
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
from sh_edraft.service.base.service_base import ServiceBase from sh_edraft.environment.base.environment_base import EnvironmentBase
class ConfigurationBase(ServiceBase): class ConfigurationBase(ABC):
@abstractmethod @abstractmethod
def __init__(self): def __init__(self): pass
ServiceBase.__init__(self)
self._config: dict[type, object] = {}
@property @property
@abstractmethod @abstractmethod
def config(self) -> dict[type, object]: pass def environment(self) -> EnvironmentBase: pass
@abstractmethod @abstractmethod
def add_config_by_type(self, key_type: type, value: object): pass def add_environment_variables(self, prefix: str): pass
@abstractmethod @abstractmethod
def get_config_by_type(self, search_type: ConfigurationModelBase) -> Callable[ConfigurationModelBase]: pass def add_argument_variables(self): pass
@abstractmethod
def add_json_file(self, name: str, optional: bool = None): pass
@abstractmethod
def add_configuration(self, key_type: type, value: object): pass
@abstractmethod
def get_configuration(self, search_type: Type[ConfigurationModelBase]) -> Callable[ConfigurationModelBase]: pass
@abstractmethod
def create(self): pass

View File

@ -3,5 +3,8 @@ from abc import ABC, abstractmethod
class ConfigurationModelBase(ABC): class ConfigurationModelBase(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod @abstractmethod
def from_dict(self, settings: dict): pass def from_dict(self, settings: dict): pass

View File

@ -1,27 +1,114 @@
from collections import Callable import json
import os
import sys
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.configuration.base.configuration_base import ConfigurationBase
from sh_edraft.configuration.model.configuration_variable_name import ConfigurationVariableName
from sh_edraft.environment.base.environment_base import EnvironmentBase
from sh_edraft.environment.hosting_environment import HostingEnvironment
from sh_edraft.environment.model import EnvironmentName
from sh_edraft.utils import Console
class Configuration(ConfigurationBase): class Configuration(ConfigurationBase):
def __init__(self): def __init__(self):
super().__init__() ConfigurationBase.__init__(self)
self._hosting_environment = HostingEnvironment()
self._config: dict[type, ConfigurationModelBase] = {}
@property @property
def config(self): def environment(self) -> EnvironmentBase:
return self._config return self._hosting_environment
def create(self): pass @staticmethod
def _print_info(name: str, message: str):
Console.write_line(f'[{name}] {message}', 'green')
def add_config_by_type(self, key_type: type, value: object): @staticmethod
def _print_warn(name: str, message: str):
Console.write_line(f'[{name}] {message}', 'yellow')
@staticmethod
def _print_error(name: str, message: str):
Console.write_line(f'[{name}] {message}', 'red')
def _set_variable(self, name: str, value: str):
if name == ConfigurationVariableName.environment.value:
self._hosting_environment.environment_name = EnvironmentName(value)
elif name == ConfigurationVariableName.name.value:
self._hosting_environment.application_name = value
elif name == ConfigurationVariableName.customer.value:
self._hosting_environment.customer = value
def add_environment_variables(self, prefix: str):
for variable in ConfigurationVariableName.to_list():
var_name = f'{prefix}{variable}'
if var_name in [key.upper() for key in os.environ.keys()]:
self._set_variable(variable, os.environ[var_name])
def add_argument_variables(self):
for arg in sys.argv[1:]:
try:
argument = arg.split('--')[1].split('=')[0].upper()
value = arg.split('=')[1]
if argument not in ConfigurationVariableName.to_list():
raise Exception(f'Invalid argument name: {argument}')
self._set_variable(argument, value)
except Exception as e:
self._print_error(__name__, f'Invalid argument: {arg} -> {e}')
exit()
def add_json_file(self, name: str, optional: bool = None):
if self._hosting_environment.content_root_path.endswith('/') and not name.startswith('/'):
file_path = f'{self._hosting_environment.content_root_path}{name}'
else:
file_path = f'{self._hosting_environment.content_root_path}/{name}'
if not os.path.isfile(file_path):
if not optional:
self._print_error(__name__, f'File not found: {file_path}')
exit()
self._print_warn(__name__, f'Not Loaded config file: {file_path}')
return None
config_from_file = self._load_json_file(file_path)
for sub in ConfigurationModelBase.__subclasses__():
for key, value in config_from_file.items():
if sub.__name__ == key:
configuration = sub()
configuration.from_dict(value)
self.add_configuration(sub, configuration)
def _load_json_file(self, file: str) -> dict:
try:
# open config file, create if not exists
with open(file, encoding='utf-8') as cfg:
# load json
json_cfg = json.load(cfg)
self._print_info(__name__, f'Loaded config file: {file}')
return json_cfg
except Exception as e:
self._print_error(__name__, f'Cannot load config file: {file}! -> {e}')
return {}
def add_configuration(self, key_type: type, value: ConfigurationModelBase):
self._config[key_type] = value self._config[key_type] = value
def get_config_by_type(self, search_type: type) -> Callable[ConfigurationModelBase]: def get_configuration(self, search_type: type) -> ConfigurationModelBase:
if search_type not in self._config: if search_type not in self._config:
raise Exception(f'Config model by type {search_type} not found') raise Exception(f'Config model by type {search_type} not found')
for config_model in self._config: for config_model in self._config:
if config_model == search_type: if config_model == search_type:
return self._config[config_model] return self._config[config_model]
def create(self):
pass

View File

@ -0,0 +1,3 @@
# imports:
from .configuration_variable_name import ConfigurationVariableName

View File

@ -0,0 +1,12 @@
from enum import Enum
class ConfigurationVariableName(Enum):
environment = 'ENVIRONMENT'
name = 'NAME'
customer = 'CUSTOMER'
@staticmethod
def to_list():
return [var.value for var in ConfigurationVariableName]

View File

@ -0,0 +1,3 @@
# imports:
from .hosting_environment import HostingEnvironment

View File

@ -0,0 +1,3 @@
# imports:
from .environment_base import EnvironmentBase

View File

@ -0,0 +1,43 @@
from abc import ABC, abstractmethod
class EnvironmentBase(ABC):
@abstractmethod
def __init__(self): pass
@property
@abstractmethod
def environment_name(self) -> str: pass
@environment_name.setter
@abstractmethod
def environment_name(self, environment_name: str): pass
@property
@abstractmethod
def application_name(self) -> str: pass
@application_name.setter
@abstractmethod
def application_name(self, application_name: str): pass
@property
@abstractmethod
def customer(self) -> str: pass
@customer.setter
@abstractmethod
def customer(self, customer: str): pass
@property
@abstractmethod
def content_root_path(self) -> str: pass
@content_root_path.setter
@abstractmethod
def content_root_path(self, content_root_path: str): pass
@property
@abstractmethod
def host_name(self) -> str: pass

View File

@ -0,0 +1,52 @@
from socket import gethostname
from typing import Optional
from sh_edraft.environment.base.environment_base import EnvironmentBase
from sh_edraft.environment.model.environment_name import EnvironmentName
class HostingEnvironment(EnvironmentBase):
def __init__(self, name: EnvironmentName = EnvironmentName.production, crp: str = './'):
EnvironmentBase.__init__(self)
self._environment_name: Optional[EnvironmentName] = name
self._app_name: Optional[str] = None
self._customer: Optional[str] = None
self._content_root_path: Optional[str] = crp
@property
def environment_name(self) -> str:
return str(self._environment_name.value)
@environment_name.setter
def environment_name(self, environment_name: str):
self._environment_name = EnvironmentName(environment_name)
@property
def application_name(self) -> str:
return self._app_name if self._app_name is not None else ''
@application_name.setter
def application_name(self, application_name: str):
self._app_name = application_name
@property
def customer(self) -> str:
return self._customer if self._customer is not None else ''
@customer.setter
def customer(self, customer: str):
self._customer = customer
@property
def content_root_path(self) -> str:
return self._content_root_path
@content_root_path.setter
def content_root_path(self, content_root_path: str):
self._content_root_path = content_root_path
@property
def host_name(self):
return gethostname()

View File

@ -0,0 +1,3 @@
# imports:
from .environment_name import EnvironmentName

View File

@ -0,0 +1,9 @@
from enum import Enum
class EnvironmentName(Enum):
production = 'production'
staging = 'staging'
testing = 'testing'
development = 'development'

View File

@ -1,3 +1,4 @@
# imports: # imports:
from .application_host import ApplicationHost from .application_host import ApplicationHost
from .application_runtime import ApplicationRuntime

View File

@ -1,37 +1,35 @@
from datetime import datetime from datetime import datetime
from sh_edraft.configuration.configuration import Configuration
from sh_edraft.configuration.base.configuration_base import ConfigurationBase
from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
from sh_edraft.hosting.application_runtime import ApplicationRuntime
from sh_edraft.hosting.base.application_host_base import ApplicationHostBase from sh_edraft.hosting.base.application_host_base import ApplicationHostBase
from sh_edraft.service.service_provider import ServiceProvider from sh_edraft.service.service_provider import ServiceProvider
from sh_edraft.service.base.service_provider_base import ServiceProviderBase
class ApplicationHost(ApplicationHostBase): class ApplicationHost(ApplicationHostBase):
def __init__(self): def __init__(self):
ApplicationHostBase.__init__(self) ApplicationHostBase.__init__(self)
self._services = ServiceProvider() self._config = Configuration()
self._app_runtime = ApplicationRuntime(self._config)
self._services = ServiceProvider(self._app_runtime)
self._start_time: datetime = datetime.now() self._start_time: datetime = datetime.now()
self._end_time: datetime = datetime.now() self._end_time: datetime = datetime.now()
@property @property
def services(self): def configuration(self) -> ConfigurationBase:
return self._config
@property
def application_runtime(self) -> ApplicationRuntimeBase:
return self._app_runtime
@property
def services(self) -> ServiceProviderBase:
return self._services return self._services
@property def create(self): pass
def end_time(self) -> datetime:
return self._end_time
@end_time.setter
def end_time(self, end_time: datetime):
self._end_time = end_time
@property
def start_time(self) -> datetime:
return self._start_time
@start_time.setter
def start_time(self, start_time: datetime):
self._start_time = start_time
@property
def date_time_now(self) -> datetime:
return datetime.now()

View File

@ -0,0 +1,38 @@
from datetime import datetime
from sh_edraft.configuration.base.configuration_base import ConfigurationBase
from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
class ApplicationRuntime(ApplicationRuntimeBase):
def __init__(self, config: ConfigurationBase):
ApplicationRuntimeBase.__init__(self)
self._app_configuration = config
self._start_time: datetime = datetime.now()
self._end_time: datetime = datetime.now()
@property
def configuration(self) -> ConfigurationBase:
return self._app_configuration
@property
def start_time(self) -> datetime:
return self._start_time
@start_time.setter
def start_time(self, start_time: datetime):
self._start_time = start_time
@property
def end_time(self) -> datetime:
return self._end_time
@end_time.setter
def end_time(self, end_time: datetime):
self._end_time = end_time
@property
def date_time_now(self) -> datetime:
return datetime.now()

View File

@ -1,2 +1,4 @@
# imports: # imports:
from .application_base import ApplicationBase
from .application_host_base import ApplicationHostBase from .application_host_base import ApplicationHostBase
from .application_runtime_base import ApplicationRuntimeBase

View File

@ -0,0 +1,19 @@
from abc import ABC, abstractmethod
class ApplicationBase(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def create_application_host(self): pass
@abstractmethod
def create_configuration(self): pass
@abstractmethod
def create_services(self): pass
@abstractmethod
def main(self): pass

View File

@ -1,5 +1,8 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime
from sh_edraft.configuration.base.configuration_base import ConfigurationBase
from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
from sh_edraft.service.base.service_provider_base import ServiceProviderBase
class ApplicationHostBase(ABC): class ApplicationHostBase(ABC):
@ -9,14 +12,15 @@ class ApplicationHostBase(ABC):
@property @property
@abstractmethod @abstractmethod
def start_time(self) -> datetime: pass def configuration(self) -> ConfigurationBase: pass
@start_time.setter
def start_time(self, start_time: datetime): pass
@property @property
@abstractmethod @abstractmethod
def end_time(self): pass def application_runtime(self) -> ApplicationRuntimeBase: pass
@end_time.setter @property
def end_time(self, end_time: datetime): pass @abstractmethod
def services(self) -> ServiceProviderBase: pass
@abstractmethod
def create(self): pass

View File

@ -0,0 +1,34 @@
from abc import ABC, abstractmethod
from datetime import datetime
from sh_edraft.configuration.base.configuration_base import ConfigurationBase
class ApplicationRuntimeBase(ABC):
@abstractmethod
def __init__(self): pass
@property
@abstractmethod
def configuration(self) -> ConfigurationBase: pass
@property
@abstractmethod
def start_time(self) -> datetime: pass
@start_time.setter
@abstractmethod
def start_time(self, start_time: datetime): pass
@property
@abstractmethod
def end_time(self): pass
@end_time.setter
@abstractmethod
def end_time(self, end_time: datetime): pass
@property
@abstractmethod
def date_time_now(self) -> datetime: pass

View File

@ -0,0 +1 @@
# imports:

View File

@ -1,20 +1,14 @@
from abc import abstractmethod from abc import abstractmethod
from sh_edraft.hosting.application_host import ApplicationHost
from sh_edraft.logging.model.logging_settings import LoggingSettings
from sh_edraft.service.base.service_base import ServiceBase from sh_edraft.service.base.service_base import ServiceBase
from sh_edraft.time.model.time_format_settings import TimeFormatSettings
class LoggerBase(ServiceBase): class LoggerBase(ServiceBase):
@abstractmethod @abstractmethod
def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings): def __init__(self):
ServiceBase.__init__(self) ServiceBase.__init__(self)
self._log_settings: LoggingSettings = logging_settings
self._time_format_settings: TimeFormatSettings = time_format
@abstractmethod @abstractmethod
def header(self, string: str): pass def header(self, string: str): pass

View File

@ -1,10 +1,9 @@
import datetime import datetime
import os import os
import traceback import traceback
from collections import Callable
from string import Template from string import Template
from sh_edraft.hosting.application_host import ApplicationHost from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
from sh_edraft.logging.base.logger_base import LoggerBase from sh_edraft.logging.base.logger_base import LoggerBase
from sh_edraft.logging.model import LoggingSettings from sh_edraft.logging.model import LoggingSettings
from sh_edraft.logging.model.logging_level import LoggingLevel from sh_edraft.logging.model.logging_level import LoggingLevel
@ -14,14 +13,16 @@ from sh_edraft.utils.console import Console
class Logger(LoggerBase): class Logger(LoggerBase):
def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings, app_host: ApplicationHost): def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings, app_runtime: ApplicationRuntimeBase):
LoggerBase.__init__(self, logging_settings, time_format) LoggerBase.__init__(self)
self._app_host: ApplicationHost = app_host self._app_runtime = app_runtime
self._log_settings: LoggingSettings = logging_settings
self._time_format_settings: TimeFormatSettings = time_format
self._log = Template(self._log_settings.filename).substitute( self._log = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
self._path = self._log_settings.path self._path = self._log_settings.path
self._level = self._log_settings.level self._level = self._log_settings.level
@ -46,7 +47,7 @@ class Logger(LoggerBase):
if not os.path.exists(self._path): if not os.path.exists(self._path):
os.mkdir(self._path) os.mkdir(self._path)
except Exception as e: except Exception as e:
self.fatal(__name__, 'Cannot create log dir', ex=e) self._fatal_console(__name__, 'Cannot create log dir', ex=e)
""" create new log file """ """ create new log file """
try: try:
@ -56,16 +57,19 @@ class Logger(LoggerBase):
Console.write_line(f'[{__name__}]: Using log file: {path}') Console.write_line(f'[{__name__}]: Using log file: {path}')
f.close() f.close()
except Exception as e: except Exception as e:
self.fatal(__name__, 'Cannot open log file', ex=e) self._fatal_console(__name__, 'Cannot open log file', ex=e)
def _append_log(self, string): def _append_log(self, string):
try: try:
# open log file and append always # open log file and append always
if not os.path.isdir(self._path):
self._fatal_console(__name__, 'Log directory not found')
with open(self._path + self._log, "a+", encoding="utf-8") as f: with open(self._path + self._log, "a+", encoding="utf-8") as f:
f.write(string + '\n') f.write(string + '\n')
f.close() f.close()
except Exception as e: except Exception as e:
self.error(__name__, f'Cannot append log file, message: {string}', ex=e) self._fatal_console(__name__, f'Cannot append log file, message: {string}', ex=e)
def _get_string(self, name: str, level: LoggingLevel, message: str) -> str: def _get_string(self, name: str, level: LoggingLevel, message: str) -> str:
log_level = level.name log_level = level.name
@ -142,9 +146,9 @@ class Logger(LoggerBase):
if ex is not None: if ex is not None:
tb = traceback.format_exc() tb = traceback.format_exc()
self.error(name, message) self.error(name, message)
output = self._get_string(name, LoggingLevel.ERROR, f'{ex} -> {tb}') output = self._get_string(name, LoggingLevel.FATAL, f'{ex} -> {tb}')
else: else:
output = self._get_string(name, LoggingLevel.ERROR, message) output = self._get_string(name, LoggingLevel.FATAL, message)
# check if message can be written to log # check if message can be written to log
if self._level.value >= LoggingLevel.FATAL.value: if self._level.value >= LoggingLevel.FATAL.value:
@ -155,3 +159,18 @@ class Logger(LoggerBase):
Console.write_line(output, 'red') Console.write_line(output, 'red')
exit() exit()
def _fatal_console(self, name: str, message: str, ex: Exception = None):
output = ''
if ex is not None:
tb = traceback.format_exc()
self.error(name, message)
output = self._get_string(name, LoggingLevel.ERROR, f'{ex} -> {tb}')
else:
output = self._get_string(name, LoggingLevel.ERROR, message)
# check if message can be shown in console
if self._console.value >= LoggingLevel.FATAL.value:
Console.write_line(output, 'red')
exit()

View File

@ -22,6 +22,7 @@ from collections import namedtuple
# imports: # imports:
from .logging_level import LoggingLevel from .logging_level import LoggingLevel
from .logging_settings import LoggingSettings from .logging_settings import LoggingSettings
from .logging_settings_name import LoggingSettingsName
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major=2020, minor=12, micro=5) version_info = VersionInfo(major=2020, minor=12, micro=5)

View File

@ -2,7 +2,7 @@ import traceback
from typing import Optional from typing import Optional
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
from sh_edraft.logging.model.logging_settings_name import LogSettingsName from sh_edraft.logging.model.logging_settings_name import LoggingSettingsName
from sh_edraft.utils.console import Console from sh_edraft.utils.console import Console
from sh_edraft.logging.model.logging_level import LoggingLevel from sh_edraft.logging.model.logging_level import LoggingLevel
@ -11,7 +11,6 @@ class LoggingSettings(ConfigurationModelBase):
def __init__(self): def __init__(self):
ConfigurationModelBase.__init__(self) ConfigurationModelBase.__init__(self)
self._path: Optional[str] = None self._path: Optional[str] = None
self._filename: Optional[str] = None self._filename: Optional[str] = None
self._console: Optional[LoggingLevel] = None self._console: Optional[LoggingLevel] = None
@ -51,10 +50,10 @@ class LoggingSettings(ConfigurationModelBase):
def from_dict(self, settings: dict): def from_dict(self, settings: dict):
try: try:
self._path = settings[LogSettingsName.path.value] self._path = settings[LoggingSettingsName.path.value]
self._filename = settings[LogSettingsName.filename.value] self._filename = settings[LoggingSettingsName.filename.value]
self._console = LoggingLevel[settings[LogSettingsName.console_level.value]] self._console = LoggingLevel[settings[LoggingSettingsName.console_level.value]]
self._level = LoggingLevel[settings[LogSettingsName.file_level.value]] self._level = LoggingLevel[settings[LoggingSettingsName.file_level.value]]
except Exception as e: except Exception as e:
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {LogSettingsName.log.value} settings', 'red') Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings', 'red')
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}', 'red') Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}', 'red')

View File

@ -1,9 +1,8 @@
from enum import Enum from enum import Enum
class LogSettingsName(Enum): class LoggingSettingsName(Enum):
log = 'Log'
path = 'Path' path = 'Path'
filename = 'Filename' filename = 'Filename'
console_level = 'ConsoleLogLevel' console_level = 'ConsoleLogLevel'

View File

@ -1,19 +1,14 @@
from abc import abstractmethod from abc import abstractmethod
from sh_edraft.logging.base.logger_base import LoggerBase
from sh_edraft.publishing.model.publish_settings_model import PublishSettingsModel
from sh_edraft.service.base.service_base import ServiceBase from sh_edraft.service.base.service_base import ServiceBase
class PublisherBase(ServiceBase): class PublisherBase(ServiceBase):
@abstractmethod @abstractmethod
def __init__(self, logger: LoggerBase, publish_settings: PublishSettingsModel): def __init__(self):
ServiceBase.__init__(self) ServiceBase.__init__(self)
self._logger: LoggerBase = logger
self._publish_settings: PublishSettingsModel = publish_settings
@property @property
@abstractmethod @abstractmethod
def source_path(self) -> str: pass def source_path(self) -> str: pass

View File

@ -22,6 +22,8 @@ from collections import namedtuple
# imports: # imports:
from .template import Template from .template import Template
from .template_enum import TemplateEnum from .template_enum import TemplateEnum
from .publish_settings_model import PublishSettings
from .publish_settings_name import PublishSettingsName
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major=2020, minor=12, micro=5) version_info = VersionInfo(major=2020, minor=12, micro=5)

View File

@ -7,7 +7,7 @@ from sh_edraft.publishing.model.publish_settings_name import PublishSettingsName
from sh_edraft.utils import Console from sh_edraft.utils import Console
class PublishSettingsModel(ConfigurationModelBase): class PublishSettings(ConfigurationModelBase):
def __init__(self): def __init__(self):
ConfigurationModelBase.__init__(self) ConfigurationModelBase.__init__(self)

View File

@ -4,14 +4,17 @@ from string import Template as stringTemplate
from sh_edraft.logging.base.logger_base import LoggerBase from sh_edraft.logging.base.logger_base import LoggerBase
from sh_edraft.publishing.base.publisher_base import PublisherBase from sh_edraft.publishing.base.publisher_base import PublisherBase
from sh_edraft.publishing.model.publish_settings_model import PublishSettingsModel from sh_edraft.publishing.model.publish_settings_model import PublishSettings
from sh_edraft.publishing.model.template import Template from sh_edraft.publishing.model.template import Template
class Publisher(PublisherBase): class Publisher(PublisherBase):
def __init__(self, logger: LoggerBase, publish_settings: PublishSettingsModel): def __init__(self, logger: LoggerBase, publish_settings: PublishSettings):
super().__init__(logger, publish_settings) PublisherBase.__init__(self)
self._logger: LoggerBase = logger
self._publish_settings: PublishSettings = publish_settings
@property @property
def source_path(self) -> str: def source_path(self) -> str:

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
sh_edraft.service sh_edraft.services
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@ -11,7 +11,7 @@ sh_edraft.service
""" """
__title__ = 'sh_edraft.service' __title__ = 'sh_edraft.services'
__author__ = 'Sven Heidemann' __author__ = 'Sven Heidemann'
__license__ = 'MIT' __license__ = 'MIT'
__copyright__ = 'Copyright (c) 2020 sh-edraft.de' __copyright__ = 'Copyright (c) 2020 sh-edraft.de'

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
sh_edraft.service.base sh_edraft.services.base
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@ -11,7 +11,7 @@ sh_edraft.service.base
""" """
__title__ = 'sh_edraft.service.base' __title__ = 'sh_edraft.services.base'
__author__ = 'Sven Heidemann' __author__ = 'Sven Heidemann'
__license__ = 'MIT' __license__ = 'MIT'
__copyright__ = 'Copyright (c) 2020 sh-edraft.de' __copyright__ = 'Copyright (c) 2020 sh-edraft.de'

View File

@ -11,14 +11,6 @@ class ServiceProviderBase(ServiceBase):
def __init__(self): def __init__(self):
ServiceBase.__init__(self) ServiceBase.__init__(self)
self._transient_services: dict[Type[ServiceBase], Type[ServiceBase]] = {}
self._scoped_services: dict[Type[ServiceBase], Type[ServiceBase]] = {}
self._singleton_services: dict[Type[ServiceBase], ServiceBase] = {}
@property
@abstractmethod
def config(self): pass
@abstractmethod @abstractmethod
def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass
@ -26,7 +18,7 @@ class ServiceProviderBase(ServiceBase):
def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass
@abstractmethod @abstractmethod
def add_singleton(self, service_type: Type[ServiceBase], service: ServiceBase): pass def add_singleton(self, service_type: Type[ServiceBase], service: Callable[ServiceBase]): pass
@abstractmethod @abstractmethod
def get_service(self, instance_type: Type[ServiceBase]) -> Callable[ServiceBase]: pass def get_service(self, instance_type: Type[ServiceBase]) -> Callable[ServiceBase]: pass

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
sh_edraft.service.base sh_edraft.services.base
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
@ -11,7 +11,7 @@ sh_edraft.service.base
""" """
__title__ = 'sh_edraft.service.base' __title__ = 'sh_edraft.services.base'
__author__ = 'Sven Heidemann' __author__ = 'Sven Heidemann'
__license__ = 'MIT' __license__ = 'MIT'
__copyright__ = 'Copyright (c) 2020 sh-edraft.de' __copyright__ = 'Copyright (c) 2020 sh-edraft.de'

View File

@ -2,22 +2,21 @@ from collections import Callable
from inspect import signature, Parameter from inspect import signature, Parameter
from typing import Type from typing import Type
from sh_edraft.configuration.configuration import Configuration
from sh_edraft.hosting.base.application_host_base import ApplicationHostBase
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase
from sh_edraft.service.base.service_provider_base import ServiceProviderBase from sh_edraft.service.base.service_provider_base import ServiceProviderBase
from sh_edraft.service.base.service_base import ServiceBase from sh_edraft.service.base.service_base import ServiceBase
class ServiceProvider(ServiceProviderBase): class ServiceProvider(ServiceProviderBase):
def __init__(self): def __init__(self, app_runtime: ApplicationRuntimeBase):
super().__init__() ServiceProviderBase.__init__(self)
self._config = Configuration() self._app_runtime: ApplicationRuntimeBase = app_runtime
@property self._transient_services: dict[Type[ServiceBase], Type[ServiceBase]] = {}
def config(self): self._scoped_services: dict[Type[ServiceBase], Type[ServiceBase]] = {}
return self._config self._singleton_services: dict[Type[ServiceBase], ServiceBase] = {}
def create(self): pass def create(self): pass
@ -27,18 +26,16 @@ class ServiceProvider(ServiceProviderBase):
for param in sig.parameters.items(): for param in sig.parameters.items():
parameter = param[1] parameter = param[1]
if parameter.name != 'self' and parameter.annotation != Parameter.empty: if parameter.name != 'self' and parameter.annotation != Parameter.empty:
if issubclass(parameter.annotation, ServiceBase): if issubclass(parameter.annotation, ApplicationRuntimeBase):
params.append(self._app_runtime)
elif issubclass(parameter.annotation, ServiceBase):
params.append(self.get_service(parameter.annotation)) params.append(self.get_service(parameter.annotation))
elif issubclass(parameter.annotation, ConfigurationModelBase) or issubclass(parameter.annotation, ApplicationHostBase): elif issubclass(parameter.annotation, ConfigurationModelBase):
params.append(self._config.get_config_by_type(parameter.annotation)) params.append(self._app_runtime.configuration.get_configuration(parameter.annotation))
return service(*params) return service(*params)
# try:
# instance.init(args)
# return instance
# except Exception as e:
# print(colored(f'Argument error\n{e}', 'red'))
def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]):
self._transient_services[service_type] = service self._transient_services[service_type] = service
@ -46,7 +43,7 @@ class ServiceProvider(ServiceProviderBase):
def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): def add_scoped(self, service_type: Type[ServiceBase], service: Type[ServiceBase]):
self._scoped_services[service_type] = service self._scoped_services[service_type] = service
def add_singleton(self, service_type: Type[ServiceBase], service: ServiceBase): def add_singleton(self, service_type: Type[ServiceBase], service: Callable[ServiceBase]):
for known_service in self._singleton_services: for known_service in self._singleton_services:
if type(known_service) == type(service_type): if type(known_service) == type(service_type):
raise Exception(f'Service with type {type(service_type)} already exists') raise Exception(f'Service with type {type(service_type)} already exists')

View File

@ -9,6 +9,7 @@ from sh_edraft.utils.console import Console
class TimeFormatSettings(ConfigurationModelBase): class TimeFormatSettings(ConfigurationModelBase):
def __init__(self): def __init__(self):
ConfigurationModelBase.__init__(self)
self._date_format: Optional[str] = None self._date_format: Optional[str] = None
self._time_format: Optional[str] = None self._time_format: Optional[str] = None
self._date_time_format: Optional[str] = None self._date_time_format: Optional[str] = None
@ -55,5 +56,5 @@ class TimeFormatSettings(ConfigurationModelBase):
self._date_time_format = settings[TimeFormatSettingsNames.date_time_format.value] self._date_time_format = settings[TimeFormatSettingsNames.date_time_format.value]
self._date_time_log_format = settings[TimeFormatSettingsNames.date_time_log_format.value] self._date_time_log_format = settings[TimeFormatSettingsNames.date_time_log_format.value]
except Exception as e: except Exception as e:
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {TimeFormatSettingsNames.formats.value} settings') Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}', 'red') Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}', 'red')

View File

@ -3,7 +3,6 @@ from enum import Enum
class TimeFormatSettingsNames(Enum): class TimeFormatSettingsNames(Enum):
formats = 'TimeFormats'
date_format = 'DateFormat' date_format = 'DateFormat'
time_format = 'TimeFormat' time_format = 'TimeFormat'
date_time_format = 'DateTimeFormat' date_time_format = 'DateTimeFormat'

View File

@ -0,0 +1,8 @@
{
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
}
}

View File

@ -0,0 +1,8 @@
{
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
}
}

View File

@ -0,0 +1,15 @@
{
"TimeFormatSettings": {
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
},
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR",
"FileLogLevel": "WARN"
}
}

View File

@ -0,0 +1,17 @@
{
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
},
"PublishSettings": {
"SourcePath": "../",
"DistPath": "../../dist",
"Templates": [],
"IncludedFiles": [],
"ExcludedFiles": [],
"TemplateEnding": "_template.txt"
}
}

View File

@ -0,0 +1,93 @@
import os
import unittest
from typing import cast
from sh_edraft.configuration import Configuration
from sh_edraft.environment.model import EnvironmentName
from sh_edraft.hosting import ApplicationHost
from sh_edraft.logging.model import LoggingSettings, LoggingLevel
from sh_edraft.publishing.model import PublishSettings
from sh_edraft.time.model import TimeFormatSettings
class ConfigTest(unittest.TestCase):
def setUp(self):
self._app_host = ApplicationHost()
self._config = cast(Configuration, self._app_host.configuration)
def test_create(self):
print(f'{__name__}.test_create:')
self.assertIsNotNone(self._config)
self._config.create()
self.assertIsNotNone(self._config)
self.assertEqual(len(self._config._config), 0)
self.assertIsNotNone(self._app_host.application_runtime)
def test_env_vars(self):
print(f'{__name__}.test_env_vars:')
self._config.add_environment_variables('PYTHON_')
self._config.add_environment_variables('CPL_')
def test_arguments(self):
print(f'{__name__}.test_arguments:')
self._config.add_argument_variables()
self.assertEqual(self._config.environment.environment_name, EnvironmentName.testing.value)
def test_appsettings(self):
print(f'{__name__}.test_appsettings:')
self._config.add_json_file(f'appsettings.json')
time_formats: TimeFormatSettings = cast(TimeFormatSettings, self._config.get_configuration(TimeFormatSettings))
self.assertIsNotNone(time_formats)
self.assertEqual(time_formats.date_format, '%Y-%m-%d')
self.assertEqual(time_formats.time_format, '%H:%M:%S')
self.assertEqual(time_formats.date_time_format, '%Y-%m-%d %H:%M:%S.%f')
self.assertEqual(time_formats.date_time_log_format, '%Y-%m-%d_%H-%M-%S')
logging = cast(LoggingSettings, self._config.get_configuration(LoggingSettings))
self.assertIsNotNone(logging)
self.assertEqual(logging.path, 'logs/')
self.assertEqual(logging.filename, 'log_$start_time.log')
self.assertEqual(logging.console.value, LoggingLevel.ERROR.value)
self.assertEqual(logging.level.value, LoggingLevel.WARN.value)
with self.assertRaises(Exception):
publish: PublishSettings = cast(PublishSettings, self._config.get_configuration(PublishSettings))
def test_appsettings_environment(self):
print(f'{__name__}.test_appsettings_environment:')
self._config.add_argument_variables()
self._config.add_json_file(f'appsettings.{self._config.environment.environment_name}.json')
logging = cast(LoggingSettings, self._config.get_configuration(LoggingSettings))
self.assertIsNotNone(logging)
self.assertEqual(logging.path, 'logs/')
self.assertEqual(logging.filename, 'log_$start_time.log')
self.assertEqual(logging.console.value, LoggingLevel.TRACE.value)
self.assertEqual(logging.level.value, LoggingLevel.TRACE.value)
publish: PublishSettings = cast(PublishSettings, self._config.get_configuration(PublishSettings))
self.assertIsNotNone(publish)
self.assertEqual(publish.source_path, '../')
self.assertEqual(publish.dist_path, '../../dist')
self.assertEqual(publish.templates, [])
self.assertEqual(publish.included_files, [])
self.assertEqual(publish.excluded_files, [])
self.assertEqual(publish.template_ending, '_template.txt')
def test_appsettings_host(self):
print(f'{__name__}.test_appsettings_host:')
self._config.add_json_file(f'appsettings.{self._config.environment.host_name}.json')
def test_appsettings_customer(self):
print(f'{__name__}.test_appsettings_customer:')
file_name = f'appsettings.{self._config.environment.customer}.json'
with self.assertRaises(SystemExit):
if os.path.isfile(f'{self._config.environment.content_root_path}/{file_name}'):
os.remove(f'{self._config.environment.content_root_path}/{file_name}')
self._config.add_json_file(file_name)
self._config.add_json_file(file_name, optional=True)

View File

@ -0,0 +1,33 @@
import unittest
import datetime
from sh_edraft.configuration.base import ConfigurationBase
from sh_edraft.hosting import ApplicationHost
from sh_edraft.hosting.base import ApplicationRuntimeBase
from sh_edraft.service.base import ServiceProviderBase
class AppHostTest(unittest.TestCase):
def setUp(self):
pass
def test_create(self):
print(f'{__name__}.test_create:')
app_host = ApplicationHost()
self.assertIsNotNone(app_host)
app_host.create()
self.assertIsNotNone(app_host.configuration)
self.assertTrue(isinstance(app_host.configuration, ConfigurationBase))
self.assertIsNotNone(app_host.application_runtime)
self.assertTrue(isinstance(app_host.application_runtime, ApplicationRuntimeBase))
self.assertIsNotNone(app_host.services)
self.assertTrue(isinstance(app_host.services, ServiceProviderBase))
self.assertIsNotNone(app_host._start_time)
self.assertTrue(isinstance(app_host._start_time, datetime.datetime))
self.assertIsNotNone(app_host._end_time)
self.assertTrue(isinstance(app_host._end_time, datetime.datetime))

View File

@ -1,59 +0,0 @@
import os
from sh_edraft.logging.base.logger_base import LoggerBase
from sh_edraft.publishing.base import PublisherBase
from sh_edraft.service.base import ServiceProviderBase
from sh_edraft.coding.model import Version
from sh_edraft.publishing import Publisher
from sh_edraft.publishing.model import Template
class PublisherTest:
@staticmethod
def start(services: ServiceProviderBase):
version = Version(2020, 12, 5).to_dict()
templates = [
Template(
'../../publish_templates/*_template.txt',
'*',
'',
'',
'2020',
'sh-edraft.de',
'MIT',
', see LICENSE for more details.',
'',
'Sven Heidemann',
version
),
Template(
'../../publish_templates/*_template.txt',
'sh_edraft',
'common python library',
'Library to share common classes and models used at sh-edraft.de',
'2020',
'sh-edraft.de',
'MIT',
', see LICENSE for more details.',
'',
'Sven Heidemann',
version
)
]
source = '../'
dist = '../../dist'
services.add_transient(Publisher, services.get_service(LoggerBase), source, dist, templates)
publisher: Publisher = services.get_service(PublisherBase)
publisher.exclude('../tests/')
publisher.include('../../LICENSE')
publisher.include('../../README.md')
publisher.create()
publisher.publish()
if not os.path.isdir(dist):
raise Exception(f'{__name__}: Dist path was not created')

View File

@ -1,54 +1,30 @@
import unittest import unittest
from typing import cast
from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting import ApplicationHost
from sh_edraft.logging import Logger from sh_edraft.logging import Logger
from sh_edraft.logging.base import LoggerBase from sh_edraft.logging.base import LoggerBase
from sh_edraft.logging.model import LoggingSettings
from sh_edraft.publishing import Publisher from sh_edraft.publishing import Publisher
from sh_edraft.publishing.base import PublisherBase from sh_edraft.publishing.base import PublisherBase
from sh_edraft.publishing.model.publish_settings_model import PublishSettingsModel
from sh_edraft.service import ServiceProvider from sh_edraft.service import ServiceProvider
from sh_edraft.service.base import ServiceBase from sh_edraft.service.base import ServiceBase
from sh_edraft.time.model import TimeFormatSettings
class ServiceProviderTest(unittest.TestCase): class ServiceProviderTest(unittest.TestCase):
def setUp(self): def setUp(self):
self._app_host = ApplicationHost() self._app_host = ApplicationHost()
self._services = self._app_host.services self._config = self._app_host.configuration
self._config.create()
self._config.add_environment_variables('PYTHON_')
self._config.add_environment_variables('CPL_')
self._config.add_argument_variables()
self._config.add_json_file(f'appsettings.json')
self._config.add_json_file(f'appsettings.{self._config.environment.environment_name}.json')
self._config.add_json_file(f'appsettings.{self._config.environment.host_name}.json', optional=True)
self._services: ServiceProvider = cast(ServiceProvider, self._app_host.services)
self._services.create() self._services.create()
self._log_settings = LoggingSettings()
self._log_settings.from_dict({
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
})
self._services.config.add_config_by_type(LoggingSettings, self._log_settings)
self._time_format_settings = TimeFormatSettings()
self._time_format_settings.from_dict({
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
})
self._services.config.add_config_by_type(TimeFormatSettings, self._time_format_settings)
self._services.config.add_config_by_type(ApplicationHost, self._app_host)
self._publish_settings_model = PublishSettingsModel()
self._publish_settings_model.from_dict({
"SourcePath": "../",
"DistPath": "../../dist",
"Templates": [],
"IncludedFiles": [],
"ExcludedFiles": [],
"TemplateEnding": "_template.txt",
})
self._services.config.add_config_by_type(PublishSettingsModel, self._publish_settings_model)
def _check_general_requirements(self): def _check_general_requirements(self):
self.assertIsNotNone(self._services) self.assertIsNotNone(self._services)
@ -59,7 +35,7 @@ class ServiceProviderTest(unittest.TestCase):
def test_create(self): def test_create(self):
print(f'{__name__}.test_create:') print(f'{__name__}.test_create:')
provider = ServiceProvider() provider = ServiceProvider(self._app_host.application_runtime)
self.assertIsNotNone(provider) self.assertIsNotNone(provider)
provider.create() provider.create()
self.assertIsNotNone(provider) self.assertIsNotNone(provider)
@ -75,7 +51,9 @@ class ServiceProviderTest(unittest.TestCase):
for service_type in self._services._singleton_services: for service_type in self._services._singleton_services:
service = self._services._singleton_services[service_type] service = self._services._singleton_services[service_type]
if service_type == LoggerBase and ( if service_type == LoggerBase and (
isinstance(service, Logger) and isinstance(service, LoggerBase) and isinstance(service, ServiceBase) isinstance(service, Logger) and
isinstance(service, LoggerBase) and
isinstance(service, ServiceBase)
): ):
if not found: if not found:
found = True found = True
@ -86,7 +64,9 @@ class ServiceProviderTest(unittest.TestCase):
for service_type in self._services._singleton_services: for service_type in self._services._singleton_services:
service = self._services._singleton_services[service_type] service = self._services._singleton_services[service_type]
if service_type == PublisherBase and ( if service_type == PublisherBase and (
isinstance(service, Publisher) and isinstance(service, PublisherBase) and isinstance(service, ServiceBase) isinstance(service, Publisher) and
isinstance(service, PublisherBase) and
isinstance(service, ServiceBase)
): ):
if not found: if not found:
found = True found = True
@ -104,9 +84,7 @@ class ServiceProviderTest(unittest.TestCase):
self.assertTrue(isinstance(logger, LoggerBase)) self.assertTrue(isinstance(logger, LoggerBase))
self.assertTrue(isinstance(logger, ServiceBase)) self.assertTrue(isinstance(logger, ServiceBase))
self.assertEqual(logger._log_settings, self._log_settings) self.assertEqual(logger._app_runtime, self._app_host.application_runtime)
self.assertEqual(logger._time_format_settings, self._time_format_settings)
self.assertEqual(logger._app_host, self._app_host)
def test_add_scoped(self): def test_add_scoped(self):
print(f'{__name__}.test_add_scoped:') print(f'{__name__}.test_add_scoped:')

View File

View File

View File

@ -1,12 +1,13 @@
import os import os
import shutil import shutil
import unittest import unittest
from datetime import datetime
from string import Template from string import Template
from typing import cast
from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting import ApplicationHost
from sh_edraft.logging import Logger from sh_edraft.logging import Logger
from sh_edraft.logging.model import LoggingSettings from sh_edraft.logging.model import LoggingSettings
from sh_edraft.service import ServiceProvider
from sh_edraft.time.model import TimeFormatSettings from sh_edraft.time.model import TimeFormatSettings
@ -14,55 +15,50 @@ class LoggerTest(unittest.TestCase):
def setUp(self): def setUp(self):
self._app_host = ApplicationHost() self._app_host = ApplicationHost()
self._services = self._app_host.services self._config = self._app_host.configuration
self._config.create()
self._config.add_environment_variables('PYTHON_')
self._config.add_environment_variables('CPL_')
self._config.add_argument_variables()
self._config.add_json_file(f'appsettings.json')
self._config.add_json_file(f'appsettings.{self._config.environment.environment_name}.json')
self._config.add_json_file(f'appsettings.{self._config.environment.host_name}.json', optional=True)
self._services: ServiceProvider = cast(ServiceProvider, self._app_host.services)
self._services.create() self._services.create()
self._log_settings = LoggingSettings() self._app_runtime = self._app_host.application_runtime
self._log_settings.from_dict({ self._log_settings: LoggingSettings = self._config.get_configuration(LoggingSettings)
"Path": "logs/", self._time_format_settings: TimeFormatSettings = self._config.get_configuration(TimeFormatSettings)
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
})
self._time_format_settings = TimeFormatSettings()
self._time_format_settings.from_dict({
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
})
def tearDown(self): def tearDown(self):
if os.path.isdir(self._log_settings.path): if os.path.isdir(self._log_settings.path):
shutil.rmtree(self._log_settings.path) shutil.rmtree(self._log_settings.path)
def _check_general_requirements(self): def _check_general_requirements(self):
self.assertIsNotNone(self._services)
self.assertIsNotNone(self._log_settings) self.assertIsNotNone(self._log_settings)
self.assertIsNotNone(self._time_format_settings) self.assertIsNotNone(self._time_format_settings)
def test_create(self): def test_create(self):
print(f'{__name__}.test_create:') print(f'{__name__}.test_create:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
self.assertTrue(os.path.isdir(self._log_settings.path)) self.assertTrue(os.path.isdir(self._log_settings.path))
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
self.assertTrue(os.path.isfile(self._log_settings.path + log_file)) self.assertTrue(os.path.isfile(self._log_settings.path + log_file))
def test_header(self): def test_header(self):
print(f'{__name__}.test_header:') print(f'{__name__}.test_header:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.header('HeaderTest:') logger.header('HeaderTest:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -78,13 +74,13 @@ class LoggerTest(unittest.TestCase):
def test_trace(self): def test_trace(self):
print(f'{__name__}.test_trace:') print(f'{__name__}.test_trace:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.trace(__name__, f'{__name__}.test_trace:') logger.trace(__name__, f'{__name__}.test_trace:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -100,13 +96,13 @@ class LoggerTest(unittest.TestCase):
def test_debug(self): def test_debug(self):
print(f'{__name__}.test_debug:') print(f'{__name__}.test_debug:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.debug(__name__, f'{__name__}.test_debug:') logger.debug(__name__, f'{__name__}.test_debug:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -122,13 +118,13 @@ class LoggerTest(unittest.TestCase):
def test_info(self): def test_info(self):
print(f'{__name__}.test_info:') print(f'{__name__}.test_info:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.info(__name__, f'{__name__}.test_info:') logger.info(__name__, f'{__name__}.test_info:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -144,13 +140,13 @@ class LoggerTest(unittest.TestCase):
def test_warn(self): def test_warn(self):
print(f'{__name__}.test_warn:') print(f'{__name__}.test_warn:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.warn(__name__, f'{__name__}.test_warn:') logger.warn(__name__, f'{__name__}.test_warn:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -166,13 +162,13 @@ class LoggerTest(unittest.TestCase):
def test_error(self): def test_error(self):
print(f'{__name__}.test_error:') print(f'{__name__}.test_error:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
logger.error(__name__, f'{__name__}.test_error:') logger.error(__name__, f'{__name__}.test_error:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -188,14 +184,14 @@ class LoggerTest(unittest.TestCase):
def test_fatal(self): def test_fatal(self):
print(f'{__name__}.test_fatal:') print(f'{__name__}.test_fatal:')
logger = Logger(self._log_settings, self._time_format_settings, self._app_host) logger = Logger(self._log_settings, self._time_format_settings, self._app_runtime)
logger.create() logger.create()
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
logger.fatal(__name__, f'{__name__}.test_fatal:') logger.fatal(__name__, f'{__name__}.test_fatal:')
log_file = Template(self._log_settings.filename).substitute( log_file = Template(self._log_settings.filename).substitute(
date_time_now=self._app_host.date_time_now.strftime(self._time_format_settings.date_time_format), date_time_now=self._app_runtime.date_time_now.strftime(self._time_format_settings.date_time_format),
start_time=self._app_host.start_time.strftime(self._time_format_settings.date_time_log_format) start_time=self._app_runtime.start_time.strftime(self._time_format_settings.date_time_log_format)
) )
log_content = [] log_content = []
@ -207,4 +203,4 @@ class LoggerTest(unittest.TestCase):
print('Cannot open log file', e) print('Cannot open log file', e)
self.assertGreater(len(log_content), 0) self.assertGreater(len(log_content), 0)
self.assertTrue(log_content[len(log_content) - 1].endswith(f'[ ERROR ] [ {__name__} ]: {__name__}.test_fatal:\n')) self.assertTrue(log_content[len(log_content) - 1].endswith(f'[ FATAL ] [ {__name__} ]: {__name__}.test_fatal:\n'))

View File

@ -4,35 +4,17 @@ import unittest
from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting import ApplicationHost
from sh_edraft.logging import Logger from sh_edraft.logging import Logger
from sh_edraft.logging.base import LoggerBase
from sh_edraft.logging.model import LoggingSettings from sh_edraft.logging.model import LoggingSettings
from sh_edraft.publishing import Publisher from sh_edraft.publishing import Publisher
from sh_edraft.publishing.base import PublisherBase
from sh_edraft.publishing.model import Template from sh_edraft.publishing.model import Template
from sh_edraft.publishing.model.publish_settings_model import PublishSettingsModel from sh_edraft.publishing.model import PublishSettings
from sh_edraft.coding.model import Version from sh_edraft.coding.model import Version
from sh_edraft.time.model import TimeFormatSettings from sh_edraft.time.model import TimeFormatSettings
class PublisherTest(unittest.TestCase): class PublisherTest(unittest.TestCase):
def _config(self): def _configure(self):
self._log_settings = LoggingSettings()
self._log_settings.from_dict({
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
})
self._time_format_settings = TimeFormatSettings()
self._time_format_settings.from_dict({
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
})
self._version = Version(2020, 12, 5).to_dict() self._version = Version(2020, 12, 5).to_dict()
templates = [ templates = [
Template( Template(
@ -66,7 +48,7 @@ class PublisherTest(unittest.TestCase):
self._source_path = '../' self._source_path = '../'
self._dist_path = '../../dist' self._dist_path = '../../dist'
self._publish_settings_model = PublishSettingsModel() self._publish_settings_model = PublishSettings()
self._publish_settings_model.from_dict({ self._publish_settings_model.from_dict({
"SourcePath": self._source_path, "SourcePath": self._source_path,
"DistPath": self._dist_path, "DistPath": self._dist_path,
@ -77,10 +59,23 @@ class PublisherTest(unittest.TestCase):
}) })
def setUp(self): def setUp(self):
self._config()
self._app_host = ApplicationHost() self._app_host = ApplicationHost()
self._logger = Logger(self._log_settings, self._time_format_settings, self._app_host) self._config = self._app_host.configuration
self._config.create()
self._config.add_environment_variables('PYTHON_')
self._config.add_environment_variables('CPL_')
self._config.add_argument_variables()
self._config.add_json_file(f'appsettings.json')
self._config.add_json_file(f'appsettings.{self._config.environment.environment_name}.json')
self._config.add_json_file(f'appsettings.{self._config.environment.host_name}.json', optional=True)
self._app_runtime = self._app_host.application_runtime
self._configure()
self._log_settings: LoggingSettings = self._config.get_configuration(LoggingSettings)
self._time_format_settings: TimeFormatSettings = self._config.get_configuration(TimeFormatSettings)
self._logger = Logger(self._log_settings, self._time_format_settings, self._app_host.application_runtime)
self._logger.create() self._logger.create()
def tearDown(self): def tearDown(self):
@ -88,8 +83,10 @@ class PublisherTest(unittest.TestCase):
shutil.rmtree(self._log_settings.path) shutil.rmtree(self._log_settings.path)
def test_create(self): def test_create(self):
print(f'{__name__}.test_create:')
publisher: Publisher = Publisher(self._logger, self._publish_settings_model) publisher: Publisher = Publisher(self._logger, self._publish_settings_model)
self.assertIsNotNone(publisher) self.assertIsNotNone(publisher)
publisher.create() publisher.create()
self.assertTrue(os.path.isdir(self._dist_path)) self.assertTrue(os.path.isdir(self._dist_path))
self.assertEqual(publisher._publish_settings, self._publish_settings_model)

View File

@ -1,7 +1,9 @@
import unittest import unittest
from tests.logging.logger import LoggerTest from tests.configuration.config import ConfigTest
from tests.publishing.publisher import PublisherTest from tests.hosting.app_host import AppHostTest
from tests.services.logging.logger import LoggerTest
from tests.services.publishing.publisher import PublisherTest
from tests.service_providing.service_provider import ServiceProviderTest from tests.service_providing.service_provider import ServiceProviderTest
@ -11,6 +13,18 @@ class Tester:
self._suite = unittest.TestSuite() self._suite = unittest.TestSuite()
def create(self): def create(self):
# hosting app host
self._suite.addTest(AppHostTest('test_create'))
# configuration
self._suite.addTest(ConfigTest('test_create'))
self._suite.addTest(ConfigTest('test_env_vars'))
self._suite.addTest(ConfigTest('test_arguments'))
self._suite.addTest(ConfigTest('test_appsettings'))
self._suite.addTest(ConfigTest('test_appsettings_environment'))
self._suite.addTest(ConfigTest('test_appsettings_host'))
self._suite.addTest(ConfigTest('test_appsettings_customer'))
# providing # providing
self._suite.addTest(ServiceProviderTest('test_create')) self._suite.addTest(ServiceProviderTest('test_create'))
self._suite.addTest(ServiceProviderTest('test_add_singleton')) self._suite.addTest(ServiceProviderTest('test_add_singleton'))

View File

View File

@ -0,0 +1,8 @@
{
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE",
"FileLogLevel": "TRACE"
}
}

View File

@ -0,0 +1,15 @@
{
"TimeFormatSettings": {
"DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
},
"LoggingSettings": {
"Path": "logs/",
"Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR",
"FileLogLevel": "WARN"
}
}

8
src/tests_dev/main.py Normal file
View File

@ -0,0 +1,8 @@
from tests_dev.program import Program
if __name__ == '__main__':
program = Program()
program.create_application_host()
program.create_configuration()
program.create_services()
program.main()

45
src/tests_dev/program.py Normal file
View File

@ -0,0 +1,45 @@
from typing import Optional
from sh_edraft.configuration.base import ConfigurationBase
from sh_edraft.hosting import ApplicationHost
from sh_edraft.hosting.base import ApplicationBase
from sh_edraft.logging import Logger
from sh_edraft.logging.base import LoggerBase
from sh_edraft.service.base import ServiceProviderBase
class Program(ApplicationBase):
def __init__(self):
ApplicationBase.__init__(self)
self._app_host: Optional[ApplicationHost] = None
self._services: Optional[ServiceProviderBase] = None
self._configuration: Optional[ConfigurationBase] = None
self._logger: Optional[LoggerBase] = None
def create_application_host(self):
self._app_host = ApplicationHost()
self._configuration = self._app_host.configuration
self._services = self._app_host.services
def create_configuration(self):
self._configuration.create()
self._configuration.add_environment_variables('PYTHON_')
self._configuration.add_environment_variables('CPL_')
self._configuration.add_argument_variables()
self._configuration.add_json_file(f'appsettings.json')
self._configuration.add_json_file(f'appsettings.{self._configuration.environment.environment_name}.json')
self._configuration.add_json_file(f'appsettings.{self._configuration.environment.host_name}.json', optional=True)
def create_services(self):
self._services.create()
self._services.add_singleton(LoggerBase, Logger)
self._logger = self._services.get_service(LoggerBase)
self._logger.create()
def main(self):
self._logger.header(f'{self._configuration.environment.application_name}:')
self._logger.debug(__name__, f'Host: {self._configuration.environment.host_name}')
self._logger.debug(__name__, f'Environment: {self._configuration.environment.environment_name}')
self._logger.debug(__name__, f'Customer: {self._configuration.environment.customer}')