diff options
author | crupest <crupest@outlook.com> | 2024-11-11 01:12:29 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2024-12-18 18:31:27 +0800 |
commit | aaa855e3839130a79193f38969f07763f2773c5d (patch) | |
tree | e4cb238df4588f4633d9c1190136895865d51a98 | |
parent | 95da3ade5bfa6ef39923cd3fc2a551ad983c1537 (diff) | |
download | crupest-aaa855e3839130a79193f38969f07763f2773c5d.tar.gz crupest-aaa855e3839130a79193f38969f07763f2773c5d.tar.bz2 crupest-aaa855e3839130a79193f38969f07763f2773c5d.zip |
HALF WORK: 2024.11.27
22 files changed, 1419 insertions, 418 deletions
diff --git a/.editorconfig b/.editorconfig index edb912e..d55cc4a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,5 @@ root = true [*] end_of_line = lf +[*.py] +profile = black diff --git a/tools/cru-py/.flake8 b/tools/cru-py/.flake8 new file mode 100644 index 0000000..a77cb08 --- /dev/null +++ b/tools/cru-py/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 80 +extend-select = B950 +extend-ignore = E203,E501,E701 diff --git a/tools/cru-py/__init__.py b/tools/cru-py/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tools/cru-py/__init__.py +++ /dev/null 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) diff --git a/tools/cru-py/aio.py b/tools/cru-py/crupest/aio.py index d5386f1..0a26146 100644 --- a/tools/cru-py/aio.py +++ b/tools/cru-py/crupest/aio.py @@ -12,18 +12,18 @@ from os.path import * import argparse import subprocess from rich.prompt import Confirm -from crupest.install_docker import * -from crupest.path import * -from crupest.nginx import * -from crupest.config import * -from crupest.check import * -from crupest.backup import * -from crupest.download_tools import * -from crupest.test import * -from crupest.dns import * -from crupest.setup import * - -from crupest.tui import console +from install_docker import * +from path import * +from nginx import * +from config import * +from check import * +from backup import * +from download_tools import * +from test import * +from dns import * +from setup import * + +from tui import console parser = argparse.ArgumentParser( diff --git a/tools/cru-py/poetry.lock b/tools/cru-py/poetry.lock new file mode 100644 index 0000000..0f74ba5 --- /dev/null +++ b/tools/cru-py/poetry.lock @@ -0,0 +1,642 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
+
+[[package]]
+name = "attrs"
+version = "24.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
+ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
+tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+
+[[package]]
+name = "black"
+version = "24.10.0"
+description = "The uncompromising code formatter."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"},
+ {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"},
+ {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"},
+ {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"},
+ {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"},
+ {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"},
+ {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"},
+ {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"},
+ {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"},
+ {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"},
+ {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"},
+ {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"},
+ {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"},
+ {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"},
+ {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"},
+ {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"},
+ {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"},
+ {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"},
+ {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"},
+ {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"},
+ {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"},
+ {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"},
+]
+
+[package.dependencies]
+click = ">=8.0.0"
+mypy-extensions = ">=0.4.3"
+packaging = ">=22.0"
+pathspec = ">=0.9.0"
+platformdirs = ">=2"
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.10)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "cffi"
+version = "1.17.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
+ {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
+ {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
+ {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
+ {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
+ {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
+ {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
+ {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
+ {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
+ {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
+ {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
+ {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
+ {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
+ {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
+ {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
+ {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
+[[package]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "cryptography"
+version = "43.0.3"
+description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"},
+ {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"},
+ {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"},
+ {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"},
+ {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"},
+ {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"},
+ {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"},
+ {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"},
+ {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"},
+ {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"},
+ {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"},
+]
+
+[package.dependencies]
+cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
+docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
+nox = ["nox"]
+pep8test = ["check-sdist", "click", "mypy", "ruff"]
+sdist = ["build"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
+
+[[package]]
+name = "flake8"
+version = "7.1.1"
+description = "the modular source code checker: pep8 pyflakes and co"
+optional = false
+python-versions = ">=3.8.1"
+files = [
+ {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"},
+ {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"},
+]
+
+[package.dependencies]
+mccabe = ">=0.7.0,<0.8.0"
+pycodestyle = ">=2.12.0,<2.13.0"
+pyflakes = ">=3.2.0,<3.3.0"
+
+[[package]]
+name = "flake8-bugbear"
+version = "24.10.31"
+description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
+optional = false
+python-versions = ">=3.8.1"
+files = [
+ {file = "flake8_bugbear-24.10.31-py3-none-any.whl", hash = "sha256:cccf786ccf9b2e1052b1ecfa80fb8f80832d0880425bcbd4cd45d3c8128c2683"},
+ {file = "flake8_bugbear-24.10.31.tar.gz", hash = "sha256:435b531c72b27f8eff8d990419697956b9fd25c6463c5ba98b3991591de439db"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+flake8 = ">=6.0.0"
+
+[package.extras]
+dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"]
+
+[[package]]
+name = "isort"
+version = "5.13.2"
+description = "A Python utility / library to sort Python imports."
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
+ {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
+]
+
+[package.extras]
+colors = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "jsonschema"
+version = "4.23.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
+ {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2024.10.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"},
+ {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"},
+]
+
+[package.dependencies]
+referencing = ">=0.31.0"
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark"]
+code-style = ["pre-commit (>=3.0,<4.0)"]
+compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
+linkify = ["linkify-it-py (>=1,<3)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
+[[package]]
+name = "mccabe"
+version = "0.7.0"
+description = "McCabe checker, plugin for flake8"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
+[[package]]
+name = "mypy"
+version = "1.13.0"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"},
+ {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"},
+ {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"},
+ {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"},
+ {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"},
+ {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"},
+ {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"},
+ {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"},
+ {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"},
+ {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"},
+ {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"},
+ {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"},
+ {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"},
+ {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"},
+ {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"},
+ {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"},
+ {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"},
+ {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"},
+ {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"},
+ {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"},
+ {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"},
+ {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"},
+ {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"},
+ {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"},
+ {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"},
+ {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"},
+ {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"},
+ {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"},
+ {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"},
+ {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"},
+ {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"},
+ {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=1.0.0"
+typing-extensions = ">=4.6.0"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+faster-cache = ["orjson"]
+install-types = ["pip"]
+mypyc = ["setuptools (>=50)"]
+reports = ["lxml"]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.0.0"
+description = "Type system extensions for programs checked with the mypy type checker."
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
+ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
+]
+
+[[package]]
+name = "packaging"
+version = "24.2"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
+ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
+]
+
+[[package]]
+name = "pathspec"
+version = "0.12.1"
+description = "Utility library for gitignore style pattern matching of file paths."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
+ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.3.6"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
+ {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
+]
+
+[package.extras]
+docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
+type = ["mypy (>=1.11.2)"]
+
+[[package]]
+name = "pycodestyle"
+version = "2.12.1"
+description = "Python style guide checker"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"},
+ {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"},
+]
+
+[[package]]
+name = "pycparser"
+version = "2.22"
+description = "C parser in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
+]
+
+[[package]]
+name = "pyflakes"
+version = "3.2.0"
+description = "passive checker of Python programs"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"},
+ {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"},
+]
+
+[[package]]
+name = "pygments"
+version = "2.18.0"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
+ {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+]
+
+[package.extras]
+windows-terminal = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "referencing"
+version = "0.35.1"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"},
+ {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
+[[package]]
+name = "rich"
+version = "13.9.4"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"},
+ {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=2.2.0"
+pygments = ">=2.13.0,<3.0.0"
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<9)"]
+
+[[package]]
+name = "rpds-py"
+version = "0.21.0"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "rpds_py-0.21.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590"},
+ {file = "rpds_py-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5"},
+ {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e"},
+ {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153"},
+ {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624"},
+ {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664"},
+ {file = "rpds_py-0.21.0-cp310-none-win32.whl", hash = "sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682"},
+ {file = "rpds_py-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5"},
+ {file = "rpds_py-0.21.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95"},
+ {file = "rpds_py-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d"},
+ {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75"},
+ {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f"},
+ {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a"},
+ {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8"},
+ {file = "rpds_py-0.21.0-cp311-none-win32.whl", hash = "sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a"},
+ {file = "rpds_py-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e"},
+ {file = "rpds_py-0.21.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d"},
+ {file = "rpds_py-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf"},
+ {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4"},
+ {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca"},
+ {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b"},
+ {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11"},
+ {file = "rpds_py-0.21.0-cp312-none-win32.whl", hash = "sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952"},
+ {file = "rpds_py-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd"},
+ {file = "rpds_py-0.21.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937"},
+ {file = "rpds_py-0.21.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94"},
+ {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3"},
+ {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a"},
+ {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3"},
+ {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976"},
+ {file = "rpds_py-0.21.0-cp313-none-win32.whl", hash = "sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202"},
+ {file = "rpds_py-0.21.0-cp313-none-win_amd64.whl", hash = "sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e"},
+ {file = "rpds_py-0.21.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928"},
+ {file = "rpds_py-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592"},
+ {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d"},
+ {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd"},
+ {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87"},
+ {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed"},
+ {file = "rpds_py-0.21.0-cp39-none-win32.whl", hash = "sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8"},
+ {file = "rpds_py-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c"},
+ {file = "rpds_py-0.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e"},
+ {file = "rpds_py-0.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89"},
+ {file = "rpds_py-0.21.0.tar.gz", hash = "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db"},
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.12.2"
+description = "Backported and Experimental Type Hints for Python 3.8+"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
+ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
+]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.11"
+content-hash = "86a0266bee7cb43e7f1f5883cefd0b2a83dc1c4584bfc6281fb7c14856a28957"
diff --git a/tools/cru-py/pyproject.toml b/tools/cru-py/pyproject.toml new file mode 100644 index 0000000..bbf7873 --- /dev/null +++ b/tools/cru-py/pyproject.toml @@ -0,0 +1,28 @@ +[tool.poetry] +package-mode = false +name = "cru" +version = "0.1.0" +description = "" +authors = ["Yuqian Yang <crupest@crupest.life>"] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +rich = "^13.9.4" +jsonschema = "^4.23.0" +cryptography = "^43.0.3" + +[tool.poetry.group.dev.dependencies] +black = "^24.10.0" +isort = "^5.13.2" +flake8 = "^7.1.1" +flake8-bugbear = "^24.10.31" +mypy = "^1.13.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.isort] +profile = "black" diff --git a/tools/cru-py/requirements.txt b/tools/cru-py/requirements.txt deleted file mode 100644 index 2fb5657..0000000 --- a/tools/cru-py/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -rich -jsonschema -cryptography |