mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05:28 +03:00
more working
This commit is contained in:
@@ -56,14 +56,14 @@ if __name__ == '__main__':
|
||||
import re
|
||||
from argenta.router import Router
|
||||
from argenta.command import Command
|
||||
from argenta.command.flag.registered_flag import Flags, Flag
|
||||
from argenta.command.flag import Flags, Flag, InputFlags
|
||||
|
||||
router = Router()
|
||||
|
||||
registered_flags = Flags(
|
||||
Flag(flag_name='host',
|
||||
flag_prefix='--',
|
||||
possible_flag_values=re.compile(r'^192.168.\d{1,3}.\d{1,3}$')),
|
||||
Flag(name='host',
|
||||
prefix='--',
|
||||
possible_values=re.compile(r'^192.168.\d{1,3}.\d{1,3}$')),
|
||||
Flag('port', '--', re.compile(r'^[0-9]{1,4}$')))
|
||||
|
||||
|
||||
@@ -75,10 +75,10 @@ def handler():
|
||||
@router.command(Command(trigger="ssh",
|
||||
description='connect via ssh',
|
||||
flags=registered_flags))
|
||||
def handler_with_flags(flags: dict):
|
||||
def handler_with_flags(flags: InputFlags):
|
||||
for flag in flags:
|
||||
print(f'Flag name: {flag['name']}\n'
|
||||
f'Flag value: {flag['value']}')
|
||||
print(f'Flag name: {flag.get_name()}\n'
|
||||
f'Flag value: {flag.get_value()}')
|
||||
```
|
||||
|
||||
---
|
||||
@@ -299,7 +299,6 @@ Router(title: str = 'Commands group title:',
|
||||
---
|
||||
|
||||
### Исключения
|
||||
- `RepeatedCommandException` - Одна и та же команда зарегистрирована в одном роутере
|
||||
- `RepeatedFlagNameException` - Повторяющиеся зарегистрированные флаги в команде
|
||||
- `TooManyTransferredArgsException` - Слишком много зарегистрированных аргументов у обработчика команды
|
||||
- `RequiredArgumentNotPassedException` - Не зарегистрирован обязательный аргумент у обработчика команды(аргумент, через который будут переданы флаги введённой команды)
|
||||
|
||||
+23
-22
@@ -52,7 +52,7 @@ class App:
|
||||
self._invalid_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Incorrect flag syntax: "{raw_command}"')
|
||||
self._repeated_input_flags_handler: Callable[[str], None] = lambda raw_command: print_func(f'Repeated input flags: "{raw_command}"')
|
||||
self._empty_input_command_handler: Callable[[], None] = lambda: print_func('Empty input command')
|
||||
self._unknown_command_handler: Callable[[Command], None] = lambda command: print_func(f"Unknown command: {command.get_trigger()}")
|
||||
self._unknown_command_handler: Callable[[InputCommand], None] = lambda command: print_func(f"Unknown command: {command.get_trigger()}")
|
||||
self._exit_command_handler: Callable[[], None] = lambda: print_func(self.farewell_message)
|
||||
|
||||
|
||||
@@ -78,28 +78,12 @@ class App:
|
||||
raw_command: str = input()
|
||||
|
||||
try:
|
||||
input_command: InputCommand = InputCommand.parse_input_command(raw_command=raw_command)
|
||||
except UnprocessedInputFlagException:
|
||||
input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
|
||||
except (UnprocessedInputFlagException,
|
||||
RepeatedInputFlagsException,
|
||||
EmptyInputCommandException) as error:
|
||||
self.print_func(self.line_separate)
|
||||
self._invalid_input_flags_handler(raw_command)
|
||||
self.print_func(self.line_separate)
|
||||
|
||||
if not self.repeat_command_groups:
|
||||
self.print_func(self.prompt)
|
||||
continue
|
||||
|
||||
except RepeatedInputFlagsException:
|
||||
self.print_func(self.line_separate)
|
||||
self._repeated_input_flags_handler(raw_command)
|
||||
self.print_func(self.line_separate)
|
||||
|
||||
if not self.repeat_command_groups:
|
||||
self.print_func(self.prompt)
|
||||
continue
|
||||
|
||||
except EmptyInputCommandException:
|
||||
self.print_func(self.line_separate)
|
||||
self._empty_input_command_handler()
|
||||
self._error_handler(error, raw_command)
|
||||
self.print_func(self.line_separate)
|
||||
|
||||
if not self.repeat_command_groups:
|
||||
@@ -203,6 +187,7 @@ class App:
|
||||
for router in routers:
|
||||
self.include_router(router)
|
||||
|
||||
|
||||
def _validate_number_of_routers(self) -> None:
|
||||
if not self._registered_routers:
|
||||
raise NoRegisteredRoutersException()
|
||||
@@ -259,3 +244,19 @@ class App:
|
||||
)
|
||||
)
|
||||
self.print_func(self.command_group_description_separate)
|
||||
|
||||
|
||||
def _error_handler(self,
|
||||
error: UnprocessedInputFlagException |
|
||||
RepeatedInputFlagsException |
|
||||
EmptyInputCommandException,
|
||||
raw_command: str) -> None:
|
||||
match error:
|
||||
case UnprocessedInputFlagException():
|
||||
self._invalid_input_flags_handler(raw_command)
|
||||
case RepeatedInputFlagsException():
|
||||
self._repeated_input_flags_handler(raw_command)
|
||||
case EmptyInputCommandException():
|
||||
self._empty_input_command_handler()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
__all__ = ('InputFlags', 'InputFlag', 'Flag', 'Flags')
|
||||
|
||||
|
||||
from .models import InputFlags, InputFlag, Flags, Flag
|
||||
|
||||
@@ -4,7 +4,7 @@ import re
|
||||
|
||||
|
||||
@dataclass
|
||||
class DefaultFlags:
|
||||
class PredeterminedFlags:
|
||||
HELP = Flag(name='help', possible_values=False)
|
||||
SHORT_HELP = Flag(name='h', prefix='-', possible_values=False)
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@ from abc import ABC, abstractmethod
|
||||
|
||||
class BaseFlag:
|
||||
def __init__(self, name: str,
|
||||
prefix: Literal['-', '--', '---'] = '--',
|
||||
possible_values: list[str] | Pattern[str] | False = True):
|
||||
prefix: Literal['-', '--', '---'] = '--'):
|
||||
self._name = name
|
||||
self._prefix = prefix
|
||||
self.possible_values = possible_values
|
||||
|
||||
def get_string_entity(self):
|
||||
string_entity: str = self._prefix + self._name
|
||||
@@ -25,9 +23,9 @@ class BaseFlag:
|
||||
class InputFlag(BaseFlag):
|
||||
def __init__(self, name: str,
|
||||
prefix: Literal['-', '--', '---'] = '--',
|
||||
possible_values: list[str] | Pattern[str] | False = True):
|
||||
super().__init__(name, prefix, possible_values)
|
||||
self._flag_value = None
|
||||
value: str = None):
|
||||
super().__init__(name, prefix)
|
||||
self._flag_value = value
|
||||
|
||||
def get_value(self):
|
||||
return self._flag_value
|
||||
@@ -38,6 +36,12 @@ class InputFlag(BaseFlag):
|
||||
|
||||
|
||||
class Flag(BaseFlag):
|
||||
def __init__(self, name: str,
|
||||
prefix: Literal['-', '--', '---'] = '--',
|
||||
possible_values: list[str] | Pattern[str] | False = True):
|
||||
super().__init__(name, prefix)
|
||||
self.possible_values = possible_values
|
||||
|
||||
def validate_input_flag_value(self, input_flag_value: str | None):
|
||||
if self.possible_values is False:
|
||||
if input_flag_value is None:
|
||||
@@ -45,11 +49,14 @@ class Flag(BaseFlag):
|
||||
else:
|
||||
return False
|
||||
elif isinstance(self.possible_values, Pattern):
|
||||
if isinstance(input_flag_value, str):
|
||||
is_valid = bool(self.possible_values.match(input_flag_value))
|
||||
if bool(is_valid):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
elif isinstance(self.possible_values, list):
|
||||
if input_flag_value in self.possible_values:
|
||||
|
||||
+29
-41
@@ -5,30 +5,24 @@ from argenta.command.exceptions import (UnprocessedInputFlagException,
|
||||
from typing import Generic, TypeVar, cast, Literal
|
||||
|
||||
|
||||
BaseCommandType = TypeVar('BaseCommandType')
|
||||
InputCommandType = TypeVar('InputCommandType')
|
||||
|
||||
|
||||
class BaseCommand(Generic[BaseCommandType]):
|
||||
def __init__(self, trigger: str,
|
||||
description: str = None,
|
||||
flags: Flag | Flags = None):
|
||||
class BaseCommand:
|
||||
def __init__(self, trigger: str):
|
||||
self._trigger = trigger
|
||||
self._description = f'description for "{self._trigger}" command' if not description else description
|
||||
|
||||
def get_trigger(self) -> str:
|
||||
return self._trigger
|
||||
|
||||
def get_description(self) -> str:
|
||||
return self._description
|
||||
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def __init__(self, trigger: str,
|
||||
description: str = None,
|
||||
flags: Flag | Flags = None):
|
||||
super().__init__(trigger, description)
|
||||
super().__init__(trigger)
|
||||
self._registered_flags: Flags = flags if isinstance(flags, Flags) else Flags(flags) if isinstance(flags, Flag) else Flags()
|
||||
self._description = f'description for "{self._trigger}" command' if not description else description
|
||||
|
||||
def get_registered_flags(self) -> Flags:
|
||||
return self._registered_flags
|
||||
@@ -49,13 +43,15 @@ class Command(BaseCommand):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_description(self) -> str:
|
||||
return self._description
|
||||
|
||||
|
||||
class InputCommand(BaseCommand):
|
||||
|
||||
class InputCommand(BaseCommand, Generic[InputCommandType]):
|
||||
def __init__(self, trigger: str,
|
||||
description: str = None,
|
||||
input_flags: InputFlag | InputFlags = None):
|
||||
super().__init__(trigger, description)
|
||||
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()
|
||||
|
||||
def _set_input_flags(self, input_flags: InputFlags):
|
||||
@@ -65,53 +61,45 @@ class InputCommand(BaseCommand):
|
||||
return self._input_flags
|
||||
|
||||
@staticmethod
|
||||
def parse_input_command(raw_command: str) -> BaseCommandType:
|
||||
def parse(raw_command: str) -> InputCommandType:
|
||||
if not raw_command:
|
||||
raise EmptyInputCommandException()
|
||||
|
||||
list_of_tokens = raw_command.split()
|
||||
command = list_of_tokens[0]
|
||||
list_of_tokens.pop(0)
|
||||
command = list_of_tokens.pop(0)
|
||||
|
||||
input_flags: InputFlags = InputFlags()
|
||||
current_flag_name = None
|
||||
current_flag_value = None
|
||||
current_flag_name, current_flag_value = None, None
|
||||
|
||||
for k, _ in enumerate(list_of_tokens):
|
||||
if _.startswith('-'):
|
||||
flag_prefix_last_symbol_index = _.rfind('-')
|
||||
if current_flag_name or len(_) < 2 or len(_[:flag_prefix_last_symbol_index]) > 3:
|
||||
if current_flag_name or len(_) < 2 or len(_[:_.rfind('-')]) > 3:
|
||||
raise UnprocessedInputFlagException()
|
||||
else:
|
||||
current_flag_name = _
|
||||
else:
|
||||
if not current_flag_name:
|
||||
raise UnprocessedInputFlagException()
|
||||
else:
|
||||
current_flag_value = _
|
||||
if current_flag_name:
|
||||
if not len(list_of_tokens) == k + 1:
|
||||
if not list_of_tokens[k + 1].startswith('-'):
|
||||
continue
|
||||
flag_prefix_last_symbol_index = current_flag_name.rfind('-')
|
||||
flag_prefix = current_flag_name[:flag_prefix_last_symbol_index + 1]
|
||||
flag_name = current_flag_name[flag_prefix_last_symbol_index + 1:]
|
||||
input_flag = InputFlag(name=flag_name,
|
||||
prefix=cast(Literal['-', '--', '---'], flag_prefix))
|
||||
input_flag.set_value(current_flag_value)
|
||||
|
||||
all_flags = [x.get_string_entity() for x in input_flags.get_flags()]
|
||||
if current_flag_name:
|
||||
if not len(list_of_tokens) == k+1:
|
||||
if not list_of_tokens[k+1].startswith('-'): continue
|
||||
|
||||
input_flag = InputFlag(name=current_flag_name[current_flag_name.rfind('-')+1:],
|
||||
prefix=cast(Literal['-', '--', '---'],
|
||||
current_flag_name[:current_flag_name.rfind('-')+1]),
|
||||
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:
|
||||
input_flags.add_flag(input_flag)
|
||||
else:
|
||||
raise RepeatedInputFlagsException(input_flag)
|
||||
|
||||
current_flag_name = None
|
||||
current_flag_value = None
|
||||
current_flag_name, current_flag_value = None, None
|
||||
|
||||
if any([current_flag_name, current_flag_value]):
|
||||
raise UnprocessedInputFlagException()
|
||||
if len(input_flags.get_flags()) == 0:
|
||||
return InputCommand(trigger=command)
|
||||
else:
|
||||
input_command = InputCommand(trigger=command)
|
||||
input_command._set_input_flags(input_flags)
|
||||
return input_command
|
||||
return InputCommand(trigger=command, input_flags=input_flags)
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ from pprint import pprint
|
||||
from rich.console import Console
|
||||
|
||||
from argenta.command import Command
|
||||
from argenta.command.flag.models import Flags, InputFlags
|
||||
from argenta.command.flag.defaults import DefaultFlags
|
||||
from argenta.command.flag import Flags, InputFlags, Flag
|
||||
from argenta.command.flag.defaults import PredeterminedFlags
|
||||
from argenta.router import Router
|
||||
from .handlers_implementation.help_command import help_command
|
||||
|
||||
@@ -22,10 +22,10 @@ def command_help():
|
||||
help_command()
|
||||
|
||||
|
||||
@work_router.command(Command(trigger='P', description='Start Solving', flags=Flags(DefaultFlags.HOST, DefaultFlags.PORT)))
|
||||
@work_router.command(Command(trigger='P', description='Start Solving', flags=Flags(PredeterminedFlags.HOST, PredeterminedFlags.PORT)))
|
||||
def command_start_solving(args: InputFlags):
|
||||
print('Solving...')
|
||||
pprint(args)
|
||||
pprint(args.get_flag('host'))
|
||||
#start_solving_command()
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "argenta"
|
||||
version = "0.4.1"
|
||||
version = "0.4.5"
|
||||
description = "python library for creating custom shells"
|
||||
authors = [
|
||||
{name = "kolo", email = "kolo.is.main@gmail.com"}
|
||||
|
||||
@@ -7,8 +7,8 @@ import re
|
||||
from argenta.app import App
|
||||
from argenta.command import Command
|
||||
from argenta.router import Router
|
||||
from argenta.command.flag.models import Flags
|
||||
from argenta.command.flag.defaults import DefaultFlags
|
||||
from argenta.command.flag.models import Flags, InputFlags
|
||||
from argenta.command.flag.defaults import PredeterminedFlags
|
||||
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_input_correct_command_with_one_correct_flag_an_one_incorrect_flag(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
flags = Flags(DefaultFlags.HOST)
|
||||
flags = Flags(PredeterminedFlags.HOST)
|
||||
|
||||
@router.command(Command('test', flags=flags))
|
||||
def test(args: dict):
|
||||
print(f'connecting to host {args["host"]["value"]}')
|
||||
def test(args: InputFlags):
|
||||
print(f'connecting to host {args.get_flag('host').get_value()}')
|
||||
|
||||
app = App()
|
||||
app.include_router(router)
|
||||
@@ -185,8 +185,8 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
def test_input_correct_command_with_repeated_flags(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('test', flags=DefaultFlags.PORT))
|
||||
def test(args):
|
||||
@router.command(Command('test', flags=PredeterminedFlags.PORT))
|
||||
def test(args: InputFlags):
|
||||
print('test command')
|
||||
|
||||
app = App()
|
||||
|
||||
@@ -8,7 +8,7 @@ from argenta.app import App
|
||||
from argenta.command.models import Command
|
||||
from argenta.router import Router
|
||||
from argenta.command.flag.models import Flag, Flags, InputFlags
|
||||
from argenta.command.flag.defaults import DefaultFlags
|
||||
from argenta.command.flag.defaults import PredeterminedFlags
|
||||
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_input_correct_command_with_default_flag(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
flag = DefaultFlags.SHORT_HELP
|
||||
flag = PredeterminedFlags.SHORT_HELP
|
||||
|
||||
@router.command(Command('test', flags=flag))
|
||||
def test(args: dict):
|
||||
@@ -109,7 +109,7 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_input_correct_command_with_default_flag2(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
flag = DefaultFlags.INFO
|
||||
flag = PredeterminedFlags.INFO
|
||||
|
||||
@router.command(Command('test', flags=flag))
|
||||
def test(args: InputFlags):
|
||||
@@ -129,7 +129,7 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_input_correct_command_with_default_flag3(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
flag = DefaultFlags.HOST
|
||||
flag = PredeterminedFlags.HOST
|
||||
|
||||
@router.command(Command('test', flags=flag))
|
||||
def test(args: InputFlags):
|
||||
@@ -148,7 +148,7 @@ class TestSystemHandlerNormalWork(unittest.TestCase):
|
||||
@patch("sys.stdout", new_callable=io.StringIO)
|
||||
def test_input_correct_command_with_two_flags(self, mock_stdout: _io.StringIO, magick_mock: MagicMock):
|
||||
router = Router()
|
||||
flags = Flags(DefaultFlags.HOST, DefaultFlags.PORT)
|
||||
flags = Flags(PredeterminedFlags.HOST, PredeterminedFlags.PORT)
|
||||
|
||||
@router.command(Command('test', flags=flags))
|
||||
def test(args: InputFlags):
|
||||
|
||||
@@ -8,17 +8,17 @@ import unittest
|
||||
|
||||
class TestInputCommand(unittest.TestCase):
|
||||
def test_parse_correct_raw_command(self):
|
||||
self.assertEqual(InputCommand.parse_input_command('ssh --host 192.168.0.3').get_trigger(), 'ssh')
|
||||
self.assertEqual(InputCommand.parse('ssh --host 192.168.0.3').get_trigger(), 'ssh')
|
||||
|
||||
def test_parse_raw_command_without_flag_name_with_value(self):
|
||||
with self.assertRaises(UnprocessedInputFlagException):
|
||||
InputCommand.parse_input_command('ssh 192.168.0.3')
|
||||
InputCommand.parse('ssh 192.168.0.3')
|
||||
|
||||
def test_parse_raw_command_with_repeated_flag_name(self):
|
||||
with self.assertRaises(RepeatedInputFlagsException):
|
||||
InputCommand.parse_input_command('ssh --host 192.168.0.3 --host 172.198.0.43')
|
||||
InputCommand.parse('ssh --host 192.168.0.3 --host 172.198.0.43')
|
||||
|
||||
def test_parse_empty_raw_command(self):
|
||||
with self.assertRaises(EmptyInputCommandException):
|
||||
InputCommand.parse_input_command('')
|
||||
InputCommand.parse('')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user