aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-11-11 01:12:29 +0800
committerYuqian Yang <crupest@crupest.life>2024-12-18 18:31:27 +0800
commit1d370f56d5a7b21fc440e90944f69627fd6cedb4 (patch)
treeb09dd63c2a99c3b3ff9f30f46a5bf5ff6f054964 /tools
parente710a36af2775118c514954252537ae37f11996c (diff)
downloadcrupest-1d370f56d5a7b21fc440e90944f69627fd6cedb4.tar.gz
crupest-1d370f56d5a7b21fc440e90944f69627fd6cedb4.tar.bz2
crupest-1d370f56d5a7b21fc440e90944f69627fd6cedb4.zip
HALF WORK: 2024.12.12
Diffstat (limited to 'tools')
-rw-r--r--tools/cru-py/cru/__init__.py4
-rw-r--r--tools/cru-py/cru/_base.py (renamed from tools/cru-py/cru/_cru.py)24
-rw-r--r--tools/cru-py/cru/_const.py2
-rw-r--r--tools/cru-py/cru/_decorator.py2
-rw-r--r--tools/cru-py/cru/_func.py12
-rw-r--r--tools/cru-py/cru/_iter.py96
-rw-r--r--tools/cru-py/cru/_list.py104
-rw-r--r--tools/cru-py/cru/_type.py51
8 files changed, 179 insertions, 116 deletions
diff --git a/tools/cru-py/cru/__init__.py b/tools/cru-py/cru/__init__.py
index 2ae241e..94d0d69 100644
--- a/tools/cru-py/cru/__init__.py
+++ b/tools/cru-py/cru/__init__.py
@@ -1,7 +1,9 @@
import sys
+from ._base import CruException
-class CruInitError(Exception):
+
+class CruInitError(CruException):
pass
diff --git a/tools/cru-py/cru/_cru.py b/tools/cru-py/cru/_base.py
index 0085a80..96466d1 100644
--- a/tools/cru-py/cru/_cru.py
+++ b/tools/cru-py/cru/_base.py
@@ -1,8 +1,24 @@
-from typing import Any
+from typing import Any, NoReturn
from ._lang import remove_none
+class CruException(Exception):
+ """Base exception class of all exceptions in cru."""
+
+
+class CruNamespaceError(CruException):
+ """Raised when a namespace is not found."""
+
+
+class CruUnreachableError(CruException):
+ """Raised when a code path is unreachable."""
+
+
+def cru_unreachable() -> NoReturn:
+ raise CruUnreachableError()
+
+
class _Cru:
NAME_PREFIXES = ("CRU_", "Cru", "cru_")
@@ -30,13 +46,15 @@ class _Cru:
if name is None:
continue
if self.has_name(name):
- raise ValueError(f"Name {name} exists in CRU.")
+ raise CruNamespaceError(f"Name {name} exists in CRU.")
@staticmethod
def check_name_format(name: str) -> tuple[str, str]:
no_prefix_name = _Cru._maybe_remove_prefix(name)
if no_prefix_name is None:
- raise ValueError(f"Name {name} is not prefixed with {_Cru.NAME_PREFIXES}.")
+ raise ValueError(
+ f"Name {name} is not prefixed with any of {_Cru.NAME_PREFIXES}."
+ )
return name, no_prefix_name
@staticmethod
diff --git a/tools/cru-py/cru/_const.py b/tools/cru-py/cru/_const.py
index bc02c3a..8246b35 100644
--- a/tools/cru-py/cru/_const.py
+++ b/tools/cru-py/cru/_const.py
@@ -1,7 +1,7 @@
from enum import Enum, auto
from typing import Self, TypeGuard, TypeVar
-from ._cru import CRU
+from ._base import CRU
_T = TypeVar("_T")
diff --git a/tools/cru-py/cru/_decorator.py b/tools/cru-py/cru/_decorator.py
index 432ceca..137fc05 100644
--- a/tools/cru-py/cru/_decorator.py
+++ b/tools/cru-py/cru/_decorator.py
@@ -9,7 +9,7 @@ from typing import (
cast,
)
-from ._cru import CRU
+from ._base import CRU
_P = ParamSpec("_P")
_T = TypeVar("_T")
diff --git a/tools/cru-py/cru/_func.py b/tools/cru-py/cru/_func.py
index 1b437be..2b317ab 100644
--- a/tools/cru-py/cru/_func.py
+++ b/tools/cru-py/cru/_func.py
@@ -13,7 +13,7 @@ from typing import (
)
-from ._cru import CRU
+from ._base import CRU
from ._const import CruPlaceholder
_P = ParamSpec("_P")
@@ -163,11 +163,11 @@ class _Creators:
class CruFunction:
- RawBase = _RawBase
- Base = _Base
- Creators = _Creators
- Wrapper = _Wrapper
- Decorators = _Dec
+ RawBase: TypeAlias = _RawBase
+ Base: TypeAlias = _Base
+ Creators: TypeAlias = _Creators
+ Wrapper: TypeAlias = _Wrapper
+ Decorators: TypeAlias = _Dec
CRU.add_objects(CruFunction)
diff --git a/tools/cru-py/cru/_iter.py b/tools/cru-py/cru/_iter.py
index 83a9513..bf1dfde 100644
--- a/tools/cru-py/cru/_iter.py
+++ b/tools/cru-py/cru/_iter.py
@@ -18,7 +18,7 @@ from typing import (
cast,
)
-from ._cru import CRU
+from ._base import CRU, cru_unreachable
from ._const import CruNotFound
_P = ParamSpec("_P")
@@ -238,7 +238,7 @@ class _Generic:
pass
except StopIteration as stop:
return stop.value
- raise RuntimeError("Should not reach here")
+ cru_unreachable()
class _Helper:
@@ -255,38 +255,49 @@ class _Helper:
return wrapper
-class _Dec:
-
- @staticmethod
- def wrap(origin: Callable[_P, Iterable[_T]]) -> Callable[_P, _Wrapper[_T]]:
- def _wrapped(*args: _P.args, **kwargs: _P.kwargs) -> _Wrapper[_T]:
- return _Wrapper(origin(*args, **kwargs))
-
- return _wrapped
-
-
class _Creators:
+
@staticmethod
- @_Dec.wrap
- def empty() -> Iterable[Never]:
- return iter([])
+ def empty(
+ *,
+ wrapper_type: type["_Wrapper[Never]"] | None = None,
+ attr: dict[str, Any] | None = None,
+ ) -> _Wrapper[Never]:
+ wrapper_type = wrapper_type or _Wrapper
+ return wrapper_type(iter([]), attr)
@staticmethod
- @_Dec.wrap
- def range(*args) -> Iterable[int]:
- return iter(range(*args))
+ def range(
+ *args,
+ wrapper_type: type["_Wrapper[int]"] | None = None,
+ attr: dict[str, Any] | None = None,
+ ) -> _Wrapper[int]:
+ wrapper_type = wrapper_type or _Wrapper
+ return wrapper_type(iter(range(*args)), attr)
@staticmethod
- @_Dec.wrap
- def unite(*args: _O) -> Iterable[_O]:
- return iter(args)
+ def unite(
+ *args: _O,
+ wrapper_type: type["_Wrapper[_O]"] | None = None,
+ attr: dict[str, Any] | None = None,
+ ) -> _Wrapper[_O]:
+ wrapper_type = wrapper_type or _Wrapper
+ return wrapper_type(iter(args), attr)
@staticmethod
- @_Dec.wrap
- def concat(*iterables: Iterable[_T]) -> Iterable[_T]:
+ def _concat(*iterables: Iterable[_T]) -> Iterable[_T]:
for iterable in iterables:
yield from iterable
+ @staticmethod
+ def concat(
+ *iterables: Iterable[_T],
+ wrapper_type: type["_Wrapper[_T]"] | None = None,
+ attr: dict[str, Any] | None = None,
+ ) -> _Wrapper[_T]:
+ wrapper_type = wrapper_type or _Wrapper
+ return wrapper_type(_Creators._concat(*iterables), attr)
+
class _Wrapper(Generic[_T]):
ElementOperation: TypeAlias = Callable[[_V], Any]
@@ -297,10 +308,10 @@ class _Wrapper(Generic[_T]):
AnyElementTransformer: TypeAlias = ElementTransformer[Any, Any]
def __init__(
- self,
- iterable: Iterable[_T],
+ self, iterable: Iterable[_T], attr: dict[str, Any] | None = None
) -> None:
self._iterable = iterable
+ self._attr = attr or {}
def __iter__(self) -> Iterator[_T]:
return self._iterable.__iter__()
@@ -309,23 +320,39 @@ class _Wrapper(Generic[_T]):
def me(self) -> Iterable[_T]:
return self._iterable
- _wrap = _Dec.wrap
+ @property
+ def my_attr(self) -> dict[str, Any]:
+ return self._attr
+
+ def create_with_me(self, iterable: Iterable[_O]) -> _Wrapper[_O]:
+ return type(self)(iterable, self._attr) # type: ignore
+
+ @staticmethod
+ def _wrap(
+ f: Callable[Concatenate[_Wrapper[_T], _P], Iterable[_O]]
+ ) -> Callable[Concatenate[_Wrapper[_T], _P], _Wrapper[_O]]:
+ def _wrapped(
+ self: _Wrapper[_T], *args: _P.args, **kwargs: _P.kwargs
+ ) -> _Wrapper[_O]:
+ return self.create_with_me(f(self, *args, **kwargs))
+
+ return _wrapped
@_wrap
def replace_me(self, iterable: Iterable[_O]) -> Iterable[_O]:
return iterable
def replace_me_with_empty(self) -> _Wrapper[Never]:
- return _Creators.empty()
+ return _Creators.empty(wrapper_type=type(self), attr=self._attr) # type: ignore
def replace_me_with_range(self, *args) -> _Wrapper[int]:
- return _Creators.range(*args)
+ return _Creators.range(*args, attr=self._attr)
def replace_me_with_unite(self, *args: _O) -> _Wrapper[_O]:
- return _Creators.unite(*args)
+ return _Creators.unite(*args, attr=self._attr)
def replace_me_with_concat(self, *iterables: Iterable[_T]) -> _Wrapper[_T]:
- return _Creators.concat(*iterables)
+ return _Creators.concat(*iterables, attr=self._attr)
def to_set(self, discard: Iterable[Any]) -> set[_T]:
return set(self.me) - set(discard)
@@ -422,11 +449,10 @@ class _Wrapper(Generic[_T]):
class CruIterable:
- Decorators = _Dec
- Generic = _Generic
- Helper = _Helper
- Creators = _Creators
- Wrapper = _Wrapper
+ Generic: TypeAlias = _Generic
+ Helper: TypeAlias = _Helper
+ Creators: TypeAlias = _Creators
+ Wrapper: TypeAlias = _Wrapper
CRU.add_objects(CruIterable, _Wrapper)
diff --git a/tools/cru-py/cru/_list.py b/tools/cru-py/cru/_list.py
index f1965db..45122bf 100644
--- a/tools/cru-py/cru/_list.py
+++ b/tools/cru-py/cru/_list.py
@@ -1,77 +1,75 @@
+from __future__ import annotations
+from collections.abc import Callable
+from typing import Generic, Iterable, Self, TypeAlias, TypeVar
+from ._iter import CruIterable
-class CruInplaceList(CruList, Generic[_V]):
+_T = TypeVar("_T")
- def clear(self) -> "CruInplaceList[_V]":
- self.clear()
- return self
- def extend(self, *l: Iterable[_V]) -> "CruInplaceList[_V]":
- self.extend(l)
- return self
+class CruListEdit(CruIterable.Wrapper[_T]):
+ def done(self) -> CruList[_T]:
+ l: CruList[_T] = self.my_attr["list"]
+ l.reset(self)
+ return l
- def reset(self, *l: Iterable[_V]) -> "CruInplaceList[_V]":
+
+class CruList(list[_T]):
+ def reset(self, new_values: Iterable[_T]):
+ if self is new_values:
+ new_values = list(new_values)
self.clear()
- self.extend(l)
+ self.extend(new_values)
return self
- def transform(self, *f: OptionalElementTransformer) -> "CruInplaceList"[Any]:
- return self.reset(super().transform(*f))
-
- def transform_if(
- self, f: OptionalElementTransformer, p: ElementPredicate[_V]
- ) -> "CruInplaceList"[Any]:
- return self.reset(super().transform_if(f, p))
+ def as_iterable_wrapper(self) -> CruIterable.Wrapper[_T]:
+ return CruIterable.Wrapper(self)
- def remove_by_indices(self, *index: int) -> "CruInplaceList"[_V]:
- return self.reset(super().remove_by_indices(*index))
-
- def remove_all_if(self, p: ElementPredicate[_V]) -> "CruInplaceList"[_V]:
- return self.reset(super().remove_all_if(p))
-
- def remove_all_value(self, *r: Any) -> "CruInplaceList"[_V]:
- return self.reset(super().remove_all_value(*r))
-
- def replace_all_value(
- self, old_value: Any, new_value: R
- ) -> "CruInplaceList"[_V | R]:
- return self.reset(super().replace_all_value(old_value, new_value))
+ def as_edit_iterable_wrapper(self) -> CruListEdit[_T]:
+ return CruListEdit(self, attr={"list": self})
@staticmethod
- def make(l: CanBeList[_V]) -> "CruInplaceList"[_V]:
- return CruInplaceList(ListOperations.make(l))
-
+ def make(maybe_list: Iterable[_T] | _T | None) -> CruList[_T]:
+ if maybe_list is None:
+ return CruList()
+ if isinstance(maybe_list, Iterable):
+ return CruList(maybe_list)
+ return CruList([maybe_list])
-K = TypeVar("K")
+_K = TypeVar("_K")
+_KeyGetter: TypeAlias = Callable[[_T], _K]
-class CruUniqueKeyInplaceList(Generic[_V, K]):
- KeyGetter = Callable[[_V], K]
+class CruUniqueKeyList(Generic[_T, _K]):
def __init__(
- self, get_key: KeyGetter, *, before_add: Callable[[_V], _V] | None = None
+ self,
+ key_getter: _KeyGetter[_T, _K],
+ *,
+ before_add: Callable[[_T], _T] | None = None,
):
super().__init__()
- self._get_key = get_key
+ self._key_getter = key_getter
self._before_add = before_add
- self._l: CruInplaceList[_V] = CruInplaceList()
+ self._list: CruList[_T] = CruList()
@property
- def object_key_getter(self) -> KeyGetter:
- return self._get_key
+ def key_getter(self) -> _KeyGetter[_T, _K]:
+ return self._key_getter
@property
- def internal_list(self) -> CruInplaceList[_V]:
- return self._l
+ def internal_list(self) -> CruList[_T]:
+ return self._list
def validate_self(self):
- keys = self._l.transform(self._get_key)
+ keys = self._list.transform(self._key_getter)
if len(keys) != len(set(keys)):
raise ValueError("Duplicate keys!")
- def get_or(self, k: K, fallback: Any = CRU_NOT_FOUND) -> _V | Any:
- r = self._l.find_if(lambda i: k == self._get_key(i))
+ # TODO: Continue here!
+ def get_or(self, key: K, fallback: Any = CRU_NOT_FOUND) -> _V | Any:
+ r = self._l.find_if(lambda i: k == self._key_getter(i))
return r if r is not CRU_NOT_FOUND else fallback
def get(self, k: K) -> _V:
@@ -84,10 +82,10 @@ class CruUniqueKeyInplaceList(Generic[_V, K]):
return self.get_or(k, CRU_NOT_FOUND) is not CRU_NOT_FOUND
def has_any_key(self, *k: K) -> bool:
- return self._l.any(lambda i: self._get_key(i) in k)
+ return self._l.any(lambda i: self._key_getter(i) in k)
def try_remove(self, k: K) -> bool:
- i = self._l.find_index_if(lambda v: k == self._get_key(v))
+ i = self._l.find_index_if(lambda v: k == self._key_getter(v))
if i is CRU_NOT_FOUND:
return False
self._l.remove_by_indices(i)
@@ -98,11 +96,11 @@ class CruUniqueKeyInplaceList(Generic[_V, K]):
raise KeyError(f"Key {k} not found!")
def add(self, v: _V, /, replace: bool = False) -> None:
- if self.has_key(self._get_key(v)):
+ if self.has_key(self._key_getter(v)):
if replace:
- self.remove(self._get_key(v))
+ self.remove(self._key_getter(v))
else:
- raise ValueError(f"Key {self._get_key(v)} already exists!")
+ raise ValueError(f"Key {self._key_getter(v)} already exists!")
if self._before_add is not None:
v = self._before_add(v)
self._l.append(v)
@@ -111,12 +109,12 @@ class CruUniqueKeyInplaceList(Generic[_V, K]):
self.add(v, True)
def extend(self, l: Iterable[_V], /, replace: bool = False) -> None:
- if not replace and self.has_any_key([self._get_key(i) for i in l]):
+ if not replace and self.has_any_key([self._key_getter(i) for i in l]):
raise ValueError("Keys already exists!")
if self._before_add is not None:
l = [self._before_add(i) for i in l]
- keys = [self._get_key(i) for i in l]
- self._l.remove_all_if(lambda i: self._get_key(i) in keys).extend(l)
+ keys = [self._key_getter(i) for i in l]
+ self._l.remove_all_if(lambda i: self._key_getter(i) in keys).extend(l)
def clear(self) -> None:
self._l.clear()
diff --git a/tools/cru-py/cru/_type.py b/tools/cru-py/cru/_type.py
index b67ee9a..c60a913 100644
--- a/tools/cru-py/cru/_type.py
+++ b/tools/cru-py/cru/_type.py
@@ -1,26 +1,31 @@
from types import NoneType
from typing import Any
-from ._iter import CanBeList, CruList
-
DEFAULT_NONE_ERR = ValueError
DEFAULT_NONE_ERR_MSG = "None is not allowed here."
DEFAULT_TYPE_ERR = ValueError
DEFAULT_TYPE_ERR_MSG = "Type of object is not allowed here."
-class TypeSet(set[type]):
- def __init__(self, *l: type):
+class TypeSet:
+ def __init__(self, *types: type):
l = CruList.make(l).remove_all_value(None, NoneType)
if not l.all_is_instance(type):
raise TypeError("t must be a type or None.")
super().__init__(l)
- def check_value(self, v: Any, /, allow_none: bool, empty_allow_all: bool = True, *,
- none_err: type[Exception] = DEFAULT_NONE_ERR,
- none_err_msg: str = DEFAULT_NONE_ERR_MSG,
- type_err: type[Exception] = DEFAULT_TYPE_ERR,
- type_err_msg: str = DEFAULT_TYPE_ERR_MSG) -> None:
+ def check_value(
+ self,
+ v: Any,
+ /,
+ allow_none: bool,
+ empty_allow_all: bool = True,
+ *,
+ none_err: type[Exception] = DEFAULT_NONE_ERR,
+ none_err_msg: str = DEFAULT_NONE_ERR_MSG,
+ type_err: type[Exception] = DEFAULT_TYPE_ERR,
+ type_err_msg: str = DEFAULT_TYPE_ERR_MSG,
+ ) -> None:
if v is None:
if allow_none:
return
@@ -31,12 +36,26 @@ class TypeSet(set[type]):
if type(v) not in self:
raise type_err(type_err_msg)
- def check_value_list(self, l: CanBeList, /, allow_none: bool, empty_allow_all: bool = True, *,
- none_err: type[Exception] = DEFAULT_NONE_ERR,
- none_err_msg: str = DEFAULT_NONE_ERR_MSG,
- type_err: type[Exception] = DEFAULT_TYPE_ERR,
- type_err_msg: str = DEFAULT_TYPE_ERR_MSG) -> None:
+ def check_value_list(
+ self,
+ l: CanBeList,
+ /,
+ allow_none: bool,
+ empty_allow_all: bool = True,
+ *,
+ none_err: type[Exception] = DEFAULT_NONE_ERR,
+ none_err_msg: str = DEFAULT_NONE_ERR_MSG,
+ type_err: type[Exception] = DEFAULT_TYPE_ERR,
+ type_err_msg: str = DEFAULT_TYPE_ERR_MSG,
+ ) -> None:
l = CruList.make(l)
for v in l:
- self.check_value(v, allow_none, empty_allow_all, none_err=none_err, none_err_msg=none_err_msg,
- type_err=type_err, type_err_msg=type_err_msg)
+ self.check_value(
+ v,
+ allow_none,
+ empty_allow_all,
+ none_err=none_err,
+ none_err_msg=none_err_msg,
+ type_err=type_err,
+ type_err_msg=type_err_msg,
+ )