diff --git a/CHANGELOG.md b/CHANGELOG.md index c1fee43..37975e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,5 @@ # Changelog -## 0.7.0 "The Lucky Update" - -+ Add RNG/random selection overloads such as `luck()`, `rng_overload()` -+ Add 7 new throwable exceptions -+ Add color utilities: `chalk` module - ## 0.6.1 - First release on PyPI under the name `suou`. diff --git a/aliases/sakuragasaki46-suou/pyproject.toml b/aliases/sakuragasaki46-suou/pyproject.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/aliases/sakuragasaki46-suou/pyproject.toml @@ -0,0 +1 @@ + diff --git a/aliases/sakuragasaki46_suou/README.md b/aliases/sakuragasaki46_suou/README.md deleted file mode 100644 index 2b29355..0000000 --- a/aliases/sakuragasaki46_suou/README.md +++ /dev/null @@ -1 +0,0 @@ -moved to [suou](https://pypi.org/project/suou) diff --git a/aliases/sakuragasaki46_suou/pyproject.toml b/aliases/sakuragasaki46_suou/pyproject.toml deleted file mode 100644 index 035fdb5..0000000 --- a/aliases/sakuragasaki46_suou/pyproject.toml +++ /dev/null @@ -1,8 +0,0 @@ -[project] -name = "sakuragasaki46_suou" -authors = [ { name = "Sakuragasaki46" } ] -version = "0.6.1" -requires-python = ">=3.10" -dependencies = [ "suou==0.6.1" ] -readme = "README.md" - diff --git a/src/suou/__init__.py b/src/suou/__init__.py index a33a879..3c0efd3 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -35,9 +35,8 @@ from .strtools import PrefixIdentifier from .validators import matches from .redact import redact_url_password from .http import WantsContentType -from .color import chalk -__version__ = "0.7.0-dev37" +__version__ = "0.6.1" __all__ = ( 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', @@ -47,7 +46,7 @@ __all__ = ( 'StringCase', 'TimedDict', 'TomlI18n', 'UserSigner', 'Wanted', 'WantsContentType', 'addattr', 'additem', 'age_and_days', 'alru_cache', 'b2048decode', 'b2048encode', 'b32ldecode', 'b32lencode', 'b64encode', 'b64decode', 'cb32encode', - 'cb32decode', 'chalk', 'count_ones', 'dei_args', 'deprecated', 'ilex', 'join_bits', + 'cb32decode', 'count_ones', 'dei_args', 'deprecated', 'ilex', 'join_bits', 'jsonencode', 'kwargs_prefix', 'lex', 'ltuple', 'makelist', 'mask_shift', 'matches', 'mod_ceil', 'mod_floor', 'none_pass', 'not_implemented', 'redact_url_password', 'rtuple', 'split_bits', 'ssv_list', 'symbol_table', diff --git a/src/suou/asgi.py b/src/suou/asgi.py index 7229920..3f3fd70 100644 --- a/src/suou/asgi.py +++ b/src/suou/asgi.py @@ -1,17 +1,5 @@ """ -ASGI stuff ---- - -Copyright (c) 2025 Sakuragasaki46. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -See LICENSE for the specific language governing permissions and -limitations under the License. - -This software is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ from typing import Any, Awaitable, Callable, MutableMapping, ParamSpec, Protocol diff --git a/src/suou/color.py b/src/suou/color.py deleted file mode 100644 index 31ea031..0000000 --- a/src/suou/color.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Colors for coding artists - -NEW 0.7.0 - ---- - -Copyright (c) 2025 Sakuragasaki46. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -See LICENSE for the specific language governing permissions and -limitations under the License. - -This software is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -""" - - -from functools import lru_cache - - -class Chalk: - """ - ANSI escape codes for terminal colors, similar to JavaScript's `chalk` library. - - Best used with Python 3.12+ that allows arbitrary nesting of f-strings. - - Yes, I am aware colorama exists. - - UNTESTED - - NEW 0.7.0 - """ - CSI = '\x1b[' - RED = CSI + "31m" - GREEN = CSI + "32m" - YELLOW = CSI + "33m" - BLUE = CSI + "34m" - CYAN = CSI + "36m" - PURPLE = CSI + "35m" - GREY = CSI + "90m" - END_COLOR = CSI + "39m" - BOLD = CSI + "1m" - END_BOLD = CSI + "22m" - FAINT = CSI + "2m" - def __init__(self, flags = (), ends = ()): - self._flags = tuple(flags) - self._ends = tuple(ends) - @lru_cache() - def _wrap(self, beg, end): - return Chalk(self._flags + (beg,), self._ends + (end,)) - def __call__(self, s: str) -> str: - return ''.join(self._flags) + s + ''.join(reversed(self._ends)) - def red(self): - return self._wrap(self.RED, self.END_COLOR) - def green(self): - return self._wrap(self.GREEN, self.END_COLOR) - def blue(self): - return self._wrap(self.BLUE, self.END_COLOR) - def yellow(self): - return self._wrap(self.YELLOW, self.END_COLOR) - def cyan(self): - return self._wrap(self.CYAN, self.END_COLOR) - def purple(self): - return self._wrap(self.PURPLE, self.END_COLOR) - def grey(self): - return self._wrap(self.GREY, self.END_COLOR) - gray = grey - marine = blue - def bold(self): - return self._wrap(self.BOLD, self.END_BOLD) - def faint(self): - return self._wrap(self.FAINT, self.END_BOLD) - - -## TODO make it lazy? -chalk = Chalk() diff --git a/src/suou/exceptions.py b/src/suou/exceptions.py index 74ea7ec..7952bc7 100644 --- a/src/suou/exceptions.py +++ b/src/suou/exceptions.py @@ -1,5 +1,5 @@ """ -Exceptions and throwables for all purposes! +Exceptions and throwables for various purposes --- @@ -14,17 +14,6 @@ This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ - -class PoliticalError(Exception): - """ - Base class for anything that is refused to be executed for political reasons. - """ - -class PoliticalWarning(PoliticalError, Warning): - """ - Base class for politically suspicious behaviors. - """ - class MissingConfigError(LookupError): """ Config variable not found. @@ -64,35 +53,6 @@ class BabelTowerError(NotFoundError): The user requested a language that cannot be understood. """ -class BadLuckError(Exception): - """ - Stuff did not go as expected. - - Raised by @lucky decorator. - """ - -class TerminalRequiredError(OSError): - """ - Raised by terminal_required() decorator when a function is called from a non-interactive environment. - """ - -class BrokenStringsError(OSError): - """ - Issues related to audio happened, i.e. appropriate executables/libraries/drivers are not installed. - """ - -class Fahrenheit451Error(PoliticalError): - """ - Base class for thought crimes related to arts (e.g. writing, visual arts, music) - """ - -class FuckAroundFindOutError(PoliticalError): - """ - Raised when there is no actual grounds to raise an exception, but you did something in the past to deserve this outcome. - - Ideal for permanent service bans or something. - """ - __all__ = ( 'MissingConfigError', 'MissingConfigWarning', 'LexError', 'InconsistencyError', 'NotFoundError' ) \ No newline at end of file diff --git a/src/suou/lex.py b/src/suou/lex.py index 5655eea..15791c3 100644 --- a/src/suou/lex.py +++ b/src/suou/lex.py @@ -2,16 +2,6 @@ Utilities for tokenization of text. --- - -Copyright (c) 2025 Sakuragasaki46. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -See LICENSE for the specific language governing permissions and -limitations under the License. - -This software is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ from re import Match diff --git a/src/suou/luck.py b/src/suou/luck.py deleted file mode 100644 index 7b8192e..0000000 --- a/src/suou/luck.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -Fortune' RNG and esoterism. - -NEW 0.7.0 - ---- - -Copyright (c) 2025 Sakuragasaki46. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -See LICENSE for the specific language governing permissions and -limitations under the License. - -This software is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -""" - -from typing import Callable, Generic, Iterable, TypeVar -import random -from suou.exceptions import BadLuckError - -_T = TypeVar('_T') -_U = TypeVar('_U') - - -def lucky(validators: Iterable[Callable[[_U], bool]] = ()): - """ - Add one or more constraint on a function's return value. - Each validator must return a boolean. If false, the result is considered - unlucky and BadLuckError() is raised. - - UNTESTED - - NEW 0.7.0 - """ - def decorator(func: Callable[_T, _U]): - @wraps(func) - def wrapper(*args, **kwargs) -> _U: - try: - result = func(*args, **kwargs) - except Exception as e: - raise BadLuckError(f'exception happened: {e}') from e - for v in validators: - try: - if not v(result): - raise BadLuckError(f'result not expected: {result!r}') - except BadLuckError: - raise - except Exception as e: - raise BadLuckError(f'cannot validate: {e}') from e - return result - return wrapper - return decorator - -class RngCallable(Callable, Generic[_T, _U]): - """ - Overloaded ... randomly chosen callable. - - UNTESTED - - NEW 0.7.0 - """ - def __init__(self, /, func: Callable[_T, _U] | None = None, weight: int = 1): - self._callables = [] - self._max_weight = 0 - if callable(func): - self.add_callable(func, weight) - def add_callable(self, func: Callable[_T, _U], weight: int = 1): - """ - """ - weight = int(weight) - if weight <= 0: - return - self._callables.append((func, weight)) - self._max_weight += weight - def __call__(self, *a, **ka) -> _U: - choice = random.randrange(self._max_weight) - for w, c in self._callables: - if choice < w: - return c(*a, **ka) - elif choice < 0: - raise RuntimeError('inconsistent state') - else: - choice -= w - - -def rng_overload(prev_func: RngCallable[_T, _U] | int | None, /, *, weight: int = 1) -> RngCallable[_T, _U]: - """ - Decorate the first function with @rng_overload and the weight= parameter - (default 1, must be an integer) to create a "RNG" overloaded callable. - - Each call chooses randomly one candidate (weight is taken in consideration) - , calls it, and returns the result. - - UNTESTED - - NEW 0.7.0 - """ - if isinstance(prev_func, int) and weight == 1: - weight, prev_func = prev_func, None - - def decorator(func: Callable[_T, _U]): - nonlocal prev_func - if prev_func is None: - prev_func = RngCallable(func, weight=weight) - else: - prev_func.add_callable(func, weight=weight) - return prev_func - return decorator - - -# This module is experimental and therefore not re-exported into __init__ -__all__ = ('lucky', 'rng_overload') \ No newline at end of file diff --git a/src/suou/waiter.py b/src/suou/waiter.py index a210f45..74d2d0e 100644 --- a/src/suou/waiter.py +++ b/src/suou/waiter.py @@ -54,5 +54,4 @@ def ko(status: int, /, content = None, **ka): return PlainTextResponse(content, status_code=status, **ka) return content -# This module is experimental and therefore not re-exported into __init__ __all__ = ('ko', 'ok', 'Waiter') \ No newline at end of file