mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05:28 +03:00
perffff
This commit is contained in:
+27
-11
@@ -3,7 +3,7 @@ __all__ = ["App"]
|
|||||||
import io
|
import io
|
||||||
import re
|
import re
|
||||||
from contextlib import redirect_stdout
|
from contextlib import redirect_stdout
|
||||||
from typing import Never, TypeAlias
|
from typing import Callable, Never, TypeAlias
|
||||||
|
|
||||||
from art import text2art
|
from art import text2art
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
@@ -30,6 +30,8 @@ from argenta.router import Router
|
|||||||
|
|
||||||
Matches: TypeAlias = list[str] | list[Never]
|
Matches: TypeAlias = list[str] | list[Never]
|
||||||
|
|
||||||
|
_ANSI_ESCAPE_RE: re.Pattern[str] = re.compile(r"\u001b\[[0-9;]*m")
|
||||||
|
|
||||||
|
|
||||||
class BaseApp:
|
class BaseApp:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -58,6 +60,8 @@ class BaseApp:
|
|||||||
self._farewell_message: str = farewell_message
|
self._farewell_message: str = farewell_message
|
||||||
self._initial_message: str = initial_message
|
self._initial_message: str = initial_message
|
||||||
|
|
||||||
|
self._stdout_buffer: io.StringIO = io.StringIO()
|
||||||
|
|
||||||
self._description_message_gen: DescriptionMessageGenerator = (
|
self._description_message_gen: DescriptionMessageGenerator = (
|
||||||
lambda command, description: f"{command} *=*=* {description}"
|
lambda command, description: f"{command} *=*=* {description}"
|
||||||
)
|
)
|
||||||
@@ -160,7 +164,7 @@ class BaseApp:
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if isinstance(self._dividing_line, DynamicDividingLine):
|
if isinstance(self._dividing_line, DynamicDividingLine):
|
||||||
clear_text = re.sub(r"\u001b\[[0-9;]*m", "", text)
|
clear_text = _ANSI_ESCAPE_RE.sub("", text)
|
||||||
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
max_length_line = max([len(line) for line in clear_text.split("\n")])
|
||||||
max_length_line = (
|
max_length_line = (
|
||||||
max_length_line
|
max_length_line
|
||||||
@@ -217,6 +221,18 @@ class BaseApp:
|
|||||||
return True
|
return True
|
||||||
return False
|
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:
|
def _error_handler(self, error: InputCommandException, raw_command: str) -> None:
|
||||||
"""
|
"""
|
||||||
Private. Handles parsing errors of the entered command
|
Private. Handles parsing errors of the entered command
|
||||||
@@ -368,9 +384,9 @@ class BaseApp:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
with redirect_stdout(io.StringIO()) as stdout:
|
stdout_result = self._capture_stdout(
|
||||||
processing_router.finds_appropriate_handler(input_command)
|
lambda: processing_router.finds_appropriate_handler(input_command)
|
||||||
stdout_result: str = stdout.getvalue()
|
)
|
||||||
self._print_framed_text(stdout_result)
|
self._print_framed_text(stdout_result)
|
||||||
|
|
||||||
|
|
||||||
@@ -442,9 +458,9 @@ class App(BaseApp):
|
|||||||
try:
|
try:
|
||||||
input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
|
input_command: InputCommand = InputCommand.parse(raw_command=raw_command)
|
||||||
except InputCommandException as error:
|
except InputCommandException as error:
|
||||||
with redirect_stdout(io.StringIO()) as stderr:
|
stderr_result = self._capture_stdout(
|
||||||
self._error_handler(error, raw_command)
|
lambda: self._error_handler(error, raw_command)
|
||||||
stderr_result: str = stderr.getvalue()
|
)
|
||||||
self._print_framed_text(stderr_result)
|
self._print_framed_text(stderr_result)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -454,9 +470,9 @@ class App(BaseApp):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if self._is_unknown_command(input_command):
|
if self._is_unknown_command(input_command):
|
||||||
with redirect_stdout(io.StringIO()) as stdout:
|
stdout_res = self._capture_stdout(
|
||||||
self._unknown_command_handler(input_command)
|
lambda: self._unknown_command_handler(input_command)
|
||||||
stdout_res: str = stdout.getvalue()
|
)
|
||||||
self._print_framed_text(stdout_res)
|
self._print_framed_text(stdout_res)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
__all__ = ["NonStandardBehaviorHandler", "EmptyCommandHandler", "Printer", "DescriptionMessageGenerator"]
|
__all__ = ["NonStandardBehaviorHandler", "EmptyCommandHandler", "Printer", "DescriptionMessageGenerator", "HandlerFunc"]
|
||||||
|
|
||||||
from typing import Protocol, TypeVar
|
from typing import ParamSpec, Protocol, TypeVar
|
||||||
|
from argenta.response import Response
|
||||||
|
|
||||||
T = TypeVar("T", contravariant=True) # noqa: WPS111
|
T = TypeVar("T", contravariant=True)
|
||||||
|
P = ParamSpec("P")
|
||||||
|
|
||||||
|
|
||||||
class NonStandardBehaviorHandler(Protocol[T]):
|
class NonStandardBehaviorHandler(Protocol[T]):
|
||||||
@@ -23,3 +25,8 @@ class Printer(Protocol):
|
|||||||
class DescriptionMessageGenerator(Protocol):
|
class DescriptionMessageGenerator(Protocol):
|
||||||
def __call__(self, _command: str, _description: str, /) -> str:
|
def __call__(self, _command: str, _description: str, /) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class HandlerFunc(Protocol):
|
||||||
|
def __call__(self, response: Response) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Orchestrator:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
arg_parser: ArgParser = DEFAULT_ARGPARSER,
|
arg_parser: ArgParser = DEFAULT_ARGPARSER,
|
||||||
custom_providers: list[Provider] = [],
|
custom_providers: list[Provider] | None = None,
|
||||||
auto_inject_handlers: bool = True,
|
auto_inject_handlers: bool = True,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@@ -23,7 +23,7 @@ class Orchestrator:
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self._arg_parser: ArgParser = arg_parser
|
self._arg_parser: ArgParser = arg_parser
|
||||||
self._custom_providers: list[Provider] = custom_providers
|
self._custom_providers: list[Provider] = custom_providers or []
|
||||||
self._auto_inject_handlers: bool = auto_inject_handlers
|
self._auto_inject_handlers: bool = auto_inject_handlers
|
||||||
|
|
||||||
self._arg_parser._parse_args() # pyright: ignore[reportPrivateUsage]
|
self._arg_parser._parse_args() # pyright: ignore[reportPrivateUsage]
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
__all__ = ["CommandHandler", "CommandHandlers"]
|
__all__ = ["CommandHandler", "CommandHandlers"]
|
||||||
|
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
from typing import Callable, Never
|
from typing import Never
|
||||||
|
|
||||||
|
from argenta.app.protocols import HandlerFunc
|
||||||
from argenta.command import Command
|
from argenta.command import Command
|
||||||
from argenta.response import Response
|
from argenta.response import Response
|
||||||
|
|
||||||
HandlerFunc = Callable[..., None]
|
|
||||||
|
|
||||||
|
|
||||||
class CommandHandler:
|
class CommandHandler:
|
||||||
def __init__(self, handler_as_func: HandlerFunc, handled_command: Command):
|
def __init__(self, handler_as_func: HandlerFunc, handled_command: Command):
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
__all__ = ["Router"]
|
__all__ = ["Router"]
|
||||||
|
|
||||||
from inspect import get_annotations, getfullargspec, getsourcefile, getsourcelines
|
from inspect import get_annotations, getfullargspec, getsourcefile, getsourcelines
|
||||||
from typing import Callable, TypeAlias
|
from typing import Callable
|
||||||
|
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
|
||||||
|
from argenta.app.protocols import HandlerFunc
|
||||||
from argenta.command import Command, InputCommand
|
from argenta.command import Command, InputCommand
|
||||||
from argenta.command.flag import ValidationStatus
|
from argenta.command.flag import ValidationStatus
|
||||||
from argenta.command.flag.flags import InputFlags
|
from argenta.command.flag.flags import InputFlags
|
||||||
@@ -16,8 +17,6 @@ from argenta.router.exceptions import (RepeatedAliasNameException,
|
|||||||
RequiredArgumentNotPassedException,
|
RequiredArgumentNotPassedException,
|
||||||
TriggerContainSpacesException)
|
TriggerContainSpacesException)
|
||||||
|
|
||||||
HandlerFunc: TypeAlias = Callable[..., None]
|
|
||||||
|
|
||||||
|
|
||||||
class Router:
|
class Router:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -176,8 +175,7 @@ def _validate_func_args(func: HandlerFunc) -> None:
|
|||||||
|
|
||||||
response_arg_annotation = func_annotations.get(response_arg)
|
response_arg_annotation = func_annotations.get(response_arg)
|
||||||
|
|
||||||
if response_arg_annotation is not None:
|
if response_arg_annotation is not None and response_arg_annotation is not Response:
|
||||||
if response_arg_annotation is not Response:
|
|
||||||
source_line: int = getsourcelines(func)[1]
|
source_line: int = getsourcelines(func)[1]
|
||||||
Console().print(
|
Console().print(
|
||||||
f'\nFile "{getsourcefile(func)}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
|
f'\nFile "{getsourcefile(func)}", line {source_line}\n[b red]WARNING:[/b red] [i]The typehint '
|
||||||
|
|||||||
Reference in New Issue
Block a user