Skip to content

Commit

Permalink
🍻 @deprecated for v1
Browse files Browse the repository at this point in the history
  • Loading branch information
RF-Tar-Railt committed Oct 25, 2024
1 parent 60cdd95 commit a1fe56f
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 48 deletions.
5 changes: 1 addition & 4 deletions src/arclet/alconna/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,8 @@
from .exceptions import NullMessage as NullMessage
from .exceptions import ParamsUnmatched as ParamsUnmatched
from .formatter import TextFormatter as TextFormatter
from .manager import ShortcutArgs as ShortcutArgs
from .shortcut import ShortcutArgs as ShortcutArgs
from .manager import command_manager as command_manager
from .typing import AllParam as AllParam

__version__ = "1.8.31"

# backward compatibility
AnyOne = ANY
6 changes: 4 additions & 2 deletions src/arclet/alconna/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,10 @@ def __new__(
if seps is not None:
arg.field.seps = seps
cls.__args_data__ = _Args(all_args, cls)

dcls = dc.make_dataclass(cls.__name__, [(arg.name, arg.type_, arg.field.to_dc_field()) for arg in cls.__args_data__.data], namespace=types_namespace, repr=True)
try:
dcls = dc.make_dataclass(cls.__name__, [(arg.name, arg.type_, arg.field.to_dc_field()) for arg in cls.__args_data__.data], namespace=types_namespace, repr=True)
except TypeError as e:
raise TypeError(f"cannot create Args Model: {e}") from None
cls.__init__ = dcls.__init__ # type: ignore
if "__repr__" not in cls.__dict__:
cls.__repr__ = dcls.__repr__ # type: ignore
Expand Down
2 changes: 2 additions & 0 deletions src/arclet/alconna/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ def _parse(self, message: TDC, ctx: dict[str, Any] | None = None) -> Arparma[TDC
return res
analyser = command_manager.require(self)
argv = analyser.argv
if message.__class__ is str:
message = [message] # type: ignore
argv.enter(ctx).build(message)
if argv.message_cache and (res := command_manager.get_record(argv.token)):
return res
Expand Down
17 changes: 9 additions & 8 deletions src/arclet/alconna/ingedia/_argv.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,8 @@ def build(self, data: TDC) -> Self:
"""
self.reset()
if self.checker and not self.checker(data):
if not self.converter:
raise TypeError(data)
try:
data = self.converter(data) # type: ignore
except Exception as e:
raise TypeError(data) from e
raise TypeError(data)
self.origin = data
if data.__class__ is str:
data = [data] # type: ignore
i = 0
raw_data = self.raw_data
for unit in data:
Expand Down Expand Up @@ -320,3 +313,11 @@ def argv_config(
Argv._cache.setdefault(target or __argv_type__.get(), {}).update(
{k: v for k, v in locals().items() if v is not None}
)


def reset_argv_config(target: type[Argv] | None = None):
"""重置命令行参数配置"""
if target:
Argv._cache.pop(target, None)
else:
Argv._cache.clear()
4 changes: 4 additions & 0 deletions src/arclet/alconna/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@
from .typing import StrMulti as StrMulti
from .typing import UnpackVar as UnpackVar
from .typing import Up as Up


# backward compatibility
AnyOne = ANY
2 changes: 2 additions & 0 deletions src/arclet/alconna/v1/compat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import warnings
from typing import Literal, Any, Callable, ContextManager
from typing_extensions import deprecated
from arclet.alconna import Metadata, Config, global_config
Expand Down Expand Up @@ -93,6 +94,7 @@ def __setattr__(self, key, value):
elif key in ("name", "prefixes", "formatter_type", "to_text", "converter"):
setattr(self.origin, key, value)
else:
warnings.warn(f"Namespace.{key} is deprecated, use Namespace.config.{key} instead", DeprecationWarning, stacklevel=2)
setattr(self.origin.config, key, value)


Expand Down
3 changes: 3 additions & 0 deletions src/arclet/alconna/v1/duplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from inspect import isclass
from typing import cast
from typing_extensions import deprecated

from tarina import Empty

Expand All @@ -12,6 +13,7 @@
from .stub import ArgsStub, BaseStub, OptionStub, SubcommandStub


@deprecated("Duplication is removed", category=DeprecationWarning, stacklevel=1)
class Duplication:
"""`副本`, 用以更方便的检查、调用解析结果的类。"""

Expand Down Expand Up @@ -47,6 +49,7 @@ def subcommand(self, name: str) -> SubcommandStub | None:
return cast(SubcommandStub, getattr(self, name, None))


@deprecated("generate_duplication is removed", category=DeprecationWarning, stacklevel=1)
def generate_duplication(alc: Alconna) -> type[Duplication]:
"""依据给定的命令生成一个解析结果的检查类。"""

Expand Down
5 changes: 4 additions & 1 deletion src/arclet/alconna/v1/stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclasses import dataclass, field
from inspect import isclass
from typing import Any, Generic, TypeVar
from typing_extensions import Self
from typing_extensions import Self, deprecated

from nepattern import ANY, BasePattern

Expand Down Expand Up @@ -40,6 +40,7 @@ def __repr__(self):
return f"{{{', '.join([f'{k}={v}' for k, v in vars(self).items() if v and not k.startswith('_')])}}}"


@deprecated("ArgsStub is removed, use `ArgsBase` instead", category=DeprecationWarning, stacklevel=1)
@dataclass(init=True)
class ArgsStub(BaseStub[_Args]):
"""参数存根"""
Expand Down Expand Up @@ -103,6 +104,7 @@ def __getitem__(self, item: int | str) -> Any:
return self._value[item]


@deprecated("OptionStub is removed", category=DeprecationWarning, stacklevel=1)
@dataclass(init=True)
class OptionStub(BaseStub[Option]):
"""选项存根"""
Expand Down Expand Up @@ -130,6 +132,7 @@ def set_result(self, result: OptionResult | None):
return self


@deprecated("SubcommandStub is removed", category=DeprecationWarning, stacklevel=1)
@dataclass(init=True)
class SubcommandStub(BaseStub[Subcommand]):
"""子命令存根"""
Expand Down
5 changes: 5 additions & 0 deletions src/arclet/alconna/v1/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Literal,
TypeVar,
)
from typing_extensions import deprecated

from nepattern import BasePattern, MatchMode, parser

Expand All @@ -14,6 +15,7 @@
T = TypeVar("T")


@deprecated("KeyWordVar is deprecated, use `Field(kw_only=True)` instead", category=DeprecationWarning, stacklevel=1)
class KeyWordVar(BasePattern[T, Any, Literal[MatchMode.KEEP]]):
"""对具名参数的包装"""

Expand Down Expand Up @@ -45,6 +47,7 @@ def __getitem__(self, item: BasePattern[T, Any, Any] | type[T] | Any):
__rmatmul__ = __getitem__


@deprecated("MultiVar is deprecated, use `Field(multiple=...)` instead", category=DeprecationWarning, stacklevel=1)
class MultiVar(BasePattern[T, Any, Literal[MatchMode.KEEP]]):
"""对可变参数的包装"""

Expand Down Expand Up @@ -87,6 +90,7 @@ class KWBool(BasePattern):
"""对布尔参数的包装"""


@deprecated("UnpackVar is deprecated, use `ArgsBase` instead", category=DeprecationWarning, stacklevel=1)
class UnpackVar(BasePattern):
"""特殊参数,利用dataclass 的 field 生成 arg 信息,并返回dcls"""

Expand Down Expand Up @@ -114,6 +118,7 @@ def __mul__(self, other):
Up = _Up()


@deprecated("StrMulti is deprecated, use `Field(multiple=str)` instead", stacklevel=1)
class _StrMulti(MultiVar[str]):
pass

Expand Down
27 changes: 16 additions & 11 deletions tests/analyser_test.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from dataclasses import dataclass, field
from typing import Any, Union
from typing import Union
from collections import UserList

import pytest
from nepattern import BasePattern, MatchMode

from arclet.alconna import Alconna, Args, Option
from arclet.alconna.ingedia._argv import argv_config
from arclet.alconna.ingedia._argv import argv_config, reset_argv_config


@dataclass
Expand Down Expand Up @@ -49,7 +51,7 @@ def test_filter_out():
ana = Alconna("ana", Args.foo(str))
assert ana.parse(["ana", 123, "bar"]).matched is True
assert ana.parse("ana bar").matched is True
argv_config(filter_out=[])
reset_argv_config()
ana_1 = Alconna("ana", Args.foo(str))
assert ana_1.parse(["ana", 123, "bar"]).matched is False

Expand All @@ -59,7 +61,7 @@ def test_preprocessor():
ana1 = Alconna("ana1", Args.bar(int))
assert ana1.parse(["ana1", [1, 2, 3]]).matched is True
assert ana1.parse(["ana1", [1, 2, 3]]).bar == 3
argv_config(preprocessors={})
reset_argv_config()
ana1_1 = Alconna("ana1", Args.bar(int))
assert ana1_1.parse(["ana1", [1, 2, 3]]).matched is False

Expand All @@ -72,7 +74,7 @@ def test_with_set_unit():
assert res.matched is True
assert res.foo.data["qq"] == "123456"
assert not ana2.parse([Segment.text("ana2"), Segment.face(103), Segment.at(123456)]).matched
argv_config()
reset_argv_config()


def test_unhashable_unit():
Expand All @@ -88,15 +90,18 @@ def test_unhashable_unit():
print(ana3_1.parse(["ana3_1", "--foo", "--comp", Segment.at(123)]))
print(ana3_1.parse(["ana3_1", "--comp", Segment.at(123)]))

reset_argv_config()


def test_checker():
argv_config(checker=lambda x: isinstance(x, list))
argv_config(checker=lambda x: isinstance(x, UserList))
ana4 = Alconna("ana4", Args.foo(int))
print(ana4.parse(["ana4", "123"]))
try:
print(ana4.parse("ana4 123"))
except TypeError as e:
print(e)
assert ana4.parse(UserList(["ana4", "123"]))

with pytest.raises(TypeError):
ana4.parse("ana4 123")

reset_argv_config()


if __name__ == "__main__":
Expand Down
40 changes: 24 additions & 16 deletions tests/args_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest

from typing import Union

from nepattern import INTEGER, BasePattern, MatchMode, combine

from arclet.alconna import Args, Arg
from arclet.alconna import Args, Arg, ArgsBase, arg_field
from devtool import analyse_args


Expand Down Expand Up @@ -201,21 +203,27 @@ def test_annotated():
assert analyse_args(arg18, ["0 0"], raise_exception=False) != {"foo": 0, "bar": 0}


# def test_unpack():
# from dataclasses import dataclass, field
#
# from arclet.alconna.typing import UnpackVar
#
# @dataclass
# class People:
# name: str
# age: int = field(default=16)
#
# arg19 = Args["people", UnpackVar(People)]
# assert analyse_args(arg19, ["alice", 16]) == {"people": People("alice", 16)}
# assert analyse_args(arg19, ["bob"]) == {"people": People("bob", 16)}
# arg19_1 = Args["people", UnpackVar(People, kw_only=True)].separate("&")
# assert analyse_args(arg19_1, ["name=alice&age=16"]) == {"people": People("alice", 16)}
def test_args_model():
class People(ArgsBase):
name: str
age: int = arg_field(default=16)

assert analyse_args(People, ["abc"]) == {"name": "abc", "age": 16}

class Foo(ArgsBase):
foo: str

class Bar(ArgsBase):
bar: int = arg_field(42)

class Baz(Bar, Foo):
baz: bool = arg_field(True)

assert analyse_args(Baz, ["abc 123"]) == {"foo": "abc", "bar": 123, "baz": True}

with pytest.raises(TypeError, match="cannot create Args Model: non-default argument 'foo' follows default argument"):
class Baz1(Foo, Bar):
baz: bool = arg_field(True)


def test_multi_multi():
Expand Down
6 changes: 3 additions & 3 deletions tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ def test_option_aliases():

def test_separator():
opt2 = Option("foo", Args.bar(int), separators="|")
assert analyse_option(opt2, "foo|123") == OptionResult(None, {"bar": 123})
assert analyse_option(opt2, ["foo|123"]) == OptionResult(None, {"bar": 123})
opt2_1 = Option("foo", Args.bar(int)).separate("|")
assert opt2 == opt2_1


def test_subcommand():
sub = Subcommand("test", Option("foo"), Option("bar"))
assert len(sub.options) == 2
assert analyse_subcommand(sub, "test foo") == SubcommandResult(None, {}, {"foo": OptionResult()})
assert analyse_subcommand(sub, ["test foo"]) == SubcommandResult(None, {}, {"foo": OptionResult()})


def test_compact():
opt3 = Option("-Foo", Args.bar(int), compact=True)
assert analyse_option(opt3, "-Foo123") == OptionResult(None, {"bar": 123})
assert analyse_option(opt3, ["-Foo123"]) == OptionResult(None, {"bar": 123})


def test_add():
Expand Down
13 changes: 13 additions & 0 deletions tests/core_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ def test_completion_interface():

def test_call():
from dataclasses import dataclass
from arclet.alconna import ArgsBase

alc22 = Alconna("core22", Args.foo(int), Args.bar(str))
alc22("core22 123 abc")
Expand All @@ -748,6 +749,18 @@ class A:
alc22_1.parse("core22_1 abc")
assert alc22_1.exec_result["A"] == A("abc")

class B(ArgsBase):
name: str

alc22_2 = Alconna("core22_2", B)

@alc22_2.bind(False)
def cb1(args: B):
return args.name

alc22_2.parse("core22_2 abc")
assert cb1.result == "abc"


def test_nest_subcommand():
class A:
Expand Down
6 changes: 3 additions & 3 deletions tests/devtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def analyse_args(
def analyse_header(
headers: list[str | Any] | list[tuple[Any, str]],
command_name: str,
command: DataCollection[str | Any],
command: list[str | Any],
sep: str = " ",
compact: bool = False,
raise_exception: bool = True,
Expand All @@ -83,7 +83,7 @@ def analyse_header(

def analyse_option(
option: Option,
command: DataCollection[str | Any],
command: list[str | Any],
raise_exception: bool = True,
context_style: Literal["bracket", "parentheses"] | None = None,
**kwargs,
Expand Down Expand Up @@ -111,7 +111,7 @@ def analyse_option(

def analyse_subcommand(
subcommand: Subcommand,
command: DataCollection[str | Any],
command: list[str | Any],
raise_exception: bool = True,
context_style: Literal["bracket", "parentheses"] | None = None,
**kwargs,
Expand Down

0 comments on commit a1fe56f

Please sign in to comment.