def add_time(self, h: int = 0, m: int = 0, d: int = 0, dw: int = 0, mh: int = 0, y: int = 0):
if any(v < 0 for v in [h,m,d,dw,mh,y]):
raise ValueError()
args = {'h':h, 'm':m, 'd':d, 'dw':dw, 'mh':mh, 'y':y}
bad = list(filter(lambda k: args[k] < 0, args.keys()))
if bad:
raise ValueError('Invalid values for: ' + ','.join(bad))
import functools
import inspect
# пусть чек-функция имеет вид (value) -> bool, и возвращает True для "хороших" значений. Пример:
def not_whitespace(s: str) -> bool:
'String must not contain only whitespace' # док строка будет использоваться в сообщении об ошибке
return bool(s.strip()) # проверяем что строка не состоит из одних пробелов.
# чек-функции можно генерировать и на ходу:
def in_range(low, high):
def check(value):
return (low is None or low <= value) and (high is None or value <= high)
check.__doc__ = f'Value must be between {low} and {high}.'
return check
# теперь сделаем декоратор, который умеет принимать чек-функции и применять их перед вызовом цели
def check(**checks):
def wrapper(func):
sign = inspect.signature(func)
names = list(sign.parameters.keys()) # имена параметров по порядку
not_found = set(checks.keys()) - set(names) # все ли чеки ссылаются на известные параметры?
if not_found:
# у нас есть чек на неизвестный параметр!
raise NameError(', '.join(not_found))
# всё ок, делаем обёртку над функцией
@functools.wraps(func)
def wrapped(*args, **kwargs):
bad = []
for param_name, check_func in checks.items():
idx = names.index(param_name)
if idx < len(args):
# параметр был передан через args
value = args[idx]
if not check_func(value): # вызываем чек-функцию
err = getattr(check_func, '__doc__', '')
if err:
bad.append(f'{param_name} ({err})')
else:
bad.append(param_name)
else:
pass # могут быть хитрости с kwargs-only параметрами. Тут уж извини, мне влом писать.
if bad: # нашли ошибки?
raise ValueError('Bad value for parameters: '+', '.join(bad))
# тут ещё можно помудрить над скрытием последнего фрейма в traceback, но мне опять влом
else: # не нашли, вызываем функцию
return func(*args, **kwargs)
return wrapped
return wrapper
# пример использования
# строка должна быть не из одних пробелов
# число должно быть в пределах от 1 до 10 включительно
@check(s=not_whitespace, n=in_range(1, 10))
def repeat(s: str, n: int) -> str:
return s * n
print(repeat('test ', 3))
try:
print(repeat('test ', 20))
except ValueError as err:
print('yep! it failed!', err)
try:
print(repeat('test ', -1))
except ValueError as err:
print('yep! it failed!', err)
try:
print(repeat(' ', 5))
except ValueError as err:
print('yep! it failed!', err)
try:
print(repeat(' ', 15))
except ValueError as err:
print('yep! it failed!', err)
def read_lines_in_range(f, ifrom: int, ito: int) -> list[str]:
f.seek(0)
for i in range(ifrom):
f.readline()
return [f.readline() for i in range(ito-ifrom)]
import math
z = float(input('Z = ')) # например, 10
logz = math.log(z, 2) # 10 находится между 2**3 и 2**4, так что logz будет 3 с копейками (но меньше 4)
pwr = int(logz) # отбрасываем дробную часть, получаем 3
value = 2 ** pwr # ближайшее меньшее значение - 2 ** 3
import pathlib # стандартный модуль питона. Очень советую его освоить!
import sys
# путь к папке скрипта, например, C:\myscript
script_dir = pathlib.Path(sys.argv[0]).parent
# путь к файлу собирается из частей вот так
user_file = script_dir / "some_folder" / "user_file" # C:\myscript\some_folder\user_file
# обрати внимание, мы не паримся по поводу того, что
# под виндой разделитель каталогов \, а под линуксом /
# это уже забота pathlib
with user_file.open('w+') as f:
pass # делаешь что тебе нужно с файлом
# через функцию open() тоже сработает, метод open() просто для удобства
with open(user_file, 'w+') as f:
pass # делаешь что тебе нужно с файлом
GotoIfTime\((?P<from>\d+:\d+)-(?P<to>\d+:\d+),(?P<days>[a-z-]+),\*,\*\?open,s,1\)
извлечёт из строки нужные части. Их можно будет вытащить так:regexp = re.compile(r'GotoIfTime\((?P<from>\d+:\d+)-(?P<to>\d+:\d+),(?P<days>[a-z-]+),\*,\*\?open,s,1\)', re.I)
m = regexp.match('GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1)')
if m:
print(m.group('days'), m.group('from'), m.group('to'))
now = datetime.datetime.now()
weekday = now.weekday()
days = m.group('days').lower()
days_of_week = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] # datetime.datetime.weekday()
if '-' in days: # диапазон
dfrom, _, dto = days.partition('-')
dfrom, dto = days_of_week.index(dfrom), days_of_week.index(dto)
if dfrom <= dto: # обычный кейс, вроде mon-fri
day_is_good = dfrom <= weekday <= dto
else: # на случае если нужно зацикливание вида fri-tue
day_is_good = (weekday >= dfrom) or (weekday <= dto)
else: # один день, не диапазон
dow = days_of_week.index(days)
day_is_good = weekday == dow
print(day_is_good) # True или False
datetime.datetime.now().replace(hour=h, minute=m)
и получаешь указанное время в текущий день.if from <= now <= to:
async def choice_cat(message):
CATs = cur.execute(f'SELECT name FROM cathlete WHERE id = "{message.from_user.id}"').fetchall()
for fds in range(len(CATs)):
astt = ReplyKeyboardMarkup(resize_keyboard=True).add(KeyboardButton(f"CATs[{fds}]"))
kbd = ReplyKeyboardMarkup(resize_keyboard=True)
btns = cur.execute(f'SELECT name FROM cathlete WHERE id = ?', (message.from_user.id,)).fetchall()
# btns - список списков.
if not btns:
# кнопки не предусмотрены, как-то даём пользователю знать об этом
return # если это фатально, останавливаемся тут
# иначе создаём какое-то значение btns по умолчанию и продолжаем
# тут уж сам решай
# делаем клавиатуру
for btn in btns:
kbd.add(KeyboardButton(btn[0]))
# ну и отправляем её вместе с сообщением