mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05:28 +03:00
Update documentation and code snippets
This commit is contained in:
+2
-2
@@ -29,8 +29,8 @@ html_static_path = ["_static"]
|
||||
|
||||
html_context = {
|
||||
"languages": [
|
||||
("English", "/en/latest/%s/", "en"),
|
||||
("Русский", "/ru/latest/%s/", "ru"),
|
||||
("English", "/en/latest/%s.html", "en"),
|
||||
("Русский", "/ru/latest/%s.html", "ru"),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ from argenta.command.exceptions import (
|
||||
RepeatedInputFlagsException,
|
||||
UnprocessedInputFlagException,
|
||||
)
|
||||
from argenta.router.exceptions import RepeatedAliasNameException, RepeatedTriggerNameException
|
||||
from argenta.command.models import Command, InputCommand
|
||||
from argenta.response import Response
|
||||
from argenta.router import Router
|
||||
@@ -274,6 +275,28 @@ class BaseApp:
|
||||
self.system_router.command_register_ignore = self._ignore_command_register
|
||||
self.registered_routers.add_registered_router(self.system_router)
|
||||
|
||||
def _validate_routers_for_collisions(self) -> None:
|
||||
"""
|
||||
Private. Validates that there are no trigger/alias collisions between routers
|
||||
:return: None
|
||||
:raises: RepeatedTriggerNameException or RepeatedAliasNameException if collision detected
|
||||
"""
|
||||
|
||||
all_triggers: set[str] = set()
|
||||
all_aliases: set[str] = set()
|
||||
|
||||
for router_entity in self.registered_routers:
|
||||
trigger_collisions: set[str] = (all_triggers | all_aliases) & router_entity.triggers
|
||||
if trigger_collisions:
|
||||
raise RepeatedTriggerNameException()
|
||||
|
||||
alias_collisions: set[str] = (all_aliases | all_triggers) & router_entity.aliases
|
||||
if alias_collisions:
|
||||
raise RepeatedAliasNameException(alias_collisions)
|
||||
|
||||
all_triggers.update(router_entity.triggers)
|
||||
all_aliases.update(router_entity.aliases)
|
||||
|
||||
def _most_similar_command(self, unknown_command: str) -> str | None:
|
||||
all_commands = list(self._current_matching_triggers_with_routers.keys())
|
||||
|
||||
@@ -344,6 +367,7 @@ class BaseApp:
|
||||
:return: None
|
||||
"""
|
||||
self._setup_system_router()
|
||||
self._validate_routers_for_collisions()
|
||||
|
||||
for router_entity in self.registered_routers:
|
||||
router_triggers = router_entity.triggers
|
||||
|
||||
@@ -81,6 +81,9 @@ class Router:
|
||||
if command_name.lower() in self.triggers:
|
||||
raise RepeatedTriggerNameException()
|
||||
|
||||
if command_name.lower() in self.aliases:
|
||||
raise RepeatedAliasNameException({command_name.lower()})
|
||||
|
||||
if overlapping := (self.aliases | self.triggers) & set(map(lambda x: x.lower(), command.aliases)):
|
||||
raise RepeatedAliasNameException(overlapping)
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
__all__ = ["RepeatedFlagNameException", "RequiredArgumentNotPassedException", "TriggerContainSpacesException"]
|
||||
__all__ = [
|
||||
"RepeatedFlagNameException",
|
||||
"RepeatedTriggerNameException",
|
||||
"RepeatedAliasNameException",
|
||||
"RequiredArgumentNotPassedException",
|
||||
"TriggerContainSpacesException",
|
||||
]
|
||||
|
||||
from typing import override
|
||||
|
||||
|
||||
@@ -221,6 +221,90 @@ def test_overlapping_aliases_raises_exception() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_app_detects_trigger_collision_between_routers() -> None:
|
||||
from argenta.router.exceptions import RepeatedTriggerNameException
|
||||
|
||||
app = App()
|
||||
router1 = Router()
|
||||
router2 = Router()
|
||||
|
||||
@router1.command('hello')
|
||||
def handler1(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router2.command('hello')
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_router(router1)
|
||||
app.include_router(router2)
|
||||
|
||||
with pytest.raises(RepeatedTriggerNameException):
|
||||
app._pre_cycle_setup()
|
||||
|
||||
|
||||
def test_app_detects_alias_collision_between_routers() -> None:
|
||||
app = App()
|
||||
router1 = Router()
|
||||
router2 = Router()
|
||||
|
||||
@router1.command(Command('hello', aliases={'hi'}))
|
||||
def handler1(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router2.command(Command('world', aliases={'hi'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_router(router1)
|
||||
app.include_router(router2)
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
app._pre_cycle_setup()
|
||||
|
||||
|
||||
def test_app_detects_trigger_alias_collision_between_routers() -> None:
|
||||
app = App()
|
||||
router1 = Router()
|
||||
router2 = Router()
|
||||
|
||||
@router1.command('hello')
|
||||
def handler1(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router2.command(Command('world', aliases={'hello'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_router(router1)
|
||||
app.include_router(router2)
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
app._pre_cycle_setup()
|
||||
|
||||
|
||||
def test_app_detects_collision_case_insensitive() -> None:
|
||||
from argenta.router.exceptions import RepeatedTriggerNameException
|
||||
|
||||
app = App()
|
||||
router1 = Router()
|
||||
router2 = Router()
|
||||
|
||||
@router1.command('Hello')
|
||||
def handler1(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router2.command('hELLo')
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_router(router1)
|
||||
app.include_router(router2)
|
||||
|
||||
with pytest.raises(RepeatedTriggerNameException):
|
||||
app._pre_cycle_setup()
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for startup messages
|
||||
# ============================================================================
|
||||
|
||||
@@ -9,8 +9,9 @@ from argenta.command.flag.flags import Flags, InputFlags
|
||||
from argenta.command.flag.models import PossibleValues, ValidationStatus
|
||||
from argenta.response.entity import Response
|
||||
from argenta.router import Router
|
||||
from argenta.router.entity import _structuring_input_flags, _validate_func_args # pyright: ignore[reportPrivateUsage]
|
||||
from argenta.router.entity import _structuring_input_flags, _validate_func_args
|
||||
from argenta.router.exceptions import (
|
||||
RepeatedAliasNameException,
|
||||
RepeatedFlagNameException,
|
||||
RepeatedTriggerNameException,
|
||||
RequiredArgumentNotPassedException,
|
||||
@@ -247,3 +248,60 @@ def test_finds_appropriate_handler_executes_handler_with_flags_by_alias(capsys:
|
||||
output = capsys.readouterr()
|
||||
|
||||
assert "Hello World!" in output.out
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for alias and trigger collision detection
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_validate_command_raises_error_for_alias_collision_with_existing_trigger() -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command('hello')
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
@router.command(Command('world', aliases={'hello'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_validate_command_raises_error_for_alias_collision_with_existing_alias() -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', aliases={'hi'}))
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
@router.command(Command('world', aliases={'hi'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_validate_command_raises_error_for_trigger_collision_with_existing_alias() -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', aliases={'hi'}))
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
@router.command('hi')
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_validate_command_raises_error_for_alias_collision_case_insensitive() -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', aliases={'Hi'}))
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(RepeatedAliasNameException):
|
||||
@router.command(Command('world', aliases={'hI'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user