Skip to content

Commit

Permalink
✨ version 0.7.2
Browse files Browse the repository at this point in the history
add some func pattern
  • Loading branch information
RF-Tar-Railt committed Apr 25, 2024
1 parent b50cc35 commit d728c08
Show file tree
Hide file tree
Showing 12 changed files with 930 additions and 243 deletions.
16 changes: 14 additions & 2 deletions nepattern/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Any
from pathlib import Path
from typing import Any

from tarina import Empty as Empty # noqa

Expand All @@ -9,8 +9,8 @@
from .base import BOOLEAN as BOOLEAN
from .base import BYTES as BYTES
from .base import DATETIME as DATETIME
from .base import DelimiterInt as DelimiterInt
from .base import DICT as DICT
from .base import DelimiterInt as DelimiterInt
from .base import DirectPattern as DirectPattern
from .base import DirectTypePattern as DirectTypePattern
from .base import EMAIL as EMAIL
Expand Down Expand Up @@ -47,6 +47,18 @@
from .core import MatchMode as MatchMode
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
Expand Down
136 changes: 68 additions & 68 deletions nepattern/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from enum import Enum
from datetime import datetime
from enum import Enum
from pathlib import Path
import re
import sys
Expand All @@ -11,19 +11,20 @@
Callable,
Dict,
ForwardRef,
Generic,
Iterable,
Literal,
Match,
TypeVar,
Union,
cast,
final,
overload, Generic,
overload,
)

from tarina import DateParser, Empty, lang

from .core import BasePattern, MatchMode, ResultFlag, ValidateResult, _MATCHES, TMM
from .core import _MATCHES, TMM, BasePattern, MatchMode, ResultFlag, ValidateResult
from .exception import MatchFailed
from .util import TPattern

Expand All @@ -36,8 +37,6 @@
class DirectPattern(BasePattern[TOrigin, TOrigin, Literal[MatchMode.KEEP]]):
"""直接判断"""

__slots__ = ("target",)

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))
Expand All @@ -50,42 +49,39 @@ def match(self, input_: Any):
return input_

@overload
def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]:
...
def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ...

@overload
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]:
...
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]: ...

@overload
def validate(self, input_: TOrigin, default: Any) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]:
...
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]]:
...
) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ...

def validate(self, input_: Any, default: Union[TDefault, Empty] = Empty) -> ValidateResult[TOrigin | TDefault, ResultFlag]: # type: ignore
if input_ == self.target:
return ValidateResult(input_, flag=ResultFlag.VALID)
e = MatchFailed(
lang.require("nepattern", "content_error").format(target=input_, expected=self.target)
)
if default is Empty:
return ValidateResult(error=e, flag=ResultFlag.ERROR)
return ValidateResult(default, flag=ResultFlag.DEFAULT) # 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, DirectPattern) and self.target == other.target

def copy(self):
return DirectPattern(self.target, self.alias)


class DirectTypePattern(BasePattern[TOrigin, TOrigin, Literal[MatchMode.KEEP]]):
"""直接类型判断"""

__slots__ = ("target",)

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__)
Expand All @@ -100,38 +96,35 @@ def match(self, input_: Any):
return input_

@overload
def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]:
...
def validate(self, input_: TOrigin) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]: ...

@overload
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]:
...
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.ERROR]]: ...

@overload
def validate(self, input_: TOrigin, default: Any) -> ValidateResult[TOrigin, Literal[ResultFlag.VALID]]:
...
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]]:
...
) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ...

def validate(self, input_: Any, default: Union[TDefault, Empty] = Empty) -> ValidateResult[TOrigin | TDefault, ResultFlag]: # type: ignore
if isinstance(input_, self.target):
return ValidateResult(input_, flag=ResultFlag.VALID)
e = MatchFailed(
lang.require("nepattern", "type_error").format(
type=input_.__class__, target=input_, expected=self.target
)
)
if default is Empty:
return ValidateResult(error=e, flag=ResultFlag.ERROR)
return ValidateResult(default, flag=ResultFlag.DEFAULT) # 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 copy(self):
return DirectTypePattern(self.target, self.alias)


