Skip to content

Commit

Permalink
🔥 remove duplication argument
Browse files Browse the repository at this point in the history
  • Loading branch information
RF-Tar-Railt committed Feb 26, 2024
1 parent ba2dd92 commit 53bc26a
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 54 deletions.
28 changes: 22 additions & 6 deletions exam3.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
from typing import Any, Callable, TypeVar
from typing_extensions import ParamSpec, Self
from __future__ import annotations
from typing import Any, Callable, TypeVar, overload, Literal
from typing_extensions import ParamSpec, Concatenate, Self


T = TypeVar("T")
R = TypeVar("R")
P = ParamSpec("P")


def deco(fn: Callable[P, T]) -> Callable[[Callable[[Any, T], R]], Callable[P, R]]:
def wrapper(func: Callable[[Any, T], R]) -> Callable[P, R]:
@overload
def deco(fn: Callable[P, T]) -> Callable[[Callable[[T], R]], Callable[P, R]]: ...


@overload
def deco(
fn: Callable[P, T], is_method: Literal[True]
) -> Callable[[Callable[[Any, T], R]], Callable[Concatenate[Any, P], R]]: ...


def deco( # type: ignore
fn: Callable[P, T], is_method: bool = False
) -> Callable[[Callable[[T], R] | Callable[[Any, T], R]], Callable[P, R] | Callable[Concatenate[Any, P], R]]:
def wrapper(func: Callable[[T], R] | Callable[[Any, T], R]) -> Callable[P, R] | Callable[Concatenate[Any, P], R]:
def inner(*args: P.args, **kwargs: P.kwargs):
return func(args[0], fn(*args[1:], **kwargs)) # type: ignore
if is_method:
return func(args[0], fn(*args[1:], **kwargs)) # type: ignore
return func(fn(*args, **kwargs)) # type: ignore

return inner

Expand All @@ -25,7 +41,7 @@ class B:
def foo(self, num: int):
...

