diff options
Diffstat (limited to 'tools/cru-py/cru')
| -rw-r--r-- | tools/cru-py/cru/__init__.py | 1 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/__init__.py | 63 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_const.py | 49 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_cru.py (renamed from tools/cru-py/cru/util/_cru.py) | 22 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_event.py (renamed from tools/cru-py/cru/util/_event.py) | 0 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_func.py | 259 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_lang.py | 16 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_list.py (renamed from tools/cru-py/cru/util/_list.py) | 511 | ||||
| -rw-r--r-- | tools/cru-py/cru/_util/_type.py (renamed from tools/cru-py/cru/util/_type.py) | 0 | ||||
| -rw-r--r-- | tools/cru-py/cru/attr.py | 2 | ||||
| -rw-r--r-- | tools/cru-py/cru/excp.py | 2 | ||||
| -rw-r--r-- | tools/cru-py/cru/service/docker.py | 2 | ||||
| -rw-r--r-- | tools/cru-py/cru/util/__init__.py | 25 | ||||
| -rw-r--r-- | tools/cru-py/cru/util/_const.py | 56 | ||||
| -rw-r--r-- | tools/cru-py/cru/util/_func.py | 126 | 
15 files changed, 731 insertions, 403 deletions
diff --git a/tools/cru-py/cru/__init__.py b/tools/cru-py/cru/__init__.py index e36a778..2ae241e 100644 --- a/tools/cru-py/cru/__init__.py +++ b/tools/cru-py/cru/__init__.py @@ -4,6 +4,7 @@ import sys  class CruInitError(Exception):      pass +  def check_python_version(required_version=(3, 11)):      if sys.version_info < required_version:          raise CruInitError(f"Python version must be >= {required_version}!") diff --git a/tools/cru-py/cru/_util/__init__.py b/tools/cru-py/cru/_util/__init__.py new file mode 100644 index 0000000..481502c --- /dev/null +++ b/tools/cru-py/cru/_util/__init__.py @@ -0,0 +1,63 @@ +from ._const import ( +    CruNotFound, +    CruUseDefault, +    CruDontChange, +    CruNoValue, +    CruPlaceholder, +) +from ._func import ( +    CruFunction, +    CruFunctionMeta, +    CruRawFunctions, +    CruWrappedFunctions, +    CruFunctionGenerators, +) +from ._list import ( +    CruList, +    CruInplaceList, +    CruUniqueKeyInplaceList, +    ListOperations, +    CanBeList, +    ElementOperation, +    ElementPredicate, +    ElementTransformer, +    OptionalElementOperation, +    ElementPredicate, +    OptionalElementTransformer, +) +from ._type import TypeSet + +F = CruFunction +WF = CruWrappedFunctions +FG = CruFunctionGenerators +L = CruList + + +__all__ = [ +    "CruNotFound", +    "CruUseDefault", +    "CruDontChange", +    "CruNoValue", +    "CruPlaceholder", +    "CruFunction", +    "CruFunctionMeta", +    "CruRawFunctions", +    "CruWrappedFunctions", +    "CruFunctionGenerators", +    "CruList", +    "CruInplaceList", +    "CruUniqueKeyInplaceList", +    "ListOperations", +    "CanBeList", +    "ElementOperation", +    "ElementPredicate", +    "ElementTransformer", +    "OptionalElementOperation", +    "ElementPredicate", +    "OptionalElementTransformer", +    "TypeSet", +    "F", +    "WF", +    "FG", +    "L", +] diff --git a/tools/cru-py/cru/_util/_const.py b/tools/cru-py/cru/_util/_const.py new file mode 100644 index 0000000..bc02c3a --- /dev/null +++ b/tools/cru-py/cru/_util/_const.py @@ -0,0 +1,49 @@ +from enum import Enum, auto +from typing import Self, TypeGuard, TypeVar + +from ._cru import CRU + +_T = TypeVar("_T") + + +class CruConstantBase(Enum): +    @classmethod +    def check(cls, v: _T | Self) -> TypeGuard[Self]: +        return isinstance(v, cls) + +    @classmethod +    def check_not(cls, v: _T | Self) -> TypeGuard[_T]: +        return not cls.check(v) + +    @classmethod +    def value(cls) -> Self: +        return cls.VALUE  # type: ignore + + +class CruNotFound(CruConstantBase): +    VALUE = auto() + + +class CruUseDefault(CruConstantBase): +    VALUE = auto() + + +class CruDontChange(CruConstantBase): +    VALUE = auto() + + +class CruNoValue(CruConstantBase): +    VALUE = auto() + + +class CruPlaceholder(CruConstantBase): +    VALUE = auto() + + +CRU.add_objects( +    CruNotFound, +    CruUseDefault, +    CruDontChange, +    CruNoValue, +    CruPlaceholder, +) diff --git a/tools/cru-py/cru/util/_cru.py b/tools/cru-py/cru/_util/_cru.py index 61a0ee1..0085a80 100644 --- a/tools/cru-py/cru/util/_cru.py +++ b/tools/cru-py/cru/_util/_cru.py @@ -1,10 +1,12 @@  from typing import Any +from ._lang import remove_none +  class _Cru:      NAME_PREFIXES = ("CRU_", "Cru", "cru_") -    def __init__(self): +    def __init__(self) -> None:          self._d: dict[str, Any] = {}      def all_names(self) -> list[str]: @@ -20,12 +22,13 @@ class _Cru:      def _maybe_remove_prefix(name: str) -> str | None:          for prefix in _Cru.NAME_PREFIXES:              if name.startswith(prefix): -                return name[len(prefix):] +                return name[len(prefix) :]          return None -    def _check_name_exist(self, *names: str) -> None: +    def _check_name_exist(self, *names: str | None) -> None:          for name in names: -            if name is None: continue +            if name is None: +                continue              if self.has_name(name):                  raise ValueError(f"Name {name} exists in CRU.") @@ -41,13 +44,13 @@ class _Cru:          return _Cru.check_name_format(o.__name__)      def _do_add(self, o, *names: str | None) -> list[str]: -        names = set(names) -        names.remove(None) -        for name in names: +        name_list: list[str] = remove_none(names) +        for name in name_list:              self._d[name] = o -        return list(names) +        return name_list      def add(self, o, name: str | None) -> tuple[str, str | None]: +        no_prefix_name: str | None          if name is None:              name, no_prefix_name = self._check_object_name(o)          else: @@ -58,7 +61,8 @@ class _Cru:          return name, no_prefix_name      def add_with_alias(self, o, name: str | None = None, *aliases: str) -> list[str]: -        final_names = [] +        final_names: list[str | None] = [] +        no_prefix_name: str | None          if name is None:              name, no_prefix_name = self._check_object_name(o)              self._check_name_exist(name, no_prefix_name) diff --git a/tools/cru-py/cru/util/_event.py b/tools/cru-py/cru/_util/_event.py index 813e33f..813e33f 100644 --- a/tools/cru-py/cru/util/_event.py +++ b/tools/cru-py/cru/_util/_event.py diff --git a/tools/cru-py/cru/_util/_func.py b/tools/cru-py/cru/_util/_func.py new file mode 100644 index 0000000..0b8b07a --- /dev/null +++ b/tools/cru-py/cru/_util/_func.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +from collections.abc import Callable +from enum import Flag, auto +from typing import ( +    Any, +    Generic, +    Iterable, +    Literal, +    ParamSpec, +    TypeAlias, +    TypeVar, +    cast, +) + +from ._cru import CRU +from ._const import CruPlaceholder + +_P = ParamSpec("_P") +_T = TypeVar("_T") + + +class CruRawFunctions: +    @staticmethod +    def none(*_v, **_kwargs) -> None: +        return None + +    @staticmethod +    def true(*_v, **_kwargs) -> Literal[True]: +        return True + +    @staticmethod +    def false(*_v, **_kwargs) -> Literal[False]: +        return False + +    @staticmethod +    def identity(v: _T) -> _T: +        return v + +    @staticmethod +    def only_you(v: _T, *_v, **_kwargs) -> _T: +        return v + +    @staticmethod +    def equal(a: Any, b: Any) -> bool: +        return a == b + +    @staticmethod +    def not_equal(a: Any, b: Any) -> bool: +        return a != b + +    @staticmethod +    def not_(v: Any) -> Any: +        return not v + + +CruArgsChainableCallable: TypeAlias = Callable[..., Iterable[Any]] +CruKwargsChainableCallable: TypeAlias = Callable[..., Iterable[tuple[str, Any]]] +CruChainableCallable: TypeAlias = Callable[ +    ..., tuple[Iterable[Any], Iterable[tuple[str, Any]]] +] + + +class CruFunctionChainMode(Flag): +    ARGS = auto() +    KWARGS = auto() +    BOTH = ARGS | KWARGS + + +class CruFunctionMeta: +    @staticmethod +    def bind(func: Callable[..., _T], *bind_args, **bind_kwargs) -> Callable[..., _T]: +        def bound_func(*args, **kwargs): +            popped = 0 +            real_args = [] +            for arg in bind_args: +                if CruPlaceholder.check(arg): +                    real_args.append(args[popped]) +                    popped += 1 +                else: +                    real_args.append(arg) +            real_args.extend(args[popped:]) +            return func(*real_args, **(bind_kwargs | kwargs)) + +        return bound_func + +    @staticmethod +    def chain_with_args( +        funcs: Iterable[CruArgsChainableCallable], *bind_args, **bind_kwargs +    ) -> CruArgsChainableCallable: +        def chained_func(*args): +            for func in funcs: +                args = CruFunctionMeta.bind(func, *bind_args, **bind_kwargs)(*args) +            return args + +        return chained_func + +    @staticmethod +    def chain_with_kwargs( +        funcs: Iterable[CruKwargsChainableCallable], *bind_args, **bind_kwargs +    ) -> CruKwargsChainableCallable: +        def chained_func(**kwargs): +            for func in funcs: +                kwargs = CruFunctionMeta.bind(func, *bind_args, **bind_kwargs)(**kwargs) +            return kwargs + +        return chained_func + +    @staticmethod +    def chain_with_both( +        funcs: Iterable[CruChainableCallable], *bind_args, **bind_kwargs +    ) -> CruChainableCallable: +        def chained_func(*args, **kwargs): +            for func in funcs: +                args, kwargs = CruFunctionMeta.bind(func, *bind_args, **bind_kwargs)( +                    *args, **kwargs +                ) +            return args, kwargs + +        return chained_func + +    @staticmethod +    def chain( +        mode: CruFunctionChainMode, +        funcs: Iterable[ +            CruArgsChainableCallable | CruKwargsChainableCallable | CruChainableCallable +        ], +        *bind_args, +        **bind_kwargs, +    ) -> CruArgsChainableCallable | CruKwargsChainableCallable | CruChainableCallable: +        if mode == CruFunctionChainMode.ARGS: +            return CruFunctionMeta.chain_with_args( +                cast(Iterable[CruArgsChainableCallable], funcs), +                *bind_args, +                **bind_kwargs, +            ) +        elif mode == CruFunctionChainMode.KWARGS: +            return CruFunctionMeta.chain_with_kwargs( +                cast(Iterable[CruKwargsChainableCallable], funcs), +                *bind_args, +                **bind_kwargs, +            ) +        elif mode == CruFunctionChainMode.BOTH: +            return CruFunctionMeta.chain_with_both( +                cast(Iterable[CruChainableCallable], funcs), *bind_args, **bind_kwargs +            ) + + +# Advanced Function Wrapper +class CruFunction(Generic[_P, _T]): + +    def __init__(self, f: Callable[_P, _T]): +        self._f = f + +    @property +    def f(self) -> Callable[_P, _T]: +        return self._f + +    @property +    def func(self) -> Callable[_P, _T]: +        return self.f + +    def bind(self, *bind_args, **bind_kwargs) -> CruFunction[..., _T]: +        self._f = CruFunctionMeta.bind(self._f, *bind_args, **bind_kwargs) +        return self + +    def _iter_with_self( +        self, funcs: Iterable[Callable[..., Any]] +    ) -> Iterable[Callable[..., Any]]: +        yield self +        yield from funcs + +    @staticmethod +    def chain_with_args( +        self, +        funcs: Iterable[CruArgsChainableCallable], +        *bind_args, +        **bind_kwargs, +    ) -> CruArgsChainableCallable: +        return CruFunction( +            CruFunctionMeta.chain_with_args( +                self._iter_with_self(funcs), *bind_args, **bind_kwargs +            ) +        ) + +    def chain_with_kwargs( +        self, funcs: Iterable[CruKwargsChainableCallable], *bind_args, **bind_kwargs +    ) -> CruKwargsChainableCallable: +        return CruFunction( +            CruFunctionMeta.chain_with_kwargs( +                self._iter_with_self(funcs), *bind_args, **bind_kwargs +            ) +        ) + +    def chain_with_both( +        self, funcs: Iterable[CruChainableCallable], *bind_args, **bind_kwargs +    ) -> CruChainableCallable: +        return CruFunction( +            CruFunctionMeta.chain_with_both( +                self._iter_with_self(funcs), *bind_args, **bind_kwargs +            ) +        ) + +    def chain( +        self, +        mode: CruFunctionChainMode, +        funcs: Iterable[ +            CruArgsChainableCallable | CruKwargsChainableCallable | CruChainableCallable +        ], +        *bind_args, +        **bind_kwargs, +    ) -> CruArgsChainableCallable | CruKwargsChainableCallable | CruChainableCallable: +        return CruFunction( +            CruFunctionMeta.chain( +                mode, self._iter_with_self(funcs), *bind_args, **bind_kwargs +            ) +        ) + +    def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _T: +        return self._f(*args, **kwargs) + +    @staticmethod +    def make_chain( +        mode: CruFunctionChainMode, +        funcs: Iterable[ +            CruArgsChainableCallable | CruKwargsChainableCallable | CruChainableCallable +        ], +        *bind_args, +        **bind_kwargs, +    ) -> CruFunction: +        return CruFunction( +            CruFunctionMeta.chain(mode, funcs, *bind_args, **bind_kwargs) +        ) + + +class CruWrappedFunctions: +    none = CruFunction(CruRawFunctions.none) +    true = CruFunction(CruRawFunctions.true) +    false = CruFunction(CruRawFunctions.false) +    identity = CruFunction(CruRawFunctions.identity) +    only_you = CruFunction(CruRawFunctions.only_you) +    equal = CruFunction(CruRawFunctions.equal) +    not_equal = CruFunction(CruRawFunctions.not_equal) +    not_ = CruFunction(CruRawFunctions.not_) + + +class CruFunctionGenerators: +    @staticmethod +    def make_isinstance_of_types(*types: type) -> Callable: +        return CruFunction(lambda v: type(v) in types) + + +CRU.add_objects( +    CruRawFunctions, +    CruFunctionMeta, +    CruFunction, +    CruWrappedFunctions, +    CruFunctionGenerators, +) diff --git a/tools/cru-py/cru/_util/_lang.py b/tools/cru-py/cru/_util/_lang.py new file mode 100644 index 0000000..925ba00 --- /dev/null +++ b/tools/cru-py/cru/_util/_lang.py @@ -0,0 +1,16 @@ +from collections.abc import Callable +from typing import Any, Iterable, TypeVar, cast + +T = TypeVar("T") +D = TypeVar("D") + + +def remove_element( +    iterable: Iterable[T | None], to_rm: Iterable[Any], des: type[D] | None = None +) -> D: +    to_rm = set(to_rm) +    return cast(Callable[..., D], des or list)(v for v in iterable if v not in to_rm) + + +def remove_none(iterable: Iterable[T | None], des: type[D] | None = None) -> D: +    return cast(Callable[..., D], des or list)(v for v in iterable if v is not None) diff --git a/tools/cru-py/cru/util/_list.py b/tools/cru-py/cru/_util/_list.py index e1c8373..711d5f1 100644 --- a/tools/cru-py/cru/util/_list.py +++ b/tools/cru-py/cru/_util/_list.py @@ -1,85 +1,235 @@ +from __future__ import annotations +  from collections.abc import Iterable, Callable  from dataclasses import dataclass  from enum import Enum -from typing import TypeVar, ParamSpec, Any, Generic, ClassVar, Optional, Union - -from ._const import CRU_NOT_FOUND - +from typing import ( +    Generator, +    Literal, +    Self, +    TypeAlias, +    TypeVar, +    ParamSpec, +    Any, +    Generic, +    ClassVar, +    Optional, +    Union, +    assert_never, +    cast, +    overload, +    override, +) + +from ._const import CruNoValue, CruNotFound + +P = ParamSpec("P")  T = TypeVar("T")  O = TypeVar("O") -R = TypeVar("R")  F = TypeVar("F") -CanBeList = T | Iterable[T] | None +CanBeList: TypeAlias = Iterable[T] | T | None -OptionalIndex = int | None -OptionalType = type | None -ElementOperation = Callable[[T], Any] | None -ElementPredicate = Callable[[T], bool] -ElementTransformer = Callable[[T], R] -SelfElementTransformer = ElementTransformer[T, T] -AnyElementTransformer = ElementTransformer[Any, Any] -OptionalElementOperation = ElementOperation | None -OptionalElementTransformer = ElementTransformer | None -OptionalSelfElementTransformer = ElementTransformer[T, T] -OptionalAnyElementTransformer = AnyElementTransformer | None +OptionalIndex: TypeAlias = int | None +OptionalType: TypeAlias = type | None +ElementOperation: TypeAlias = Callable[[T], Any] +ElementPredicate: TypeAlias = Callable[[T], bool] +ElementTransformer: TypeAlias = Callable[[T], O] +SelfElementTransformer: TypeAlias = ElementTransformer[T, T] +AnyElementTransformer: TypeAlias = ElementTransformer[Any, Any] -def _flatten_with_func(o: T, max_depth: int, is_leave: ElementPredicate[T], -                       get_children: SelfElementTransformer[T], depth: int = 0) -> Iterable[T]: +def flatten_with_func( +    o: T, +    max_depth: int, +    is_leave: ElementPredicate[T], +    get_children: ElementTransformer[T, Iterable[T]], +    depth: int = 0, +) -> Iterable[T]:      if depth == max_depth or is_leave(o):          yield o          return      for child in get_children(o): -        yield from _flatten_with_func(child, max_depth, is_leave, get_children, depth + 1) +        yield from flatten_with_func( +            child, max_depth, is_leave, get_children, depth + 1 +        ) -class _Action(Enum): +class _StepActionKind(Enum):      SKIP = 0 +    # TODO: Rename this      SEND = 1      STOP = 2      AGGREGATE = 3  @dataclass -class _Result(Generic[T]): -    Action: ClassVar[type[_Action]] = _Action +class _StepAction(Generic[T]): +    value: Iterable[_StepAction[T]] | T | None +    kind: _StepActionKind + +    @property +    def non_aggregate_value(self) -> T: +        assert self.kind != _StepActionKind.AGGREGATE +        return cast(T, self.value) + +    @staticmethod +    def skip() -> _StepAction[T]: +        return _StepAction(None, _StepActionKind.SKIP) -    value: T | O | None -    action: Action +    @staticmethod +    def send(value: T | None) -> _StepAction[T]: +        return _StepAction(value, _StepActionKind.SEND)      @staticmethod -    def skip() -> "_Result"[T]: -        return _Result(None, _Action.SKIP) +    def stop(value: T | None = None) -> _StepAction[T]: +        return _StepAction(value, _StepActionKind.STOP) + +    @staticmethod +    def aggregate(*results: _StepAction[T]) -> _StepAction[T]: +        return _StepAction(results, _StepActionKind.AGGREGATE) + +    @staticmethod +    def send_last(value: Any) -> _StepAction[T]: +        return _StepAction.aggregate(_StepAction.send(value), _StepAction.stop()) + +    def flatten(self) -> Iterable[_StepAction[T]]: +        return flatten_with_func( +            self, +            -1, +            lambda r: r.kind != _StepActionKind.AGGREGATE, +            lambda r: cast(Iterable[_StepAction[T]], r.value), +        ) + + +_r_skip = _StepAction.skip +_r_send = _StepAction.send +_r_stop = _StepAction.stop +_r_send_last = _StepAction.send_last +_r_aggregate = _StepAction.aggregate + + +_GeneralStepAction: TypeAlias = _StepAction[T] | T | None +_GeneralStepActionConverter: TypeAlias = Callable[ +    [_GeneralStepAction[T]], _StepAction[T] +] +_IterateOperation = Callable[[T, int], _GeneralStepAction[O]] +_IteratePreHook = Callable[[Iterable[T]], _GeneralStepAction[O]] +_IteratePostHook = Callable[[int], _GeneralStepAction[O]] + + +class CruGenericIterableMeta: +    StepActionKind = _StepActionKind +    StepAction = _StepAction +    GeneralStepAction = _GeneralStepAction +    GeneralStepActionConverter = _GeneralStepActionConverter +    IterateOperation = _IterateOperation +    IteratePreHook = _IteratePreHook +    IteratePostHook = _IteratePostHook      @staticmethod -    def send(value: Any) -> "_Result"[T]: -        return _Result(value, _Action.SEND) +    def _non_result_to_send(value: O | None) -> _StepAction[O]: +        return _StepAction.send(value)      @staticmethod -    def stop(value: Any = None) -> "_Result"[T]: -        return _Result(value, _Action.STOP) +    def _non_result_to_stop(value: O | None) -> _StepAction[O]: +        return _StepAction.stop(value)      @staticmethod -    def aggregate(*result: "_Result"[T]) -> "_Result"[T]: -        return _Result(result, _Action.AGGREGATE) +    def _none_pre_iterate() -> _StepAction[O]: +        return _r_skip()      @staticmethod -    def send_last(value: Any) -> "_Result"[T]: -        return _Result.aggregate(_Result.send(value), _Result.stop()) +    def _none_post_iterate( +        _index: int, +    ) -> _StepAction[O]: +        return _r_skip() -    def flatten(self) -> Iterable["_Result"[T]]: -        return _flatten_with_func(self, -1, lambda r: r.action != _Action.AGGREGATE, lambda r: r.value) +    def iterate( +        self, +        operation: _IterateOperation[T, O], +        fallback_return: O, +        pre_iterate: _IteratePreHook[T, O], +        post_iterate: _IteratePostHook[O], +        convert_non_result: Callable[[O | None], _StepAction[O]], +    ) -> Generator[O, None, O]: +        pre_result = pre_iterate(self._iterable) +        if not isinstance(pre_result, _StepAction): +            real_pre_result = convert_non_result(pre_result) +        for r in real_pre_result.flatten(): +            if r.kind == _StepActionKind.STOP: +                return r.non_aggregate_value +            elif r.kind == _StepActionKind.SEND: +                yield r.non_aggregate_value +        for index, element in enumerate(self._iterable): +            result = operation(element, index) +            if not isinstance(result, _StepAction): +                real_result = convert_non_result(result) +            for r in real_result.flatten(): +                if r.kind == _StepActionKind.STOP: +                    return r.non_aggregate_value +                elif r.kind == _StepActionKind.SEND: +                    yield r.non_aggregate_value +                else: +                    continue -_r_skip = _Result.skip -_r_send = _Result.send -_r_stop = _Result.stop -_r_send_last = _Result.send_last -_r_aggregate = _Result.aggregate +        post_result = post_iterate(index + 1) +        if not isinstance(post_result, _StepAction): +            real_post_result = convert_non_result(post_result) +        for r in real_post_result.flatten(): +            if r.kind == _StepActionKind.STOP: +                return r.non_aggregate_value +            elif r.kind == _StepActionKind.SEND: +                yield r.non_aggregate_value + +        return fallback_return + +    def _new( +        self, +        operation: _IterateOperation, +        fallback_return: O, +        /, +        pre_iterate: _IteratePreHook[T, O] | None = None, +        post_iterate: _IteratePostHook[O] | None = None, +    ) -> CruIterableWrapper: +        return CruIterableWrapper( +            self.iterate( +                operation, +                fallback_return, +                pre_iterate or CruIterableWrapper._none_pre_iterate, +                post_iterate or CruIterableWrapper._none_post_iterate, +                CruIterableWrapper._non_result_to_send, +            ), +            self._create_new_upstream(), +        ) + +    def _result( +        self, +        operation: _IterateOperation, +        fallback_return: O, +        /, +        result_transform: SelfElementTransformer[O] | None = None, +        pre_iterate: _IteratePreHook[T, O] | None = None, +        post_iterate: _IteratePostHook[O] | None = None, +    ) -> O: +        try: +            for _ in self.iterate( +                operation, +                fallback_return, +                pre_iterate or CruIterableWrapper._none_pre_iterate, +                post_iterate or CruIterableWrapper._none_post_iterate, +                CruIterableWrapper._non_result_to_stop, +            ): +                pass +        except StopIteration as stop: +            return ( +                stop.value if result_transform is None else result_transform(stop.value) +            ) +        raise RuntimeError("Should not reach here") -class _Defaults: +class IterDefaultResults:      @staticmethod      def true(_):          return True @@ -90,35 +240,30 @@ class _Defaults:      @staticmethod      def not_found(_): -        return CRU_NOT_FOUND - - -def _default_upstream() -> Iterable[Iterable]: -    return iter([]) - - -CruIterableUpstream = Iterable[Iterable] -CruIterableOptionalUpstream = CruIterableUpstream | None +        return CruNotFound.VALUE  class CruIterableCreators:      @staticmethod -    def with_(o: Any, /, upstreams: CruIterableOptionalUpstream = _default_upstream()) -> "CruIterableWrapper": -        return CruIterableWrapper(iter(o), upstreams) +    def with_(o: Any) -> CruIterableWrapper: +        return CruIterableWrapper(iter(o))      @staticmethod -    def empty(upstreams: CruIterableOptionalUpstream = _default_upstream()) -> "CruIterableWrapper": -        return CruIterableCreators.with_([], upstreams) +    def empty() -> CruIterableWrapper: +        return CruIterableCreators.with_([])      @staticmethod -    def range(a, b=None, c=None, /, upstreams: CruIterableOptionalUpstream = _default_upstream()) -> \ -    "CruIterableWrapper"[int]: +    def range( +        a, +        b=None, +        c=None, +    ) -> CruIterableWrapper[int]:          args = [arg for arg in [a, b, c] if arg is not None] -        return CruIterableCreators.with_(range(*args), upstreams) +        return CruIterableCreators.with_(range(*args))      @staticmethod -    def unite(*args: T, upstreams: CruIterableOptionalUpstream = _default_upstream()) -> "CruIterableWrapper"[T]: -        return CruIterableCreators.with_(args, upstreams) +    def unite(*args: T) -> CruIterableWrapper[T]: +        return CruIterableCreators.with_(args)      @staticmethod      def _concat(*iterables: Iterable) -> Iterable: @@ -126,138 +271,95 @@ class CruIterableCreators:              yield from iterable      @staticmethod -    def concat(*iterables: Iterable, -               upstreams: CruIterableOptionalUpstream = _default_upstream()) -> "CruIterableWrapper": -        return CruIterableWrapper(CruIterableCreators._concat(*iterables), upstreams) +    def concat(*iterables: Iterable) -> CruIterableWrapper: +        return CruIterableWrapper(CruIterableCreators._concat(*iterables))  class CruIterableWrapper(Generic[T]): -    Upstream = CruIterableUpstream -    OptionalUpstream = CruIterableOptionalUpstream -    _Result = _Result[T] -    _Operation = Callable[[T, int], _Result | Any | None] -    def __init__(self, iterable: Iterable[T], /, upstreams: OptionalUpstream = _default_upstream()) -> None: +    def __init__( +        self, +        iterable: Iterable[T], +    ) -> None:          self._iterable = iterable -        self._upstreams = None if upstreams is None else list(upstreams) + +    def __iter__(self): +        return self._iterable.__iter__()      @property      def me(self) -> Iterable[T]:          return self._iterable -    # TODO: Return Type -    @property -    def my_upstreams(self) -> Optional["CruIterableWrapper"]: -        if self._upstreams is None: -            return None -        return CruIterableWrapper(iter(self._upstreams)) - -    def disable_my_upstreams(self) -> "CruIterableWrapper"[T]: -        return CruIterableWrapper(self._iterable, None) - -    def clear_my_upstreams(self) -> "CruIterableWrapper"[T]: -        return CruIterableWrapper(self._iterable) - -    def _create_upstreams_prepend_self(self) -> Upstream: -        yield self._iterable -        yield self.my_upstreams - -    # TODO: Return Type -    def _create_new_upstreams(self, append: bool = True) -> Optional["CruIterableWrapper"]: -        if not append: return self.my_upstreams -        if self.my_upstreams is None: -            return None -        return CruIterableWrapper(self._create_upstreams_prepend_self()) - -    def clone_me(self, /, update_upstreams: bool = True) -> "CruIterableWrapper"[T]: -        return CruIterableWrapper(self._iterable, self._create_new_upstreams(update_upstreams)) - -    def replace_me_with(self, iterable: Iterable[O], /, update_upstreams: bool = True) -> "CruIterableWrapper"[O]: -        return CruIterableCreators.with_(iterable, upstreams=self._create_new_upstreams(update_upstreams)) - -    def replace_me_with_empty(self, /, update_upstreams: bool = True) -> "CruIterableWrapper"[O]: -        return CruIterableCreators.empty(upstreams=self._create_new_upstreams(update_upstreams)) - -    def replace_me_with_range(self, a, b=None, c=None, /, update_upstreams: bool = True) -> "CruIterableWrapper"[int]: -        return CruIterableCreators.range(a, b, c, upstreams=self._create_new_upstreams(update_upstreams)) - -    def replace_me_with_unite(self, *args: O, update_upstreams: bool = True) -> "CruIterableWrapper"[O]: -        return CruIterableCreators.unite(*args, upstreams=self._create_new_upstreams(update_upstreams)) - -    def replace_me_with_concat(self, *iterables: Iterable, update_upstreams: bool = True) -> "CruIterableWrapper": -        return CruIterableCreators.concat(*iterables, upstreams=self._create_new_upstreams(update_upstreams)) - -    @staticmethod -    def _non_result_to_yield(value: Any | None) -> _Result: -        return _Result.stop(value) - -    @staticmethod -    def _non_result_to_return(value: Any | None) -> _Result: -        return _Result.stop(value) +    def replace_me_with(self, iterable: Iterable[O]) -> CruIterableWrapper[O]: +        return CruIterableCreators.with_(iterable) -    def _real_iterate(self, operation: _Operation, -                      convert_non_result: Callable[[Any | None], _Result]) -> Iterable: +    def replace_me_with_empty(self) -> CruIterableWrapper[O]: +        return CruIterableCreators.empty() -        for index, element in enumerate(self._iterable): -            result = operation(element, index) -            if not isinstance(result, _Result): -                result = convert_non_result(result) -            for result in result.flatten(): -                if result.action == _Result.Action.STOP: -                    return result.value -                elif result.action == _Result.Action.SEND: -                    yield result.value -                else: -                    continue +    def replace_me_with_range(self, a, b=None, c=None) -> CruIterableWrapper[int]: +        return CruIterableCreators.range(a, b, c) -    def _new(self, operation: _Operation) -> "CruIterableWrapper": -        return CruIterableWrapper(self._real_iterate(operation, CruIterableWrapper._non_result_to_yield), -                                  self._create_new_upstreams()) +    def replace_me_with_unite(self, *args: O) -> CruIterableWrapper[O]: +        return CruIterableCreators.unite(*args) -    def _result(self, operation: _Operation, -                result_transform: OptionalElementTransformer[T, T | O] = None) -> T | O: -        try: -            self._real_iterate(operation, CruIterableWrapper._non_result_to_return) -        except StopIteration as stop: -            return stop.value if result_transform is None else result_transform(stop.value) +    def replace_me_with_concat(self, *iterables: Iterable) -> CruIterableWrapper: +        return CruIterableCreators.concat(*iterables)      @staticmethod -    def _make_set(iterable: Iterable, discard: Iterable | None) -> set: +    def _make_set(iterable: Iterable[O], discard: Iterable[Any] | None) -> set[O]:          s = set(iterable)          if discard is not None:              s = s - set(discard)          return s      @staticmethod -    def _make_list(iterable: Iterable, discard: Iterable | None) -> list: -        if discard is None: return list(iterable) +    def _make_list(iterable: Iterable[O], discard: Iterable[Any] | None) -> list[O]: +        if discard is None: +            return list(iterable)          return [v for v in iterable if v not in discard] -    # noinspection PyMethodMayBeStatic -    def _help_make_set(self, iterable: Iterable, discard: Iterable | None = iter([None])) -> set: +    def _help_make_set( +        self, iterable: Iterable[O], discard: Iterable[Any] | None +    ) -> set[O]:          return CruIterableWrapper._make_set(iterable, discard) -    # noinspection PyMethodMayBeStatic -    def _help_make_list(self, iterable: Iterable, discard: Iterable | None = iter([None])) -> list: +    def _help_make_list( +        self, iterable: Iterable[O], discard: Iterable[Any] | None +    ) -> list[O]:          return CruIterableWrapper._make_list(iterable, discard) -    def to_set(self, discard: Iterable | None = None) -> set[T]: +    def to_set(self, discard: Iterable[Any] | None = None) -> set[T]:          return CruIterableWrapper._make_set(self.me, discard) -    def to_list(self, discard: Iterable | None = None) -> list[T]: +    def to_list(self, discard: Iterable[Any] | None = None) -> list[T]:          return CruIterableWrapper._make_list(self.me, discard) -    def copy(self) -> "CruIterableWrapper": -        return CruIterableWrapper(iter(self.to_list()), self._create_new_upstreams()) +    def copy(self) -> CruIterableWrapper: +        return CruIterableWrapper(iter(self.to_list()), self._create_new_upstream()) -    def concat(self, *iterable: Iterable[T]) -> "CruIterableWrapper": -        return self.replace_me_with_concat(self.me, *iterable) +    def new_start( +        self, other: Iterable[O], /, clear_upstream: bool = False +    ) -> CruIterableWrapper[O]: +        return CruIterableWrapper( +            other, None if clear_upstream else self._create_new_upstream() +        ) + +    @overload +    def concat(self) -> Self: ... + +    @overload +    def concat( +        self, *iterable: Iterable[Any], last: Iterable[O] +    ) -> CruIterableWrapper[O]: ... + +    def concat(self, *iterable: Iterable[Any]) -> CruIterableWrapper[Any]:  # type: ignore +        return self.new_start(CruIterableCreators.concat(self.me, *iterable))      def all(self, predicate: ElementPredicate[T]) -> bool:          """          partial          """ -        return self._result(lambda v, _: predicate(v) and None, _Defaults.true) +        return self._result(lambda v, _: predicate(v) and None, IterDefaultResults.true)      def all_isinstance(self, *types: OptionalType) -> bool:          """ @@ -270,21 +372,23 @@ class CruIterableWrapper(Generic[T]):          """          partial          """ -        return self._result(lambda v, _: predicate(v) or None, _Defaults.false) +        return self._result(lambda v, _: predicate(v) or None, IterDefaultResults.false) -    def number(self) -> "CruIterableWrapper": +    def number(self) -> CruIterableWrapper:          """          partial          """          return self._new(lambda _, i: i) -    def take(self, predicate: ElementPredicate[T]) -> "CruIterableWrapper": +    def take(self, predicate: ElementPredicate[T]) -> CruIterableWrapper:          """          complete          """          return self._new(lambda v, _: _r_send(v) if predicate(v) else None) -    def transform(self, *transformers: OptionalElementTransformer) -> "CruIterableWrapper": +    def transform( +        self, *transformers: OptionalElementTransformer +    ) -> CruIterableWrapper:          """          complete          """ @@ -297,7 +401,7 @@ class CruIterableWrapper(Generic[T]):          return self._new(_transform_element) -    def take_n(self, max_count: int, neg_is_clone: bool = True) -> "CruIterableWrapper": +    def take_n(self, max_count: int, neg_is_clone: bool = True) -> CruIterableWrapper:          """          partial          """ @@ -308,17 +412,23 @@ class CruIterableWrapper(Generic[T]):                  raise ValueError("max_count must be 0 or positive.")          elif max_count == 0:              return self.drop_all() -        return self._new(lambda v, i: _r_send(v) if i < max_count - 1 else _r_send_last(v)) +        return self._new( +            lambda v, i: _r_send(v) if i < max_count - 1 else _r_send_last(v) +        ) -    def take_by_indices(self, *indices: OptionalIndex) -> "CruIterableWrapper": +    def take_by_indices(self, *indices: OptionalIndex) -> CruIterableWrapper:          """          partial          """          indices = self._help_make_set(indices)          max_index = max(indices) -        return self.take_n(max_index + 1)._new(lambda v, i: _r_send(v) if i in indices else None) +        return self.take_n(max_index + 1)._new( +            lambda v, i: _r_send(v) if i in indices else None +        ) -    def single_or(self, fallback: Any | None = CRU_NOT_FOUND) -> T | Any | CRU_NOT_FOUND: +    def single_or( +        self, fallback: Any | None = CRU_NOT_FOUND +    ) -> T | Any | CRU_NOT_FOUND:          """          partial          """ @@ -335,14 +445,18 @@ class CruIterableWrapper(Generic[T]):          else:              return fallback -    def first_or(self, predicate: ElementPredicate[T], fallback: Any | None = CRU_NOT_FOUND) -> T | CRU_NOT_FOUND: +    def first_or( +        self, predicate: ElementPredicate[T], fallback: Any | None = CRU_NOT_FOUND +    ) -> T | CRU_NOT_FOUND:          """          partial          """          result_iterable = self.take_n(1).single_or()      @staticmethod -    def first_index(iterable: Iterable[T], predicate: ElementPredicate[T]) -> int | CRU_NOT_FOUND: +    def first_index( +        iterable: Iterable[T], predicate: ElementPredicate[T] +    ) -> int | CRU_NOT_FOUND:          """          partial          """ @@ -351,7 +465,9 @@ class CruIterableWrapper(Generic[T]):                  return index      @staticmethod -    def take_indices(iterable: Iterable[T], predicate: ElementPredicate[T]) -> Iterable[int]: +    def take_indices( +        iterable: Iterable[T], predicate: ElementPredicate[T] +    ) -> Iterable[int]:          """          complete          """ @@ -360,8 +476,12 @@ class CruIterableWrapper(Generic[T]):                  yield index      @staticmethod -    def flatten(o, max_depth=-1, is_leave: ElementPredicate | None = None, -                get_children: OptionalElementTransformer = None) -> Iterable: +    def flatten( +        o, +        max_depth=-1, +        is_leave: ElementPredicate | None = None, +        get_children: OptionalElementTransformer = None, +    ) -> Iterable:          """          complete          """ @@ -369,7 +489,9 @@ class CruIterableWrapper(Generic[T]):              is_leave = lambda v: not isinstance(v, Iterable)          if get_children is None:              get_children = lambda v: v -        return CruIterableWrapper._flatten_with_func(o, max_depth, is_leave, get_children) +        return CruIterableWrapper._flatten_with_func( +            o, max_depth, is_leave, get_children +        )      @staticmethod      def skip_by_indices(iterable: Iterable[T], *indices: OptionalIndex) -> Iterable[T]: @@ -390,7 +512,7 @@ class CruIterableWrapper(Generic[T]):              if not predicate(element):                  yield element -    def drop_all(self) -> "CruIterableWrapper": +    def drop_all(self) -> CruIterableWrapper:          return self.replace_me_with_empty()      @staticmethod @@ -407,7 +529,8 @@ class CruIterableWrapper(Generic[T]):      @staticmethod      def foreach(iterable: Iterable[T], *f: OptionalElementOperation[T]) -> None: -        if len(f) == 0: return +        if len(f) == 0: +            return          for v in iterable:              for f_ in f:                  if f_ is not None: @@ -415,7 +538,8 @@ class CruIterableWrapper(Generic[T]):      @staticmethod      def make(v: CanBeList[T], /, none_to_empty_list: bool = True) -> list[T]: -        if v is None and none_to_empty_list: return [] +        if v is None and none_to_empty_list: +            return []          return list(v) if isinstance(v, Iterable) else [v] @@ -457,7 +581,9 @@ class ListOperations:          return _God.new(iterable, lambda v, _: _God.yield_(v) if predicate(v) else None)      @staticmethod -    def transform(iterable: Iterable[T], *transformers: OptionalElementTransformer) -> Iterable: +    def transform( +        iterable: Iterable[T], *transformers: OptionalElementTransformer +    ) -> Iterable:          """          complete          """ @@ -479,7 +605,9 @@ class ListOperations:              return iterable          elif n == 0:              return [] -        return range(n)._god_yield(iterable, lambda v, i: _yield(v) if i < n else _return()) +        return range(n)._god_yield( +            iterable, lambda v, i: _yield(v) if i < n else _return() +        )      @staticmethod      def take_by_indices(iterable: Iterable[T], *indices: OptionalIndex) -> Iterable[T]: @@ -502,7 +630,9 @@ class ListOperations:          return CRU_NOT_FOUND      @staticmethod -    def first_index(iterable: Iterable[T], predicate: ElementPredicate[T]) -> int | CRU_NOT_FOUND: +    def first_index( +        iterable: Iterable[T], predicate: ElementPredicate[T] +    ) -> int | CRU_NOT_FOUND:          """          partial          """ @@ -511,7 +641,9 @@ class ListOperations:                  return index      @staticmethod -    def take_indices(iterable: Iterable[T], predicate: ElementPredicate[T]) -> Iterable[int]: +    def take_indices( +        iterable: Iterable[T], predicate: ElementPredicate[T] +    ) -> Iterable[int]:          """          complete          """ @@ -567,7 +699,8 @@ class ListOperations:      @staticmethod      def foreach(iterable: Iterable[T], *f: OptionalElementOperation[T]) -> None: -        if len(f) == 0: return +        if len(f) == 0: +            return          for v in iterable:              for f_ in f:                  if f_ is not None: @@ -575,7 +708,8 @@ class ListOperations:      @staticmethod      def make(v: CanBeList[T], /, none_to_empty_list: bool = True) -> list[T]: -        if v is None and none_to_empty_list: return [] +        if v is None and none_to_empty_list: +            return []          return list(v) if isinstance(v, Iterable) else [v] @@ -629,7 +763,9 @@ class CruList(list, Generic[T]):      def transform(self, *f: OptionalElementTransformer) -> "CruList"[Any]:          return CruList(ListOperations.transform(self, *f)) -    def transform_if(self, f: OptionalElementTransformer, p: ElementPredicate[T]) -> "CruList"[Any]: +    def transform_if( +        self, f: OptionalElementTransformer, p: ElementPredicate[T] +    ) -> "CruList"[Any]:          return CruList(ListOperations.transform_if(self, f, p))      def remove_by_indices(self, *index: int) -> "CruList"[T]: @@ -670,7 +806,9 @@ class CruInplaceList(CruList, Generic[T]):      def transform(self, *f: OptionalElementTransformer) -> "CruInplaceList"[Any]:          return self.reset(super().transform(*f)) -    def transform_if(self, f: OptionalElementTransformer, p: ElementPredicate[T]) -> "CruInplaceList"[Any]: +    def transform_if( +        self, f: OptionalElementTransformer, p: ElementPredicate[T] +    ) -> "CruInplaceList"[Any]:          return self.reset(super().transform_if(f, p))      def remove_by_indices(self, *index: int) -> "CruInplaceList"[T]: @@ -682,7 +820,9 @@ class CruInplaceList(CruList, Generic[T]):      def remove_all_value(self, *r: Any) -> "CruInplaceList"[T]:          return self.reset(super().remove_all_value(*r)) -    def replace_all_value(self, old_value: Any, new_value: R) -> "CruInplaceList"[T | R]: +    def replace_all_value( +        self, old_value: Any, new_value: R +    ) -> "CruInplaceList"[T | R]:          return self.reset(super().replace_all_value(old_value, new_value))      @staticmethod @@ -696,7 +836,9 @@ K = TypeVar("K")  class CruUniqueKeyInplaceList(Generic[T, K]):      KeyGetter = Callable[[T], K] -    def __init__(self, get_key: KeyGetter, *, before_add: Callable[[T], T] | None = None): +    def __init__( +        self, get_key: KeyGetter, *, before_add: Callable[[T], T] | None = None +    ):          super().__init__()          self._get_key = get_key          self._before_add = before_add @@ -733,7 +875,8 @@ class CruUniqueKeyInplaceList(Generic[T, K]):      def try_remove(self, k: K) -> bool:          i = self._l.find_index_if(lambda v: k == self._get_key(v)) -        if i is CRU_NOT_FOUND: return False +        if i is CRU_NOT_FOUND: +            return False          self._l.remove_by_indices(i)          return True diff --git a/tools/cru-py/cru/util/_type.py b/tools/cru-py/cru/_util/_type.py index dc50def..dc50def 100644 --- a/tools/cru-py/cru/util/_type.py +++ b/tools/cru-py/cru/_util/_type.py diff --git a/tools/cru-py/cru/attr.py b/tools/cru-py/cru/attr.py index 32cca8d..a52585a 100644 --- a/tools/cru-py/cru/attr.py +++ b/tools/cru-py/cru/attr.py @@ -3,7 +3,7 @@ from collections.abc import Callable, Iterable  from dataclasses import dataclass, field  from typing import Any, ClassVar -from .util import CanBeList, TypeSet, F, L, WF, CruUniqueKeyInplaceList, CRU_NOT_FOUND, CRU_USE_DEFAULT, \ +from ._util import CanBeList, TypeSet, F, L, WF, CruUniqueKeyInplaceList, CRU_NOT_FOUND, CRU_USE_DEFAULT, \      CRU_DONT_CHANGE, CRU_PLACEHOLDER diff --git a/tools/cru-py/cru/excp.py b/tools/cru-py/cru/excp.py index 358ad90..9ea204e 100644 --- a/tools/cru-py/cru/excp.py +++ b/tools/cru-py/cru/excp.py @@ -1,7 +1,7 @@  from typing import Any  from .attr import CruAttrDefRegistry, CruAttr, CruAttrTable -from .util import CRU_NOT_FOUND, CruList, CRU_USE_DEFAULT +from ._util import CRU_NOT_FOUND, CruList, CRU_USE_DEFAULT  CRU_EXCEPTION_ATTR_DEF_REGISTRY = CruAttrDefRegistry() diff --git a/tools/cru-py/cru/service/docker.py b/tools/cru-py/cru/service/docker.py index a57a246..5958f4f 100644 --- a/tools/cru-py/cru/service/docker.py +++ b/tools/cru-py/cru/service/docker.py @@ -1,7 +1,7 @@  import shutil  import subprocess -from ..util import L +from .._util import L  class DockerController: diff --git a/tools/cru-py/cru/util/__init__.py b/tools/cru-py/cru/util/__init__.py deleted file mode 100644 index ecd9673..0000000 --- a/tools/cru-py/cru/util/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Any - -from ._const import cru_make_unique_object, cru_make_bool_unique_object, CRU_NOT_FOUND, CRU_USE_DEFAULT, \ -    CRU_DONT_CHANGE, \ -    CRU_PLACEHOLDER -from ._func import CruFunction, CruFunctionMeta, CruRawFunctions, CruWrappedFunctions, CruFunctionGenerators -from ._list import CruList, CruInplaceList, CruUniqueKeyInplaceList, ListOperations, CanBeList, ElementOperation, \ -    ElementPredicate, ElementTransformer, OptionalElementOperation, ElementPredicate, OptionalElementTransformer -from ._type import TypeSet - -F = CruFunction -WF = CruWrappedFunctions -FG = CruFunctionGenerators -L = CruList - - -__all__ = [ -    "CRU_NOT_FOUND", "CRU_USE_DEFAULT", "CRU_DONT_CHANGE", "CRU_PLACEHOLDER", -    "CruFunction", "CruFunctionMeta", "CruRawFunctions", "CruWrappedFunctions", "CruFunctionGenerators", -    "CruList", "CruInplaceList", "CruUniqueKeyInplaceList", "ListOperations", -    "CanBeList", "ElementOperation", "ElementPredicate", "ElementTransformer", -    "OptionalElementOperation", "ElementPredicate", "OptionalElementTransformer", -    "TypeSet", -    "F", "WF", "FG", "L" -] diff --git a/tools/cru-py/cru/util/_const.py b/tools/cru-py/cru/util/_const.py deleted file mode 100644 index 8140988..0000000 --- a/tools/cru-py/cru/util/_const.py +++ /dev/null @@ -1,56 +0,0 @@ -from typing import Any - -from ._cru import CRU - - -def cru_make_unique_object() -> Any: -    class _CruUnique: -        _i = False - -        def __init__(self): -            if self._i: -                raise ValueError("_CruAttrNotSet is a singleton!") -            self._i = True - -        def __copy__(self): -            return self - -        def __eq__(self, other): -            return isinstance(other, _CruUnique) - -    v = _CruUnique() - -    return v - - -def cru_make_bool_unique_object(b: bool) -> Any: -    class _CruBoolUnique: -        _i = False - -        def __init__(self): -            super().__init__(b) -            if self._i: -                raise ValueError("_CruAttrNotSet is a singleton!") -            self._i = True - -        def __copy__(self): -            return self - -        def __eq__(self, other): -            return isinstance(other, _CruBoolUnique) or b == other - -        def __bool__(self): -            return b - -    v = _CruBoolUnique() - -    return v - - -CRU_NOT_FOUND = cru_make_bool_unique_object(False) -CRU_USE_DEFAULT = cru_make_unique_object() -CRU_DONT_CHANGE = cru_make_unique_object() -CRU_PLACEHOLDER = cru_make_unique_object() - -CRU.add_objects(cru_make_unique_object, cru_make_bool_unique_object, CRU_NOT_FOUND, CRU_USE_DEFAULT, -                CRU_DONT_CHANGE, CRU_PLACEHOLDER) diff --git a/tools/cru-py/cru/util/_func.py b/tools/cru-py/cru/util/_func.py deleted file mode 100644 index d9f8044..0000000 --- a/tools/cru-py/cru/util/_func.py +++ /dev/null @@ -1,126 +0,0 @@ -from collections.abc import Callable -from typing import TypeVar - -from ._cru import CRU -from ._const import CRU_PLACEHOLDER - -T = TypeVar("T") - -_PLACEHOLDER = CRU_PLACEHOLDER - -class CruRawFunctions: -    @staticmethod -    def none(*_v, **_kwargs) -> None: -        return None - -    @staticmethod -    def true(*_v, **_kwargs) -> True: -        return True - -    @staticmethod -    def false(*_v, **_kwargs) -> False: -        return False - -    @staticmethod -    def identity(v: T) -> T: -        return v - -    @staticmethod -    def only_you(v: T, *_v, **_kwargs) -> T: -        return v - -    @staticmethod -    def equal(a, b) -> bool: -        return a == b - -    @staticmethod -    def not_equal(a, b) -> bool: -        return a != b - -    @staticmethod -    def not_(v): -        return not v - - -class CruFunctionMeta: -    @staticmethod -    def bind(func: Callable, *bind_args, **bind_kwargs) -> Callable: -        def bound_func(*args, **kwargs): -            popped = 0 -            real_args = [] -            for arg in bind_args: -                if arg is _PLACEHOLDER: -                    real_args.append(args[popped]) -                    popped += 1 -                else: -                    real_args.append(arg) -            real_args.extend(args[popped:]) -            return func(*real_args, **(bind_kwargs | kwargs)) - -        return bound_func - -    @staticmethod -    def chain(*funcs: Callable) -> Callable: -        if len(funcs) == 0: -            raise ValueError("At least one function is required!") - -        final_func = funcs[0] -        for func in funcs[1:]: -            func_copy = func - -            def chained_func(*args, **kwargs): -                results = final_func(*args, **kwargs) -                results = results if isinstance(results, tuple) else (results,) -                return func_copy(*results) - -            final_func = chained_func - -        return final_func - - -# Advanced Function Wrapper -class CruFunction: -    def __init__(self, f: Callable): -        self._f = f - -    @property -    def f(self) -> Callable: -        return self._f - -    @property -    def func(self) -> Callable: -        return self.f - -    def bind(self, *bind_args, **bind_kwargs) -> "CruFunction": -        self._f = CruFunctionMeta.bind(self._f, *bind_args, **bind_kwargs) -        return self - -    def chain(self, *funcs: Callable) -> "CruFunction": -        self._f = CruFunctionMeta.chain(self._f, *funcs) -        return self - -    def __call__(self, *args, **kwargs): -        return self._f(*args, **kwargs) - -    @staticmethod -    def make_chain(base_func: Callable, *funcs: Callable) -> "CruFunction": -        return CruFunction(base_func).chain(*funcs) - - -class CruWrappedFunctions: -    none = CruFunction(CruRawFunctions.none) -    true = CruFunction(CruRawFunctions.true) -    false = CruFunction(CruRawFunctions.false) -    identity = CruFunction(CruRawFunctions.identity) -    only_you = CruFunction(CruRawFunctions.only_you) -    equal = CruFunction(CruRawFunctions.equal) -    not_equal = CruFunction(CruRawFunctions.not_equal) -    not_ = CruFunction(CruRawFunctions.not_) - - -class CruFunctionGenerators: -    @staticmethod -    def make_isinstance_of_types(*types: type) -> Callable: -        return CruFunction(lambda v: type(v) in types) - -CRU.add_objects(CruRawFunctions, CruFunctionMeta, CruFunction, CruWrappedFunctions, CruFunctionGenerators)  | 
