mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 01:55:29 +03:00
viewr
This commit is contained in:
@@ -19,7 +19,7 @@ def test_input_incorrect_command(capsys: CaptureFixture[str]):
|
||||
def test(response: Response) -> None:
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_unknown_command_handler(
|
||||
lambda command: print(f'Unknown command: {command.trigger}')
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
from argenta import App, Orchestrator
|
||||
from argenta.app import DynamicDividingLine
|
||||
from .handlers import router
|
||||
|
||||
|
||||
app = App(initial_message="metrics", override_system_messages=False)
|
||||
app = App(initial_message="metrics", dividing_line=DynamicDividingLine('~'), override_system_messages=True)
|
||||
orchestrator = Orchestrator()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from rich.console import Console
|
||||
|
||||
Console().print('[red]hi[/red]')
|
||||
@@ -1,6 +1,6 @@
|
||||
from rich.markup import escape
|
||||
|
||||
from argenta import Response
|
||||
from argenta.response.entity import Response
|
||||
from argenta.app.presentation.renderers import Renderer
|
||||
from argenta.app.protocols import (
|
||||
NonStandardBehaviorHandler,
|
||||
@@ -53,7 +53,7 @@ class BehaviorHandlersFabric:
|
||||
return unknown_command_handler
|
||||
|
||||
def generate_exit_command_handler(self, farewell_message: str) -> NonStandardBehaviorHandler[Response]:
|
||||
return lambda _: self._printer(self._renderer.render_farewell_message(farewell_message))
|
||||
return lambda _: self._printer(farewell_message)
|
||||
|
||||
def generate_description_message_generator(self) -> DescriptionMessageGenerator:
|
||||
return lambda command, description: self._renderer.render_text_for_description_message_generator(
|
||||
|
||||
@@ -41,9 +41,9 @@ class StaticDividingLine(BaseDividingLine):
|
||||
:return: full line of dividing line as str
|
||||
"""
|
||||
if is_override:
|
||||
return f"\n{self.length * self.get_unit_part()}\n"
|
||||
return self.length * self.get_unit_part()
|
||||
else:
|
||||
return f"\n[dim]{self.length * self.get_unit_part()}[/dim]\n"
|
||||
return f"[dim]{self.length * self.get_unit_part()}[/dim]"
|
||||
|
||||
|
||||
class DynamicDividingLine(BaseDividingLine):
|
||||
@@ -63,6 +63,6 @@ class DynamicDividingLine(BaseDividingLine):
|
||||
:return: full line of dividing line as str
|
||||
"""
|
||||
if is_override:
|
||||
return f"\n{length * self.get_unit_part()}\n"
|
||||
return length * self.get_unit_part()
|
||||
else:
|
||||
return f"\n[dim]{self.get_unit_part() * length}[/dim]\n"
|
||||
return f"[dim]{self.get_unit_part() * length}[/dim]"
|
||||
|
||||
+28
-100
@@ -1,9 +1,6 @@
|
||||
__all__ = ["App"]
|
||||
|
||||
import io
|
||||
import re
|
||||
from contextlib import redirect_stdout
|
||||
from typing import Callable, Never, TypeAlias
|
||||
from typing import Never, TypeAlias
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
@@ -31,7 +28,6 @@ from argenta.router import Router
|
||||
|
||||
|
||||
Matches: TypeAlias = list[str] | list[Never]
|
||||
_ANSI_ESCAPE_RE: re.Pattern[str] = re.compile(r"\u001b\[[0-9;]*m")
|
||||
|
||||
|
||||
class BaseApp:
|
||||
@@ -47,10 +43,10 @@ class BaseApp:
|
||||
repeat_command_groups_printing: bool,
|
||||
override_system_messages: bool,
|
||||
autocompleter: AutoCompleter,
|
||||
print_func: Printer,
|
||||
printer: Printer,
|
||||
) -> None:
|
||||
self._prompt: str = prompt
|
||||
self._print_func: Printer = print_func
|
||||
self._printer: Printer = printer
|
||||
self._exit_command: Command = exit_command
|
||||
self._dividing_line: StaticDividingLine | DynamicDividingLine | None = dividing_line
|
||||
self._repeat_command_groups_printing: bool = repeat_command_groups_printing
|
||||
@@ -58,7 +54,6 @@ class BaseApp:
|
||||
self._autocompleter: AutoCompleter = autocompleter
|
||||
self._system_router: Router = Router(title=system_router_title)
|
||||
|
||||
self._stdout_buffer: io.StringIO = io.StringIO()
|
||||
self.registered_routers: RegisteredRouters = RegisteredRouters()
|
||||
self._messages_on_startup: list[str] = []
|
||||
|
||||
@@ -67,11 +62,16 @@ class BaseApp:
|
||||
else:
|
||||
self._renderer: Renderer = RichRenderer()
|
||||
|
||||
self._viewer: Viewer = Viewer(self._print_func, self._renderer)
|
||||
self._viewer: Viewer = Viewer(
|
||||
printer=self._printer,
|
||||
renderer=self._renderer,
|
||||
dividing_line=self._dividing_line,
|
||||
override_system_messages=self._override_system_messages,
|
||||
)
|
||||
self._handlers_fabric: BehaviorHandlersFabric = BehaviorHandlersFabric(
|
||||
self._print_func,
|
||||
self._renderer,
|
||||
self._most_similar_command
|
||||
printer=self._printer,
|
||||
renderer=self._renderer,
|
||||
most_similar_command_getter=self._most_similar_command
|
||||
)
|
||||
|
||||
self._initial_message: str = self._renderer.render_initial_message(initial_message)
|
||||
@@ -131,34 +131,6 @@ class BaseApp:
|
||||
"""
|
||||
self._exit_command_handler = _
|
||||
|
||||
def _print_static_framed_text(self, text: str) -> None:
|
||||
"""
|
||||
Private. Outputs text by framing it in a static or dynamic split strip
|
||||
:param text: framed text
|
||||
:return: None
|
||||
"""
|
||||
match self._dividing_line:
|
||||
case StaticDividingLine() as dividing_line:
|
||||
self._print_func(dividing_line.get_full_static_line(is_override=self._override_system_messages))
|
||||
print(text.strip("\n"))
|
||||
self._print_func(dividing_line.get_full_static_line(is_override=self._override_system_messages))
|
||||
case DynamicDividingLine() as dividing_line:
|
||||
self._print_func(
|
||||
StaticDividingLine(dividing_line.get_unit_part()).get_full_static_line(
|
||||
is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
print(text.strip("\n"))
|
||||
self._print_func(
|
||||
StaticDividingLine(dividing_line.get_unit_part()).get_full_static_line(
|
||||
is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
case None:
|
||||
print("\n" + text.strip("\n") + "\n")
|
||||
case _:
|
||||
raise NotImplementedError(f"Dividing line with type {self._dividing_line} is not implemented")
|
||||
|
||||
def _is_exit_command(self, command: InputCommand) -> bool:
|
||||
"""
|
||||
Private. Checks if the given command is an exit command
|
||||
@@ -178,18 +150,6 @@ class BaseApp:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _capture_stdout(self, func: Callable[[], None]) -> str:
|
||||
"""
|
||||
Private. Captures stdout from a function call using a reusable buffer
|
||||
:param func: function to execute with captured stdout
|
||||
:return: captured stdout as string
|
||||
"""
|
||||
self._stdout_buffer.seek(0)
|
||||
self._stdout_buffer.truncate(0)
|
||||
with redirect_stdout(self._stdout_buffer):
|
||||
func()
|
||||
return self._stdout_buffer.getvalue()
|
||||
|
||||
def _error_handler(self, error: InputCommandException, raw_command: str) -> None:
|
||||
"""
|
||||
Private. Handles parsing errors of the entered command
|
||||
@@ -276,46 +236,14 @@ class BaseApp:
|
||||
if not processing_router:
|
||||
raise RuntimeError(f"Router for '{input_command.trigger}' not found. Panic!")
|
||||
|
||||
match (self._dividing_line, processing_router.disable_redirect_stdout):
|
||||
case (None, bool()):
|
||||
processing_router.finds_appropriate_handler(input_command)
|
||||
case (DynamicDividingLine(), False):
|
||||
stdout_result = self._capture_stdout(lambda: processing_router.finds_appropriate_handler(input_command))
|
||||
clear_text = _ANSI_ESCAPE_RE.sub("", stdout_result)
|
||||
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
||||
max_length_line = (
|
||||
max_length_line if 10 <= max_length_line <= 100 else 100 if max_length_line > 100 else 10
|
||||
)
|
||||
|
||||
self._print_func(
|
||||
self._dividing_line.get_full_dynamic_line(
|
||||
length=max_length_line, is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
print(clear_text.strip("\n"))
|
||||
self._print_func(
|
||||
self._dividing_line.get_full_dynamic_line(
|
||||
length=max_length_line, is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
case (StaticDividingLine() as dividing_line, bool()) | (DynamicDividingLine() as dividing_line, True):
|
||||
self._print_func(
|
||||
StaticDividingLine(dividing_line.get_unit_part()).get_full_static_line(
|
||||
is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
processing_router.finds_appropriate_handler(input_command)
|
||||
self._print_func(
|
||||
StaticDividingLine(dividing_line.get_unit_part()).get_full_static_line(
|
||||
is_override=self._override_system_messages
|
||||
)
|
||||
)
|
||||
case _:
|
||||
raise NotImplementedError(f"Dividing line with type {self._dividing_line} is not implemented")
|
||||
self._viewer.view_framed_text_from_generator(
|
||||
output_text_generator=lambda: processing_router.finds_appropriate_handler(input_command),
|
||||
is_stdout_redirected_by_router=processing_router.is_redirect_stdout_disabled
|
||||
)
|
||||
|
||||
|
||||
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine
|
||||
DEFAULT_PRINT_FUNC: Printer = Console().print
|
||||
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine | None
|
||||
DEFAULT_PRINTER: Printer = Console().print
|
||||
DEFAULT_EXIT_COMMAND: Command = Command("q", description="Exit command")
|
||||
|
||||
|
||||
@@ -328,11 +256,11 @@ class App(BaseApp):
|
||||
farewell_message: str = "See you",
|
||||
exit_command: Command = DEFAULT_EXIT_COMMAND,
|
||||
system_router_title: str = "System points:",
|
||||
dividing_line: AVAILABLE_DIVIDING_LINES | None = None,
|
||||
dividing_line: AVAILABLE_DIVIDING_LINES = None,
|
||||
repeat_command_groups_printing: bool = False,
|
||||
override_system_messages: bool = False,
|
||||
autocompleter: AutoCompleter | None = None,
|
||||
print_func: Printer = DEFAULT_PRINT_FUNC,
|
||||
printer: Printer = DEFAULT_PRINTER,
|
||||
) -> None:
|
||||
"""
|
||||
Public. The essence of the application itself.
|
||||
@@ -346,7 +274,7 @@ class App(BaseApp):
|
||||
:param repeat_command_groups_printing: whether to repeat the available commands and their description
|
||||
:param override_system_messages: whether to redefine the default formatting of system messages
|
||||
:param autocompleter: the entity of the autocompleter
|
||||
:param print_func: system messages text output function
|
||||
:param printer: system messages text output function
|
||||
:return: None
|
||||
"""
|
||||
super().__init__(
|
||||
@@ -359,7 +287,7 @@ class App(BaseApp):
|
||||
repeat_command_groups_printing=repeat_command_groups_printing,
|
||||
override_system_messages=override_system_messages,
|
||||
autocompleter=autocompleter or AutoCompleter(),
|
||||
print_func=print_func,
|
||||
printer=printer,
|
||||
)
|
||||
|
||||
def run_polling(self) -> None:
|
||||
@@ -367,7 +295,7 @@ class App(BaseApp):
|
||||
Private. Starts the user input processing cycle
|
||||
:return: None
|
||||
"""
|
||||
self._print_func(self._initial_message)
|
||||
self._viewer.view_initial_message(self._initial_message)
|
||||
self._pre_cycle_setup()
|
||||
while True:
|
||||
if self._repeat_command_groups_printing:
|
||||
@@ -380,10 +308,9 @@ class App(BaseApp):
|
||||
try:
|
||||
input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
|
||||
except InputCommandException as error: # noqa F841
|
||||
stderr_result = self._capture_stdout(
|
||||
lambda: self._error_handler(error, raw_command) # noqa F821
|
||||
self._viewer.view_framed_text_from_generator(
|
||||
output_text_generator=lambda: self._error_handler(error, raw_command)
|
||||
)
|
||||
self._print_static_framed_text(stderr_result)
|
||||
continue
|
||||
|
||||
if self._is_exit_command(input_command):
|
||||
@@ -391,8 +318,9 @@ class App(BaseApp):
|
||||
return
|
||||
|
||||
if self._is_unknown_command(input_command):
|
||||
stdout_res = self._capture_stdout(lambda: self._unknown_command_handler(input_command))
|
||||
self._print_static_framed_text(stdout_res)
|
||||
self._viewer.view_framed_text_from_generator(
|
||||
output_text_generator=lambda: self._unknown_command_handler(input_command)
|
||||
)
|
||||
continue
|
||||
|
||||
self._process_exist_and_valid_command(input_command)
|
||||
|
||||
@@ -78,7 +78,7 @@ class RichRenderer(Renderer):
|
||||
|
||||
@staticmethod
|
||||
def render_messages_on_startup(messages: Iterable[str]) -> str:
|
||||
return "\n".join(messages)
|
||||
return "\n" + "\n".join(messages)
|
||||
|
||||
@staticmethod
|
||||
def render_command_groups_description(
|
||||
@@ -87,10 +87,10 @@ class RichRenderer(Renderer):
|
||||
) -> str:
|
||||
command_groups_description = ""
|
||||
for registered_router in registered_routers:
|
||||
command_groups_description += "\n" + registered_router.title
|
||||
command_groups_description += "\n\n" + registered_router.title
|
||||
for command_handler in registered_router.command_handlers:
|
||||
handled_command = command_handler.handled_command
|
||||
command_groups_description += description_message_generator(
|
||||
command_groups_description += '\n' + description_message_generator(
|
||||
handled_command.trigger,
|
||||
handled_command.description,
|
||||
)
|
||||
@@ -114,7 +114,7 @@ class RichRenderer(Renderer):
|
||||
most_similar_command_trigger: str | None
|
||||
) -> str:
|
||||
return (
|
||||
f"[red]Unknown command:[/red][blue]{command_trigger}[/blue]"
|
||||
f"[red]Unknown command:[/red] [blue]{command_trigger}[/blue]"
|
||||
+ (f"[red], most similar:[/red][blue]{most_similar_command_trigger}[/blue]"
|
||||
if most_similar_command_trigger else "")
|
||||
)
|
||||
@@ -131,14 +131,14 @@ class PlainRenderer(Renderer):
|
||||
|
||||
@staticmethod
|
||||
def render_farewell_message(text: str) -> str:
|
||||
return f"{text} | [https://github.com/koloideal/Argenta](https://github.com/koloideal/Argenta) | made by kolo"
|
||||
return f"\n{text} | https://github.com/koloideal/Argenta | made by kolo"
|
||||
|
||||
@staticmethod
|
||||
def render_text_for_description_message_generator(command: str, description: str) -> str:
|
||||
return f"{command} *=*=* {description}"
|
||||
|
||||
def render_messages_on_startup(self, messages: Iterable[str]) -> str:
|
||||
return "\n".join(messages)
|
||||
return "\n" + "\n".join(messages)
|
||||
|
||||
@staticmethod
|
||||
def render_command_groups_description(
|
||||
@@ -147,10 +147,10 @@ class PlainRenderer(Renderer):
|
||||
) -> str:
|
||||
command_groups_description = ""
|
||||
for registered_router in registered_routers:
|
||||
command_groups_description += "\n" + registered_router.title
|
||||
command_groups_description += "\n\n" + registered_router.title
|
||||
for command_handler in registered_router.command_handlers:
|
||||
handled_command = command_handler.handled_command
|
||||
command_groups_description += description_message_generator(
|
||||
command_groups_description += "\n" + description_message_generator(
|
||||
handled_command.trigger,
|
||||
handled_command.description,
|
||||
)
|
||||
@@ -175,7 +175,7 @@ class PlainRenderer(Renderer):
|
||||
) -> str:
|
||||
return (
|
||||
f"Unknown command: {command_trigger}"
|
||||
+ (f", most similar:{most_similar_command_trigger}"
|
||||
+ (f", most similar: {most_similar_command_trigger}"
|
||||
if most_similar_command_trigger else "")
|
||||
)
|
||||
|
||||
|
||||
@@ -1,14 +1,43 @@
|
||||
from typing import Iterable
|
||||
__all__ = ["Viewer"]
|
||||
|
||||
import re
|
||||
from contextlib import redirect_stdout
|
||||
from io import StringIO
|
||||
from typing import Iterable, Callable, TypeAlias
|
||||
|
||||
from rich.text import Text
|
||||
|
||||
from argenta.app import StaticDividingLine, DynamicDividingLine
|
||||
from argenta.app.presentation.renderers import Renderer
|
||||
from argenta.app.protocols import Printer, DescriptionMessageGenerator
|
||||
from argenta.app.registered_routers.entity import RegisteredRouters
|
||||
|
||||
|
||||
AVAILABLE_DIVIDING_LINES: TypeAlias = StaticDividingLine | DynamicDividingLine | None
|
||||
|
||||
|
||||
class Viewer:
|
||||
def __init__(self, printer: Printer, renderer: Renderer):
|
||||
ANSI_ESCAPE_RE: re.Pattern[str] = re.compile(r"\u001b\[[0-9;]*m")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
printer: Printer,
|
||||
renderer: Renderer,
|
||||
dividing_line: AVAILABLE_DIVIDING_LINES,
|
||||
override_system_messages: bool
|
||||
):
|
||||
self._printer = printer
|
||||
self._renderer = renderer
|
||||
self._dividing_line = dividing_line
|
||||
self._override_system_messages = override_system_messages
|
||||
self._stdout_buffer: StringIO = StringIO()
|
||||
|
||||
def _capture_stdout(self, func: Callable[[], None]) -> str:
|
||||
self._stdout_buffer.seek(0)
|
||||
self._stdout_buffer.truncate(0)
|
||||
with redirect_stdout(self._stdout_buffer):
|
||||
func()
|
||||
return self._stdout_buffer.getvalue()
|
||||
|
||||
def view_messages_on_startup(self, messages: Iterable[str]) -> None:
|
||||
self._printer(self._renderer.render_messages_on_startup(messages))
|
||||
@@ -25,3 +54,43 @@ class Viewer:
|
||||
)
|
||||
)
|
||||
|
||||
def view_initial_message(self, initial_message: str) -> None:
|
||||
self._printer(initial_message)
|
||||
|
||||
def view_framed_text_from_generator(
|
||||
self,
|
||||
output_text_generator: Callable[[], None],
|
||||
is_stdout_redirected_by_router: bool = False,
|
||||
) -> None:
|
||||
match (self._dividing_line, is_stdout_redirected_by_router):
|
||||
case (None, bool()):
|
||||
output_text_generator()
|
||||
case (DynamicDividingLine(), False):
|
||||
stdout_result = self._capture_stdout(
|
||||
lambda: output_text_generator()
|
||||
)
|
||||
clear_text = self.ANSI_ESCAPE_RE.sub("", stdout_result)
|
||||
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
||||
max_length_line = (
|
||||
max_length_line
|
||||
if 10 <= max_length_line <= 100
|
||||
else 100
|
||||
if max_length_line > 100
|
||||
else 10
|
||||
)
|
||||
dividing_line_as_str: str = self._dividing_line.get_full_dynamic_line(
|
||||
length=max_length_line, is_override=self._override_system_messages
|
||||
)
|
||||
self._printer(dividing_line_as_str + "\n")
|
||||
self._printer(Text.from_ansi(stdout_result.strip("\n")).markup)
|
||||
self._printer('\n' + dividing_line_as_str)
|
||||
|
||||
case (StaticDividingLine() as dividing_line, bool()) | (DynamicDividingLine() as dividing_line, True):
|
||||
dividing_line_as_str: str = StaticDividingLine(dividing_line.get_unit_part()).get_full_static_line(
|
||||
is_override=self._override_system_messages
|
||||
)
|
||||
self._printer(dividing_line_as_str + '\n')
|
||||
output_text_generator()
|
||||
self._printer('\n' + dividing_line_as_str)
|
||||
case _:
|
||||
raise NotImplementedError(f"Dividing line with type {self._dividing_line} is not implemented")
|
||||
|
||||
@@ -35,7 +35,7 @@ class Router:
|
||||
:return: None
|
||||
"""
|
||||
self.title: str = title
|
||||
self.disable_redirect_stdout: bool = disable_redirect_stdout
|
||||
self.is_redirect_stdout_disabled: bool = disable_redirect_stdout
|
||||
|
||||
self.command_handlers: CommandHandlers = CommandHandlers()
|
||||
self.aliases: set[str] = set()
|
||||
@@ -56,7 +56,7 @@ class Router:
|
||||
self._update_routing_keys(redefined_command)
|
||||
|
||||
def decorator(func: HandlerFunc) -> HandlerFunc:
|
||||
_validate_func_args(func)
|
||||
self._validate_func_args(func)
|
||||
self.command_handlers.add_handler(CommandHandler(func, redefined_command))
|
||||
return func
|
||||
|
||||
@@ -116,7 +116,7 @@ class Router:
|
||||
handle_command = command_handler.handled_command
|
||||
if handle_command.registered_flags.flags:
|
||||
if input_command_flags.flags:
|
||||
response: Response = _structuring_input_flags(handle_command, input_command_flags)
|
||||
response: Response = self._structuring_input_flags(handle_command, input_command_flags)
|
||||
command_handler.handling(response)
|
||||
else:
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
@@ -133,53 +133,53 @@ class Router:
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
command_handler.handling(response)
|
||||
|
||||
@staticmethod
|
||||
def _structuring_input_flags(handled_command: Command, input_flags: InputFlags) -> Response:
|
||||
"""
|
||||
Private. Validates flags of input command
|
||||
:param handled_command: entity of the handled command
|
||||
:param input_flags:
|
||||
:return: entity of response as Response
|
||||
"""
|
||||
invalid_value_flags, undefined_flags = False, False
|
||||
|
||||
def _structuring_input_flags(handled_command: Command, input_flags: InputFlags) -> Response:
|
||||
"""
|
||||
Private. Validates flags of input command
|
||||
:param handled_command: entity of the handled command
|
||||
:param input_flags:
|
||||
:return: entity of response as Response
|
||||
"""
|
||||
invalid_value_flags, undefined_flags = False, False
|
||||
for flag in input_flags:
|
||||
flag_status: ValidationStatus = handled_command.validate_input_flag(flag)
|
||||
flag.status = flag_status
|
||||
if flag_status == ValidationStatus.INVALID:
|
||||
invalid_value_flags = True
|
||||
elif flag_status == ValidationStatus.UNDEFINED:
|
||||
undefined_flags = True
|
||||
|
||||
for flag in input_flags:
|
||||
flag_status: ValidationStatus = handled_command.validate_input_flag(flag)
|
||||
flag.status = flag_status
|
||||
if flag_status == ValidationStatus.INVALID:
|
||||
invalid_value_flags = True
|
||||
elif flag_status == ValidationStatus.UNDEFINED:
|
||||
undefined_flags = True
|
||||
|
||||
status = ResponseStatus.from_flags(
|
||||
has_invalid_value_flags=invalid_value_flags,
|
||||
has_undefined_flags=undefined_flags
|
||||
)
|
||||
|
||||
return Response(status=status, input_flags=input_flags)
|
||||
|
||||
|
||||
def _validate_func_args(func: HandlerFunc) -> None:
|
||||
"""
|
||||
Private. Validates the arguments of the handler
|
||||
:param func: entity of the handler func
|
||||
:return: None if func is valid else raise exception
|
||||
"""
|
||||
transferred_args = getfullargspec(func).args
|
||||
if len(transferred_args) == 0:
|
||||
raise RequiredArgumentNotPassedException()
|
||||
|
||||
response_arg: str = transferred_args[0]
|
||||
func_annotations: dict[str, None] = get_annotations(func)
|
||||
|
||||
response_arg_annotation = func_annotations.get(response_arg)
|
||||
|
||||
if response_arg_annotation is not None and response_arg_annotation is not Response:
|
||||
source_line: int = getsourcelines(func)[1]
|
||||
Console().print(
|
||||
f'\nFile "{getsourcefile(func)}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
|
||||
+ f"of argument([green]{response_arg}[/green]) passed to the handler must be [/i][bold blue]{Response}[/bold blue],"
|
||||
+ f" [i]but[/i] [bold blue]{response_arg_annotation}[/bold blue] [i]is specified[/i]",
|
||||
highlight=False,
|
||||
status = ResponseStatus.from_flags(
|
||||
has_invalid_value_flags=invalid_value_flags,
|
||||
has_undefined_flags=undefined_flags
|
||||
)
|
||||
|
||||
return Response(status=status, input_flags=input_flags)
|
||||
|
||||
@staticmethod
|
||||
def _validate_func_args(func: HandlerFunc) -> None:
|
||||
"""
|
||||
Private. Validates the arguments of the handler
|
||||
:param func: entity of the handler func
|
||||
:return: None if func is valid else raise exception
|
||||
"""
|
||||
transferred_args = getfullargspec(func).args
|
||||
if len(transferred_args) == 0:
|
||||
raise RequiredArgumentNotPassedException()
|
||||
|
||||
response_arg: str = transferred_args[0]
|
||||
func_annotations: dict[str, None] = get_annotations(func)
|
||||
|
||||
response_arg_annotation = func_annotations.get(response_arg)
|
||||
|
||||
if response_arg_annotation is not None and response_arg_annotation is not Response:
|
||||
source_line: int = getsourcelines(func)[1]
|
||||
Console().print(
|
||||
f'\nFile "{getsourcefile(func)}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
|
||||
+ f"of argument([green]{response_arg}[/green]) passed to the handler must be [/i][bold blue]{Response}[/bold blue],"
|
||||
+ f" [i]but[/i] [bold blue]{response_arg_annotation}[/bold blue] [i]is specified[/i]",
|
||||
highlight=False,
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ def test_empty_input_triggers_empty_command_handler(monkeypatch: pytest.MonkeyPa
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_empty_command_handler(lambda: print('Empty input command'))
|
||||
orchestrator.start_polling(app)
|
||||
@@ -61,7 +61,7 @@ def test_unknown_command_triggers_unknown_command_handler(monkeypatch: pytest.Mo
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.trigger}'))
|
||||
orchestrator.start_polling(app)
|
||||
@@ -82,7 +82,7 @@ def test_mixed_valid_and_unknown_commands_handled_correctly(monkeypatch: pytest.
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.trigger}'))
|
||||
orchestrator.start_polling(app)
|
||||
@@ -107,7 +107,7 @@ def test_multiple_commands_with_unknown_command_in_between(monkeypatch: pytest.M
|
||||
def test1(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('more command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_unknown_command_handler(lambda command: print(f'Unknown command: {command.trigger}'))
|
||||
orchestrator.start_polling(app)
|
||||
@@ -135,7 +135,7 @@ def test_unregistered_flag_without_value_is_accessible(monkeypatch: pytest.Monke
|
||||
if undefined_flag and undefined_flag.status == ValidationStatus.UNDEFINED:
|
||||
print(f'test command with undefined flag: {undefined_flag.string_entity}')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -159,7 +159,7 @@ def test_unregistered_flag_with_value_is_accessible(monkeypatch: pytest.MonkeyPa
|
||||
else:
|
||||
raise
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -182,7 +182,7 @@ def test_registered_and_unregistered_flags_coexist(monkeypatch: pytest.MonkeyPat
|
||||
if undefined_flag and undefined_flag.status == ValidationStatus.UNDEFINED:
|
||||
print(f'connecting to host with flag: {undefined_flag.string_entity} {undefined_flag.input_value}')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -207,7 +207,7 @@ def test_flag_without_value_triggers_incorrect_syntax_handler(monkeypatch: pytes
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_incorrect_input_syntax_handler(lambda command: print(f'Incorrect flag syntax: "{command}"'))
|
||||
orchestrator.start_polling(app)
|
||||
@@ -233,7 +233,7 @@ def test_repeated_flags_trigger_repeated_flags_handler(monkeypatch: pytest.Monke
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
app.set_repeated_input_flags_handler(lambda command: print(f'Repeated input flags: "{command}"'))
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -36,7 +36,7 @@ def test_simple_command_executes_successfully(monkeypatch: pytest.MonkeyPatch, c
|
||||
def test(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -60,7 +60,7 @@ def test_two_commands_execute_sequentially(monkeypatch: pytest.MonkeyPatch, caps
|
||||
def test2(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('some command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -88,7 +88,7 @@ def test_three_commands_execute_sequentially(monkeypatch: pytest.MonkeyPatch, ca
|
||||
def test2(_response: Response) -> None: # pyright: ignore[reportUnusedFunction]
|
||||
print('more command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -116,7 +116,7 @@ def test_custom_flag_without_value_is_recognized(monkeypatch: pytest.MonkeyPatch
|
||||
if valid_flag and valid_flag.status == ValidationStatus.VALID:
|
||||
print(f'\nhelp for {valid_flag.name} flag\n')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -139,7 +139,7 @@ def test_custom_flag_with_regex_validation_accepts_valid_value(monkeypatch: pyte
|
||||
if valid_flag and valid_flag.status == ValidationStatus.VALID:
|
||||
print(f'flag value for {valid_flag.name} flag : {valid_flag.input_value}')
|
||||
|
||||
app = App(override_system_messages=True, repeat_command_groups_printing=True, print_func=print)
|
||||
app = App(override_system_messages=True, repeat_command_groups_printing=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -167,7 +167,7 @@ def test_predefined_short_help_flag_is_recognized(monkeypatch: pytest.MonkeyPatc
|
||||
if valid_flag and valid_flag.status == ValidationStatus.VALID:
|
||||
print(f'help for {valid_flag.name} flag')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -190,7 +190,7 @@ def test_predefined_info_flag_is_recognized(monkeypatch: pytest.MonkeyPatch, cap
|
||||
if valid_flag and valid_flag.status == ValidationStatus.VALID:
|
||||
print('info about test command')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -213,7 +213,7 @@ def test_predefined_host_flag_with_value_is_recognized(monkeypatch: pytest.Monke
|
||||
if valid_flag and valid_flag.status == ValidationStatus.VALID:
|
||||
print(f'connecting to host {valid_flag.input_value}')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
@@ -242,7 +242,7 @@ def test_two_predefined_flags_are_recognized_together(monkeypatch: pytest.Monkey
|
||||
if (host_flag and host_flag.status == ValidationStatus.VALID) and (port_flag and port_flag.status == ValidationStatus.VALID):
|
||||
print(f'connecting to host {host_flag.input_value} and port {port_flag.input_value}')
|
||||
|
||||
app = App(override_system_messages=True, print_func=print)
|
||||
app = App(override_system_messages=True, printer=print)
|
||||
app.include_router(router)
|
||||
orchestrator.start_polling(app)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user