diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ef000..150dfde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.9.0 + ++ Fix to make experimental `Waiter` usable ++ Suspend `glue()` release indefinitely ++ Add `yesno()` ++ Document validators + ## 0.8.2 and 0.7.9 + `.color`: fix `chalk` not behaving as expected diff --git a/README.md b/README.md index 5b9a797..3a08b1e 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ Please note that you probably already have those dependencies, if you just use t ## Features -... +Read the [documentation](https://suou.readthedocs.io/). ## Support -Just a heads up: SUOU was made to support Sakuragasaki46 (me)'s own selfish, egoistic needs. Not to provide a service to the public. +Just a heads up: SUOU was made to support Sakuragasaki46 (me)'s own selfish, egoistic needs. Not certainly to provide a service to the public. As a consequence, 'add this add that' stuff is best-effort. diff --git a/docs/index.rst b/docs/index.rst index 12e5d40..9c3d855 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,4 +15,5 @@ ease programmer's QoL and write shorter and cleaner code that works. sqlalchemy iding + validators api \ No newline at end of file diff --git a/docs/validators.rst b/docs/validators.rst new file mode 100644 index 0000000..e878900 --- /dev/null +++ b/docs/validators.rst @@ -0,0 +1,15 @@ + +validators +================== + +.. currentmodule:: suou.validators + +Validators for use in frameworks such as Pydantic or Marshmallow. + +.. autofunction:: matches + +.. autofunction:: not_greater_than + +.. autofunction:: not_less_than + +.. autofunction:: yesno \ No newline at end of file diff --git a/src/suou/__init__.py b/src/suou/__init__.py index a74a37a..a7c96c8 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -32,12 +32,12 @@ from .signing import UserSigner from .snowflake import Snowflake, SnowflakeGen from .lex import symbol_table, lex, ilex from .strtools import PrefixIdentifier -from .validators import matches +from .validators import matches, not_less_than, not_greater_than, yesno from .redact import redact_url_password from .http import WantsContentType from .color import chalk, WebColor -__version__ = "0.8.2" +__version__ = "0.9.0" __all__ = ( 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', @@ -51,9 +51,10 @@ __all__ = ( 'cb32decode', 'chalk', 'count_ones', 'dei_args', 'deprecated', 'future', 'ilex', 'join_bits', 'jsonencode', 'kwargs_prefix', 'lex', 'ltuple', 'makelist', 'mask_shift', - 'matches', 'mod_ceil', 'mod_floor', 'none_pass', 'not_implemented', + 'matches', 'mod_ceil', 'mod_floor', 'must_be', 'none_pass', 'not_implemented', + 'not_less_than', 'not_greater_than', 'redact_url_password', 'rtuple', 'split_bits', 'ssv_list', 'symbol_table', 'timed_cache', 'twocolon_list', 'want_bytes', 'want_datetime', 'want_isodate', - 'want_str', 'want_timestamp', 'want_urlsafe', 'want_urlsafe_bytes', + 'want_str', 'want_timestamp', 'want_urlsafe', 'want_urlsafe_bytes', 'yesno', 'z85encode', 'z85decode' ) diff --git a/src/suou/calendar.py b/src/suou/calendar.py index d2af051..f738b88 100644 --- a/src/suou/calendar.py +++ b/src/suou/calendar.py @@ -17,7 +17,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import datetime -from suou.functools import not_implemented from suou.luck import lucky from suou.validators import not_greater_than diff --git a/src/suou/glue.py b/src/suou/glue.py index 3f1a799..6368deb 100644 --- a/src/suou/glue.py +++ b/src/suou/glue.py @@ -22,7 +22,7 @@ from suou.classtools import MISSING from suou.functools import future -@future(version="0.9.0") +@future() class FakeModule(ModuleType): """ Fake module used in @glue() in case of import error @@ -34,12 +34,12 @@ class FakeModule(ModuleType): raise AttributeError(f'Module {self.__name__} not found; this feature is not available ({self._exc})') from self._exc -@future(version = "0.9.0") +@future() def glue(*modules): """ Helper for "glue" code -- it imports the given modules and passes them as keyword arguments to the wrapped functions. - NEW 0.9.0 + EXPERIMENTAL """ module_dict = dict() imports_succeeded = True diff --git a/src/suou/validators.py b/src/suou/validators.py index 53a7be3..e8b366f 100644 --- a/src/suou/validators.py +++ b/src/suou/validators.py @@ -18,6 +18,10 @@ import re from typing import Any, Iterable, TypeVar +from suou.classtools import MISSING + +from .functools import future + _T = TypeVar('_T') def matches(regex: str | int, /, length: int = 0, *, flags=0): @@ -55,5 +59,13 @@ def not_less_than(y): """ return lambda x: x >= y -__all__ = ('matches', 'not_greater_than') +def yesno(x: str) -> bool: + """ + Returns False if x.lower() is in '0', '', 'no', 'n', 'false' or 'off'. + + *New in 0.9.0* + """ + return x not in (None, MISSING) and x.lower() not in ('', '0', 'off', 'n', 'no', 'false', 'f') + +__all__ = ('matches', 'must_be', 'not_greater_than', 'not_less_than', 'yesno') diff --git a/src/suou/waiter.py b/src/suou/waiter.py index 51e4590..a959c88 100644 --- a/src/suou/waiter.py +++ b/src/suou/waiter.py @@ -17,6 +17,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ +from typing import Callable import warnings from starlette.applications import Starlette from starlette.responses import JSONResponse, PlainTextResponse, Response @@ -27,15 +28,22 @@ from suou.functools import future @future() class Waiter(): + _cached_app: Callable | None = None + def __init__(self): self.routes: list[Route] = [] self.production = False - + + async def __call__(self, *args): + return await self._build_app()(*args) + def _build_app(self) -> Starlette: - return Starlette( - debug = not self.production, - routes= self.routes - ) + if not self._cached_app: + self._cached_app = Starlette( + debug = not self.production, + routes= self.routes + ) + return self._cached_app def get(self, endpoint: str, *a, **k): return self._route('GET', endpoint, *a, **k) diff --git a/tests/test_validators.py b/tests/test_validators.py new file mode 100644 index 0000000..0064128 --- /dev/null +++ b/tests/test_validators.py @@ -0,0 +1,24 @@ + + +import unittest +from suou.validators import yesno + +class TestValidators(unittest.TestCase): + def setUp(self): + ... + def tearDown(self): + ... + def test_yesno(self): + self.assertFalse(yesno('false')) + self.assertFalse(yesno('FALSe')) + self.assertTrue(yesno('fasle')) + self.assertTrue(yesno('falso')) + self.assertTrue(yesno('zero')) + self.assertTrue(yesno('true')) + self.assertFalse(yesno('0')) + self.assertTrue(yesno('00')) + self.assertTrue(yesno('.')) + self.assertTrue(yesno('2')) + self.assertTrue(yesno('o')) + self.assertFalse(yesno('oFF')) + self.assertFalse(yesno('no')) \ No newline at end of file