@deco(A)
@deco(A, is_method=True)
def add(self, args: A) -> Self:
print(args.num)
return self
Expand Down
6 changes: 3 additions & 3 deletions src/arclet/alconna/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def __init__(
default.default = None if default.default is Empty else default.default # type: ignore
if _value == NONE:
raise InvalidArgs(lang.require("args", "value_error").format(target=name))
self.value = _value
self.value = _value # type: ignore
self.field = default
self.notice = notice
self.separators = (seps,) if isinstance(seps, str) else tuple(seps)
Expand All @@ -137,7 +137,7 @@ def __init__(
self.optional = ArgFlag.OPTIONAL in self.flag
self.hidden = ArgFlag.HIDDEN in self.flag
if ArgFlag.ANTI in self.flag and self.value not in (ANY, AllParam):
self.value = AntiPattern(self.value)
self.value = AntiPattern(self.value) # type: ignore

def __repr__(self):
n, v = f"'{self.name}'", str(self.value)
Expand Down Expand Up @@ -381,7 +381,7 @@ def __getitem__(self, item: Union[Arg, tuple[Arg, ...], str, tuple[Any, ...]]) -
Returns:
Self | Arg: 参数集合自身或需要的参数单元
"""
if isinstance(item, str) and (res := next(filter(lambda x: x.name == item, self.argument), None)):
if res := next((x for x in self.argument if x.name == item), None):
return res
data: tuple[Arg, ...] | tuple[Any, ...] = item if isinstance(item, tuple) else (item,)
if isinstance(data[0], Arg):
Expand Down
56 changes: 13 additions & 43 deletions src/arclet/alconna/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@
from .arparma import Arparma, ArparmaBehavior, requirement_handler
from .base import Completion, Help, Option, Shortcut, Subcommand
from .config import Namespace, config
from .duplication import Duplication
from .exceptions import ExecuteFailed, NullMessage
from .formatter import TextFormatter
from .manager import ShortcutArgs, command_manager
from .typing import TDC, CommandMeta, DataCollection, InnerShortcutArgs, ShortcutRegWrapper, TPrefixes

T_Duplication = TypeVar("T_Duplication", bound=Duplication)
T = TypeVar("T")
TDC1 = TypeVar("TDC1", bound=DataCollection[Any])

Expand Down Expand Up @@ -63,7 +61,8 @@ class ArparmaExecutor(Generic[T]):
target: Callable[..., T]
binding: Callable[..., list[Arparma]] = field(default=lambda: [], repr=False)

__call__ = lambda self, *args, **kwargs: self.target(*args, **kwargs)
def __call__(self, *args, **kwargs):
return self.target(*args, **kwargs)

@property
def result(self) -> T:
Expand Down Expand Up @@ -171,7 +170,6 @@ def __init__(
command_manager.register(self)
self._executors: dict[ArparmaExecutor, Any] = {}
self.union: "WeakSet[Alconna]" = WeakSet()
self._union = False

@property
def namespace_config(self) -> Namespace:
Expand Down Expand Up @@ -276,24 +274,6 @@ def shortcut(self, key: str, *, delete: Literal[True]) -> str:
...

def shortcut(self, key: str, args: ShortcutArgs | None = None, delete: bool = False, **kwargs):
"""操作快捷命令
Args:
key (str): 快捷命令名
args (ShortcutArgs | None, optional): 快捷命令参数, 不传入时则尝试使用最近一次使用的命令
delete (bool, optional): 是否删除快捷命令, 默认为 `False`
command (str, optional): 快捷命令指向的命令
arguments (list[Any] | None, optional): 快捷命令参数, 默认为 `None`
fuzzy (bool, optional): 是否允许命令后随参数, 默认为 `True`
prefix (bool, optional): 是否调用时保留指令前缀, 默认为 `False`
wrapper (ShortcutRegWrapper, optional): 快捷指令的正则匹配结果的额外处理函数, 默认为 `None`
Returns:
str: 操作结果
Raises:
ValueError: 快捷命令操作失败时抛出
"""
try:
if delete:
return command_manager.delete_shortcut(self, key)
Expand Down Expand Up @@ -337,41 +317,28 @@ def add(self, opt: Option | Subcommand) -> Self:
command_manager.register(self)
return self

@init_spec(Option, True)
@init_spec(Option, is_method=True)
def option(self, opt: Option) -> Self:
"""添加选项"""
return self.add(opt)

@init_spec(Subcommand, True)
@init_spec(Subcommand, is_method=True)
def subcommand(self, sub: Subcommand) -> Self:
"""添加子命令"""
return self.add(sub)

def _parse(self, message: TDC, ctx: dict[str, Any] | None = None) -> Arparma[TDC]:
if self._union:
for ana, argv in command_manager.unpack(self.union):
if (res := ana.process(argv.enter(ctx).build(message))).matched:
return res
analyser = command_manager.require(self)
argv = command_manager.resolve(self)
argv.enter(ctx).build(message)
return analyser.process(argv)

@overload
def parse(self, message: TDC, ctx: dict[str, Any] | None = None) -> Arparma[TDC]:
...

@overload
def parse(self, message, ctx: dict[str, Any] | None = None, *, duplication: type[T_Duplication]) -> T_Duplication:
...

def parse(self, message: TDC, ctx: dict[str, Any] | None = None, *, duplication: type[T_Duplication] | None = None) -> Arparma[TDC] | T_Duplication:
"""命令分析功能, 传入字符串或消息链, 返回一个特定的数据集合类
Args:
message (TDC): 命令消息
ctx (dict[str, Any], optional): 上下文信息
duplication (type[T_Duplication], optional): 指定的`副本`类型
Returns:
Arparma[TDC] | T_Duplication: 若`duplication`参数为`None`则返回`Arparma`对象, 否则返回`duplication`类型的对象
Raises:
Expand All @@ -388,7 +355,7 @@ def parse(self, message: TDC, ctx: dict[str, Any] | None = None, *, duplication:
if self._executors:
for ext in self._executors:
self._executors[ext] = arp.call(ext.target)
return duplication(arp) if duplication else arp
return arp

def bind(self, active: bool = True):
"""绑定命令执行器
Expand Down Expand Up @@ -433,7 +400,14 @@ def __add__(self, other) -> Self:

def __or__(self, other: Alconna) -> Self:
self.union.add(other)
self._union = True

def _parse(message: TDC, ctx: dict[str, Any] | None = None) -> Arparma[TDC]:
for ana, argv in command_manager.unpack(self.union):
if (res := ana.process(argv.enter(ctx).build(message))).matched:
return res
return command_manager.require(self).process(command_manager.resolve(self).enter(ctx).build(message))

self._parse = _parse
return self

def _calc_hash(self):
Expand All @@ -448,10 +422,6 @@ def __call__(self, *args):
return self.parse(argv) # type: ignore
return self.parse([head, *argv]) # type: ignore

@property
def headers(self):
return self.prefixes

@property
def header_display(self):
ana = command_manager.require(self)
Expand Down
4 changes: 2 additions & 2 deletions tests/components_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ class Demo1(Duplication):
)
res = com4.parse("comp4 123 --bar abc sub --sub1 xyz")
assert res.matched is True
duplication = com4.parse("comp4 123 --bar abc sub --sub1 xyz", duplication=Demo)
duplication = Demo(com4.parse("comp4 123 --bar abc sub --sub1 xyz"))
assert isinstance(duplication, Demo)
assert duplication.testArgs.available is True
assert duplication.testArgs.foo == 123
assert duplication.bar.available is True
assert duplication.bar.args.bar == "abc"
assert duplication.sub.available is True
assert duplication.sub.option("sub1").args.first == "xyz"
duplication1 = com4.parse("comp4 123 --bar abc sub --sub1 xyz", duplication=Demo1)
duplication1 = Demo1(com4.parse("comp4 123 --bar abc sub --sub1 xyz"))
assert isinstance(duplication1, Demo1)
assert isinstance(duplication1.foo, int)
assert isinstance(duplication1.bar, str)
Expand Down

0 comments on commit 53bc26a

Please sign in to comment.