Compare commits
	
		
			39 Commits
		
	
	
		
			75fde0f444
			...
			#170
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 60a349f918 | |||
| a155bbc468 | |||
| 2e8886e255 | |||
| aabbfeaa92 | |||
| 39ca803d36 | |||
| b7d518022a | |||
| 2ec4af8bb3 | |||
| 30b163a440 | |||
| 82f23f237c | |||
| 79a6c1db8f | |||
| 51803bf5d1 | |||
| a463ac5274 | |||
| 3ee617ee38 | |||
| e5fd7df519 | |||
| 7001b23b31 | |||
| e94ff1b26f | |||
| d7d41b878c | |||
| 9d05d76cfa | |||
| e6ee543a1d | |||
| efc9cf9c83 | |||
| 8dee4d8f70 | |||
| 315b8e631a | |||
| cbb1860f25 | |||
| 9839bcaa14 | |||
| da54337221 | |||
| a6a1e764d1 | |||
| eb6aa08c10 | |||
| 14a190a67f | |||
| cf5ae89884 | |||
| 558dfb8ced | |||
| 2ec8fc22b3 | |||
| c94700495b | |||
| 69a3bc5e31 | |||
| d189f49418 | |||
| 60fb416b67 | |||
| 792429d19d | |||
| 106975015e | |||
| 1117735f2e | |||
| 0378f8944a | 
@@ -87,7 +87,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Install the CPL package
 | 
					Install the CPL package
 | 
				
			||||||
```sh
 | 
					```sh
 | 
				
			||||||
pip install cpl --extra-index-url https://pip.sh-edraft.de
 | 
					pip install cpl-core --extra-index-url https://pip.sh-edraft.de
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install the CPL CLI
 | 
					Install the CPL CLI
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
      "cpl-core": "src/cpl_core/cpl-core.json",
 | 
					      "cpl-core": "src/cpl_core/cpl-core.json",
 | 
				
			||||||
      "cpl-discord": "src/cpl_discord/cpl-discord.json",
 | 
					      "cpl-discord": "src/cpl_discord/cpl-discord.json",
 | 
				
			||||||
      "cpl-query": "src/cpl_query/cpl-query.json",
 | 
					      "cpl-query": "src/cpl_query/cpl-query.json",
 | 
				
			||||||
 | 
					      "cpl-reactive-extensions": "src/cpl_reactive_extensions/cpl-reactive-extensions.json",
 | 
				
			||||||
      "cpl-translation": "src/cpl_translation/cpl-translation.json",
 | 
					      "cpl-translation": "src/cpl_translation/cpl-translation.json",
 | 
				
			||||||
      "set-version": "tools/set_version/set-version.json",
 | 
					      "set-version": "tools/set_version/set-version.json",
 | 
				
			||||||
      "set-pip-urls": "tools/set_pip_urls/set-pip-urls.json",
 | 
					      "set-pip-urls": "tools/set_pip_urls/set-pip-urls.json",
 | 
				
			||||||