class RegexPattern(BasePattern[Match[str], str, Literal[MatchMode.REGEX_MATCH]]):
"""针对正则的特化匹配,支持正则组"""
Expand All @@ -157,6 +150,9 @@ def match(self, input_: Any) -> Match[str]:
def __calc_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]]):
"""多类型参数的匹配"""
Expand Down Expand Up @@ -195,7 +191,7 @@ def match(self, input_: Any):
lang.require("nepattern", "content_error").format(target=input_, expected=self.alias)
)
return input_

@classmethod
def _(cls, *types: type[_T1]) -> UnionPattern[_T1]:
from .main import parser
Expand Down Expand Up @@ -224,7 +220,9 @@ class IterMode(str, Enum):
TIterMode = TypeVar("TIterMode", bound=IterMode)


class SequencePattern(BasePattern[TSeq, Union[str, TSeq], Literal[MatchMode.REGEX_CONVERT]], Generic[TSeq, TIterMode]):
class SequencePattern(
BasePattern[TSeq, Union[str, TSeq], Literal[MatchMode.REGEX_CONVERT]], Generic[TSeq, TIterMode]
):
"""匹配列表或者元组或者集合"""

base: BasePattern
Expand Down Expand Up @@ -286,10 +284,10 @@ class MappingPattern(
itermode: TIterMode

def __init__(
self,
arg_key: BasePattern[TKey, Any, Any],
self,
arg_key: BasePattern[TKey, Any, Any],
arg_value: BasePattern[TVal, Any, Any],
mode: TIterMode = IterMode.ALL
mode: TIterMode = IterMode.ALL,
):
self.key = arg_key
self.value = arg_value
Expand Down Expand Up @@ -376,7 +374,9 @@ def __calc_eq__(self, other): # pragma: no cover
class ForwardRefPattern(BasePattern[Any, Any, Literal[MatchMode.TYPE_CONVERT]]):
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__(
mode=MatchMode.TYPE_CONVERT, origin=Any, converter=lambda _, x: eval(x), alias=ref.__forward_arg__
)

def match(self, input_: Any):
if isinstance(input_, str) and input_ == self.ref.__forward_arg__:
Expand Down Expand Up @@ -404,22 +404,18 @@ def __init__(self, pattern: BasePattern[TOrigin, Any, Any]):
super().__init__(mode=MatchMode.TYPE_CONVERT, origin=pattern.origin, alias=f"!{pattern}")

@overload
def validate(self, input_: TOrigin) -> ValidateResult[Any, Literal[ResultFlag.ERROR]]:
...
def validate(self, input_: TOrigin) -> ValidateResult[Any, Literal[ResultFlag.ERROR]]: ...

@overload
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.VALID]]:
...
def validate(self, input_: _T) -> ValidateResult[_T, Literal[ResultFlag.VALID]]: ...

@overload
def validate(
self, input_: TOrigin, default: TDefault
) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]:
...
) -> ValidateResult[TDefault, Literal[ResultFlag.DEFAULT]]: ...

