Compare commits

...

2 commits

6 changed files with 91 additions and 12 deletions

View file

@ -6,7 +6,9 @@
+ Module `sqlalchemy`: + Module `sqlalchemy`:
* removed deprecated alias `entity_base()`. use `declarative_base()` instead. * removed deprecated alias `entity_base()`. use `declarative_base()` instead.
* fix imports. * fix imports.
+ Module `functools`: add `cooldown()` + Module `functools`: add `cooldown()`, `do_not_flood()`
+ Module `color`: add `ColorFormatter()`
+ Separated `suou[waiter]` dependency from `suou[quart]`
## 0.12.6 ## 0.12.6

View file

@ -56,7 +56,9 @@ markdown = [
] ]
quart = [ quart = [
"Quart", "Quart",
"Quart-Schema", "Quart-Schema"
]
waiter = [
"starlette>=0.47.2" "starlette>=0.47.2"
] ]
quart_auth = [ quart_auth = [
@ -78,7 +80,8 @@ full = [
"suou[quart_auth]", # includes quart, sqlalchemy and quart_sqlalchemy "suou[quart_auth]", # includes quart, sqlalchemy and quart_sqlalchemy
"suou[peewee]", "suou[peewee]",
"suou[markdown]", "suou[markdown]",
"suou[sass]" "suou[sass]",
"suou[waiter]"
] ]
docs = [ docs = [

View file

@ -18,13 +18,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from .iding import Siq, SiqCache, SiqType, SiqGen from .iding import Siq, SiqCache, SiqType, SiqGen
from .codecs import (StringCase, cb32encode, cb32decode, b32lencode, b32ldecode, b64encode, b64decode, b2048encode, b2048decode, from .codecs import (StringCase, cb32encode, cb32decode, b32lencode, b32ldecode, b64encode, b64decode, b2048encode, b2048decode,
jsonencode, twocolon_list, want_bytes, want_str, ssv_list, want_urlsafe, want_urlsafe_bytes) jsonencode, twocolon_list, want_bytes, want_str, ssv_list, want_urlsafe, want_urlsafe_bytes,
z85encode, z85decode)
from .bits import count_ones, mask_shift, split_bits, join_bits, mod_ceil, mod_floor from .bits import count_ones, mask_shift, split_bits, join_bits, mod_ceil, mod_floor
from .calendar import want_datetime, want_isodate, want_timestamp, age_and_days from .calendar import want_datetime, want_isodate, want_timestamp, age_and_days
from .configparse import MissingConfigError, MissingConfigWarning, ConfigOptions, ConfigParserConfigSource, ConfigSource, DictConfigSource, ConfigValue, EnvConfigSource from .configparse import MissingConfigError, MissingConfigWarning, ConfigOptions, ConfigParserConfigSource, ConfigSource, DictConfigSource, ConfigValue, EnvConfigSource
from .collections import TimedDict from .collections import TimedDict
from .dei import dei_args from .dei import dei_args
from .functools import deprecated, not_implemented, timed_cache, none_pass, alru_cache, future from .functools import deprecated, not_implemented, timed_cache, none_pass, alru_cache, future, cooldown, do_not_flood
from .classtools import Wanted, Incomplete from .classtools import Wanted, Incomplete
from .itertools import makelist, kwargs_prefix, ltuple, rtuple, additem, addattr from .itertools import makelist, kwargs_prefix, ltuple, rtuple, additem, addattr
from .i18n import I18n, JsonI18n, TomlI18n from .i18n import I18n, JsonI18n, TomlI18n
@ -32,16 +33,18 @@ from .signing import UserSigner
from .snowflake import Snowflake, SnowflakeGen from .snowflake import Snowflake, SnowflakeGen
from .lex import symbol_table, lex, ilex from .lex import symbol_table, lex, ilex
from .strtools import PrefixIdentifier from .strtools import PrefixIdentifier
from .validators import matches, not_less_than, not_greater_than, yesno from .validators import matches, not_less_than, not_greater_than, yesno, must_be
from .redact import redact_url_password from .redact import redact_url_password
from .http import WantsContentType from .http import WantsContentType
from .color import OKLabColor, chalk, WebColor, RGBColor, LinearRGBColor, XYZColor, OKLCHColor from .color import OKLabColor, chalk, WebColor, RGBColor, LinearRGBColor, \
XYZColor, OKLCHColor, ColorFormatter
from .mat import Matrix from .mat import Matrix
from .argparse import LetterSubparsers from .argparse import LetterSubparsers
__version__ = "0.13.0a2" __version__ = "0.13.0a4"
__all__ = ( __all__ = (
'ColorFormatter',
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
'DictConfigSource', 'EnvConfigSource', 'I18n', 'Incomplete', 'JsonI18n', 'DictConfigSource', 'EnvConfigSource', 'I18n', 'Incomplete', 'JsonI18n',
'LetterSubparsers', 'LinearRGBColor', 'LetterSubparsers', 'LinearRGBColor',
@ -52,7 +55,7 @@ __all__ = (
'WebColor', 'XYZColor', 'WebColor', 'XYZColor',
'addattr', 'additem', 'age_and_days', 'alru_cache', 'b2048decode', 'b2048encode', 'addattr', 'additem', 'age_and_days', 'alru_cache', 'b2048decode', 'b2048encode',
'b32ldecode', 'b32lencode', 'b64encode', 'b64decode', 'cb32encode', 'b32ldecode', 'b32lencode', 'b64encode', 'b64decode', 'cb32encode',
'cb32decode', 'chalk', 'count_ones', 'dei_args', 'deprecated', 'cb32decode', 'chalk', 'cooldown', 'count_ones', 'dei_args', 'deprecated', 'do_not_flood',
'future', 'ilex', 'join_bits', 'jsonencode', 'kwargs_prefix', 'future', 'ilex', 'join_bits', 'jsonencode', 'kwargs_prefix',
'lex', 'ltuple', 'makelist', 'mask_shift', 'lex', 'ltuple', 'makelist', 'mask_shift',
'matches', 'mod_ceil', 'mod_floor', 'must_be', 'none_pass', 'not_implemented', 'matches', 'mod_ceil', 'mod_floor', 'must_be', 'none_pass', 'not_implemented',

View file

@ -19,7 +19,7 @@ from __future__ import annotations
import argparse import argparse
import sys import sys
from typing import Callable, Mapping from typing import Callable
class LetterSubparsers(object): class LetterSubparsers(object):
""" """

View file

@ -21,6 +21,7 @@ from __future__ import annotations
from collections import namedtuple from collections import namedtuple
from functools import lru_cache from functools import lru_cache
import logging
import math import math
from suou.functools import deprecated from suou.functools import deprecated
@ -331,4 +332,48 @@ class OKLCHColor(namedtuple('_OKLCHColor', 'l c h')):
return sum(abs(i - j) / k for i, j, k in zip(self, other, (1, 1, 36))) return sum(abs(i - j) / k for i, j, k in zip(self, other, (1, 1, 36)))
__all__ = ('chalk', 'WebColor', "RGBColor", 'LinearRGBColor', 'XYZColor', 'OKLabColor', 'OKLCHColor') class ColorFormatter(logging.Formatter):
"""
Colored logging formatter.
Opinionated.
Taken from https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output
"""
def _get_base_format(color):
return f"[%(asctime)s] {color('%(levelname)s')}{chalk.grey(': ')}{color('%(name)s')}{chalk.grey(': ')}%(message)s"
FORMATS = {
logging.DEBUG: _get_base_format(chalk.cyan),
logging.INFO: _get_base_format(chalk.green),
logging.WARNING: _get_base_format(chalk.yellow),
logging.ERROR: _get_base_format(chalk.red),
logging.CRITICAL: _get_base_format(chalk.bold.red)
}
del _get_base_format
def format(self, record: logging.LogRecord) -> str:
log_fmt = self.FORMATS.get(record.levelno)
formatter = logging.Formatter(log_fmt)
return formatter.format(record)
@classmethod
def apply_handler(cls, logger: logging.Logger, level = logging.INFO):
"""
Apply the colored formatter to a logger.
Use this with logging.root, instead of logging.basicConfig().
Should not be called more than once.
"""
logger.setLevel(level)
ch = logging.StreamHandler()
ch.setLevel(level)
ch.setFormatter(cls())
logger.addHandler(ch)
__all__ = ('chalk', 'WebColor', "RGBColor", 'LinearRGBColor', 'XYZColor',
'OKLabColor', 'OKLCHColor', 'ColorFormatter')

View file

@ -382,6 +382,32 @@ def cooldown(unit: int, /, exception: Exception | None = None):
return wrapper return wrapper
return decorator return decorator
def do_not_flood(unit = .25):
"""
Implement a calling cooldown for a function or procedure.
If the decorated function is called during the cooldown, the function
blocks before being called again.
This is blocking and uses time.sleep().
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
if wrapper.timeout_until is not None and wrapper.timeout_until > now:
wrapper.timeout_delay += unit
time.sleep(wrapper.timeout_until - now)
wrapper.timeout_until = now + wrapper.timeout_delay
else:
wrapper.timeout_delay = unit
wrapper.timeout_until = time.time() + unit
return func(*args, **kwargs)
wrapper.timeout_until = None
wrapper.timeout_delay = unit
return wrapper
return decorator
__all__ = ( __all__ = (
'deprecated', 'not_implemented', 'timed_cache', 'none_pass', 'alru_cache', 'cooldown' 'deprecated', 'not_implemented', 'timed_cache', 'none_pass', 'alru_cache', 'cooldown', 'do_not_flood'
) )