Merge pull request '2021.4' (#19) from 2021.4 into master
Reviewed-on: sh-edraft.de/sh_common_py_lib#19
This commit is contained in:
commit
caca34168e
4
.gitignore
vendored
4
.gitignore
vendored
@ -37,7 +37,7 @@ MANIFEST
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
# Unit model / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
@ -130,4 +130,4 @@ dmypy.json
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
|
||||
.idea/
|
||||
|
@ -1,3 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="sven" />
|
||||
</component>
|
@ -1,17 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="termcolor" />
|
||||
<item index="1" class="java.lang.String" itemvalue="discord" />
|
||||
<item index="2" class="java.lang.String" itemvalue="mysql-connector" />
|
||||
<item index="3" class="java.lang.String" itemvalue="flask" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectPlainTextFileTypeManager">
|
||||
<file url="file://$PROJECT_DIR$/publish_templates/all_template.txt" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||
</project>
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/sh_common_py_lib.iml" filepath="$PROJECT_DIR$/.idea/sh_common_py_lib.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/tests/logs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/tests_dev/logs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/sh_edraft.egg-info" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/dist" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/src/tests/old" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.vscode" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build_test" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
File diff suppressed because one or more lines are too long
@ -1,4 +0,0 @@
|
||||
<changelist name="Uncommitted_changes_before_Update_at_26_11_2020_10_36_[Default_Changelist]" date="1606383362450" recycled="false" toDelete="true">
|
||||
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_Update_at_26_11_2020_10_36_[Default_Changelist]/shelved.patch" />
|
||||
<option name="DESCRIPTION" value="Uncommitted changes before Update at 26.11.2020 10:36 [Default Changelist]" />
|
||||
</changelist>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -1,868 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="BranchesTreeState">
|
||||
<expand>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="GROUP_NODE:origin" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="7e2256bc-a6b8-4880-83a6-8b0e3372d0a4" name="Default Changelist" comment="Removed unused packages">
|
||||
<change afterPath="$PROJECT_DIR$/src/tests/publish_test/__init__.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/tests/publish_test/publisher_test.py" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/tests/setup.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/sh_common_py_lib.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/sh_common_py_lib.iml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/build/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/build/app.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/publish/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/publish/app.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/base/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/base/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/base/publisher_base.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/base/publisher_base.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/model/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/model/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/model/publish_settings_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/model/publish_settings_model.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/model/publish_settings_name.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/model/publish_settings_name.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/model/template.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/model/template.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/model/template_enum.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/model/template_enum.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/sh_edraft/publishing/publisher.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/sh_edraft/publish/publisher.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/appsettings.edrafts-lapi.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/appsettings.edrafts-lapi.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/appsettings.edrafts-pc.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/appsettings.edrafts-pc.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/build.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/build.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/service_test/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/service_test/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/time_test/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/time_test/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/tests/utils_test/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/tests/utils_test/__init__.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Python Script" />
|
||||
<option value="Python Unit Test" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Pull.Settings">
|
||||
<option name="BRANCH" value="2020.12.6" />
|
||||
</component>
|
||||
<component name="Git.Rebase.Settings">
|
||||
<option name="NEW_BASE" value="2020.12" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="2020.12" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
<option name="RESET_MODE" value="HARD" />
|
||||
<option name="UPDATE_TYPE" value="REBASE" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1kYeNqJzjIXigSYYCzg4D16FL1E" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/src/tests" />
|
||||
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/src/tests" />
|
||||
<recent name="$PROJECT_DIR$/src/tests_dev" />
|
||||
<recent name="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/database" />
|
||||
<recent name="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/publish" />
|
||||
<recent name="$PROJECT_DIR$/src" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/src/tests" />
|
||||
<recent name="$PROJECT_DIR$/src/tests/publish_test" />
|
||||
<recent name="$PROJECT_DIR$/src/tests/old" />
|
||||
<recent name="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/commands/build" />
|
||||
<recent name="$PROJECT_DIR$/src" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python tests.Unittests">
|
||||
<configuration name="cli build" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="build test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli database migration" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/tests_dev" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="db mig add InitialMigration" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli database update" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/tests_dev" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="database update" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli help" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="help" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new app" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new app ./Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new base" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new app ./Test/Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new class" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new class ./Test/Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new configmodel" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new configmodel ./Test/Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new enum" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new enum ./Test/Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli new service" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="new service ./Test/Test" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli publish" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="publish" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli version" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="version" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="cli" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/sh_edraft/cli/cpl_cli/cli.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
<env name="CPL_NAME" value="CPL_Dev_Test" />
|
||||
<env name="PYTHON_ENVIRONMENT" value="development" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/tests_dev" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/src/tests_dev/main.py" />
|
||||
<option name="PARAMETERS" value="--customer=sh-edraft.de" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Unittests" type="tests" factoryName="Unittests" temporary="true" nameIsGenerated="true">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="CPL_ENVIRONMENT" value="testing" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/tests" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="_new_pattern" value="""" />
|
||||
<option name="_new_additionalArguments" value=""discover -s $PROJECT_DIR$/src/tests -p \u0027*_test.py\u0027"" />
|
||||
<option name="_new_target" value="""" />
|
||||
<option name="_new_targetType" value=""CUSTOM"" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Unittests" type="tests" factoryName="Unittests" temporary="true" nameIsGenerated="true">
|
||||
<module name="sh_common_py_lib" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="CPL_ENVIRONMENT" value="testing" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/src/tests" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="_new_pattern" value="""" />
|
||||
<option name="_new_additionalArguments" value=""discover -s $PROJECT_DIR$/src/tests -p \u0027*_test.py\u0027"" />
|
||||
<option name="_new_target" value="""" />
|
||||
<option name="_new_targetType" value=""CUSTOM"" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="Python.cli build" />
|
||||
<item itemvalue="Python.cli database migration" />
|
||||
<item itemvalue="Python.cli database update" />
|
||||
<item itemvalue="Python.cli help" />
|
||||
<item itemvalue="Python.cli new app" />
|
||||
<item itemvalue="Python.cli new base" />
|
||||
<item itemvalue="Python.cli new class" />
|
||||
<item itemvalue="Python.cli new configmodel" />
|
||||
<item itemvalue="Python.cli new enum" />
|
||||
<item itemvalue="Python.cli new service" />
|
||||
<item itemvalue="Python.cli publish" />
|
||||
<item itemvalue="Python.cli version" />
|
||||
<item itemvalue="Python.cli" />
|
||||
<item itemvalue="Python.main" />
|
||||
<item itemvalue="Python tests.Unittests" />
|
||||
</list>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python tests.Unittests" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="7e2256bc-a6b8-4880-83a6-8b0e3372d0a4" name="Default Changelist" comment="" />
|
||||
<created>1605881914521</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1605881914521</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00031" summary="Improved database module structure">
|
||||
<created>1607285697331</created>
|
||||
<option name="number" value="00031" />
|
||||
<option name="presentableId" value="LOCAL-00031" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607285697331</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00032" summary="Improved database module structure">
|
||||
<created>1607620265254</created>
|
||||
<option name="number" value="00032" />
|
||||
<option name="presentableId" value="LOCAL-00032" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607620265254</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00033" summary="Changed DatabaseConnection">
|
||||
<created>1607712129507</created>
|
||||
<option name="number" value="00033" />
|
||||
<option name="presentableId" value="LOCAL-00033" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607712129507</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00034" summary="Improved session reference">
|
||||
<created>1607971885250</created>
|
||||
<option name="number" value="00034" />
|
||||
<option name="presentableId" value="LOCAL-00034" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607971885250</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00035" summary="Added console module">
|
||||
<created>1607976456889</created>
|
||||
<option name="number" value="00035" />
|
||||
<option name="presentableId" value="LOCAL-00035" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607976456889</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00036" summary="Added console module">
|
||||
<created>1607976626173</created>
|
||||
<option name="number" value="00036" />
|
||||
<option name="presentableId" value="LOCAL-00036" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1607976626173</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00037" summary="Improved console">
|
||||
<created>1608037411172</created>
|
||||
<option name="number" value="00037" />
|
||||
<option name="presentableId" value="LOCAL-00037" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608037411172</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00038" summary="Improved console">
|
||||
<created>1608047595029</created>
|
||||
<option name="number" value="00038" />
|
||||
<option name="presentableId" value="LOCAL-00038" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608047595029</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00039" summary="Improved ApplicationHost">
|
||||
<created>1608047655667</created>
|
||||
<option name="number" value="00039" />
|
||||
<option name="presentableId" value="LOCAL-00039" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608047655667</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00040" summary="Improved publisher">
|
||||
<created>1608048544558</created>
|
||||
<option name="number" value="00040" />
|
||||
<option name="presentableId" value="LOCAL-00040" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608048544558</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00041" summary="Improved publisher">
|
||||
<created>1608049672925</created>
|
||||
<option name="number" value="00041" />
|
||||
<option name="presentableId" value="LOCAL-00041" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608049672925</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00042" summary="Published for 2020.12.9">
|
||||
<created>1608049772153</created>
|
||||
<option name="number" value="00042" />
|
||||
<option name="presentableId" value="LOCAL-00042" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608049772153</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00043" summary="Publish improvements for pip install">
|
||||
<created>1608059323858</created>
|
||||
<option name="number" value="00043" />
|
||||
<option name="presentableId" value="LOCAL-00043" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608059323858</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00044" summary="Improved setup.py">
|
||||
<created>1608059501153</created>
|
||||
<option name="number" value="00044" />
|
||||
<option name="presentableId" value="LOCAL-00044" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608059501153</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00045" summary="Added first cli commands">
|
||||
<created>1608066984496</created>
|
||||
<option name="number" value="00045" />
|
||||
<option name="presentableId" value="LOCAL-00045" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608066984496</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00046" summary="Bugfixes and improved setup logic">
|
||||
<created>1608070231599</created>
|
||||
<option name="number" value="00046" />
|
||||
<option name="presentableId" value="LOCAL-00046" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608070231599</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00047" summary="Improved cli">
|
||||
<created>1608122289003</created>
|
||||
<option name="number" value="00047" />
|
||||
<option name="presentableId" value="LOCAL-00047" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608122289003</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00048" summary="Added version command to cli">
|
||||
<created>1608125743068</created>
|
||||
<option name="number" value="00048" />
|
||||
<option name="presentableId" value="LOCAL-00048" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608125743068</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00049" summary="Improved version command & improved help command">
|
||||
<created>1608127752645</created>
|
||||
<option name="number" value="00049" />
|
||||
<option name="presentableId" value="LOCAL-00049" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608127752645</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00050" summary="Improved cli error handling">
|
||||
<created>1608127998033</created>
|
||||
<option name="number" value="00050" />
|
||||
<option name="presentableId" value="LOCAL-00050" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608127998034</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00051" summary="Removed module template">
|
||||
<created>1608128026922</created>
|
||||
<option name="number" value="00051" />
|
||||
<option name="presentableId" value="LOCAL-00051" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608128026922</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00052" summary="Added build command to cli">
|
||||
<created>1608133651981</created>
|
||||
<option name="number" value="00052" />
|
||||
<option name="presentableId" value="LOCAL-00052" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608133651982</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00053" summary="Improved publish process">
|
||||
<created>1608136663213</created>
|
||||
<option name="number" value="00053" />
|
||||
<option name="presentableId" value="LOCAL-00053" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608136663213</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00054" summary="Improved publish process">
|
||||
<created>1608137669182</created>
|
||||
<option name="number" value="00054" />
|
||||
<option name="presentableId" value="LOCAL-00054" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608137669182</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00055" summary="Added publish command to cli">
|
||||
<created>1608138851088</created>
|
||||
<option name="number" value="00055" />
|
||||
<option name="presentableId" value="LOCAL-00055" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608138851088</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00056" summary="Added imports to cli module">
|
||||
<created>1608138986801</created>
|
||||
<option name="number" value="00056" />
|
||||
<option name="presentableId" value="LOCAL-00056" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608138986801</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00057" summary="Improved help command">
|
||||
<created>1608139067953</created>
|
||||
<option name="number" value="00057" />
|
||||
<option name="presentableId" value="LOCAL-00057" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608139067953</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00058" summary="Changed deps">
|
||||
<created>1608139239527</created>
|
||||
<option name="number" value="00058" />
|
||||
<option name="presentableId" value="LOCAL-00058" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608139239527</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00059" summary="Bugfixes">
|
||||
<created>1608139414722</created>
|
||||
<option name="number" value="00059" />
|
||||
<option name="presentableId" value="LOCAL-00059" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608139414722</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00060" summary="Bugfixes">
|
||||
<created>1608139502304</created>
|
||||
<option name="number" value="00060" />
|
||||
<option name="presentableId" value="LOCAL-00060" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608139502304</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00061" summary="Removed publisher.py">
|
||||
<created>1608139612476</created>
|
||||
<option name="number" value="00061" />
|
||||
<option name="presentableId" value="LOCAL-00061" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608139612476</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00062" summary="Added first steps of database command">
|
||||
<created>1608383809354</created>
|
||||
<option name="number" value="00062" />
|
||||
<option name="presentableId" value="LOCAL-00062" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608383809355</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00063" summary="Improved error handling">
|
||||
<created>1608383870849</created>
|
||||
<option name="number" value="00063" />
|
||||
<option name="presentableId" value="LOCAL-00063" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608383870849</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00064" summary="Improved service providing">
|
||||
<created>1608472168532</created>
|
||||
<option name="number" value="00064" />
|
||||
<option name="presentableId" value="LOCAL-00064" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608472168532</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00065" summary="Added email client">
|
||||
<created>1608472183294</created>
|
||||
<option name="number" value="00065" />
|
||||
<option name="presentableId" value="LOCAL-00065" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608472183294</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00066" summary="Published">
|
||||
<created>1608474022759</created>
|
||||
<option name="number" value="00066" />
|
||||
<option name="presentableId" value="LOCAL-00066" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608474022759</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00067" summary="Improved publisher">
|
||||
<created>1608474032244</created>
|
||||
<option name="number" value="00067" />
|
||||
<option name="presentableId" value="LOCAL-00067" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608474032244</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00068" summary="Added imports">
|
||||
<created>1608474289859</created>
|
||||
<option name="number" value="00068" />
|
||||
<option name="presentableId" value="LOCAL-00068" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608474289859</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00069" summary="Removed build form gitignore, added build command">
|
||||
<created>1608813096023</created>
|
||||
<option name="number" value="00069" />
|
||||
<option name="presentableId" value="LOCAL-00069" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608813096023</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00070" summary="Added init file for build command package">
|
||||
<created>1608813152266</created>
|
||||
<option name="number" value="00070" />
|
||||
<option name="presentableId" value="LOCAL-00070" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608813152266</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00071" summary="Added pycharm files to gitignore">
|
||||
<created>1608822597300</created>
|
||||
<option name="number" value="00071" />
|
||||
<option name="presentableId" value="LOCAL-00071" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608822597311</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00072" summary="Added more development tests">
|
||||
<created>1608823061488</created>
|
||||
<option name="number" value="00072" />
|
||||
<option name="presentableId" value="LOCAL-00072" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608823061489</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00073" summary="Added new tester and CredentialManager TestCase">
|
||||
<created>1608894745271</created>
|
||||
<option name="number" value="00073" />
|
||||
<option name="presentableId" value="LOCAL-00073" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608894745274</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00074" summary="Bugfix">
|
||||
<created>1608896199033</created>
|
||||
<option name="number" value="00074" />
|
||||
<option name="presentableId" value="LOCAL-00074" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608896199034</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00075" summary="Added TimeFormatSettings Test">
|
||||
<created>1608896235005</created>
|
||||
<option name="number" value="00075" />
|
||||
<option name="presentableId" value="LOCAL-00075" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608896235006</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00076" summary="Bugfixes">
|
||||
<created>1608901608928</created>
|
||||
<option name="number" value="00076" />
|
||||
<option name="presentableId" value="LOCAL-00076" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608901608930</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00077" summary="Improved tests">
|
||||
<created>1608921175852</created>
|
||||
<option name="number" value="00077" />
|
||||
<option name="presentableId" value="LOCAL-00077" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608921175853</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00078" summary="Bugfixes and improved tests">
|
||||
<created>1608986131753</created>
|
||||
<option name="number" value="00078" />
|
||||
<option name="presentableId" value="LOCAL-00078" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1608986131755</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00079" summary="Removed unused packages">
|
||||
<created>1611431001647</created>
|
||||
<option name="number" value="00079" />
|
||||
<option name="presentableId" value="LOCAL-00079" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1611431001649</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="80" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="Added build command to cli" />
|
||||
<MESSAGE value="Improved publish process" />
|
||||
<MESSAGE value="Added publish command to cli" />
|
||||
<MESSAGE value="Added imports to cli module" />
|
||||
<MESSAGE value="Improved help command" />
|
||||
<MESSAGE value="Changed deps" />
|
||||
<MESSAGE value="Removed publisher.py" />
|
||||
<MESSAGE value="Added first steps of database command" />
|
||||
<MESSAGE value="Improved error handling" />
|
||||
<MESSAGE value="Improved service providing" />
|
||||
<MESSAGE value="Added email client" />
|
||||
<MESSAGE value="Published" />
|
||||
<MESSAGE value="Improved publisher" />
|
||||
<MESSAGE value="Added imports" />
|
||||
<MESSAGE value="Removed build form gitignore, added build command" />
|
||||
<MESSAGE value="Added init file for build command package" />
|
||||
<MESSAGE value="Added pycharm files to gitignore" />
|
||||
<MESSAGE value="Added more development tests" />
|
||||
<MESSAGE value="Added new tester and CredentialManager TestCase" />
|
||||
<MESSAGE value="Bugfix" />
|
||||
<MESSAGE value="Added TimeFormatSettings Test" />
|
||||
<MESSAGE value="Bugfixes" />
|
||||
<MESSAGE value="Improved tests" />
|
||||
<MESSAGE value="Bugfixes and improved tests" />
|
||||
<MESSAGE value="Removed unused packages" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Removed unused packages" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/src/tests/publish_test/publisher_test.py</url>
|
||||
<line>50</line>
|
||||
<option name="timeStamp" value="3" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
101
README.md
101
README.md
@ -1,2 +1,101 @@
|
||||
# sh_common_py_lib
|
||||
<h1 align="center">CPL - Common python library</h1>
|
||||
|
||||
<!-- Summary -->
|
||||
<p align="center">
|
||||
<!-- <img src="" alt="cpl-logo" width="120px" height="120px"/> -->
|
||||
<br>
|
||||
<i>
|
||||
CPL is a development platform for python server applications
|
||||
<br>using Python.</i>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#getting-started">Getting Started</a>
|
||||
<ul>
|
||||
<li><a href="#prerequisites">Prerequisites</a></li>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#roadmap">Roadmap</a></li>
|
||||
<li><a href="#contributing">Contributing</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
|
||||
|
||||
<!-- GETTING STARTED -->
|
||||
## Getting Started
|
||||
|
||||
[Get started with CPL][quickstart].
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Install [python] which includes [Pip installs packages][pip]
|
||||
|
||||
### Installation
|
||||
|
||||
Install the cpl package
|
||||
```sh
|
||||
pip install sh_cpl --extra-index-url https://pip.sh-edraft.de
|
||||
```
|
||||
|
||||
Create workspace:
|
||||
```sh
|
||||
cpl new <console|library> <PROJECT NAME>
|
||||
```
|
||||
|
||||
Run the application:
|
||||
```sh
|
||||
cd <PROJECT NAME>
|
||||
cpl start
|
||||
```
|
||||
|
||||
|
||||
<!-- ROADMAP -->
|
||||
## Roadmap
|
||||
|
||||
See the [open issues](https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib/issues) for a list of proposed features (and known issues).
|
||||
|
||||
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
## Contributing
|
||||
|
||||
### Contributing Guidelines
|
||||
|
||||
Read through our [contributing guidelines][contributing] to learn about our submission process, coding rules and more.
|
||||
|
||||
### Want to Help?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing][contributing].
|
||||
|
||||
|
||||
|
||||
<!-- LICENSE -->
|
||||
## License
|
||||
|
||||
Distributed under the MIT License. See [LICENSE] for more information.
|
||||
|
||||
|
||||
|
||||
<!-- CONTACT -->
|
||||
## Contact
|
||||
|
||||
Sven Heidemann - sven.heidemann@sh-edraft.de
|
||||
|
||||
Project link: [https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib](https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib)
|
||||
|
||||
<!-- External LINKS -->
|
||||
[pip_url]: https://pip.sh-edraft.de
|
||||
[python]: https://www.python.org/
|
||||
[pip]: https://pypi.org/project/pip/
|
||||
|
||||
<!-- Internal LINKS -->
|
||||
[project]: https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib
|
||||
[quickstart]: https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib/wiki/quickstart
|
||||
[contributing]: https://git.sh-edraft.de/sh-edraft.de/sh_common_py_lib/wiki/contributing
|
||||
[license]: LICENSE
|
||||
|
57
cpl.json
Normal file
57
cpl.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"ProjectSettings": {
|
||||
"Name": "sh_cpl",
|
||||
"Version": {
|
||||
"Major": "2021",
|
||||
"Minor": "04",
|
||||
"Micro": "0"
|
||||
},
|
||||
"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": [
|
||||
"colorama==0.4.4",
|
||||
"mysql-connector==2.2.9",
|
||||
"psutil==5.8.0",
|
||||
"packaging==20.9",
|
||||
"pyfiglet==0.8.post1",
|
||||
"pynput==1.7.3",
|
||||
"SQLAlchemy==1.4.3",
|
||||
"setuptools==54.2.0",
|
||||
"tabulate==0.8.9",
|
||||
"termcolor==1.1.0",
|
||||
"watchdog==2.0.2",
|
||||
"wheel==0.36.2"
|
||||
],
|
||||
"PythonVersion": ">=3.8",
|
||||
"PythonPath": {},
|
||||
"Classifiers": []
|
||||
},
|
||||
"BuildSettings": {
|
||||
"ProjectType": "library",
|
||||
"SourcePath": "src",
|
||||
"OutputPath": "dist",
|
||||
"Main": "cpl_cli.main",
|
||||
"EntryPoint": "cpl",
|
||||
"IncludePackageData": true,
|
||||
"Included": [
|
||||
"*/templates"
|
||||
],
|
||||
"Excluded": [
|
||||
"*/__pycache__",
|
||||
"*/logs",
|
||||
"*/tests"
|
||||
],
|
||||
"PackageData": {
|
||||
"cpl_cli": [
|
||||
"*.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
prefix: cpl
|
||||
commands:
|
||||
new:
|
||||
app
|
||||
base
|
||||
class
|
||||
configmodel
|
||||
enum
|
||||
service
|
19
docs/cli.txt
Normal file
19
docs/cli.txt
Normal file
@ -0,0 +1,19 @@
|
||||
prefix: cpl
|
||||
commands:
|
||||
build
|
||||
|
||||
generate:
|
||||
abc | a
|
||||
class | c
|
||||
configmodel | cm
|
||||
enum | e
|
||||
service | s
|
||||
|
||||
help
|
||||
new
|
||||
console
|
||||
|
||||
start
|
||||
publish
|
||||
update
|
||||
version
|
11
docs/pip.txt
Normal file
11
docs/pip.txt
Normal file
@ -0,0 +1,11 @@
|
||||
upload:
|
||||
prod:
|
||||
twine upload --repository-url https://pip.sh-edraft.de dist/publish/setup/*
|
||||
twine upload -r pip.sh-edraft.de dist/publish/setup/*
|
||||
|
||||
dev:
|
||||
twine upload --repository-url https://pip-dev.sh-edraft.de dist/publish/setup/*
|
||||
twine upload -r pip-dev.sh-edraft.de dist/publish/setup/*
|
||||
|
||||
install:
|
||||
pip install --extra-index-url https://pip.sh-edraft.de/ sh_cpl
|
@ -1,10 +0,0 @@
|
||||
- sh_edraft
|
||||
- common # Contains Interfaces and models for the hole library
|
||||
- interface
|
||||
- model
|
||||
- configuration # Contains classes for app configuration by JSON, ENV vars and arguments
|
||||
- discord # Contains classes for better use of discord.py
|
||||
- logging # Contains classes for logging
|
||||
- mailing # Contains classes for mailing
|
||||
- messenger # Contains classes for sh_messenger_server client
|
||||
- service # Contains classes to provide and use the services defined in this library
|
@ -1,2 +0,0 @@
|
||||
- create logger
|
||||
- use logger in publisher
|
@ -1,25 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
$Name $Description
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
$LongDescription
|
||||
|
||||
:copyright: (c) $CopyrightDate $CopyrightName
|
||||
:license: $LicenseName$LicenseDescription
|
||||
|
||||
"""
|
||||
|
||||
__title__ = '$Title'
|
||||
__author__ = '$Author'
|
||||
__license__ = '$LicenseName'
|
||||
__copyright__ = 'Copyright (c) $CopyrightDate $CopyrightName'
|
||||
__version__ = '$Version'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
$Imports
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major=$Major, minor=$Minor, micro=$Micro)
|
@ -1,29 +0,0 @@
|
||||
aiohttp==3.6.3
|
||||
async-timeout==3.0.1
|
||||
attrs==20.3.0
|
||||
certifi==2020.11.8
|
||||
chardet==3.0.4
|
||||
click==7.1.2
|
||||
dateutils==0.6.12
|
||||
discord==1.0.1
|
||||
discord.py==1.5.1
|
||||
Flask==1.1.2
|
||||
idna==2.10
|
||||
itsdangerous==1.1.0
|
||||
Jinja2==2.11.2
|
||||
keyboard==0.13.5
|
||||
MarkupSafe==1.1.1
|
||||
multidict==4.7.6
|
||||
mysql-connector==2.2.9
|
||||
overloading==0.5.0
|
||||
python-dateutil==2.8.1
|
||||
pytz==2020.4
|
||||
six==1.15.0
|
||||
SQLAlchemy==1.3.20
|
||||
termcolor==1.1.0
|
||||
urllib3==1.26.2
|
||||
Werkzeug==1.0.1
|
||||
yarl==1.5.1
|
||||
setuptools~=49.2.1
|
||||
pyfiglet~=0.8.post1
|
||||
tabulate~=0.8.7
|
@ -1,2 +0,0 @@
|
||||
include ../ README
|
||||
recursive-include sh_edraft *.txt
|
@ -1,66 +0,0 @@
|
||||
{
|
||||
"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": "../build/logs/",
|
||||
"Filename": "log_$start_time.log",
|
||||
"ConsoleLogLevel": "INFO",
|
||||
"FileLogLevel": "TRACE"
|
||||
},
|
||||
"PublishSettings": {
|
||||
"SourcePath": "./",
|
||||
"DistPath": "../build/dist",
|
||||
"Templates": [
|
||||
{
|
||||
"TemplatePath": "../publish_templates/all_template.txt",
|
||||
"Name": "all",
|
||||
"Description": "",
|
||||
"LongDescription": "",
|
||||
"CopyrightDate": "2020",
|
||||
"CopyrightName": "sh-edraft.de",
|
||||
"LicenseName": "MIT",
|
||||
"LicenseDescription": ", see LICENSE for more details.",
|
||||
"Title": "",
|
||||
"Author": "Sven Heidemann",
|
||||
"Version": {
|
||||
"Major": 2020,
|
||||
"Minor": 12,
|
||||
"Micro": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"TemplatePath": "../publish_templates/all_template.txt",
|
||||
"Name": "sh_edraft",
|
||||
"Description": "common python library",
|
||||
"LongDescription": "Library to share common classes and models used at sh-edraft.de",
|
||||
"CopyrightDate": "2020",
|
||||
"CopyrightName": "sh-edraft.de",
|
||||
"LicenseName": "MIT",
|
||||
"LicenseDescription": ", see LICENSE for more details.",
|
||||
"Title": "",
|
||||
"Author": "Sven Heidemann",
|
||||
"Version": {
|
||||
"Major": 2020,
|
||||
"Minor": 12,
|
||||
"Micro": 10
|
||||
}
|
||||
}
|
||||
],
|
||||
"IncludedFiles": [
|
||||
"./MANIFEST.in",
|
||||
"../LICENSE",
|
||||
"../README.md",
|
||||
"../requirements.txt",
|
||||
"sh_edraft/cli/cpl_cli/templates"
|
||||
],
|
||||
"ExcludedFiles": [
|
||||
"./tests",
|
||||
"./tests_dev"
|
||||
],
|
||||
"TemplateEnding": "_template.txt"
|
||||
}
|
||||
}
|
25
src/cpl/__init__.py
Normal file
25
src/cpl/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'sh_cpl.cpl'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
29
src/cpl/application/__init__.py
Normal file
29
src/cpl/application/__init__.py
Normal file
@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.application'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .application_abc import ApplicationABC
|
||||
from .application_builder import ApplicationBuilder
|
||||
from .application_builder_abc import ApplicationBuilderABC
|
||||
from .startup_abc import StartupABC
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
46
src/cpl/application/application_abc.py
Normal file
46
src/cpl/application/application_abc.py
Normal file
@ -0,0 +1,46 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
from cpl.environment import ApplicationEnvironmentABC
|
||||
|
||||
|
||||
class ApplicationABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, config: ConfigurationABC, services: ServiceProviderABC):
|
||||
"""
|
||||
ABC of application
|
||||
"""
|
||||
self._configuration: Optional[ConfigurationABC] = config
|
||||
self._environment: Optional[ApplicationEnvironmentABC] = self._configuration.environment
|
||||
self._services: Optional[ServiceProviderABC] = services
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Entry point
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
self.configure()
|
||||
self.main()
|
||||
except KeyboardInterrupt:
|
||||
Console.close()
|
||||
|
||||
@abstractmethod
|
||||
def configure(self):
|
||||
"""
|
||||
Prepare the application
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def main(self):
|
||||
"""
|
||||
Custom entry point
|
||||
:return:
|
||||
"""
|
||||
pass
|
41
src/cpl/application/application_builder.py
Normal file
41
src/cpl/application/application_builder.py
Normal file
@ -0,0 +1,41 @@
|
||||
from typing import Type, Optional
|
||||
|
||||
from cpl.application.application_abc import ApplicationABC
|
||||
from cpl.application.application_builder_abc import ApplicationBuilderABC
|
||||
from cpl.application.startup_abc import StartupABC
|
||||
from cpl.configuration.configuration import Configuration
|
||||
from cpl.dependency_injection.service_collection import ServiceCollection
|
||||
|
||||
|
||||
class ApplicationBuilder(ApplicationBuilderABC):
|
||||
|
||||
def __init__(self, app: Type[ApplicationABC]):
|
||||
"""
|
||||
Builder class for application
|
||||
"""
|
||||
ApplicationBuilderABC.__init__(self)
|
||||
self._app = app
|
||||
self._startup: Optional[StartupABC] = None
|
||||
|
||||
self._configuration = Configuration()
|
||||
self._environment = self._configuration.environment
|
||||
self._services = ServiceCollection(self._configuration)
|
||||
|
||||
def use_startup(self, startup: Type[StartupABC]):
|
||||
"""
|
||||
Sets the used startup class
|
||||
:param startup:
|
||||
:return:
|
||||
"""
|
||||
self._startup = startup(self._configuration, self._services)
|
||||
|
||||
def build(self) -> ApplicationABC:
|
||||
"""
|
||||
Creates application host and runtime
|
||||
:return:
|
||||
"""
|
||||
if self._startup is not None:
|
||||
self._startup.configure_configuration()
|
||||
self._startup.configure_services()
|
||||
|
||||
return self._app(self._configuration, self._services.build_service_provider())
|
30
src/cpl/application/application_builder_abc.py
Normal file
30
src/cpl/application/application_builder_abc.py
Normal file
@ -0,0 +1,30 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Type
|
||||
|
||||
from cpl.application.application_abc import ApplicationABC
|
||||
from cpl.application.startup_abc import StartupABC
|
||||
|
||||
|
||||
class ApplicationBuilderABC(ABC):
|
||||
|
||||
def __init__(self, *args):
|
||||
"""
|
||||
ABC of application builder
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def use_startup(self, startup: Type[StartupABC]):
|
||||
"""
|
||||
Sets the used startup class
|
||||
:param startup:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def build(self) -> ApplicationABC:
|
||||
"""
|
||||
Creates application host and runtime
|
||||
:return:
|
||||
"""
|
||||
pass
|
29
src/cpl/application/startup_abc.py
Normal file
29
src/cpl/application/startup_abc.py
Normal file
@ -0,0 +1,29 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
|
||||
|
||||
class StartupABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, *args):
|
||||
"""
|
||||
ABC for a startup class
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def configure_configuration(self) -> ConfigurationABC:
|
||||
"""
|
||||
Creates configuration of application
|
||||
:return: configuration
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def configure_services(self) -> ServiceProviderABC:
|
||||
"""
|
||||
Creates service provider
|
||||
:return: service provider
|
||||
"""
|
||||
pass
|
30
src/cpl/configuration/__init__.py
Normal file
30
src/cpl/configuration/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.configuration'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .configuration import Configuration
|
||||
from .configuration_abc import ConfigurationABC
|
||||
from .configuration_model_abc import ConfigurationModelABC
|
||||
from .configuration_variable_name_enum import ConfigurationVariableNameEnum
|
||||
from .console_argument import ConsoleArgument
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
357
src/cpl/configuration/configuration.py
Normal file
357
src/cpl/configuration/configuration.py
Normal file
@ -0,0 +1,357 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from collections import Callable
|
||||
from typing import Union, Type, Optional
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.configuration.configuration_variable_name_enum import ConfigurationVariableNameEnum
|
||||
from cpl.configuration.console_argument import ConsoleArgument
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.environment.application_environment import ApplicationEnvironment
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.environment.environment_name_enum import EnvironmentNameEnum
|
||||
|
||||
|
||||
class Configuration(ConfigurationABC):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Representation of configuration
|
||||
"""
|
||||
ConfigurationABC.__init__(self)
|
||||
|
||||
self._application_environment = ApplicationEnvironment()
|
||||
self._config: dict[Union[type, str], Union[ConfigurationModelABC, str]] = {}
|
||||
|
||||
self._argument_types: list[ConsoleArgument] = []
|
||||
self._additional_arguments: list[str] = []
|
||||
|
||||
self._argument_error_function: Optional[Callable] = None
|
||||
|
||||
self._handled_args = []
|
||||
|
||||
@property
|
||||
def environment(self) -> ApplicationEnvironmentABC:
|
||||
return self._application_environment
|
||||
|
||||
@property
|
||||
def additional_arguments(self) -> list[str]:
|
||||
return self._additional_arguments
|
||||
|
||||
@property
|
||||
def argument_error_function(self) -> Optional[Callable]:
|
||||
return self._argument_error_function
|
||||
|
||||
@argument_error_function.setter
|
||||
def argument_error_function(self, argument_error_function: Callable):
|
||||
self._argument_error_function = argument_error_function
|
||||
|
||||
@staticmethod
|
||||
def _print_info(name: str, message: str):
|
||||
"""
|
||||
Prints an info message
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(f'[{name}] {message}')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
@staticmethod
|
||||
def _print_warn(name: str, message: str):
|
||||
"""
|
||||
Prints a warning
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
Console.set_foreground_color(ForegroundColorEnum.yellow)
|
||||
Console.write_line(f'[{name}] {message}')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
@staticmethod
|
||||
def _print_error(name: str, message: str):
|
||||
"""
|
||||
Prints an error
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[{name}] {message}')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def _set_variable(self, name: str, value: str):
|
||||
"""
|
||||
Sets variable to given value
|
||||
:param name:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
if name == ConfigurationVariableNameEnum.environment.value:
|
||||
self._application_environment.environment_name = EnvironmentNameEnum(value)
|
||||
|
||||
elif name == ConfigurationVariableNameEnum.name.value:
|
||||
self._application_environment.application_name = value
|
||||
|
||||
elif name == ConfigurationVariableNameEnum.customer.value:
|
||||
self._application_environment.customer = value
|
||||
|
||||
else:
|
||||
self._config[name] = value
|
||||
|
||||
def _validate_argument_child(self, argument: str, argument_type: ConsoleArgument,
|
||||
next_arguments: Optional[list[str]]) -> bool:
|
||||
"""
|
||||
Validates the child arguments of argument
|
||||
:param argument:
|
||||
:param argument_type:
|
||||
:param next_arguments:
|
||||
:return:
|
||||
"""
|
||||
if argument_type.console_arguments is not None and len(argument_type.console_arguments) > 0:
|
||||
found = False
|
||||
for child_argument_type in argument_type.console_arguments:
|
||||
found = self._validate_argument_by_argument_type(argument, child_argument_type, next_arguments)
|
||||
if found and child_argument_type.name not in self._additional_arguments:
|
||||
self._additional_arguments.append(child_argument_type.name)
|
||||
|
||||
if not found:
|
||||
raise Exception(f'Invalid argument: {argument}')
|
||||
|
||||
return found
|
||||
|
||||
return True
|
||||
|
||||
def _validate_argument_by_argument_type(self, argument: str, argument_type: ConsoleArgument,
|
||||
next_arguments: list[str] = None) -> bool:
|
||||
"""
|
||||
Validate argument by argument type
|
||||
:param argument:
|
||||
:param argument_type:
|
||||
:param next_arguments:
|
||||
:return:
|
||||
"""
|
||||
argument_name = ''
|
||||
value = ''
|
||||
result = False
|
||||
|
||||
if argument_type.value_token != '' and argument_type.value_token in argument:
|
||||
# ?new=value
|
||||
found = False
|
||||
for alias in argument_type.aliases:
|
||||
if alias in argument:
|
||||
found = True
|
||||
|
||||
if argument_type.name not in argument_name and not found:
|
||||
return False
|
||||
|
||||
if argument_type.is_value_token_optional is not None and argument_type.is_value_token_optional:
|
||||
if argument_type.name not in self._additional_arguments:
|
||||
self._additional_arguments.append(argument_type.name)
|
||||
result = True
|
||||
|
||||
if argument_type.token != '' and argument.startswith(argument_type.token):
|
||||
# --new=value
|
||||
argument_name = argument.split(argument_type.token)[1].split(argument_type.value_token)[0]
|
||||
else:
|
||||
# new=value
|
||||
argument_name = argument.split(argument_type.token)[1]
|
||||
|
||||
result = True
|
||||
|
||||
if argument_type.is_value_token_optional is True:
|
||||
is_valid = False
|
||||
|
||||
name_list = argument.split(argument_type.token)
|
||||
if len(name_list) > 1:
|
||||
value_list = name_list[1].split(argument_type.value_token)
|
||||
if len(value_list) > 1:
|
||||
is_valid = True
|
||||
value = argument.split(argument_type.token)[1].split(argument_type.value_token)[1]
|
||||
|
||||
if not is_valid:
|
||||
if argument_type.name not in self._additional_arguments:
|
||||
self._additional_arguments.append(argument_type.name)
|
||||
result = True
|
||||
else:
|
||||
value = argument.split(argument_type.token)[1].split(argument_type.value_token)[1]
|
||||
|
||||
if argument_name != argument_type.name and argument_name not in argument_type.aliases:
|
||||
return False
|
||||
|
||||
self._set_variable(argument_type.name, value)
|
||||
result = True
|
||||
|
||||
elif argument_type.value_token == ' ':
|
||||
# ?new value
|
||||
found = False
|
||||
for alias in argument_type.aliases:
|
||||
if alias in argument:
|
||||
found = True
|
||||
|
||||
if argument_type.name not in argument and not found:
|
||||
return False
|
||||
|
||||
if (next_arguments is None or len(next_arguments) == 0) and \
|
||||
argument_type.is_value_token_optional is not True:
|
||||
raise Exception(f'Invalid argument: {argument}')
|
||||
|
||||
if (next_arguments is None or len(next_arguments) == 0) and argument_type.is_value_token_optional is True:
|
||||
value = ''
|
||||
else:
|
||||
value = next_arguments[0]
|
||||
self._handled_args.append(value)
|
||||
|
||||
if argument_type.token != '' and argument.startswith(argument_type.token):
|
||||
# --new value
|
||||
argument_name = argument.split(argument_type.token)[1]
|
||||
else:
|
||||
# new value
|
||||
argument_name = argument
|
||||
|
||||
if argument_name != argument_type.name and argument_name not in argument_type.aliases:
|
||||
return False
|
||||
|
||||
if value == '':
|
||||
if argument_type.name not in self._additional_arguments:
|
||||
self._additional_arguments.append(argument_type.name)
|
||||
else:
|
||||
self._set_variable(argument_type.name, value)
|
||||
|
||||
result = True
|
||||
|
||||
elif argument_type.name == argument or argument in argument_type.aliases:
|
||||
# new
|
||||
self._additional_arguments.append(argument_type.name)
|
||||
result = True
|
||||
|
||||
if result:
|
||||
self._handled_args.append(argument)
|
||||
if next_arguments is not None and len(next_arguments) > 0:
|
||||
next_args = []
|
||||
if len(next_arguments) > 1:
|
||||
next_args = next_arguments[1:]
|
||||
result = self._validate_argument_child(next_arguments[0], argument_type, next_args)
|
||||
|
||||
return result
|
||||
|
||||
def add_environment_variables(self, prefix: str):
|
||||
for variable in ConfigurationVariableNameEnum.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_console_argument(self, argument: ConsoleArgument):
|
||||
self._argument_types.append(argument)
|
||||
|
||||
def add_console_arguments(self, error: bool = None):
|
||||
for arg_name in ConfigurationVariableNameEnum.to_list():
|
||||
self.add_console_argument(ConsoleArgument('--', str(arg_name).upper(), [str(arg_name).lower()], '='))
|
||||
|
||||
arg_list = sys.argv[1:]
|
||||
for i in range(0, len(arg_list)):
|
||||
argument = arg_list[i]
|
||||
next_arguments = []
|
||||
error_message = ''
|
||||
|
||||
if argument in self._handled_args:
|
||||
break
|
||||
|
||||
if i + 1 < len(arg_list):
|
||||
next_arguments = arg_list[i + 1:]
|
||||
|
||||
found = False
|
||||
for argument_type in self._argument_types:
|
||||
try:
|
||||
found = self._validate_argument_by_argument_type(argument, argument_type, next_arguments)
|
||||
if found:
|
||||
break
|
||||
except Exception as e:
|
||||
error_message = e
|
||||
|
||||
if not found and error_message == '' and error is not False:
|
||||
error_message = f'Invalid argument: {argument}'
|
||||
|
||||
if self._argument_error_function is not None:
|
||||
self._argument_error_function(error_message)
|
||||
else:
|
||||
self._print_error(__name__, error_message)
|
||||
|
||||
exit()
|
||||
|
||||
def add_json_file(self, name: str, optional: bool = None, output: bool = True, path: str = None):
|
||||
path_root = self._application_environment.content_root_path
|
||||
if path is not None:
|
||||
path_root = path
|
||||
|
||||
if str(path_root).endswith('/') and not name.startswith('/'):
|
||||
file_path = f'{path_root}{name}'
|
||||
else:
|
||||
file_path = f'{path_root}/{name}'
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
if optional is not True:
|
||||
if output:
|
||||
self._print_error(__name__, f'File not found: {file_path}')
|
||||
|
||||
exit()
|
||||
|
||||
if output:
|
||||
self._print_warn(__name__, f'Not Loaded config file: {file_path}')
|
||||
|
||||
return None
|
||||
|
||||
config_from_file = self._load_json_file(file_path, output)
|
||||
for sub in ConfigurationModelABC.__subclasses__():
|
||||
for key, value in config_from_file.items():
|
||||
if sub.__name__ == key or sub.__name__.replace('Settings', '') == key:
|
||||
configuration = sub()
|
||||
configuration.from_dict(value)
|
||||
self.add_configuration(sub, configuration)
|
||||
|
||||
def _load_json_file(self, file: str, output: bool) -> dict:
|
||||
"""
|
||||
Reads the json file
|
||||
:param file:
|
||||
:param output:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
# open config file, create if not exists
|
||||
with open(file, encoding='utf-8') as cfg:
|
||||
# load json
|
||||
json_cfg = json.load(cfg)
|
||||
if output:
|
||||
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: ConfigurationModelABC):
|
||||
self._config[key_type] = value
|
||||
|
||||
def get_configuration(self, search_type: Union[str, Type[ConfigurationModelABC]]) -> Union[
|
||||
str, Callable[ConfigurationModelABC]]:
|
||||
if type(search_type) is str:
|
||||
if search_type == ConfigurationVariableNameEnum.environment.value:
|
||||
return self._application_environment.environment_name
|
||||
|
||||
elif search_type == ConfigurationVariableNameEnum.name.value:
|
||||
return self._application_environment.application_name
|
||||
|
||||
elif search_type == ConfigurationVariableNameEnum.customer.value:
|
||||
return self._application_environment.customer
|
||||
|
||||
if search_type not in self._config:
|
||||
return None
|
||||
|
||||
for config_model in self._config:
|
||||
if config_model == search_type:
|
||||
return self._config[config_model]
|
91
src/cpl/configuration/configuration_abc.py
Normal file
91
src/cpl/configuration/configuration_abc.py
Normal file
@ -0,0 +1,91 @@
|
||||
from abc import abstractmethod, ABC
|
||||
from collections import Callable
|
||||
from typing import Type, Union, Optional
|
||||
|
||||
from cpl.configuration.console_argument import ConsoleArgument
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
|
||||
|
||||
class ConfigurationABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC of configuration
|
||||
"""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def environment(self) -> ApplicationEnvironmentABC: pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def additional_arguments(self) -> list[str]: pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def argument_error_function(self) -> Optional[Callable]: pass
|
||||
|
||||
@argument_error_function.setter
|
||||
@abstractmethod
|
||||
def argument_error_function(self, argument_error_function: Callable): pass
|
||||
|
||||
@abstractmethod
|
||||
def add_environment_variables(self, prefix: str):
|
||||
"""
|
||||
Reads the environment variables
|
||||
:param prefix:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_console_argument(self, argument: ConsoleArgument):
|
||||
"""
|
||||
Adds console argument to known console arguments
|
||||
:param argument:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_console_arguments(self, error: bool = None):
|
||||
"""
|
||||
Reads the console arguments
|
||||
:param error: defines is invalid argument error will be shown or not
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_json_file(self, name: str, optional: bool = None, output: bool = True, path: str = None):
|
||||
"""
|
||||
Reads and saves settings from given json file
|
||||
:param name:
|
||||
:param optional:
|
||||
:param output:
|
||||
:param path:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_configuration(self, key_type: type, value: object):
|
||||
"""
|
||||
Add configuration object
|
||||
:param key_type:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_configuration(self, search_type: Union[str, Type[ConfigurationModelABC]]) -> Union[str, Callable[ConfigurationModelABC]]:
|
||||
"""
|
||||
Returns value in configuration by given type
|
||||
:param search_type:
|
||||
:return:
|
||||
"""
|
||||
pass
|
20
src/cpl/configuration/configuration_model_abc.py
Normal file
20
src/cpl/configuration/configuration_model_abc.py
Normal file
@ -0,0 +1,20 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class ConfigurationModelABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC for settings representation
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def from_dict(self, settings: dict):
|
||||
"""
|
||||
Converts attributes to dict
|
||||
:param settings:
|
||||
:return:
|
||||
"""
|
||||
pass
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ConfigurationVariableName(Enum):
|
||||
class ConfigurationVariableNameEnum(Enum):
|
||||
|
||||
environment = 'ENVIRONMENT'
|
||||
name = 'NAME'
|
||||
@ -9,4 +9,4 @@ class ConfigurationVariableName(Enum):
|
||||
|
||||
@staticmethod
|
||||
def to_list():
|
||||
return [var.value for var in ConfigurationVariableName]
|
||||
return [var.value for var in ConfigurationVariableNameEnum]
|
49
src/cpl/configuration/console_argument.py
Normal file
49
src/cpl/configuration/console_argument.py
Normal file
@ -0,0 +1,49 @@
|
||||
class ConsoleArgument:
|
||||
|
||||
def __init__(self,
|
||||
token: str,
|
||||
name: str,
|
||||
aliases: list[str],
|
||||
value_token: str,
|
||||
is_value_token_optional: bool = None,
|
||||
console_arguments: list['ConsoleArgument'] = None
|
||||
):
|
||||
"""
|
||||
Representation of an console argument
|
||||
:param token:
|
||||
:param name:
|
||||
:param aliases:
|
||||
:param value_token:
|
||||
:param is_value_token_optional:
|
||||
:param console_arguments:
|
||||
"""
|
||||
self._token = token
|
||||
self._name = name
|
||||
self._aliases = aliases
|
||||
self._value_token = value_token
|
||||
self._is_value_token_optional = is_value_token_optional
|
||||
self._console_arguments = console_arguments
|
||||
|
||||
@property
|
||||
def token(self) -> str:
|
||||
return self._token
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def aliases(self) -> list[str]:
|
||||
return self._aliases
|
||||
|
||||
@property
|
||||
def value_token(self) -> str:
|
||||
return self._value_token
|
||||
|
||||
@property
|
||||
def is_value_token_optional(self) -> bool:
|
||||
return self._is_value_token_optional
|
||||
|
||||
@property
|
||||
def console_arguments(self) -> list['ConsoleArgument']:
|
||||
return self._console_arguments
|
30
src/cpl/console/__init__.py
Normal file
30
src/cpl/console/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.console'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .background_color_enum import BackgroundColorEnum
|
||||
from .console import Console
|
||||
from .console_call import ConsoleCall
|
||||
from .foreground_color_enum import ForegroundColorEnum
|
||||
from .spinner_thread import SpinnerThread
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class BackgroundColor(Enum):
|
||||
class BackgroundColorEnum(Enum):
|
||||
|
||||
default = 'on_default'
|
||||
grey = 'on_grey'
|
528
src/cpl/console/console.py
Normal file
528
src/cpl/console/console.py
Normal file
@ -0,0 +1,528 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from collections import Callable
|
||||
from typing import Union, Optional
|
||||
|
||||
import colorama
|
||||
import pyfiglet
|
||||
from pynput import keyboard
|
||||
from pynput.keyboard import Key
|
||||
from tabulate import tabulate
|
||||
from termcolor import colored
|
||||
|
||||
from cpl.console.background_color_enum import BackgroundColorEnum
|
||||
from cpl.console.console_call import ConsoleCall
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.console.spinner_thread import SpinnerThread
|
||||
|
||||
|
||||
class Console:
|
||||
"""
|
||||
Useful functions for handling with input and output
|
||||
"""
|
||||
colorama.init()
|
||||
_is_first_write = True
|
||||
|
||||
_background_color: BackgroundColorEnum = BackgroundColorEnum.default
|
||||
_foreground_color: ForegroundColorEnum = ForegroundColorEnum.default
|
||||
_x: Optional[int] = None
|
||||
_y: Optional[int] = None
|
||||
_disabled: bool = False
|
||||
|
||||
_hold_back = False
|
||||
_hold_back_calls: list[ConsoleCall] = []
|
||||
|
||||
_select_menu_items: list[str] = []
|
||||
_is_first_select_menu_output = True
|
||||
_selected_menu_item_index: int = 0
|
||||
_selected_menu_item_char: str = ''
|
||||
_selected_menu_option_foreground_color: ForegroundColorEnum = ForegroundColorEnum.default
|
||||
_selected_menu_option_background_color: BackgroundColorEnum = BackgroundColorEnum.default
|
||||
_selected_menu_cursor_foreground_color: ForegroundColorEnum = ForegroundColorEnum.default
|
||||
_selected_menu_cursor_background_color: BackgroundColorEnum = BackgroundColorEnum.default
|
||||
|
||||
"""
|
||||
Properties
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def background_color(cls) -> str:
|
||||
return str(cls._background_color.value)
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def foreground_color(cls) -> str:
|
||||
return str(cls._foreground_color.value)
|
||||
|
||||
"""
|
||||
Settings
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def set_hold_back(cls, value: bool):
|
||||
cls._hold_back = value
|
||||
|
||||
@classmethod
|
||||
def set_background_color(cls, color: Union[BackgroundColorEnum, str]):
|
||||
"""
|
||||
Sets the background color
|
||||
:param color:
|
||||
:return:
|
||||
"""
|
||||
if type(color) is str:
|
||||
cls._background_color = BackgroundColorEnum[color]
|
||||
else:
|
||||
cls._background_color = color
|
||||
|
||||
@classmethod
|
||||
def set_foreground_color(cls, color: Union[ForegroundColorEnum, str]):
|
||||
"""
|
||||
Sets the foreground color
|
||||
:param color:
|
||||
:return:
|
||||
"""
|
||||
if type(color) is str:
|
||||
cls._foreground_color = ForegroundColorEnum[color]
|
||||
else:
|
||||
cls._foreground_color = color
|
||||
|
||||
@classmethod
|
||||
def reset_cursor_position(cls):
|
||||
"""
|
||||
Resets cursor position
|
||||
:return:
|
||||
"""
|
||||
cls._x = None
|
||||
cls._y = None
|
||||
|
||||
@classmethod
|
||||
def set_cursor_position(cls, x: int, y: int):
|
||||
"""
|
||||
Sets cursor position
|
||||
:param x:
|
||||
:param y:
|
||||
:return:
|
||||
"""
|
||||
cls._x = x
|
||||
cls._y = y
|
||||
|
||||
"""
|
||||
Useful protected methods
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _output(cls, string: str, x: int = None, y: int = None, end: str = None):
|
||||
"""
|
||||
Prints given output with given format
|
||||
:param string:
|
||||
:param x:
|
||||
:param y:
|
||||
:param end:
|
||||
:return:
|
||||
"""
|
||||
if cls._is_first_write:
|
||||
cls._is_first_write = False
|
||||
|
||||
if end is None:
|
||||
end = '\n'
|
||||
|
||||
args = []
|
||||
colored_args = []
|
||||
if x is not None and y is not None:
|
||||
args.append(f'\033[{y};{x}H')
|
||||
elif cls._x is not None and cls._y is not None:
|
||||
args.append(f'\033[{cls._y};{cls._x}H')
|
||||
|
||||
colored_args.append(string)
|
||||
if cls._foreground_color != ForegroundColorEnum.default and cls._background_color == BackgroundColorEnum.default:
|
||||
colored_args.append(cls._foreground_color.value)
|
||||
elif cls._foreground_color == ForegroundColorEnum.default and cls._background_color != BackgroundColorEnum.default:
|
||||
colored_args.append(cls._background_color.value)
|
||||
elif cls._foreground_color != ForegroundColorEnum.default and cls._background_color != BackgroundColorEnum.default:
|
||||
colored_args.append(cls._foreground_color.value)
|
||||
colored_args.append(cls._background_color.value)
|
||||
|
||||
args.append(colored(*colored_args))
|
||||
print(*args, end=end)
|
||||
|
||||
@classmethod
|
||||
def _show_select_menu(cls):
|
||||
"""
|
||||
Shows the select menu
|
||||
:return:
|
||||
"""
|
||||
if not cls._is_first_select_menu_output:
|
||||
for _ in range(0, len(cls._select_menu_items) + 1):
|
||||
sys.stdout.write('\x1b[1A\x1b[2K')
|
||||
else:
|
||||
cls._is_first_select_menu_output = False
|
||||
|
||||
for i in range(0, len(cls._select_menu_items)):
|
||||
Console.set_foreground_color(cls._selected_menu_cursor_foreground_color)
|
||||
Console.set_background_color(cls._selected_menu_cursor_background_color)
|
||||
placeholder = ''
|
||||
for _ in cls._selected_menu_item_char:
|
||||
placeholder += ' '
|
||||
|
||||
Console.write_line(
|
||||
f'{cls._selected_menu_item_char if cls._selected_menu_item_index == i else placeholder} ')
|
||||
Console.set_foreground_color(cls._selected_menu_option_foreground_color)
|
||||
Console.set_background_color(cls._selected_menu_option_background_color)
|
||||
Console.write(f'{cls._select_menu_items[i]}')
|
||||
|
||||
Console.write_line()
|
||||
|
||||
@classmethod
|
||||
def _select_menu_key_press(cls, key: Key):
|
||||
"""
|
||||
Event function when key press is detected
|
||||
:param key:
|
||||
:return:
|
||||
"""
|
||||
if key == Key.down:
|
||||
if cls._selected_menu_item_index == len(cls._select_menu_items) - 1:
|
||||
return
|
||||
cls._selected_menu_item_index += 1
|
||||
cls._show_select_menu()
|
||||
|
||||
elif key == Key.up:
|
||||
if cls._selected_menu_item_index == 0:
|
||||
return
|
||||
cls._selected_menu_item_index -= 1
|
||||
cls._show_select_menu()
|
||||
|
||||
elif key == Key.enter:
|
||||
return False
|
||||
|
||||
"""
|
||||
Useful public methods
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def banner(cls, string: str):
|
||||
"""
|
||||
Prints the string as a banner
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.banner, string))
|
||||
return
|
||||
|
||||
ascii_banner = pyfiglet.figlet_format(string)
|
||||
cls.write_line(ascii_banner)
|
||||
|
||||
@classmethod
|
||||
def color_reset(cls):
|
||||
"""
|
||||
Resets color
|
||||
:return:
|
||||
"""
|
||||
cls._background_color = BackgroundColorEnum.default
|
||||
cls._foreground_color = ForegroundColorEnum.default
|
||||
|
||||
@classmethod
|
||||
def clear(cls):
|
||||
"""
|
||||
Clears the console
|
||||
:return:
|
||||
"""
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.clear))
|
||||
return
|
||||
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
@classmethod
|
||||
def close(cls):
|
||||
"""
|
||||
Close the application
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.close))
|
||||
return
|
||||
|
||||
Console.color_reset()
|
||||
Console.write('\n\n\nPress any key to continue...')
|
||||
Console.read()
|
||||
exit()
|
||||
|
||||
@classmethod
|
||||
def disable(cls):
|
||||
"""
|
||||
Disable console interaction
|
||||
:return:
|
||||
"""
|
||||
cls._disabled = True
|
||||
|
||||
@classmethod
|
||||
def error(cls, string: str, tb: str = None):
|
||||
"""
|
||||
Prints an error with traceback
|
||||
:param string:
|
||||
:param tb:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.error, string, tb))
|
||||
return
|
||||
|
||||
cls.set_foreground_color('red')
|
||||
if tb is not None:
|
||||
cls.write_line(f'{string} -> {tb}')
|
||||
else:
|
||||
cls.write_line(string)
|
||||
cls.set_foreground_color('default')
|
||||
|
||||
@classmethod
|
||||
def enable(cls):
|
||||
"""
|
||||
Enable console interaction
|
||||
:return:
|
||||
"""
|
||||
cls._disabled = False
|
||||
|
||||
@classmethod
|
||||
def read(cls, output: str = None) -> str:
|
||||
"""
|
||||
Read in line
|
||||
:param output:
|
||||
:return:
|
||||
"""
|
||||
if output is not None and not cls._hold_back:
|
||||
cls.write_line(output)
|
||||
|
||||
return input()
|
||||
|
||||
@classmethod
|
||||
def read_line(cls, output: str = None) -> str:
|
||||
"""
|
||||
Reads in next line
|
||||
:param output:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled and not cls._hold_back:
|
||||
return ''
|
||||
|
||||
if output is not None:
|
||||
cls.write_line(output)
|
||||
|
||||
cls._output('\n', end='')
|
||||
|
||||
return input()
|
||||
|
||||
@classmethod
|
||||
def table(cls, header: list[str], values: list[list[str]]):
|
||||
"""
|
||||
Prints a table with header and values
|
||||
:param header:
|
||||
:param values:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.table, header, values))
|
||||
return
|
||||
|
||||
table = tabulate(values, headers=header)
|
||||
|
||||
Console.write_line(table)
|
||||
Console.write('\n')
|
||||
|
||||
@classmethod
|
||||
def select(cls, char: str, message: str, options: list[str],
|
||||
header_foreground_color: Union[str, ForegroundColorEnum] = ForegroundColorEnum.default,
|
||||
header_background_color: Union[str, BackgroundColorEnum] = BackgroundColorEnum.default,
|
||||
option_foreground_color: Union[str, ForegroundColorEnum] = ForegroundColorEnum.default,
|
||||
option_background_color: Union[str, BackgroundColorEnum] = BackgroundColorEnum.default,
|
||||
cursor_foreground_color: Union[str, ForegroundColorEnum] = ForegroundColorEnum.default,
|
||||
cursor_background_color: Union[str, BackgroundColorEnum] = BackgroundColorEnum.default
|
||||
) -> str:
|
||||
"""
|
||||
Prints select menu
|
||||
:param char:
|
||||
:param message:
|
||||
:param options:
|
||||
:param header_foreground_color:
|
||||
:param header_background_color:
|
||||
:param option_foreground_color:
|
||||
:param option_background_color:
|
||||
:param cursor_foreground_color:
|
||||
:param cursor_background_color:
|
||||
:return: Selected option as str
|
||||
"""
|
||||
cls._selected_menu_item_char = char
|
||||
cls.options = options
|
||||
cls._select_menu_items = cls.options
|
||||
|
||||
if option_foreground_color is not None:
|
||||
cls._selected_menu_option_foreground_color = option_foreground_color
|
||||
if option_background_color is not None:
|
||||
cls._selected_menu_option_background_color = option_background_color
|
||||
|
||||
if cursor_foreground_color is not None:
|
||||
cls._selected_menu_cursor_foreground_color = cursor_foreground_color
|
||||
if cursor_background_color is not None:
|
||||
cls._selected_menu_cursor_background_color = cursor_background_color
|
||||
|
||||
Console.set_foreground_color(header_foreground_color)
|
||||
Console.set_background_color(header_background_color)
|
||||
Console.write_line(message, '\n')
|
||||
cls._show_select_menu()
|
||||
|
||||
with keyboard.Listener(
|
||||
on_press=cls._select_menu_key_press, suppress=True) as listener:
|
||||
listener.join()
|
||||
|
||||
Console.color_reset()
|
||||
return cls._select_menu_items[cls._selected_menu_item_index]
|
||||
|
||||
@classmethod
|
||||
def spinner(cls, message: str, call: Callable, *args, text_foreground_color: Union[str, ForegroundColorEnum] = None,
|
||||
spinner_foreground_color: Union[str, ForegroundColorEnum] = None,
|
||||
text_background_color: Union[str, BackgroundColorEnum] = None,
|
||||
spinner_background_color: Union[str, BackgroundColorEnum] = None, **kwargs) -> any:
|
||||
"""
|
||||
Shows spinner and calls given function
|
||||
When function has ended the spinner stops
|
||||
:param message:
|
||||
:param call:
|
||||
:param args:
|
||||
:param text_foreground_color:
|
||||
:param spinner_foreground_color:
|
||||
:param text_background_color:
|
||||
:param spinner_background_color:
|
||||
:param kwargs:
|
||||
:return: Return value of call
|
||||
"""
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.spinner, message, call, *args))
|
||||
return
|
||||
|
||||
if text_foreground_color is not None:
|
||||
cls.set_foreground_color(text_foreground_color)
|
||||
|
||||
if text_background_color is not None:
|
||||
cls.set_background_color(text_background_color)
|
||||
|
||||
if type(spinner_foreground_color) is str:
|
||||
spinner_foreground_color = ForegroundColorEnum[spinner_foreground_color]
|
||||
|
||||
if type(spinner_background_color) is str:
|
||||
spinner_background_color = BackgroundColorEnum[spinner_background_color]
|
||||
|
||||
cls.write_line(message)
|
||||
cls.set_hold_back(True)
|
||||
spinner = SpinnerThread(len(message), spinner_foreground_color, spinner_background_color)
|
||||
spinner.start()
|
||||
|
||||
return_value = None
|
||||
try:
|
||||
return_value = call(*args, **kwargs)
|
||||
except KeyboardInterrupt:
|
||||
spinner.exit()
|
||||
cls.close()
|
||||
|
||||
spinner.stop_spinning()
|
||||
cls.set_hold_back(False)
|
||||
|
||||
cls.set_foreground_color(ForegroundColorEnum.default)
|
||||
cls.set_background_color(BackgroundColorEnum.default)
|
||||
|
||||
for call in cls._hold_back_calls:
|
||||
call.function(*call.args)
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
return return_value
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args, end=''):
|
||||
"""
|
||||
Prints in active line
|
||||
:param args:
|
||||
:param end:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.write, args))
|
||||
return
|
||||
|
||||
string = ' '.join(map(str, args))
|
||||
cls._output(string, end=end)
|
||||
|
||||
@classmethod
|
||||
def write_at(cls, x: int, y: int, *args):
|
||||
"""
|
||||
Prints at given position
|
||||
:param x:
|
||||
:param y:
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.write_at, x, y, args))
|
||||
return
|
||||
|
||||
string = ' '.join(map(str, args))
|
||||
cls._output(string, x, y, end='')
|
||||
|
||||
@classmethod
|
||||
def write_line(cls, *args):
|
||||
"""
|
||||
Prints to new line
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.write_line, args))
|
||||
return
|
||||
|
||||
string = ' '.join(map(str, args))
|
||||
if not cls._is_first_write:
|
||||
cls._output('')
|
||||
cls._output(string, end='')
|
||||
|
||||
@classmethod
|
||||
def write_line_at(cls, x: int, y: int, *args):
|
||||
"""
|
||||
Prints new line at given position
|
||||
:param x:
|
||||
:param y:
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if cls._disabled:
|
||||
return
|
||||
|
||||
if cls._hold_back:
|
||||
cls._hold_back_calls.append(ConsoleCall(cls.write_line_at, x, y, args))
|
||||
return
|
||||
|
||||
string = ' '.join(map(str, args))
|
||||
if not cls._is_first_write:
|
||||
cls._output('', end='')
|
||||
cls._output(string, x, y, end='')
|
21
src/cpl/console/console_call.py
Normal file
21
src/cpl/console/console_call.py
Normal file
@ -0,0 +1,21 @@
|
||||
from collections import Callable
|
||||
|
||||
|
||||
class ConsoleCall:
|
||||
|
||||
def __init__(self, function: Callable, *args):
|
||||
"""
|
||||
Represents a console call, for hold back when spinner is active
|
||||
:param function:
|
||||
:param args:
|
||||
"""
|
||||
self._func = function
|
||||
self._args = args
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
return self._func
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
return self._args
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ForegroundColor(Enum):
|
||||
class ForegroundColorEnum(Enum):
|
||||
|
||||
default = 'default'
|
||||
grey = 'grey'
|
107
src/cpl/console/spinner_thread.py
Normal file
107
src/cpl/console/spinner_thread.py
Normal file
@ -0,0 +1,107 @@
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
from termcolor import colored
|
||||
|
||||
from cpl.console.background_color_enum import BackgroundColorEnum
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
|
||||
|
||||
class SpinnerThread(threading.Thread):
|
||||
|
||||
def __init__(self, msg_len: int, foreground_color: ForegroundColorEnum, background_color: BackgroundColorEnum):
|
||||
"""
|
||||
Thread to show spinner in terminal
|
||||
:param msg_len:
|
||||
:param foreground_color:
|
||||
:param background_color:
|
||||
"""
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
self._msg_len = msg_len
|
||||
self._foreground_color = foreground_color
|
||||
self._background_color = background_color
|
||||
|
||||
self._is_spinning = True
|
||||
self._exit = False
|
||||
|
||||
@staticmethod
|
||||
def _spinner():
|
||||
"""
|
||||
Selects active spinner char
|
||||
:return:
|
||||
"""
|
||||
while True:
|
||||
for cursor in '|/-\\':
|
||||
yield cursor
|
||||
|
||||
def _get_color_args(self) -> list[str]:
|
||||
"""
|
||||
Creates color arguments
|
||||
:return:
|
||||
"""
|
||||
color_args = []
|
||||
if self._foreground_color is not None:
|
||||
color_args.append(str(self._foreground_color.value))
|
||||
|
||||
if self._background_color is not None:
|
||||
color_args.append(str(self._background_color.value))
|
||||
|
||||
return color_args
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Entry point of thread, shows the spinner
|
||||
:return:
|
||||
"""
|
||||
columns = 0
|
||||
if sys.platform == 'win32':
|
||||
columns = os.get_terminal_size().columns
|
||||
else:
|
||||
term_rows, term_columns = os.popen('stty size', 'r').read().split()
|
||||
columns = int(term_columns)
|
||||
|
||||
end_msg = 'done'
|
||||
end_msg_pos = columns - self._msg_len - len(end_msg)
|
||||
if end_msg_pos > 0:
|
||||
print(f'{"" : >{end_msg_pos}}', end='')
|
||||
else:
|
||||
print('', end='')
|
||||
|
||||
first = True
|
||||
spinner = self._spinner()
|
||||
while self._is_spinning:
|
||||
if first:
|
||||
first = False
|
||||
print(colored(f'{next(spinner): >{len(end_msg) - 1}}', *self._get_color_args()), end='')
|
||||
else:
|
||||
print(colored(f'{next(spinner): >{len(end_msg)}}', *self._get_color_args()), end='')
|
||||
time.sleep(0.1)
|
||||
back = ''
|
||||
for i in range(0, len(end_msg)):
|
||||
back += '\b'
|
||||
|
||||
print(back, end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
if not self._exit:
|
||||
print(colored(end_msg, *self._get_color_args()), end='')
|
||||
|
||||
def stop_spinning(self):
|
||||
"""
|
||||
Stops the spinner
|
||||
:return:
|
||||
"""
|
||||
self._is_spinning = False
|
||||
time.sleep(0.1)
|
||||
|
||||
def exit(self):
|
||||
"""
|
||||
Stops the spinner
|
||||
:return:
|
||||
"""
|
||||
self._is_spinning = False
|
||||
self._exit = True
|
||||
time.sleep(0.1)
|
28
src/cpl/database/__init__.py
Normal file
28
src/cpl/database/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.database'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .database_model import DatabaseModel
|
||||
from .database_settings import DatabaseSettings
|
||||
from .database_settings_name_enum import DatabaseSettingsNameEnum
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
27
src/cpl/database/connection/__init__.py
Normal file
27
src/cpl/database/connection/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.database.connection'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .database_connection import DatabaseConnection
|
||||
from .database_connection_abc import DatabaseConnectionABC
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
@ -3,16 +3,20 @@ from typing import Optional
|
||||
from sqlalchemy import engine, create_engine
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from sh_edraft.database.connection.base.database_connection_base import DatabaseConnectionBase
|
||||
from sh_edraft.database.model.database_settings import DatabaseSettings
|
||||
from sh_edraft.console.console import Console
|
||||
from sh_edraft.console.model.foreground_color import ForegroundColor
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.database.connection.database_connection_abc import DatabaseConnectionABC
|
||||
from cpl.database.database_settings import DatabaseSettings
|
||||
|
||||
|
||||
class DatabaseConnection(DatabaseConnectionBase):
|
||||
class DatabaseConnection(DatabaseConnectionABC):
|
||||
|
||||
def __init__(self, database_settings: DatabaseSettings):
|
||||
DatabaseConnectionBase.__init__(self)
|
||||
"""
|
||||
Represents an connection to a database
|
||||
:param database_settings:
|
||||
"""
|
||||
DatabaseConnectionABC.__init__(self)
|
||||
|
||||
self._db_settings = database_settings
|
||||
|
||||
@ -32,6 +36,9 @@ class DatabaseConnection(DatabaseConnectionBase):
|
||||
try:
|
||||
self._engine = create_engine(connection_string)
|
||||
|
||||
if self._db_settings.auth_plugin is not None:
|
||||
self._engine = create_engine(connection_string, connect_args={'auth_plugin': self._db_settings.auth_plugin})
|
||||
|
||||
if self._db_settings.encoding is not None:
|
||||
self._engine.encoding = self._db_settings.encoding
|
||||
|
||||
@ -45,12 +52,11 @@ class DatabaseConnection(DatabaseConnectionBase):
|
||||
|
||||
db_session = sessionmaker(bind=self._engine)
|
||||
self._session = db_session()
|
||||
Console.set_foreground_color(ForegroundColor.green)
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(f'[{__name__}] Connected to database')
|
||||
Console.set_foreground_color(ForegroundColor.default)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColor.red)
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[{__name__}] Database connection failed -> {e}')
|
||||
Console.set_foreground_color(ForegroundColor.default)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
exit()
|
||||
|
@ -4,7 +4,7 @@ from sqlalchemy import engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
class DatabaseConnectionBase(ABC):
|
||||
class DatabaseConnectionABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self): pass
|
||||
@ -18,4 +18,10 @@ class DatabaseConnectionBase(ABC):
|
||||
def session(self) -> Session: pass
|
||||
|
||||
@abstractmethod
|
||||
def connect(self, connection_string: str): pass
|
||||
def connect(self, connection_string: str):
|
||||
"""
|
||||
Connects to a database by connection string
|
||||
:param connection_string:
|
||||
:return:
|
||||
"""
|
||||
pass
|
27
src/cpl/database/context/__init__.py
Normal file
27
src/cpl/database/context/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.database.context'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .database_context import DatabaseContext
|
||||
from .database_context_abc import DatabaseContextABC
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
50
src/cpl/database/context/database_context.py
Normal file
50
src/cpl/database/context/database_context.py
Normal file
@ -0,0 +1,50 @@
|
||||
from sqlalchemy import engine, Table
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.database.connection.database_connection import DatabaseConnection
|
||||
from cpl.database.connection.database_connection_abc import DatabaseConnectionABC
|
||||
from cpl.database.context.database_context_abc import DatabaseContextABC
|
||||
from cpl.database.database_settings import DatabaseSettings
|
||||
from cpl.database.database_model import DatabaseModel
|
||||
|
||||
|
||||
class DatabaseContext(DatabaseContextABC):
|
||||
|
||||
def __init__(self, database_settings: DatabaseSettings):
|
||||
DatabaseContextABC.__init__(self)
|
||||
|
||||
self._db: DatabaseConnectionABC = DatabaseConnection(database_settings)
|
||||
self._tables: list[Table] = []
|
||||
|
||||
@property
|
||||
def engine(self) -> engine:
|
||||
return self._db.engine
|
||||
|
||||
@property
|
||||
def session(self) -> Session:
|
||||
return self._db.session
|
||||
|
||||
def connect(self, connection_string: str):
|
||||
self._db.connect(connection_string)
|
||||
self._create_tables()
|
||||
|
||||
def save_changes(self):
|
||||
self._db.session.commit()
|
||||
|
||||
def _create_tables(self):
|
||||
try:
|
||||
for subclass in DatabaseModel.__subclasses__():
|
||||
self._tables.append(subclass.__table__)
|
||||
|
||||
DatabaseModel.metadata.drop_all(self._db.engine, self._tables)
|
||||
DatabaseModel.metadata.create_all(self._db.engine, self._tables, checkfirst=True)
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(f'[{__name__}] Created tables')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[{__name__}] Creating tables failed -> {e}')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
exit()
|
42
src/cpl/database/context/database_context_abc.py
Normal file
42
src/cpl/database/context/database_context_abc.py
Normal file
@ -0,0 +1,42 @@
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
from sqlalchemy import engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
class DatabaseContextABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, *args):
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def engine(self) -> engine: pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def session(self) -> Session: pass
|
||||
|
||||
@abstractmethod
|
||||
def connect(self, connection_string: str):
|
||||
"""
|
||||
Connects to a database with connection string
|
||||
:param connection_string:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def save_changes(self):
|
||||
"""
|
||||
Saves changes of the database
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _create_tables(self):
|
||||
"""
|
||||
Create all tables for application from database model
|
||||
:return:
|
||||
"""
|
||||
pass
|
@ -1,3 +1,3 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
DBModel: declarative_base = declarative_base()
|
||||
DatabaseModel: declarative_base = declarative_base()
|
@ -1,23 +1,32 @@
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
|
||||
from sh_edraft.database.model.database_settings_name import DatabaseSettingsName
|
||||
from sh_edraft.console.console import Console
|
||||
from sh_edraft.console.model.foreground_color import ForegroundColor
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.database.database_settings_name_enum import DatabaseSettingsNameEnum
|
||||
|
||||
|
||||
class DatabaseSettings(ConfigurationModelBase):
|
||||
class DatabaseSettings(ConfigurationModelABC):
|
||||
|
||||
def __init__(self):
|
||||
ConfigurationModelBase.__init__(self)
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._auth_plugin: Optional[str] = None
|
||||
self._connection_string: Optional[str] = None
|
||||
self._credentials: Optional[str] = None
|
||||
self._encoding: Optional[str] = None
|
||||
self._case_sensitive: Optional[bool] = None
|
||||
self._echo: Optional[bool] = None
|
||||
|
||||
@property
|
||||
def auth_plugin(self) -> str:
|
||||
return self._auth_plugin
|
||||
|
||||
@auth_plugin.setter
|
||||
def auth_plugin(self, auth_plugin: str):
|
||||
self._auth_plugin = auth_plugin
|
||||
|
||||
@property
|
||||
def connection_string(self) -> str:
|
||||
return self._connection_string
|
||||
@ -60,19 +69,22 @@ class DatabaseSettings(ConfigurationModelBase):
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._connection_string = settings[DatabaseSettingsName.connection_string.value]
|
||||
self._credentials = settings[DatabaseSettingsName.credentials.value]
|
||||
self._connection_string = settings[DatabaseSettingsNameEnum.connection_string.value]
|
||||
self._credentials = settings[DatabaseSettingsNameEnum.credentials.value]
|
||||
|
||||
if DatabaseSettingsName.encoding.value in settings:
|
||||
self._encoding = settings[DatabaseSettingsName.encoding.value]
|
||||
if DatabaseSettingsNameEnum.auth_plugin.value in settings:
|
||||
self._auth_plugin = settings[DatabaseSettingsNameEnum.auth_plugin.value]
|
||||
|
||||
if DatabaseSettingsName.case_sensitive.value in settings:
|
||||
self._case_sensitive = bool(settings[DatabaseSettingsName.case_sensitive.value])
|
||||
if DatabaseSettingsNameEnum.encoding.value in settings:
|
||||
self._encoding = settings[DatabaseSettingsNameEnum.encoding.value]
|
||||
|
||||
if DatabaseSettingsName.echo.value in settings:
|
||||
self._echo = bool(settings[DatabaseSettingsName.echo.value])
|
||||
if DatabaseSettingsNameEnum.case_sensitive.value in settings:
|
||||
self._case_sensitive = bool(settings[DatabaseSettingsNameEnum.case_sensitive.value])
|
||||
|
||||
if DatabaseSettingsNameEnum.echo.value in settings:
|
||||
self._echo = bool(settings[DatabaseSettingsNameEnum.echo.value])
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColor.red)
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
|
||||
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
||||
Console.set_foreground_color(ForegroundColor.default)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
@ -1,10 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class DatabaseSettingsName(Enum):
|
||||
class DatabaseSettingsNameEnum(Enum):
|
||||
|
||||
connection_string = 'ConnectionString'
|
||||
credentials = 'Credentials'
|
||||
encoding = 'Encoding'
|
||||
case_sensitive = 'CaseSensitive'
|
||||
echo = 'Echo'
|
||||
auth_plugin = 'AuthPlugin'
|
31
src/cpl/dependency_injection/__init__.py
Normal file
31
src/cpl/dependency_injection/__init__.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.dependency_injection'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .service_collection import ServiceCollection
|
||||
from .service_collection_abc import ServiceCollectionABC
|
||||
from .service_descriptor import ServiceDescriptor
|
||||
from .service_lifetime_enum import ServiceLifetimeEnum
|
||||
from .service_provider import ServiceProvider
|
||||
from .service_provider_abc import ServiceProviderABC
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
70
src/cpl/dependency_injection/service_collection.py
Normal file
70
src/cpl/dependency_injection/service_collection.py
Normal file
@ -0,0 +1,70 @@
|
||||
from typing import Union, Type, Callable, Optional
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.database.database_settings import DatabaseSettings
|
||||
from cpl.database.context.database_context_abc import DatabaseContextABC
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
from cpl.dependency_injection.service_collection_abc import ServiceCollectionABC
|
||||
from cpl.dependency_injection.service_descriptor import ServiceDescriptor
|
||||
from cpl.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
|
||||
from cpl.dependency_injection.service_provider import ServiceProvider
|
||||
from cpl.logging.logger_service import Logger
|
||||
from cpl.logging.logger_abc import LoggerABC
|
||||
from cpl.utils.credential_manager import CredentialManager
|
||||
|
||||
|
||||
class ServiceCollection(ServiceCollectionABC):
|
||||
|
||||
def __init__(self, config: ConfigurationABC):
|
||||
ServiceCollectionABC.__init__(self)
|
||||
self._configuration: ConfigurationABC = config
|
||||
|
||||
self._database_context: Optional[DatabaseContextABC] = None
|
||||
self._service_descriptors: list[ServiceDescriptor] = []
|
||||
|
||||
def _add_descriptor(self, service: Union[type, object], lifetime: ServiceLifetimeEnum):
|
||||
found = False
|
||||
for descriptor in self._service_descriptors:
|
||||
if isinstance(service, descriptor.service_type):
|
||||
found = True
|
||||
|
||||
if found:
|
||||
service_type = service
|
||||
if not isinstance(service, type):
|
||||
service_type = type(service)
|
||||
|
||||
raise Exception(f'Service of type {service_type} already exists')
|
||||
|
||||
self._service_descriptors.append(ServiceDescriptor(service, lifetime))
|
||||
|
||||
def add_db_context(self, db_context_type: Type[DatabaseContextABC], db_settings: DatabaseSettings):
|
||||
self._database_context = db_context_type(db_settings)
|
||||
self._database_context.connect(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials))
|
||||
|
||||
def add_logging(self):
|
||||
self.add_singleton(LoggerABC, Logger)
|
||||
|
||||
def add_singleton(self, service_type: Union[type, object], service: Union[type, object] = None):
|
||||
impl = None
|
||||
if service is not None:
|
||||
if isinstance(service, type):
|
||||
impl = self.build_service_provider().build_service(service)
|
||||
|
||||
self._add_descriptor(impl, ServiceLifetimeEnum.singleton)
|
||||
else:
|
||||
if isinstance(service_type, type):
|
||||
impl = self.build_service_provider().build_service(service_type)
|
||||
|
||||
self._add_descriptor(impl, ServiceLifetimeEnum.singleton)
|
||||
|
||||
def add_scoped(self, service_type: Type, service: Callable = None):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def add_transient(self, service_type: Union[type], service: Union[type] = None):
|
||||
if service is not None:
|
||||
self._add_descriptor(service, ServiceLifetimeEnum.transient)
|
||||
else:
|
||||
self._add_descriptor(service_type, ServiceLifetimeEnum.transient)
|
||||
|
||||
def build_service_provider(self) -> ServiceProviderABC:
|
||||
return ServiceProvider(self._service_descriptors, self._configuration, self._database_context)
|
71
src/cpl/dependency_injection/service_collection_abc.py
Normal file
71
src/cpl/dependency_injection/service_collection_abc.py
Normal file
@ -0,0 +1,71 @@
|
||||
from abc import abstractmethod, ABC
|
||||
from collections import Callable
|
||||
from typing import Type
|
||||
|
||||
from cpl.database.database_settings import DatabaseSettings
|
||||
from cpl.database.context.database_context_abc import DatabaseContextABC
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
|
||||
|
||||
class ServiceCollectionABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC for service providing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_db_context(self, db_context: Type[DatabaseContextABC], db_settings: DatabaseSettings):
|
||||
"""
|
||||
Adds database context
|
||||
:param db_context:
|
||||
:param db_settings:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_logging(self):
|
||||
"""
|
||||
Adds the CPL internal logger
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_transient(self, service_type: Type, service: Callable = None):
|
||||
"""
|
||||
Adds a service with transient lifetime
|
||||
:param service_type:
|
||||
:param service:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_scoped(self, service_type: Type, service: Callable = None):
|
||||
"""
|
||||
Adds a service with scoped lifetime
|
||||
:param service_type:
|
||||
:param service:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_singleton(self, service_type: Type, service: Callable = None):
|
||||
"""
|
||||
Adds a service with singleton lifetime
|
||||
:param service_type:
|
||||
:param service:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def build_service_provider(self) -> ServiceProviderABC:
|
||||
"""
|
||||
Creates instance of the service provider
|
||||
"""
|
||||
pass
|
33
src/cpl/dependency_injection/service_descriptor.py
Normal file
33
src/cpl/dependency_injection/service_descriptor.py
Normal file
@ -0,0 +1,33 @@
|
||||
from typing import Union, Optional
|
||||
|
||||
from cpl.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
|
||||
|
||||
|
||||
class ServiceDescriptor:
|
||||
|
||||
def __init__(self, implementation: Union[type, Optional[object]], lifetime: ServiceLifetimeEnum):
|
||||
|
||||
self._service_type = implementation
|
||||
self._implementation = implementation
|
||||
self._lifetime = lifetime
|
||||
|
||||
if not isinstance(implementation, type):
|
||||
self._service_type = type(implementation)
|
||||
else:
|
||||
self._implementation = None
|
||||
|
||||
@property
|
||||
def service_type(self) -> type:
|
||||
return self._service_type
|
||||
|
||||
@property
|
||||
def implementation(self) -> Union[type, Optional[object]]:
|
||||
return self._implementation
|
||||
|
||||
@implementation.setter
|
||||
def implementation(self, implementation: Union[type, Optional[object]]):
|
||||
self._implementation = implementation
|
||||
|
||||
@property
|
||||
def lifetime(self) -> ServiceLifetimeEnum:
|
||||
return self._lifetime
|
8
src/cpl/dependency_injection/service_lifetime_enum.py
Normal file
8
src/cpl/dependency_injection/service_lifetime_enum.py
Normal file
@ -0,0 +1,8 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ServiceLifetimeEnum(Enum):
|
||||
|
||||
singleton = 0
|
||||
scoped = 1 # not supported yet
|
||||
transient = 2
|
90
src/cpl/dependency_injection/service_provider.py
Normal file
90
src/cpl/dependency_injection/service_provider.py
Normal file
@ -0,0 +1,90 @@
|
||||
from collections import Callable
|
||||
from inspect import signature, Parameter
|
||||
from typing import Optional
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.database.context.database_context_abc import DatabaseContextABC
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
from cpl.dependency_injection.service_descriptor import ServiceDescriptor
|
||||
from cpl.dependency_injection.service_lifetime_enum import ServiceLifetimeEnum
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
|
||||
|
||||
class ServiceProvider(ServiceProviderABC):
|
||||
|
||||
def __init__(self, service_descriptors: list[ServiceDescriptor], config: ConfigurationABC, db_context: Optional[DatabaseContextABC]):
|
||||
ServiceProviderABC.__init__(self)
|
||||
|
||||
self._service_descriptors: list[ServiceDescriptor] = service_descriptors
|
||||
self._configuration: ConfigurationABC = config
|
||||
self._database_context = db_context
|
||||
|
||||
def _find_service(self, service_type: type) -> [ServiceDescriptor]:
|
||||
for descriptor in self._service_descriptors:
|
||||
if descriptor.service_type == service_type or issubclass(descriptor.service_type, service_type):
|
||||
return descriptor
|
||||
|
||||
return None
|
||||
|
||||
def _get_service(self, parameter: Parameter) -> object:
|
||||
for descriptor in self._service_descriptors:
|
||||
if descriptor.service_type == parameter.annotation or issubclass(descriptor.service_type, parameter.annotation):
|
||||
if descriptor.implementation is not None:
|
||||
return descriptor.implementation
|
||||
|
||||
implementation = self.build_service(descriptor.service_type)
|
||||
if descriptor.lifetime == ServiceLifetimeEnum.singleton:
|
||||
descriptor.implementation = implementation
|
||||
|
||||
return implementation
|
||||
|
||||
def build_service(self, service_type: type) -> object:
|
||||
for descriptor in self._service_descriptors:
|
||||
if descriptor.service_type == service_type or issubclass(descriptor.service_type, service_type):
|
||||
if descriptor.implementation is not None:
|
||||
service_type = type(descriptor.implementation)
|
||||
else:
|
||||
service_type = descriptor.service_type
|
||||
|
||||
break
|
||||
|
||||
sig = signature(service_type.__init__)
|
||||
params = []
|
||||
for param in sig.parameters.items():
|
||||
parameter = param[1]
|
||||
if parameter.name != 'self' and parameter.annotation != Parameter.empty:
|
||||
if issubclass(parameter.annotation, ServiceProviderABC):
|
||||
params.append(self)
|
||||
|
||||
elif issubclass(parameter.annotation, ApplicationEnvironmentABC):
|
||||
params.append(self._configuration.environment)
|
||||
|
||||
elif issubclass(parameter.annotation, DatabaseContextABC):
|
||||
params.append(self._database_context)
|
||||
|
||||
elif issubclass(parameter.annotation, ConfigurationModelABC):
|
||||
params.append(self._configuration.get_configuration(parameter.annotation))
|
||||
|
||||
elif issubclass(parameter.annotation, ConfigurationABC):
|
||||
params.append(self._configuration)
|
||||
|
||||
else:
|
||||
params.append(self._get_service(parameter))
|
||||
|
||||
return service_type(*params)
|
||||
|
||||
def get_service(self, service_type: type) -> Optional[Callable[object]]:
|
||||
result = self._find_service(service_type)
|
||||
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
if result.implementation is not None:
|
||||
return result.implementation
|
||||
|
||||
implementation = self.build_service(service_type)
|
||||
if result.lifetime == ServiceLifetimeEnum.singleton:
|
||||
result.implementation = implementation
|
||||
|
||||
return implementation
|
31
src/cpl/dependency_injection/service_provider_abc.py
Normal file
31
src/cpl/dependency_injection/service_provider_abc.py
Normal file
@ -0,0 +1,31 @@
|
||||
from abc import abstractmethod, ABC
|
||||
from collections import Callable
|
||||
from typing import Type, Optional
|
||||
|
||||
|
||||
class ServiceProviderABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC for service providing
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def build_service(self, service_type: type) -> object:
|
||||
"""
|
||||
Creates instance of given type
|
||||
:param service_type:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_service(self, instance_type: Type) -> Optional[Callable[object]]:
|
||||
"""
|
||||
Returns instance of given type
|
||||
:param instance_type:
|
||||
:return:
|
||||
"""
|
||||
pass
|
28
src/cpl/environment/__init__.py
Normal file
28
src/cpl/environment/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.environment'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .application_environment_abc import ApplicationEnvironmentABC
|
||||
from .environment_name_enum import EnvironmentNameEnum
|
||||
from .application_environment import ApplicationEnvironment
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
98
src/cpl/environment/application_environment.py
Normal file
98
src/cpl/environment/application_environment.py
Normal file
@ -0,0 +1,98 @@
|
||||
import pathlib
|
||||
from datetime import datetime
|
||||
from socket import gethostname
|
||||
from typing import Optional
|
||||
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.environment.environment_name_enum import EnvironmentNameEnum
|
||||
|
||||
|
||||
class ApplicationEnvironment(ApplicationEnvironmentABC):
|
||||
|
||||
def __init__(self, name: EnvironmentNameEnum = EnvironmentNameEnum.production, crp: str = './'):
|
||||
"""
|
||||
Represents environment of the application
|
||||
:param name:
|
||||
:param crp:
|
||||
"""
|
||||
ApplicationEnvironmentABC.__init__(self)
|
||||
|
||||
self._environment_name: Optional[EnvironmentNameEnum] = name
|
||||
self._app_name: Optional[str] = None
|
||||
self._customer: Optional[str] = None
|
||||
self._content_root_path: Optional[str] = crp
|
||||
|
||||
self._start_time: datetime = datetime.now()
|
||||
self._end_time: datetime = datetime.now()
|
||||
self._working_directory = pathlib.Path().absolute()
|
||||
self._runtime_directory = pathlib.Path(__file__).parent.absolute()
|
||||
|
||||
@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 = EnvironmentNameEnum(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()
|
||||
|
||||
@property
|
||||
def start_time(self) -> datetime:
|
||||
return self._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()
|
||||
|
||||
@property
|
||||
def working_directory(self) -> str:
|
||||
return self._working_directory
|
||||
|
||||
def set_working_directory(self, path: str = ''):
|
||||
if path != '':
|
||||
self._working_directory = path
|
||||
return
|
||||
|
||||
self._working_directory = pathlib.Path().absolute()
|
||||
|
||||
@property
|
||||
def runtime_directory(self) -> str:
|
||||
return self._runtime_directory
|
||||
|
||||
def set_runtime_directory(self, file: str):
|
||||
self._runtime_directory = pathlib.Path(file).parent.absolute()
|
85
src/cpl/environment/application_environment_abc.py
Normal file
85
src/cpl/environment/application_environment_abc.py
Normal file
@ -0,0 +1,85 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ApplicationEnvironmentABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC of application environment
|
||||
"""
|
||||
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
|
||||
|
||||
@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
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def working_directory(self) -> str: pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def runtime_directory(self) -> str: pass
|
||||
|
||||
@abstractmethod
|
||||
def set_runtime_directory(self, runtime_directory: str):
|
||||
"""
|
||||
Sets the current runtime directory
|
||||
:param runtime_directory:
|
||||
:return:
|
||||
"""
|
||||
pass
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class EnvironmentName(Enum):
|
||||
class EnvironmentNameEnum(Enum):
|
||||
|
||||
production = 'production'
|
||||
staging = 'staging'
|
30
src/cpl/logging/__init__.py
Normal file
30
src/cpl/logging/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.logging'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .logger_service import Logger
|
||||
from .logger_abc import LoggerABC
|
||||
from .logging_level_enum import LoggingLevelEnum
|
||||
from .logging_settings import LoggingSettings
|
||||
from .logging_settings_name_enum import LoggingSettingsNameEnum
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
82
src/cpl/logging/logger_abc.py
Normal file
82
src/cpl/logging/logger_abc.py
Normal file
@ -0,0 +1,82 @@
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
|
||||
class LoggerABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC for logging
|
||||
"""
|
||||
ABC.__init__(self)
|
||||
|
||||
@abstractmethod
|
||||
def header(self, string: str):
|
||||
"""
|
||||
Writes a header message
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def trace(self, name: str, message: str):
|
||||
"""
|
||||
Writes a trace message
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def debug(self, name: str, message: str):
|
||||
"""
|
||||
Writes a debug message
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def info(self, name: str, message: str):
|
||||
"""
|
||||
Writes an information
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def warn(self, name: str, message: str):
|
||||
"""
|
||||
Writes an warning
|
||||
:param name:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def error(self, name: str, message: str, ex: Exception = None):
|
||||
"""
|
||||
Writes an error
|
||||
:param name:
|
||||
:param message:
|
||||
:param ex:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def fatal(self, name: str, message: str, ex: Exception = None):
|
||||
"""
|
||||
Writes an error and exits
|
||||
:param name:
|
||||
:param message:
|
||||
:param ex:
|
||||
:return:
|
||||
"""
|
||||
pass
|
233
src/cpl/logging/logger_service.py
Normal file
233
src/cpl/logging/logger_service.py
Normal file
@ -0,0 +1,233 @@
|
||||
import datetime
|
||||
import os
|
||||
import traceback
|
||||
from string import Template
|
||||
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.logging.logger_abc import LoggerABC
|
||||
from cpl.logging.logging_level_enum import LoggingLevelEnum
|
||||
from cpl.logging.logging_settings import LoggingSettings
|
||||
from cpl.time.time_format_settings import TimeFormatSettings
|
||||
|
||||
|
||||
class Logger(LoggerABC):
|
||||
|
||||
def __init__(self, logging_settings: LoggingSettings, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC):
|
||||
"""
|
||||
Service for logging
|
||||
:param logging_settings:
|
||||
:param time_format:
|
||||
:param app_runtime:
|
||||
"""
|
||||
LoggerABC.__init__(self)
|
||||
|
||||
self._env = env
|
||||
self._log_settings: LoggingSettings = logging_settings
|
||||
self._time_format_settings: TimeFormatSettings = time_format
|
||||
|
||||
self._log = Template(self._log_settings.filename).substitute(
|
||||
date_time_now=self._env.date_time_now.strftime(self._time_format_settings.date_time_format),
|
||||
start_time=self._env.start_time.strftime(self._time_format_settings.date_time_log_format)
|
||||
)
|
||||
self._path = self._log_settings.path
|
||||
self._level = self._log_settings.level
|
||||
self._console = self._log_settings.console
|
||||
|
||||
self.create()
|
||||
|
||||
def _get_datetime_now(self) -> str:
|
||||
"""
|
||||
Returns the date and time by given format
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
return datetime.datetime.now().strftime(self._time_format_settings.date_time_format)
|
||||
except Exception as e:
|
||||
self.error(__name__, 'Cannot get time', ex=e)
|
||||
|
||||
def _get_date(self) -> str:
|
||||
"""
|
||||
Returns the date by given format
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
return datetime.datetime.now().strftime(self._time_format_settings.date_format)
|
||||
except Exception as e:
|
||||
self.error(__name__, 'Cannot get date', ex=e)
|
||||
|
||||
def create(self) -> None:
|
||||
"""
|
||||
Creates path tree and logfile
|
||||
:return:
|
||||
"""
|
||||
|
||||
""" path """
|
||||
try:
|
||||
# check if log file path exists
|
||||
if not os.path.exists(self._path):
|
||||
os.makedirs(self._path)
|
||||
except Exception as e:
|
||||
self._fatal_console(__name__, 'Cannot create log dir', ex=e)
|
||||
|
||||
""" create new log file """
|
||||
try:
|
||||
# open log file, create if not exists
|
||||
path = f'{self._path}{self._log}'
|
||||
f = open(path, "w+")
|
||||
Console.write_line(f'[{__name__}]: Using log file: {path}')
|
||||
f.close()
|
||||
except Exception as e:
|
||||
self._fatal_console(__name__, 'Cannot open log file', ex=e)
|
||||
|
||||
def _append_log(self, string):
|
||||
"""
|
||||
Writes to logfile
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
# 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:
|
||||
f.write(string + '\n')
|
||||
f.close()
|
||||
except Exception as e:
|
||||
self._fatal_console(__name__, f'Cannot append log file, message: {string}', ex=e)
|
||||
|
||||
def _get_string(self, name: str, level: LoggingLevelEnum, message: str) -> str:
|
||||
"""
|
||||
Returns input as log entry format
|
||||
:param name:
|
||||
:param level:
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
log_level = level.name
|
||||
return f'<{self._get_datetime_now()}> [ {log_level} ] [ {name} ]: {message}'
|
||||
|
||||
def header(self, string: str):
|
||||
# append log and print message
|
||||
self._append_log(string)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
Console.write_line(string)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def trace(self, name: str, message: str):
|
||||
output = self._get_string(name, LoggingLevelEnum.TRACE, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.TRACE.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.TRACE.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def debug(self, name: str, message: str):
|
||||
output = self._get_string(name, LoggingLevelEnum.DEBUG, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.DEBUG.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.DEBUG.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def info(self, name: str, message: str):
|
||||
output = self._get_string(name, LoggingLevelEnum.INFO, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.INFO.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.INFO.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.green)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def warn(self, name: str, message: str):
|
||||
output = self._get_string(name, LoggingLevelEnum.WARN, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.WARN.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.WARN.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.yellow)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def error(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, LoggingLevelEnum.ERROR, f'{ex} -> {tb}')
|
||||
else:
|
||||
output = self._get_string(name, LoggingLevelEnum.ERROR, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.ERROR.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.ERROR.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def fatal(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, LoggingLevelEnum.FATAL, f'{ex} -> {tb}')
|
||||
else:
|
||||
output = self._get_string(name, LoggingLevelEnum.FATAL, message)
|
||||
|
||||
# check if message can be written to log
|
||||
if self._level.value >= LoggingLevelEnum.FATAL.value:
|
||||
self._append_log(output)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.FATAL.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
exit()
|
||||
|
||||
def _fatal_console(self, name: str, message: str, ex: Exception = None):
|
||||
"""
|
||||
Writes an error to console only
|
||||
:param name:
|
||||
:param message:
|
||||
:param ex:
|
||||
:return:
|
||||
"""
|
||||
output = ''
|
||||
if ex is not None:
|
||||
tb = traceback.format_exc()
|
||||
self.error(name, message)
|
||||
output = self._get_string(name, LoggingLevelEnum.ERROR, f'{ex} -> {tb}')
|
||||
else:
|
||||
output = self._get_string(name, LoggingLevelEnum.ERROR, message)
|
||||
|
||||
# check if message can be shown in console_old
|
||||
if self._console.value >= LoggingLevelEnum.FATAL.value:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(output)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
exit()
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class LoggingLevel(Enum):
|
||||
class LoggingLevelEnum(Enum):
|
||||
|
||||
OFF = 0 # Nothing
|
||||
FATAL = 1 # Error that cause exit
|
62
src/cpl/logging/logging_settings.py
Normal file
62
src/cpl/logging/logging_settings.py
Normal file
@ -0,0 +1,62 @@
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.logging.logging_level_enum import LoggingLevelEnum
|
||||
from cpl.logging.logging_settings_name_enum import LoggingSettingsNameEnum
|
||||
|
||||
|
||||
class LoggingSettings(ConfigurationModelABC):
|
||||
|
||||
def __init__(self):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
self._path: Optional[str] = None
|
||||
self._filename: Optional[str] = None
|
||||
self._console: Optional[LoggingLevelEnum] = None
|
||||
self._level: Optional[LoggingLevelEnum] = None
|
||||
|
||||
@property
|
||||
def path(self) -> str:
|
||||
return self._path
|
||||
|
||||
@path.setter
|
||||
def path(self, path: str) -> None:
|
||||
self._path = path
|
||||
|
||||
@property
|
||||
def filename(self) -> str:
|
||||
return self._filename
|
||||
|
||||
@filename.setter
|
||||
def filename(self, filename: str) -> None:
|
||||
self._filename = filename
|
||||
|
||||
@property
|
||||
def console(self) -> LoggingLevelEnum:
|
||||
return self._console
|
||||
|
||||
@console.setter
|
||||
def console(self, console: LoggingLevelEnum) -> None:
|
||||
self._console = console
|
||||
|
||||
@property
|
||||
def level(self) -> LoggingLevelEnum:
|
||||
return self._level
|
||||
|
||||
@level.setter
|
||||
def level(self, level: LoggingLevelEnum) -> None:
|
||||
self._level = level
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._path = settings[LoggingSettingsNameEnum.path.value]
|
||||
self._filename = settings[LoggingSettingsNameEnum.filename.value]
|
||||
self._console = LoggingLevelEnum[settings[LoggingSettingsNameEnum.console_level.value]]
|
||||
self._level = LoggingLevelEnum[settings[LoggingSettingsNameEnum.file_level.value]]
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
|
||||
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class LoggingSettingsName(Enum):
|
||||
class LoggingSettingsNameEnum(Enum):
|
||||
|
||||
path = 'Path'
|
||||
filename = 'Filename'
|
30
src/cpl/mailing/__init__.py
Normal file
30
src/cpl/mailing/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.mailing'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .email import EMail
|
||||
from .email_client_service import EMailClient
|
||||
from .email_client_abc import EMailClientABC
|
||||
from .email_client_settings import EMailClientSettings
|
||||
from .email_client_settings_name_enum import EMailClientSettingsNameEnum
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
@ -4,6 +4,14 @@ import re
|
||||
class EMail:
|
||||
|
||||
def __init__(self, header: list[str] = None, subject: str = None, body: str = None, transceiver: str = None, receiver: list[str] = None):
|
||||
"""
|
||||
Represents an email
|
||||
:param header:
|
||||
:param subject:
|
||||
:param body:
|
||||
:param transceiver:
|
||||
:param receiver:
|
||||
"""
|
||||
self._header: list[str] = header
|
||||
|
||||
self._subject: str = subject
|
||||
@ -65,15 +73,30 @@ class EMail:
|
||||
|
||||
@staticmethod
|
||||
def check_mail(address: str) -> bool:
|
||||
"""
|
||||
Checks if an email is valid
|
||||
:param address:
|
||||
:return:
|
||||
"""
|
||||
return bool(re.search('^\\w+([.-]?\\w+)*@\\w+([.-]?\\w+)*(.\\w{2,3})+$', address))
|
||||
|
||||
def add_header(self, header: str):
|
||||
"""
|
||||
Adds header
|
||||
:param header:
|
||||
:return:
|
||||
"""
|
||||
if self._header is None:
|
||||
self._header = []
|
||||
|
||||
self._header.append(header)
|
||||
|
||||
def add_receiver(self, receiver: str):
|
||||
"""
|
||||
Adds receiver
|
||||
:param receiver:
|
||||
:return:
|
||||
"""
|
||||
if self._receiver is None:
|
||||
self._receiver = []
|
||||
|
||||
@ -83,4 +106,9 @@ class EMail:
|
||||
raise Exception(f'Invalid email: {receiver}')
|
||||
|
||||
def get_content(self, transceiver: str):
|
||||
"""
|
||||
Returns the mail as string
|
||||
:param transceiver:
|
||||
:return:
|
||||
"""
|
||||
return str(f'From: {transceiver}\r\nTo: {self.receiver}\r\n{self.header}\r\nSubject: {self.subject}\r\n{self.body}').encode('utf-8')
|
30
src/cpl/mailing/email_client_abc.py
Normal file
30
src/cpl/mailing/email_client_abc.py
Normal file
@ -0,0 +1,30 @@
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
from cpl.mailing.email import EMail
|
||||
|
||||
|
||||
class EMailClientABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
"""
|
||||
ABC to send emails
|
||||
"""
|
||||
ABC.__init__(self)
|
||||
|
||||
@abstractmethod
|
||||
def connect(self):
|
||||
"""
|
||||
Connects to server
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def send_mail(self, email: EMail):
|
||||
"""
|
||||
Sends email
|
||||
:param email:
|
||||
:return:
|
||||
"""
|
||||
pass
|
@ -2,19 +2,24 @@ import ssl
|
||||
from smtplib import SMTP
|
||||
from typing import Optional
|
||||
|
||||
from sh_edraft.environment.base.environment_base import EnvironmentBase
|
||||
from sh_edraft.logging.base.logger_base import LoggerBase
|
||||
from sh_edraft.mailing.base.email_client_base import EMailClientBase
|
||||
from sh_edraft.mailing.model.email import EMail
|
||||
from sh_edraft.mailing.model.email_client_settings import EMailClientSettings
|
||||
from sh_edraft.service.base.service_base import ServiceBase
|
||||
from sh_edraft.utils.credential_manager import CredentialManager
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.logging.logger_abc import LoggerABC
|
||||
from cpl.mailing.email import EMail
|
||||
from cpl.mailing.email_client_abc import EMailClientABC
|
||||
from cpl.mailing.email_client_settings import EMailClientSettings
|
||||
from cpl.utils.credential_manager import CredentialManager
|
||||
|
||||
|
||||
class EMailClient(EMailClientBase):
|
||||
class EMailClient(EMailClientABC):
|
||||
|
||||
def __init__(self, environment: EnvironmentBase, logger: LoggerBase, mail_settings: EMailClientSettings):
|
||||
ServiceBase.__init__(self)
|
||||
def __init__(self, environment: ApplicationEnvironmentABC, logger: LoggerABC, mail_settings: EMailClientSettings):
|
||||
"""
|
||||
Service to send emails
|
||||
:param environment:
|
||||
:param logger:
|
||||
:param mail_settings:
|
||||
"""
|
||||
EMailClientABC.__init__(self)
|
||||
|
||||
self._environment = environment
|
||||
self._mail_settings = mail_settings
|
||||
@ -25,6 +30,10 @@ class EMailClient(EMailClientBase):
|
||||
self.create()
|
||||
|
||||
def create(self):
|
||||
"""
|
||||
Creates connection
|
||||
:return:
|
||||
"""
|
||||
self._logger.trace(__name__, f'Started {__name__}.create')
|
||||
self.connect()
|
||||
self._logger.trace(__name__, f'Stopped {__name__}.create')
|
||||
@ -45,6 +54,10 @@ class EMailClient(EMailClientBase):
|
||||
self._logger.trace(__name__, f'Stopped {__name__}.connect')
|
||||
|
||||
def login(self):
|
||||
"""
|
||||
Login to server
|
||||
:return:
|
||||
"""
|
||||
self._logger.trace(__name__, f'Started {__name__}.login')
|
||||
try:
|
||||
self._logger.debug(__name__, f'Try to login {self._mail_settings.user_name}@{self._mail_settings.host}:{self._mail_settings.port}')
|
@ -1,14 +1,14 @@
|
||||
import traceback
|
||||
|
||||
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
|
||||
from sh_edraft.console.console import Console
|
||||
from sh_edraft.mailing.model.email_client_settings_name import EMailClientSettingsName
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.mailing.email_client_settings_name_enum import EMailClientSettingsNameEnum
|
||||
|
||||
|
||||
class EMailClientSettings(ConfigurationModelBase):
|
||||
class EMailClientSettings(ConfigurationModelABC):
|
||||
|
||||
def __init__(self):
|
||||
ConfigurationModelBase.__init__(self)
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._host: str = ''
|
||||
self._port: int = 0
|
||||
@ -49,10 +49,10 @@ class EMailClientSettings(ConfigurationModelBase):
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._host = settings[EMailClientSettingsName.host.value]
|
||||
self._port = settings[EMailClientSettingsName.port.value]
|
||||
self._user_name = settings[EMailClientSettingsName.user_name.value]
|
||||
self._credentials = settings[EMailClientSettingsName.credentials.value]
|
||||
self._host = settings[EMailClientSettingsNameEnum.host.value]
|
||||
self._port = settings[EMailClientSettingsNameEnum.port.value]
|
||||
self._user_name = settings[EMailClientSettingsNameEnum.user_name.value]
|
||||
self._credentials = settings[EMailClientSettingsNameEnum.credentials.value]
|
||||
except Exception as e:
|
||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
|
||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class EMailClientSettingsName(Enum):
|
||||
class EMailClientSettingsNameEnum(Enum):
|
||||
|
||||
host = 'Host'
|
||||
port = 'Port'
|
27
src/cpl/time/__init__.py
Normal file
27
src/cpl/time/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.time'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .time_format_settings import TimeFormatSettings
|
||||
from .time_format_settings_names_enum import TimeFormatSettingsNamesEnum
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
@ -1,16 +1,16 @@
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase
|
||||
from sh_edraft.time.model.time_format_settings_names import TimeFormatSettingsNames
|
||||
from sh_edraft.console.console import Console
|
||||
from sh_edraft.console.model.foreground_color import ForegroundColor
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.time.time_format_settings_names_enum import TimeFormatSettingsNamesEnum
|
||||
|
||||
|
||||
class TimeFormatSettings(ConfigurationModelBase):
|
||||
class TimeFormatSettings(ConfigurationModelABC):
|
||||
|
||||
def __init__(self):
|
||||
ConfigurationModelBase.__init__(self)
|
||||
ConfigurationModelABC.__init__(self)
|
||||
self._date_format: Optional[str] = None
|
||||
self._time_format: Optional[str] = None
|
||||
self._date_time_format: Optional[str] = None
|
||||
@ -50,12 +50,12 @@ class TimeFormatSettings(ConfigurationModelBase):
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._date_format = settings[TimeFormatSettingsNames.date_format.value]
|
||||
self._time_format = settings[TimeFormatSettingsNames.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_format = settings[TimeFormatSettingsNamesEnum.date_format.value]
|
||||
self._time_format = settings[TimeFormatSettingsNamesEnum.time_format.value]
|
||||
self._date_time_format = settings[TimeFormatSettingsNamesEnum.date_time_format.value]
|
||||
self._date_time_log_format = settings[TimeFormatSettingsNamesEnum.date_time_log_format.value]
|
||||
except Exception as e:
|
||||
Console.set_foreground_color(ForegroundColor.red)
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
|
||||
Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
||||
Console.set_foreground_color(ForegroundColor.default)
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class TimeFormatSettingsNames(Enum):
|
||||
class TimeFormatSettingsNamesEnum(Enum):
|
||||
|
||||
date_format = 'DateFormat'
|
||||
time_format = 'TimeFormat'
|
28
src/cpl/utils/__init__.py
Normal file
28
src/cpl/utils/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl.utils'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .credential_manager import CredentialManager
|
||||
from .string import String
|
||||
from .pip import Pip
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
@ -2,16 +2,35 @@ import base64
|
||||
|
||||
|
||||
class CredentialManager:
|
||||
"""
|
||||
Handles credentials
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def encrypt(string: str) -> str:
|
||||
"""
|
||||
Encode with base64
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
return base64.b64encode(string.encode('utf-8')).decode('utf-8')
|
||||
|
||||
@staticmethod
|
||||
def decrypt(string: str) -> str:
|
||||
"""
|
||||
Decode with base64
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
return base64.b64decode(string).decode('utf-8')
|
||||
|
||||
@staticmethod
|
||||
def build_string(string: str, credentials: str):
|
||||
"""
|
||||
Builds string with credentials in it
|
||||
:param string:
|
||||
:param credentials:
|
||||
:return:
|
||||
"""
|
||||
return string.replace('$credentials', CredentialManager.decrypt(credentials))
|
||||
|
113
src/cpl/utils/pip.py
Normal file
113
src/cpl/utils/pip.py
Normal file
@ -0,0 +1,113 @@
|
||||
import subprocess
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Pip:
|
||||
"""
|
||||
Executes pip commands
|
||||
"""
|
||||
_executable = sys.executable
|
||||
|
||||
"""
|
||||
Getter
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_executable(cls) -> str:
|
||||
return cls._executable
|
||||
|
||||
"""
|
||||
Setter
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def set_executable(cls, executable: str):
|
||||
"""
|
||||
Sets the executable
|
||||
:param executable:
|
||||
:return:
|
||||
"""
|
||||
if executable is not None:
|
||||
cls._executable = executable
|
||||
|
||||
@classmethod
|
||||
def reset_executable(cls):
|
||||
"""
|
||||
Resets the executable to system standard
|
||||
:return:
|
||||
"""
|
||||
cls._executable = sys.executable
|
||||
|
||||
"""
|
||||
Public utils functions
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_package(cls, package: str) -> Optional[str]:
|
||||
"""
|
||||
Gets given package py local pip list
|
||||
:param package:
|
||||
:return:
|
||||
"""
|
||||
result = None
|
||||
with suppress(Exception):
|
||||
result = subprocess.check_output([cls._executable, "-m", "pip", "show", package], stderr=subprocess.DEVNULL)
|
||||
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
new_package: list[str] = str(result, 'utf-8').lower().split('\n')
|
||||
new_version = ''
|
||||
|
||||
for atr in new_package:
|
||||
if 'version' in atr:
|
||||
new_version = atr.split(': ')[1]
|
||||
|
||||
if new_version != '':
|
||||
return f'{package}=={new_version}'
|
||||
|
||||
return package
|
||||
|
||||
@classmethod
|
||||
def get_outdated(cls) -> bytes:
|
||||
"""
|
||||
Gets table of outdated packages
|
||||
:return:
|
||||
"""
|
||||
return subprocess.check_output([cls._executable, "-m", "pip", "list", "--outdated"])
|
||||
|
||||
@classmethod
|
||||
def install(cls, package: str, *args, source: str = None, stdout=None, stderr=None):
|
||||
"""
|
||||
Installs given package
|
||||
:param package:
|
||||
:param args:
|
||||
:param source:
|
||||
:param stdout:
|
||||
:param stderr:
|
||||
:return:
|
||||
"""
|
||||
pip_args = [cls._executable, "-m", "pip", "install"]
|
||||
|
||||
for arg in args:
|
||||
pip_args.append(arg)
|
||||
|
||||
if source is not None:
|
||||
pip_args.append(f'--extra-index-url')
|
||||
pip_args.append(source)
|
||||
|
||||
pip_args.append(package)
|
||||
subprocess.run(pip_args, stdout=stdout, stderr=stderr)
|
||||
|
||||
@classmethod
|
||||
def uninstall(cls, package: str, stdout=None, stderr=None):
|
||||
"""
|
||||
Uninstalls given package
|
||||
:param package:
|
||||
:param stdout:
|
||||
:param stderr:
|
||||
:return:
|
||||
"""
|
||||
subprocess.run([cls._executable, "-m", "pip", "uninstall", "--yes", package], stdout=stdout, stderr=stderr)
|
37
src/cpl/utils/string.py
Normal file
37
src/cpl/utils/string.py
Normal file
@ -0,0 +1,37 @@
|
||||
import re
|
||||
|
||||
|
||||
class String:
|
||||
"""
|
||||
Useful functions for strings
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def convert_to_snake_case(name: str) -> str:
|
||||
"""
|
||||
Converts string to snake case
|
||||
:param name:
|
||||
:return:
|
||||
"""
|
||||
pattern1 = re.compile(r'(.)([A-Z][a-z]+)')
|
||||
pattern2 = re.compile(r'([a-z0-9])([A-Z])')
|
||||
file_name = re.sub(pattern1, r'\1_\2', name)
|
||||
return re.sub(pattern2, r'\1_\2', file_name).lower()
|
||||
|
||||
@staticmethod
|
||||
def first_to_upper(string: str) -> str:
|
||||
"""
|
||||
Converts first char to upper
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
return f'{string[0].upper()}{string[1:]}'
|
||||
|
||||
@staticmethod
|
||||
def first_to_lower(string: str) -> str:
|
||||
"""
|
||||
Converts first char to lower
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
return f'{string[0].lower()}{string[1:]}'
|
32
src/cpl_cli/__init__.py
Normal file
32
src/cpl_cli/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'sh_cpl.cpl_cli'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .cli import CLI
|
||||
from .command_abc import CommandABC
|
||||
from .command_handler_service import CommandHandler
|
||||
from .command_model import CommandModel
|
||||
from .error import Error
|
||||
from .main import main
|
||||
from .startup import Startup
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
5
src/cpl_cli/appsettings.json
Normal file
5
src/cpl_cli/appsettings.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"CLI": {
|
||||
"PipPath": "https://pip.sh-edraft.de"
|
||||
}
|
||||
}
|
72
src/cpl_cli/cli.py
Normal file
72
src/cpl_cli/cli.py
Normal file
@ -0,0 +1,72 @@
|
||||
from typing import Optional
|
||||
|
||||
from cpl.application.application_abc import ApplicationABC
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.dependency_injection import ServiceProviderABC
|
||||
from cpl_cli.command.build_service import BuildService
|
||||
from cpl_cli.command.generate_service import GenerateService
|
||||
from cpl_cli.command.install_service import InstallService
|
||||
from cpl_cli.command.new_service import NewService
|
||||
from cpl_cli.command.publish_service import PublishService
|
||||
from cpl_cli.command.start_service import StartService
|
||||
from cpl_cli.command.uninstall_service import UninstallService
|
||||
from cpl_cli.command.update_service import UpdateService
|
||||
from cpl_cli.command_handler_service import CommandHandler
|
||||
from cpl_cli.command_model import CommandModel
|
||||
from cpl_cli.error import Error
|
||||
from cpl_cli.command.help_service import HelpService
|
||||
from cpl_cli.command.version_service import VersionService
|
||||
|
||||
|
||||
class CLI(ApplicationABC):
|
||||
|
||||
def __init__(self, config: ConfigurationABC, services: ServiceProviderABC):
|
||||
"""
|
||||
CPL CLI
|
||||
"""
|
||||
ApplicationABC.__init__(self, config, services)
|
||||
|
||||
self._command_handler: Optional[CommandHandler] = None
|
||||
|
||||
def configure(self):
|
||||
self._command_handler: CommandHandler = self._services.get_service(CommandHandler)
|
||||
|
||||
self._command_handler.add_command(CommandModel('build', ['h', 'B'], BuildService, True))
|
||||
self._command_handler.add_command(CommandModel('generate', ['g', 'G'], GenerateService, True))
|
||||
self._command_handler.add_command(CommandModel('help', ['h', 'H'], HelpService, False))
|
||||
self._command_handler.add_command(CommandModel('install', ['i', 'I'], InstallService, True))
|
||||
self._command_handler.add_command(CommandModel('new', ['n', 'N'], NewService, False))
|
||||
self._command_handler.add_command(CommandModel('publish', ['p', 'P'], PublishService, True))
|
||||
self._command_handler.add_command(CommandModel('start', ['s', 'S'], StartService, True))
|
||||
self._command_handler.add_command(CommandModel('uninstall', ['ui', 'UI'], UninstallService, True))
|
||||
self._command_handler.add_command(CommandModel('update', ['u', 'U'], UpdateService, True))
|
||||
self._command_handler.add_command(CommandModel('version', ['v', 'V'], VersionService, False))
|
||||
|
||||
def main(self):
|
||||
"""
|
||||
Entry point of the CPL CLI
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
command = None
|
||||
args = []
|
||||
if len(self._configuration.additional_arguments) > 0:
|
||||
command = self._configuration.additional_arguments[0]
|
||||
if len(self._configuration.additional_arguments) > 1:
|
||||
args = self._configuration.additional_arguments[1:]
|
||||
else:
|
||||
for cmd in self._command_handler.commands:
|
||||
result = self._configuration.get_configuration(cmd.name)
|
||||
if result is not None:
|
||||
command = cmd.name
|
||||
args.append(result)
|
||||
|
||||
if command is None:
|
||||
Error.error(f'Expected command')
|
||||
return
|
||||
|
||||
self._command_handler.handle(command, args)
|
||||
except KeyboardInterrupt:
|
||||
Console.write_line()
|
||||
exit()
|
25
src/cpl_cli/cli_settings.py
Normal file
25
src/cpl_cli/cli_settings.py
Normal file
@ -0,0 +1,25 @@
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
from cpl.configuration.configuration_model_abc import ConfigurationModelABC
|
||||
from cpl.console.console import Console
|
||||
from cpl_cli.cli_settings_name_enum import CLISettingsNameEnum
|
||||
|
||||
|
||||
class CLISettings(ConfigurationModelABC):
|
||||
|
||||
def __init__(self):
|
||||
ConfigurationModelABC.__init__(self)
|
||||
|
||||
self._pip_path: Optional[str] = None
|
||||
|
||||
@property
|
||||
def pip_path(self) -> str:
|
||||
return self._pip_path
|
||||
|
||||
def from_dict(self, settings: dict):
|
||||
try:
|
||||
self._pip_path = settings[CLISettingsNameEnum.pip_path.value]
|
||||
except Exception as e:
|
||||
Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings')
|
||||
Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')
|
6
src/cpl_cli/cli_settings_name_enum.py
Normal file
6
src/cpl_cli/cli_settings_name_enum.py
Normal file
@ -0,0 +1,6 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class CLISettingsNameEnum(Enum):
|
||||
|
||||
pip_path = 'PipPath'
|
31
src/cpl_cli/command/__init__.py
Normal file
31
src/cpl_cli/command/__init__.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sh_cpl sh-edraft Common Python library
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
sh-edraft Common Python library
|
||||
|
||||
:copyright: (c) 2020 - 2021 sh-edraft.de
|
||||
:license: MIT, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
__title__ = 'cpl_cli.command'
|
||||
__author__ = 'Sven Heidemann'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) 2020 - 2021 sh-edraft.de'
|
||||
__version__ = '2021.4.0'
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
# imports:
|
||||
from .build_service import BuildService
|
||||
from .generate_service import GenerateService
|
||||
from .help_service import HelpService
|
||||
from .new_service import NewService
|
||||
from .publish_service import PublishService
|
||||
from .version_service import VersionService
|
||||
|
||||
VersionInfo = namedtuple('VersionInfo', 'major minor micro')
|
||||
version_info = VersionInfo(major='2021', minor='04', micro='0')
|
22
src/cpl_cli/command/build_service.py
Normal file
22
src/cpl_cli/command/build_service.py
Normal file
@ -0,0 +1,22 @@
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.publish.publisher_abc import PublisherABC
|
||||
|
||||
|
||||
class BuildService(CommandABC):
|
||||
|
||||
def __init__(self, publisher: PublisherABC):
|
||||
"""
|
||||
Service for the CLI command build
|
||||
:param publisher:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._publisher = publisher
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
self._publisher.build()
|
162
src/cpl_cli/command/generate_service.py
Normal file
162
src/cpl_cli/command/generate_service.py
Normal file
@ -0,0 +1,162 @@
|
||||
import os
|
||||
from collections import Callable
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.console.console import Console
|
||||
from cpl.utils.string import String
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.templates.generate.init_template import InitTemplate
|
||||
from cpl_cli.templates.generate.abc_template import ABCTemplate
|
||||
from cpl_cli.templates.generate.class_template import ClassTemplate
|
||||
from cpl_cli.templates.generate.configmodel_template import ConfigModelTemplate
|
||||
from cpl_cli.templates.generate.enum_template import EnumTemplate
|
||||
from cpl_cli.templates.generate.service_template import ServiceTemplate
|
||||
from cpl_cli.templates.generate.thread_template import ThreadTemplate
|
||||
from cpl_cli.templates.template_file_abc import TemplateFileABC
|
||||
|
||||
|
||||
class GenerateService(CommandABC):
|
||||
|
||||
def __init__(self, configuration: ConfigurationABC):
|
||||
"""
|
||||
Service for the CLI command generate
|
||||
:param configuration:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._schematics = {
|
||||
"abc": {
|
||||
"Upper": "ABC",
|
||||
"Template": ABCTemplate
|
||||
},
|
||||
"class": {
|
||||
"Upper": "",
|
||||
"Template": ClassTemplate
|
||||
},
|
||||
"enum": {
|
||||
"Upper": "Enum",
|
||||
"Template": EnumTemplate
|
||||
},
|
||||
"service": {
|
||||
"Upper": "Service",
|
||||
"Template": ServiceTemplate
|
||||
},
|
||||
"settings": {
|
||||
"Upper": "Settings",
|
||||
"Template": ConfigModelTemplate
|
||||
},
|
||||
"thread": {
|
||||
"Upper": "Thread",
|
||||
"Template": ThreadTemplate
|
||||
}
|
||||
}
|
||||
|
||||
self._config = configuration
|
||||
self._env = self._config.environment
|
||||
|
||||
@staticmethod
|
||||
def _help(message: str):
|
||||
"""
|
||||
Internal help output
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
Console.error(message)
|
||||
|
||||
schematics = [
|
||||
'abc (a|A)',
|
||||
'class (c|C)',
|
||||
'enum (e|E)',
|
||||
'service (s|S)',
|
||||
'settings (st|ST)'
|
||||
]
|
||||
Console.write_line('Available Schematics:')
|
||||
for name in schematics:
|
||||
Console.write(f'\n\t{name} ')
|
||||
|
||||
@staticmethod
|
||||
def _create_file(file_path: str, value: str):
|
||||
"""
|
||||
Creates the given file with content
|
||||
:param file_path:
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
with open(file_path, 'w') as template:
|
||||
template.write(value)
|
||||
template.close()
|
||||
|
||||
def _generate(self, schematic: str, name: str, template: Callable[TemplateFileABC]):
|
||||
"""
|
||||
Generates files by given schematic, name and template
|
||||
:param schematic:
|
||||
:param name:
|
||||
:param template:
|
||||
:return:
|
||||
"""
|
||||
class_name = name
|
||||
rel_path = ''
|
||||
if '/' in name:
|
||||
parts = name.split('/')
|
||||
rel_path = '/'.join(parts[:-1])
|
||||
class_name = parts[len(parts) - 1]
|
||||
|
||||
template = template(class_name, schematic, self._schematics[schematic]["Upper"], rel_path)
|
||||
|
||||
file_path = os.path.join(self._env.working_directory, template.path, template.name)
|
||||
if not os.path.isdir(os.path.dirname(file_path)):
|
||||
os.makedirs(os.path.dirname(file_path))
|
||||
directory = ''
|
||||
for subdir in template.path.split('/'):
|
||||
directory = os.path.join(directory, subdir)
|
||||
if subdir != 'src':
|
||||
file = InitTemplate(class_name, schematic, self._schematics[schematic]["Upper"], rel_path)
|
||||
Console.spinner(
|
||||
f'Creating {os.path.abspath(directory)}/{file.name}',
|
||||
self._create_file,
|
||||
os.path.join(os.path.abspath(directory), file.name),
|
||||
file.value,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
if os.path.isfile(file_path):
|
||||
Console.error(f'{String.first_to_upper(schematic)} already exists!')
|
||||
exit()
|
||||
|
||||
message = f'Creating {self._env.working_directory}/{template.path}/{template.name}'
|
||||
if template.path == '':
|
||||
message = f'Creating {self._env.working_directory}/{template.name}'
|
||||
|
||||
Console.spinner(
|
||||
message,
|
||||
self._create_file,
|
||||
file_path,
|
||||
template.value,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if len(args) == 0:
|
||||
self._help('Usage: cpl generate <schematic> [options]')
|
||||
exit()
|
||||
|
||||
schematic = args[0]
|
||||
name = self._config.get_configuration(schematic)
|
||||
if name is None:
|
||||
name = Console.read(f'Name for the {args[0]}: ')
|
||||
|
||||
if schematic in self._schematics:
|
||||
s = self._schematics[schematic]
|
||||
self._generate(schematic, name, s["Template"])
|
||||
|
||||
else:
|
||||
self._help('Usage: cpl generate <schematic> [options]')
|
||||
exit()
|
37
src/cpl_cli/command/help_service.py
Normal file
37
src/cpl_cli/command/help_service.py
Normal file
@ -0,0 +1,37 @@
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
|
||||
|
||||
class HelpService(CommandABC):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Service for CLI command help
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
Console.write_line('Available Commands:')
|
||||
commands = [
|
||||
['build (b|B)', 'Prepares files for publish into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.'],
|
||||
['generate (g|G)', 'Generate a new file.'],
|
||||
['help (h|H)', 'Lists available command and their short descriptions.'],
|
||||
['install (i|I)', 'With argument installs packages to project, without argument installs project dependencies.'],
|
||||
['new (n|N)', 'Creates new CPL project.'],
|
||||
['publish (p|P)', 'Prepares files for publish into an output directory named dist/ at the given output path and executes setup.py. Must be executed from within a library workspace directory.'],
|
||||
['start (s|S)', 'Starts CPL project, restarting on file changes'],
|
||||
['uninstall (ui|UI)', 'Uninstalls packages from project.'],
|
||||
['update (u|u)', 'Update CPL and project dependencies.'],
|
||||
['version (v|V)', 'Outputs CPL CLI version.']
|
||||
]
|
||||
for name, description in commands:
|
||||
Console.set_foreground_color(ForegroundColorEnum.blue)
|
||||
Console.write(f'\n\t{name} ')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
Console.write(f'{description}')
|
165
src/cpl_cli/command/install_service.py
Normal file
165
src/cpl_cli/command/install_service.py
Normal file
@ -0,0 +1,165 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from packaging import version
|
||||
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.utils.pip import Pip
|
||||
from cpl_cli.cli_settings import CLISettings
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.configuration.build_settings import BuildSettings
|
||||
from cpl_cli.configuration.project_settings import ProjectSettings
|
||||
from cpl_cli.configuration.settings_helper import SettingsHelper
|
||||
from cpl_cli.error import Error
|
||||
|
||||
|
||||
class InstallService(CommandABC):
|
||||
|
||||
def __init__(self, env: ApplicationEnvironmentABC, build_settings: BuildSettings, project_settings: ProjectSettings,
|
||||
cli_settings: CLISettings):
|
||||
"""
|
||||
Service for the CLI command install
|
||||
:param env:
|
||||
:param build_settings:
|
||||
:param project_settings:
|
||||
:param cli_settings:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._env = env
|
||||
self._build_settings = build_settings
|
||||
self._project_settings = project_settings
|
||||
self._cli_settings = cli_settings
|
||||
|
||||
def _install_project(self):
|
||||
"""
|
||||
Installs dependencies of CPl project
|
||||
:return:
|
||||
"""
|
||||
|
||||
if self._project_settings is None or self._build_settings is None:
|
||||
Error.error('The command requires to be run in an CPL project, but a project could not be found.')
|
||||
return
|
||||
|
||||
if self._project_settings.dependencies is None:
|
||||
Error.error('Found invalid dependencies in cpl.json.')
|
||||
return
|
||||
|
||||
Pip.set_executable(self._project_settings.python_executable)
|
||||
for dependency in self._project_settings.dependencies:
|
||||
Console.spinner(
|
||||
f'Installing: {dependency}',
|
||||
Pip.install, dependency,
|
||||
source=self._cli_settings.pip_path if 'sh_cpl' in dependency else None,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
Pip.reset_executable()
|
||||
|
||||
def _install_package(self, package: str):
|
||||
"""
|
||||
Installs given package
|
||||
:param package:
|
||||
:return:
|
||||
"""
|
||||
is_already_in_project = False
|
||||
Pip.set_executable(self._project_settings.python_executable)
|
||||
|
||||
if self._project_settings is None or self._build_settings is None:
|
||||
Error.error('The command requires to be run in an CPL project, but a project could not be found.')
|
||||
return
|
||||
|
||||
if self._project_settings.dependencies is None:
|
||||
Error.error('Found invalid dependencies in cpl.json.')
|
||||
return
|
||||
|
||||
package_version = ''
|
||||
name = package
|
||||
if '==' in package:
|
||||
name = package.split('==')[0]
|
||||
package_version = package.split('==')[1]
|
||||
|
||||
to_remove_list = []
|
||||
for dependency in self._project_settings.dependencies:
|
||||
dependency_version = ''
|
||||
|
||||
if '==' in dependency:
|
||||
dependency_version = dependency.split('==')[1]
|
||||
|
||||
if name in dependency:
|
||||
if package_version != '' and version.parse(package_version) != version.parse(dependency_version):
|
||||
to_remove_list.append(dependency)
|
||||
break
|
||||
else:
|
||||
is_already_in_project = True
|
||||
|
||||
for to_remove in to_remove_list:
|
||||
self._project_settings.dependencies.remove(to_remove)
|
||||
|
||||
local_package = Pip.get_package(package)
|
||||
if local_package is not None and local_package in self._project_settings.dependencies:
|
||||
Error.warn(f'Package {local_package} is already installed.')
|
||||
return
|
||||
|
||||
elif is_already_in_project:
|
||||
Error.warn(f'Package {package} is already installed.')
|
||||
return
|
||||
|
||||
Console.spinner(
|
||||
f'Installing: {package}',
|
||||
Pip.install, package,
|
||||
source=self._cli_settings.pip_path if 'sh_cpl' in package else None,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
new_package = Pip.get_package(name)
|
||||
if new_package is None \
|
||||
or '==' in package and \
|
||||
version.parse(package.split('==')[1]) != version.parse(new_package.split('==')[1]):
|
||||
Console.error(f'Installation of package {package} failed')
|
||||
return
|
||||
|
||||
if not is_already_in_project:
|
||||
new_name = package
|
||||
if '==' in new_package:
|
||||
new_name = new_package
|
||||
elif '==' in name:
|
||||
new_name = name
|
||||
|
||||
if '/' in new_name:
|
||||
new_name = new_name.split('/')[0]
|
||||
|
||||
if '\r' in new_name:
|
||||
new_name = new_name.replace('\r', '')
|
||||
|
||||
self._project_settings.dependencies.append(new_name)
|
||||
|
||||
config = {
|
||||
ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(self._project_settings),
|
||||
BuildSettings.__name__: SettingsHelper.get_build_settings_dict(self._build_settings)
|
||||
}
|
||||
|
||||
with open(os.path.join(self._env.working_directory, 'cpl.json'), 'w') as project_file:
|
||||
project_file.write(json.dumps(config, indent=2))
|
||||
project_file.close()
|
||||
|
||||
Pip.reset_executable()
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if len(args) == 0:
|
||||
self._install_project()
|
||||
else:
|
||||
self._install_package(args[0])
|
231
src/cpl_cli/command/new_service.py
Normal file
231
src/cpl_cli/command/new_service.py
Normal file
@ -0,0 +1,231 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from packaging import version
|
||||
|
||||
import cpl
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.console.console import Console
|
||||
from cpl.utils.string import String
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.configuration.build_settings import BuildSettings
|
||||
from cpl_cli.configuration.build_settings_name_enum import BuildSettingsNameEnum
|
||||
from cpl_cli.configuration.project_settings import ProjectSettings
|
||||
from cpl_cli.configuration.project_settings_name_enum import ProjectSettingsNameEnum
|
||||
from cpl_cli.configuration.project_type_enum import ProjectTypeEnum
|
||||
from cpl_cli.configuration.version_settings_name_enum import VersionSettingsNameEnum
|
||||
from cpl_cli.source_creator.console_builder import ConsoleBuilder
|
||||
from cpl_cli.source_creator.library_builder import LibraryBuilder
|
||||
|
||||
|
||||
class NewService(CommandABC):
|
||||
|
||||
def __init__(self, configuration: ConfigurationABC):
|
||||
"""
|
||||
Service for the CLI command new
|
||||
:param configuration:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._config = configuration
|
||||
self._env = self._config.environment
|
||||
|
||||
self._project: ProjectSettings = ProjectSettings()
|
||||
self._project_dict = {}
|
||||
self._build: BuildSettings = BuildSettings()
|
||||
self._build_dict = {}
|
||||
self._project_json = {}
|
||||
|
||||
self._command: str = ''
|
||||
self._use_application_api: bool = False
|
||||
self._use_startup: bool = False
|
||||
self._use_service_providing: bool = False
|
||||
|
||||
@staticmethod
|
||||
def _help(message: str):
|
||||
"""
|
||||
Internal help output
|
||||
:param message:
|
||||
:return:
|
||||
"""
|
||||
Console.error(message)
|
||||
|
||||
schematics = [
|
||||
'console (c|C) <name>',
|
||||
]
|
||||
Console.write_line('Available Schematics:')
|
||||
for name in schematics:
|
||||
Console.write(f'\n\t{name} ')
|
||||
|
||||
def _create_project_settings(self, name: str):
|
||||
self._project_dict = {
|
||||
ProjectSettingsNameEnum.name.value: name,
|
||||
ProjectSettingsNameEnum.version.value: {
|
||||
VersionSettingsNameEnum.major.value: '0',
|
||||
VersionSettingsNameEnum.minor.value: '0',
|
||||
VersionSettingsNameEnum.micro.value: '0'
|
||||
},
|
||||
ProjectSettingsNameEnum.author.value: '',
|
||||
ProjectSettingsNameEnum.author_email.value: '',
|
||||
ProjectSettingsNameEnum.description.value: '',
|
||||
ProjectSettingsNameEnum.long_description.value: '',
|
||||
ProjectSettingsNameEnum.url.value: '',
|
||||
ProjectSettingsNameEnum.copyright_date.value: '',
|
||||
ProjectSettingsNameEnum.copyright_name.value: '',
|
||||
ProjectSettingsNameEnum.license_name.value: '',
|
||||
ProjectSettingsNameEnum.license_description.value: '',
|
||||
ProjectSettingsNameEnum.dependencies.value: [
|
||||
f'sh_cpl=={version.parse(cpl.__version__)}'
|
||||
],
|
||||
ProjectSettingsNameEnum.python_version.value: f'>={sys.version.split(" ")[0]}',
|
||||
ProjectSettingsNameEnum.python_path.value: {
|
||||
sys.platform: ''
|
||||
},
|
||||
ProjectSettingsNameEnum.classifiers.value: []
|
||||
}
|
||||
|
||||
self._project.from_dict(self._project_dict)
|
||||
|
||||
def _create_build_settings(self):
|
||||
main = f'{String.convert_to_snake_case(self._project.name)}.main'
|
||||
if self._command == ProjectTypeEnum.library.value:
|
||||
main = f'{String.convert_to_snake_case(self._project.name)}_cli.main'
|
||||
|
||||
self._build_dict = {
|
||||
BuildSettingsNameEnum.project_type.value: self._command,
|
||||
BuildSettingsNameEnum.source_path.value: 'src',
|
||||
BuildSettingsNameEnum.output_path.value: 'dist',
|
||||
BuildSettingsNameEnum.main.value: main,
|
||||
BuildSettingsNameEnum.entry_point.value: self._project.name,
|
||||
BuildSettingsNameEnum.include_package_data.value: False,
|
||||
BuildSettingsNameEnum.included.value: [],
|
||||
BuildSettingsNameEnum.excluded.value: [
|
||||
'*/__pycache__',
|
||||
'*/logs',
|
||||
'*/tests'
|
||||
],
|
||||
BuildSettingsNameEnum.package_data.value: {}
|
||||
}
|
||||
self._build.from_dict(self._build_dict)
|
||||
|
||||
def _create_project_json(self):
|
||||
"""
|
||||
Creates cpl.json content
|
||||
:return:
|
||||
"""
|
||||
self._project_json = {
|
||||
ProjectSettings.__name__: self._project_dict,
|
||||
BuildSettings.__name__: self._build_dict
|
||||
}
|
||||
|
||||
def _get_project_path(self) -> Optional[str]:
|
||||
"""
|
||||
Gets project path
|
||||
:return:
|
||||
"""
|
||||
project_path = os.path.join(self._env.working_directory, self._project.name)
|
||||
if os.path.isdir(project_path) and len(os.listdir(project_path)) > 0:
|
||||
Console.error('Project path is not empty\n')
|
||||
return None
|
||||
|
||||
return project_path
|
||||
|
||||
def _get_project_information(self):
|
||||
"""
|
||||
Gets project information's from user
|
||||
:return:
|
||||
"""
|
||||
result = Console.read('Do you want to use application base? (y/n) ')
|
||||
if result.lower() == 'y':
|
||||
self._use_application_api = True
|
||||
|
||||
result = Console.read('Do you want to use startup? (y/n) ')
|
||||
if result.lower() == 'y':
|
||||
self._use_startup = True
|
||||
else:
|
||||
result = Console.read('Do you want to use service providing? (y/n) ')
|
||||
if result.lower() == 'y':
|
||||
self._use_service_providing = True
|
||||
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def _console(self, args: list[str]):
|
||||
"""
|
||||
Generates new console project
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
name = self._config.get_configuration(self._command)
|
||||
|
||||
self._create_project_settings(name)
|
||||
self._create_build_settings()
|
||||
self._create_project_json()
|
||||
path = self._get_project_path()
|
||||
if path is None:
|
||||
return
|
||||
|
||||
self._get_project_information()
|
||||
try:
|
||||
ConsoleBuilder.build(
|
||||
path,
|
||||
self._use_application_api,
|
||||
self._use_startup,
|
||||
self._use_service_providing,
|
||||
self._project.name,
|
||||
self._project_json
|
||||
)
|
||||
except Exception as e:
|
||||
Console.error('Could not create project', str(e))
|
||||
|
||||
def _library(self, args: list[str]):
|
||||
"""
|
||||
Generates new library project
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
name = self._config.get_configuration(self._command)
|
||||
|
||||
self._create_project_settings(name)
|
||||
self._create_build_settings()
|
||||
self._create_project_json()
|
||||
path = self._get_project_path()
|
||||
if path is None:
|
||||
return
|
||||
|
||||
self._get_project_information()
|
||||
try:
|
||||
LibraryBuilder.build(
|
||||
path,
|
||||
self._use_application_api,
|
||||
self._use_startup,
|
||||
self._use_service_providing,
|
||||
self._project.name,
|
||||
self._project_json
|
||||
)
|
||||
except Exception as e:
|
||||
Console.error('Could not create project', str(e))
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if len(args) == 0:
|
||||
self._help('Usage: cpl new <schematic> [options]')
|
||||
return
|
||||
|
||||
self._command = str(args[0]).lower()
|
||||
if self._command == ProjectTypeEnum.console.value:
|
||||
self._console(args)
|
||||
|
||||
elif self._command == ProjectTypeEnum.library.value:
|
||||
self._library(args)
|
||||
|
||||
else:
|
||||
self._help('Usage: cpl new <schematic> [options]')
|
||||
return
|
23
src/cpl_cli/command/publish_service.py
Normal file
23
src/cpl_cli/command/publish_service.py
Normal file
@ -0,0 +1,23 @@
|
||||
from cpl.console.console import Console
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.publish.publisher_abc import PublisherABC
|
||||
|
||||
|
||||
class PublishService(CommandABC):
|
||||
|
||||
def __init__(self, publisher: PublisherABC):
|
||||
"""
|
||||
Service for the CLI command publish
|
||||
:param publisher:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._publisher = publisher
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
self._publisher.publish()
|
22
src/cpl_cli/command/start_service.py
Normal file
22
src/cpl_cli/command/start_service.py
Normal file
@ -0,0 +1,22 @@
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.live_server.live_server_service import LiveServerService
|
||||
|
||||
|
||||
class StartService(CommandABC):
|
||||
|
||||
def __init__(self, live_server: LiveServerService):
|
||||
"""
|
||||
Service for the CLI command start
|
||||
:param live_server:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._live_server = live_server
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
self._live_server.start()
|
82
src/cpl_cli/command/uninstall_service.py
Normal file
82
src/cpl_cli/command/uninstall_service.py
Normal file
@ -0,0 +1,82 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.utils.pip import Pip
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.configuration.build_settings import BuildSettings
|
||||
from cpl_cli.configuration.project_settings import ProjectSettings
|
||||
from cpl_cli.configuration.settings_helper import SettingsHelper
|
||||
|
||||
|
||||
class UninstallService(CommandABC):
|
||||
|
||||
def __init__(self, env: ApplicationEnvironmentABC, build_settings: BuildSettings,
|
||||
project_settings: ProjectSettings):
|
||||
"""
|
||||
Service for the CLI command uninstall
|
||||
:param env:
|
||||
:param build_settings:
|
||||
:param project_settings:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._env = env
|
||||
|
||||
self._build_settings = build_settings
|
||||
self._project_settings = project_settings
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
if len(args) == 0:
|
||||
Console.error(f'Expected package')
|
||||
Console.error(f'Usage: cpl uninstall <package>')
|
||||
return
|
||||
|
||||
Pip.set_executable(self._project_settings.python_executable)
|
||||
|
||||
package = args[0]
|
||||
is_in_dependencies = False
|
||||
|
||||
pip_package = Pip.get_package(package)
|
||||
|
||||
for dependency in self._project_settings.dependencies:
|
||||
if package in dependency:
|
||||
is_in_dependencies = True
|
||||
package = dependency
|
||||
|
||||
if not is_in_dependencies and pip_package is None:
|
||||
Console.error(f'Package {package} not found')
|
||||
return
|
||||
|
||||
elif not is_in_dependencies and pip_package is not None:
|
||||
package = pip_package
|
||||
|
||||
Console.spinner(
|
||||
f'Uninstalling: {package}',
|
||||
Pip.uninstall, package,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
if package in self._project_settings.dependencies:
|
||||
self._project_settings.dependencies.remove(package)
|
||||
config = {
|
||||
ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(self._project_settings),
|
||||
BuildSettings.__name__: SettingsHelper.get_build_settings_dict(self._build_settings)
|
||||
}
|
||||
with open(os.path.join(self._env.working_directory, 'cpl.json'), 'w') as project_file:
|
||||
project_file.write(json.dumps(config, indent=2))
|
||||
project_file.close()
|
||||
|
||||
Console.write_line(f'Removed {package}')
|
||||
Pip.reset_executable()
|
151
src/cpl_cli/command/update_service.py
Normal file
151
src/cpl_cli/command/update_service.py
Normal file
@ -0,0 +1,151 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl.environment.application_environment_abc import ApplicationEnvironmentABC
|
||||
from cpl.utils.pip import Pip
|
||||
from cpl_cli.cli_settings import CLISettings
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
from cpl_cli.configuration import BuildSettings
|
||||
from cpl_cli.configuration.project_settings import ProjectSettings
|
||||
from cpl_cli.configuration.settings_helper import SettingsHelper
|
||||
|
||||
|
||||
class UpdateService(CommandABC):
|
||||
|
||||
def __init__(self,
|
||||
env: ApplicationEnvironmentABC,
|
||||
build_settings: BuildSettings,
|
||||
project_settings: ProjectSettings,
|
||||
cli_settings: CLISettings):
|
||||
"""
|
||||
Service for the CLI command update
|
||||
:param env:
|
||||
:param build_settings:
|
||||
:param project_settings:
|
||||
:param cli_settings:
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
self._env = env
|
||||
self._build_settings = build_settings
|
||||
self._project_settings = project_settings
|
||||
self._cli_settings = cli_settings
|
||||
|
||||
def _collect_project_dependencies(self) -> list[tuple]:
|
||||
"""
|
||||
Collects project dependencies
|
||||
:return:
|
||||
"""
|
||||
dependencies = []
|
||||
for package in self._project_settings.dependencies:
|
||||
name = package
|
||||
if '==' in package:
|
||||
name = package.split('==')[0]
|
||||
|
||||
dependencies.append((package, name))
|
||||
|
||||
return dependencies
|
||||
|
||||
def _update_project_dependencies(self, dependencies):
|
||||
"""
|
||||
Updates project dependencies
|
||||
:return:
|
||||
"""
|
||||
for package, name in dependencies:
|
||||
Pip.install(
|
||||
name,
|
||||
'--upgrade',
|
||||
'--upgrade-strategy',
|
||||
'eager',
|
||||
source=self._cli_settings.pip_path if 'sh_cpl' in name else None,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
new_package = Pip.get_package(name)
|
||||
if new_package is None:
|
||||
Console.error(f'Update for package {package} failed')
|
||||
return
|
||||
|
||||
self._project_json_update_dependency(package, new_package)
|
||||
|
||||
def _check_project_dependencies(self):
|
||||
"""
|
||||
Checks project dependencies for updates
|
||||
:return:
|
||||
"""
|
||||
dependencies = Console.spinner(
|
||||
'Collecting installed dependencies', self._collect_project_dependencies,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
Console.spinner(
|
||||
'Updating installed dependencies', self._update_project_dependencies, dependencies,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
Console.write_line(f'Found {len(self._project_settings.dependencies)} dependencies.')
|
||||
|
||||
@staticmethod
|
||||
def _check_outdated():
|
||||
"""
|
||||
Checks for outdated packages in project
|
||||
:return:
|
||||
"""
|
||||
table_str: bytes = Console.spinner(
|
||||
'Analyzing for available package updates', Pip.get_outdated,
|
||||
text_foreground_color=ForegroundColorEnum.green,
|
||||
spinner_foreground_color=ForegroundColorEnum.cyan
|
||||
)
|
||||
|
||||
table = str(table_str, 'utf-8').split('\n')
|
||||
if len(table) > 1 and table[0] != '':
|
||||
Console.write_line('\tAvailable updates for packages:')
|
||||
for row in table:
|
||||
Console.write_line(f'\t{row}')
|
||||
|
||||
Console.set_foreground_color(ForegroundColorEnum.yellow)
|
||||
Console.write_line(f'\tUpdate with {Pip.get_executable()} -m pip install --upgrade <package>')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
|
||||
def _project_json_update_dependency(self, old_package: str, new_package: str):
|
||||
"""
|
||||
Writes new package version to cpl.json
|
||||
:param old_package:
|
||||
:param new_package:
|
||||
:return:
|
||||
"""
|
||||
if old_package in self._project_settings.dependencies:
|
||||
index = self._project_settings.dependencies.index(old_package)
|
||||
if '/' in new_package:
|
||||
new_package = new_package.split('/')[0]
|
||||
|
||||
if '\r' in new_package:
|
||||
new_package = new_package.replace('\r', '')
|
||||
|
||||
self._project_settings.dependencies[index] = new_package
|
||||
|
||||
config = {
|
||||
ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(self._project_settings),
|
||||
BuildSettings.__name__: SettingsHelper.get_build_settings_dict(self._build_settings)
|
||||
}
|
||||
|
||||
with open(os.path.join(self._env.working_directory, 'cpl.json'), 'w') as project:
|
||||
project.write(json.dumps(config, indent=2))
|
||||
project.close()
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
Pip.set_executable(self._project_settings.python_executable)
|
||||
self._check_project_dependencies()
|
||||
self._check_outdated()
|
||||
Pip.reset_executable()
|
54
src/cpl_cli/command/version_service.py
Normal file
54
src/cpl_cli/command/version_service.py
Normal file
@ -0,0 +1,54 @@
|
||||
import pkgutil
|
||||
import sys
|
||||
import platform
|
||||
import pkg_resources
|
||||
|
||||
import cpl
|
||||
import cpl_cli
|
||||
from cpl.console.console import Console
|
||||
from cpl.console.foreground_color_enum import ForegroundColorEnum
|
||||
from cpl_cli.command_abc import CommandABC
|
||||
|
||||
|
||||
class VersionService(CommandABC):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Service for the CLI command version
|
||||
"""
|
||||
CommandABC.__init__(self)
|
||||
|
||||
def run(self, args: list[str]):
|
||||
"""
|
||||
Entry point of command
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
Console.set_foreground_color(ForegroundColorEnum.yellow)
|
||||
Console.banner('CPL CLI')
|
||||
Console.set_foreground_color(ForegroundColorEnum.default)
|
||||
if '__version__' in dir(cpl_cli):
|
||||
Console.write_line(f'Common Python library CLI: ')
|
||||
Console.write(cpl_cli.__version__)
|
||||
|
||||
Console.write_line(f'Python: ')
|
||||
Console.write(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')
|
||||
|
||||
Console.write_line(f'OS: {platform.system()} {platform.processor()}')
|
||||
|
||||
Console.write_line('\nCPL packages:')
|
||||
packages = []
|
||||
for importer, modname, is_pkg in pkgutil.iter_modules(cpl.__path__):
|
||||
module = importer.find_module(modname).load_module(modname)
|
||||
if '__version__' in dir(module):
|
||||
packages.append([f'{modname}', module.__version__])
|
||||
|
||||
Console.table(['Name', 'Version'], packages)
|
||||
|
||||
Console.write_line('\nPython packages:')
|
||||
packages = []
|
||||
dependencies = dict(tuple(str(ws).split()) for ws in pkg_resources.working_set)
|
||||
for p in dependencies:
|
||||
packages.append([p, dependencies[p]])
|
||||
|
||||
Console.table(['Name', 'Version'], packages)
|
11
src/cpl_cli/command_abc.py
Normal file
11
src/cpl_cli/command_abc.py
Normal file
@ -0,0 +1,11 @@
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
|
||||
class CommandABC(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
ABC.__init__(self)
|
||||
|
||||
@abstractmethod
|
||||
def run(self, args: list[str]): pass
|
54
src/cpl_cli/command_handler_service.py
Normal file
54
src/cpl_cli/command_handler_service.py
Normal file
@ -0,0 +1,54 @@
|
||||
import os
|
||||
from abc import ABC
|
||||
|
||||
from cpl.configuration.configuration_abc import ConfigurationABC
|
||||
from cpl.console.console import Console
|
||||
from cpl.dependency_injection.service_provider_abc import ServiceProviderABC
|
||||
from cpl_cli.error import Error
|
||||
from cpl_cli.command_model import CommandModel
|
||||
|
||||
|
||||
class CommandHandler(ABC):
|
||||
|
||||
def __init__(self, config: ConfigurationABC, services: ServiceProviderABC):
|
||||
"""
|
||||
Service to handle incoming commands and args
|
||||
:param config:
|
||||
:param services:
|
||||
"""
|
||||
ABC.__init__(self)
|
||||
|
||||
self._config = config
|
||||
self._env = self._config.environment
|
||||
self._services = services
|
||||
|
||||
self._commands: list[CommandModel] = []
|
||||
|
||||
@property
|
||||
def commands(self) -> list[CommandModel]:
|
||||
return self._commands
|
||||
|
||||
def add_command(self, cmd: CommandModel):
|
||||
self._commands.append(cmd)
|
||||
|
||||
def remove_command(self, cmd: CommandModel):
|
||||
self._commands.remove(cmd)
|
||||
|
||||
def handle(self, cmd: str, args: list[str]):
|
||||
"""
|
||||
Handles incoming commands and args
|
||||
:param cmd:
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
for command in self._commands:
|
||||
if cmd == command.name or cmd in command.aliases:
|
||||
if command.is_project_needed and not os.path.isfile(os.path.join(self._env.working_directory, 'cpl.json')):
|
||||
Error.error('The command requires to be run in an CPL project, but a project could not be found.')
|
||||
return
|
||||
|
||||
if command.is_project_needed:
|
||||
self._config.add_json_file('cpl.json', optional=True, output=False)
|
||||
|
||||
self._services.get_service(command.command).run(args)
|
||||
Console.write('\n')
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user