From 04dc83e54b098d3ff313ed00dad468094f19bac4 Mon Sep 17 00:00:00 2001 From: RF-Tar-Railt Date: Mon, 14 Oct 2024 01:42:21 +0800 Subject: [PATCH] :boom: refactor --- nepattern/__init__.py | 18 +- nepattern/base.py | 530 ++++------------ nepattern/context.py | 10 +- nepattern/context.pyi | 12 +- nepattern/core.py | 822 +++---------------------- nepattern/core.pyi | 883 --------------------------- nepattern/func.py | 266 -------- nepattern/i18n/.config.json | 5 +- nepattern/i18n/.lang.schema.json | 49 +- nepattern/i18n/.template.json | 17 +- nepattern/i18n/.template.schema.json | 30 +- nepattern/i18n/__init__.py | 2 - nepattern/i18n/en-US.json | 11 +- nepattern/i18n/zh-CN.json | 11 +- nepattern/main.py | 62 +- nepattern/main.pyi | 65 -- nepattern/util.py | 12 +- pdm.lock | 205 ++++--- pyproject.toml | 6 +- test.py | 511 ++++++++-------- 20 files changed, 691 insertions(+), 2836 deletions(-) delete mode 100644 nepattern/core.pyi delete mode 100644 nepattern/func.py delete mode 100644 nepattern/main.pyi diff --git a/nepattern/__init__.py b/nepattern/__init__.py index 2940c68..860081a 100644 --- a/nepattern/__init__.py +++ b/nepattern/__init__.py @@ -19,9 +19,7 @@ from .base import HEX_COLOR as HEX_COLOR from .base import INTEGER as INTEGER from .base import IP as IP -from .base import IterMode as IterMode from .base import LIST as LIST -from .base import MappingPattern as MappingPattern from .base import NONE as NONE from .base import NUMBER as NUMBER from .base import PATH as PATH @@ -29,7 +27,6 @@ from .base import RegexPattern as RegexPattern from .base import SET as SET from .base import STRING as STRING -from .base import SequencePattern as SequencePattern from .base import SwitchPattern as SwitchPattern from .base import TUPLE as TUPLE from .base import URL as URL @@ -43,22 +40,9 @@ from .context import local_patterns as local_patterns from .context import reset_local_patterns as reset_local_patterns from .context import switch_local_patterns as switch_local_patterns -from .core import BasePattern as BasePattern -from .core import MatchMode as MatchMode +from .core import Pattern as Pattern from .core import ValidateResult as ValidateResult from .exception import MatchFailed as MatchFailed -from .func import Dot as Dot -from .func import Filter as Filter -from .func import GetItem as GetItem -from .func import Index as Index -from .func import Join as Join -from .func import Lower as Lower -from .func import Map as Map -from .func import Reduce as Reduce -from .func import Slice as Slice -from .func import Step as Step -from .func import Sum as Sum -from .func import Upper as Upper from .main import parser as parser from .util import RawStr as RawStr from .util import TPattern as TPattern diff --git a/nepattern/base.py b/nepattern/base.py index c7ec41f..b0fae89 100644 --- a/nepattern/base.py +++ b/nepattern/base.py @@ -6,25 +6,19 @@ import re import sys from typing import ( - TYPE_CHECKING, Any, - Callable, - Dict, ForwardRef, Generic, - Iterable, - Literal, Match, TypeVar, Union, - cast, final, - overload, + Final ) -from tarina import DateParser, Empty, lang +from tarina import DateParser, lang -from .core import _MATCHES, TMM, BasePattern, MatchMode, ResultFlag, ValidateResult +from .core import Pattern from .exception import MatchFailed from .util import TPattern @@ -34,136 +28,84 @@ _T1 = TypeVar("_T1") -class DirectPattern(BasePattern[TOrigin, TOrigin, Literal[MatchMode.KEEP]]): +class DirectPattern(Pattern[TOrigin]): """直接判断""" def __init__(self, target: TOrigin, alias: str | None = None): self.target = target - super().__init__(mode=MatchMode.KEEP, origin=type(target), alias=alias or str(target)) + super().__init__(type(target), alias) def match(self, input_: Any): if input_ != self.target: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.target) + lang.require("nepattern", "error.content").format(target=input_, expected=self.target) ) return input_ - @overload - def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - - @overload - def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]: ... - - @overload - def validate( - self, input_: TOrigin, default: Any - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - - @overload - def validate( - self, input_: Any, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - - def validate(self, input_: Any, default: Union[TDefault, Empty] = Empty) -> ValidateResult[TOrigin | TDefault, ResultFlag]: # type: ignore - try: - return ValidateResult(self.match(input_), flag=ResultFlag.VALID) - except MatchFailed as e: - if default is Empty: - return ValidateResult(error=e, flag=ResultFlag.ERROR) - return ValidateResult(default, flag=ResultFlag.DEFAULT) # type: ignore - - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, DirectPattern) and self.target == other.target def copy(self): return DirectPattern(self.target, self.alias) -class DirectTypePattern(BasePattern[TOrigin, TOrigin, Literal[MatchMode.KEEP]]): +class DirectTypePattern(Pattern[TOrigin]): """直接类型判断""" - def __init__(self, target: type[TOrigin], alias: str | None = None): - self.target = target - super().__init__(mode=MatchMode.KEEP, origin=target, alias=alias or target.__name__) - def match(self, input_: Any): - if not isinstance(input_, self.target): + if not isinstance(input_, self.origin): raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.target + lang.require("nepattern", "error.type").format( + type=input_.__class__, target=input_, expected=self.origin ) ) return input_ - @overload - def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - - @overload - def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]: ... - - @overload - def validate( - self, input_: TOrigin, default: Any - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - - @overload - def validate( - self, input_: Any, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - - def validate(self, input_: Any, default: Union[TDefault, Empty] = Empty) -> ValidateResult[TOrigin | TDefault, ResultFlag]: # type: ignore - try: - return ValidateResult(self.match(input_), flag=ResultFlag.VALID) - except MatchFailed as e: - if default is Empty: - return ValidateResult(error=e, flag=ResultFlag.ERROR) - return ValidateResult(default, flag=ResultFlag.DEFAULT) # type: ignore - - def __calc_eq__(self, other): # pragma: no cover - return isinstance(other, DirectTypePattern) and self.target == other.target + def __eq__(self, other): # pragma: no cover + return isinstance(other, DirectTypePattern) and self.origin is other.origin def copy(self): - return DirectTypePattern(self.target, self.alias) + return DirectTypePattern(self.origin, self.alias) -class RegexPattern(BasePattern[Match[str], str, Literal[MatchMode.REGEX_MATCH]]): +class RegexPattern(Pattern[Match[str]]): """针对正则的特化匹配,支持正则组""" def __init__(self, pattern: str | TPattern, alias: str | None = None): - super().__init__("", origin=Match[str], alias=alias or "regex[:group]") # type: ignore + super().__init__(Match[str], alias=alias or "regex[:group]") self.regex_pattern = re.compile(pattern) self.pattern = self.regex_pattern.pattern def match(self, input_: Any) -> Match[str]: if not isinstance(input_, str): raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="str" ) ) if mat := self.regex_pattern.match(input_): return mat raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.pattern) + lang.require("nepattern", "error.content").format(target=input_, expected=self.pattern) ) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, RegexPattern) and self.pattern == other.pattern def copy(self): return RegexPattern(self.pattern, self.alias) -class UnionPattern(BasePattern[Any, _T, Literal[MatchMode.KEEP]]): +class UnionPattern(Pattern[_T]): """多类型参数的匹配""" - optional: bool - for_validate: list[BasePattern] - for_equal: list[str | object] + # optional: bool + # for_validate: list[BasePattern] + # for_equal: list[str | object] __slots__ = ("base", "optional", "for_validate", "for_equal") - def __init__(self, base: Iterable[BasePattern[Any, _T, Any] | _T]): + def __init__(self, *base: Any): self.base = list(base) self.optional = False self.for_validate = [] @@ -173,179 +115,44 @@ def __init__(self, base: Iterable[BasePattern[Any, _T, Any] | _T]): if arg == NONE: self.optional = True self.for_equal.append(None) - elif isinstance(arg, BasePattern): + elif isinstance(arg, Pattern): self.for_validate.append(arg) else: self.for_equal.append(arg) alias_content = "|".join([repr(a) for a in self.for_validate] + [repr(a) for a in self.for_equal]) - super().__init__(mode=MatchMode.KEEP, origin=Any, alias=alias_content) + types = [i.origin for i in self.for_validate] + [type(i) for i in self.for_equal] + super().__init__(Union[*types], alias=alias_content) # type: ignore def match(self, input_: Any): if not input_: input_ = None if input_ not in self.for_equal: for pat in self.for_validate: - if (res := pat.validate(input_)).success: + if (res := pat.execute(input_)).success: return res.value() raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) + lang.require("nepattern", "error.content").format(target=input_, expected=self.alias) ) return input_ @classmethod - def _(cls, *types: type[_T1]) -> UnionPattern[_T1]: + def of(cls, *types: type[_T1]) -> UnionPattern[_T1]: from .main import parser return cls([parser(i) for i in types]) # type: ignore - def __calc_repr__(self): + def __repr__(self): return "|".join(repr(a) for a in (*self.for_validate, *self.for_equal)) - def __or__(self, other: BasePattern[Any, _T1, Any]) -> UnionPattern[Union[_T, _T1]]: - return UnionPattern([*self.base, other]) # type: ignore - - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, UnionPattern) and self.base == other.base -TSeq = TypeVar("TSeq", list, tuple, set) - - -class IterMode(str, Enum): - PRE = "pre" - SUF = "suf" - ALL = "all" - - -TIterMode = TypeVar("TIterMode", bound=IterMode) - - -class SequencePattern( - BasePattern[TSeq, Union[str, TSeq], Literal[MatchMode.REGEX_CONVERT]], Generic[TSeq, TIterMode] -): - """匹配列表或者元组或者集合""" - - base: BasePattern - itermode: TIterMode - - def __init__(self, form: type[TSeq], base: BasePattern, mode: TIterMode = IterMode.ALL): - self.base = base - self.itermode = mode - if form is list: - super().__init__(r"\[(.+?)\]", MatchMode.REGEX_CONVERT, form, alias=f"list[{base}]") - elif form is tuple: - super().__init__(r"\((.+?)\)", MatchMode.REGEX_CONVERT, form, alias=f"tuple[{base}]") - elif form is set: - super().__init__(r"\{(.+?)\}", MatchMode.REGEX_CONVERT, form, alias=f"set[{base}]") - else: - raise ValueError(lang.require("nepattern", "sequence_form_error").format(target=str(form))) - self.converter = lambda _, x: x[1] # type: ignore - self._match = _MATCHES[MatchMode.REGEX_CONVERT](self) - - def match(self, input_: Any): - _res = self._match(self, input_) # type: ignore - _max = 0 - success: list[tuple[int, Any]] = [] - fail: list[tuple[int, MatchFailed]] = [] - for _max, s in enumerate(re.split(r"\s*,\s*", _res) if isinstance(_res, str) else _res): - try: - success.append((_max, self.base.match(s))) - except MatchFailed: - fail.append((_max, MatchFailed(f"{s} is not matched with {self.base}"))) - - if ( - (self.itermode == IterMode.ALL and fail) - or (self.itermode == IterMode.PRE and fail and fail[0][0] == 0) - or (self.itermode == IterMode.SUF and fail and fail[-1][0] == _max) - ): - raise fail[0][1] - if self.itermode == IterMode.PRE and fail: - return self.origin(i[1] for i in success if i[0] < fail[0][0]) - if self.itermode == IterMode.SUF and fail: - return self.origin(i[1] for i in success if i[0] > fail[-1][0]) - return self.origin(i[1] for i in success) - - def __calc_repr__(self): - return f"{self.origin.__name__}[{self.base}]" - - -TKey = TypeVar("TKey") -TVal = TypeVar("TVal") - - -class MappingPattern( - BasePattern[Dict[TKey, TVal], Union[str, Dict[TKey, TVal]], Literal[MatchMode.REGEX_CONVERT]], - Generic[TKey, TVal, TIterMode], -): - """匹配字典或者映射表""" - - key: BasePattern[TKey, Any, Any] - value: BasePattern[TVal, Any, Any] - itermode: TIterMode - - def __init__( - self, - arg_key: BasePattern[TKey, Any, Any], - arg_value: BasePattern[TVal, Any, Any], - mode: TIterMode = IterMode.ALL, - ): - self.key = arg_key - self.value = arg_value - self.itermode = mode - super().__init__( - r"\{(.+?)\}", - MatchMode.REGEX_CONVERT, - dict, - alias=f"dict[{self.key}, {self.value}]", - ) - self.converter = lambda _, x: x[1] - self._match = _MATCHES[MatchMode.REGEX_CONVERT](self) - - def match(self, input_: str | dict): - _res = self._match(self, input_) # type: ignore - success: list[tuple[int, Any, Any]] = [] - fail: list[tuple[int, MatchFailed]] = [] - _max = 0 - - def _generator_items(res: str | dict): - if isinstance(res, dict): - yield from res.items() - return - for m in re.split(r"\s*,\s*", res): - yield re.split(r"\s*[:=]\s*", m) - - for _max, item in enumerate(_generator_items(_res)): - k, v = item - try: - success.append((_max, self.key.match(k), self.value.match(v))) - except MatchFailed: - fail.append( - ( - _max, - MatchFailed(f"{k}: {v} is not matched with {self.key}: {self.value}"), - ) - ) - if ( - (self.itermode == IterMode.ALL and fail) - or (self.itermode == IterMode.PRE and fail and fail[0][0] == 0) - or (self.itermode == IterMode.SUF and fail and fail[-1][0] == _max) - ): - raise fail[0][1] - if self.itermode == IterMode.PRE and fail: - return {i[1]: i[2] for i in success if i[0] < fail[0][0]} - if self.itermode == IterMode.SUF and fail: - return {i[1]: i[2] for i in success if i[0] > fail[-1][0]} - return {i[1]: i[2] for i in success} - - def __calc_repr__(self): - return f"dict[{self.key.origin.__name__}, {self.value}]" - - _TCase = TypeVar("_TCase") _TSwtich = TypeVar("_TSwtich") -class SwitchPattern(BasePattern[_TCase, _TSwtich, Literal[MatchMode.TYPE_CONVERT]], Generic[_TCase, _TSwtich]): +class SwitchPattern(Pattern[_TCase], Generic[_TCase, _TSwtich]): """匹配多种情况的表达式""" switch: dict[_TSwtich | ellipsis, _TCase] @@ -353,9 +160,9 @@ class SwitchPattern(BasePattern[_TCase, _TSwtich, Literal[MatchMode.TYPE_CONVERT def __init__(self, data: dict[_TSwtich, _TCase] | dict[_TSwtich | ellipsis, _TCase]): self.switch = data # type: ignore - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=type(list(data.values())[0])) + super().__init__(type(list(data.values())[0])) - def __calc_repr__(self): + def __repr__(self): return "|".join(f"{k}" for k in self.switch if k != Ellipsis) def match(self, input_: Any) -> _TCase: @@ -365,147 +172,81 @@ def match(self, input_: Any) -> _TCase: if Ellipsis in self.switch: return self.switch[...] raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self._repr) + lang.require("nepattern", "error.content").format(target=input_, expected=self.__repr__()) ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, SwitchPattern) and self.switch == other.switch -class ForwardRefPattern(BasePattern[Any, Any, Literal[MatchMode.TYPE_CONVERT]]): +class ForwardRefPattern(Pattern[Any]): def __init__(self, ref: ForwardRef): self.ref = ref - super().__init__( - mode=MatchMode.TYPE_CONVERT, origin=Any, converter=lambda _, x: eval(x), alias=ref.__forward_arg__ - ) + super().__init__(alias=ref.__forward_arg__) def match(self, input_: Any): if isinstance(input_, str) and input_ == self.ref.__forward_arg__: return input_ _main = sys.modules["__main__"] if sys.version_info < (3, 9): # pragma: no cover - origin = self.ref._evaluate(_main.__dict__, _main.__dict__) + origin = self.ref._evaluate(_main.__dict__, _main.__dict__) # type: ignore else: # pragma: no cover origin = self.ref._evaluate(_main.__dict__, _main.__dict__, recursive_guard=frozenset()) # type: ignore if not isinstance(input_, origin): # type: ignore raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected=self.ref.__forward_arg__ ) ) return input_ - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, ForwardRefPattern) and self.ref == other.ref -class AntiPattern(BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]]): - def __init__(self, pattern: BasePattern[TOrigin, Any, Any]): - self.base: BasePattern[TOrigin, Any, Any] = pattern - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=pattern.origin, alias=f"!{pattern}") +class AntiPattern(Pattern[TOrigin]): + def __init__(self, pattern: Pattern[TOrigin]): + self.base: Pattern[TOrigin] = pattern + super().__init__(origin=pattern.origin, alias=f"!{pattern}") - @overload - def validate(self, input_: TOrigin) -> ValidateResult[Any, Literal[ResultFlag.ERROR]]: ... - - @overload - def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.VALID]]: ... - - @overload - def validate( - self, input_: TOrigin, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - - @overload - def validate(self, input_: _T, default: Any) -> ValidateResult[_T, Literal[ResultFlag.VALID]]: ... - - def validate(self, input_: _T, default: Union[TDefault, Empty] = Empty) -> ValidateResult[_T | TDefault, ResultFlag]: # type: ignore - """ - 对传入的值进行反向验证,返回可能的匹配与转化结果。 - - 若传入默认值,验证失败会返回默认值 - """ + def match(self, input_: Any): try: - res = self.base.match(input_) + self.base.match(input_) except MatchFailed: - return ValidateResult(value=input_, flag=ResultFlag.VALID) - else: # pragma: no cover - for i in self.base.validators + self.validators: - if not i(res): - return ValidateResult(value=input_, flag=ResultFlag.VALID) - if default is Empty: - return ValidateResult( - error=MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self._repr) - ), - flag=ResultFlag.ERROR, - ) - if TYPE_CHECKING: - default = cast(TDefault, default) - return ValidateResult(default, flag=ResultFlag.DEFAULT) + return input_ + raise MatchFailed( + lang.require("nepattern", "error.content").format(target=input_, expected=self.alias) + ) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return isinstance(other, AntiPattern) and self.base == other.base -TInput = TypeVar("TInput") - - -class CustomMatchPattern(BasePattern[TOrigin, TInput, Literal[MatchMode.TYPE_CONVERT]]): - def __init__( - self, - origin: type[TOrigin], - func: Callable[[BasePattern, TInput], TOrigin | None], - alias: str | None = None, - ): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=origin, alias=alias or func.__name__) - self.__func__ = func - self.match = func.__get__(self) # type: ignore - - def __calc_eq__(self, other): # pragma: no cover - return isinstance(other, CustomMatchPattern) and self.__func__ == other.__func__ - - -NONE = CustomMatchPattern(type(None), lambda _, __: None, alias="none") # pragma: no cover - - -@final -class AnyPattern(BasePattern[Any, Any, Literal[MatchMode.KEEP]]): - def __init__(self): - super().__init__(mode=MatchMode.KEEP, origin=Any, alias="any") - - def match(self, input_: Any) -> Any: # pragma: no cover - return input_ - - def __calc_eq__(self, other): # pragma: no cover - return other.__class__ is AnyPattern - - -ANY = AnyPattern() +NONE: Final[Pattern[None]] = Pattern(type(None), alias="none").convert(lambda _, __: None) # pragma: no cover +ANY: Final[Pattern[Any]] = Pattern(alias="any") """匹配任意内容的表达式""" @final -class AnyStrPattern(BasePattern[str, Any, Literal[MatchMode.KEEP]]): +class AnyStrPattern(Pattern[str]): def __init__(self): - super().__init__(mode=MatchMode.KEEP, origin=str, alias="any_str") + super().__init__(origin=str, alias="any_str") def match(self, input_: Any) -> str: return str(input_) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is AnyStrPattern -AnyString = AnyStrPattern() +AnyString: Final = AnyStrPattern() """匹配任意内容并转为字符串的表达式""" @final -class StrPattern(BasePattern[str, Union[str, bytes, bytearray], Literal[MatchMode.TYPE_CONVERT]]): +class StrPattern(Pattern[str]): def __init__(self): - super().__init__( - mode=MatchMode.TYPE_CONVERT, origin=str, accepts=Union[str, bytes, bytearray], alias="str" - ) + super().__init__(origin=str, alias="str") def match(self, input_: Any) -> str: if isinstance(input_, str): @@ -513,24 +254,22 @@ def match(self, input_: Any) -> str: elif isinstance(input_, (bytes, bytearray)): return input_.decode() raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="str | bytes | bytearray" ) ) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is StrPattern -STRING = StrPattern() +STRING: Final = StrPattern() @final -class BytesPattern(BasePattern[bytes, Union[str, bytes, bytearray], Literal[MatchMode.TYPE_CONVERT]]): +class BytesPattern(Pattern[bytes]): def __init__(self): - super().__init__( - mode=MatchMode.TYPE_CONVERT, origin=bytes, accepts=Union[str, bytes, bytearray], alias="bytes" - ) + super().__init__(origin=bytes, alias="bytes") def match(self, input_: Any) -> bytes: if isinstance(input_, bytes): @@ -540,22 +279,22 @@ def match(self, input_: Any) -> bytes: elif isinstance(input_, str): return input_.encode() raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="bytes | str" ) ) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is BytesPattern -BYTES = BytesPattern() +BYTES: Final = BytesPattern() @final -class IntPattern(BasePattern[int, Any, Literal[MatchMode.TYPE_CONVERT]]): +class IntPattern(Pattern[int]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=int, alias="int") + super().__init__(origin=int, alias="int") def match(self, input_: Any) -> int: if isinstance(input_, int) and input_ is not True and input_ is not False: @@ -566,45 +305,44 @@ def match(self, input_: Any) -> int: return int(input_) except (ValueError, TypeError, OverflowError) as e: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="int") + lang.require("nepattern", "error.content").format(target=input_, expected="int") ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is IntPattern -INTEGER = IntPattern() +INTEGER: Final = IntPattern() """整形数表达式,只能接受整数样式的量""" @final -class FloatPattern(BasePattern[float, Any, Literal[MatchMode.TYPE_CONVERT]]): +class FloatPattern(Pattern[float]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=float, alias="float") + super().__init__(origin=float, alias="float") def match(self, input_: Any) -> float: if isinstance(input_, float): return input_ - try: return float(input_) except (TypeError, ValueError) as e: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="float") + lang.require("nepattern", "error.content").format(target=input_, expected="float") ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is FloatPattern -FLOAT = FloatPattern() +FLOAT: Final = FloatPattern() """浮点数表达式""" @final -class NumberPattern(BasePattern[Union[int, float], Any, Literal[MatchMode.TYPE_CONVERT]]): +class NumberPattern(Pattern[Union[int, float]]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=Union[int, float], alias="number") # type: ignore + super().__init__(origin=Union[int, float], alias="number") # type: ignore def match(self, input_: Any) -> int | float: if isinstance(input_, (float, int)): @@ -614,21 +352,21 @@ def match(self, input_: Any) -> int | float: return int(res) if res.is_integer() else res except (ValueError, TypeError) as e: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="int | float") + lang.require("nepattern", "error.content").format(target=input_, expected="int | float") ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is NumberPattern -NUMBER = NumberPattern() +NUMBER: Final = NumberPattern() """一般数表达式,既可以浮点数也可以整数 """ @final -class BoolPattern(BasePattern[bool, Union[str, bytes, bool], Literal[MatchMode.TYPE_CONVERT]]): +class BoolPattern(Pattern[bool]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=bool, alias="bool") + super().__init__(origin=bool, alias="bool") def match(self, input_: Any) -> bool: if input_ is True or input_ is False: @@ -641,20 +379,20 @@ def match(self, input_: Any) -> bool: return True if input_ == "false": return False - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected="bool")) + raise MatchFailed(lang.require("nepattern", "error.content").format(target=input_, expected="bool")) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is BoolPattern -BOOLEAN = BoolPattern() +BOOLEAN: Final = BoolPattern() """布尔表达式,只能接受true或false样式的量""" @final -class WideBoolPattern(BasePattern[bool, Any, Literal[MatchMode.TYPE_CONVERT]]): +class WideBoolPattern(Pattern[bool]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=bool, alias="bool") + super().__init__(origin=bool, alias="bool") BOOL_FALSE = {0, "0", "off", "f", "false", "n", "no"} BOOL_TRUE = {1, "1", "on", "t", "true", "y", "yes"} @@ -672,54 +410,52 @@ def match(self, input_: Any) -> bool: if input_ in self.BOOL_FALSE: return False raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="bool") + lang.require("nepattern", "error.content").format(target=input_, expected="bool") ) except (ValueError, TypeError) as e: raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="bool" ) ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is BoolPattern WIDE_BOOLEAN = WideBoolPattern() """宽松布尔表达式,可以接受更多的布尔样式的量""" -LIST = BasePattern(r"(\[.+?\])", MatchMode.REGEX_CONVERT, list, alias="list") -TUPLE = BasePattern(r"(\(.+?\))", MatchMode.REGEX_CONVERT, tuple, alias="tuple") -SET = BasePattern(r"(\{.+?\})", MatchMode.REGEX_CONVERT, set, alias="set") -DICT = BasePattern(r"(\{.+?\})", MatchMode.REGEX_CONVERT, dict, alias="dict") +LIST: Final[Pattern[list]] = Pattern.regex_convert(r"(\[.+?\])",list, lambda m: eval(m[1]), alias="list") +TUPLE: Final[Pattern[tuple]] = Pattern.regex_convert(r"(\(.+?\))",tuple, lambda m: eval(m[1]), alias="tuple") +SET: Final[Pattern[set]] = Pattern.regex_convert(r"(\{.+?\})",set, lambda m: eval(m[1]), alias="set") +DICT: Final[Pattern[dict]] = Pattern.regex_convert(r"(\{.+?\})",dict, lambda m: eval(m[1]), alias="dict") -EMAIL = BasePattern(r"(?:[\w\.+-]+)@(?:[\w\.-]+)\.(?:[\w\.-]+)", MatchMode.REGEX_MATCH, alias="email") +EMAIL: Final = Pattern.regex_match(r"(?:[\w\.+-]+)@(?:[\w\.-]+)\.(?:[\w\.-]+)", alias="email") """匹配邮箱地址的表达式""" -IP = BasePattern( +IP: Final = Pattern.regex_match( r"(?:(?:[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}(?:[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]):?(?:\d+)?", - MatchMode.REGEX_MATCH, alias="ip", ) """匹配Ip地址的表达式""" -URL = BasePattern( +URL: Final = Pattern.regex_match( r"(?:\w+://)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(?:\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(?::[0-9]{1,5})?[-a-zA-Z0-9()@:%_\\\+\.~#?&//=]*", - MatchMode.REGEX_MATCH, alias="url", ) """匹配网页链接的表达式""" @final -class HexPattern(BasePattern[int, str, Literal[MatchMode.TYPE_CONVERT]]): +class HexPattern(Pattern[int]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=int, alias="hex", accepts=str) + super().__init__(origin=int, alias="hex") - def match(self, input_: str) -> int: + def match(self, input_: Any) -> int: if not isinstance(input_, str): raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="str" ) ) @@ -727,50 +463,48 @@ def match(self, input_: str) -> int: return int(input_, 16) except ValueError as e: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="hex") + lang.require("nepattern", "error.content").format(target=input_, expected="hex") ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is HexPattern -HEX = HexPattern() +HEX: Final = HexPattern() """匹配16进制数的表达式""" -HEX_COLOR = BasePattern(r"(#[0-9a-fA-F]{6})", MatchMode.REGEX_CONVERT, str, lambda _, x: x[1][1:], "color") +HEX_COLOR = Pattern.regex_convert(r"(#[0-9a-fA-F]{6})", str, lambda m: m[1][1:], "color") """匹配16进制颜色代码的表达式""" @final -class DateTimePattern(BasePattern[datetime, Union[str, int, float], Literal[MatchMode.TYPE_CONVERT]]): +class DateTimePattern(Pattern[datetime]): def __init__(self): - super().__init__( - mode=MatchMode.TYPE_CONVERT, origin=datetime, alias="datetime", accepts=Union[str, int, float] - ) + super().__init__(origin=datetime, alias="datetime") - def match(self, input_: Union[str, int, float]) -> datetime: + def match(self, input_: Any) -> datetime: if isinstance(input_, (int, float)): return datetime.fromtimestamp(input_) if not isinstance(input_, str): raise MatchFailed( - lang.require("nepattern", "type_error").format( + lang.require("nepattern", "error.type").format( type=input_.__class__, target=input_, expected="str | int | float" ) ) return DateParser.parse(input_) - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is DateTimePattern -DATETIME = DateTimePattern() +DATETIME: Final = DateTimePattern() """匹配时间的表达式""" @final -class PathPattern(BasePattern[Path, Any, Literal[MatchMode.TYPE_CONVERT]]): +class PathPattern(Pattern[Path]): def __init__(self): - super().__init__(mode=MatchMode.TYPE_CONVERT, origin=Path, alias="path") + super().__init__(origin=Path, alias="path") def match(self, input_: Any) -> Path: if isinstance(input_, Path): @@ -780,31 +514,28 @@ def match(self, input_: Any) -> Path: return Path(input_) except (ValueError, TypeError) as e: raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected="PathLike") + lang.require("nepattern", "error.content").format(target=input_, expected="PathLike") ) from e - def __calc_eq__(self, other): # pragma: no cover + def __eq__(self, other): # pragma: no cover return other.__class__ is PathPattern -PATH = PathPattern() +PATH: Final = PathPattern() -PathFile = BasePattern( - mode=MatchMode.TYPE_CONVERT, - origin=bytes, - accepts=Path, - previous=PATH, - alias="filedata", - converter=lambda _, x: x.read_bytes() if x.exists() and x.is_file() else None, +PathFile: Final = ( + Pattern(bytes) + .accept(Union[str, Path, bytes]) + .pre_validate(lambda x: isinstance(x, bytes) or (isinstance(x, (str, Path)) and Path(x).is_file())) + .convert(lambda _, x: x if isinstance(x, bytes) else x.read_bytes()) ) def combine( - current: BasePattern[TOrigin, TInput, TMM], - previous: BasePattern[TInput, Any, Any] | None = None, + current: Pattern[_T], + previous: Pattern[Any], alias: str | None = None, - validators: list[Callable[[TOrigin], bool]] | None = None, -) -> BasePattern[TOrigin, TInput, TMM]: +) -> Pattern[_T]: _new = current.copy() if previous: _match = _new.match @@ -815,14 +546,11 @@ def match(self, input_): _new.match = match.__get__(_new) if alias: _new.alias = alias - _new.refresh() - if validators: - _new.validators = validators return _new DelimiterInt = combine( INTEGER, - BasePattern(mode=MatchMode.VALUE_OPERATE, origin=str, converter=lambda _, x: x.replace(",", "_")), + Pattern(str).accept(str).convert(lambda _, x: x.replace(",", "_")), "DelimInt", ) diff --git a/nepattern/context.py b/nepattern/context.py index dac4d94..dfb6a7f 100644 --- a/nepattern/context.py +++ b/nepattern/context.py @@ -4,8 +4,6 @@ from contextvars import ContextVar, Token from typing import final -from tarina import Empty - from .base import NONE, UnionPattern @@ -33,9 +31,9 @@ def set(self, target, alias=None, cover=True, no_alias=False): else: al_pat = self.data[k] self.data[k] = ( - UnionPattern([*al_pat.base, target]) + UnionPattern(*al_pat.base, target) if isinstance(al_pat, UnionPattern) - else (UnionPattern([al_pat, target])) + else (UnionPattern(al_pat, target)) ) def sets(self, patterns, cover=True, no_alias=False): @@ -49,7 +47,7 @@ def merge(self, patterns, no_alias=False): def remove(self, origin_type, alias=None): if alias and (al_pat := self.data.get(alias)): if isinstance(al_pat, UnionPattern): - self.data[alias] = UnionPattern(filter(lambda x: x.alias != alias, al_pat.base)) # type: ignore + self.data[alias] = UnionPattern(*filter(lambda x: x.alias != alias, al_pat.base)) # type: ignore if not self.data[alias].base: # type: ignore # pragma: no cover del self.data[alias] else: @@ -57,7 +55,7 @@ def remove(self, origin_type, alias=None): elif al_pat := self.data.get(origin_type): if isinstance(al_pat, UnionPattern): self.data[origin_type] = UnionPattern( - filter(lambda x: x.origin != origin_type, al_pat.for_validate) + *filter(lambda x: x.origin != origin_type, al_pat.for_validate) ) if not self.data[origin_type].base: # type: ignore # pragma: no cover del self.data[origin_type] diff --git a/nepattern/context.pyi b/nepattern/context.pyi index 64f8455..c7c4261 100644 --- a/nepattern/context.pyi +++ b/nepattern/context.pyi @@ -1,14 +1,14 @@ from collections import UserDict from typing import Any, Iterable, final -from .core import BasePattern +from .core import Pattern @final -class Patterns(UserDict[Any, BasePattern]): +class Patterns(UserDict[Any, Pattern]): name: str def __init__(self, name: str): ... def set( - self, target: BasePattern[Any, Any, Any], alias: str | None = None, cover: bool = True, no_alias=False + self, target: Pattern[Any], alias: str | None = None, cover: bool = True, no_alias=False ): """ 增加可使用的类型转换器 @@ -21,13 +21,13 @@ class Patterns(UserDict[Any, BasePattern]): """ ... - def sets(self, patterns: Iterable[BasePattern[Any, Any, Any]], cover: bool = True, no_alias=False): ... - def merge(self, patterns: dict[str, BasePattern[Any, Any, Any]], no_alias=False): ... + def sets(self, patterns: Iterable[Pattern[Any]], cover: bool = True, no_alias=False): ... + def merge(self, patterns: dict[str, Pattern[Any]], no_alias=False): ... def remove(self, origin_type: type, alias: str | None = None): ... def create_local_patterns( name: str, - data: dict[Any, BasePattern[Any, Any, Any]] | None = None, + data: dict[Any, Pattern[Any]] | None = None, set_current: bool = True, ) -> Patterns: """ diff --git a/nepattern/core.py b/nepattern/core.py index 7a0c3e3..467a6b2 100644 --- a/nepattern/core.py +++ b/nepattern/core.py @@ -1,10 +1,9 @@ from __future__ import annotations from copy import deepcopy -from enum import Enum, IntEnum import re -from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar -from typing_extensions import Self, get_args, get_origin +from typing import Any, Callable, Generic, TypeVar, overload +from typing_extensions import Self from tarina import Empty, generic_isinstance from tarina.lang import lang @@ -12,780 +11,146 @@ from .exception import MatchFailed -class MatchMode(IntEnum): - """参数表达式匹配模式""" - - VALUE_OPERATE = 4 - """传入值进行操作""" - REGEX_CONVERT = 3 - """正则匹配并转换""" - TYPE_CONVERT = 2 - """传入值直接转换""" - REGEX_MATCH = 1 - """正则匹配""" - KEEP = 0 - """保持传入值""" - - -class ResultFlag(str, Enum): - """参数表达式验证结果标识符""" - - VALID = "valid" - "验证通过" - ERROR = "error" - "验证失败" - DEFAULT = "default" - "默认值" - - T = TypeVar("T") -TInput = TypeVar("TInput", covariant=True) -TOrigin = TypeVar("TOrigin") -TVOrigin = TypeVar("TVOrigin") -TDefault = TypeVar("TDefault") -TVRF = TypeVar("TVRF", bound=ResultFlag) -TMM = TypeVar("TMM", bound=MatchMode) -class ValidateResult(Generic[TVOrigin, TVRF]): +class ValidateResult(Generic[T]): """参数表达式验证结果""" def __init__( self, - value: TVOrigin | type[Empty] = Empty, + value: T | type[Empty] = Empty, error: Exception | type[Empty] = Empty, - flag: TVRF = ResultFlag.VALID, ): self._value = value self._error = error - self.flag = flag - __slots__ = ("_value", "_error", "flag") + __slots__ = ("_value", "_error") - def value(self) -> TVOrigin: - if self.flag == ResultFlag.ERROR or self._value == Empty: + def value(self) -> T: + if self._value is Empty: raise RuntimeError("cannot access value") return self._value # type: ignore def error(self) -> Exception | None: - if self.flag == ResultFlag.ERROR and self._error != Empty: + if self._error is not Empty: assert isinstance(self._error, Exception) return self._error @property def success(self) -> bool: - return self.flag == ResultFlag.VALID + return self._value is not Empty @property def failed(self) -> bool: - return self.flag == ResultFlag.ERROR - - @property - def or_default(self) -> bool: - return self.flag == ResultFlag.DEFAULT - - def step( - self, other: type[T] | Callable[[TVOrigin], T] | Any | BasePattern[T, TVOrigin, MatchMode] - ) -> T | Self | ValidateResult[T, TVRF]: - if other is bool: - return self.success # type: ignore - if callable(other) and self.success: - return other(self.value()) # type: ignore - return other.validate(self.value()) if isinstance(other, BasePattern) else self # type: ignore - - def __rshift__( - self, other: type[T] | Callable[[TVOrigin], T] | Any - ) -> T | Self | ValidateResult[T, TVRF]: - return self.step(other) # type: ignore + return self._value is Empty def __bool__(self): - return self.flag != ResultFlag.ERROR + return self._value != Empty def __repr__(self): - if self.flag == ResultFlag.VALID: - return f"ValidateResult(value={self._value!r})" - if self.flag == ResultFlag.ERROR: - return f"ValidateResult(error={self._error!r})" - return f"ValidateResult(default={self._value!r})" - - -def _keep_any(self: BasePattern[Any, Any, Literal[MatchMode.KEEP]], input_: Any) -> Any: - return input_ - - -def _keep_no_previous(self: BasePattern[Any, Any, Literal[MatchMode.KEEP]], input_: Any) -> Any: - if not self.accept(input_): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - return input_ - - -def _keep_previous(self: BasePattern[Any, Any, Literal[MatchMode.KEEP]], input_: Any) -> Any: - if TYPE_CHECKING: - assert self.previous - if self.accept(input_): - input_ = self.previous.match(input_) - elif not self.accept(input_ := self.previous.match(input_)): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - return input_ - - -def select_keep_match(self: BasePattern[Any, Any, Literal[MatchMode.KEEP]]): - if self._accepts or self._pattern_accepts: - return _keep_previous if self.previous else _keep_no_previous - return _keep_any - - -def _regex_match_no_previous(self: BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]], input_: Any) -> str: - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - return mat[0] - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_match_type(self: BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]], input_: Any) -> str: - if TYPE_CHECKING: - assert self.previous - if not isinstance(input_, str) and not isinstance( - input_ := self.previous.match(input_), str - ): # pragma: no cover - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - return mat[0] - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_match_value(self: BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]], input_: Any) -> str: - if TYPE_CHECKING: - assert self.previous - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - input_ = self.previous.match(input_) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - return mat[0] - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def select_regex_match(self: BasePattern[Any, Any, Literal[MatchMode.REGEX_MATCH]]): - if self.previous: - if self.previous.mode == MatchMode.TYPE_CONVERT: - return _regex_match_type - return _regex_match_value - return _regex_match_no_previous - - -def _regex_convert_no_previous_any( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_convert_no_previous_other( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if generic_isinstance(input_, self.origin): - return input_ # type: ignore - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_convert_any_type( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not isinstance(input_, str) and not isinstance(input_ := self.previous.match(input_), str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_convert_any_value( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - input_ = self.previous.match(input_) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_convert_value( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - input_ = self.previous.match(input_) - if generic_isinstance(input_, self.origin): - return input_ # type: ignore - if not isinstance(input_, str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def _regex_convert_type( - self: BasePattern[TOrigin, str | TOrigin, Literal[MatchMode.REGEX_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if generic_isinstance(input_, self.origin): - return input_ # type: ignore - if not isinstance(input_, str) and not isinstance(input_ := self.previous.match(input_), str): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if mat := (self.regex_pattern.match(input_) or self.regex_pattern.search(input_)): - if (res := self.converter(self, mat)) is not None: - return res - raise MatchFailed(lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)) - - -def select_regex_convert(self: BasePattern[Any, Any, Literal[MatchMode.REGEX_CONVERT]]): - if self.origin is Any or self.origin is str: - if not self.previous: - return _regex_convert_no_previous_any - return ( - _regex_convert_any_value - if self.previous.mode == MatchMode.VALUE_OPERATE - else _regex_convert_any_type - ) - if not self.previous: - return _regex_convert_no_previous_other - if self.previous.mode == MatchMode.VALUE_OPERATE: - return _regex_convert_value - return _regex_convert_type - - -def _type_convert_no_previous_no_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_no_previous_no_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_no_previous_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if not self.accept(input_): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_no_previous_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if not self.accept(input_): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_type_no_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if (res := self.converter(self, input_)) is None and ( - res := self.converter(self, self.previous.match(input_)) - ) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_type_no_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None and ( - res := self.converter(self, self.previous.match(input_)) - ) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_type_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not self.accept(input_) and not self.accept(input_ := self.previous.match(input_)): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if (res := self.converter(self, input_)) is None and ( - res := self.converter(self, self.previous.match(input_)) - ) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_type_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not self.accept(input_) and not self.accept(input_ := self.previous.match(input_)): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None and ( - res := self.converter(self, self.previous.match(input_)) - ) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_value_no_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - input_ = self.previous.match(input_) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_value_no_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - input_ = self.previous.match(input_) - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_value_accepts_any( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if self.accept(input_): - input_ = self.previous.match(input_) - elif not self.accept(input_ := self.previous.match(input_)): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _type_convert_value_accepts_other( - self: BasePattern[TOrigin, Any, Literal[MatchMode.TYPE_CONVERT]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if self.accept(input_): - input_ = self.previous.match(input_) - elif not self.accept(input_ := self.previous.match(input_)): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if generic_isinstance(input_, self.origin): - return input_ - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def select_type_convert(self: BasePattern[Any, Any, Literal[MatchMode.TYPE_CONVERT]]): - if self._accepts or self._pattern_accepts: - if self.origin is Any: - if not self.previous: - return _type_convert_no_previous_accepts_any - return _type_convert_value_accepts_any if self.previous else _type_convert_type_accepts_any - if not self.previous: - return _type_convert_no_previous_accepts_other - return _type_convert_value_accepts_other if self.previous else _type_convert_type_accepts_other - if self.origin is Any: - if not self.previous: - return _type_convert_no_previous_no_accepts_any - return _type_convert_value_no_accepts_any if self.previous else _type_convert_type_no_accepts_any - if not self.previous: - return _type_convert_no_previous_no_accepts_other - return _type_convert_value_no_accepts_other if self.previous else _type_convert_type_no_accepts_other - - -def _value_operate_no_previous( - self: BasePattern[TOrigin, TOrigin, Literal[MatchMode.VALUE_OPERATE]], input_: Any -) -> TOrigin: - if not generic_isinstance(input_, self.origin): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _value_operate_type( - self: BasePattern[TOrigin, TOrigin, Literal[MatchMode.VALUE_OPERATE]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not generic_isinstance(input_, self.origin) and not generic_isinstance( - input_ := self.previous.match(input_), self.origin - ): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def _value_operate_value( - self: BasePattern[TOrigin, TOrigin, Literal[MatchMode.VALUE_OPERATE]], input_: Any -) -> TOrigin: - if TYPE_CHECKING: - assert self.previous - if not generic_isinstance(input_, self.origin): - raise MatchFailed( - lang.require("nepattern", "type_error").format( - type=input_.__class__, target=input_, expected=self.alias - ) - ) - input_ = self.previous.match(input_) - if (res := self.converter(self, input_)) is None: - raise MatchFailed( - lang.require("nepattern", "content_error").format(target=input_, expected=self.alias) - ) - return res # type: ignore - - -def select_value_operate(self: BasePattern[Any, Any, Literal[MatchMode.VALUE_OPERATE]]): - if self.previous: - if self.previous.mode == MatchMode.TYPE_CONVERT: - return _value_operate_type - return _value_operate_value - return _value_operate_no_previous - - -_MATCHES = { - MatchMode.KEEP: select_keep_match, - MatchMode.REGEX_MATCH: select_regex_match, - MatchMode.REGEX_CONVERT: select_regex_convert, - MatchMode.TYPE_CONVERT: select_type_convert, - MatchMode.VALUE_OPERATE: select_value_operate, -} - - -class BasePattern(Generic[TOrigin, TInput, TMM]): - """对参数类型值的包装""" - - __slots__ = ( - "regex_pattern", - "pattern", - "mode", - "converter", - "origin", - "alias", - "previous", - "validators", - "match", - "accept", - "_accepts", - "_pattern_accepts", - "_hash", - "_repr", - ) - - def __new__(cls, *args, **kwargs): - cls.__eq__ = cls.__calc_eq__ - return super().__new__(cls) + return f"ValidateResult(value={self._value!r})" if self._value is not Empty else f"ValidateResult(error={self._error!r})" - def __init__( - self, - pattern: str | None = None, - mode: TMM | None = None, - origin: type[TOrigin] | None = None, - converter: Callable[[BasePattern, Any], TOrigin | None] | None = None, - alias: str | None = None, - previous: BasePattern | None = None, - accepts: Any = None, - addition_accepts: BasePattern | None = None, - validators: list[Callable[[TOrigin], bool]] | None = None, - ): - """ - 初始化参数匹配表达式 - """ - if pattern is None: - _origin = origin or Any - self.mode = MatchMode(mode or MatchMode.KEEP) - self.pattern = "" - self.regex_pattern = re.compile("") - else: - if pattern.startswith("^") or pattern.endswith("$"): - raise ValueError( - lang.require("nepattern", "pattern_head_or_tail_error").format(target=pattern) - ) - self.pattern = pattern - self.regex_pattern = re.compile(f"^{pattern}$") - self.mode = MatchMode(mode or MatchMode.REGEX_MATCH) - _origin = origin or str - self.origin: type[TOrigin] = _origin # type: ignore - self.alias = alias - self.previous = previous - if TYPE_CHECKING: - assert self.origin is not None - if self.mode == MatchMode.TYPE_CONVERT: - if not converter and (not origin or origin is Any): - raise ValueError(origin) - self.converter = converter or (lambda _, x: (get_origin(self.origin) or self.origin)(x)) # type: ignore - elif self.mode == MatchMode.VALUE_OPERATE: - if not converter: - raise ValueError(converter) - self.converter = converter - else: - self.converter = converter or (lambda _, x: eval(x[0])) - self.validators = validators or [] - if accepts is Any or not accepts: - _accepts = Any - self._accepts = () - else: - _accepts = get_args(accepts) or accepts - self._accepts = get_args(accepts) or (accepts,) - self._pattern_accepts = addition_accepts - self._repr = self.__calc_repr__() - self._hash = self.__calc_hash__() - - if not addition_accepts: - self.accept = (lambda x: True) if _accepts is Any else (lambda _: generic_isinstance(_, _accepts)) - elif _accepts is Any: - self.accept = lambda _: addition_accepts.validate(_).flag == "valid" - else: - self.accept = lambda _: ( - generic_isinstance(_, _accepts) or addition_accepts.validate(_).flag == "valid" - ) - if not hasattr(self, "match"): - self.match = _MATCHES[self.mode](self).__get__(self) # type: ignore - - def refresh(self): # pragma: no cover - self._repr = self.__calc_repr__() - self._hash = self.__calc_hash__() - - def __calc_hash__(self): - return hash( - (self._repr, self.origin, self.mode, self.alias, self.previous, self._accepts, self.pattern) - ) - - def __calc_repr__(self): - if self.mode == MatchMode.KEEP: - if self.alias: - return self.alias - return ( - "Any" - if not self._accepts and not self._pattern_accepts - else "|".join([x.__name__ for x in self._accepts] + [self._pattern_accepts.__repr__()]) - ) - - if not self.alias: - name = getattr(self.origin, "__name__", str(self.origin)) - if self.mode == MatchMode.REGEX_MATCH: - text = self.pattern - elif self.mode == MatchMode.REGEX_CONVERT or (not self._accepts and not self._pattern_accepts): - text = name - else: - text = ( - "|".join([x.__name__ for x in self._accepts] + [self._pattern_accepts.__repr__()]) - + f" -> {name}" - ) - else: - text = self.alias - return ( - f"{f'{self.previous.__repr__()} -> ' if self.previous and id(self.previous) != id(self) else ''}" - f"{text}" - ) - def __repr__(self): - return self._repr - - def __str__(self): - return self._repr +class Pattern(Generic[T]): + @staticmethod + def regex_match(pattern: str, alias: str | None = None): + pat = Pattern(str, alias) - def __hash__(self): - return self._hash + @pat.convert + def _(self, x: str): + mat = re.match(pattern, x) + if not mat: + raise MatchFailed(lang.require("nepattern", "error.content").format(target=x, expected=pattern)) + return x - def __calc_eq__(self, other): - return isinstance(other, self.__class__) and self._hash == other._hash + return pat @staticmethod - def of(unit: type[TOrigin]): - """提供 Type[DataUnit] 类型的构造方法""" - from .base import DirectTypePattern + def regex_convert(pattern: str, origin: type[T], fn: Callable[[re.Match], T], alias: str | None = None): + pat = Pattern(origin, alias).accept(str) + + @pat.convert + def _(self, x: str): + mat = re.match(pattern, x) + if not mat: + raise MatchFailed(lang.require("nepattern", "error.content").format(target=x, expected=pattern)) + return fn(mat) - return DirectTypePattern(unit) + return pat @staticmethod - def on(obj: TOrigin): + def on(obj: T): """提供 DataUnit 类型的构造方法""" from .base import DirectPattern return DirectPattern(obj) - @staticmethod - def to(content: Any): - """便捷的使用 type_parser 的方法""" - from .main import parser + @overload + def __init__(self, origin: type[T], alias: str | None = None): + ... + + @overload + def __init__(self: Pattern[Any], *, alias: str | None = None): + ... + + def __init__(self, origin: type[T] | None = None, alias: str | None = None): + self.origin: type[T] = origin or Any # type: ignore + self.alias = alias - res = parser(content, "allow") - return res if isinstance(res, BasePattern) else parser(Any) # type: ignore + self._accepts = Any + self._post_validator = lambda x: generic_isinstance(x, self.origin) + self._pre_validator = None + self._converter = None - def validate(self, input_: Any, default: TDefault | Empty = Empty) -> ValidateResult[TOrigin | TDefault, ResultFlag]: # type: ignore - """ - 对传入的值进行正向验证,返回可能的匹配与转化结果。 + def accept(self, input_type: Any): + self._accepts = input_type + return self + + def pre_validate(self, func: Callable[[Any], bool]): + self._pre_validator = func + return self + + def post_validate(self, func: Callable[[T], bool]): + self._post_validator = func + return self - 若传入默认值,验证失败会返回默认值 - """ + def convert(self, func: Callable[[Self, Any], T]): + self._converter = func + return self + + def match(self, input_: Any) -> T: + if not generic_isinstance(input_, self._accepts): + raise MatchFailed(lang.require("nepattern", "error.type").format(target=input_, expected=self._accepts)) + if self._pre_validator and not self._pre_validator(input_): + raise MatchFailed(lang.require("nepattern", "error.content").format(target=input_, expected=self.origin)) + if self._converter: + input_ = self._converter(self, input_) + if self._post_validator and not self._post_validator(input_): + raise MatchFailed(lang.require("nepattern", "error.content").format(target=input_, expected=self.origin)) + return input_ + + def execute(self, input_: Any) -> ValidateResult[T]: try: - res = self.match(input_) - if self.validators and not all(i(res) for i in self.validators): - raise MatchFailed(lang.require("nepattern", "validate_error").format(target=input_)) - return ValidateResult(value=res, flag=ResultFlag.VALID) + return ValidateResult(self.match(input_)) except Exception as e: - if default is Empty: - return ValidateResult(error=e, flag=ResultFlag.ERROR) - return ValidateResult(default, flag=ResultFlag.DEFAULT) # type: ignore + return ValidateResult(error=e) + + def __str__(self): + if self.alias: + return self.alias + if self._accepts is self.origin: + return f"{self.origin.__name__}" + return f"{self._accepts.__name__} -> {self.origin.__name__}" + + def __repr__(self): + return f"Pattern({self.origin.__name__}, {self.alias})" def copy(self) -> Self: return deepcopy(self) def __rrshift__(self, other): - return self.validate(other) + return self.execute(other) def __rmatmul__(self, other) -> Self: # pragma: no cover if isinstance(other, str): @@ -796,12 +161,3 @@ def __matmul__(self, other) -> Self: # pragma: no cover if isinstance(other, str): self.alias = other return self - - def __or__(self, other): - from .base import UnionPattern - - if isinstance(other, BasePattern): - return UnionPattern([self, other]) # type: ignore - raise TypeError( # pragma: no cover - f"unsupported operand type(s) for |: 'BasePattern' and '{other.__class__.__name__}'" - ) diff --git a/nepattern/core.pyi b/nepattern/core.pyi deleted file mode 100644 index 95df358..0000000 --- a/nepattern/core.pyi +++ /dev/null @@ -1,883 +0,0 @@ -from __future__ import annotations - -from enum import Enum, IntEnum -import re -from typing import Any, Callable, Generic, Literal, TypeVar, overload -from typing_extensions import NoReturn, Self - -from tarina import Empty - -from .base import DirectPattern, DirectTypePattern -from .util import TPattern - -class MatchMode(IntEnum): - """参数表达式匹配模式""" - - VALUE_OPERATE = 4 - """传入值进行操作""" - REGEX_CONVERT = 3 - """正则匹配并转换""" - TYPE_CONVERT = 2 - """传入值直接转换""" - REGEX_MATCH = 1 - """正则匹配""" - KEEP = 0 - """保持传入值""" - -class ResultFlag(str, Enum): - """参数表达式验证结果标识符""" - - VALID = "valid" - "验证通过" - ERROR = "error" - "验证失败" - DEFAULT = "default" - "默认值" - -T = TypeVar("T") -T1 = TypeVar("T1") -TInput = TypeVar("TInput", covariant=True) -TInput1 = TypeVar("TInput1") -TInput2 = TypeVar("TInput2") -TInput3 = TypeVar("TInput3") -TInput4 = TypeVar("TInput4") -TOrigin = TypeVar("TOrigin") -TOrigin1 = TypeVar("TOrigin1") -TVOrigin = TypeVar("TVOrigin") -TDefault = TypeVar("TDefault") -TVRF = TypeVar("TVRF", bound=ResultFlag) -TMM = TypeVar("TMM", bound=MatchMode) - -class ValidateResult(Generic[TVOrigin, TVRF]): - """参数表达式验证结果""" - - flag: TVRF - _value: TVOrigin | type[Empty] - _error: Exception | type[Empty] - - def __init__( - self, - value: TVOrigin | type[Empty] = Empty, - error: Exception | type[Empty] = Empty, - flag: TVRF = ResultFlag.VALID, - ): ... - @overload - def value(self: ValidateResult[Any, Literal[ResultFlag.ERROR]]) -> NoReturn: ... - @overload - def value(self: ValidateResult[TVOrigin, TVRF]) -> TVOrigin: ... - @overload - def error(self: ValidateResult[Any, Literal[ResultFlag.VALID]]) -> None: ... - @overload - def error(self: ValidateResult[Any, Literal[ResultFlag.ERROR]]) -> Exception: ... - @overload - def error(self: ValidateResult[Any, Literal[ResultFlag.DEFAULT]]) -> None: ... - @overload - def error(self: ValidateResult[TVOrigin, TVRF]) -> Exception | None: ... - @property - def success(self) -> bool: ... - @property - def failed(self) -> bool: ... - @property - def or_default(self) -> bool: ... - @overload - def step(self, other: type[T]) -> T: ... - @overload - def step(self, other: BasePattern[T, TVOrigin, MatchMode]) -> ValidateResult[T, TVRF]: ... - @overload - def step(self, other: Callable[[TVOrigin], T]) -> T: ... - @overload - def step(self, other: Any) -> Self: ... - @overload - def __rshift__(self, other: BasePattern[T, TVOrigin, MatchMode]) -> ValidateResult[T, TVRF]: ... - @overload - def __rshift__(self, other: type[T]) -> T: ... - @overload - def __rshift__(self, other: Callable[[TVOrigin], T]) -> T: ... - @overload - def __rshift__(self, other: Any) -> Self: ... - @overload - def __bool__( - self: ( - ValidateResult[TVOrigin, Literal[ResultFlag.VALID]] - | ValidateResult[TVOrigin, Literal[ResultFlag.DEFAULT]] - ) - ) -> Literal[True]: ... - @overload - def __bool__(self: ValidateResult[TVOrigin, Literal[ResultFlag.ERROR]]) -> Literal[False]: ... - def __repr__(self): ... - -_MATCHES: dict[MatchMode, Callable[[Any], Callable[[Any, Any], Any]]] = {} - -class BasePattern(Generic[TOrigin, TInput, TMM]): - """对参数类型值的包装""" - - regex_pattern: TPattern # type: ignore - pattern: str - mode: MatchMode - converter: Callable[[BasePattern[TOrigin, TInput, TMM], Any], TOrigin | None] - validators: list[Callable[[TOrigin], bool]] - - origin: type[TOrigin] - alias: str | None - previous: BasePattern | None - accept: Callable[[Any], bool] - _repr: str - _hash: int - _accepts: type[Any] | tuple[type[Any], ...] - _pattern_accepts: BasePattern | None - - @overload - def __init__( - self: BasePattern[Any, Any, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - origin: Any = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[T], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1, TInput1, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - accepts: type[TInput1], - origin: Any = None, - alias: str | None = None, - previous: None = None, - addition_accepts: None = None, - validators: list[Callable[[TInput1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1, TInput1, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - addition_accepts: BasePattern[Any, TInput1, Any], - origin: Any = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - validators: list[Callable[[TInput1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1 | TInput2, TInput1 | TInput2, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - accepts: type[TInput1], - addition_accepts: BasePattern[Any, TInput2, Any], - origin: Any = None, - alias: str | None = None, - previous: None = None, - validators: list[Callable[[TInput1 | TInput2], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1, TInput1, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - accepts: type[TInput1], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - origin: Any = None, - alias: str | None = None, - addition_accepts: None = None, - validators: list[Callable[[TInput1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1, TInput1, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - addition_accepts: BasePattern[Any, TInput1, Any], - origin: Any = None, - alias: str | None = None, - accepts: None = None, - validators: list[Callable[[TInput1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TInput1 | TInput2, TInput1 | TInput2, Literal[MatchMode.KEEP]], - *, - mode: Literal[MatchMode.KEEP], - accepts: type[TInput1], - previous: BasePattern[TInput1 | TInput2, TInput1 | TInput2, Literal[MatchMode.VALUE_OPERATE]], - addition_accepts: BasePattern[Any, TInput2, Any], - origin: Any = None, - alias: str | None = None, - validators: list[Callable[[TInput1 | TInput2], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]], - pattern: str, - mode: Literal[MatchMode.REGEX_MATCH], - origin: type[str] = str, - converter: None = None, - alias: str | None = None, - previous: None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[str], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]], - pattern: str, - mode: Literal[MatchMode.REGEX_MATCH], - previous: BasePattern[str, str, Literal[MatchMode.VALUE_OPERATE]], - origin: type[str] = str, - converter: None = None, - alias: str | None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[str], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[str, str | TInput1, Literal[MatchMode.REGEX_MATCH]], - pattern: str, - mode: Literal[MatchMode.REGEX_MATCH], - previous: BasePattern[str, TInput1, Literal[MatchMode.TYPE_CONVERT]], - origin: type[str] = str, - converter: None = None, - alias: str | None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[str], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, str | TOrigin1, Literal[MatchMode.REGEX_CONVERT]], - pattern: str, - mode: Literal[MatchMode.REGEX_CONVERT], - origin: type[TOrigin1], - converter: ( - Callable[ - [BasePattern[TOrigin1, str | TOrigin1, Literal[MatchMode.REGEX_CONVERT]], re.Match[str]], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - previous: None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, str | TOrigin1 | TInput1, Literal[MatchMode.REGEX_CONVERT]], - pattern: str, - mode: Literal[MatchMode.REGEX_CONVERT], - origin: type[TOrigin1], - previous: ( - BasePattern[str | TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[str, TInput1, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]] - ), - converter: ( - Callable[ - [ - BasePattern[TOrigin1, str | TOrigin1 | TInput1, Literal[MatchMode.REGEX_CONVERT]], - re.Match[str], - ], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, str | TOrigin1, Literal[MatchMode.REGEX_CONVERT]], - pattern: str, - mode: Literal[MatchMode.REGEX_CONVERT], - origin: type[TOrigin1], - previous: ( - BasePattern[str | TOrigin1, str | TOrigin1, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[str, str, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TOrigin1, TOrigin1, Literal[MatchMode.VALUE_OPERATE]] - ), - converter: ( - Callable[ - [BasePattern[TOrigin1, str | TOrigin1, Literal[MatchMode.REGEX_CONVERT]], re.Match[str]], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - accepts: type[str] = str, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - converter: Callable[ - [BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], Any], TOrigin1 | None - ], - origin: None = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ], - origin: None = None, - alias: str | None = None, - previous: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - addition_accepts: BasePattern[Any, TInput1, Any], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ], - origin: None = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - addition_accepts: BasePattern[Any, TInput2, Any], - converter: Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput2], - TOrigin1 | None, - ], - origin: None = None, - alias: str | None = None, - previous: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - converter: ( - Callable[[BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], Any], TOrigin1 | None] | None - ) = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ] - | None - ) = None, - alias: str | None = None, - previous: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - addition_accepts: BasePattern[Any, TInput1, Any], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ] - | None - ) = None, - alias: str | None = None, - previous: None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - addition_accepts: BasePattern[Any, TInput2, Any], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput2], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - previous: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - previous: BasePattern[TInput1, Any, Literal[MatchMode.TYPE_CONVERT]], - converter: Callable[ - [BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], TInput1 | Any], TOrigin1 | None - ], - alias: str | None = None, - origin: None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - previous: BasePattern[TInput1, Any, Literal[MatchMode.TYPE_CONVERT]], - converter: ( - Callable[ - [BasePattern[TOrigin1, Any, Literal[MatchMode.TYPE_CONVERT]], TInput1 | Any], TOrigin1 | None - ] - | None - ) = None, - alias: str | None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ], - alias: str | None = None, - origin: None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TOrigin1 | TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - previous: ( - BasePattern[TOrigin1 | TInput1, TOrigin1 | TInput1, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TOrigin1, TOrigin1, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]] - ), - converter: ( - Callable[ - [BasePattern[TOrigin1, TOrigin1 | TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - previous: BasePattern[TInput4 | TInput1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput4], - TOrigin1 | None, - ], - alias: str | None = None, - origin: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - previous: BasePattern[TInput4 | TInput1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput4], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ], - alias: str | None = None, - origin: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ] - | None - ) = None, - alias: str | None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - addition_accepts: BasePattern[Any, TInput1, Any], - previous: BasePattern[TInput4 | TInput1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput4], - TOrigin1 | None, - ], - alias: str | None = None, - origin: None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - addition_accepts: BasePattern[Any, TInput1, Any], - previous: BasePattern[TInput4 | TInput1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput4], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - addition_accepts: BasePattern[Any, TInput1, Any], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ], - alias: str | None = None, - origin: None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - addition_accepts: BasePattern[Any, TInput1, Any], - previous: BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], TInput1], TOrigin1 | None - ] - | None - ) = None, - alias: str | None = None, - accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - previous: ( - BasePattern[TInput1 | TInput3, TInput2, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[TInput1, TInput2, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[TInput3, TInput2, Literal[MatchMode.TYPE_CONVERT]] - ), - addition_accepts: BasePattern[Any, TInput3, Any], - converter: Callable[ - [ - BasePattern[TOrigin1, TInput1 | TInput2 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - TInput1 | TInput3, - ], - TOrigin1 | None, - ], - alias: str | None = None, - origin: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput2 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - previous: ( - BasePattern[TInput1 | TInput3, TInput2, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[TInput1, TInput2, Literal[MatchMode.TYPE_CONVERT]] - | BasePattern[TInput3, TInput2, Literal[MatchMode.TYPE_CONVERT]] - ), - addition_accepts: BasePattern[Any, TInput3, Any], - converter: ( - Callable[ - [ - BasePattern[TOrigin1, TInput1 | TInput2 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - TInput1 | TInput3, - ], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - accepts: type[TInput1], - previous: ( - BasePattern[TInput1 | TInput3, TInput1 | TInput3, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TInput3, TInput3, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]] - ), - addition_accepts: BasePattern[Any, TInput3, Any], - converter: Callable[ - [BasePattern[TOrigin1, TInput1 | TInput3, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput3], - TOrigin1 | None, - ], - origin: None = None, - alias: str | None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1 | TInput3, Literal[MatchMode.TYPE_CONVERT]], - *, - mode: Literal[MatchMode.TYPE_CONVERT], - origin: type[TOrigin1], - accepts: type[TInput1], - previous: ( - BasePattern[TInput1 | TInput3, TInput1 | TInput3, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TInput3, TInput3, Literal[MatchMode.VALUE_OPERATE]] - | BasePattern[TInput1, TInput1, Literal[MatchMode.VALUE_OPERATE]] - ), - addition_accepts: BasePattern[Any, TInput3, Any], - converter: ( - Callable[ - [BasePattern[TOrigin1, TInput1 | TInput3, Literal[MatchMode.TYPE_CONVERT]], TInput1 | TInput3], - TOrigin1 | None, - ] - | None - ) = None, - alias: str | None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TOrigin1, Literal[MatchMode.VALUE_OPERATE]], - *, - mode: Literal[MatchMode.VALUE_OPERATE], - origin: type[TOrigin1], - converter: Callable[ - [BasePattern[TOrigin1, TOrigin1, Literal[MatchMode.VALUE_OPERATE]], TOrigin1], TOrigin1 | None - ], - alias: str | None = None, - previous: BasePattern[TOrigin1, TOrigin1, Literal[MatchMode.VALUE_OPERATE]] | None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TInput1, Literal[MatchMode.VALUE_OPERATE]], - *, - mode: Literal[MatchMode.VALUE_OPERATE], - origin: type[TOrigin1], - previous: BasePattern[TOrigin1, TInput1, Literal[MatchMode.TYPE_CONVERT]], - converter: Callable[ - [BasePattern[TOrigin1, TInput1, Literal[MatchMode.VALUE_OPERATE]], TOrigin1], - TOrigin1 | None, - ], - alias: str | None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - @overload - def __init__( - self: BasePattern[TOrigin1, TOrigin1 | TInput2, Literal[MatchMode.VALUE_OPERATE]], - *, - mode: Literal[MatchMode.VALUE_OPERATE], - origin: type[TOrigin1], - previous: BasePattern[TOrigin1, TOrigin1 | TInput2, Literal[MatchMode.TYPE_CONVERT]], - converter: Callable[ - [BasePattern[TOrigin1, TOrigin1 | TInput2, Literal[MatchMode.VALUE_OPERATE]], TOrigin1], - TOrigin1 | None, - ], - alias: str | None = None, - accepts: None = None, - addition_accepts: None = None, - validators: list[Callable[[TOrigin1], bool]] | None = None, - ): ... - def refresh(self): ... - def __calc_hash__(self): ... - def __calc_repr__(self): ... - def __calc_eq__(self, other): ... - def __repr__(self): ... - def __str__(self): ... - def __hash__(self): ... - def __eq__(self, other): ... - @staticmethod - def of(unit: type[TOrigin1]) -> DirectTypePattern[TOrigin1]: - """提供 Type[DataUnit] 类型的构造方法""" - ... - - @staticmethod - def on(obj: TOrigin1) -> DirectPattern[TOrigin1]: - """提供 DataUnit 类型的构造方法""" - ... - - @staticmethod - def to(content: Any) -> BasePattern: - """便捷的使用 type_parser 的方法""" - ... - - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.KEEP]], input_: TInput1 - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.KEEP]], input_: T - ) -> ValidateResult[T, Literal[ResultFlag.ERROR]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.VALUE_OPERATE]], input_: TInput1 - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.VALUE_OPERATE]], input_: T - ) -> ValidateResult[T, Literal[ResultFlag.ERROR]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, TMM], input_: TInput1 - ) -> ( - ValidateResult[TOrigin, Literal[ResultFlag.VALID]] - | ValidateResult[TOrigin, Literal[ResultFlag.ERROR]] - ): ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, TMM], input_: T - ) -> ValidateResult[T, Literal[ResultFlag.ERROR]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.KEEP]], input_: TInput1, default: Any - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput, Literal[MatchMode.KEEP]], input_: Any, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.VALUE_OPERATE]], input_: TInput1, default: Any - ) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, Literal[MatchMode.VALUE_OPERATE]], input_: Any, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, TMM], input_: TInput1, default: Any - ) -> ( - ValidateResult[TOrigin, Literal[ResultFlag.VALID]] - | ValidateResult[TOrigin, Literal[ResultFlag.ERROR]] - ): ... - @overload - def validate( - self: BasePattern[TOrigin, TInput1, TMM], input_: Any, default: TDefault - ) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ... - def match(self, input_: Any) -> TOrigin: ... - def copy(self) -> BasePattern[TOrigin, TInput, TMM]: ... - def __rrshift__( - self, other: T - ) -> ValidateResult[T, Literal[ResultFlag.VALID]] | ValidateResult[T, Literal[ResultFlag.ERROR]]: ... - def __rmatmul__(self, other) -> Self: ... - def __matmul__(self, other) -> Self: ... - def __or__( - self, other: BasePattern[TOrigin1, TInput2, Any] - ) -> BasePattern[TOrigin1 | TOrigin, TInput2 | TInput, TMM]: ... diff --git a/nepattern/func.py b/nepattern/func.py deleted file mode 100644 index f4fded1..0000000 --- a/nepattern/func.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import annotations - -from functools import reduce -from typing import Any, Callable, Protocol, TypeVar, overload - -from tarina import Empty - -from .core import TMM, BasePattern, MatchMode, TInput - -T = TypeVar("T") -T1 = TypeVar("T1") - - -def Index( - pat: BasePattern[list[T], TInput, TMM], - index: int, -) -> BasePattern[T, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return _match(input_)[index] - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}[{index}]" - _new.refresh() - return _new # type: ignore - - -def Slice( - pat: BasePattern[list[T], TInput, TMM], - start: int | None = None, - end: int | None = None, - step: int = 1, -) -> BasePattern[list[T], TInput, TMM]: - if start is None and end is None: - return pat - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return _match(input_)[start:end:step] - - _new.match = match.__get__(_new) - if start is not None and end is not None: - _slice = f"{start}:{end}" - elif start is not None: - _slice = f"{start}:" - else: - _slice = f":{end}" - if step != 1: - _slice += f":{step}" - _new.alias = f"{_new._repr}[{_slice}]" - _new.refresh() - return _new - - -def Map( - pat: BasePattern[list[T], TInput, TMM], - func: Callable[[T], T1], - funcname: str | None = None, -) -> BasePattern[list[T1], TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return list(map(func, _match(input_))) - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.map({funcname or func.__name__})" - _new.refresh() - return _new # type: ignore - - -def Filter( - pat: BasePattern[list[T], TInput, TMM], - func: Callable[[T], bool], - funcname: str | None = None, -) -> BasePattern[list[T], TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return list(filter(func, _match(input_))) - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.filter({funcname or func.__name__})" - _new.refresh() - return _new - - -_T_contra = TypeVar("_T_contra", contravariant=True) -_T_co = TypeVar("_T_co", covariant=True) - - -class SupportsAdd(Protocol[_T_contra, _T_co]): - def __add__(self, x: _T_contra, /) -> _T_co: ... - - -class SupportsRAdd(Protocol[_T_contra, _T_co]): - def __radd__(self, x: _T_contra, /) -> _T_co: ... - - -class _SupportsSumWithNoDefaultGiven(SupportsAdd[Any, Any], SupportsRAdd[int, Any], Protocol): ... - - -_SupportsSumNoDefaultT = TypeVar("_SupportsSumNoDefaultT", bound=_SupportsSumWithNoDefaultGiven) - - -def Sum( - pat: BasePattern[list[_SupportsSumNoDefaultT], TInput, TMM] -) -> BasePattern[_SupportsSumNoDefaultT, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return sum(_match(input_)) - - _new.match = match.__get__(_new) - _new.alias = f"sum({_new._repr})" - _new.refresh() - return _new # type: ignore - - -@overload -def Reduce( - pat: BasePattern[list[T], TInput, TMM], - func: Callable[[T, T], T], - initializer: None = ..., - funcname: str | None = ..., -) -> BasePattern[T, TInput, TMM]: ... - - -@overload -def Reduce( - pat: BasePattern[list[T], TInput, TMM], - func: Callable[[T1, T], T1], - initializer: T1, - funcname: str | None = ..., -) -> BasePattern[T1, TInput, TMM]: ... - - -def Reduce( - pat: BasePattern[list[T], TInput, TMM], - func: Callable[[T, T], T] | Callable[[T1, T], T1], - initializer: T1 | None = None, - funcname: str | None = None, -) -> BasePattern[T, TInput, TMM] | BasePattern[T1, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return reduce(func, _match(input_), initializer) if initializer is not None else reduce(func, _match(input_)) # type: ignore - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.reduce({funcname or func.__name__})" - _new.refresh() - return _new # type: ignore - - -def Join( - pat: BasePattern[list[str], TInput, TMM], - sep: str, -) -> BasePattern[str, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return sep.join(_match(input_)) - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.join({sep!r})" - _new.refresh() - return _new # type: ignore - - -def Upper( - pat: BasePattern[str, TInput, TMM], -) -> BasePattern[str, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return _match(input_).upper() - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.upper()" - _new.refresh() - return _new # type: ignore - - -def Lower( - pat: BasePattern[str, TInput, TMM], -) -> BasePattern[str, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return _match(input_).lower() - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.lower()" - _new.refresh() - return _new # type: ignore - - -def Dot( - pat: BasePattern[Any, TInput, TMM], - origin: type[T], - key: str, - default: T | None = None, -) -> BasePattern[T, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return getattr(_match(input_), key, default) - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.{key}" - _new.refresh() - _new.origin = origin - return _new # type: ignore - - -def GetItem( - pat: BasePattern[Any, TInput, TMM], - origin: type[T], - key: str, - default: T | None = None, -) -> BasePattern[T, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_) -> T: - try: - return _match(input_)[key] - except Exception as e: - if default is not None: - return default - raise e - - _new.match = match.__get__(_new) - _new.alias = f"{_new._repr}.{key}" - _new.refresh() - _new.origin = origin - return _new # type: ignore - - -def Step( - pat: BasePattern[T, TInput, TMM], - func: Callable[[T], T1], - *args, - funcname: str | None = None, - **kwargs, -) -> BasePattern[T1, TInput, TMM]: - _new = pat.copy() - _match = _new.match - - def match(self, input_): - return func(_match(input_), *args, **kwargs) - - _new.match = match.__get__(_new) - _new.alias = f"{funcname or func.__name__}({_new._repr})" - _new.refresh() - return _new # type: ignore diff --git a/nepattern/i18n/.config.json b/nepattern/i18n/.config.json index 3cc72c8..70fb687 100644 --- a/nepattern/i18n/.config.json +++ b/nepattern/i18n/.config.json @@ -1,5 +1,6 @@ { "default": "zh-CN", "frozen": [], - "require": [] -} \ No newline at end of file + "require": [], + "name": "nepattern" +} diff --git a/nepattern/i18n/.lang.schema.json b/nepattern/i18n/.lang.schema.json index 0828a8c..0c2715b 100644 --- a/nepattern/i18n/.lang.schema.json +++ b/nepattern/i18n/.lang.schema.json @@ -2,8 +2,6 @@ "title": "Lang Schema", "description": "Schema for lang file", "type": "object", - "minProperties": 2, - "maxProperties": 2, "properties": { "nepattern": { "title": "Nepattern", @@ -11,35 +9,28 @@ "type": "object", "additionalProperties": false, "properties": { - "type_error": { - "title": "type_error", - "description": "value of lang item type 'type_error'", + "parse_reject": { + "title": "parse_reject", + "description": "value of lang item type 'parse_reject'", "type": "string" }, - "content_error": { - "title": "content_error", - "description": "value of lang item type 'content_error'", - "type": "string" - }, - "validate_error": { - "title": "validate_error", - "description": "value of lang item type 'validate_error'", - "type": "string" - }, - "sequence_form_error": { - "title": "sequence_form_error", - "description": "value of lang item type 'sequence_form_error'", - "type": "string" - }, - "validate_reject": { - "title": "validate_reject", - "description": "value of lang item type 'validate_reject'", - "type": "string" - }, - "pattern_head_or_tail_error": { - "title": "pattern_head_or_tail_error", - "description": "value of lang item type 'pattern_head_or_tail_error'", - "type": "string" + "error": { + "title": "Error", + "description": "Scope 'error' of lang item", + "type": "object", + "additionalProperties": false, + "properties": { + "content": { + "title": "content", + "description": "value of lang item type 'content'", + "type": "string" + }, + "type": { + "title": "type", + "description": "value of lang item type 'type'", + "type": "string" + } + } } } } diff --git a/nepattern/i18n/.template.json b/nepattern/i18n/.template.json index 088d07a..fe23cd8 100644 --- a/nepattern/i18n/.template.json +++ b/nepattern/i18n/.template.json @@ -1,16 +1,17 @@ - { - "$schema": "./.template.schema.json", + "$schema": ".template.schema.json", "scopes": [ { "scope": "nepattern", "types": [ - "type_error", - "content_error", - "validate_error", - "sequence_form_error", - "validate_reject", - "pattern_head_or_tail_error" + "parse_reject", + { + "subtype": "error", + "types": [ + "content", + "type" + ] + } ] } ] diff --git a/nepattern/i18n/.template.schema.json b/nepattern/i18n/.template.schema.json index ac41237..87fbe89 100644 --- a/nepattern/i18n/.template.schema.json +++ b/nepattern/i18n/.template.schema.json @@ -1,4 +1,3 @@ - { "title": "Template", "description": "Template for lang items to generate schema for lang files", @@ -17,16 +16,37 @@ "scope": { "type": "string", "description": "Scope name" - }, + }, "types": { "type": "array", "description": "All types of lang items", "uniqueItems": true, "items": { - "type": "string", - "description": "Value of lang item" + "oneOf": [ + { + "type": "string", + "description": "Value of lang item" + }, + { + "type": "object", + "properties": { + "subtype": { + "type": "string", + "description": "Subtype name of lang item" + }, + "types": { + "type": "array", + "description": "All subtypes of lang items", + "uniqueItems": true, + "items": { + "$ref": "#/properties/scopes/items/properties/types/items" + } + } + } + } + ] } - } + } } } } diff --git a/nepattern/i18n/__init__.py b/nepattern/i18n/__init__.py index 8f0ac98..b3ecfe8 100644 --- a/nepattern/i18n/__init__.py +++ b/nepattern/i18n/__init__.py @@ -1,4 +1,3 @@ - # This file is @generated by tarina.lang CLI tool # It is not intended for manual editing. @@ -6,5 +5,4 @@ from tarina.lang import lang - lang.load(Path(__file__).parent) diff --git a/nepattern/i18n/en-US.json b/nepattern/i18n/en-US.json index 84ad656..ea2d2fd 100644 --- a/nepattern/i18n/en-US.json +++ b/nepattern/i18n/en-US.json @@ -1,11 +1,10 @@ { "$schema": "./.lang.schema.json", "nepattern": { - "type_error": "type {type} of parameter {target} is incorrect; expected {expected}", - "content_error": "parameter {target} is incorrect; expected {expected}", - "validate_error": "validate {target} failed", - "sequence_form_error": "incorrect sequence form: {target}", - "validate_reject": "validate {target} failed", - "pattern_head_or_tail_error": "the head or tail of regular expression {target} is not allowed to use '^' or '$'" + "parse_reject": "validate {target} failed", + "error": { + "content": "parameter {target} is incorrect; expected {expected}", + "type": "type {type} of parameter {target} is incorrect; expected {expected}" + } } } \ No newline at end of file diff --git a/nepattern/i18n/zh-CN.json b/nepattern/i18n/zh-CN.json index ddd9f65..b7ef48d 100644 --- a/nepattern/i18n/zh-CN.json +++ b/nepattern/i18n/zh-CN.json @@ -1,11 +1,10 @@ { "$schema": "./.lang.schema.json", "nepattern": { - "type_error": "参数 {target!r} 的类型 {type} 不正确, 其应该是 {expected!r}", - "content_error": "参数 {target!r} 不正确, 其应该符合 {expected!r}", - "validate_error": "{target} 校验失败", - "sequence_form_error": "不正确的序列形式: {target}", - "validate_reject": "{target} 校验失败", - "pattern_head_or_tail_error": "不允许正则表达式 {target} 头尾部分使用 '^' 或 '$' " + "error": { + "content": "参数 {target!r} 不正确, 其应该符合 {expected!r}", + "type": "参数 {target!r} 的类型 {type} 不正确, 其应该是 {expected!r}" + }, + "parse_reject": "{target} 校验失败" } } \ No newline at end of file diff --git a/nepattern/main.py b/nepattern/main.py index b4413e3..f0c866e 100644 --- a/nepattern/main.py +++ b/nepattern/main.py @@ -19,63 +19,50 @@ ANY, NONE, DirectPattern, + DirectTypePattern, ForwardRefPattern, - MappingPattern, RegexPattern, - SequencePattern, SwitchPattern, UnionPattern, ) from .context import all_patterns -from .core import BasePattern, MatchMode +from .core import Pattern from .util import CGenericAlias, CUnionType, GenericAlias, RawStr, TPattern _Contents = (Union, CUnionType, Literal) -def _generic_parser(item: GenericAlias, extra: str) -> BasePattern: # type: ignore +def _generic_parser(item: GenericAlias, extra: str) -> Pattern: # type: ignore origin = get_origin(item) if origin is Annotated: org, *meta = get_args(item) - if not isinstance(_o := parser(org, extra), BasePattern): # type: ignore # pragma: no cover + if not isinstance(_o := parser(org, extra), Pattern): # type: ignore # pragma: no cover raise TypeError(_o) _arg = deepcopy(_o) _arg.alias = al[-1] if (al := [i for i in meta if isinstance(i, str)]) else _arg.alias - _arg.validators.extend(i for i in meta if callable(i)) + validators = [i for i in meta if callable(i)] + if validators: + _arg.post_validate(lambda x: all(i(x) for i in validators)) return _arg if origin in _Contents: _args = {parser(t, extra) for t in get_args(item)} - return (_args.pop() if len(_args) == 1 else UnionPattern(_args)) if _args else ANY - if origin in (dict, ABCMap, ABCMuMap): - if args := get_args(item): - return MappingPattern( - arg_key=parser(args[0], "ignore"), - arg_value=parser(args[1], "allow"), - ) - return MappingPattern(ANY, ANY) # pragma: no cover - _args = parser(args[0], "allow") if (args := get_args(item)) else ANY - if origin in (ABCMuSeq, list): - return SequencePattern(list, _args) - if origin in (ABCSeq, tuple): - return SequencePattern(tuple, _args) - if origin in (ABCMuSet, ABCSet, set): - return SequencePattern(set, _args) - return BasePattern(mode=MatchMode.KEEP, origin=origin, alias=f"{repr(item).split('.')[-1]}", accepts=origin) # type: ignore + return (_args.pop() if len(_args) == 1 else UnionPattern(*_args)) if _args else ANY + return Pattern(origin=origin, alias=f"{repr(item).split('.')[-1]}").accept(origin) def _typevar_parser(item: TypeVar): - return BasePattern(mode=MatchMode.KEEP, origin=Any, alias=f"{item}"[1:], accepts=item) # type: ignore + return Pattern(alias=f"{item}"[1:]).accept(item) def _protocol_parser(item: type): if not getattr(item, "_is_runtime_protocol", True): # pragma: no cover item = runtime_checkable(deepcopy(item)) # type: ignore - return BasePattern(mode=MatchMode.KEEP, alias=f"{item}", accepts=item) + return Pattern(alias=f"{item}").accept(item) -def parser(item: Any, extra: str = "allow") -> BasePattern: - """对数类型的检查, 将一般数据类型转为 BasePattern 或者特殊类型""" - if isinstance(item, BasePattern): +def parser(item: Any, extra: str = "allow") -> Pattern: + """对数类型的检查, 将一般数据类型转为 Pattern 或者特殊类型""" + if isinstance(item, Pattern): return item with suppress(TypeError): if item and (pat := all_patterns().get(item, None)): @@ -90,29 +77,28 @@ def parser(item: Any, extra: str = "allow") -> BasePattern: if len((sig := inspect.signature(item)).parameters) not in (1, 2): # pragma: no cover raise TypeError(f"{item} can only accept 1 or 2 argument") anno = list(sig.parameters.values())[-1].annotation - return BasePattern( - accepts=Any if anno == inspect.Signature.empty else anno, # type: ignore - origin=(Any if sig.return_annotation == inspect.Signature.empty else sig.return_annotation), # type: ignore - converter=item if len(sig.parameters) == 2 else lambda _, x: item(x), - mode=MatchMode.TYPE_CONVERT, + return ( + Pattern((Any if sig.return_annotation == inspect.Signature.empty else sig.return_annotation)) # type: ignore + .accept(Any if anno == inspect.Signature.empty else anno) + .convert(item if len(sig.parameters) == 2 else lambda _, x: item(x)) ) if isinstance(item, TPattern): # type: ignore return RegexPattern(item.pattern, alias=f"'{item.pattern}'") if isinstance(item, str): if item.startswith("re:"): pat = item[3:] - return BasePattern(pat, MatchMode.REGEX_MATCH, alias=f"'{pat}'") + return Pattern.regex_match(pat, alias=f"'{pat}'") if item.startswith("rep:"): pat = item[4:] return RegexPattern(pat, alias=f"'{pat}'") if "|" in item: names = item.split("|") - return UnionPattern(all_patterns().get(i, i) for i in names if i) + return UnionPattern(*(all_patterns().get(i, i) for i in names if i)) return DirectPattern(item, alias=f"'{item}'") if isinstance(item, RawStr): return DirectPattern(item.value, alias=f"'{item.value}'") if isinstance(item, (list, tuple, set, ABCSeq, ABCMuSeq, ABCSet, ABCMuSet)): # Args[foo, [123, int]] - return UnionPattern(map(lambda x: parser(x) if inspect.isclass(x) else x, item)) + return UnionPattern(*map(lambda x: parser(x) if inspect.isclass(x) else x, item)) if isinstance(item, (dict, ABCMap, ABCMuMap)): return SwitchPattern(dict(item)) if isinstance(item, ForwardRef): @@ -122,8 +108,10 @@ def parser(item: Any, extra: str = "allow") -> BasePattern: if extra == "ignore": return ANY elif extra == "reject": - raise TypeError(lang.require("nepattern", "validate_reject").format(target=item)) - return BasePattern.of(item) if inspect.isclass(item) else BasePattern.on(item) + raise TypeError(lang.require("nepattern", "parse_reject").format(target=item)) + if inspect.isclass(item): + return DirectTypePattern(origin=item) # type: ignore + return DirectPattern(item) __all__ = ["parser"] diff --git a/nepattern/main.pyi b/nepattern/main.pyi deleted file mode 100644 index 33e0240..0000000 --- a/nepattern/main.pyi +++ /dev/null @@ -1,65 +0,0 @@ -from collections.abc import Mapping as ABCMap -from collections.abc import MutableSequence as ABCMuSeq -from collections.abc import Set as ABCSet -from types import UnionType -from typing import Any, Callable, ForwardRef, Iterable, Literal, TypeVar, overload - -from .base import ( - DirectPattern, - DirectTypePattern, - ForwardRefPattern, - IterMode, - MappingPattern, - RegexPattern, - SequencePattern, - SwitchPattern, - UnionPattern, -) -from .core import BasePattern, MatchMode -from .util import RawStr, TPattern - -T1 = TypeVar("T1") -T2 = TypeVar("T2") - -@overload -def parser( - item: str, extra: str = "allow" -) -> ( - BasePattern[str, str, Literal[MatchMode.REGEX_MATCH]] | DirectPattern[str] | RegexPattern | UnionPattern -): ... -@overload -def parser(item: RawStr, extra: str = "allow") -> DirectPattern[str]: ... -@overload -def parser(item: TPattern, extra: str = "allow") -> RegexPattern: ... -@overload -def parser( - item: type[ABCMap[T1, T2]], extra: str = "allow" -) -> MappingPattern[T1, T2, Literal[IterMode.ALL]]: ... -@overload -def parser( - item: type[ABCMuSeq[T1]], extra: str = "allow" -) -> SequencePattern[list[T1], Literal[IterMode.ALL]]: ... -@overload -def parser( - item: type[tuple[T1, ...]], extra: str = "allow" -) -> SequencePattern[tuple[T1, ...], Literal[IterMode.ALL]]: ... -@overload -def parser( - item: type[ABCSet[T1]], extra: str = "allow" -) -> SequencePattern[set[T1], Literal[IterMode.ALL]]: ... -@overload -def parser(item: type[T1], extra: str = "allow") -> BasePattern[T1, Any, Any] | DirectTypePattern[T1]: ... -@overload -def parser(item: ABCMap[T1, T2], extra: str = "allow") -> SwitchPattern[T2, T1]: ... -@overload -def parser(item: UnionType, extra: str = "allow") -> UnionPattern[Any]: ... -@overload -def parser(item: Iterable[T1 | type[T1]], extra: str = "allow") -> UnionPattern[T1]: ... -@overload -def parser(item: ForwardRef, extra: str = "allow") -> ForwardRefPattern: ... -@overload -def parser( - item: Callable[[T1], T2], extra: str = "allow" -) -> BasePattern[T2, T1, Literal[MatchMode.TYPE_CONVERT]]: ... -@overload -def parser(item: T1, extra: str = "allow") -> BasePattern[T1, T1, Literal[MatchMode.KEEP]]: ... diff --git a/nepattern/util.py b/nepattern/util.py index 90a83c5..ce7c5ba 100644 --- a/nepattern/util.py +++ b/nepattern/util.py @@ -3,16 +3,14 @@ import dataclasses import sys from typing import TYPE_CHECKING, List, Pattern, Union +from typing_extensions import TypeAlias -from .i18n import lang as lang +from .i18n import lang as lang # noqa: F401 -if sys.version_info >= (3, 9): # pragma: no cover - from types import GenericAlias as CGenericAlias # noqa -else: # pragma: no cover - CGenericAlias: type = type(List[int]) # noqa +from types import GenericAlias as CGenericAlias # noqa: F401 if sys.version_info >= (3, 10): # pragma: no cover - from types import UnionType as CUnionType # noqa + from types import UnionType as CUnionType # noqa: F401 else: # pragma: no cover CUnionType: type = type(Union[int, str]) # noqa @@ -22,7 +20,7 @@ from sre_compile import compile as re_compile # noqa if TYPE_CHECKING: - TPattern = Pattern[str] + TPattern: TypeAlias = Pattern[str] else: TPattern: type[Pattern[str]] = type(re_compile("", 0)) GenericAlias: type = type(List[int]) diff --git a/pdm.lock b/pdm.lock index 1125c2f..18695b1 100644 --- a/pdm.lock +++ b/pdm.lock @@ -4,8 +4,11 @@ [metadata] groups = ["default", "dev"] strategy = ["cross_platform"] -lock_version = "4.4.1" -content_hash = "sha256:77372b5cc5550e3e961191e53f0523e41fcfe1bbd9f8964f13b7ff68ddc69303" +lock_version = "4.5.0" +content_hash = "sha256:c87c2dc075cdc29d11da4c4cf94edcaab1e8443dabf0357d4d249725eb5bfdab" + +[[metadata.targets]] +requires_python = ">=3.9" [[package]] name = "attrs" @@ -19,8 +22,8 @@ files = [ [[package]] name = "black" -version = "24.4.1" -requires_python = ">=3.8" +version = "24.10.0" +requires_python = ">=3.9" summary = "The uncompromising code formatter." dependencies = [ "click>=8.0.0", @@ -32,28 +35,28 @@ dependencies = [ "typing-extensions>=4.0.1; python_version < \"3.11\"", ] files = [ - {file = "black-24.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f7749fd0d97ff9415975a1432fac7df89bf13c3833cea079e55fa004d5f28c0"}, - {file = "black-24.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859f3cc5d2051adadf8fd504a01e02b0fd866d7549fff54bc9202d524d2e8bd7"}, - {file = "black-24.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59271c9c29dfa97f7fda51f56c7809b3f78e72fd8d2205189bbd23022a0618b6"}, - {file = "black-24.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:5ed9c34cba223149b5a0144951a0f33d65507cf82c5449cb3c35fe4b515fea9a"}, - {file = "black-24.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dae3ae59d6f2dc93700fd5034a3115434686e66fd6e63d4dcaa48d19880f2b0"}, - {file = "black-24.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5f8698974a81af83283eb47644f2711b5261138d6d9180c863fce673cbe04b13"}, - {file = "black-24.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f404b6e77043b23d0321fb7772522b876b6de737ad3cb97d6b156638d68ce81"}, - {file = "black-24.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:c94e52b766477bdcd010b872ba0714d5458536dc9d0734eff6583ba7266ffd89"}, - {file = "black-24.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:962d9e953872cdb83b97bb737ad47244ce2938054dc946685a4cad98520dab38"}, - {file = "black-24.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d8e3b2486b7dd522b1ab2ba1ec4907f0aa8f5e10a33c4271fb331d1d10b70c"}, - {file = "black-24.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed77e214b785148f57e43ca425b6e0850165144aa727d66ac604e56a70bb7825"}, - {file = "black-24.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:4ef4764437d7eba8386689cd06e1fb5341ee0ae2e9e22582b21178782de7ed94"}, - {file = "black-24.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:92b183f8eef5baf7b20a513abcf982ad616f544f593f6688bb2850d2982911f1"}, - {file = "black-24.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:945abd7b3572add997757c94295bb3e73c6ffaf3366b1f26cb2356a4bffd1dc3"}, - {file = "black-24.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db5154b9e5b478031371d8bc41ff37b33855fa223a6cfba456c9b73fb96f77d4"}, - {file = "black-24.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:afc84c33c1a9aaf3d73140cee776b4ddf73ff429ffe6b7c56dc1c9c10725856d"}, - {file = "black-24.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0889f4eb8b3bdf8b189e41a71cf0dbb8141a98346cd1a2695dea5995d416e940"}, - {file = "black-24.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5bb0143f175db45a55227eefd63e90849d96c266330ba31719e9667d0d5ec3b9"}, - {file = "black-24.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:713a04a78e78f28ef7e8df7a16fe075670ea164860fcef3885e4f3dffc0184b3"}, - {file = "black-24.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:171959bc879637a8cdbc53dc3fddae2a83e151937a28cf605fd175ce61e0e94a"}, - {file = "black-24.4.1-py3-none-any.whl", hash = "sha256:ecbab810604fe02c70b3a08afd39beb599f7cc9afd13e81f5336014133b4fe35"}, - {file = "black-24.4.1.tar.gz", hash = "sha256:5241612dc8cad5b6fd47432b8bd04db80e07cfbc53bb69e9ae18985063bcb8dd"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [[package]] @@ -63,6 +66,7 @@ requires_python = ">=3.7" summary = "Composable command line interface toolkit" dependencies = [ "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", ] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, @@ -104,16 +108,6 @@ files = [ {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, - {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, - {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, @@ -124,7 +118,6 @@ files = [ {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, - {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, ] @@ -206,6 +199,9 @@ name = "pluggy" version = "1.0.0" requires_python = ">=3.6" summary = "plugin and hook calling mechanisms for python" +dependencies = [ + "importlib-metadata>=0.12; python_version < \"3.8\"", +] files = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, @@ -229,6 +225,7 @@ summary = "pytest: simple powerful testing with Python" dependencies = [ "attrs>=19.2.0", "colorama; sys_platform == \"win32\"", + "importlib-metadata>=0.12; python_version < \"3.8\"", "iniconfig", "packaging", "pluggy<2.0,>=0.12", @@ -242,60 +239,90 @@ files = [ [[package]] name = "tarina" -version = "0.5.1" -requires_python = ">=3.8" +version = "0.6.1" +requires_python = ">=3.9" summary = "A collection of common utils for Arclet" dependencies = [ "typing-extensions>=4.4.0", ] files = [ - {file = "tarina-0.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6771008b563ff747cf21dfbefdc4137b5d200668663bc563d3e49cb6ede2d3bc"}, - {file = "tarina-0.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bfc0ab0fe5caefd1b7b193990f19d9495094545045727445921a4bbc513b26d"}, - {file = "tarina-0.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:338571c5ea9fb821366de5bf4b18479085fbb894d4f8f01b1779eb3d373c4df0"}, - {file = "tarina-0.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20a24f02fb971dd5938b4917b3ff4f0d3d97d232dd88abeb5d9114c50cd4bdec"}, - {file = "tarina-0.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90858896efab6820304e5580faa4b7acee6be106b5f34060e4498dfd12ad68b6"}, - {file = "tarina-0.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e4b858aae14b2d68e099fc9ed615b9900b8b3a2878337a387b315517fca14a35"}, - {file = "tarina-0.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c615eb3f0c4af88546f083b20e1ac4c5c4689a7dac358c661421a48557be58ad"}, - {file = "tarina-0.5.1-cp310-cp310-win32.whl", hash = "sha256:4806976ff6f1ac89c2ab9b96e77bd497d554abc42ae30cc2eec41e321314c594"}, - {file = "tarina-0.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:f352c43f0eb76e546628808e9211363beedadea6183c3d4d438602c9dc4573e3"}, - {file = "tarina-0.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1cc4042b091a30daa9a1bdd3697f710ffc193abd571de5c9707e32c6702b1bb7"}, - {file = "tarina-0.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee8f9ee78953e98b2f206433d7c8757c6d0d28202c7ffed1bbdcd8f71197029d"}, - {file = "tarina-0.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1660e9ae397e75fc5490b089156101b71a4bd452809bb376d1f2c433a26b8eb3"}, - {file = "tarina-0.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4475585f2510ba614938ff13476feb1c22fcf13aa526a5627e1e92835189d8ca"}, - {file = "tarina-0.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53370e4e94cede47672b49432793fb465f19f33e0c1f7052c113f20c273beb53"}, - {file = "tarina-0.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9631c95c08108b9ecf9f23a4207a149846951f9471395cce3ea1ee86dbe64552"}, - {file = "tarina-0.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d04bd1c7b4252f94612b70d994590f53f32dab86524139b1b8c26a7737a9f7e"}, - {file = "tarina-0.5.1-cp311-cp311-win32.whl", hash = "sha256:0a3a5f873d7b4d335079080ab4e5424a6c42e5afc6d96cd94748fbb4168e904d"}, - {file = "tarina-0.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:1c7b262dda5b017ce6e959863884f4d14a858c7581b5b3e052b8425633e7244a"}, - {file = "tarina-0.5.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c23599e3daace688b20e8ef090550719f6166793add3f5977f0a5395b2100911"}, - {file = "tarina-0.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:90d4a9e8f9ce45e160acf074ddd7754f8085682eede1b811d6afe075f91ff2bb"}, - {file = "tarina-0.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f570be005348a53420aef837cf4dee1b2093293a3c8012f8a286a2dd5c0e004"}, - {file = "tarina-0.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2694ceeb736641c07e98d580e40e69027b232c32089b84d53129c3cc2c987aa6"}, - {file = "tarina-0.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed943ce6276bbdf43ba0c73165ae159e2abf858c87c850ba8a051b7c53d12ece"}, - {file = "tarina-0.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3f2b9792de2cd28cdf246b65c48b6c3453d103d11fb2d3d6d339fcfdaa40e94d"}, - {file = "tarina-0.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:edd5585d290f13f301106862bf04a9c8a810f6815ce8a33be04554114def3306"}, - {file = "tarina-0.5.1-cp312-cp312-win32.whl", hash = "sha256:32dd05d72485df805c6fb449af7754a9b6bfe03d9ad87c72f31b734fb1bcb4ac"}, - {file = "tarina-0.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:30186f57be4470e1c2888bc3abc917c4fd5b38d6ddec258302c10d3c73ff2bf4"}, - {file = "tarina-0.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7460b4634f78bbbc07cf093d8425d035b36c2354149b1e981f5be6af79093ce0"}, - {file = "tarina-0.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8126fecec1d2ed6f564e13c96dbd6d9c7f34caf1ab71e2684ab789ca4669def4"}, - {file = "tarina-0.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c78e3d2660eda0751291e78cb335020cc11b06318aaedb30819d58e6d169b38a"}, - {file = "tarina-0.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eeacdb183aefc06303b365b2a938fd9049dab9961a11ea4d39bef03aeb2115a2"}, - {file = "tarina-0.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5c5e68b225f6f56a3e14cda3a8cba49ab27a289a5643462972ec0657e7c2261"}, - {file = "tarina-0.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3d9445a0c1b1c902dc6cc2ffd4a7765d153c5737646f8df6469ad21f79d1a4db"}, - {file = "tarina-0.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:10d6cd6d8d8948776cacdba83466f78f69dca8833c20831a446c8b8630049b32"}, - {file = "tarina-0.5.1-cp38-cp38-win32.whl", hash = "sha256:277e67c2a62703037e7e758a4ca3be81532407214dbde3533d404ec582dba049"}, - {file = "tarina-0.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:85fc9b00fd8114d14d40866745c8cc6827e9d9e3056af019a44d1f1da6d99dcc"}, - {file = "tarina-0.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a5b6c370ba8689451f7c2b9b3f3f3e237f32b9db6370ed360f721825492aae3"}, - {file = "tarina-0.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04b7e0f077345543a62da8a84e99051b9836f2bc6d4b8bd2b12735b22b0aca0b"}, - {file = "tarina-0.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:edd8ea799b7a0b018d0f7db7b6cb2803204c543ff067881ce48bd46aa13bac19"}, - {file = "tarina-0.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b34349d3dbf84aac27432ad1f3c7eb916e3d8c469cc93ea6c888d6ce77444685"}, - {file = "tarina-0.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd739c40a353324bafe84237e00a3c49bb208e44932c9279c1e30f02d2da37f3"}, - {file = "tarina-0.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db520f0c251bfe8ceec7abeddc2629ab3872f8724c61d9f9b54e2c6fd65a2097"}, - {file = "tarina-0.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f61b5ecaa942b1735c560dce6c1eccddcc1f93b3c7eb5377a2c7b81cad2f04ba"}, - {file = "tarina-0.5.1-cp39-cp39-win32.whl", hash = "sha256:174fda10e03bfd3dec4e9c8a0b316be25b0353b30837e2f0fa3a01a490c43608"}, - {file = "tarina-0.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:a2b938788c513a7cef3296791838f8b8846c35bfd590c8fa3a56b474191b178b"}, - {file = "tarina-0.5.1-py3-none-any.whl", hash = "sha256:d266b011abc006d1c5eff71d23074770c57c01bcabf90c58a95c6f4353a48629"}, - {file = "tarina-0.5.1.tar.gz", hash = "sha256:d906fcf3803df32dc016de8f34c3d5734e9d1d4678ccefdc3a444d01b0419e34"}, + {file = "tarina-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f81108429347d78ff703061b6e071fe17183d3ec77d0e3a4386fef503ba7609e"}, + {file = "tarina-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc7ae6c003cd367a5e962c5c29ff525d7f4ec0ec0e040ba096aa13571ad36e25"}, + {file = "tarina-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f445dcd502de9762812c97dcd7f94ebabb33353c173f81d26e97979a080d579e"}, + {file = "tarina-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:651faa58c8949485a72f28daa5e1f16c79e2c57ab78eebdb0c5b1e422b5e5d27"}, + {file = "tarina-0.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14d45da795ab3e4ef53ef0088650f31f02e5ad424ffce1f7b499ed17d56930b8"}, + {file = "tarina-0.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94d4b64e25f069ad912d258d360c136d96331ed8a04e590e576b5618edfda0e3"}, + {file = "tarina-0.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5b10559c3a4f14c051299fb8d504b6d06ecc5388fc6a58b0094450f63feeb93"}, + {file = "tarina-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2600bc9e113cbe7500e7deeee79dfd8bdf539b5a9a1dd7dd39c110ceb7ce2df0"}, + {file = "tarina-0.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:89fb41a2a3d0882ae3c76f59a5d59f082adc5844a1a5a9c1cd81ba392a81278d"}, + {file = "tarina-0.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a1592ee78428163245f610629060f1de47b4fff3ee9a459e7a2fa8a37396cfeb"}, + {file = "tarina-0.6.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:9fc37ec243622e05f8858382541948bc95f58529fb714eeb3edfd509862d9d25"}, + {file = "tarina-0.6.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4eb330aa9d0253513e6946144d633abb184df6e9412824252e26df435b4c7e6a"}, + {file = "tarina-0.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2eb88f319473117c6ce3a8adb42e72a8a1deecb25cf07a3661966d76125decd1"}, + {file = "tarina-0.6.1-cp310-cp310-win32.whl", hash = "sha256:470d4cb9e77d9950ec3c502b483d7672319033d6d9412e2505556136bbef6228"}, + {file = "tarina-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:6331774d2fc4b53a443c7aea765bc0f5325d704556f5a54c5b493548c30d248e"}, + {file = "tarina-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:21d0d2668bfe266e40cfc63fcaad6d4b082d48e51d5dedef68480ce9ef93f0d1"}, + {file = "tarina-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f89b816c22469f9f962e0546d83f2303b1ce76026ac0b01d860e78a063516ec9"}, + {file = "tarina-0.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:257f5de5dee0989f3fae910436b1033f89d59f6daf66caeaddb442ff0f300fdd"}, + {file = "tarina-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89bbb091209cf901d2238c750cc7f18221363b6d4df0ca5ae349b6edcc010b92"}, + {file = "tarina-0.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e63492d43591e68ec9d0c6a44182db831723def84047aad1aae0ed2f0b6887"}, + {file = "tarina-0.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:710d80de800abc85cd5eb70e976c6faa9eeb463a819af57b24480111de1eb4f8"}, + {file = "tarina-0.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73dabdb38b2495978dd38b49e6972326a8554c94a079cf6a76b4f51afdabe4f2"}, + {file = "tarina-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:168897ef791944a58aefa6107859662b678284e4a423a5004abd86404d23b422"}, + {file = "tarina-0.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:444a9fae02ac1cbbd1dda606999910165dcedcf3c1dc038ae776c7a79bf6038d"}, + {file = "tarina-0.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f174ce1df1f39f8ca0f4f20df86f0ed3e53d9abfd834c69647179312a4d7242"}, + {file = "tarina-0.6.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:cace7ab14894861e562a846f5555c6089763489ce949f8e1d7da2ab0c4d98c99"}, + {file = "tarina-0.6.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b67ee3b1f97e89161f4e534c607d465c671c6958ebd8a8596576b589971f002f"}, + {file = "tarina-0.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfd4f5061e9a5d557265759d7225c24ab2bd609f73826369f700c4c4f7ae99f5"}, + {file = "tarina-0.6.1-cp311-cp311-win32.whl", hash = "sha256:e0729bd693f4a33b1656e3e5740279ea13a904ea798485040ac4017b7c38ad73"}, + {file = "tarina-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:3e2d202116fb37210bb6962f5fa9c7e5c4463c8d1ac179abf81659df287edb59"}, + {file = "tarina-0.6.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3c763640cdbd1a64c3572e101db8dd430f70e2ffb69ab1857f161d5858572b89"}, + {file = "tarina-0.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:516ab567580b1baad5f9caedeea5aea64c82a690c8a66b1488fddb86db7181c4"}, + {file = "tarina-0.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3cb0dd90866ba7041f935cbbddaecbc8a2dfedb17c4eb2d14b69aea0e9204722"}, + {file = "tarina-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40fb6e397ebe35935f3aa4cf6dd1635bc7481021915a3610d35a59cb33e1e1ae"}, + {file = "tarina-0.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5838c367f2d9819ece8343908c08f277d115b21a5d3bad18588f22dbc44f7410"}, + {file = "tarina-0.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b6870463e6bcf7e2958bccf7f2824eb4f7ffc99c88c8b27f5dd9be2fef8702"}, + {file = "tarina-0.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a6875f34a7f0d4e2663525a356954b0e81241e59b8e7a8df6f66f646e8ad3e7"}, + {file = "tarina-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0084193267ccc05058baffb550db7d814b3b2d8d13ee07fc363d4fe3fa947c4"}, + {file = "tarina-0.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:26ca97ef07d1ebc73ce44532c19d74f0a65087ffcd4ed193186ed98b8ca6db87"}, + {file = "tarina-0.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bb123dde028433c612d207301d59f123a25ed25a0b2d13922b167b6595978d17"}, + {file = "tarina-0.6.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3655e5cbd143be2ca7413202052f097fae36f9224cf12e5f2a790986803c5804"}, + {file = "tarina-0.6.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fd70cf3b025de2fcc0d276e287aeafe2be3c05a0d2ef83a5b563c2f7d2bc9920"}, + {file = "tarina-0.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bfd991c93400457d2fe58461b1d300e856d7e70881699c764c6912182525e0df"}, + {file = "tarina-0.6.1-cp312-cp312-win32.whl", hash = "sha256:a422689faebe0e2b701d9ca3b1a2d172e0d7434e1159fa42782c2a957f8828be"}, + {file = "tarina-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:3104baf80f6a9e1e0a1fb3d6fabe87f7b6bc97db7c2941267a219869628f79af"}, + {file = "tarina-0.6.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3be9f60c4b39eae8451f6c63adbadec585146fbc2d3698b7ed81289c8cc22d2"}, + {file = "tarina-0.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:af8e6f999dab61d96593fad7e32fd4ffefad64813cb993a45683e83ef486e70b"}, + {file = "tarina-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b2f9c59ba6852c6cf441adf5d287fc6597a0019f80040155541b1e39dcbff20e"}, + {file = "tarina-0.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0148199bcba92ef14e639029356a65894bae33ec3872b63ad1f9a1a9130ecaec"}, + {file = "tarina-0.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c69cef0e15856d4d2eb5817f00a85701f69c444e8fca0c50618d7bfde5b4104"}, + {file = "tarina-0.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b3c250ab55c75f073023d21118fbd706e661b76a49e4cac28a6cb71f0bf04873"}, + {file = "tarina-0.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a06308187f13c41f857d79c0b33d407eae34c16974a03a5711aa6b3bd27c129e"}, + {file = "tarina-0.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea1cf6026d81be5bc186882651f99a50d19ec7de33c580635848f52ecb0286e5"}, + {file = "tarina-0.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4cfa83aa4fe0fe0d394a93a70b7ec502c734a692d6dd6dc465fd4b591a0a6411"}, + {file = "tarina-0.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:608f74951318b2f24c83e4d11b068479363073cc7346785a7b54fe09386676e9"}, + {file = "tarina-0.6.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:98532739c0044a4afe8b345d6e07906a117af2d212ebe6e5fec7d3bca0b55dcb"}, + {file = "tarina-0.6.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:611f3338df2fd80261f5b979e18554d3edc5608dcf2b5873d312123142f18031"}, + {file = "tarina-0.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c76ce872ef3cb3ed3fc7cd4dc6048f210218fe26cb2b951902b7102fe94698c1"}, + {file = "tarina-0.6.1-cp313-cp313-win32.whl", hash = "sha256:3059bf2b308d9fa77be7f18506061b6a2aee4c0fd633d0281ad6b4299bc418f0"}, + {file = "tarina-0.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:51aa1e65bff323838fb9205a66e5bdc299d507b8c52c62e9759949f77d68439a"}, + {file = "tarina-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:dbf72954eee214be1171c4d36216e6da253a8b2ce2ca6a1509489960bee4adbd"}, + {file = "tarina-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15b8e4ebefd74a90c73151c3020ee335b83a24cc6255a4b0a8c58a90f40e2d7d"}, + {file = "tarina-0.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:761f61009f628a26b4ff1ed800c6b858bbc82372ba45775b19382136b48e60f8"}, + {file = "tarina-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98a4229f4eb15a4a9b397684173a0013b5941273c68923e7ef464111e7ccf81f"}, + {file = "tarina-0.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21f733def0ba7e9e4bef88bbacbfa978d1763dfc392abf8a5a3127812127d61a"}, + {file = "tarina-0.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e24cd3a9fed98af412a3dc8c6a82143fb00e9a448337fe846cbf36d27f002214"}, + {file = "tarina-0.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bde8c549a5ac165acd2e7578f501477c54ce47283b1a4cc09d468f9d93990d96"}, + {file = "tarina-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f37682c6e6984ef51ee2692dc71f3949d0eb390efb660635459c53802c2948"}, + {file = "tarina-0.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0730ab7a8c0a3be19ce3e3bbfaad893c946acaa2cf2d191f5287ba35c9bf9a11"}, + {file = "tarina-0.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1d9186b7584d6884be799b038e7cf93011177cea2184080ff9849b17aa8ce2a6"}, + {file = "tarina-0.6.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:246eabe13f1496c19c6ea9e975398db5e78a936ebb784182cbfb5101593e8b8e"}, + {file = "tarina-0.6.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:835b93ee5ca9e302e993666a692b175ebc8514831c67e09368c1bf3e08d04be6"}, + {file = "tarina-0.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:33539f80a6de9360f1c187370057988762d598fed5eae1f4789db4952f39a59d"}, + {file = "tarina-0.6.1-cp39-cp39-win32.whl", hash = "sha256:e260313f2d62946121df941c37a7b4521e1849fa92c65236a7f35e328e77e947"}, + {file = "tarina-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:d59a5e3164a1c4f5095f8b8e16de1dbfd81eeb53a506a14ca1545ff7d0edbe2a"}, + {file = "tarina-0.6.1-py3-none-any.whl", hash = "sha256:cb9b95b62b2fee8fe86758af0acac147afa4646a7b0a7f272e0e74f3fc60cf3e"}, + {file = "tarina-0.6.1.tar.gz", hash = "sha256:153a415df95da7c08cf2a75a88c9f587e6d12fd8ec5caae01586bbbd2083f81c"}, ] [[package]] @@ -320,10 +347,10 @@ files = [ [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] diff --git a/pyproject.toml b/pyproject.toml index 4b8b84b..6093492 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,9 +7,9 @@ authors = [ ] dependencies = [ "typing-extensions>=4.5.0", - "tarina>=0.5.1", + "tarina<0.7,>=0.6", ] -requires-python = ">=3.8" +requires-python = ">=3.9" readme = "README.md" license = {text = "MIT"} keywords = [ @@ -86,7 +86,7 @@ python_files = "test.py" [tool.black] line-length = 110 -target-version = ["py38", "py39", "py310", "py311"] +target-version = ["py39", "py310", "py311", "py312", "py313"] include = '\.pyi?$' extend-exclude = ''' ''' diff --git a/test.py b/test.py index 6eea901..e506b2b 100644 --- a/test.py +++ b/test.py @@ -12,91 +12,83 @@ def test_type(): def test_basic(): from datetime import datetime - res = STRING.validate("123") + res = STRING.execute("123") if res: assert res.success assert res.value() == "123" - assert STRING.validate(b"123").value() == "123" - assert STRING.validate(123).failed - - assert BYTES.validate(b"123").success - assert BYTES.validate("123").value() == b"123" - assert BYTES.validate(123).failed - - assert INTEGER.validate(123).success - assert INTEGER.validate("123").value() == 123 - assert INTEGER.validate(123.456).value() == 123 - assert INTEGER.validate("123.456").failed - assert INTEGER.validate("-123").success - - assert FLOAT.validate(123).value() == 123.0 - assert FLOAT.validate("123").value() == 123.0 - assert FLOAT.validate(123.456).value() == 123.456 - assert FLOAT.validate("123.456").value() == 123.456 - assert FLOAT.validate("1e10").value() == 1e10 - assert FLOAT.validate("-123").value() == -123.0 - assert FLOAT.validate("-123.456").value() == -123.456 - assert FLOAT.validate("-123.456e-2").value() == -1.23456 - assert FLOAT.validate("aaa").failed - assert FLOAT.validate([]).failed - - assert BOOLEAN.validate(True).value() is True - assert BOOLEAN.validate(False).value() is False - assert BOOLEAN.validate("True").value() is True - assert BOOLEAN.validate("False").value() is False - assert BOOLEAN.validate("true").value() is True - assert BOOLEAN.validate("false").value() is False - assert BOOLEAN.validate("1").failed - - assert WIDE_BOOLEAN.validate(True).value() is True - assert WIDE_BOOLEAN.validate(False).value() is False - assert WIDE_BOOLEAN.validate("True").value() is True - assert WIDE_BOOLEAN.validate("False").value() is False - assert WIDE_BOOLEAN.validate("true").value() is True - assert WIDE_BOOLEAN.validate("false").value() is False - assert WIDE_BOOLEAN.validate(1).value() is True - assert WIDE_BOOLEAN.validate(0).value() is False - assert WIDE_BOOLEAN.validate("yes").value() is True - assert WIDE_BOOLEAN.validate("no").value() is False - assert WIDE_BOOLEAN.validate("2").failed - assert WIDE_BOOLEAN.validate([]).failed - - assert HEX.validate(123).failed - assert HEX.validate("0x123").value() == 0x123 - assert HEX.validate("0o123").failed - - assert DATETIME.validate("2020-01-01").value() == datetime(2020, 1, 1) - assert DATETIME.validate("2020-01-01-12:00:00").value() == datetime(2020, 1, 1, 12, 0, 0) - assert DATETIME.validate("2020-01-01-12:00:00.123").value() == datetime(2020, 1, 1, 12, 0, 0, 123000) - assert DATETIME.validate(datetime(2021, 12, 14).timestamp()).value() == datetime(2021, 12, 14, 0, 0, 0) - assert DATETIME.validate([]).failed - - assert PATH.validate("a/b/c").value().parts == ("a", "b", "c") - assert PATH.validate(Path("a/b/c")).value() == Path("a/b/c") - assert PATH.validate([]).failed + assert STRING.execute(b"123").value() == "123" + assert STRING.execute(123).failed + + assert BYTES.execute(b"123").success + assert BYTES.execute("123").value() == b"123" + assert BYTES.execute(123).failed + + assert INTEGER.execute(123).success + assert INTEGER.execute("123").value() == 123 + assert INTEGER.execute(123.456).value() == 123 + assert INTEGER.execute("123.456").failed + assert INTEGER.execute("-123").success + + assert FLOAT.execute(123).value() == 123.0 + assert FLOAT.execute("123").value() == 123.0 + assert FLOAT.execute(123.456).value() == 123.456 + assert FLOAT.execute("123.456").value() == 123.456 + assert FLOAT.execute("1e10").value() == 1e10 + assert FLOAT.execute("-123").value() == -123.0 + assert FLOAT.execute("-123.456").value() == -123.456 + assert FLOAT.execute("-123.456e-2").value() == -1.23456 + assert FLOAT.execute("aaa").failed + assert FLOAT.execute([]).failed + + assert BOOLEAN.execute(True).value() is True + assert BOOLEAN.execute(False).value() is False + assert BOOLEAN.execute("True").value() is True + assert BOOLEAN.execute("False").value() is False + assert BOOLEAN.execute("true").value() is True + assert BOOLEAN.execute("false").value() is False + assert BOOLEAN.execute("1").failed + + assert WIDE_BOOLEAN.execute(True).value() is True + assert WIDE_BOOLEAN.execute(False).value() is False + assert WIDE_BOOLEAN.execute("True").value() is True + assert WIDE_BOOLEAN.execute("False").value() is False + assert WIDE_BOOLEAN.execute("true").value() is True + assert WIDE_BOOLEAN.execute("false").value() is False + assert WIDE_BOOLEAN.execute(1).value() is True + assert WIDE_BOOLEAN.execute(0).value() is False + assert WIDE_BOOLEAN.execute("yes").value() is True + assert WIDE_BOOLEAN.execute("no").value() is False + assert WIDE_BOOLEAN.execute("2").failed + assert WIDE_BOOLEAN.execute([]).failed + + assert HEX.execute(123).failed + assert HEX.execute("0x123").value() == 0x123 + assert HEX.execute("0o123").failed + + assert DATETIME.execute("2020-01-01").value() == datetime(2020, 1, 1) + assert DATETIME.execute("2020-01-01-12:00:00").value() == datetime(2020, 1, 1, 12, 0, 0) + assert DATETIME.execute("2020-01-01-12:00:00.123").value() == datetime(2020, 1, 1, 12, 0, 0, 123000) + assert DATETIME.execute(datetime(2021, 12, 14).timestamp()).value() == datetime(2021, 12, 14, 0, 0, 0) + assert DATETIME.execute([]).failed + + assert PATH.execute("a/b/c").value().parts == ("a", "b", "c") + assert PATH.execute(Path("a/b/c")).value() == Path("a/b/c") + assert PATH.execute([]).failed def test_result(): - res = NUMBER.validate(123) + res = NUMBER.execute(123) assert res.success assert not res.failed - assert not res.or_default assert not res.error() - assert NUMBER.validate(123).value() == 123 - assert NUMBER.validate("123").value() == 123 - assert NUMBER.validate(123.456).value() == 123.456 - assert NUMBER.validate("123.456").value() == 123.456 - assert NUMBER.validate("aaa").failed - res1 = NUMBER.validate([], -1) - assert res1.or_default - assert not res1.failed - assert not res1.success - assert not res.error() - res2 = NUMBER.validate([]) + assert NUMBER.execute(123).value() == 123 + assert NUMBER.execute("123").value() == 123 + assert NUMBER.execute(123.456).value() == 123.456 + assert NUMBER.execute("123.456").value() == 123.456 + assert NUMBER.execute("aaa").failed + res2 = NUMBER.execute([]) assert res2.error() - assert not res2.or_default assert not res2.success - assert res2.error() try: res2.value() except RuntimeError as e: @@ -105,86 +97,75 @@ def test_result(): def test_pattern_of(): """测试 BasePattern 的快速创建方法之一, 对类有效""" - pat = BasePattern.of(int) + pat = Pattern(int) assert pat.origin == int - assert pat.validate(123).value() == 123 - assert pat.validate("abc").failed + assert pat.execute(123).value() == 123 + assert pat.execute("abc").failed print(pat) - print(pat.validate(123).error()) - print(pat.validate("abc").error()) + print(pat.execute(123).error()) + print(pat.execute("abc").error()) def test_pattern_on(): """测试 BasePattern 的快速创建方法之一, 对对象有效""" - pat1 = BasePattern.on(123) + pat1 = Pattern.on(123) assert pat1.origin == int - assert pat1.validate(123).value() == 123 - assert pat1.validate(124).failed + assert pat1.execute(123).value() == 123 + assert pat1.execute(124).failed print(pat1) def test_pattern_keep(): """测试 BasePattern 的保持模式, 不会进行匹配或者类型转换""" - pat2 = BasePattern(mode=MatchMode.KEEP) - assert pat2.validate(123).value() == 123 - assert pat2.validate("abc").value() == "abc" + pat2 = Pattern() + assert pat2.execute(123).value() == 123 + assert pat2.execute("abc").value() == "abc" print(pat2) def test_pattern_regex(): """测试 BasePattern 的正则匹配模式, 仅正则匹配""" - pat3 = BasePattern("abc[A-Z]+123", mode=MatchMode.REGEX_MATCH) - assert pat3.validate("abcABC123").value() == "abcABC123" - assert pat3.validate("abcAbc123").failed + pat3 = Pattern.regex_match("abc[A-Z]+123") + assert pat3.execute("abcABC123").value() == "abcABC123" + assert pat3.execute("abcAbc123").failed print(pat3) - try: - BasePattern("^abc$", MatchMode.REGEX_MATCH) - except ValueError as e: - print(e) - def test_pattern_regex_convert(): """测试 BasePattern 的正则转换模式, 正则匹配成功后再进行类型转换""" - pat4 = BasePattern( + pat4 = Pattern.regex_convert( r"\[at:(\d+)\]", - MatchMode.REGEX_CONVERT, int, - lambda _, x: res if (res := int(x[1])) < 1000000 else None, + lambda m: res if (res := int(x[1])) < 1000000 else None, ) - assert pat4.validate("[at:123456]").value() == 123456 - assert pat4.validate("[at:abcdef]").failed - assert pat4.validate(123456).value() == 123456 - assert pat4.validate("[at:1234567]").failed + assert pat4.execute("[at:123456]").value() == 123456 + assert pat4.execute("[at:abcdef]").failed + assert pat4.execute(123456).value() == 123456 + assert pat4.execute("[at:1234567]").failed print(pat4) def test_pattern_type_convert(): """测试 BasePattern 的类型转换模式, 仅将传入对象变为另一类型的新对象""" - pat5 = BasePattern(mode=MatchMode.TYPE_CONVERT, origin=str) - assert pat5.validate(123).value() == "123" - assert pat5.validate([4, 5, 6]).value() == "[4, 5, 6]" - pat5_1 = BasePattern(mode=MatchMode.TYPE_CONVERT, origin=int, converter=lambda self, x: self.origin(x)) - assert pat5_1.validate("123").value() == 123 - assert pat5_1.validate("123.0").failed + pat5 = Pattern(origin=str).convert(lambda _, x: str(x)) + assert pat5.execute(123).value() == "123" + assert pat5.execute([4, 5, 6]).value() == "[4, 5, 6]" + pat5_1 = Pattern(origin=int).convert(lambda _, x: int(x)) + assert pat5_1.execute("123").value() == 123 + assert pat5_1.execute("123.0").failed print(pat5) def convert(self, content): if isinstance(content, str) and content.startswith("123"): return 123 + raise ValueError(content) - pat5_3 = BasePattern(mode=MatchMode.TYPE_CONVERT, origin=int, converter=convert) - assert pat5_3.validate("1234abcd").value() == 123 - assert pat5_3.validate("abc").failed - prev = BasePattern(mode=MatchMode.VALUE_OPERATE, origin=str, converter=lambda _, x: f"123{x}") - pat5_4 = BasePattern( - mode=MatchMode.TYPE_CONVERT, - origin=int, - accepts=str, - converter=convert, - previous=prev, - ) - assert pat5_4.validate("abc").value() == 123 + pat5_3 = Pattern(origin=int).convert(convert) + assert pat5_3.execute("1234abcd").value() == 123 + assert pat5_3.execute("abc").failed + prev = Pattern(origin=str).convert(lambda _, x: f"123{x}") + pat5_4 = Pattern(int).accept(str).convert(lambda _, x: convert(_, prev.match(x))) + assert pat5_4.execute("abc").value() == 123 def test_pattern_accepts(): @@ -195,22 +176,22 @@ def test_pattern_accepts(): converter=lambda _, x: x.decode(), accepts=bytes, ) - assert pat6.validate(b"123").value() == "123" - assert pat6.validate(123).failed + assert pat6.execute(b"123").value() == "123" + assert pat6.execute(123).failed pat6_1 = BasePattern(mode=MatchMode.KEEP, accepts=Union[int, float]) - assert pat6_1.validate(123).value() == 123 - assert pat6_1.validate("123").failed + assert pat6_1.execute(123).value() == 123 + assert pat6_1.execute("123").failed print(pat6, pat6_1) pat6_2 = BasePattern(mode=MatchMode.KEEP, accepts=bytes, addition_accepts=NUMBER) - assert pat6_2.validate(123).value() == 123 - assert pat6_2.validate(123.123).value() == 123.123 - assert pat6_2.validate(b"123").value() == b"123" + assert pat6_2.execute(123).value() == 123 + assert pat6_2.execute(123.123).value() == 123.123 + assert pat6_2.execute(b"123").value() == b"123" print(pat6_2) pat6_3 = BasePattern(mode=MatchMode.KEEP, addition_accepts=INTEGER | BOOLEAN) - assert pat6_3.validate(123).value() == 123 - assert pat6_3.validate(True).value() is True - assert pat6_3.validate(b"123").value() == b"123" - assert pat6_3.validate([]).failed + assert pat6_3.execute(123).value() == 123 + assert pat6_3.execute(True).value() is True + assert pat6_3.execute(b"123").value() == b"123" + assert pat6_3.execute([]).failed def test_pattern_previous(): @@ -228,8 +209,8 @@ def __repr__(self): converter=lambda self, x: self.origin(x[1]), previous=pat7, ) - assert pat7_1.validate("abc[123]").value() == 123 - assert pat7_1.validate(A()).value() == 123 + assert pat7_1.execute("abc[123]").value() == 123 + assert pat7_1.execute(A()).value() == 123 pat7_2 = BasePattern(mode=MatchMode.TYPE_CONVERT, origin=str) pat7_3 = BasePattern( mode=MatchMode.TYPE_CONVERT, @@ -237,33 +218,33 @@ def __repr__(self): accepts=Union[int, float], # type: ignore previous=pat7_2, # type: ignore ) - assert pat7_3.validate("123").failed + assert pat7_3.execute("123").failed print(pat7, pat7_1) def test_pattern_anti(): """测试 BasePattern 的反向验证功能""" - pat8 = BasePattern.of(int) + pat8 = Pattern(int) pat8_1 = AntiPattern(pat8) - assert pat8.validate(123).value() == 123 - assert pat8.validate("123").failed - assert pat8_1.validate(123).failed - assert pat8_1.validate("123").value() == "123" + assert pat8.execute(123).value() == 123 + assert pat8.execute("123").failed + assert pat8_1.execute(123).failed + assert pat8_1.execute("123").value() == "123" def test_pattern_validator(): """测试 BasePattern 的匹配后验证器, 会对匹配结果进行验证""" pat9 = BasePattern(mode=MatchMode.KEEP, accepts=int, validators=[lambda x: x > 0]) - assert pat9.validate(23).value() == 23 - assert pat9.validate(-23).failed + assert pat9.execute(23).value() == 23 + assert pat9.execute(-23).failed print(pat9) def test_pattern_default(): - pat10 = BasePattern.of(int) - assert pat10.validate("123", 123).or_default - assert pat10.validate("123", 123).value() == 123 - assert AntiPattern(pat10).validate(123, "123").value() == "123" + pat10 = Pattern(int) + assert pat10.execute("123", 123).or_default + assert pat10.execute("123", 123).value() == 123 + assert AntiPattern(pat10).execute(123, "123").value() == "123" def test_parser(): @@ -271,23 +252,23 @@ def test_parser(): from typing_extensions import Annotated pat11 = parser(int) - assert pat11.validate(-321).success + assert pat11.execute(-321).success pat11_1 = parser(123) print(pat11, pat11_1) pat11_2 = BasePattern.to(int) assert pat11_2 == pat11 assert isinstance(parser(Literal["a", "b"]), UnionPattern) assert parser(Type[int]).origin is type - assert parser(complex) == BasePattern.of(complex) + assert parser(complex) == Pattern(complex) assert isinstance(parser("a|b|c"), UnionPattern) assert isinstance(parser("re:a|b|c"), BasePattern) - assert parser([1, 2, 3]).validate(1).success - assert parser({"a": 1, "b": 2}).validate("a").value() == 1 + assert parser([1, 2, 3]).execute(1).success + assert parser({"a": 1, "b": 2}).execute("a").value() == 1 def _func(x: int): return x + 1 - assert parser(_func).validate(1).value() == 2 + assert parser(_func).execute(1).value() == 2 def my_func(x: int) -> str: return str(x) @@ -304,7 +285,7 @@ def my_func(x: int) -> str: print(e) pat11_4 = parser(Annotated[int, lambda x: x < 10]) - assert pat11_4.validate(11).failed + assert pat11_4.execute(11).failed pat11_5 = parser(Annotated[int, lambda x: x >= 0, "normal number"]) assert pat11_5.alias == "normal number" @@ -312,29 +293,29 @@ class TestP(Protocol): def __setitem__(self): ... pat11_6 = parser(TestP) - assert pat11_6.validate([1, 2, 3]).success - assert pat11_6.validate((1, 2, 3)).failed + assert pat11_6.execute([1, 2, 3]).success + assert pat11_6.execute((1, 2, 3)).failed TestT = TypeVar("TestT", str, int) pat11_7 = parser(TestT) - assert pat11_7.validate("abc").success - assert pat11_7.validate([]).failed + assert pat11_7.execute("abc").success + assert pat11_7.execute([]).failed def test_union_pattern(): from typing import List, Optional, Union pat12 = parser(Union[int, bool]) - assert pat12.validate(123).success - assert pat12.validate("123").success - assert pat12.validate("123").value() == 123 - assert pat12.validate(123.0).value() == 123 + assert pat12.execute(123).success + assert pat12.execute("123").success + assert pat12.execute("123").value() == 123 + assert pat12.execute(123.0).value() == 123 pat12_1 = parser(Optional[str]) - assert pat12_1.validate("123").success - assert pat12_1.validate(None).success + assert pat12_1.execute("123").success + assert pat12_1.execute(None).success pat12_2 = UnionPattern(["abc", "efg"]) - assert pat12_2.validate("abc").success - assert pat12_2.validate("bca").failed + assert pat12_2.execute("abc").success + assert pat12_2.execute("bca").failed print(pat12, pat12_1, pat12_2) pat12_3 = UnionPattern._(List[bool], int) pat12_4 = pat12_2 | pat12_3 @@ -347,65 +328,65 @@ def test_seq_pattern(): pat13 = parser(List[int]) pat13_1 = parser(Tuple[int, int]) pat13_2 = parser(Set[int]) - assert pat13.validate("[1,2,3]").value() == [1, 2, 3] - assert pat13.validate([1, 2, 3]).success - assert pat13_1.validate("(1,2,3)").value() == (1, 2, 3) - assert pat13_2.validate("{1,2,a}").failed + assert pat13.execute("[1,2,3]").value() == [1, 2, 3] + assert pat13.execute([1, 2, 3]).success + assert pat13_1.execute("(1,2,3)").value() == (1, 2, 3) + assert pat13_2.execute("{1,2,a}").failed print(pat13, pat13_1, pat13_2) try: - SequencePattern(dict, BasePattern.of(int)) # type: ignore + SequencePattern(dict, Pattern(int)) # type: ignore except ValueError as e: print(e) pat13_3 = SequencePattern(list, INTEGER, IterMode.PRE) - assert pat13_3.validate([1, 2, 3]).success - assert pat13_3.validate("[1, 2, a]").value() == [1, 2] + assert pat13_3.execute([1, 2, 3]).success + assert pat13_3.execute("[1, 2, a]").value() == [1, 2] pat13_4 = SequencePattern(list, INTEGER, IterMode.SUF) - assert pat13_4.validate([1, 2, 3]).success - assert pat13_4.validate("[1, 2, a]").failed - assert pat13_4.validate("[a, 2, 3]").value() == [2, 3] + assert pat13_4.execute([1, 2, 3]).success + assert pat13_4.execute("[1, 2, a]").failed + assert pat13_4.execute("[a, 2, 3]").value() == [2, 3] def test_map_pattern(): from typing import Dict pat14 = parser(Dict[str, int]) - assert pat14.validate("{a:1,b:2}").value() == {"a": 1, "b": 2} - assert pat14.validate("{a:a, b:2}").failed - assert pat14.validate({"a": 1, "b": 2}).success + assert pat14.execute("{a:1,b:2}").value() == {"a": 1, "b": 2} + assert pat14.execute("{a:a, b:2}").failed + assert pat14.execute({"a": 1, "b": 2}).success pat14_1 = parser(Dict[int, int]) - assert pat14_1.validate({"a": 1, "b": 2}).failed + assert pat14_1.execute({"a": 1, "b": 2}).failed print(pat14) pat14_2 = MappingPattern(INTEGER, BOOLEAN, IterMode.PRE) - assert pat14_2.validate({1: True, 2: False}).success - assert pat14_2.validate({1: True, 2: None}).value() == {1: True} - assert pat14_2.validate({0: None, 1: True, 2: False}).failed + assert pat14_2.execute({1: True, 2: False}).success + assert pat14_2.execute({1: True, 2: None}).value() == {1: True} + assert pat14_2.execute({0: None, 1: True, 2: False}).failed pat14_3 = MappingPattern(INTEGER, BOOLEAN, IterMode.SUF) - assert pat14_3.validate({1: True, 2: False}).success - assert pat14_3.validate({0: None, 1: False, 2: True}).value() == {1: False, 2: True} - assert pat14_3.validate({0: False, 1: True, 2: None}).failed + assert pat14_3.execute({1: True, 2: False}).success + assert pat14_3.execute({0: None, 1: False, 2: True}).value() == {1: False, 2: True} + assert pat14_3.execute({0: False, 1: True, 2: None}).failed def test_converters(): pattern_map = all_patterns() print(pattern_map) - assert pattern_map["any_str"].validate(123456).value() == "123456" - assert pattern_map["email"].validate("example@outlook.com").success - assert pattern_map["ip"].validate("192.168.0.1").success - assert pattern_map["url"].validate("www.example.com").success - assert pattern_map["url"].validate("https://www.example.com").value() == "https://www.example.com" - assert pattern_map["url"].validate("wwwexamplecom").failed - assert pattern_map["hex"].validate("0xff").value() == 255 - assert pattern_map["color"].validate("#ffffff").value() == "ffffff" - assert pattern_map["datetime"].validate("2011-11-04").value().day == 4 - assert pattern_map["file"].validate("test.py").value()[:4] == b"from" - assert pattern_map["number"].validate("123").value() == 123 - assert pattern_map["int"].validate("123").value() == 123 - assert pattern_map["float"].validate("12.34").value() == 12.34 - assert pattern_map["bool"].validate("false").value() is False - assert pattern_map[list].validate("[1,2,3]").value() == [1, 2, 3] - assert pattern_map[tuple].validate("(1,2,3)").value() == (1, 2, 3) - assert pattern_map[set].validate("{1,2,3}").value() == {1, 2, 3} - assert pattern_map[dict].validate('{"a":1,"b":2,"c":3}').value() == { + assert pattern_map["any_str"].execute(123456).value() == "123456" + assert pattern_map["email"].execute("example@outlook.com").success + assert pattern_map["ip"].execute("192.168.0.1").success + assert pattern_map["url"].execute("www.example.com").success + assert pattern_map["url"].execute("https://www.example.com").value() == "https://www.example.com" + assert pattern_map["url"].execute("wwwexamplecom").failed + assert pattern_map["hex"].execute("0xff").value() == 255 + assert pattern_map["color"].execute("#ffffff").value() == "ffffff" + assert pattern_map["datetime"].execute("2011-11-04").value().day == 4 + assert pattern_map["file"].execute("test.py").value()[:4] == b"from" + assert pattern_map["number"].execute("123").value() == 123 + assert pattern_map["int"].execute("123").value() == 123 + assert pattern_map["float"].execute("12.34").value() == 12.34 + assert pattern_map["bool"].execute("false").value() is False + assert pattern_map[list].execute("[1,2,3]").value() == [1, 2, 3] + assert pattern_map[tuple].execute("(1,2,3)").value() == (1, 2, 3) + assert pattern_map[set].execute("{1,2,3}").value() == {1, 2, 3} + assert pattern_map[dict].execute('{"a":1,"b":2,"c":3}').value() == { "a": 1, "b": 2, "c": 3, @@ -414,13 +395,13 @@ def test_converters(): def test_converter_method(): temp = create_local_patterns("test", set_current=False) - temp.set(BasePattern.of(complex)) + temp.set(Pattern(complex)) assert temp["complex"] - temp.set(BasePattern.of(complex), alias="abc") + temp.set(Pattern(complex), alias="abc") assert temp["abc"] - temp.set(BasePattern.of(int), alias="abc", cover=False) + temp.set(Pattern(int), alias="abc", cover=False) assert isinstance(temp["abc"], UnionPattern) - temp.merge({"b": BasePattern.of(bool), "c": BasePattern.of(str)}) + temp.merge({"b": Pattern(bool), "c": Pattern(str)}) assert temp["b"] assert temp["c"] temp.remove(complex, alias="complex") @@ -436,13 +417,13 @@ def test_converter_method(): def test_dunder(): - pat17 = BasePattern.of(float) + pat17 = Pattern(float) assert ("test_float" @ pat17).alias == "test_float" - assert pat17.validate(1.33).step(str) == pat17.validate(1.33) >> str == "1.33" - assert (pat17.validate(1.33) >> 1).value() == 1.33 + assert pat17.execute(1.33).step(str) == pat17.execute(1.33) >> str == "1.33" + assert (pat17.execute(1.33) >> 1).value() == 1.33 assert not "1.33" >> pat17 - assert pat17.validate(1.33) >> bool - assert BasePattern.of(int).validate(1).step(lambda x: x + 2) == 3 + assert pat17.execute(1.33) >> bool + assert Pattern(int).execute(1).step(lambda x: x + 2) == 3 pat17_1 = BasePattern(r"@(\d+)", MatchMode.REGEX_CONVERT, str, lambda _, x: x[0][1:]) pat17_2: BasePattern[int, Any, Any] = parser(int) assert ("@123456" >> pat17_1 >> pat17_2).value() == 123456 @@ -452,34 +433,34 @@ def test_regex_pattern(): from re import Match, compile pat18 = RegexPattern(r"((https?://)?github\.com/)?(?P[^/]+)/(?P[^/]+)", "ghrepo") - res = pat18.validate("https://github.com/ArcletProject/NEPattern").value() + res = pat18.execute("https://github.com/ArcletProject/NEPattern").value() assert isinstance(res, Match) assert res.groupdict() == {"owner": "ArcletProject", "repo": "NEPattern"} - assert pat18.validate(123).failed - assert pat18.validate("www.bilibili.com").failed + assert pat18.execute(123).failed + assert pat18.execute("www.bilibili.com").failed pat18_1 = parser(r"re:(\d+)") # str starts with "re:" will convert to BasePattern instead of RegexPattern - assert pat18_1.validate("1234").value() == "1234" + assert pat18_1.execute("1234").value() == "1234" pat18_2 = parser(r"rep:(\d+)") # str starts with "rep:" will convert to RegexPattern - assert pat18_2.validate("1234").value().groups() == ("1234",) # type: ignore + assert pat18_2.execute("1234").value().groups() == ("1234",) # type: ignore pat18_3 = parser(compile(r"(\d+)")) # re.Pattern will convert to RegexPattern - assert pat18_3.validate("1234").value().groups() == ("1234",) + assert pat18_3.execute("1234").value().groups() == ("1234",) def test_switch_pattern(): pat19 = SwitchPattern({"foo": 1, "bar": 2}) - assert pat19.validate("foo").value() == 1 - assert pat19.validate("baz").failed + assert pat19.execute("foo").value() == 1 + assert pat19.execute("baz").failed pat19_1 = SwitchPattern({"foo": 1, "bar": 2, ...: 3}) - assert pat19_1.validate("foo").value() == 1 - assert pat19_1.validate("baz").value() == 3 + assert pat19_1.execute("foo").value() == 1 + assert pat19_1.execute("baz").value() == 3 def test_patterns(): - temp = create_local_patterns("temp", {"a": BasePattern.on("A")}) + temp = create_local_patterns("temp", {"a": Pattern.on("A")}) assert temp["a"] assert local_patterns() == temp assert all_patterns()["a"] - temp1 = create_local_patterns("temp1", {"b": BasePattern.on("B")}, set_current=False) + temp1 = create_local_patterns("temp1", {"b": Pattern.on("B")}, set_current=False) assert temp1["b"] assert not local_patterns().get("b") switch_local_patterns("temp1") @@ -508,23 +489,23 @@ def test_rawstr(): def test_direct(): pat20 = DirectPattern("abc") - assert pat20.validate("abc").value() == "abc" - assert pat20.validate("abcd").failed - assert pat20.validate(123).failed - assert pat20.validate("123", 123).value() == 123 + assert pat20.execute("abc").value() == "abc" + assert pat20.execute("abcd").failed + assert pat20.execute(123).failed + assert pat20.execute("123", 123).value() == 123 pat20_1 = DirectPattern(123) - assert pat20_1.validate(123).value() == 123 - assert pat20_1.validate("123").failed - assert pat20_1.validate(123, "123").value() == 123 + assert pat20_1.execute(123).value() == 123 + assert pat20_1.execute("123").failed + assert pat20_1.execute(123, "123").value() == 123 assert pat20_1.match(123) == 123 try: pat20_1.match("123") except MatchFailed as e: print(e) pat21 = DirectTypePattern(int) - assert pat21.validate(123).value() == 123 - assert pat21.validate("123").failed - assert pat21.validate(123, "123").value() == 123 + assert pat21.execute(123).value() == 123 + assert pat21.execute("123").failed + assert pat21.execute(123, "123").value() == 123 assert pat21.match(123) == 123 assert pat21.match(456) == 456 @@ -533,9 +514,9 @@ def test_forward_red(): from typing import ForwardRef pat21 = parser(ForwardRef("int")) - assert pat21.validate(123).value() == 123 - assert pat21.validate("int").value() == "int" - assert pat21.validate(134.5).failed + assert pat21.execute(123).value() == 123 + assert pat21.execute("int").value() == "int" + assert pat21.execute(134.5).failed def test_value_operate(): @@ -544,9 +525,9 @@ def test_value_operate(): origin=int, converter=lambda _, x: x + 1, ) - assert pat22.validate(123).value() == 124 - assert pat22.validate("123").failed - assert pat22.validate(123.0).failed + assert pat22.execute(123).value() == 124 + assert pat22.execute("123").failed + assert pat22.execute(123.0).failed pat22_1p = BasePattern( mode=MatchMode.TYPE_CONVERT, @@ -561,29 +542,29 @@ def test_value_operate(): converter=lambda _, x: x + 1, previous=pat22_1p, ) - assert pat22_1.validate(123).value() == 124 - assert pat22_1.validate("123").value() == 124 - assert pat22_1.validate(123.0).value() == 124 - assert pat22_1.validate("123.0").failed - assert pat22_1.validate([]).failed + assert pat22_1.execute(123).value() == 124 + assert pat22_1.execute("123").value() == 124 + assert pat22_1.execute(123.0).value() == 124 + assert pat22_1.execute("123.0").failed + assert pat22_1.execute([]).failed def test_eq(): - assert parser(123) == BasePattern.on(123) + assert parser(123) == Pattern.on(123) assert BasePattern.to(None) == NONE - assert parser(BasePattern.of(int)) == BasePattern.of(int) + assert parser(Pattern(int)) == Pattern(int) assert parser(str) == STRING def test_combine(): pre = BasePattern(mode=MatchMode.VALUE_OPERATE, origin=str, converter=lambda _, x: x.replace(",", "_")) pat23 = combine(INTEGER, pre) - assert pat23.validate("123,456").value() == 123456 - assert pat23.validate("1,000,000").value() == 1_000_000 + assert pat23.execute("123,456").value() == 123456 + assert pat23.execute("1,000,000").value() == 1_000_000 pat23_1 = combine(INTEGER, alias="0~10", validators=[lambda x: 0 <= x <= 10]) - assert pat23_1.validate(5).value() == 5 - assert pat23_1.validate(11).failed + assert pat23_1.execute(5).value() == 5 + assert pat23_1.execute(11).failed assert str(pat23_1) == "0~10" @@ -597,59 +578,59 @@ def test_funcs(): alias="chars", converter=lambda _, x: list(x), ) - assert pat.validate("abcde").value() == ["a", "b", "c", "d", "e"] + assert pat.execute("abcde").value() == ["a", "b", "c", "d", "e"] pat24 = Index(pat, 2) - assert pat24.validate("abcde").value() == "c" + assert pat24.execute("abcde").value() == "c" pat24_1 = Slice(pat, 1, 3) - assert pat24_1.validate("abcde").value() == ["b", "c"] + assert pat24_1.execute("abcde").value() == ["b", "c"] pat24_2 = Map(pat, lambda x: x.upper(), "str.upper") - assert pat24_2.validate("abcde").value() == ["A", "B", "C", "D", "E"] + assert pat24_2.execute("abcde").value() == ["A", "B", "C", "D", "E"] pat24_3 = Filter(pat, lambda x: x in "aeiou", "vowels") - assert pat24_3.validate("abcde").value() == ["a", "e"] + assert pat24_3.execute("abcde").value() == ["a", "e"] pat24_4 = Filter(Map(pat, lambda x: x.upper(), "str.upper"), lambda x: x in "AEIOU", "vowels") - assert pat24_4.validate("abcde").value() == ["A", "E"] + assert pat24_4.execute("abcde").value() == ["A", "E"] pat24_5 = Reduce(pat24_2, lambda x, y: x + y, funcname="add") - assert pat24_5.validate("abcde").value() == "ABCDE" + assert pat24_5.execute("abcde").value() == "ABCDE" pat24_6 = Join(pat, sep="-") - assert pat24_6.validate("abcde").value() == "a-b-c-d-e" + assert pat24_6.execute("abcde").value() == "a-b-c-d-e" pat24_7 = Upper(pat24_6) - assert pat24_7.validate("abcde").value() == "A-B-C-D-E" + assert pat24_7.execute("abcde").value() == "A-B-C-D-E" pat24_8 = Lower(pat24_7) - assert pat24_8.validate("abcde").value() == "a-b-c-d-e" + assert pat24_8.execute("abcde").value() == "a-b-c-d-e" pat24_9 = Sum(Map(pat, ord)) - assert pat24_9.validate("abcde").value() == 495 + assert pat24_9.execute("abcde").value() == 495 pat24_10 = Step(pat, len) - assert pat24_10.validate("abcde").value() == 5 + assert pat24_10.execute("abcde").value() == 5 pat24_11 = Step(pat, lambda x: x.count("a"), funcname="count_a") - assert pat24_11.validate("abcde").value() == 1 + assert pat24_11.execute("abcde").value() == 1 @dataclass class Test: a: int b: str - pat1 = BasePattern.of(Test) + pat1 = Pattern(Test) obj = Test(123, "abc") - assert pat1.validate(obj).value() == obj + assert pat1.execute(obj).value() == obj pat24_12 = Dot(pat1, int, "a") - assert pat24_12.validate(obj).value() == 123 + assert pat24_12.execute(obj).value() == 123 - pat2 = BasePattern.on({"a": 123, "b": "abc"}) + pat2 = Pattern.on({"a": 123, "b": "abc"}) pat24_13 = GetItem(pat2, int, "a") - assert pat24_13.validate({"a": 123, "b": "abc"}).value() == 123 + assert pat24_13.execute({"a": 123, "b": "abc"}).value() == 123 if __name__ == "__main__":