add parse_time(), validators.not_greater_than()
This commit is contained in:
parent
18950c3445
commit
f07d691004
4 changed files with 43 additions and 4 deletions
|
|
@ -6,6 +6,8 @@
|
|||
+ Add 7 new throwable exceptions
|
||||
+ Add color utilities: `chalk` module
|
||||
+ Add `.terminal` module, to ease TUI development.
|
||||
+ `calendar`: add `parse_time()`.
|
||||
+ Add validator `not_greater_than()`.
|
||||
|
||||
## 0.6.1
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ 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
|
||||
|
||||
|
||||
def want_isodate(d: datetime.datetime | str | float | int, *, tz = None) -> str:
|
||||
|
|
@ -63,4 +65,28 @@ def age_and_days(date: datetime.datetime, now: datetime.datetime | None = None)
|
|||
d = (now - datetime.date(date.year + y, date.month, date.day)).days
|
||||
return y, d
|
||||
|
||||
__all__ = ('want_datetime', 'want_timestamp', 'want_isodate', 'age_and_days')
|
||||
@lucky([not_greater_than(259200)])
|
||||
def parse_time(timestr: str, /) -> int:
|
||||
"""
|
||||
Parse a number-suffix (es. 3s, 15m) or colon (1:30) time expression.
|
||||
|
||||
Returns seconds as an integer.
|
||||
"""
|
||||
if timestr.isdigit():
|
||||
return int(timestr)
|
||||
elif ':' in timestr:
|
||||
timeparts = timestr.split(':')
|
||||
if not timeparts[0].isdigit() and not all(x.isdigit() and len(x) == 2 for x in timeparts[1:]):
|
||||
raise ValueError('invalid time format')
|
||||
return sum(int(x) * 60 ** (len(timeparts) - 1 - i) for i, x in enumerate(timeparts))
|
||||
elif timestr.endswith('s') and timestr[:-1].isdigit():
|
||||
return int(timestr[:-1])
|
||||
elif timestr.endswith('m') and timestr[:-1].isdigit():
|
||||
return int(timestr[:-1]) * 60
|
||||
elif timestr.endswith('h') and timestr[:-1].isdigit():
|
||||
return int(float(timestr[:-1]) * 3600)
|
||||
else:
|
||||
raise ValueError('invalid time format')
|
||||
|
||||
|
||||
__all__ = ('want_datetime', 'want_timestamp', 'want_isodate', 'age_and_days', 'parse_time')
|
||||
|
|
@ -44,7 +44,8 @@ def lucky(validators: Iterable[Callable[[_U], bool]] = ()):
|
|||
for v in validators:
|
||||
try:
|
||||
if not v(result):
|
||||
raise BadLuckError(f'result not expected: {result!r}')
|
||||
message = 'result not expected'
|
||||
raise BadLuckError(f'{message}: {result!r}')
|
||||
except BadLuckError:
|
||||
raise
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ _T = TypeVar('_T')
|
|||
|
||||
def matches(regex: str | int, /, length: int = 0, *, flags=0):
|
||||
"""
|
||||
Return a function which returns true if X is shorter than length and matches the given regex.
|
||||
Return a function which returns True if X is shorter than length and matches the given regex.
|
||||
"""
|
||||
if isinstance(regex, int):
|
||||
length = regex
|
||||
|
|
@ -31,13 +31,23 @@ def matches(regex: str | int, /, length: int = 0, *, flags=0):
|
|||
return (not length or len(s) < length) and bool(re.fullmatch(regex, s, flags=flags))
|
||||
return validator
|
||||
|
||||
|
||||
def must_be(obj: _T | Any, typ: type[_T] | Iterable[type], message: str, *, exc = TypeError) -> _T:
|
||||
"""
|
||||
Raise TypeError if the requested object is not of the desired type(s), with a nice message.
|
||||
|
||||
(Not properly a validator.)
|
||||
"""
|
||||
if not isinstance(obj, typ):
|
||||
raise TypeError(f'{message}, not {obj.__class__.__name__!r}')
|
||||
return obj
|
||||
|
||||
|
||||
__all__ = ('matches', )
|
||||
def not_greater_than(y):
|
||||
"""
|
||||
Return a function that returns True if X is not greater than (i.e. lesser than or equal to) the given value.
|
||||
"""
|
||||
return lambda x: x <= y
|
||||
|
||||
__all__ = ('matches', 'not_greater_than')
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue