diff --git a/CHANGELOG.md b/CHANGELOG.md index 326455a..fe54664 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,11 @@ + Add RNG/random selection overloads such as `luck()`, `rng_overload()` + Add 7 new throwable exceptions -+ Add color utilities: `chalk` module ++ Add color utilities: `chalk` object and `WebColor()` + Add `.terminal` module, to ease TUI development + `calendar`: add `parse_time()` -+ Add validator `not_greater_than()` -+ Add `@future()` decorator ++ Add validators `not_greater_than()`, `not_less_than()` ++ Add `@future()` decorator: it signals features not yet intended to be public, for instance, backported as a part of a bug fix. ## 0.6.1 diff --git a/README.md b/README.md index 56da550..8f931dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SIS Unified Object Underarmor -Good morning, my brother! Welcome **SUOU** (**S**IS **U**nified **O**bject **U**nderarmor), the Python library which makes API development faster for developing API's, database schemas and stuff in Python. +Good morning, my brother! Welcome **SUOU** (**S**IS **U**nified **O**bject **U**nderarmor), the Python library which speeds up and makes it pleasing to develop API, database schemas and stuff in Python. It provides utilities such as: * [SIQ](https://yusur.moe/protocols/siq.html) diff --git a/src/suou/__init__.py b/src/suou/__init__.py index 7abb543..171d4e5 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -37,7 +37,7 @@ from .redact import redact_url_password from .http import WantsContentType from .color import chalk -__version__ = "0.7.0-dev37" +__version__ = "0.7.0-dev38" __all__ = ( 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', diff --git a/src/suou/color.py b/src/suou/color.py index 31ea031..07241ba 100644 --- a/src/suou/color.py +++ b/src/suou/color.py @@ -17,7 +17,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ +from __future__ import annotations +from collections import namedtuple from functools import lru_cache @@ -75,5 +77,56 @@ class Chalk: return self._wrap(self.FAINT, self.END_BOLD) -## TODO make it lazy? +## TODO make it lazy / an instance variable? chalk = Chalk() + + +## Utilities for web colors + +class WebColor(namedtuple('_WebColor', 'red green blue')): + """ + Representation of a color in the TrueColor space (aka rgb). + + Useful for theming. + """ + def lighten(self, *, factor = .75): + """ + Return a whitened shade of the color. + Factor stands between 0 and 1: 0 = total white, 1 = no change. Default is .75 + """ + return WebColor( + 255 - int((255 - self.red) * factor), + 255 - int((255 - self.green) * factor), + 255 - int((255 - self.blue) * factor), + ) + def darken(self, *, factor = .75): + """ + Return a darkened shade of the color. + Factor stands between 0 and 1: 0 = total black, 1 = no change. Default is .75 + """ + return WebColor( + int(self.red * factor), + int(self.green * factor), + int(self.blue * factor) + ) + def greyen(self, *, factor = .75): + """ + Return a desaturated shade of the color. + Factor stands between 0 and 1: 0 = gray, 1 = no change. Default is .75 + """ + return self.darken(factor=factor) + self.lighten(factor=factor) + + def blend_with(self, other: WebColor): + """ + Mix two colors, returning the average. + """ + return WebColor ( + (self.red + other.red) // 2, + (self.green + other.green) // 2, + (self.blue + other.blue) // 2 + ) + + __add__ = blend_with + + def __str__(self): + return f"rgb({self.red}, {self.green}, {self.blue})" diff --git a/src/suou/luck.py b/src/suou/luck.py index 04d4291..669025c 100644 --- a/src/suou/luck.py +++ b/src/suou/luck.py @@ -16,6 +16,7 @@ This software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ +from functools import wraps from typing import Callable, Generic, Iterable, TypeVar import random from suou.exceptions import BadLuckError @@ -34,7 +35,7 @@ def lucky(validators: Iterable[Callable[[_U], bool]] = ()): NEW 0.7.0 """ - def decorator(func: Callable[_T, _U]): + def decorator(func: Callable[..., _U]): @wraps(func) def wrapper(*args, **kwargs) -> _U: try: @@ -56,7 +57,7 @@ def lucky(validators: Iterable[Callable[[_U], bool]] = ()): class RngCallable(Callable, Generic[_T, _U]): """ - Overloaded ... randomly chosen callable. + Overloaded ...randomly chosen callable. UNTESTED @@ -86,13 +87,13 @@ class RngCallable(Callable, Generic[_T, _U]): choice -= w -def rng_overload(prev_func: RngCallable[_T, _U] | int | None, /, *, weight: int = 1) -> RngCallable[_T, _U]: +def rng_overload(prev_func: RngCallable[..., _U] | int | None, /, *, weight: int = 1) -> RngCallable[..., _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. + Each call chooses randomly one candidate (weight is taken in consideration), + calls it, and returns the result. UNTESTED diff --git a/src/suou/validators.py b/src/suou/validators.py index 9fd0a3c..53a7be3 100644 --- a/src/suou/validators.py +++ b/src/suou/validators.py @@ -49,5 +49,11 @@ def not_greater_than(y): """ return lambda x: x <= y +def not_less_than(y): + """ + Return a function that returns True if X is not less than (i.e. greater than or equal to) the given value. + """ + return lambda x: x >= y + __all__ = ('matches', 'not_greater_than')