From eb43806da6d4beb5f0b12d3ddd9098b913c0b0db Mon Sep 17 00:00:00 2001 From: kolo Date: Mon, 28 Apr 2025 02:21:34 +0300 Subject: [PATCH] new model - Response --- mock/default_mock_app/main.py | 11 +- src/argenta/command/exceptions.py | 4 +- src/argenta/command/flag/__init__.py | 4 +- src/argenta/command/flag/models.py | 142 +++++--------------------- src/argenta/command/flags/__init__.py | 0 src/argenta/command/flags/models.py | 69 +++++++++++++ src/argenta/command/models.py | 14 +-- src/argenta/response/__init__.py | 0 src/argenta/response/entity.py | 13 +++ src/argenta/response/status.py | 6 ++ src/argenta/router/entity.py | 23 +---- tests/unit_tests/test_command.py | 12 +-- tests/unit_tests/test_flag.py | 16 +-- tests/unit_tests/test_router.py | 24 ++--- 14 files changed, 158 insertions(+), 180 deletions(-) create mode 100644 src/argenta/command/flags/__init__.py create mode 100644 src/argenta/command/flags/models.py create mode 100644 src/argenta/response/__init__.py create mode 100644 src/argenta/response/entity.py create mode 100644 src/argenta/response/status.py diff --git a/mock/default_mock_app/main.py b/mock/default_mock_app/main.py index 9070838..c9b3c1d 100644 --- a/mock/default_mock_app/main.py +++ b/mock/default_mock_app/main.py @@ -1,8 +1,7 @@ -#from mock.mock_app.handlers.routers import work_router +from mock.mock_app.handlers.routers import work_router from argenta.app import App from argenta.app.defaults import PredefinedMessages -from argenta.app.dividing_line import DynamicDividingLine from argenta.app.autocompleter import AutoCompleter from argenta.orchestrator import Orchestrator from argenta.orchestrator.argparser import ArgParser @@ -10,16 +9,16 @@ from argenta.orchestrator.argparser.arguments import BooleanArgument arg_parser = ArgParser(processed_args=[BooleanArgument('repeat')]) -app: App = App() +app: App = App(autocompleter=AutoCompleter('.hist')) orchestrator: Orchestrator = Orchestrator() def main(): - #app.include_router(work_router) + app.include_router(work_router) - '''app.add_message_on_startup(PredefinedMessages.USAGE) + app.add_message_on_startup(PredefinedMessages.USAGE) app.add_message_on_startup(PredefinedMessages.AUTOCOMPLETE) - app.add_message_on_startup(PredefinedMessages.HELP)''' + app.add_message_on_startup(PredefinedMessages.HELP) orchestrator.start_polling(app) diff --git a/src/argenta/command/exceptions.py b/src/argenta/command/exceptions.py index 1ef7b08..c693e28 100644 --- a/src/argenta/command/exceptions.py +++ b/src/argenta/command/exceptions.py @@ -1,4 +1,4 @@ -from argenta.command.flag.models import InputFlag, Flag +from argenta.command.flag.models import ValidInputFlag, Flag class BaseInputCommandException(Exception): @@ -20,7 +20,7 @@ class RepeatedInputFlagsException(BaseInputCommandException): """ Private. Raised when repeated input flags are detected """ - def __init__(self, flag: Flag | InputFlag): + def __init__(self, flag: Flag | ValidInputFlag): self.flag = flag def __str__(self): return ("Repeated Input Flags\n" diff --git a/src/argenta/command/flag/__init__.py b/src/argenta/command/flag/__init__.py index 6c446fd..352a56e 100644 --- a/src/argenta/command/flag/__init__.py +++ b/src/argenta/command/flag/__init__.py @@ -1,4 +1,4 @@ -__all__ = ('InputFlags', 'InputFlag', 'Flag', 'Flags') +__all__ = ('InputFlags', 'ValidInputFlag', 'Flag', 'Flags') -from argenta.command.flag.models import InputFlags, InputFlag, Flags, Flag +from argenta.command.flag.models import InputFlags, ValidInputFlag, Flags, Flag diff --git a/src/argenta/command/flag/models.py b/src/argenta/command/flag/models.py index 36add2f..7632a75 100644 --- a/src/argenta/command/flag/models.py +++ b/src/argenta/command/flag/models.py @@ -38,37 +38,6 @@ class BaseFlag(ABC): -class InputFlag(BaseFlag): - def __init__(self, name: str, - prefix: Literal['-', '--', '---'] = '--', - value: str = None): - """ - Public. The entity of the flag of the entered command - :param name: the name of the input flag - :param prefix: the prefix of the input flag - :param value: the value of the input flag - :return: None - """ - super().__init__(name, prefix) - self._flag_value = value - - def get_value(self) -> str | None: - """ - Public. Returns the value of the flag - :return: the value of the flag as str - """ - return self._flag_value - - def set_value(self, value): - """ - Private. Sets the value of the flag - :param value: the fag value to set - :return: None - """ - self._flag_value = value - - - class Flag(BaseFlag): def __init__(self, name: str, prefix: Literal['-', '--', '---'] = '--', @@ -114,105 +83,40 @@ class Flag(BaseFlag): -class BaseFlags(ABC): - """ - Private. Base class for groups of flags - """ - __slots__ = ('_flags',) - - @abstractmethod - def get_flags(self): +class ValidInputFlag(BaseFlag): + def __init__(self, name: str, + prefix: Literal['-', '--', '---'] = '--', + value: str = None): """ - Public. Returns a list of flags - :return: list of flags - """ - pass - - @abstractmethod - def add_flag(self, flag: Flag | InputFlag): - """ - Public. Adds a flag to the list of flags - :param flag: flag to add + Public. The entity of the flag of the entered command + :param name: the name of the input flag + :param prefix: the prefix of the input flag + :param value: the value of the input flag :return: None """ - pass + super().__init__(name, prefix) + self._flag_value = value - @abstractmethod - def add_flags(self, flags: list[Flag] | list[InputFlag]): + def get_value(self) -> str | None: """ - Public. Adds a list of flags to the list of flags - :param flags: list of flags to add + Public. Returns the value of the flag + :return: the value of the flag as str + """ + return self._flag_value + + def set_value(self, value): + """ + Private. Sets the value of the flag + :param value: the fag value to set :return: None """ - pass - - @abstractmethod - def get_flag(self, name: str): - """ - Public. Returns the flag entity by its name or None if not found - :param name: the name of the flag to get - :return: entity of the flag or None - """ - pass - - def __iter__(self): - return iter(self._flags) - - def __next__(self): - return next(iter(self)) - - def __getitem__(self, item): - return self._flags[item] + self._flag_value = value -class Flags(BaseFlags, ABC): - def __init__(self, *flags: Flag): - """ - Public. A model that combines the registered flags - :param flags: the flags that will be registered - :return: None - """ - self._flags = flags if flags else [] - - def get_flags(self) -> list[Flag]: - return self._flags - - def add_flag(self, flag: Flag): - self._flags.append(flag) - - def add_flags(self, flags: list[Flag]): - self._flags.extend(flags) - - def get_flag(self, name: str) -> Flag | None: - if name in [flag.get_name() for flag in self._flags]: - return list(filter(lambda flag: flag.get_name() == name, self._flags))[0] - else: - return None +class UndefinedInputFlag(ValidInputFlag): pass -class InputFlags(BaseFlags, ABC): - def __init__(self, *flags: InputFlag): - """ - Public. A model that combines the input flags of the input command - :param flags: all input flags - :return: None - """ - self._flags = flags if flags else [] - - def get_flags(self) -> list[InputFlag]: - return self._flags - - def add_flag(self, flag: InputFlag): - self._flags.append(flag) - - def add_flags(self, flags: list[InputFlag]): - self._flags.extend(flags) - - def get_flag(self, name: str) -> InputFlag | None: - if name in [flag.get_name() for flag in self._flags]: - return list(filter(lambda flag: flag.get_name() == name, self._flags))[0] - else: - return None +class InvalidValueInputFlag(ValidInputFlag): pass diff --git a/src/argenta/command/flags/__init__.py b/src/argenta/command/flags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/argenta/command/flags/models.py b/src/argenta/command/flags/models.py new file mode 100644 index 0000000..cf86eea --- /dev/null +++ b/src/argenta/command/flags/models.py @@ -0,0 +1,69 @@ +from argenta.command.flag import Flag, ValidInputFlag + + + +class Flags: + def __init__(self, *flags: Flag): + """ + Public. A model that combines the registered flags + :param flags: the flags that will be registered + :return: None + """ + self._flags = flags if flags else [] + + def get_flags(self) -> list[Flag]: + """ + Public. Returns a list of flags + :return: list of flags + """ + return self._flags + + def add_flag(self, flag: Flag): + """ + Public. Adds a flag to the list of flags + :param flag: flag to add + :return: None + """ + self._flags.append(flag) + + def add_flags(self, flags: list[Flag]): + """ + Public. Adds a list of flags to the list of flags + :param flags: list of flags to add + :return: None + """ + self._flags.extend(flags) + + def get_flag(self, name: str) -> Flag | None: + """ + Public. Returns the flag entity by its name or None if not found + :param name: the name of the flag to get + :return: entity of the flag or None + """ + if name in [flag.get_name() for flag in self._flags]: + return list(filter(lambda flag: flag.get_name() == name, self._flags))[0] + else: + return None + + def __iter__(self): + return iter(self._flags) + + def __next__(self): + return next(iter(self)) + + def __getitem__(self, item): + return self._flags[item] + + + +class ValidInputFlags(ValidInputFlag): + pass + + +class UndefinedInputFlags(ValidInputFlags): + pass + + +class InvalidValueInputFlags(ValidInputFlags): + pass + diff --git a/src/argenta/command/models.py b/src/argenta/command/models.py index 7f4e17d..9d3557f 100644 --- a/src/argenta/command/models.py +++ b/src/argenta/command/models.py @@ -1,4 +1,4 @@ -from argenta.command.flag.models import Flag, InputFlag, Flags, InputFlags +from argenta.command.flag.models import Flag, ValidInputFlag, Flags, InputFlags from argenta.command.exceptions import (UnprocessedInputFlagException, RepeatedInputFlagsException, EmptyInputCommandException) @@ -55,7 +55,7 @@ class Command(BaseCommand): """ return self._aliases - def validate_input_flag(self, flag: InputFlag) -> bool: + def validate_input_flag(self, flag: ValidInputFlag) -> bool: """ Private. Validates the input flag :param flag: input flag for validation @@ -87,7 +87,7 @@ class Command(BaseCommand): class InputCommand(BaseCommand, Generic[InputCommandType]): def __init__(self, trigger: str, - input_flags: InputFlag | InputFlags = None): + input_flags: ValidInputFlag | InputFlags = None): """ Private. The model of the input command, after parsing :param trigger:the trigger of the command @@ -95,7 +95,7 @@ class InputCommand(BaseCommand, Generic[InputCommandType]): :return: None """ super().__init__(trigger) - self._input_flags: InputFlags = input_flags if isinstance(input_flags, InputFlags) else InputFlags(input_flags) if isinstance(input_flags, InputFlag) else InputFlags() + self._input_flags: InputFlags = input_flags if isinstance(input_flags, InputFlags) else InputFlags(input_flags) if isinstance(input_flags, ValidInputFlag) else InputFlags() def _set_input_flags(self, input_flags: InputFlags) -> None: """ @@ -144,10 +144,10 @@ class InputCommand(BaseCommand, Generic[InputCommandType]): if not list_of_tokens[k+1].startswith('-'): continue - input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-')+1:], - prefix=cast(Literal['-', '--', '---'], + input_flag = ValidInputFlag(name=current_flag_name[current_flag_name.rfind('-') + 1:], + prefix=cast(Literal['-', '--', '---'], current_flag_name[:current_flag_name.rfind('-')+1]), - value=current_flag_value) + value=current_flag_value) all_flags = [flag.get_string_entity() for flag in input_flags.get_flags()] if input_flag.get_string_entity() not in all_flags: diff --git a/src/argenta/response/__init__.py b/src/argenta/response/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/argenta/response/entity.py b/src/argenta/response/entity.py new file mode 100644 index 0000000..e83d86f --- /dev/null +++ b/src/argenta/response/entity.py @@ -0,0 +1,13 @@ +from argenta.command.flags.models import ValidInputFlags, UndefinedInputFlags, InvalidValueInputFlags +from argenta.response.status import Status + + +class Response: + def __init__(self, status: Status, + valid_flags: ValidInputFlags = None, + undefined_flags: UndefinedInputFlags = None, + invalid_value_flags: InvalidValueInputFlags = None): + self.status = status + self.valid_flags = valid_flags + self.undefined_flags = undefined_flags + self.invalid_value_flags = invalid_value_flags diff --git a/src/argenta/response/status.py b/src/argenta/response/status.py new file mode 100644 index 0000000..fe7bf5a --- /dev/null +++ b/src/argenta/response/status.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class Status(Enum): + SUCCESSFUL = 200 + UNSUCCESSFUL = 400 diff --git a/src/argenta/router/entity.py b/src/argenta/router/entity.py index a019c1e..cd2c982 100644 --- a/src/argenta/router/entity.py +++ b/src/argenta/router/entity.py @@ -3,7 +3,8 @@ from inspect import getfullargspec from argenta.command import Command from argenta.command.models import InputCommand from argenta.router.command_handler.entity import CommandHandlers, CommandHandler -from argenta.command.flag.models import Flag, Flags, InputFlags +from argenta.command.flag.models import Flag +from argenta.command.flags.models import Flags from argenta.router.exceptions import (RepeatedFlagNameException, TooManyTransferredArgsException, RequiredArgumentNotPassedException, @@ -22,7 +23,6 @@ class Router: self._command_handlers: CommandHandlers = CommandHandlers() self._ignore_command_register: bool = False - self._not_valid_flag_handler: Callable[[Flag], None] = lambda flag: print(f"Undefined or incorrect input flag: {flag.get_string_entity()}{(' '+flag.get_value()) if flag.get_value() else ''}") def command(self, command: Command) -> Callable: @@ -44,15 +44,6 @@ class Router: return command_decorator - def set_invalid_input_flag_handler(self, func: Callable[[Flag], None]) -> None: - """ - Public. Registers handler for invalid input flag - :param func: registered handler - :return: None - """ - self._not_valid_flag_handler = func - - def finds_appropriate_handler(self, input_command: InputCommand) -> None: """ Private. Finds the appropriate handler for given input command and passes control to it @@ -136,15 +127,11 @@ class Router: :param func: entity of the handler func :return: None if func is valid else raise exception """ - registered_args = command.get_registered_flags() transferred_args = getfullargspec(func).args - if registered_args.get_flags() and transferred_args: - if len(transferred_args) != 1: - raise TooManyTransferredArgsException() - elif registered_args.get_flags() and not transferred_args: - raise RequiredArgumentNotPassedException() - elif not registered_args.get_flags() and transferred_args: + if len(transferred_args) > 1: raise TooManyTransferredArgsException() + elif len(transferred_args) == 0: + raise RequiredArgumentNotPassedException() def set_command_register_ignore(self, _: bool) -> None: diff --git a/tests/unit_tests/test_command.py b/tests/unit_tests/test_command.py index 2587c0c..50e94f3 100644 --- a/tests/unit_tests/test_command.py +++ b/tests/unit_tests/test_command.py @@ -1,4 +1,4 @@ -from argenta.command.flag import Flag, InputFlag, Flags +from argenta.command.flag import Flag, ValidInputFlag, Flags from argenta.command.models import InputCommand, Command from argenta.command.exceptions import (UnprocessedInputFlagException, RepeatedInputFlagsException, @@ -25,23 +25,23 @@ class TestInputCommand(unittest.TestCase): def test_validate_correct_input_flag1(self): command = Command('some', flags=Flag('test')) - self.assertEqual(command.validate_input_flag(InputFlag('test')), True) + self.assertEqual(command.validate_input_flag(ValidInputFlag('test')), True) def test_validate_correct_input_flag2(self): command = Command('some', flags=Flags(Flag('test'), Flag('more'))) - self.assertEqual(command.validate_input_flag(InputFlag('more')), True) + self.assertEqual(command.validate_input_flag(ValidInputFlag('more')), True) def test_validate_incorrect_input_flag1(self): command = Command('some', flags=Flags(Flag('test'))) - self.assertEqual(command.validate_input_flag(InputFlag('more')), False) + self.assertEqual(command.validate_input_flag(ValidInputFlag('more')), False) def test_validate_incorrect_input_flag2(self): command = Command('some', flags=Flags(Flag('test'), Flag('more'))) - self.assertEqual(command.validate_input_flag(InputFlag('case')), False) + self.assertEqual(command.validate_input_flag(ValidInputFlag('case')), False) def test_validate_incorrect_input_flag3(self): command = Command('some') - self.assertEqual(command.validate_input_flag(InputFlag('case')), False) + self.assertEqual(command.validate_input_flag(ValidInputFlag('case')), False) def test_isinstance_parse_correct_raw_command(self): cmd = InputCommand.parse('ssh --host 192.168.0.3') diff --git a/tests/unit_tests/test_flag.py b/tests/unit_tests/test_flag.py index c83bb95..ef272df 100644 --- a/tests/unit_tests/test_flag.py +++ b/tests/unit_tests/test_flag.py @@ -1,4 +1,4 @@ -from argenta.command.flag.models import Flag, InputFlag, InputFlags, Flags +from argenta.command.flag.models import Flag, ValidInputFlag, InputFlags, Flags import unittest import re @@ -28,11 +28,11 @@ class TestFlag(unittest.TestCase): '--') def test_get_flag_value_without_set(self): - self.assertEqual(InputFlag(name='test').get_value(), + self.assertEqual(ValidInputFlag(name='test').get_value(), None) def test_get_flag_value_with_set(self): - flag = InputFlag(name='test') + flag = ValidInputFlag(name='test') flag.set_value('example') self.assertEqual(flag.get_value(), 'example') @@ -69,19 +69,19 @@ class TestFlag(unittest.TestCase): self.assertEqual(flag.validate_input_flag_value('random value'), True) def test_get_input_flag1(self): - flag = InputFlag(name='test') + flag = ValidInputFlag(name='test') input_flags = InputFlags(flag) self.assertEqual(input_flags.get_flag('test'), flag) def test_get_input_flag2(self): - flag = InputFlag(name='test') - flag2 = InputFlag(name='some') + flag = ValidInputFlag(name='test') + flag2 = ValidInputFlag(name='some') input_flags = InputFlags(flag, flag2) self.assertEqual(input_flags.get_flag('some'), flag2) def test_get_undefined_input_flag(self): - flag = InputFlag(name='test') - flag2 = InputFlag(name='some') + flag = ValidInputFlag(name='test') + flag2 = ValidInputFlag(name='some') input_flags = InputFlags(flag, flag2) self.assertEqual(input_flags.get_flag('case'), None) diff --git a/tests/unit_tests/test_router.py b/tests/unit_tests/test_router.py index 6ccb3a7..3c0dfb2 100644 --- a/tests/unit_tests/test_router.py +++ b/tests/unit_tests/test_router.py @@ -1,4 +1,4 @@ -from argenta.command.flag import InputFlags, InputFlag, Flag, Flags +from argenta.command.flag import InputFlags, ValidInputFlag, Flag, Flags from argenta.router import Router from argenta.command import Command from argenta.router.exceptions import (TriggerContainSpacesException, @@ -27,66 +27,66 @@ class TestRouter(unittest.TestCase): def test_validate_incorrect_input_flag1(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) - self.assertEqual(router._validate_input_flags(Command('cmd'), InputFlags(InputFlag('ssh'))), False) + self.assertEqual(router._validate_input_flags(Command('cmd'), InputFlags(ValidInputFlag('ssh'))), False) def test_validate_incorrect_input_flag2(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) - self.assertEqual(router._validate_input_flags(Command('cmd'), InputFlags(InputFlag('ssh', value='some'))), False) + self.assertEqual(router._validate_input_flags(Command('cmd'), InputFlags(ValidInputFlag('ssh', value='some'))), False) def test_validate_incorrect_input_flag3(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) command = Command('cmd', flags=Flag('port')) - input_flags = InputFlags(InputFlag('ssh', value='some2')) + input_flags = InputFlags(ValidInputFlag('ssh', value='some2')) self.assertEqual(router._validate_input_flags(command, input_flags), False) def test_validate_incorrect_input_flag4(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) command = Command('cmd', flags=Flag('ssh', possible_values=False)) - input_flags = InputFlags(InputFlag('ssh', value='some3')) + input_flags = InputFlags(ValidInputFlag('ssh', value='some3')) self.assertEqual(router._validate_input_flags(command, input_flags), False) def test_validate_incorrect_input_flag5(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$'))) - input_flags = InputFlags(InputFlag('ssh', value='some40')) + input_flags = InputFlags(ValidInputFlag('ssh', value='some40')) self.assertEqual(router._validate_input_flags(command, input_flags), False) def test_validate_incorrect_input_flag6(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) command = Command('cmd', flags=Flag('ssh', possible_values=['example'])) - input_flags = InputFlags(InputFlag('ssh', value='example2')) + input_flags = InputFlags(ValidInputFlag('ssh', value='example2')) self.assertEqual(router._validate_input_flags(command, input_flags), False) def test_validate_incorrect_input_flag7(self): router = Router() router.set_invalid_input_flag_handler(lambda flag: None) command = Command('cmd', flags=Flag('ssh', possible_values=['example'])) - input_flags = InputFlags(InputFlag('ssh')) + input_flags = InputFlags(ValidInputFlag('ssh')) self.assertEqual(router._validate_input_flags(command, input_flags), False) def test_validate_correct_input_flag1(self): command = Command('cmd', flags=Flag('port')) - input_flags = InputFlags(InputFlag('port', value='some2')) + input_flags = InputFlags(ValidInputFlag('port', value='some2')) self.assertEqual(Router()._validate_input_flags(command, input_flags), True) def test_validate_correct_input_flag2(self): command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3'])) - input_flags = InputFlags(InputFlag('port', value='some2')) + input_flags = InputFlags(ValidInputFlag('port', value='some2')) self.assertEqual(Router()._validate_input_flags(command, input_flags), True) def test_validate_correct_input_flag3(self): command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$'))) - input_flags = InputFlags(InputFlag('ssh', value='more5')) + input_flags = InputFlags(ValidInputFlag('ssh', value='more5')) self.assertEqual(Router()._validate_input_flags(command, input_flags), True) def test_validate_correct_input_flag4(self): command = Command('cmd', flags=Flag('ssh', possible_values=False)) - input_flags = InputFlags(InputFlag('ssh')) + input_flags = InputFlags(ValidInputFlag('ssh')) self.assertEqual(Router()._validate_input_flags(command, input_flags), True) def test_validate_incorrect_func_args1(self):