From d1c93abe2ca8bcc6b42be376eb68bdf8d76749da Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 5 Dec 2022 19:57:27 +0100 Subject: [PATCH] Improved cpl g templating & added custom templating #137 --- src/cpl_cli/.cpl/__init__.py | 0 src/cpl_cli/.cpl/abc_schematic.py | 30 ++++ src/cpl_cli/.cpl/class_schematic.py | 28 ++++ src/cpl_cli/.cpl/configmodel_schematic.py | 46 ++++++ src/cpl_cli/.cpl/enum_schematic.py | 29 ++++ src/cpl_cli/.cpl/init_schematic.py | 25 ++++ src/cpl_cli/.cpl/pipe_schematic.py | 32 ++++ src/cpl_cli/.cpl/service_schematic.py | 27 ++++ src/cpl_cli/.cpl/test_case_schematic.py | 33 +++++ src/cpl_cli/.cpl/thread_schematic.py | 33 +++++ src/cpl_cli/.cpl/validator_schematic.py | 33 +++++ src/cpl_cli/_templates/generate/__init__.py | 26 ---- .../_templates/generate/abc_template.py | 44 ------ .../_templates/generate/class_template.py | 35 ----- .../generate/configmodel_template.py | 60 -------- .../_templates/generate/enum_template.py | 43 ------ .../_templates/generate/init_template.py | 35 ----- .../_templates/generate/pipe_template.py | 46 ------ .../_templates/generate/service_template.py | 41 ------ .../_templates/generate/test_case_template.py | 47 ------ .../_templates/generate/thread_template.py | 47 ------ .../_templates/generate/validator_template.py | 47 ------ src/cpl_cli/abc/__init__.py | 1 + src/cpl_cli/abc/file_template_abc.py | 28 ++++ src/cpl_cli/abc/generate_schematic_abc.py | 37 +++++ src/cpl_cli/command/generate_service.py | 139 +++++++++++------- .../configuration/schematic_collection.py | 16 ++ src/cpl_cli/startup_argument_extension.py | 20 +-- src/cpl_cli/test_enum.py | 1 + src/cpl_cli/test_init.py | 1 + tests/custom/general/.cpl/custom_schematic.py | 27 ++++ tests/custom/general/test/__init__.py | 1 + tests/custom/general/test/custom.py | 4 + unittests/unittests_cli/generate_test_case.py | 4 +- 34 files changed, 527 insertions(+), 539 deletions(-) create mode 100644 src/cpl_cli/.cpl/__init__.py create mode 100644 src/cpl_cli/.cpl/abc_schematic.py create mode 100644 src/cpl_cli/.cpl/class_schematic.py create mode 100644 src/cpl_cli/.cpl/configmodel_schematic.py create mode 100644 src/cpl_cli/.cpl/enum_schematic.py create mode 100644 src/cpl_cli/.cpl/init_schematic.py create mode 100644 src/cpl_cli/.cpl/pipe_schematic.py create mode 100644 src/cpl_cli/.cpl/service_schematic.py create mode 100644 src/cpl_cli/.cpl/test_case_schematic.py create mode 100644 src/cpl_cli/.cpl/thread_schematic.py create mode 100644 src/cpl_cli/.cpl/validator_schematic.py delete mode 100644 src/cpl_cli/_templates/generate/__init__.py delete mode 100644 src/cpl_cli/_templates/generate/abc_template.py delete mode 100644 src/cpl_cli/_templates/generate/class_template.py delete mode 100644 src/cpl_cli/_templates/generate/configmodel_template.py delete mode 100644 src/cpl_cli/_templates/generate/enum_template.py delete mode 100644 src/cpl_cli/_templates/generate/init_template.py delete mode 100644 src/cpl_cli/_templates/generate/pipe_template.py delete mode 100644 src/cpl_cli/_templates/generate/service_template.py delete mode 100644 src/cpl_cli/_templates/generate/test_case_template.py delete mode 100644 src/cpl_cli/_templates/generate/thread_template.py delete mode 100644 src/cpl_cli/_templates/generate/validator_template.py create mode 100644 src/cpl_cli/abc/__init__.py create mode 100644 src/cpl_cli/abc/file_template_abc.py create mode 100644 src/cpl_cli/abc/generate_schematic_abc.py create mode 100644 src/cpl_cli/configuration/schematic_collection.py create mode 100644 src/cpl_cli/test_enum.py create mode 100644 src/cpl_cli/test_init.py create mode 100644 tests/custom/general/.cpl/custom_schematic.py create mode 100644 tests/custom/general/test/__init__.py create mode 100644 tests/custom/general/test/custom.py diff --git a/src/cpl_cli/.cpl/__init__.py b/src/cpl_cli/.cpl/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/cpl_cli/.cpl/abc_schematic.py b/src/cpl_cli/.cpl/abc_schematic.py new file mode 100644 index 00000000..917a60a6 --- /dev/null +++ b/src/cpl_cli/.cpl/abc_schematic.py @@ -0,0 +1,30 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class ABC(GenerateSchematicABC): + + def __init__(self, *args): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + from abc import ABC, abstractmethod + + + class $Name(ABC): + + @abstractmethod + def __init__(self): pass + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'abc', + ['a', 'A'] + ) diff --git a/src/cpl_cli/.cpl/class_schematic.py b/src/cpl_cli/.cpl/class_schematic.py new file mode 100644 index 00000000..f5cdb462 --- /dev/null +++ b/src/cpl_cli/.cpl/class_schematic.py @@ -0,0 +1,28 @@ +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC +from cpl_core.utils import String + + +class Class(GenerateSchematicABC): + + def __init__(self, name: str, path: str, schematic: str): + GenerateSchematicABC.__init__(self, name, path, schematic) + self._name = f'{String.convert_to_snake_case(name)}.py' + self._class_name = f'{String.first_to_upper(name)}' + + def get_code(self) -> str: + code = """\ + class $Name: + + def __init__(self): + pass + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'class', + ['c', 'C'] + ) diff --git a/src/cpl_cli/.cpl/configmodel_schematic.py b/src/cpl_cli/.cpl/configmodel_schematic.py new file mode 100644 index 00000000..e692f1e1 --- /dev/null +++ b/src/cpl_cli/.cpl/configmodel_schematic.py @@ -0,0 +1,46 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class ConfigModel(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + import traceback + + from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC + from cpl_core.console import Console + + + class $Name(ConfigurationModelABC): + + def __init__(self): + ConfigurationModelABC.__init__(self) + + self._atr = '' + + @property + def atr(self) -> str: + return self._atr + + def from_dict(self, settings: dict): + try: + self._atr = settings['atr'] + except Exception as e: + Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') + Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'settings', + ['st', 'ST'] + ) diff --git a/src/cpl_cli/.cpl/enum_schematic.py b/src/cpl_cli/.cpl/enum_schematic.py new file mode 100644 index 00000000..bd838159 --- /dev/null +++ b/src/cpl_cli/.cpl/enum_schematic.py @@ -0,0 +1,29 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Enum(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + from enum import Enum + + + class $Name(Enum): + + atr = 0 + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'enum', + ['e', 'E'] + ) diff --git a/src/cpl_cli/.cpl/init_schematic.py b/src/cpl_cli/.cpl/init_schematic.py new file mode 100644 index 00000000..f089ac18 --- /dev/null +++ b/src/cpl_cli/.cpl/init_schematic.py @@ -0,0 +1,25 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Init(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + self._name = f'__init__.py' + + def get_code(self) -> str: + code = """\ + # imports + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'init', + [] + ) diff --git a/src/cpl_cli/.cpl/pipe_schematic.py b/src/cpl_cli/.cpl/pipe_schematic.py new file mode 100644 index 00000000..fe7ab972 --- /dev/null +++ b/src/cpl_cli/.cpl/pipe_schematic.py @@ -0,0 +1,32 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Pipe(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + from cpl_core.pipes.pipe_abc import PipeABC + + + class $Name(PipeABC): + + def __init__(self): pass + + def transform(self, value: any, *args): + return value + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'pipe', + ['p', 'P'] + ) diff --git a/src/cpl_cli/.cpl/service_schematic.py b/src/cpl_cli/.cpl/service_schematic.py new file mode 100644 index 00000000..9651f7de --- /dev/null +++ b/src/cpl_cli/.cpl/service_schematic.py @@ -0,0 +1,27 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Service(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + class $Name: + + def __init__(self): + pass + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'service', + ['s', 'S'] + ) diff --git a/src/cpl_cli/.cpl/test_case_schematic.py b/src/cpl_cli/.cpl/test_case_schematic.py new file mode 100644 index 00000000..63ffe56c --- /dev/null +++ b/src/cpl_cli/.cpl/test_case_schematic.py @@ -0,0 +1,33 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class TestCase(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + import unittest + + + class $Name(unittest.TestCase): + + def setUp(self): + pass + + def test_equal(self): + pass + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'test-case', + ['tc', 'TC'] + ) diff --git a/src/cpl_cli/.cpl/thread_schematic.py b/src/cpl_cli/.cpl/thread_schematic.py new file mode 100644 index 00000000..4bb19e98 --- /dev/null +++ b/src/cpl_cli/.cpl/thread_schematic.py @@ -0,0 +1,33 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Thread(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + import threading + + + class $Name(threading.Thread): + + def __init__(self): + threading.Thread.__init__(self) + + def run(self) -> None: + pass + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'thread', + ['t', 'T'] + ) diff --git a/src/cpl_cli/.cpl/validator_schematic.py b/src/cpl_cli/.cpl/validator_schematic.py new file mode 100644 index 00000000..a7a17cb1 --- /dev/null +++ b/src/cpl_cli/.cpl/validator_schematic.py @@ -0,0 +1,33 @@ +import textwrap + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Validator(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + from cpl_core.configuration.validator_abc import ValidatorABC + + + class $Name(ValidatorABC): + + def __init__(self): + ValidatorABC.__init__(self) + + def validate(self) -> bool: + return True + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'validator', + ['v', 'V'] + ) diff --git a/src/cpl_cli/_templates/generate/__init__.py b/src/cpl_cli/_templates/generate/__init__.py deleted file mode 100644 index 07d118a6..00000000 --- a/src/cpl_cli/_templates/generate/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -cpl-cli sh-edraft Common Python library CLI -~~~~~~~~~~~~~~~~~~~ - -sh-edraft Common Python library Command Line Interface - -:copyright: (c) 2020 - 2022 sh-edraft.de -:license: MIT, see LICENSE for more details. - -""" - -__title__ = 'cpl_cli._templates.generate' -__author__ = 'Sven Heidemann' -__license__ = 'MIT' -__copyright__ = 'Copyright (c) 2020 - 2022 sh-edraft.de' -__version__ = '2022.12.0' - -from collections import namedtuple - - -# imports: - -VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='2022', minor='12', micro='0') diff --git a/src/cpl_cli/_templates/generate/abc_template.py b/src/cpl_cli/_templates/generate/abc_template.py deleted file mode 100644 index 3e292182..00000000 --- a/src/cpl_cli/_templates/generate/abc_template.py +++ /dev/null @@ -1,44 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ABCTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - from abc import ABC, abstractmethod - - - class $Name(ABC): - - @abstractmethod - def __init__(self): pass - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/class_template.py b/src/cpl_cli/_templates/generate/class_template.py deleted file mode 100644 index 6d01d659..00000000 --- a/src/cpl_cli/_templates/generate/class_template.py +++ /dev/null @@ -1,35 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ClassTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}.py' - self._class_name = f'{String.first_to_upper(name)}' - self._path = path - self._value = textwrap.dedent("""\ - class $Name: - - def __init__(self): - pass - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/configmodel_template.py b/src/cpl_cli/_templates/generate/configmodel_template.py deleted file mode 100644 index f4b9ce41..00000000 --- a/src/cpl_cli/_templates/generate/configmodel_template.py +++ /dev/null @@ -1,60 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ConfigModelTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - import traceback - - from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC - from cpl_core.console import Console - - - class $Name(ConfigurationModelABC): - - def __init__(self): - ConfigurationModelABC.__init__(self) - - self._atr = '' - - @property - def atr(self) -> str: - return self._atr - - def from_dict(self, settings: dict): - try: - self._atr = settings['atr'] - except Exception as e: - Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') - Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/enum_template.py b/src/cpl_cli/_templates/generate/enum_template.py deleted file mode 100644 index b8c04b49..00000000 --- a/src/cpl_cli/_templates/generate/enum_template.py +++ /dev/null @@ -1,43 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class EnumTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - from enum import Enum - - - class $Name(Enum): - - atr = 0 - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/init_template.py b/src/cpl_cli/_templates/generate/init_template.py deleted file mode 100644 index 48c2e2da..00000000 --- a/src/cpl_cli/_templates/generate/init_template.py +++ /dev/null @@ -1,35 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class InitTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'__init__.py' - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - # imports - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/pipe_template.py b/src/cpl_cli/_templates/generate/pipe_template.py deleted file mode 100644 index 6a33035b..00000000 --- a/src/cpl_cli/_templates/generate/pipe_template.py +++ /dev/null @@ -1,46 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class PipeTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - from cpl_core.pipes.pipe_abc import PipeABC - - - class $Name(PipeABC): - - def __init__(self): pass - - def transform(self, value: any, *args): - return value - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/service_template.py b/src/cpl_cli/_templates/generate/service_template.py deleted file mode 100644 index 24846155..00000000 --- a/src/cpl_cli/_templates/generate/service_template.py +++ /dev/null @@ -1,41 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ServiceTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - class $Name: - - def __init__(self): - pass - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/test_case_template.py b/src/cpl_cli/_templates/generate/test_case_template.py deleted file mode 100644 index 5888bb5c..00000000 --- a/src/cpl_cli/_templates/generate/test_case_template.py +++ /dev/null @@ -1,47 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class TestCaseTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - import unittest - - - class $Name(unittest.TestCase): - - def setUp(self): - pass - - def test_equal(self): - pass - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/thread_template.py b/src/cpl_cli/_templates/generate/thread_template.py deleted file mode 100644 index 4609d678..00000000 --- a/src/cpl_cli/_templates/generate/thread_template.py +++ /dev/null @@ -1,47 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ThreadTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - import threading - - - class $Name(threading.Thread): - - def __init__(self): - threading.Thread.__init__(self) - - def run(self) -> None: - pass - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/_templates/generate/validator_template.py b/src/cpl_cli/_templates/generate/validator_template.py deleted file mode 100644 index 683cea5e..00000000 --- a/src/cpl_cli/_templates/generate/validator_template.py +++ /dev/null @@ -1,47 +0,0 @@ -import textwrap -from string import Template - -from cpl_core.utils.string import String -from cpl_cli._templates.template_file_abc import TemplateFileABC - - -class ValidatorTemplate(TemplateFileABC): - - def __init__(self, name: str, schematic: str, schematic_upper: str, path: str): - TemplateFileABC.__init__(self) - - self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' - if schematic in name.lower(): - self._name = f'{String.convert_to_snake_case(name)}.py' - - self._class_name = f'{String.first_to_upper(name)}{schematic_upper}' - if schematic in name.lower(): - self._class_name = f'{String.first_to_upper(name)}' - - self._path = path - self._value = textwrap.dedent("""\ - from cpl_core.configuration.validator_abc import ValidatorABC - - - class $Name(ValidatorABC): - - def __init__(self): - ValidatorABC.__init__(self) - - def validate(self) -> bool: - return True - """) - - @property - def name(self) -> str: - return self._name - - @property - def path(self) -> str: - return self._path - - @property - def value(self) -> str: - return Template(self._value).substitute( - Name=self._class_name - ) diff --git a/src/cpl_cli/abc/__init__.py b/src/cpl_cli/abc/__init__.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/src/cpl_cli/abc/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/src/cpl_cli/abc/file_template_abc.py b/src/cpl_cli/abc/file_template_abc.py new file mode 100644 index 00000000..09e39f23 --- /dev/null +++ b/src/cpl_cli/abc/file_template_abc.py @@ -0,0 +1,28 @@ +from abc import ABC, abstractmethod + +from cpl_core.utils import String + + +class FileTemplateABC(ABC): + + @abstractmethod + def __init__(self, name: str, path: str, code: str): + self._name = f'{String.convert_to_snake_case(name)}.py' + self._path = path + self._code = code + + @property + def name(self) -> str: + return self._name + + @property + def path(self) -> str: + return self._path + + @property + def value(self) -> str: + return self.get_code() + + @abstractmethod + def get_code(self) -> str: + return self._code diff --git a/src/cpl_cli/abc/generate_schematic_abc.py b/src/cpl_cli/abc/generate_schematic_abc.py new file mode 100644 index 00000000..7254e176 --- /dev/null +++ b/src/cpl_cli/abc/generate_schematic_abc.py @@ -0,0 +1,37 @@ +import textwrap +from abc import abstractmethod +from string import Template + +from cpl_cli.abc.file_template_abc import FileTemplateABC +from cpl_cli.configuration.schematic_collection import SchematicCollection +from cpl_core.utils import String + + +class GenerateSchematicABC(FileTemplateABC): + + def __init__(self, name: str, schematic: str, path: str): + FileTemplateABC.__init__(self, name, path, '') + self._name = f'{String.convert_to_snake_case(name)}_{schematic}.py' + if schematic in name.lower(): + self._name = f'{String.convert_to_snake_case(name)}.py' + + self._class_name = f'{String.first_to_upper(name)}{String.first_to_upper(schematic)}' + if schematic in name.lower(): + self._class_name = f'{String.first_to_upper(name)}' + + @property + def class_name(self) -> str: + return self._class_name + + @abstractmethod + def get_code(self) -> str: pass + + @classmethod + def build_code_str(cls, code: str, **kwargs) -> str: + text = textwrap.dedent(code) + return Template(text).substitute(**kwargs) + + @classmethod + @abstractmethod + def register(cls, *args): + SchematicCollection.register(*args) diff --git a/src/cpl_cli/command/generate_service.py b/src/cpl_cli/command/generate_service.py index 12236c83..41783b66 100644 --- a/src/cpl_cli/command/generate_service.py +++ b/src/cpl_cli/command/generate_service.py @@ -2,19 +2,10 @@ import os import sys import textwrap -from cpl_cli._templates.generate.abc_template import ABCTemplate -from cpl_cli._templates.generate.class_template import ClassTemplate -from cpl_cli._templates.generate.configmodel_template import ConfigModelTemplate -from cpl_cli._templates.generate.enum_template import EnumTemplate -from cpl_cli._templates.generate.init_template import InitTemplate -from cpl_cli._templates.generate.pipe_template import PipeTemplate -from cpl_cli._templates.generate.service_template import ServiceTemplate -from cpl_cli._templates.generate.test_case_template import TestCaseTemplate -from cpl_cli._templates.generate.thread_template import ThreadTemplate -from cpl_cli._templates.generate.validator_template import ValidatorTemplate -from cpl_cli._templates.template_file_abc import TemplateFileABC +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC from cpl_cli.command_abc import CommandABC from cpl_cli.configuration import WorkspaceSettings +from cpl_cli.configuration.schematic_collection import SchematicCollection from cpl_core.configuration.configuration_abc import ConfigurationABC from cpl_core.console.console import Console from cpl_core.console.foreground_color_enum import ForegroundColorEnum @@ -37,44 +28,44 @@ class GenerateService(CommandABC): self._config = configuration self._workspace = workspace - self._schematics = { - "abc": { - "Upper": "ABC", - "Template": ABCTemplate - }, - "class": { - "Upper": "Class", - "Template": ClassTemplate - }, - "enum": { - "Upper": "Enum", - "Template": EnumTemplate - }, - "pipe": { - "Upper": "Pipe", - "Template": PipeTemplate - }, - "service": { - "Upper": "Service", - "Template": ServiceTemplate - }, - "settings": { - "Upper": "Settings", - "Template": ConfigModelTemplate - }, - "test_case": { - "Upper": "TestCase", - "Template": TestCaseTemplate - }, - "thread": { - "Upper": "Thread", - "Template": ThreadTemplate - }, - "validator": { - "Upper": "Validator", - "Template": ValidatorTemplate - } - } + self._schematics = {} + # "abc": { + # "Upper": "ABC", + # "Template": ABCTemplate + # }, + # "class": { + # "Upper": "Class", + # "Template": ClassTemplate + # }, + # "enum": { + # "Upper": "Enum", + # "Template": EnumTemplate + # }, + # "pipe": { + # "Upper": "Pipe", + # "Template": PipeTemplate + # }, + # "service": { + # "Upper": "Service", + # "Template": ServiceTemplate + # }, + # "settings": { + # "Upper": "Settings", + # "Template": ConfigModelTemplate + # }, + # "test_case": { + # "Upper": "TestCase", + # "Template": TestCaseTemplate + # }, + # "thread": { + # "Upper": "Thread", + # "Template": ThreadTemplate + # }, + # "validator": { + # "Upper": "Validator", + # "Template": ValidatorTemplate + # } + # } self._config = configuration self._env = self._config.environment @@ -137,7 +128,7 @@ class GenerateService(CommandABC): template.write(value) template.close() - def _create_init_files(self, file_path: str, template: TemplateFileABC, class_name: str, schematic: str, rel_path: str): + def _create_init_files(self, file_path: str, template: GenerateSchematicABC, class_name: str, schematic: str, rel_path: str): if not os.path.isdir(os.path.dirname(file_path)): os.makedirs(os.path.dirname(file_path)) directory = '' @@ -146,7 +137,7 @@ class GenerateService(CommandABC): if subdir == 'src': continue - file = InitTemplate(class_name, schematic, self._schematics[schematic]["Upper"], rel_path) + file = self._schematics['init']['Template'](class_name, 'init', rel_path) if os.path.exists(os.path.join(os.path.abspath(directory), file.name)): continue @@ -154,12 +145,12 @@ class GenerateService(CommandABC): f'Creating {os.path.abspath(directory)}/{file.name}', self._create_file, os.path.join(os.path.abspath(directory), file.name), - file.value, + file.get_code(), text_foreground_color=ForegroundColorEnum.green, spinner_foreground_color=ForegroundColorEnum.cyan ) - def _generate(self, schematic: str, name: str, template: TemplateFileABC): + def _generate(self, schematic: str, name: str, template: type): """ Generates files by given schematic, name and template :param schematic: @@ -175,9 +166,9 @@ class GenerateService(CommandABC): class_name = parts[len(parts) - 1] if self._workspace is not None and parts[0] in self._workspace.projects: - rel_path = os.path.dirname(self._workspace.projects[parts[0]]) + rel_path = os.path.join(os.path.dirname(self._workspace.projects[parts[0]]), *parts[1:-1]) - template = template(class_name, schematic, self._schematics[schematic]["Upper"], rel_path) + template = template(class_name, String.convert_to_snake_case(schematic), rel_path) file_path = os.path.join(self._env.working_directory, template.path, template.name) self._create_init_files(file_path, template, class_name, schematic, rel_path) @@ -194,17 +185,47 @@ class GenerateService(CommandABC): message, self._create_file, file_path, - template.value, + template.get_code(), text_foreground_color=ForegroundColorEnum.green, spinner_foreground_color=ForegroundColorEnum.cyan ) + @staticmethod + def _read_custom_schematics_from_path(path: str): + if not os.path.exists(os.path.join(path, '.cpl')): + return + + for r, d, f in os.walk(os.path.join(path, '.cpl')): + for file in f: + if not file.endswith('_schematic.py'): + continue + + code = '' + with open(os.path.join(r, file), 'r') as py_file: + code = py_file.read() + py_file.close() + + exec(code) + + def _get_schematic_by_alias(self, schematic: str) -> str: + for key in self._schematics: + if schematic in self._schematics[key]['Aliases']: + return key + + return schematic + def execute(self, args: list[str]): """ Entry point of command :param args: :return: """ + self._read_custom_schematics_from_path(self._env.runtime_directory) + self._read_custom_schematics_from_path(self._env.working_directory) + for schematic in GenerateSchematicABC.__subclasses__(): + schematic.register() + self._schematics = SchematicCollection.get_schematics() + schematic = None value = None for s in self._schematics: @@ -213,6 +234,12 @@ class GenerateService(CommandABC): schematic = s break + schematic_by_alias = self._get_schematic_by_alias(args[0]) + if schematic is None and len(args) >= 1 and (args[0] in self._schematics or schematic_by_alias != args[0]): + schematic = schematic_by_alias + self._config.add_configuration(schematic, args[1]) + value = args[1] + if schematic is None: self._help('Usage: cpl generate [options]') Console.write_line() diff --git a/src/cpl_cli/configuration/schematic_collection.py b/src/cpl_cli/configuration/schematic_collection.py new file mode 100644 index 00000000..a3469077 --- /dev/null +++ b/src/cpl_cli/configuration/schematic_collection.py @@ -0,0 +1,16 @@ +from cpl_core.utils import String + + +class SchematicCollection: + _schematics: dict = {} + + @classmethod + def register(cls, template: type, schematic: str, aliases: list[str]): + cls._schematics[schematic] = { + "Template": template, + "Aliases": aliases + } + + @classmethod + def get_schematics(cls) -> dict: + return cls._schematics diff --git a/src/cpl_cli/startup_argument_extension.py b/src/cpl_cli/startup_argument_extension.py index 16bd5449..008f47f3 100644 --- a/src/cpl_cli/startup_argument_extension.py +++ b/src/cpl_cli/startup_argument_extension.py @@ -29,16 +29,16 @@ class StartupArgumentExtension(StartupExtensionABC): config.create_console_argument(ArgumentTypeEnum.Executable, '', 'add', ['a', 'A'], AddService, True, validators=[WorkspaceValidator]) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'build', ['b', 'B'], BuildService, True, validators=[ProjectValidator]) - config.create_console_argument(ArgumentTypeEnum.Executable, '', 'generate', ['g', 'G'], GenerateService, True) \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'abc', ['a', 'A'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'class', ['c', 'C'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'enum', ['e', 'E'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'pipe', ['p', 'P'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'service', ['s', 'S'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'settings', ['st', 'ST'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'test_case', ['tc', 'TC'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 'T'], ' ') \ - .add_console_argument(ArgumentTypeEnum.Variable, '', 'validator', ['v', 'V'], ' ') + config.create_console_argument(ArgumentTypeEnum.Executable, '', 'generate', ['g', 'G'], GenerateService, True) #\ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'abc', ['a', 'A'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'class', ['c', 'C'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'enum', ['e', 'E'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'pipe', ['p', 'P'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'service', ['s', 'S'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'settings', ['st', 'ST'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'test_case', ['tc', 'TC'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 'T'], ' ') \ + # .add_console_argument(ArgumentTypeEnum.Variable, '', 'validator', ['v', 'V'], ' ') config.create_console_argument(ArgumentTypeEnum.Executable, '', 'install', ['i', 'I'], InstallService, True, validators=[ProjectValidator]) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'dev', ['d', 'D']) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ diff --git a/src/cpl_cli/test_enum.py b/src/cpl_cli/test_enum.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/src/cpl_cli/test_enum.py @@ -0,0 +1 @@ +# imports diff --git a/src/cpl_cli/test_init.py b/src/cpl_cli/test_init.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/src/cpl_cli/test_init.py @@ -0,0 +1 @@ +# imports diff --git a/tests/custom/general/.cpl/custom_schematic.py b/tests/custom/general/.cpl/custom_schematic.py new file mode 100644 index 00000000..dd951a69 --- /dev/null +++ b/tests/custom/general/.cpl/custom_schematic.py @@ -0,0 +1,27 @@ + + +from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC + + +class Custom(GenerateSchematicABC): + + def __init__(self, *args: str): + GenerateSchematicABC.__init__(self, *args) + + def get_code(self) -> str: + code = """\ + class $Name: + + def __init__(self): + print('hello') + """ + x = self.build_code_str(code, Name=self._class_name) + return x + + @classmethod + def register(cls): + GenerateSchematicABC.register( + cls, + 'custom', + ['cm', 'CM'] + ) diff --git a/tests/custom/general/test/__init__.py b/tests/custom/general/test/__init__.py new file mode 100644 index 00000000..425ab6c1 --- /dev/null +++ b/tests/custom/general/test/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/tests/custom/general/test/custom.py b/tests/custom/general/test/custom.py new file mode 100644 index 00000000..16baa336 --- /dev/null +++ b/tests/custom/general/test/custom.py @@ -0,0 +1,4 @@ +class Custom: + + def __init__(self): + print('hello') diff --git a/unittests/unittests_cli/generate_test_case.py b/unittests/unittests_cli/generate_test_case.py index cba7d8a7..16bb382b 100644 --- a/unittests/unittests_cli/generate_test_case.py +++ b/unittests/unittests_cli/generate_test_case.py @@ -78,8 +78,8 @@ class GenerateTestCase(CommandTestCase): self._test_file_with_project('settings', '_settings', path=self._project) def test_test_case(self): - self._test_file('test_case', '_test_case') - self._test_file_with_project('test_case', '_test_case', path=self._project) + self._test_file('test-case', '_test_case') + self._test_file_with_project('test-case', '_test_case', path=self._project) def test_thread(self): self._test_file('thread', '_thread')