@overload
def validate(self, input_: _T, default: Any) -> ValidateResult[_T, Literal[ResultFlag.VALID]]:
...
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
"""
Expand Down Expand Up @@ -506,16 +502,19 @@ def __calc_eq__(self, other): # pragma: no cover
@final
class StrPattern(BasePattern[str, Union[str, bytes, bytearray], Literal[MatchMode.TYPE_CONVERT]]):
def __init__(self):
super().__init__(mode=MatchMode.TYPE_CONVERT, origin=str, accepts=Union[str, bytes, bytearray], alias="str")
super().__init__(
mode=MatchMode.TYPE_CONVERT, origin=str, accepts=Union[str, bytes, bytearray], alias="str"
)

def match(self, input_: Any) -> str:
if isinstance(input_, str):
return input_.value if isinstance(input_, Enum) else input_
elif isinstance(input_, (bytes, bytearray)):
return input_.decode()
raise MatchFailed(
lang.require("nepattern", "type_error")
.format(type=input_.__class__, target=input_, expected="str | bytes | bytearray")
lang.require("nepattern", "type_error").format(
type=input_.__class__, target=input_, expected="str | bytes | bytearray"
)
)

def __calc_eq__(self, other): # pragma: no cover
Expand All @@ -528,7 +527,9 @@ def __calc_eq__(self, other): # pragma: no cover
@final
class BytesPattern(BasePattern[bytes, Union[str, bytes, bytearray], Literal[MatchMode.TYPE_CONVERT]]):
def __init__(self):
super().__init__(mode=MatchMode.TYPE_CONVERT, origin=bytes, accepts=Union[str, bytes, bytearray], alias="bytes")
super().__init__(
mode=MatchMode.TYPE_CONVERT, origin=bytes, accepts=Union[str, bytes, bytearray], alias="bytes"
)

def match(self, input_: Any) -> bytes:
if isinstance(input_, bytes):
Expand Down Expand Up @@ -639,9 +640,7 @@ 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", "content_error").format(target=input_, expected="bool"))

def __calc_eq__(self, other): # pragma: no cover
return other.__class__ is BoolPattern
Expand All @@ -656,8 +655,8 @@ class WideBoolPattern(BasePattern[bool, Any, Literal[MatchMode.TYPE_CONVERT]]):
def __init__(self):
super().__init__(mode=MatchMode.TYPE_CONVERT, origin=bool, alias="bool")

BOOL_FALSE = {0, '0', 'off', 'f', 'false', 'n', 'no'}
BOOL_TRUE = {1, '1', 'on', 't', 'true', 'y', 'yes'}
BOOL_FALSE = {0, "0", "off", "f", "false", "n", "no"}
BOOL_TRUE = {1, "1", "on", "t", "true", "y", "yes"}

def match(self, input_: Any) -> bool:
if input_ is True or input_ is False:
Expand All @@ -676,8 +675,9 @@ def match(self, input_: Any) -> bool:
)
except (ValueError, TypeError) as e:
raise MatchFailed(
lang.require("nepattern", "type_error")
.format(type=input_.__class__, target=input_, expected="bool")
lang.require("nepattern", "type_error").format(
type=input_.__class__, target=input_, expected="bool"
)
) from e

def __calc_eq__(self, other): # pragma: no cover
Expand Down Expand Up @@ -728,7 +728,7 @@ def match(self, input_: str) -> int:
raise MatchFailed(
lang.require("nepattern", "content_error").format(target=input_, expected="hex")
) from e

def __calc_eq__(self, other): # pragma: no cover
return other.__class__ is HexPattern

Expand Down Expand Up @@ -800,7 +800,7 @@ def __calc_eq__(self, other): # pragma: no cover

def combine(
current: BasePattern[TOrigin, TInput, TMM],
previous: BasePattern[Any, Any, Literal[MatchMode.VALUE_OPERATE]] | None = None,
previous: BasePattern[TInput, Any, Any] | None = None,
alias: str | None = None,
validators: list[Callable[[TOrigin], bool]] | None = None,
) -> BasePattern[TOrigin, TInput, TMM]:
Expand Down
2 changes: 1 addition & 1 deletion nepattern/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from tarina import Empty

from .base import UnionPattern, NONE
from .base import NONE, UnionPattern


@final
Expand Down
5 changes: 4 additions & 1 deletion nepattern/context.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ from .core import BasePattern
class Patterns(UserDict[Any, BasePattern]):
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):
def set(
self, target: BasePattern[Any, Any, Any], alias: str | None = None, cover: bool = True, no_alias=False
):
"""
增加可使用的类型转换器
Expand All @@ -18,6 +20,7 @@ class Patterns(UserDict[Any, BasePattern]):
no_alias: 是否不使用目标类型自带的别名
"""
...

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 remove(self, origin_type: type, alias: str | None = None): ...
Expand Down

0 comments on commit d728c08

Please sign in to comment.