Skip to content

Commit

Permalink
🎨 format
Browse files Browse the repository at this point in the history
  • Loading branch information
RF-Tar-Railt committed Oct 13, 2024
1 parent 04dc83e commit 7cfb8d7
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 266 deletions.
37 changes: 21 additions & 16 deletions nepattern/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@
from pathlib import Path
import re
import sys
from typing import (
Any,
ForwardRef,
Generic,
Match,
TypeVar,
Union,
final,
Final
)
from typing import Any, Callable, Final, ForwardRef, Generic, Match, TypeVar, Union, final

from tarina import DateParser, lang

Expand Down Expand Up @@ -154,6 +145,7 @@ def __eq__(self, other): # pragma: no cover

class SwitchPattern(Pattern[_TCase], Generic[_TCase, _TSwtich]):
"""匹配多种情况的表达式"""

switch: dict[_TSwtich | ellipsis, _TCase]

__slots__ = ("switch",)
Expand Down Expand Up @@ -426,10 +418,10 @@ def __eq__(self, other): # pragma: no cover
WIDE_BOOLEAN = WideBoolPattern()
"""宽松布尔表达式,可以接受更多的布尔样式的量"""

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")
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: Final = Pattern.regex_match(r"(?:[\w\.+-]+)@(?:[\w\.-]+)\.(?:[\w\.-]+)", alias="email")
"""匹配邮箱地址的表达式"""
Expand Down Expand Up @@ -527,14 +519,15 @@ def __eq__(self, other): # pragma: no cover
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())
.convert(lambda _, x: x if isinstance(x, bytes) else Path(x).read_bytes())
)


def combine(
current: Pattern[_T],
previous: Pattern[Any],
previous: Pattern[Any] | None = None,
alias: str | None = None,
validator: Callable[[_T], bool] | None = None,
) -> Pattern[_T]:
_new = current.copy()
if previous:
Expand All @@ -546,6 +539,18 @@ def match(self, input_):
_new.match = match.__get__(_new)
if alias:
_new.alias = alias
if validator:
_match = _new.match

def match(self, input_):
res = _match(input_)
if not validator(res):
raise MatchFailed(
lang.require("nepattern", "error.content").format(target=input_, expected=alias)
)
return res

_new.match = match.__get__(_new)
return _new


Expand Down
4 changes: 1 addition & 3 deletions nepattern/context.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ from .core import Pattern
class Patterns(UserDict[Any, Pattern]):
name: str
def __init__(self, name: str): ...
def set(
self, target: Pattern[Any], alias: str | None = None, cover: bool = True, no_alias=False
):
def set(self, target: Pattern[Any], alias: str | None = None, cover: bool = True, no_alias=False):
"""
增加可使用的类型转换器
Expand Down
84 changes: 63 additions & 21 deletions nepattern/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

from copy import deepcopy
import re
from typing import Any, Callable, Generic, TypeVar, overload
from typing import Any, Callable, Generic, TypeVar, Union, overload
from typing_extensions import Self

from tarina import Empty, generic_isinstance
from tarina.lang import lang

from .exception import MatchFailed


T = TypeVar("T")


Expand Down Expand Up @@ -49,7 +48,11 @@ def __bool__(self):
return self._value != Empty

def __repr__(self):
return f"ValidateResult(value={self._value!r})" if self._value is not Empty else f"ValidateResult(error={self._error!r})"
return (
f"ValidateResult(value={self._value!r})"
if self._value is not Empty
else f"ValidateResult(error={self._error!r})"
)


class Pattern(Generic[T]):
Expand All @@ -61,21 +64,47 @@ def regex_match(pattern: str, alias: str | None = None):
def _(self, x: str):
mat = re.match(pattern, x)
if not mat:
raise MatchFailed(lang.require("nepattern", "error.content").format(target=x, expected=pattern))
raise MatchFailed(
lang.require("nepattern", "error.content").format(target=x, expected=pattern)
)
return x

return pat

@staticmethod
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)
def regex_convert(
pattern: str,
origin: type[T],
fn: Callable[[re.Match], T],
alias: str | None = None,
allow_origin: bool = False,
):
pat = Pattern(origin, alias)
if allow_origin:
pat.accept(Union[str, origin])

@pat.convert
def _(self, x):
if isinstance(x, origin):
return x
mat = re.match(pattern, x)
if not mat:
raise MatchFailed(
lang.require("nepattern", "error.content").format(target=x, expected=pattern)
)
return fn(mat)

else:
pat.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 pat

Expand All @@ -87,12 +116,10 @@ def on(obj: T):
return DirectPattern(obj)

@overload
def __init__(self, origin: type[T], alias: str | None = None):
...
def __init__(self, origin: type[T], alias: str | None = None): ...

@overload
def __init__(self: Pattern[Any], *, alias: str | None = None):
...
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
Expand All @@ -103,6 +130,9 @@ def __init__(self, origin: type[T] | None = None, alias: str | None = None):
self._pre_validator = None
self._converter = None

def __init_subclass__(cls, **kwargs):
cls.__hash__ = Pattern.__hash__

def accept(self, input_type: Any):
self._accepts = input_type
return self
Expand All @@ -121,13 +151,19 @@ def convert(self, func: Callable[[Self, Any], T]):

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))
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))
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))
raise MatchFailed(
lang.require("nepattern", "error.content").format(target=input_, expected=self.origin)
)
return input_

def execute(self, input_: Any) -> ValidateResult[T]:
Expand All @@ -144,7 +180,7 @@ def __str__(self):
return f"{self._accepts.__name__} -> {self.origin.__name__}"

def __repr__(self):
return f"Pattern({self.origin.__name__}, {self.alias})"
return f"{self.__class__.__name__}({self.origin.__name__}, {self.alias})"

def copy(self) -> Self:
return deepcopy(self)
Expand All @@ -161,3 +197,9 @@ def __matmul__(self, other) -> Self: # pragma: no cover
if isinstance(other, str):
self.alias = other
return self

def __hash__(self):
return id((self.origin, self.alias, self._accepts, self._converter))

def __eq__(self, other):
return isinstance(other, Pattern) and self.__hash__() == other.__hash__()
11 changes: 6 additions & 5 deletions nepattern/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
RegexPattern,
SwitchPattern,
UnionPattern,
combine,
)
from .context import all_patterns
from .core import Pattern
Expand All @@ -38,12 +39,12 @@ def _generic_parser(item: GenericAlias, extra: str) -> Pattern: # type: ignore
org, *meta = get_args(item)
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
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
return combine(
_o,
alias=al[-1] if (al := [i for i in meta if isinstance(i, str)]) else _o.alias,
validator=(lambda x: all(i(x) for i in validators)) if validators else None,
)
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
Expand Down
3 changes: 1 addition & 2 deletions nepattern/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

import dataclasses
import sys
from types import GenericAlias as CGenericAlias # noqa: F401
from typing import TYPE_CHECKING, List, Pattern, Union
from typing_extensions import TypeAlias

from .i18n import lang as lang # noqa: F401

from types import GenericAlias as CGenericAlias # noqa: F401

if sys.version_info >= (3, 10): # pragma: no cover
from types import UnionType as CUnionType # noqa: F401
else: # pragma: no cover
Expand Down
Loading

0 comments on commit 7cfb8d7

Please sign in to comment.