@@ -14,7 +15,8 @@
 | 
				
			|||||||
      "unittests_core": "unittests/unittests_core/unittests_core.json",
 | 
					      "unittests_core": "unittests/unittests_core/unittests_core.json",
 | 
				
			||||||
      "unittests_query": "unittests/unittests_query/unittests_query.json",
 | 
					      "unittests_query": "unittests/unittests_query/unittests_query.json",
 | 
				
			||||||
      "unittests_shared": "unittests/unittests_shared/unittests_shared.json",
 | 
					      "unittests_shared": "unittests/unittests_shared/unittests_shared.json",
 | 
				
			||||||
      "unittests_translation": "unittests/unittests_translation/unittests_translation.json"
 | 
					      "unittests_translation": "unittests/unittests_translation/unittests_translation.json",
 | 
				
			||||||
 | 
					      "unittests_reactive_extenstions": "unittests/unittests_reactive_extenstions/unittests_reactive_extenstions.json"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Scripts": {
 | 
					    "Scripts": {
 | 
				
			||||||
      "hello-world": "echo 'Hello World'",
 | 
					      "hello-world": "echo 'Hello World'",
 | 
				
			||||||
@@ -40,12 +42,13 @@
 | 
				
			|||||||
      "test": "cpl run unittests",
 | 
					      "test": "cpl run unittests",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "pre-build-all": "cpl sv $ARGS; cpl spu $ARGS;",
 | 
					      "pre-build-all": "cpl sv $ARGS; cpl spu $ARGS;",
 | 
				
			||||||
      "build-all": "cpl build-cli; cpl build-core; cpl build-discord; cpl build-query; cpl build-translation; cpl build-set-pip-urls; cpl build-set-version",
 | 
					      "build-all": "cpl build-cli; cpl build-core; cpl build-discord; cpl build-query; cpl build-reactive-extensions; cpl build-translation; cpl build-set-pip-urls; cpl build-set-version",
 | 
				
			||||||
      "ba": "cpl build-all $ARGS",
 | 
					      "ba": "cpl build-all $ARGS",
 | 
				
			||||||
      "build-cli": "echo 'Build cpl-cli'; cd ./src/cpl_cli; cpl build; cd ../../;",
 | 
					      "build-cli": "echo 'Build cpl-cli'; cd ./src/cpl_cli; cpl build; cd ../../;",
 | 
				
			||||||
      "build-core": "echo 'Build cpl-core'; cd ./src/cpl_core; cpl build; cd ../../;",
 | 
					      "build-core": "echo 'Build cpl-core'; cd ./src/cpl_core; cpl build; cd ../../;",
 | 
				
			||||||
      "build-discord": "echo 'Build cpl-discord'; cd ./src/cpl_discord; cpl build; cd ../../;",
 | 
					      "build-discord": "echo 'Build cpl-discord'; cd ./src/cpl_discord; cpl build; cd ../../;",
 | 
				
			||||||
      "build-query": "echo 'Build cpl-query'; cd ./src/cpl_query; cpl build; cd ../../;",
 | 
					      "build-query": "echo 'Build cpl-query'; cd ./src/cpl_query; cpl build; cd ../../;",
 | 
				
			||||||
 | 
					      "build-reactive-extensions": "echo 'Build cpl-reactive-x'; cd ./src/cpl_reactive_extensions; cpl build; cd ../../;",
 | 
				
			||||||
      "build-translation": "echo 'Build cpl-translation'; cd ./src/cpl_translation; cpl build; cd ../../;",
 | 
					      "build-translation": "echo 'Build cpl-translation'; cd ./src/cpl_translation; cpl build; cd ../../;",
 | 
				
			||||||
      "build-set-pip-urls": "echo 'Build set-pip-urls'; cd ./tools/set_pip_urls; cpl build; cd ../../;",
 | 
					      "build-set-pip-urls": "echo 'Build set-pip-urls'; cd ./tools/set_pip_urls; cpl build; cd ../../;",
 | 
				
			||||||
      "build-set-version": "echo 'Build set-version'; cd ./tools/set_version; cpl build; cd ../../;",
 | 
					      "build-set-version": "echo 'Build set-version'; cd ./tools/set_version; cpl build; cd ../../;",
 | 
				
			||||||
@@ -57,6 +60,7 @@
 | 
				
			|||||||
      "publish-core": "echo 'Publish cpl-core'; cd ./src/cpl_core; cpl publish; cd ../../;",
 | 
					      "publish-core": "echo 'Publish cpl-core'; cd ./src/cpl_core; cpl publish; cd ../../;",
 | 
				
			||||||
      "publish-discord": "echo 'Publish cpl-discord'; cd ./src/cpl_discord; cpl publish; cd ../../;",
 | 
					      "publish-discord": "echo 'Publish cpl-discord'; cd ./src/cpl_discord; cpl publish; cd ../../;",
 | 
				
			||||||
      "publish-query": "echo 'Publish cpl-query'; cd ./src/cpl_query; cpl publish; cd ../../;",
 | 
					      "publish-query": "echo 'Publish cpl-query'; cd ./src/cpl_query; cpl publish; cd ../../;",
 | 
				
			||||||
 | 
					      "publish-reactive-extensions": "echo 'Publish cpl-reactive-x'; cd ./src/cpl_reactive_extensions; cpl publish; cd ../../;",
 | 
				
			||||||
      "publish-translation": "echo 'Publish cpl-translation'; cd ./src/cpl_translation; cpl publish; cd ../../;",
 | 
					      "publish-translation": "echo 'Publish cpl-translation'; cd ./src/cpl_translation; cpl publish; cd ../../;",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "upload-prod-cli": "echo 'PROD Upload cpl-cli'; cpl upl-prod-cli;",
 | 
					      "upload-prod-cli": "echo 'PROD Upload cpl-cli'; cpl upl-prod-cli;",
 | 
				
			||||||
@@ -71,6 +75,9 @@
 | 
				
			|||||||
      "upload-prod-query": "echo 'PROD Upload cpl-query'; cpl upl-prod-query;",
 | 
					      "upload-prod-query": "echo 'PROD Upload cpl-query'; cpl upl-prod-query;",
 | 
				
			||||||
      "upl-prod-query": "twine upload -r pip.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
					      "upl-prod-query": "twine upload -r pip.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "upload-prod-reactive-extensions": "echo 'PROD Upload cpl-reactive-extensions'; cpl upl-prod-query;",
 | 
				
			||||||
 | 
					      "upl-prod-reactive-extensions": "twine upload -r pip.sh-edraft.de dist/cpl-reactive-extensions/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "upload-prod-translation": "echo 'PROD Upload cpl-translation'; cpl upl-prod-translation;",
 | 
					      "upload-prod-translation": "echo 'PROD Upload cpl-translation'; cpl upl-prod-translation;",
 | 
				
			||||||
      "upl-prod-translation": "twine upload -r pip.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
					      "upl-prod-translation": "twine upload -r pip.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,6 +93,9 @@
 | 
				
			|||||||
      "upload-exp-query": "echo 'EXP Upload cpl-query'; cpl upl-exp-query;",
 | 
					      "upload-exp-query": "echo 'EXP Upload cpl-query'; cpl upl-exp-query;",
 | 
				
			||||||
      "upl-exp-query": "twine upload -r pip-exp.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
					      "upl-exp-query": "twine upload -r pip-exp.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "upload-exp-reactive-extensions": "echo 'EXP Upload cpl-reactive-extensions'; cpl upl-exp-query;",
 | 
				
			||||||
 | 
					      "upl-exp-reactive-extensions": "twine upload -r pip-exp.sh-edraft.de dist/cpl-reactive-extensions/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "upload-exp-translation": "echo 'EXP Upload cpl-translation'; cpl upl-exp-translation;",
 | 
					      "upload-exp-translation": "echo 'EXP Upload cpl-translation'; cpl upl-exp-translation;",
 | 
				
			||||||
      "upl-exp-translation": "twine upload -r pip-exp.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
					      "upl-exp-translation": "twine upload -r pip-exp.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -101,6 +111,9 @@
 | 
				
			|||||||
      "upload-dev-query": "echo 'DEV Upload cpl-query'; cpl upl-dev-query;",
 | 
					      "upload-dev-query": "echo 'DEV Upload cpl-query'; cpl upl-dev-query;",
 | 
				
			||||||
      "upl-dev-query": "twine upload -r pip-dev.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
					      "upl-dev-query": "twine upload -r pip-dev.sh-edraft.de dist/cpl-query/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "upload-dev-reactive-extensions": "echo 'DEV Upload cpl-reactive-extensions'; cpl upl-dev-query;",
 | 
				
			||||||
 | 
					      "upl-dev-reactive-extensions": "twine upload -r pip-dev.sh-edraft.de dist/cpl-reactive-extensions/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "upload-dev-translation": "echo 'DEV Upload cpl-translation'; cpl upl-dev-translation;",
 | 
					      "upload-dev-translation": "echo 'DEV Upload cpl-translation'; cpl upl-dev-translation;",
 | 
				
			||||||
      "upl-dev-translation": "twine upload -r pip-dev.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
					      "upl-dev-translation": "twine upload -r pip-dev.sh-edraft.de dist/cpl-translation/publish/setup/*",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,6 @@
 | 
				
			|||||||
import traceback
 | 
					 | 
				
			||||||
from typing import Optional
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
 | 
					from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC
 | 
				
			||||||
from cpl_core.console.console import Console
 | 
					 | 
				
			||||||
from cpl_cli.cli_settings_name_enum import CLISettingsNameEnum
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CLISettings(ConfigurationModelABC):
 | 
					class CLISettings(ConfigurationModelABC):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,10 @@ class BuildSettings(ConfigurationModelABC):
 | 
				
			|||||||
        main: str = None,
 | 
					        main: str = None,
 | 
				
			||||||
        entry_point: str = None,
 | 
					        entry_point: str = None,
 | 
				
			||||||
        include_package_data: bool = None,
 | 
					        include_package_data: bool = None,
 | 
				
			||||||
        included: list[str] = None,
 | 
					        included: list = None,
 | 
				
			||||||
        excluded: list[str] = None,
 | 
					        excluded: list = None,
 | 
				
			||||||
        package_data: dict[str, list[str]] = None,
 | 
					        package_data: dict = None,
 | 
				
			||||||
        project_references: list[str] = None,
 | 
					        project_references: list = None,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        ConfigurationModelABC.__init__(self)
 | 
					        ConfigurationModelABC.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ class ProjectSettings(ConfigurationModelABC):
 | 
				
			|||||||
        self._python_executable: Optional[str] = python_executable
 | 
					        self._python_executable: Optional[str] = python_executable
 | 
				
			||||||
        self._classifiers: Optional[list[str]] = [] if classifiers is None else classifiers
 | 
					        self._classifiers: Optional[list[str]] = [] if classifiers is None else classifiers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if python_path is not None:
 | 
					        if python_path is not None and sys.platform in python_path:
 | 
				
			||||||
            path = f"{python_path[sys.platform]}"
 | 
					            path = f"{python_path[sys.platform]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if path == "" or path is None:
 | 
					            if path == "" or path is None:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,4 +23,4 @@ from collections import namedtuple
 | 
				
			|||||||
# imports:
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.application"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,4 +29,4 @@ from .startup_abc import StartupABC
 | 
				
			|||||||
from .startup_extension_abc import StartupExtensionABC
 | 
					from .startup_extension_abc import StartupExtensionABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.configuration"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,4 +35,4 @@ from .validator_abc import ValidatorABC
 | 
				
			|||||||
from .variable_argument import VariableArgument
 | 
					from .variable_argument import VariableArgument
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -294,7 +294,7 @@ class Configuration(ConfigurationABC):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    self.add_configuration(sub, configuration)
 | 
					                    self.add_configuration(sub, configuration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_configuration(self, key_type: T, value: any):
 | 
					    def add_configuration(self, key_type: Type[T], value: any):
 | 
				
			||||||
        self._config[key_type] = value
 | 
					        self._config[key_type] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_console_argument(
 | 
					    def create_console_argument(
 | 
				
			||||||
@@ -314,7 +314,7 @@ class Configuration(ConfigurationABC):
 | 
				
			|||||||
        for arg in self._argument_types:
 | 
					        for arg in self._argument_types:
 | 
				
			||||||
            call(arg)
 | 
					            call(arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_configuration(self, search_type: Type[T]) -> Optional[T]:
 | 
					    def get_configuration(self, search_type: T) -> Optional[T]:
 | 
				
			||||||
        if type(search_type) is str:
 | 
					        if type(search_type) is str:
 | 
				
			||||||
            if search_type == ConfigurationVariableNameEnum.environment.value:
 | 
					            if search_type == ConfigurationVariableNameEnum.environment.value:
 | 
				
			||||||
                return self._application_environment.environment_name
 | 
					                return self._application_environment.environment_name
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,7 +77,7 @@ class ConfigurationABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def add_configuration(self, key_type: T, value: any):
 | 
					    def add_configuration(self, key_type: Type[T], value: any):
 | 
				
			||||||
        r"""Add configuration object
 | 
					        r"""Add configuration object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter:
 | 
					        Parameter:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.console"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,4 +28,4 @@ from .foreground_color_enum import ForegroundColorEnum
 | 
				
			|||||||
from .spinner_thread import SpinnerThread
 | 
					from .spinner_thread import SpinnerThread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
    "Version": {
 | 
					    "Version": {
 | 
				
			||||||
      "Major": "2023",
 | 
					      "Major": "2023",
 | 
				
			||||||
      "Minor": "4",
 | 
					      "Minor": "4",
 | 
				
			||||||
      "Micro": "0"
 | 
					      "Micro": "dev170"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Author": "Sven Heidemann",
 | 
					    "Author": "Sven Heidemann",
 | 
				
			||||||
    "AuthorEmail": "sven.heidemann@sh-edraft.de",
 | 
					    "AuthorEmail": "sven.heidemann@sh-edraft.de",
 | 
				
			||||||
@@ -16,17 +16,17 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "art==5.9",
 | 
					      "art>=5.9",
 | 
				
			||||||
      "colorama==0.4.6",
 | 
					      "colorama>=0.4.6",
 | 
				
			||||||
      "mysql-connector==2.2.9",
 | 
					      "mysql-connector>=2.2.9",
 | 
				
			||||||
      "psutil==5.9.4",
 | 
					      "psutil>=5.9.4",
 | 
				
			||||||
      "packaging==23.0",
 | 
					      "packaging>=23.0",
 | 
				
			||||||
      "pynput==1.7.6",
 | 
					      "pynput>=1.7.6",
 | 
				
			||||||
      "setuptools==67.6.1",
 | 
					      "setuptools>=67.6.1",
 | 
				
			||||||
      "tabulate==0.9.0",
 | 
					      "tabulate>=0.9.0",
 | 
				
			||||||
      "termcolor==2.2.0",
 | 
					      "termcolor>=2.2.0",
 | 
				
			||||||
      "watchdog==3.0.0",
 | 
					      "watchdog>=3.0.0",
 | 
				
			||||||
      "wheel==0.40.0"
 | 
					      "wheel>=0.40.0"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [
 | 
					    "DevDependencies": [
 | 
				
			||||||
      "Sphinx==5.0.2",
 | 
					      "Sphinx==5.0.2",
 | 
				
			||||||
@@ -36,7 +36,7 @@
 | 
				
			|||||||
      "sphinx-markdown-builder==0.5.5",
 | 
					      "sphinx-markdown-builder==0.5.5",
 | 
				
			||||||
      "pygount==1.5.1"
 | 
					      "pygount==1.5.1"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "PythonVersion": ">=3.11",
 | 
					    "PythonVersion": ">=3.10",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
    "Classifiers": []
 | 
					    "Classifiers": []
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.database"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,4 +26,4 @@ from .database_settings import DatabaseSettings
 | 
				
			|||||||
from .table_abc import TableABC
 | 
					from .table_abc import TableABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.database.connection"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,4 +25,4 @@ from .database_connection import DatabaseConnection
 | 
				
			|||||||
from .database_connection_abc import DatabaseConnectionABC
 | 
					from .database_connection_abc import DatabaseConnectionABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.database.context"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,4 +25,4 @@ from .database_context import DatabaseContext
 | 
				
			|||||||
from .database_context_abc import DatabaseContextABC
 | 
					from .database_context_abc import DatabaseContextABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,11 +12,11 @@ class DatabaseSettings(ConfigurationModelABC):
 | 
				
			|||||||
        port: int = None,
 | 
					        port: int = None,
 | 
				
			||||||
        user: str = None,
 | 
					        user: str = None,
 | 
				
			||||||
        password: str = None,
 | 
					        password: str = None,
 | 
				
			||||||
        databse: str = None,
 | 
					        database: str = None,
 | 
				
			||||||
        charset: str = None,
 | 
					        charset: str = None,
 | 
				
			||||||
        use_unicode: bool = None,
 | 
					        use_unicode: bool = None,
 | 
				
			||||||
        buffered: bool = None,
 | 
					        buffered: bool = None,
 | 
				
			||||||
        auth_plugin: bool = None,
 | 
					        auth_plugin: str = None,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        ConfigurationModelABC.__init__(self)
 | 
					        ConfigurationModelABC.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +24,7 @@ class DatabaseSettings(ConfigurationModelABC):
 | 
				
			|||||||
        self._port: Optional[int] = port
 | 
					        self._port: Optional[int] = port
 | 
				
			||||||
        self._user: Optional[str] = user
 | 
					        self._user: Optional[str] = user
 | 
				
			||||||
        self._password: Optional[str] = password
 | 
					        self._password: Optional[str] = password
 | 
				
			||||||
        self._databse: Optional[str] = databse
 | 
					        self._databse: Optional[str] = database
 | 
				
			||||||
        self._charset: Optional[str] = charset
 | 
					        self._charset: Optional[str] = charset
 | 
				
			||||||
        self._use_unicode: Optional[bool] = use_unicode
 | 
					        self._use_unicode: Optional[bool] = use_unicode
 | 
				
			||||||
        self._buffered: Optional[bool] = buffered
 | 
					        self._buffered: Optional[bool] = buffered
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.dependency_injection"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,4 +31,4 @@ from .service_provider import ServiceProvider
 | 
				
			|||||||
from .service_provider_abc import ServiceProviderABC
 | 
					from .service_provider_abc import ServiceProviderABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,15 +61,15 @@ class ServiceCollection(ServiceCollectionABC):
 | 
				
			|||||||
            self.add_transient(PipeABC, pipe)
 | 
					            self.add_transient(PipeABC, pipe)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_singleton(self, service_type: T, service: T = None):
 | 
					    def add_singleton(self, service_type: Type[T], service: T = None):
 | 
				
			||||||
        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.singleton, service)
 | 
					        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.singleton, service)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_scoped(self, service_type: T, service: Callable = None):
 | 
					    def add_scoped(self, service_type: Type[T], service: Callable = None):
 | 
				
			||||||
        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.scoped, service)
 | 
					        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.scoped, service)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add_transient(self, service_type: T, service: T = None):
 | 
					    def add_transient(self, service_type: Type[T], service: T = None):
 | 
				
			||||||
        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.transient, service)
 | 
					        self._add_descriptor_by_lifetime(service_type, ServiceLifetimeEnum.transient, service)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ class ServiceCollectionABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def add_transient(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
 | 
					    def add_transient(self, service_type: Type[T], service: T = None) -> "ServiceCollectionABC":
 | 
				
			||||||
        r"""Adds a service with transient lifetime
 | 
					        r"""Adds a service with transient lifetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter:
 | 
					        Parameter:
 | 
				
			||||||
@@ -61,7 +61,7 @@ class ServiceCollectionABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def add_scoped(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
 | 
					    def add_scoped(self, service_type: Type[T], service: T = None) -> "ServiceCollectionABC":
 | 
				
			||||||
        r"""Adds a service with scoped lifetime
 | 
					        r"""Adds a service with scoped lifetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter:
 | 
					        Parameter:
 | 
				
			||||||
@@ -76,7 +76,7 @@ class ServiceCollectionABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def add_singleton(self, service_type: T, service: T = None) -> "ServiceCollectionABC":
 | 
					    def add_singleton(self, service_type: Type[T], service: T = None) -> "ServiceCollectionABC":
 | 
				
			||||||
        r"""Adds a service with singleton lifetime
 | 
					        r"""Adds a service with singleton lifetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter:
 | 
					        Parameter:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,7 +138,7 @@ class ServiceProvider(ServiceProviderABC):
 | 
				
			|||||||
        sb = ScopeBuilder(ServiceProvider(descriptors, self._configuration, self._database_context))
 | 
					        sb = ScopeBuilder(ServiceProvider(descriptors, self._configuration, self._database_context))
 | 
				
			||||||
        return sb.build()
 | 
					        return sb.build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_service(self, service_type: T, *args, **kwargs) -> Optional[T]:
 | 
					    def get_service(self, service_type: typing.Type[T], *args, **kwargs) -> Optional[T]:
 | 
				
			||||||
        result = self._find_service(service_type)
 | 
					        result = self._find_service(service_type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if result is None:
 | 
					        if result is None:
 | 
				
			||||||
@@ -157,7 +157,7 @@ class ServiceProvider(ServiceProviderABC):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return implementation
 | 
					        return implementation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_services(self, service_type: T, *args, **kwargs) -> list[Optional[T]]:
 | 
					    def get_services(self, service_type: typing.Type[T], *args, **kwargs) -> list[Optional[T]]:
 | 
				
			||||||
        implementations = []
 | 
					        implementations = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if typing.get_origin(service_type) != list:
 | 
					        if typing.get_origin(service_type) != list:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import functools
 | 
					import functools
 | 
				
			||||||
from abc import abstractmethod, ABC
 | 
					from abc import abstractmethod, ABC
 | 
				
			||||||
from inspect import Signature, signature
 | 
					from inspect import Signature, signature
 | 
				
			||||||
from typing import Type, Optional
 | 
					from typing import Optional, Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cpl_core.dependency_injection.scope_abc import ScopeABC
 | 
					from cpl_core.dependency_injection.scope_abc import ScopeABC
 | 
				
			||||||
from cpl_core.type import T
 | 
					from cpl_core.type import T
 | 
				
			||||||
@@ -61,7 +61,7 @@ class ServiceProviderABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def get_service(self, instance_type: T, *args, **kwargs) -> Optional[T]:
 | 
					    def get_service(self, instance_type: Type[T], *args, **kwargs) -> Optional[T]:
 | 
				
			||||||
        r"""Returns instance of given type
 | 
					        r"""Returns instance of given type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter
 | 
					        Parameter
 | 
				
			||||||
@@ -76,7 +76,7 @@ class ServiceProviderABC(ABC):
 | 
				
			|||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @abstractmethod
 | 
					    @abstractmethod
 | 
				
			||||||
    def get_services(self, service_type: T, *args, **kwargs) -> list[Optional[T]]:
 | 
					    def get_services(self, service_type: Type[T], *args, **kwargs) -> list[Optional[T]]:
 | 
				
			||||||
        r"""Returns instance of given type
 | 
					        r"""Returns instance of given type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Parameter
 | 
					        Parameter
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.environment"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,4 +26,4 @@ from .environment_name_enum import EnvironmentNameEnum
 | 
				
			|||||||
from .application_environment import ApplicationEnvironment
 | 
					from .application_environment import ApplicationEnvironment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.logging"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,4 +28,4 @@ from .logging_settings import LoggingSettings
 | 
				
			|||||||
from .logging_settings_name_enum import LoggingSettingsNameEnum
 | 
					from .logging_settings_name_enum import LoggingSettingsNameEnum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.mailing"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,4 +28,4 @@ from .email_client_settings import EMailClientSettings
 | 
				
			|||||||
from .email_client_settings_name_enum import EMailClientSettingsNameEnum
 | 
					from .email_client_settings_name_enum import EMailClientSettingsNameEnum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,14 +15,15 @@ __title__ = "cpl_core.pipes"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# imports:
 | 
					# imports:
 | 
				
			||||||
from .bool_pipe import BoolPipe
 | 
					from .bool_pipe import BoolPipe
 | 
				
			||||||
from .ip_address_pipe import IPAddressPipe
 | 
					from .ip_address_pipe import IPAddressPipe
 | 
				
			||||||
from .pipe_abc import PipeABC
 | 
					from .pipe_abc import PipeABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.time"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,4 +25,4 @@ from .time_format_settings import TimeFormatSettings
 | 
				
			|||||||
from .time_format_settings_names_enum import TimeFormatSettingsNamesEnum
 | 
					from .time_format_settings_names_enum import TimeFormatSettingsNamesEnum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
from typing import TypeVar
 | 
					from typing import TypeVar, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
T = TypeVar("T")
 | 
					T = TypeVar("T")
 | 
				
			||||||
 | 
					Number = Union[int, float]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ __title__ = "cpl_core.utils"
 | 
				
			|||||||
__author__ = "Sven Heidemann"
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
__license__ = "MIT"
 | 
					__license__ = "MIT"
 | 
				
			||||||
__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
					__copyright__ = "Copyright (c) 2020 - 2023 sh-edraft.de"
 | 
				
			||||||
__version__ = "2023.4.0"
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,4 +26,4 @@ from .string import String
 | 
				
			|||||||
from .pip import Pip
 | 
					from .pip import Pip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
version_info = VersionInfo(major="2023", minor="4", micro="0")
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,14 @@ class JSONProcessor:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            name = String.first_to_upper(String.convert_to_camel_case(parameter.name))
 | 
					            name = String.first_to_upper(String.convert_to_camel_case(parameter.name))
 | 
				
			||||||
            name_first_lower = String.first_to_lower(name)
 | 
					            name_first_lower = String.first_to_lower(name)
 | 
				
			||||||
            if name in values or name_first_lower in values:
 | 
					            if name in values or name_first_lower in values or name.upper() in values:
 | 
				
			||||||
                value = ""
 | 
					                value = ""
 | 
				
			||||||
                if name in values:
 | 
					                if name in values:
 | 
				
			||||||
                    value = values[name]
 | 
					                    value = values[name]
 | 
				
			||||||
                else:
 | 
					                elif name_first_lower in values:
 | 
				
			||||||
                    value = values[name_first_lower]
 | 
					                    value = values[name_first_lower]
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    value = values[name.upper()]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if isinstance(value, dict) and not issubclass(parameter.annotation, dict):
 | 
					                if isinstance(value, dict) and not issubclass(parameter.annotation, dict):
 | 
				
			||||||
                    value = JSONProcessor.process(parameter.annotation, value)
 | 
					                    value = JSONProcessor.process(parameter.annotation, value)
 | 
				
			||||||
@@ -30,6 +32,9 @@ class JSONProcessor:
 | 
				
			|||||||
                if issubclass(parameter.annotation, enum.Enum):
 | 
					                if issubclass(parameter.annotation, enum.Enum):
 | 
				
			||||||
                    value = parameter.annotation[value]
 | 
					                    value = parameter.annotation[value]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if type(value) != parameter.annotation:
 | 
				
			||||||
 | 
					                    value = parameter.annotation(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                args.append(value)
 | 
					                args.append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            elif parameter.default != Parameter.empty:
 | 
					            elif parameter.default != Parameter.empty:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ __version__ = "2023.4.0"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from collections import namedtuple
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# imports:
 | 
					# imports:
 | 
				
			||||||
from .default_lambda import default_lambda
 | 
					from .default_lambda import default_lambda
 | 
				
			||||||
from .ordered_queryable import OrderedQueryable
 | 
					from .ordered_queryable import OrderedQueryable
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [],
 | 
					    "Dependencies": [],
 | 
				
			||||||
    "DevDependencies": [],
 | 
					    "DevDependencies": [],
 | 
				
			||||||
    "PythonVersion": ">=3.11",
 | 
					    "PythonVersion": ">=3.10",
 | 
				
			||||||
    "PythonPath": {},
 | 
					    "PythonPath": {},
 | 
				
			||||||
    "Classifiers": []
 | 
					    "Classifiers": []
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/abc/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/abc/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.abc"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/cpl_reactive_extensions/abc/observer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/cpl_reactive_extensions/abc/observer.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					from abc import abstractmethod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Observer:
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def next(self, value: T):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def error(self, ex: Exception):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def complete(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/cpl_reactive_extensions/abc/operator.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/cpl_reactive_extensions/abc/operator.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Operator:
 | 
				
			||||||
 | 
					    def call(self, subscriber: Subscriber, source: Any):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/cpl_reactive_extensions/abc/scheduler_action.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/cpl_reactive_extensions/abc/scheduler_action.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from abc import ABC, abstractmethod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T, Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SchedulerAction(ABC):
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def schedule(self, state: T = None, delay: Number = None) -> Subscription:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/cpl_reactive_extensions/abc/scheduler_like.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/cpl_reactive_extensions/abc/scheduler_like.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					from abc import ABC, abstractmethod
 | 
				
			||||||
 | 
					from typing import Callable, Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import Number, T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.scheduler_action import SchedulerAction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SchedulerLike(ABC):
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def schedule(self, work: Callable[[SchedulerAction, Optional[T]], None], delay: Number, state: T) -> Subscription:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/cpl_reactive_extensions/abc/subscribable.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/cpl_reactive_extensions/abc/subscribable.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					from abc import ABC, abstractmethod
 | 
				
			||||||
 | 
					from typing import Union, Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.unsubscribable import Unsubscribable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Subscribable(ABC):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        ABC.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def subscribe(
 | 
				
			||||||
 | 
					        self, observer_or_next: Union[Callable, Observer], on_error: Callable = None, on_complete: Callable = None
 | 
				
			||||||
 | 
					    ) -> Unsubscribable:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/cpl_reactive_extensions/abc/unsubscribable.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/cpl_reactive_extensions/abc/unsubscribable.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from abc import ABC, abstractmethod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Unsubscribable(ABC):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        ABC.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abstractmethod
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/cpl_reactive_extensions/cpl-reactive-extensions.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/cpl_reactive_extensions/cpl-reactive-extensions.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "ProjectSettings": {
 | 
				
			||||||
 | 
					    "Name": "cpl-reactive-extensions",
 | 
				
			||||||
 | 
					    "Version": {
 | 
				
			||||||
 | 
					      "Major": "2023",
 | 
				
			||||||
 | 
					      "Minor": "4",
 | 
				
			||||||
 | 
					      "Micro": "dev170"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Author": "Sven Heidemann",
 | 
				
			||||||
 | 
					    "AuthorEmail": "sven.heidemann@sh-edraft.de",
 | 
				
			||||||
 | 
					    "Description": "CPL Simple ReactiveX implementation",
 | 
				
			||||||
 | 
					    "LongDescription": "CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.",
 | 
				
			||||||
 | 
					    "URL": "https://www.sh-edraft.de",
 | 
				
			||||||
 | 
					    "CopyrightDate": "2023",
 | 
				
			||||||
 | 
					    "CopyrightName": "sh-edraft.de",
 | 
				
			||||||
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
 | 
					    "Dependencies": [
 | 
				
			||||||
 | 
					      "cpl-core>=2023.4.dev170"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "DevDependencies": [
 | 
				
			||||||
 | 
					      "cpl-cli>=2023.4.0"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
 | 
					    "PythonPath": {},
 | 
				
			||||||
 | 
					    "Classifiers": []
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "BuildSettings": {
 | 
				
			||||||
 | 
					    "ProjectType": "library",
 | 
				
			||||||
 | 
					    "SourcePath": "",
 | 
				
			||||||
 | 
					    "OutputPath": "../../dist",
 | 
				
			||||||
 | 
					    "Main": "",
 | 
				
			||||||
 | 
					    "EntryPoint": "",
 | 
				
			||||||
 | 
					    "IncludePackageData": false,
 | 
				
			||||||
 | 
					    "Included": [],
 | 
				
			||||||
 | 
					    "Excluded": [
 | 
				
			||||||
 | 
					      "*/__pycache__",
 | 
				
			||||||
 | 
					      "*/logs",
 | 
				
			||||||
 | 
					      "*/tests"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "PackageData": {},
 | 
				
			||||||
 | 
					    "ProjectReferences": []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/helper/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/helper/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.helper"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/cpl_reactive_extensions/helper/bind.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/cpl_reactive_extensions/helper/bind.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					def bind(instance, func, *args, as_name=None):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Bind the function *func* to *instance*, with either provided name *as_name*
 | 
				
			||||||
 | 
					    or the existing name of *func*. The provided *func* should accept the
 | 
				
			||||||
 | 
					    instance as the first argument, i.e. "self".
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    if as_name is None:
 | 
				
			||||||
 | 
					        as_name = func.__name__
 | 
				
			||||||
 | 
					    bound_method = func.__get__(instance, instance.__class__)
 | 
				
			||||||
 | 
					    setattr(instance, as_name, bound_method)
 | 
				
			||||||
 | 
					    return bound_method
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/internal/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/internal/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.internal"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/cpl_reactive_extensions/internal/action.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/cpl_reactive_extensions/internal/action.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from cpl_core.type import T, Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Action(Subscription):
 | 
				
			||||||
 | 
					    def __init__(self, scheduler, work):
 | 
				
			||||||
 | 
					        Subscription.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def schedule(self, state: T = None, delay: Number = 0) -> Subscription:
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
							
								
								
									
										103
									
								
								src/cpl_reactive_extensions/internal/async_action.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/cpl_reactive_extensions/internal/async_action.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T, Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.action import Action
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.timer import Timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncAction(Action):
 | 
				
			||||||
 | 
					    def __init__(self, scheduler, work):
 | 
				
			||||||
 | 
					        from cpl_reactive_extensions.scheduler.async_scheduler import AsyncScheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Action.__init__(self, scheduler, work)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._scheduler: AsyncScheduler = scheduler
 | 
				
			||||||
 | 
					        self._work = work
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.timer = None
 | 
				
			||||||
 | 
					        self.state: Optional[T] = None
 | 
				
			||||||
 | 
					        self.delay: Number = 0
 | 
				
			||||||
 | 
					        self._pending = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def schedule(self, state: T = None, delay: Number = 0) -> Subscription:
 | 
				
			||||||
 | 
					        if self.closed:
 | 
				
			||||||
 | 
					            return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.state = state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        timer = self.timer
 | 
				
			||||||
 | 
					        scheduler = self._scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if timer is not None:
 | 
				
			||||||
 | 
					            self.timer = self.recycle_async_timer(scheduler, timer, delay)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._pending = True
 | 
				
			||||||
 | 
					        self.delay = delay
 | 
				
			||||||
 | 
					        self.timer = self.timer if self.timer is not None else self.request_async_timer(scheduler, delay)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def request_async_timer(self, scheduler, delay: Number = 0):
 | 
				
			||||||
 | 
					        from cpl_reactive_extensions.scheduler.async_scheduler import AsyncScheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scheduler: AsyncScheduler = scheduler
 | 
				
			||||||
 | 
					        return Timer(delay, lambda: scheduler.flush(self))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recycle_async_timer(self, scheduler, timer=None, delay: Number = None):
 | 
				
			||||||
 | 
					        from cpl_reactive_extensions.scheduler.async_scheduler import AsyncScheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scheduler: AsyncScheduler = scheduler
 | 
				
			||||||
 | 
					        if delay is None and self.delay == delay and not self._pending:
 | 
				
			||||||
 | 
					            return timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if timer is not None:
 | 
				
			||||||
 | 
					            timer.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self, state: T, delay: Number):
 | 
				
			||||||
 | 
					        if self.closed:
 | 
				
			||||||
 | 
					            return Exception("Executing cancelled action")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._pending = False
 | 
				
			||||||
 | 
					        error = self._execute(state, delay)
 | 
				
			||||||
 | 
					        if error is not None:
 | 
				
			||||||
 | 
					            return error
 | 
				
			||||||
 | 
					        elif not self._pending and self.timer is not None:
 | 
				
			||||||
 | 
					            self._timer = self.recycle_async_timer(self._scheduler, self.timer, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _execute(self, state: T, delay: Number):
 | 
				
			||||||
 | 
					        errored = False
 | 
				
			||||||
 | 
					        ex = None
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self._work(state)
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            errored = True
 | 
				
			||||||
 | 
					            ex = e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if errored:
 | 
				
			||||||
 | 
					            self.unsubscribe()
 | 
				
			||||||
 | 
					            return ex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        if self.closed:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        timer = self.timer
 | 
				
			||||||
 | 
					        scheduler = self._scheduler
 | 
				
			||||||
 | 
					        actions = self._scheduler.actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._work = None
 | 
				
			||||||
 | 
					        self.state = None
 | 
				
			||||||
 | 
					        self._scheduler = None
 | 
				
			||||||
 | 
					        self._pending = False
 | 
				
			||||||
 | 
					        self.delay = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self in actions:
 | 
				
			||||||
 | 
					            actions.remove(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.timer is not None:
 | 
				
			||||||
 | 
					            self.timer = self.recycle_async_timer(scheduler, timer, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Action.unsubscribe(self)
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/cpl_reactive_extensions/internal/operator_subscriber.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/cpl_reactive_extensions/internal/operator_subscriber.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OperatorSubscriber(Subscriber, Observer):
 | 
				
			||||||
 | 
					    def __init__(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        destination: Subscriber,
 | 
				
			||||||
 | 
					        on_next: Callable = None,
 | 
				
			||||||
 | 
					        on_error: Callable = None,
 | 
				
			||||||
 | 
					        on_complete: Callable = None,
 | 
				
			||||||
 | 
					        on_finalize: Callable = None,
 | 
				
			||||||
 | 
					        should_unsubscribe: Callable = None,
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        Subscriber.__init__(self, destination)
 | 
				
			||||||
 | 
					        self._on_finalize = on_finalize
 | 
				
			||||||
 | 
					        self._should_unsubscribe = should_unsubscribe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_next_wrapper(value: T):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                on_next(value)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                destination.error(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._on_next = on_next_wrapper if on_next is not None else self._on_next
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_error_wrapper(value: T):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                on_error(value)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                destination.error(e)
 | 
				
			||||||
 | 
					            finally:
 | 
				
			||||||
 | 
					                self.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._on_error = on_error_wrapper if on_error is not None else self._on_error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_complete_wrapper(value: T):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                on_complete(value)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                destination.error(e)
 | 
				
			||||||
 | 
					            finally:
 | 
				
			||||||
 | 
					                self.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._on_complete = on_complete_wrapper if on_complete is not None else self._on_complete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        if self._should_unsubscribe is not None and not self._should_unsubscribe():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        Subscriber.unsubscribe(self)
 | 
				
			||||||
 | 
					        if not self.closed and self._on_finalize is not None:
 | 
				
			||||||
 | 
					            self._on_finalize()
 | 
				
			||||||
							
								
								
									
										65
									
								
								src/cpl_reactive_extensions/internal/subscriber.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/cpl_reactive_extensions/internal/subscriber.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.type import ObserverOrCallable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Subscriber(Subscription, Observer):
 | 
				
			||||||
 | 
					    def __init__(
 | 
				
			||||||
 | 
					        self, on_next_or_observer: ObserverOrCallable, on_error: Callable = None, on_complete: Callable = None
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        self.is_stopped = False
 | 
				
			||||||
 | 
					        Subscription.__init__(self)
 | 
				
			||||||
 | 
					        if isinstance(on_next_or_observer, Observer):
 | 
				
			||||||
 | 
					            self._on_next = on_next_or_observer.next
 | 
				
			||||||
 | 
					            self._on_error = on_next_or_observer.error
 | 
				
			||||||
 | 
					            self._on_complete = on_next_or_observer.complete
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self._on_next = on_next_or_observer
 | 
				
			||||||
 | 
					            self._on_error = on_error
 | 
				
			||||||
 | 
					            self._on_complete = on_complete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _next(self, value: T):
 | 
				
			||||||
 | 
					        self._on_next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next(self, value: T):
 | 
				
			||||||
 | 
					        if self.is_stopped:
 | 
				
			||||||
 | 
					            raise Exception("Observer is closed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _error(self, ex: Exception):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self._on_error(ex)
 | 
				
			||||||
 | 
					        except TypeError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def error(self, ex: Exception):
 | 
				
			||||||
 | 
					        self._error(ex)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _complete(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self._on_complete()
 | 
				
			||||||
 | 
					        except TypeError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def complete(self):
 | 
				
			||||||
 | 
					        if self.is_stopped:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_stopped = True
 | 
				
			||||||
 | 
					        self._complete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        if self._closed:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_stopped = True
 | 
				
			||||||
 | 
					        Subscription.unsubscribe(self)
 | 
				
			||||||
 | 
					        self._on_next = None
 | 
				
			||||||
							
								
								
									
										96
									
								
								src/cpl_reactive_extensions/internal/subscription.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/cpl_reactive_extensions/internal/subscription.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					from __future__ import annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					from typing import Union, Callable, Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.console import Console
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.unsubscribable import Unsubscribable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Subscription(Unsubscribable):
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def empty():
 | 
				
			||||||
 | 
					        empty = Subscription()
 | 
				
			||||||
 | 
					        empty.closed = True
 | 
				
			||||||
 | 
					        return empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, initial_teardown: Optional[Callable] = None):
 | 
				
			||||||
 | 
					        Unsubscribable.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._initial_teardown = initial_teardown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._closed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._parentage: list[Subscription] = []
 | 
				
			||||||
 | 
					        self._finalizers: list[Subscription] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def closed(self) -> bool:
 | 
				
			||||||
 | 
					        return self._closed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @closed.setter
 | 
				
			||||||
 | 
					    def closed(self, value: bool):
 | 
				
			||||||
 | 
					        self._closed = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _add_parent(self, parent: Subscription):
 | 
				
			||||||
 | 
					        self._parentage.append(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _remove_parent(self, parent: Subscription):
 | 
				
			||||||
 | 
					        if self == parent:
 | 
				
			||||||
 | 
					            self._parentage.clear()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._parentage.remove(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _has_parent(self, parent: Subscription) -> bool:
 | 
				
			||||||
 | 
					        return parent in self._parentage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _exec_finalizer(self, finalizer: Union[Callable, Unsubscribable]):
 | 
				
			||||||
 | 
					        if isinstance(finalizer, Callable):
 | 
				
			||||||
 | 
					            finalizer()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            finalizer.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        if not self._closed:
 | 
				
			||||||
 | 
					            self._closed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for parent in self._parentage:
 | 
				
			||||||
 | 
					            parent.remove(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self._initial_teardown is not None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self._initial_teardown()
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                Console.error(e, traceback.format_exc())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        finalizers = self._finalizers
 | 
				
			||||||
 | 
					        self._finalizers = None
 | 
				
			||||||
 | 
					        for finalizer in finalizers:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self._exec_finalizer(finalizer)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                Console.error(e, traceback.format_exc())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add(self, tear_down: Union[Subscription, Unsubscribable]):
 | 
				
			||||||
 | 
					        if tear_down is None or tear_down == self:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.closed:
 | 
				
			||||||
 | 
					            self._exec_finalizer(tear_down)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if isinstance(tear_down, Subscription):
 | 
				
			||||||
 | 
					            if tear_down.closed or tear_down._has_parent(self):
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tear_down._add_parent(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._finalizers.append(tear_down)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove(self, tear_down: Union[Subscription, Unsubscribable]):
 | 
				
			||||||
 | 
					        if self._finalizers is not None:
 | 
				
			||||||
 | 
					            self._finalizers.remove(tear_down)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if isinstance(tear_down, Subscription):
 | 
				
			||||||
 | 
					            tear_down._remove_parent(self)
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/cpl_reactive_extensions/internal/timer_provider.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/cpl_reactive_extensions/internal/timer_provider.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.timer import Timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TimerProvider:
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def set_timer(handler: Callable, timeout: Number = None, *args):
 | 
				
			||||||
 | 
					        return Timer(timeout, handler, *args)
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/cpl_reactive_extensions/internal/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/cpl_reactive_extensions/internal/utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def operate(init: Callable[[Observable, Subscriber], None]):
 | 
				
			||||||
 | 
					    def observable(source: Observable):
 | 
				
			||||||
 | 
					        def create(self: Subscriber, lifted_source: Observable):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                return init(lifted_source, self)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                self.error(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if "lift" not in dir(source):
 | 
				
			||||||
 | 
					            raise TypeError("Unable to lift unknown Observable type")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return source.lift(create)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return observable
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/cpl_reactive_extensions/interval.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/cpl_reactive_extensions/interval.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import sched
 | 
				
			||||||
 | 
					import threading
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Interval(Observable):
 | 
				
			||||||
 | 
					    def __init__(self, interval: float, callback: Callable = None, not_in_background=False):
 | 
				
			||||||
 | 
					        self._interval = interval
 | 
				
			||||||
 | 
					        callback = callback if callback is not None else self._default_callback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def schedule(x: Subscriber):
 | 
				
			||||||
 | 
					            scheduler = sched.scheduler(time.time, time.sleep)
 | 
				
			||||||
 | 
					            scheduler.enter(
 | 
				
			||||||
 | 
					                self._interval,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                self._run,
 | 
				
			||||||
 | 
					                (scheduler, x, callback),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            scheduler.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def thread(x: Subscriber):
 | 
				
			||||||
 | 
					            t = threading.Thread(target=schedule, args=(x,))
 | 
				
			||||||
 | 
					            t.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Observable.__init__(self, schedule if not_in_background else thread)
 | 
				
			||||||
 | 
					        self._i = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _run(self, scheduler, x: Subscriber, callback: Callable):
 | 
				
			||||||
 | 
					        if x.closed:
 | 
				
			||||||
 | 
					            x.complete()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        scheduler.enter(
 | 
				
			||||||
 | 
					            self._interval,
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					            self._run,
 | 
				
			||||||
 | 
					            (scheduler, x, callback),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        callback(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _default_callback(self, x: Subscriber):
 | 
				
			||||||
 | 
					        x.next(self._i)
 | 
				
			||||||
 | 
					        self._i += 1
 | 
				
			||||||
							
								
								
									
										114
									
								
								src/cpl_reactive_extensions/observable.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/cpl_reactive_extensions/observable.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					from __future__ import annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import Callable, Any, Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.subscribable import Subscribable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.type import ObserverOrCallable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Observable(Subscribable):
 | 
				
			||||||
 | 
					    def __init__(self, subscribe: Callable = None):
 | 
				
			||||||
 | 
					        Subscribable.__init__(self)
 | 
				
			||||||
 | 
					        if subscribe is not None:
 | 
				
			||||||
 | 
					            self._subscribe = subscribe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._source: Optional[Observable] = None
 | 
				
			||||||
 | 
					        self._operator: Optional[Callable] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def from_observable(obs: Observable):
 | 
				
			||||||
 | 
					        def inner(subscriber: Subscriber):
 | 
				
			||||||
 | 
					            if "subscribe" not in dir(obs):
 | 
				
			||||||
 | 
					                raise TypeError("Unable to lift unknown Observable type")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return obs.subscribe(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Observable(inner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def from_list(values: list):
 | 
				
			||||||
 | 
					        i = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def callback(x: Subscriber):
 | 
				
			||||||
 | 
					            nonlocal i
 | 
				
			||||||
 | 
					            if i == len(values):
 | 
				
			||||||
 | 
					                i = 0
 | 
				
			||||||
 | 
					                x.complete()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                x.next(values[i])
 | 
				
			||||||
 | 
					                i += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if not x.closed:
 | 
				
			||||||
 | 
					                    callback(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Observable(callback)
 | 
				
			||||||
 | 
					        return observable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def lift(self, operator: Callable) -> Observable:
 | 
				
			||||||
 | 
					        observable = Observable()
 | 
				
			||||||
 | 
					        observable._source = self
 | 
				
			||||||
 | 
					        observable._operator = operator
 | 
				
			||||||
 | 
					        return observable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _is_observer(value: Any) -> bool:
 | 
				
			||||||
 | 
					        return isinstance(value, Observer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _is_subscription(value: Any) -> bool:
 | 
				
			||||||
 | 
					        return isinstance(value, Subscription)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _is_subscriber(value: Any) -> bool:
 | 
				
			||||||
 | 
					        return isinstance(value, Subscriber) or Observable._is_observer(value) and Observable._is_subscription(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _subscribe(self, subscriber: Subscriber) -> Subscription:
 | 
				
			||||||
 | 
					        return self._source.subscribe(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _try_subscribe(self, subscriber: Subscriber) -> Subscription:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return self._subscribe(subscriber)
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            subscriber.error(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def subscribe(
 | 
				
			||||||
 | 
					        self, observer_or_next: ObserverOrCallable, on_error: Callable = None, on_complete: Callable = None
 | 
				
			||||||
 | 
					    ) -> Subscription:
 | 
				
			||||||
 | 
					        subscriber = (
 | 
				
			||||||
 | 
					            observer_or_next
 | 
				
			||||||
 | 
					            if Observable._is_subscriber(observer_or_next)
 | 
				
			||||||
 | 
					            else Subscriber(observer_or_next, on_error, on_complete)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subscriber.add(
 | 
				
			||||||
 | 
					            self._operator(subscriber, self._source)
 | 
				
			||||||
 | 
					            if self._operator is not None
 | 
				
			||||||
 | 
					            else self._subscribe(subscriber)
 | 
				
			||||||
 | 
					            if self._source is not None
 | 
				
			||||||
 | 
					            else self._try_subscribe(subscriber)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return subscriber
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def pipe(self, *args) -> Observable:
 | 
				
			||||||
 | 
					        return self._pipe_from_array(args)(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _pipe_from_array(self, args):
 | 
				
			||||||
 | 
					        if len(args) == 0:
 | 
				
			||||||
 | 
					            return lambda x: x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(args) == 1:
 | 
				
			||||||
 | 
					            return args[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def piped(input: T):
 | 
				
			||||||
 | 
					            return Observable._reduce(lambda prev, fn: fn(prev), input)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return piped
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _reduce(func: Callable, input: T):
 | 
				
			||||||
 | 
					        return func(input)
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/operators/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/operators/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.operators"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/cpl_reactive_extensions/operators/debounce_time.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/cpl_reactive_extensions/operators/debounce_time.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T, Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.scheduler_action import SchedulerAction
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.operator_subscriber import OperatorSubscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.utils import operate
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.scheduler.async_scheduler import async_scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def debounce_time(time: Number, scheduler=async_scheduler):
 | 
				
			||||||
 | 
					    def init(source: Observable, subscriber: Subscriber):
 | 
				
			||||||
 | 
					        active_task: Optional[Subscription] = None
 | 
				
			||||||
 | 
					        last_value: Optional[T] = None
 | 
				
			||||||
 | 
					        last_time: Optional[Number] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def emit():
 | 
				
			||||||
 | 
					            nonlocal active_task, last_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if active_task is None:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            active_task.unsubscribe()
 | 
				
			||||||
 | 
					            active_task = None
 | 
				
			||||||
 | 
					            value = last_value
 | 
				
			||||||
 | 
					            last_value = None
 | 
				
			||||||
 | 
					            subscriber.next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def emit_when_idle(action: SchedulerAction):
 | 
				
			||||||
 | 
					            nonlocal active_task, last_time
 | 
				
			||||||
 | 
					            target_time = last_time + time
 | 
				
			||||||
 | 
					            now = scheduler.now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if now < target_time:
 | 
				
			||||||
 | 
					                active_task = action.schedule(None, target_time - now)
 | 
				
			||||||
 | 
					                subscriber.add(active_task)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            emit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_next(value: T):
 | 
				
			||||||
 | 
					            nonlocal active_task, last_value
 | 
				
			||||||
 | 
					            last_value = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if active_task is None:
 | 
				
			||||||
 | 
					                active_task = scheduler.schedule(emit_when_idle, time)
 | 
				
			||||||
 | 
					                subscriber.add(active_task)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_complete():
 | 
				
			||||||
 | 
					            emit()
 | 
				
			||||||
 | 
					            subscriber.complete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_finalize():
 | 
				
			||||||
 | 
					            nonlocal active_task, last_value
 | 
				
			||||||
 | 
					            last_value = None
 | 
				
			||||||
 | 
					            active_task = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub = source.subscribe(OperatorSubscriber(subscriber, on_next, None, on_complete, on_finalize))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return operate(init)
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/cpl_reactive_extensions/operators/take.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/cpl_reactive_extensions/operators/take.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.operator_subscriber import OperatorSubscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.utils import operate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def take(count: int):
 | 
				
			||||||
 | 
					    if count <= 0:
 | 
				
			||||||
 | 
					        return Observable()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init(source: Observable, subscriber: Subscriber):
 | 
				
			||||||
 | 
					        seen = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_next(value: T):
 | 
				
			||||||
 | 
					            nonlocal seen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if seen + 1 <= count:
 | 
				
			||||||
 | 
					                seen += 1
 | 
				
			||||||
 | 
					                subscriber.next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if count <= seen:
 | 
				
			||||||
 | 
					                    subscriber.complete()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                sub.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub = source.subscribe(OperatorSubscriber(subscriber, on_next))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return operate(init)
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/cpl_reactive_extensions/operators/take_until.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/cpl_reactive_extensions/operators/take_until.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.operator_subscriber import OperatorSubscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.utils import operate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def take_until(notifier: Observable):
 | 
				
			||||||
 | 
					    def init(source: Observable, subscriber: Subscriber):
 | 
				
			||||||
 | 
					        Observable.from_observable(notifier).subscribe(OperatorSubscriber(subscriber, lambda: subscriber.complete()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not subscriber.closed:
 | 
				
			||||||
 | 
					            source.subscribe(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return operate(init)
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/scheduler/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/scheduler/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.scheduler"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/cpl_reactive_extensions/scheduler/async_scheduler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/cpl_reactive_extensions/scheduler/async_scheduler.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					from typing import Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.action import Action
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.async_action import AsyncAction
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.scheduler.scheduler import Scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncScheduler(Scheduler):
 | 
				
			||||||
 | 
					    def __init__(self, scheduler_action_ctor: Type[Action], now=None):
 | 
				
			||||||
 | 
					        Scheduler.__init__(self, scheduler_action_ctor, now)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.actions: list[AsyncAction] = []
 | 
				
			||||||
 | 
					        self._active = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flush(self, action: AsyncAction):
 | 
				
			||||||
 | 
					        if self._active:
 | 
				
			||||||
 | 
					            self.actions.append(action)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        error = None
 | 
				
			||||||
 | 
					        self._active = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for action in self.actions:
 | 
				
			||||||
 | 
					            error = action.execute(action.state, action.delay)
 | 
				
			||||||
 | 
					            if error:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._active = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if error is not None:
 | 
				
			||||||
 | 
					            for action in self.actions:
 | 
				
			||||||
 | 
					                action.unsubscribe()
 | 
				
			||||||
 | 
					            raise error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async_scheduler = AsyncScheduler(AsyncAction)
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/cpl_reactive_extensions/scheduler/scheduler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/cpl_reactive_extensions/scheduler/scheduler.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from typing import Callable, Optional, Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T, Number
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.scheduler_action import SchedulerAction
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.scheduler_like import SchedulerLike
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.action import Action
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Scheduler(SchedulerLike):
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def _get_now(self=None) -> Number:
 | 
				
			||||||
 | 
					        return int(datetime.now().strftime("%s"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    now = _get_now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, scheduler_action_ctor: Type[Action], now=None):
 | 
				
			||||||
 | 
					        self.now = self._get_now if now is None else now
 | 
				
			||||||
 | 
					        self._scheduler_action_ctor = scheduler_action_ctor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def schedule(
 | 
				
			||||||
 | 
					        self, work: Callable[[SchedulerAction, Optional[T]], None], delay: Number, state: T = None
 | 
				
			||||||
 | 
					    ) -> Subscription:
 | 
				
			||||||
 | 
					        action = self._scheduler_action_ctor(self, work)
 | 
				
			||||||
 | 
					        x = action.schedule(state, delay)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return x
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/cpl_reactive_extensions/subject/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/cpl_reactive_extensions/subject/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					cpl-reactive-extensions CPL Simple ReactiveX implementation
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CPL Simple ReactiveX implementation, see RxJS and RxPy for detailed implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:copyright: (c) 2023 sh-edraft.de
 | 
				
			||||||
 | 
					:license: MIT, see LICENSE for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__title__ = "cpl_reactive_extensions.subject"
 | 
				
			||||||
 | 
					__author__ = "Sven Heidemann"
 | 
				
			||||||
 | 
					__license__ = "MIT"
 | 
				
			||||||
 | 
					__copyright__ = "Copyright (c) 2023 sh-edraft.de"
 | 
				
			||||||
 | 
					__version__ = "2023.4.dev170"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from collections import namedtuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# imports:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VersionInfo = namedtuple("VersionInfo", "major minor micro")
 | 
				
			||||||
 | 
					version_info = VersionInfo(major="2023", minor="4", micro="dev170")
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/cpl_reactive_extensions/subject/behavior_subject.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/cpl_reactive_extensions/subject/behavior_subject.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					from typing import Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.subject.subject import Subject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BehaviorSubject(Subject):
 | 
				
			||||||
 | 
					    def __init__(self, _t: Type[T], value: T):
 | 
				
			||||||
 | 
					        Subject.__init__(self, _t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not isinstance(value, _t):
 | 
				
			||||||
 | 
					            raise TypeError(f"Expected {_t.__name__} not {type(value).__name__}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._t = _t
 | 
				
			||||||
 | 
					        self._value = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def value(self) -> T:
 | 
				
			||||||
 | 
					        return self._value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next(self, value: T):
 | 
				
			||||||
 | 
					        super().next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._value = value
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/cpl_reactive_extensions/subject/subject.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/cpl_reactive_extensions/subject/subject.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					from types import NoneType
 | 
				
			||||||
 | 
					from typing import Any, Optional, Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import T
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Subscriber
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscription import Subscription
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Subject(Observable, Observer):
 | 
				
			||||||
 | 
					    def __init__(self, _t: Type[T]):
 | 
				
			||||||
 | 
					        Observable.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_closed = False
 | 
				
			||||||
 | 
					        self._t = _t if _t is not None else NoneType
 | 
				
			||||||
 | 
					        self._current_observers: Optional[list[Observer]] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.closed = False
 | 
				
			||||||
 | 
					        self.observers: list[Observer] = []
 | 
				
			||||||
 | 
					        self.is_stopped = False
 | 
				
			||||||
 | 
					        self.has_error = False
 | 
				
			||||||
 | 
					        self.raised_error: Any = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def observed(self) -> bool:
 | 
				
			||||||
 | 
					        return len(self.observers) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _raise_if_closed(self):
 | 
				
			||||||
 | 
					        if not self.closed:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        raise Exception("Subject is unsubscribed!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next(self, value: T):
 | 
				
			||||||
 | 
					        self._raise_if_closed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not isinstance(value, self._t):
 | 
				
			||||||
 | 
					            raise TypeError(f"Expected {self._t.__name__} not {type(value).__name__}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.is_stopped:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self._current_observers is None:
 | 
				
			||||||
 | 
					            self._current_observers = self.observers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for observer in self._current_observers:
 | 
				
			||||||
 | 
					            observer.next(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def error(self, error: Exception):
 | 
				
			||||||
 | 
					        self._raise_if_closed()
 | 
				
			||||||
 | 
					        if self.is_stopped:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_stopped = True
 | 
				
			||||||
 | 
					        self.has_error = self.is_stopped
 | 
				
			||||||
 | 
					        for observer in self.observers:
 | 
				
			||||||
 | 
					            observer.error(error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def complete(self):
 | 
				
			||||||
 | 
					        self._raise_if_closed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.is_stopped:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_stopped = True
 | 
				
			||||||
 | 
					        for observer in self.observers:
 | 
				
			||||||
 | 
					            observer.complete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unsubscribe(self):
 | 
				
			||||||
 | 
					        self.is_stopped = True
 | 
				
			||||||
 | 
					        self.is_closed = True
 | 
				
			||||||
 | 
					        self._current_observers = None
 | 
				
			||||||
 | 
					        self.observers = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _try_subscribe(self, subscriber: Subscriber):
 | 
				
			||||||
 | 
					        self._raise_if_closed()
 | 
				
			||||||
 | 
					        return super()._try_subscribe(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _subscribe(self, subscriber: Subscriber) -> Subscription:
 | 
				
			||||||
 | 
					        self._raise_if_closed()
 | 
				
			||||||
 | 
					        self._check_finalized_statuses(subscriber)
 | 
				
			||||||
 | 
					        return self._inner_subscribe(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_finalized_statuses(self, subscriber: Subscriber):
 | 
				
			||||||
 | 
					        if self.has_error:
 | 
				
			||||||
 | 
					            subscriber.error(self.raised_error)
 | 
				
			||||||
 | 
					        elif self.is_stopped:
 | 
				
			||||||
 | 
					            subscriber.complete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _inner_subscribe(self, subscriber: Subscriber) -> Optional[Subscription]:
 | 
				
			||||||
 | 
					        if self.has_error or self.is_stopped:
 | 
				
			||||||
 | 
					            return Subscription.empty()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._current_observers = None
 | 
				
			||||||
 | 
					        self.observers.append(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _initial():
 | 
				
			||||||
 | 
					            self._current_observers = None
 | 
				
			||||||
 | 
					            self.observers.remove(subscriber)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Subscription(_initial)
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/cpl_reactive_extensions/timer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/cpl_reactive_extensions/timer.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import threading
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.type import Number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Timer:
 | 
				
			||||||
 | 
					    def __init__(self, interval: Number, action: Callable, *args):
 | 
				
			||||||
 | 
					        self._interval = interval / 1000
 | 
				
			||||||
 | 
					        self._action = action
 | 
				
			||||||
 | 
					        self._args = args
 | 
				
			||||||
 | 
					        self.stop_event = threading.Event()
 | 
				
			||||||
 | 
					        thread = threading.Thread(target=self.__set_interval)
 | 
				
			||||||
 | 
					        thread.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __set_interval(self):
 | 
				
			||||||
 | 
					        next_time = time.time() + self._interval
 | 
				
			||||||
 | 
					        while not self.stop_event.wait(next_time - time.time()):
 | 
				
			||||||
 | 
					            next_time += self._interval
 | 
				
			||||||
 | 
					            self._action(*self._args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clear(self):
 | 
				
			||||||
 | 
					        self.stop_event.set()
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/cpl_reactive_extensions/type.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/cpl_reactive_extensions/type.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					from typing import Callable, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.abc.observer import Observer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ObserverOrCallable = Union[Callable, Observer]
 | 
				
			||||||
@@ -8,6 +8,7 @@ from cpl_core.dependency_injection import ServiceProviderABC
 | 
				
			|||||||
from cpl_core.logging import LoggerABC
 | 
					from cpl_core.logging import LoggerABC
 | 
				
			||||||
from cpl_core.mailing import EMailClientABC, EMail
 | 
					from cpl_core.mailing import EMailClientABC, EMail
 | 
				
			||||||
from cpl_core.pipes import IPAddressPipe
 | 
					from cpl_core.pipes import IPAddressPipe
 | 
				
			||||||
 | 
					from general.test_settings import TestSettings
 | 
				
			||||||
from test_service import TestService
 | 
					from test_service import TestService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,4 +58,13 @@ class Application(ApplicationABC):
 | 
				
			|||||||
        Console.write_line("scope", scope)
 | 
					        Console.write_line("scope", scope)
 | 
				
			||||||
        with self._services.create_scope() as s:
 | 
					        with self._services.create_scope() as s:
 | 
				
			||||||
            Console.write_line("with scope", s)
 | 
					            Console.write_line("with scope", s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_settings = self._configuration.get_configuration(TestSettings)
 | 
				
			||||||
 | 
					        Console.write_line(test_settings.value)
 | 
				
			||||||
 | 
					        Console.write_line("reload config")
 | 
				
			||||||
 | 
					        self._configuration.add_json_file(f"appsettings.json")
 | 
				
			||||||
 | 
					        self._configuration.add_json_file(f"appsettings.{self._environment.environment_name}.json")
 | 
				
			||||||
 | 
					        self._configuration.add_json_file(f"appsettings.{self._environment.host_name}.json", optional=True)
 | 
				
			||||||
 | 
					        test_settings1 = self._configuration.get_configuration(TestSettings)
 | 
				
			||||||
 | 
					        Console.write_line(test_settings1.value)
 | 
				
			||||||
        # self.test_send_mail()
 | 
					        # self.test_send_mail()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,5 +29,9 @@
 | 
				
			|||||||
    "UseUnicode": "true",
 | 
					    "UseUnicode": "true",
 | 
				
			||||||
    "Buffered": "true",
 | 
					    "Buffered": "true",
 | 
				
			||||||
    "AuthPlugin": "mysql_native_password"
 | 
					    "AuthPlugin": "mysql_native_password"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "TestSettings": {
 | 
				
			||||||
 | 
					    "Value": 20
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								tests/custom/general/src/general/test_settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/custom/general/src/general/test_settings.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					from cpl_core.configuration import ConfigurationModelABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestSettings(ConfigurationModelABC):
 | 
				
			||||||
 | 
					    def __init__(self, value: int = None):
 | 
				
			||||||
 | 
					        self.value = value
 | 
				
			||||||
@@ -16,8 +16,8 @@
 | 
				
			|||||||
    "LicenseName": "MIT",
 | 
					    "LicenseName": "MIT",
 | 
				
			||||||
    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
					    "LicenseDescription": "MIT, see LICENSE for more details.",
 | 
				
			||||||
    "Dependencies": [
 | 
					    "Dependencies": [
 | 
				
			||||||
      "cpl-core==2022.12.0",
 | 
					      "cpl-core>=2022.12.0",
 | 
				
			||||||
      "GitPython==3.1.29"
 | 
					      "GitPython>=3.1.29"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "DevDependencies": [],
 | 
					    "DevDependencies": [],
 | 
				
			||||||
    "PythonVersion": ">=3.10.4",
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ from cpl_core.dependency_injection import ServiceProviderABC
 | 
				
			|||||||
from unittests_cli.cli_test_suite import CLITestSuite
 | 
					from unittests_cli.cli_test_suite import CLITestSuite
 | 
				
			||||||
from unittests_core.core_test_suite import CoreTestSuite
 | 
					from unittests_core.core_test_suite import CoreTestSuite
 | 
				
			||||||
from unittests_query.query_test_suite import QueryTestSuite
 | 
					from unittests_query.query_test_suite import QueryTestSuite
 | 
				
			||||||
 | 
					from unittests_reactive_extenstions.reactive_test_suite import ReactiveTestSuite
 | 
				
			||||||
from unittests_translation.translation_test_suite import TranslationTestSuite
 | 
					from unittests_translation.translation_test_suite import TranslationTestSuite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,4 +22,5 @@ class Application(ApplicationABC):
 | 
				
			|||||||
        runner.run(CoreTestSuite())
 | 
					        runner.run(CoreTestSuite())
 | 
				
			||||||
        runner.run(CLITestSuite())
 | 
					        runner.run(CLITestSuite())
 | 
				
			||||||
        runner.run(QueryTestSuite())
 | 
					        runner.run(QueryTestSuite())
 | 
				
			||||||
 | 
					        runner.run(ReactiveTestSuite())
 | 
				
			||||||
        runner.run(TranslationTestSuite())
 | 
					        runner.run(TranslationTestSuite())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ from unittests_cli.constants import PLAYGROUND_PATH
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class CommandTestCase(unittest.TestCase):
 | 
					class CommandTestCase(unittest.TestCase):
 | 
				
			||||||
    _skip_tear_down = False
 | 
					    _skip_tear_down = False
 | 
				
			||||||
 | 
					    _cwd = os.getcwd()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, method_name: str):
 | 
					    def __init__(self, method_name: str):
 | 
				
			||||||
        unittest.TestCase.__init__(self, method_name)
 | 
					        unittest.TestCase.__init__(self, method_name)
 | 
				
			||||||
@@ -32,6 +33,7 @@ class CommandTestCase(unittest.TestCase):
 | 
				
			|||||||
        if cls._skip_tear_down:
 | 
					        if cls._skip_tear_down:
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
 | 
					            os.chdir(cls._cwd)
 | 
				
			||||||
            if os.path.exists(PLAYGROUND_PATH):
 | 
					            if os.path.exists(PLAYGROUND_PATH):
 | 
				
			||||||
                shutil.rmtree(os.path.abspath(os.path.join(PLAYGROUND_PATH)))
 | 
					                shutil.rmtree(os.path.abspath(os.path.join(PLAYGROUND_PATH)))
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										0
									
								
								unittests/unittests_core/configuration/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								unittests/unittests_core/configuration/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from unittest.mock import Mock, MagicMock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.configuration import Configuration, ArgumentTypeEnum
 | 
				
			||||||
 | 
					from cpl_core.database import DatabaseSettings
 | 
				
			||||||
 | 
					from cpl_core.dependency_injection import ServiceProvider, ServiceCollection
 | 
				
			||||||
 | 
					from cpl_core.mailing import EMailClientSettings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigurationTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._config = Configuration()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_env_vars(self):
 | 
				
			||||||
 | 
					        os.environ["CPLT_TESTVAR"] = "Hello World"
 | 
				
			||||||
 | 
					        os.environ["CPL_NOT_EXISTING"] = "Hello World"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.add_environment_variables("CPLT_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self._config.get_configuration("TESTVAR"), "Hello World")
 | 
				
			||||||
 | 
					        self.assertEqual(self._config.get_configuration("TESTVAR"), "Hello World")
 | 
				
			||||||
 | 
					        self.assertEqual(self._config.get_configuration("NOT_EXISTING"), None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_json_file(self):
 | 
				
			||||||
 | 
					        self._config.add_json_file("unittests_core/configuration/test-settings.json")
 | 
				
			||||||
 | 
					        db = self._config.get_configuration(DatabaseSettings)
 | 
				
			||||||
 | 
					        self.assertIsNotNone(db)
 | 
				
			||||||
 | 
					        self.assertEqual("localhost", db.host)
 | 
				
			||||||
 | 
					        self.assertEqual("local", db.user)
 | 
				
			||||||
 | 
					        self.assertEqual("bG9jYWw=", db.password)
 | 
				
			||||||
 | 
					        self.assertEqual("local", db.database)
 | 
				
			||||||
 | 
					        self.assertEqual(int, type(db.port))
 | 
				
			||||||
 | 
					        self.assertEqual(3306, db.port)
 | 
				
			||||||
 | 
					        self.assertEqual("utf8mb4", db.charset)
 | 
				
			||||||
 | 
					        self.assertTrue(db.use_unicode)
 | 
				
			||||||
 | 
					        self.assertTrue(db.buffered)
 | 
				
			||||||
 | 
					        self.assertEqual("mysql_native_password", db.auth_plugin)
 | 
				
			||||||
 | 
					        self.assertIsNone(self._config.get_configuration(EMailClientSettings))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_config(self):
 | 
				
			||||||
 | 
					        self.assertIsNone(self._config.get_configuration("Test"))
 | 
				
			||||||
 | 
					        self._config.add_configuration("Test", "Hello World")
 | 
				
			||||||
 | 
					        self.assertIsNotNone(self._config.get_configuration("Test"))
 | 
				
			||||||
 | 
					        self.assertEqual("Hello World", self._config.get_configuration("Test"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_console_argument(self):
 | 
				
			||||||
 | 
					        sc = ServiceCollection(self._config)
 | 
				
			||||||
 | 
					        self.assertEqual([], sys.argv[1:])
 | 
				
			||||||
 | 
					        sys.argv.append("flag")
 | 
				
			||||||
 | 
					        sys.argv.append("exec")
 | 
				
			||||||
 | 
					        sys.argv.append("var=test")
 | 
				
			||||||
 | 
					        self.assertNotEqual([], sys.argv[1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Flag, "", "flag", [])
 | 
				
			||||||
 | 
					        mocked_exec = Mock()
 | 
				
			||||||
 | 
					        mocked_exec.run = MagicMock()
 | 
				
			||||||
 | 
					        sc.add_transient(mocked_exec)
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Executable, "", "exec", [], Mock)
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Variable, "", "var", [], "=")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNone(self._config.get_configuration("var"))
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(sc.build_service_provider())
 | 
				
			||||||
 | 
					        mocked_exec.run.assert_called()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual("test", self._config.get_configuration("var"))
 | 
				
			||||||
 | 
					        self.assertIn("flag", self._config.additional_arguments)
 | 
				
			||||||
@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from unittest.mock import Mock, MagicMock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.configuration import Configuration, ArgumentTypeEnum
 | 
				
			||||||
 | 
					from cpl_core.dependency_injection import ServiceCollection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConsoleArgumentsTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._config = Configuration()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Flag, "", "flag", [])
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Variable, "", "var", [], "=")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.create_console_argument(ArgumentTypeEnum.Executable, "", "exec", [], Mock).add_console_argument(
 | 
				
			||||||
 | 
					            ArgumentTypeEnum.Flag, "--", "dev", ["d", "D"]
 | 
				
			||||||
 | 
					        ).add_console_argument(ArgumentTypeEnum.Flag, "--", "virtual", ["v", "V"]).add_console_argument(
 | 
				
			||||||
 | 
					            ArgumentTypeEnum.Variable, "", "var1", [], "="
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.for_each_argument(
 | 
				
			||||||
 | 
					            lambda a: a.add_console_argument(ArgumentTypeEnum.Flag, "--", "help", ["h", "H"])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._sc = ServiceCollection(self._config)
 | 
				
			||||||
 | 
					        self._mocked_exec = Mock()
 | 
				
			||||||
 | 
					        self._mocked_exec.run = MagicMock()
 | 
				
			||||||
 | 
					        self._sc.add_transient(self._mocked_exec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_flag(self):
 | 
				
			||||||
 | 
					        sys.argv.append("flag")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self.assertIn("flag", self._config.additional_arguments)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_var(self):
 | 
				
			||||||
 | 
					        sys.argv.append("var=1")
 | 
				
			||||||
 | 
					        sys.argv.append("var2=1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self.assertEqual("1", self._config.get_configuration("var"))
 | 
				
			||||||
 | 
					        self.assertIsNone(self._config.get_configuration("var1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_exec(self):
 | 
				
			||||||
 | 
					        sys.argv.append("exec")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self._mocked_exec.run.assert_called()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_exec_with_one_flag(self):
 | 
				
			||||||
 | 
					        sys.argv.append("exec")
 | 
				
			||||||
 | 
					        sys.argv.append("--dev")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self._mocked_exec.run.assert_called()
 | 
				
			||||||
 | 
					        self.assertIn("dev", self._config.additional_arguments)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_exec_with_one_flag_alias(self):
 | 
				
			||||||
 | 
					        sys.argv.append("exec")
 | 
				
			||||||
 | 
					        sys.argv.append("--d")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self._mocked_exec.run.assert_called()
 | 
				
			||||||
 | 
					        self.assertIn("dev", self._config.additional_arguments)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_exec_with_two_flags(self):
 | 
				
			||||||
 | 
					        sys.argv.append("exec")
 | 
				
			||||||
 | 
					        sys.argv.append("--dev")
 | 
				
			||||||
 | 
					        sys.argv.append("--virtual")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.parse_console_arguments(self._sc.build_service_provider())
 | 
				
			||||||
 | 
					        self._mocked_exec.run.assert_called()
 | 
				
			||||||
 | 
					        self.assertIn("dev", self._config.additional_arguments)
 | 
				
			||||||
 | 
					        self.assertIn("virtual", self._config.additional_arguments)
 | 
				
			||||||
@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from _socket import gethostname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.configuration import Configuration
 | 
				
			||||||
 | 
					from cpl_core.environment import ApplicationEnvironment, ApplicationEnvironmentABC
 | 
				
			||||||
 | 
					from cpl_core.environment import application_environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EnvironmentTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._config = Configuration()
 | 
				
			||||||
 | 
					        self._env = self._config.environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_app_env_created(self):
 | 
				
			||||||
 | 
					        self.assertTrue(isinstance(self._env, ApplicationEnvironment))
 | 
				
			||||||
 | 
					        self.assertTrue(issubclass(type(self._env), ApplicationEnvironmentABC))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_app_env_values_correct_when_default(self):
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.environment_name, "production")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.application_name, "")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.customer, "")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.host_name, gethostname())
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.working_directory, os.getcwd())
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            self._env.runtime_directory,
 | 
				
			||||||
 | 
					            os.path.dirname(os.path.dirname(os.path.abspath(application_environment.__file__))),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_app_env_values_correct_when_read_from_env(self):
 | 
				
			||||||
 | 
					        os.environ["CPLT_ENVIRONMENT"] = "development"
 | 
				
			||||||
 | 
					        os.environ["CPLT_NAME"] = "Core Tests"
 | 
				
			||||||
 | 
					        os.environ["CPLT_CUSTOMER"] = "sh-edraft.de"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._config.add_environment_variables("CPLT_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.environment_name, "development")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.application_name, "Core Tests")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.customer, "sh-edraft.de")
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.host_name, gethostname())
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.working_directory, os.getcwd())
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            self._env.runtime_directory,
 | 
				
			||||||
 | 
					            os.path.dirname(os.path.dirname(os.path.abspath(application_environment.__file__))),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_app_env_set_dirs(self):
 | 
				
			||||||
 | 
					        new_cwd = os.path.join(os.getcwd(), "../")
 | 
				
			||||||
 | 
					        self._env.set_working_directory(new_cwd)
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.working_directory, new_cwd)
 | 
				
			||||||
 | 
					        self._env.set_runtime_directory(new_cwd)
 | 
				
			||||||
 | 
					        self.assertEqual(self._env.runtime_directory, new_cwd)
 | 
				
			||||||
							
								
								
									
										25
									
								
								unittests/unittests_core/configuration/test-settings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								unittests/unittests_core/configuration/test-settings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "TimeFormatSettings": {
 | 
				
			||||||
 | 
					    "DateFormat": "%Y-%m-%d",
 | 
				
			||||||
 | 
					    "TimeFormat": "%H:%M:%S",
 | 
				
			||||||
 | 
					    "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
 | 
				
			||||||
 | 
					    "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "LoggingSettings": {
 | 
				
			||||||
 | 
					    "Path": "logs/$date_now/",
 | 
				
			||||||
 | 
					    "Filename": "bot.log",
 | 
				
			||||||
 | 
					    "ConsoleLogLevel": "TRACE",
 | 
				
			||||||
 | 
					    "FileLogLevel": "TRACE"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "DatabaseSettings": {
 | 
				
			||||||
 | 
					    "Host": "localhost",
 | 
				
			||||||
 | 
					    "User": "local",
 | 
				
			||||||
 | 
					    "Password": "bG9jYWw=",
 | 
				
			||||||
 | 
					    "Database": "local",
 | 
				
			||||||
 | 
					    "Port": "3306",
 | 
				
			||||||
 | 
					    "Charset": "utf8mb4",
 | 
				
			||||||
 | 
					    "UseUnicode": "true",
 | 
				
			||||||
 | 
					    "Buffered": "true",
 | 
				
			||||||
 | 
					    "AuthPlugin": "mysql_native_password"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,10 @@
 | 
				
			|||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from unittests_core.configuration.console_arguments_test_case import ConsoleArgumentsTestCase
 | 
				
			||||||
 | 
					from unittests_core.configuration.configuration_test_case import ConfigurationTestCase
 | 
				
			||||||
 | 
					from unittests_core.configuration.environment_test_case import EnvironmentTestCase
 | 
				
			||||||
 | 
					from unittests_core.di.service_collection_test_case import ServiceCollectionTestCase
 | 
				
			||||||
 | 
					from unittests_core.di.service_provider_test_case import ServiceProviderTestCase
 | 
				
			||||||
from unittests_core.pipes.bool_pipe_test_case import BoolPipeTestCase
 | 
					from unittests_core.pipes.bool_pipe_test_case import BoolPipeTestCase
 | 
				
			||||||
from unittests_core.pipes.ip_address_pipe_test_case import IPAddressTestCase
 | 
					from unittests_core.pipes.ip_address_pipe_test_case import IPAddressTestCase
 | 
				
			||||||
from unittests_core.pipes.version_pipe_test_case import VersionPipeTestCase
 | 
					from unittests_core.pipes.version_pipe_test_case import VersionPipeTestCase
 | 
				
			||||||
@@ -14,6 +19,13 @@ class CoreTestSuite(unittest.TestSuite):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        loader = unittest.TestLoader()
 | 
					        loader = unittest.TestLoader()
 | 
				
			||||||
        tests = [
 | 
					        tests = [
 | 
				
			||||||
 | 
					            # config
 | 
				
			||||||
 | 
					            ConfigurationTestCase,
 | 
				
			||||||
 | 
					            ConsoleArgumentsTestCase,
 | 
				
			||||||
 | 
					            EnvironmentTestCase,
 | 
				
			||||||
 | 
					            # di
 | 
				
			||||||
 | 
					            ServiceCollectionTestCase,
 | 
				
			||||||
 | 
					            ServiceProviderTestCase,
 | 
				
			||||||
            # pipes
 | 
					            # pipes
 | 
				
			||||||
            BoolPipeTestCase,
 | 
					            BoolPipeTestCase,
 | 
				
			||||||
            IPAddressTestCase,
 | 
					            IPAddressTestCase,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										0
									
								
								unittests/unittests_core/di/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								unittests/unittests_core/di/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										56
									
								
								unittests/unittests_core/di/service_collection_test_case.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								unittests/unittests_core/di/service_collection_test_case.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from unittest.mock import Mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.configuration import Configuration
 | 
				
			||||||
 | 
					from cpl_core.dependency_injection import ServiceCollection, ServiceLifetimeEnum, ServiceProviderABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ServiceCollectionTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._sc = ServiceCollection(Configuration())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_singleton_type(self):
 | 
				
			||||||
 | 
					        self._sc.add_singleton(Mock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service = self._sc._service_descriptors[0]
 | 
				
			||||||
 | 
					        self.assertEqual(ServiceLifetimeEnum.singleton, service.lifetime)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.service_type)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.base_type)
 | 
				
			||||||
 | 
					        self.assertIsNone(service.implementation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_singleton_instance(self):
 | 
				
			||||||
 | 
					        mock = Mock()
 | 
				
			||||||
 | 
					        self._sc.add_singleton(mock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service = self._sc._service_descriptors[0]
 | 
				
			||||||
 | 
					        self.assertEqual(ServiceLifetimeEnum.singleton, service.lifetime)
 | 
				
			||||||
 | 
					        self.assertEqual(type(mock), service.service_type)
 | 
				
			||||||
 | 
					        self.assertEqual(type(mock), service.base_type)
 | 
				
			||||||
 | 
					        self.assertIsNotNone(service.implementation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_transient_type(self):
 | 
				
			||||||
 | 
					        self._sc.add_transient(Mock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service = self._sc._service_descriptors[0]
 | 
				
			||||||
 | 
					        self.assertEqual(ServiceLifetimeEnum.transient, service.lifetime)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.service_type)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.base_type)
 | 
				
			||||||
 | 
					        self.assertIsNone(service.implementation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_add_scoped_type(self):
 | 
				
			||||||
 | 
					        self._sc.add_scoped(Mock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service = self._sc._service_descriptors[0]
 | 
				
			||||||
 | 
					        self.assertEqual(ServiceLifetimeEnum.scoped, service.lifetime)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.service_type)
 | 
				
			||||||
 | 
					        self.assertEqual(Mock, service.base_type)
 | 
				
			||||||
 | 
					        self.assertIsNone(service.implementation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_build_service_provider(self):
 | 
				
			||||||
 | 
					        self._sc.add_singleton(Mock)
 | 
				
			||||||
 | 
					        service = self._sc._service_descriptors[0]
 | 
				
			||||||
 | 
					        self.assertIsNone(service.implementation)
 | 
				
			||||||
 | 
					        sp = self._sc.build_service_provider()
 | 
				
			||||||
 | 
					        self.assertTrue(isinstance(sp, ServiceProviderABC))
 | 
				
			||||||
 | 
					        self.assertTrue(isinstance(sp.get_service(Mock), Mock))
 | 
				
			||||||
 | 
					        self.assertIsNotNone(service.implementation)
 | 
				
			||||||
							
								
								
									
										98
									
								
								unittests/unittests_core/di/service_provider_test_case.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								unittests/unittests_core/di/service_provider_test_case.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.configuration import Configuration
 | 
				
			||||||
 | 
					from cpl_core.dependency_injection import ServiceCollection, ServiceProviderABC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ServiceCount:
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.count = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestService:
 | 
				
			||||||
 | 
					    def __init__(self, sp: ServiceProviderABC, count: ServiceCount):
 | 
				
			||||||
 | 
					        count.count += 1
 | 
				
			||||||
 | 
					        self.sp = sp
 | 
				
			||||||
 | 
					        self.id = count.count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DifferentService:
 | 
				
			||||||
 | 
					    def __init__(self, sp: ServiceProviderABC, count: ServiceCount):
 | 
				
			||||||
 | 
					        count.count += 1
 | 
				
			||||||
 | 
					        self.sp = sp
 | 
				
			||||||
 | 
					        self.id = count.count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MoreDifferentService:
 | 
				
			||||||
 | 
					    def __init__(self, sp: ServiceProviderABC, count: ServiceCount):
 | 
				
			||||||
 | 
					        count.count += 1
 | 
				
			||||||
 | 
					        self.sp = sp
 | 
				
			||||||
 | 
					        self.id = count.count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ServiceProviderTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._services = (
 | 
				
			||||||
 | 
					            ServiceCollection(Configuration())
 | 
				
			||||||
 | 
					            .add_singleton(ServiceCount)
 | 
				
			||||||
 | 
					            .add_singleton(TestService)
 | 
				
			||||||
 | 
					            .add_singleton(TestService)
 | 
				
			||||||
 | 
					            .add_transient(DifferentService)
 | 
				
			||||||
 | 
					            .add_scoped(MoreDifferentService)
 | 
				
			||||||
 | 
					            .build_service_provider()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        count = self._services.get_service(ServiceCount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_singleton(self):
 | 
				
			||||||
 | 
					        x = self._services.get_service(TestService)
 | 
				
			||||||
 | 
					        self.assertIsNotNone(x)
 | 
				
			||||||
 | 
					        self.assertEqual(1, x.id)
 | 
				
			||||||
 | 
					        self.assertEqual(x, self._services.get_service(TestService))
 | 
				
			||||||
 | 
					        self.assertEqual(x, self._services.get_service(TestService))
 | 
				
			||||||
 | 
					        self.assertEqual(x, self._services.get_service(TestService))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_singletons(self):
 | 
				
			||||||
 | 
					        x = self._services.get_services(list[TestService])
 | 
				
			||||||
 | 
					        self.assertEqual(2, len(x))
 | 
				
			||||||
 | 
					        self.assertEqual(1, x[0].id)
 | 
				
			||||||
 | 
					        self.assertEqual(2, x[1].id)
 | 
				
			||||||
 | 
					        self.assertNotEqual(x[0], x[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_transient(self):
 | 
				
			||||||
 | 
					        x = self._services.get_service(DifferentService)
 | 
				
			||||||
 | 
					        self.assertIsNotNone(x)
 | 
				
			||||||
 | 
					        self.assertEqual(1, x.id)
 | 
				
			||||||
 | 
					        self.assertNotEqual(x, self._services.get_service(DifferentService))
 | 
				
			||||||
 | 
					        self.assertNotEqual(x, self._services.get_service(DifferentService))
 | 
				
			||||||
 | 
					        self.assertNotEqual(x, self._services.get_service(DifferentService))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_scoped(self):
 | 
				
			||||||
 | 
					        scoped_id = 0
 | 
				
			||||||
 | 
					        singleton = self._services.get_service(TestService)
 | 
				
			||||||
 | 
					        transient = self._services.get_service(DifferentService)
 | 
				
			||||||
 | 
					        with self._services.create_scope() as scope:
 | 
				
			||||||
 | 
					            sp: ServiceProviderABC = scope.service_provider
 | 
				
			||||||
 | 
					            self.assertNotEqual(sp, self._services)
 | 
				
			||||||
 | 
					            y = sp.get_service(DifferentService)
 | 
				
			||||||
 | 
					            self.assertIsNotNone(y)
 | 
				
			||||||
 | 
					            self.assertEqual(3, y.id)
 | 
				
			||||||
 | 
					            x = sp.get_service(MoreDifferentService)
 | 
				
			||||||
 | 
					            self.assertIsNotNone(x)
 | 
				
			||||||
 | 
					            self.assertEqual(4, x.id)
 | 
				
			||||||
 | 
					            scoped_id = 4
 | 
				
			||||||
 | 
					            self.assertEqual(singleton.sp, self._services)
 | 
				
			||||||
 | 
					            self.assertEqual(transient.sp, self._services)
 | 
				
			||||||
 | 
					            self.assertEqual(x.sp, sp)
 | 
				
			||||||
 | 
					            self.assertNotEqual(x.sp, singleton.sp)
 | 
				
			||||||
 | 
					            transient_in_scope = sp.get_service(DifferentService)
 | 
				
			||||||
 | 
					            self.assertEqual(transient_in_scope.sp, sp)
 | 
				
			||||||
 | 
					            self.assertNotEqual(transient.sp, transient_in_scope.sp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.assertEqual(x.id, sp.get_service(MoreDifferentService).id)
 | 
				
			||||||
 | 
					            self.assertEqual(x.id, sp.get_service(MoreDifferentService).id)
 | 
				
			||||||
 | 
					            self.assertNotEqual(x, self._services.get_service(MoreDifferentService))
 | 
				
			||||||
 | 
					            self.assertEqual(singleton, self._services.get_service(TestService))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNone(scope.service_provider)
 | 
				
			||||||
 | 
					        self.assertNotEqual(scoped_id, self._services.get_service(MoreDifferentService).id)
 | 
				
			||||||
@@ -26,7 +26,7 @@ class JSONProcessorTestCase(unittest.TestCase):
 | 
				
			|||||||
            "i": 10,
 | 
					            "i": 10,
 | 
				
			||||||
            "s": "Hello World",
 | 
					            "s": "Hello World",
 | 
				
			||||||
            "d": {"test": "Test"},
 | 
					            "d": {"test": "Test"},
 | 
				
			||||||
            "l": range(0, 11),
 | 
					            "l": list(range(0, 11)),
 | 
				
			||||||
            "value": {"value": "Hello World"},
 | 
					            "value": {"value": "Hello World"},
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        test: TestClass = JSONProcessor.process(TestClass, test_dict)
 | 
					        test: TestClass = JSONProcessor.process(TestClass, test_dict)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ class StringTestCase(unittest.TestCase):
 | 
				
			|||||||
        expected = "HelloWorld"
 | 
					        expected = "HelloWorld"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(expected, String.convert_to_camel_case("hello-world"))
 | 
					        self.assertEqual(expected, String.convert_to_camel_case("hello-world"))
 | 
				
			||||||
 | 
					        self.assertEqual(expected, String.convert_to_camel_case("hello-World"))
 | 
				
			||||||
        self.assertEqual(expected, String.convert_to_camel_case("hello_world"))
 | 
					        self.assertEqual(expected, String.convert_to_camel_case("hello_world"))
 | 
				
			||||||
        self.assertEqual("helloWorld", String.convert_to_camel_case("helloWorld"))
 | 
					        self.assertEqual("helloWorld", String.convert_to_camel_case("helloWorld"))
 | 
				
			||||||
        self.assertEqual(expected, String.convert_to_camel_case("Hello_world"))
 | 
					        self.assertEqual(expected, String.convert_to_camel_case("Hello_world"))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								unittests/unittests_reactive_extenstions/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								unittests/unittests_reactive_extenstions/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					# imports
 | 
				
			||||||
@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					import time
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.console import Console
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.operators.debounce_time import debounce_time
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.subject.subject import Subject
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.interval import Interval
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.operators.take import take
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.operators.take_until import take_until
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ObservableOperatorTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._error = False
 | 
				
			||||||
 | 
					        self._completed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _on_error(self, ex: Exception):
 | 
				
			||||||
 | 
					        tb = traceback.format_exc()
 | 
				
			||||||
 | 
					        Console.error(f"Got error from observable: {ex}", tb)
 | 
				
			||||||
 | 
					        self._error = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _on_complete(self):
 | 
				
			||||||
 | 
					        self._completed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_take_two(self):
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def sub(x):
 | 
				
			||||||
 | 
					            nonlocal count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Interval(0.1)
 | 
				
			||||||
 | 
					        sub = observable.pipe(take(2)).subscribe(sub)
 | 
				
			||||||
 | 
					        time.sleep(0.5)
 | 
				
			||||||
 | 
					        self.assertEqual(count, 2)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_take_five(self):
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def sub(x):
 | 
				
			||||||
 | 
					            nonlocal count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Interval(0.1)
 | 
				
			||||||
 | 
					        sub = observable.pipe(take(5)).subscribe(sub)
 | 
				
			||||||
 | 
					        time.sleep(1)
 | 
				
			||||||
 | 
					        self.assertEqual(count, 5)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_take_until(self):
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					        unsubscriber = Subject(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def sub(x):
 | 
				
			||||||
 | 
					            nonlocal count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Interval(0.1)
 | 
				
			||||||
 | 
					        observable.pipe(take_until(unsubscriber)).subscribe(sub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        timer = 2
 | 
				
			||||||
 | 
					        time.sleep(timer)
 | 
				
			||||||
 | 
					        unsubscriber.next(None)
 | 
				
			||||||
 | 
					        unsubscriber.complete()
 | 
				
			||||||
 | 
					        self.assertEqual(count, timer * 10 - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # def test_debounce_time(self):
 | 
				
			||||||
 | 
					    #     def call(x):
 | 
				
			||||||
 | 
					    #         x.next(1)
 | 
				
			||||||
 | 
					    #         x.next(2)
 | 
				
			||||||
 | 
					    #         x.next(3)
 | 
				
			||||||
 | 
					    #         x.next(4)
 | 
				
			||||||
 | 
					    #         x.next(5)
 | 
				
			||||||
 | 
					    #         x.next(6)
 | 
				
			||||||
 | 
					    #         x.complete()
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #     observable = Observable(call)
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #     sub = observable.pipe(debounce_time(600)).subscribe(lambda x: Console.write_line("Hey", x))
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #     time.sleep(2)
 | 
				
			||||||
 | 
					    #     sub.unsubscribe()
 | 
				
			||||||
							
								
								
									
										176
									
								
								unittests/unittests_reactive_extenstions/reactive_test_case.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								unittests/unittests_reactive_extenstions/reactive_test_case.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					import time
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from threading import Timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.console import Console
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.subject.behavior_subject import BehaviorSubject
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.interval import Interval
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.observable import Observable
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.subject.subject import Subject
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.internal.subscriber import Observer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReactiveTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._error = False
 | 
				
			||||||
 | 
					        self._completed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _on_error(self, ex: Exception):
 | 
				
			||||||
 | 
					        tb = traceback.format_exc()
 | 
				
			||||||
 | 
					        Console.error(f"Got error from observable: {ex}", tb)
 | 
				
			||||||
 | 
					        self._error = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _on_complete(self):
 | 
				
			||||||
 | 
					        self._completed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_observer(self):
 | 
				
			||||||
 | 
					        called = 0
 | 
				
			||||||
 | 
					        test_x = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def callback(observer: Observer):
 | 
				
			||||||
 | 
					            nonlocal test_x
 | 
				
			||||||
 | 
					            observer.next(test_x)
 | 
				
			||||||
 | 
					            test_x += 1
 | 
				
			||||||
 | 
					            observer.next(test_x)
 | 
				
			||||||
 | 
					            test_x += 1
 | 
				
			||||||
 | 
					            observer.next(test_x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            def complete():
 | 
				
			||||||
 | 
					                nonlocal test_x
 | 
				
			||||||
 | 
					                test_x += 1
 | 
				
			||||||
 | 
					                observer.next(test_x)
 | 
				
			||||||
 | 
					                observer.complete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Timer(1.0, complete).start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Observable(callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def on_next(x):
 | 
				
			||||||
 | 
					            nonlocal called
 | 
				
			||||||
 | 
					            called += 1
 | 
				
			||||||
 | 
					            self.assertEqual(test_x, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(called, 0)
 | 
				
			||||||
 | 
					        self.assertFalse(self._error)
 | 
				
			||||||
 | 
					        self.assertFalse(self._completed)
 | 
				
			||||||
 | 
					        observable.subscribe(
 | 
				
			||||||
 | 
					            on_next,
 | 
				
			||||||
 | 
					            self._on_error,
 | 
				
			||||||
 | 
					            self._on_complete,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(called, 3)
 | 
				
			||||||
 | 
					        self.assertFalse(self._error)
 | 
				
			||||||
 | 
					        self.assertFalse(self._completed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def complete():
 | 
				
			||||||
 | 
					            self.assertEqual(called, 4)
 | 
				
			||||||
 | 
					            self.assertFalse(self._error)
 | 
				
			||||||
 | 
					            self.assertTrue(self._completed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Timer(1.0, complete).start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_observer_completed(self):
 | 
				
			||||||
 | 
					        def _test_complete(x: Observer):
 | 
				
			||||||
 | 
					            x.next(1)
 | 
				
			||||||
 | 
					            x.next(2)
 | 
				
			||||||
 | 
					            x.complete()
 | 
				
			||||||
 | 
					            x.next(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Observable(_test_complete)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable.subscribe(lambda x: Console.write_line(1, x), self._on_error)
 | 
				
			||||||
 | 
					        self.assertTrue(self._error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_observable_from(self):
 | 
				
			||||||
 | 
					        expected_x = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _next(x):
 | 
				
			||||||
 | 
					            nonlocal expected_x
 | 
				
			||||||
 | 
					            self.assertEqual(expected_x, x)
 | 
				
			||||||
 | 
					            expected_x += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Observable.from_list([1, 2, 3, 4])
 | 
				
			||||||
 | 
					        sub = observable.subscribe(
 | 
				
			||||||
 | 
					            _next,
 | 
				
			||||||
 | 
					            self._on_error,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertFalse(self._error)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_subject(self):
 | 
				
			||||||
 | 
					        expected_x = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _next(calc, x):
 | 
				
			||||||
 | 
					            nonlocal expected_x
 | 
				
			||||||
 | 
					            self.assertEqual(expected_x, x)
 | 
				
			||||||
 | 
					            if not calc:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            expected_x += 1
 | 
				
			||||||
 | 
					            if expected_x == 4:
 | 
				
			||||||
 | 
					                expected_x = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subject = Subject(int)
 | 
				
			||||||
 | 
					        subject.subscribe(lambda x: _next(False, x), self._on_error)
 | 
				
			||||||
 | 
					        subject.subscribe(lambda x: _next(True, x), self._on_error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Observable.from_list([1, 2, 3])
 | 
				
			||||||
 | 
					        sub = observable.subscribe(subject, self._on_error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertFalse(self._error)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_behavior_subject(self):
 | 
				
			||||||
 | 
					        subject = BehaviorSubject(int, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subject.subscribe(lambda x: Console.write_line("a", x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subject.next(1)
 | 
				
			||||||
 | 
					        subject.next(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subject.subscribe(lambda x: Console.write_line("b", x))
 | 
				
			||||||
 | 
					        subject.next(3)
 | 
				
			||||||
 | 
					        subject.unsubscribe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_interval_default(self):
 | 
				
			||||||
 | 
					        wait = 10
 | 
				
			||||||
 | 
					        i = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def test_sub(x):
 | 
				
			||||||
 | 
					            nonlocal i
 | 
				
			||||||
 | 
					            self.assertEqual(x, i)
 | 
				
			||||||
 | 
					            i += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Interval(1.0)
 | 
				
			||||||
 | 
					        sub = observable.subscribe(test_sub)
 | 
				
			||||||
 | 
					        start = datetime.now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        time.sleep(wait)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					        end = datetime.now()
 | 
				
			||||||
 | 
					        self.assertEqual(round((end - start).total_seconds()), wait)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_interval_custom(self):
 | 
				
			||||||
 | 
					        wait = 10
 | 
				
			||||||
 | 
					        i = 0
 | 
				
			||||||
 | 
					        n = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def callback(x: Observer):
 | 
				
			||||||
 | 
					            nonlocal n
 | 
				
			||||||
 | 
					            x.next(n)
 | 
				
			||||||
 | 
					            n += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def test_sub(x):
 | 
				
			||||||
 | 
					            nonlocal i
 | 
				
			||||||
 | 
					            self.assertEqual(x, i)
 | 
				
			||||||
 | 
					            i += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        observable = Interval(1.0, callback)
 | 
				
			||||||
 | 
					        sub = observable.subscribe(test_sub)
 | 
				
			||||||
 | 
					        start = datetime.now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        time.sleep(wait)
 | 
				
			||||||
 | 
					        sub.unsubscribe()
 | 
				
			||||||
 | 
					        end = datetime.now()
 | 
				
			||||||
 | 
					        self.assertEqual(round((end - start).total_seconds()), wait)
 | 
				
			||||||
@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from unittests_reactive_extenstions.observable_operator_test_case import ObservableOperatorTestCase
 | 
				
			||||||
 | 
					from unittests_reactive_extenstions.reactive_test_case import ReactiveTestCase
 | 
				
			||||||
 | 
					from unittests_reactive_extenstions.scheduler_test_case import SchedulerTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReactiveTestSuite(unittest.TestSuite):
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        unittest.TestSuite.__init__(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        loader = unittest.TestLoader()
 | 
				
			||||||
 | 
					        self.addTests(loader.loadTestsFromTestCase(ReactiveTestCase))
 | 
				
			||||||
 | 
					        self.addTests(loader.loadTestsFromTestCase(ObservableOperatorTestCase))
 | 
				
			||||||
 | 
					        self.addTests(loader.loadTestsFromTestCase(SchedulerTestCase))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self, *args):
 | 
				
			||||||
 | 
					        super().run(*args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    runner = unittest.TextTestRunner()
 | 
				
			||||||
 | 
					    runner.run(ReactiveTestSuite())
 | 
				
			||||||
@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import time
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.console import Console
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.timer import Timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SchedulerTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_timer(self):
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def task():
 | 
				
			||||||
 | 
					            nonlocal count
 | 
				
			||||||
 | 
					            Console.write_line(datetime.now(), "Hello world")
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        timer = Timer(100, task)
 | 
				
			||||||
 | 
					        time.sleep(0.25)
 | 
				
			||||||
 | 
					        self.assertEqual(count, 2)
 | 
				
			||||||
 | 
					        timer.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_schedule(self):
 | 
				
			||||||
 | 
					        count = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def task():
 | 
				
			||||||
 | 
					            nonlocal count
 | 
				
			||||||
 | 
					            Console.write_line(datetime.now(), "Hello world")
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # async_scheduler.schedule(task, 100)
 | 
				
			||||||
 | 
					        time.sleep(2)
 | 
				
			||||||
							
								
								
									
										21
									
								
								unittests/unittests_reactive_extenstions/test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								unittests/unittests_reactive_extenstions/test.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import time
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from cpl_core.console import Console
 | 
				
			||||||
 | 
					from cpl_reactive_extensions.timer import Timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_timer():
 | 
				
			||||||
 | 
					    is_working = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def task():
 | 
				
			||||||
 | 
					        nonlocal is_working
 | 
				
			||||||
 | 
					        Console.write_line(datetime.now(), "Hello world")
 | 
				
			||||||
 | 
					        is_working = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer = Timer(100, task)
 | 
				
			||||||
 | 
					    time.sleep(0.2)
 | 
				
			||||||
 | 
					    timer.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_timer()
 | 
				
			||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "ProjectSettings": {
 | 
				
			||||||
 | 
					    "Name": "unittests_reactive_extenstions",
 | 
				
			||||||
 | 
					    "Version": {
 | 
				
			||||||
 | 
					      "Major": "2023",
 | 
				
			||||||
 | 
					      "Minor": "4",
 | 
				
			||||||
 | 
					      "Micro": "dev170"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Author": "",
 | 
				
			||||||
 | 
					    "AuthorEmail": "",
 | 
				
			||||||
 | 
					    "Description": "",
 | 
				
			||||||
 | 
					    "LongDescription": "",
 | 
				
			||||||
 | 
					    "URL": "",
 | 
				
			||||||
 | 
					    "CopyrightDate": "",
 | 
				
			||||||
 | 
					    "CopyrightName": "",
 | 
				
			||||||
 | 
					    "LicenseName": "",
 | 
				
			||||||
 | 
					    "LicenseDescription": "",
 | 
				
			||||||
 | 
					    "Dependencies": [
 | 
				
			||||||
 | 
					      "cpl-core>=2023.4.dev170"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "DevDependencies": [
 | 
				
			||||||
 | 
					      "cpl-cli>=2023.4.0"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "PythonVersion": ">=3.10.4",
 | 
				
			||||||
 | 
					    "PythonPath": {
 | 
				
			||||||
 | 
					      "linux": ""
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Classifiers": []
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "BuildSettings": {
 | 
				
			||||||
 | 
					    "ProjectType": "unittest",
 | 
				
			||||||
 | 
					    "SourcePath": "",
 | 
				
			||||||
 | 
					    "OutputPath": "../../dist",
 | 
				
			||||||
 | 
					    "Main": "unittests_reactive_extenstions.main",
 | 
				
			||||||
 | 
					    "EntryPoint": "unittests_reactive_extenstions",
 | 
				
			||||||
 | 
					    "IncludePackageData": false,
 | 
				
			||||||
 | 
					    "Included": [],
 | 
				
			||||||
 | 
					    "Excluded": [
 | 
				
			||||||
 | 
					      "*/__pycache__",
 | 
				
			||||||
 | 
					      "*/logs",
 | 
				
			||||||
 | 
					      "*/tests"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "PackageData": {},
 | 
				
			||||||
 | 
					    "ProjectReferences": []
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user