Ответы пользователя по тегу Python
  • Python, VKBottle, SQL. Как ограничить доступ к команде на время?

    drygdryg
    @drygdryg
    Python-разработчик
    В этой строке метод fetchone() возвращает один результат в виде кортежа полей, в вашем случае состоящего из одного элемента — значения поля time:
    last_command_use_time = cursor.fetchone()
    Поэтому вы можете извлечь из него первый элемент и положить его в last_command_use_time:
    last_command_use_time = cursor.fetchone()[0]
    Никогда не используйте f-строки или иной способ форматирования для подстановки значений в SQL-запросы: это может вызвать проблемы с безопасностью приложения. Как верно отметил Vindicar, лучше использовать средства вашего драйвера СУБД для подстановки параметров в запросы (parametrized quieries).
    К тому же, для ограничения частоты выполнения каких-либо действий в вашем приложении обычно лучше использовать решения на базе быстрых хранилищ "ключ-значение" вроде Redis или Memcached, чем на базе реляционных СУБД (коей является PostgreSQL).
    Советую обратить внимание на инструмент PyrateLimiter: он обеспечивает ограничение частоты выполнения функции (либо корутины, что может быть полезным в вашем случае) и в качестве хранилища может использовать оперативную память (queue.Queue), Redis или SQLite.
    Ответ написан
  • Как называются "\n","\r","\t"... в строках?

    drygdryg
    @drygdryg
    Python-разработчик
    Это специальные управляющие последовательности (англ. escape sequences), которые используются для записи пробельных (непечатных) символов (англ. whitespace characters). Все эти символы соответствуют шаблону \s в регулярных выражениях:
    import re
    
    print(all(re.fullmatch(r'\s', string) for string in ('\n', '\r', '\t', ' ')))  # True
    Ответ написан
    1 комментарий
  • Как преобразовать список в словари?

    drygdryg
    @drygdryg
    Python-разработчик
    Например, с помощью генератора словаря (dict comprehension) и range:
    a, b, c, d = 'abcd'
    lst = [1, a, b, c, d, 2, a, b, c, d, 3, a, b, c, d]
    result = {lst[i]: {lst[i+1]: lst[i+2], lst[i+3]: lst[i+4]} for i in range(0, len(lst), 5)}
    print(result)  # {1: {'a': 'b', 'c': 'd'}, 2: {'a': 'b', 'c': 'd'}, 3: {'a': 'b', 'c': 'd'}}

    или с помощью цикла:
    result = {}
    for i in range(0, len(lst), 5):
        result[lst[i]] = {lst[i+1]: lst[i+2], lst[i+3]: lst[i+4]}
    print(result)  # {1: {'a': 'b', 'c': 'd'}, 2: {'a': 'b', 'c': 'd'}, 3: {'a': 'b', 'c': 'd'}}
    Ответ написан
    Комментировать
  • Как сделать время пробытия юезра в боте?

    drygdryg
    @drygdryg
    Python-разработчик
    1. Определите момент, с которого вы будете отсчитывать дни, сколько пользователь "с вами": это может быть запуск бота командой /start, либо какое-то другое значительное действие (например, регистрация);
    2. Запишите этот момент в виде даты и времени в базу данных.
    3. Когда нужно отобразить, сколько пользователь с вами, берите текущее время и вычитайте из него время из базы данных. Для этого удобно использовать модуль datetime:
    import datetime as dt
    
    joined = …  # Момент, с которого пользователь начал пользоваться ботом (тип данных dt.datetime, из БД)
    now = dt.datetime.now()
    days_with_us = (now - joined).days
    msg = f"Вы с нами дней: {days}"

    Если нужно красиво выводить разницу во времени (вроде "9 дней, 2 часа" или "2 года, 3 месяца 7 дней"), то можно воспользоваться сторонними библиотеками, которые позволяют перевести объект datetime.timedelta в удобочитаемое представление. Например, Humanize: https://python-humanize.readthedocs.io/en/latest/
    Ответ написан
    Комментировать
  • Как исправить краш вовремя бездействия?

    drygdryg
    @drygdryg
    Python-разработчик
    В решении ловятся только ошибки, связанные с API. А у вас ошибка, связанная с сетевым подключением. Нужно добавить обработку соотв. исключения. Чтобы обрабатывать все исключения, связанные с проблемами сети, используйте ConnectionError:
    from requests.exceptions import ConnectionError
    ...
    except (telebot.apihelper.ApiException, RequestException) as e:
    ...

    См. исключения в Requests.

    Также, если вы используете polling для получения обновлений Bot API, то в продакшене лучше использовать веб-хуки.
    https://github.com/eternnoir/pyTelegramBotAPI/tree...
    Ответ написан
    Комментировать
  • Как упростить код?

    drygdryg
    @drygdryg
    Python-разработчик
    Использовать функцию sum и генераторы (generator expressions) для расчёта общего количества и общей стоимости:
    for good_name, good_id in goods.items():
        goodss = store[good_id]
        total_quantity = sum(i["quantity"] for i in goodss)
        total_price = sum(i["quantity"] * i["price"] for i in goodss)
        print(f"{good_name} - {total_quantity} штук, стоимость {total_price} рублей")
    Ответ написан
    Комментировать
  • FastApi StaticFiles не работает?

    drygdryg
    @drygdryg
    Python-разработчик
    app.mount("/sql_app", StaticFiles(directory=base_dir+"/static"), name="sql_app")

    Во-первых, никогда не соединяйте пути к файлам с помощью конкатенации: это может вызвать проблемы с безопасностью. Используйте для этого os.path.join():
    app.mount("/sql_app", StaticFiles(directory=os.path.join(base_dir, "/static")), name="sql_app")

    Во-вторых, нужно указать только путь к директории "static" относительно файла main.py, не указывая директорию с проектом (base_dir). Достаточно указать directory="static":
    app.mount("/sql_app", StaticFiles(directory="static"), name="sql_app")
    Ответ написан
    5 комментариев
  • Телеграм бот на Aiogram - как совместить работу entities и parse_mode?

    drygdryg
    @drygdryg
    Python-разработчик
    В официальной документации сказано, что parse_mode и entities взаимоисключаемые, т.е. возможно использовать только одно из них. Можно отказаться от parse_mode и использовать entities для вставки своей ссылки в конец сообщения как MessageEntity с типом "text_link", например, так:
    @dp.channel_post()
    async def redactor(message: types.Message):
        ent = message.entities
        new_ent = [e for e in ent if e.type != "text_link"]
        new_text = f'{message.text}\n'
        link_text = "text for link"
        link_address = "http://t.me/some_link"
        new_ent.append(types.MessageEntity(
            type="text_link", offset=len(new_text),
            length=len(link_text), url=link_address
        ))
        new_text = f'{new_text}{link_text}'
        await message.edit_text(new_text, entities=new_ent)

    Результат работы:
    636a70de08509412107858.png
    Ответ написан
    4 комментария
  • Как скомпилировать extractor для трово с гитхаба?

    drygdryg
    @drygdryg
    Python-разработчик
    В обсуждении на GitHub вам указали на то, что нужно установить версию yt-dlp, включающую исправление проблемы (PR: https://github.com/yt-dlp/yt-dlp/pull/4880). Судя по всему, это исправление уже вошло в версию 2022.10.04, которую вам просто нужно установить. Проверьте, какая установлена версия у вас сейчас командой:
    yt-dlp --version
    и обновите её при необходимости.
    Ответ написан
    Комментировать
  • Как присвоить значение списку по индексу, если данного индекса ещё не в списке?

    drygdryg
    @drygdryg
    Python-разработчик
    Используйте генератор списка:
    arr = [[] for _ in range(10)]  # Получится: [[], [], [], [], [], [], [], [], [], []]
    Ответ написан
    Комментировать
  • Почему при использовании оператора or в Пайтон, нарушается логика if?

    drygdryg
    @drygdryg
    Python-разработчик
    Потому что у оператора or меньший приоритет, чем у оператора ==. Сначала выполняется message.text == 'BLA', затем 'BLABLA' — последнее всегда расценивается как True (непустая строка). Можно расставить скобки для лучшего понимания приоритета выполнения:
    if (message.text == 'BLA') or 'BLABLA':
    Затем строку "BLABLA" можно заменить на True:
    if (message.text == 'BLA') or True:
    Это условное выражение всегда будет равно True.

    Скорее всего, вы хотели написать:
    if message.text == 'BLA' or message.text == 'BLABLA':

    Я заменил бы эти два условия кортежем с допустимыми значениями и оператором in:
    if message.text in ('BLA', 'BLABLA'):
    Ответ написан
    1 комментарий
  • Python телеграм бот telebot. Как циклично заполнить ReplyKeyboardMarkup из списка чтобы кнопки были горизонтально?

    drygdryg
    @drygdryg
    Python-разработчик
    Вместо
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    if len(list1) == 1:
         markup.row(list1[0])
    if len(list1) == 2:
         markup.row(list1[0], list1[1])
    if len(list1) == 3:
        markup.row(list1[0], list1[1], list1[2])

    используйте
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    markup.row(*list1)


    Подробнее про распаковку списков и применение символа * в Python можете прочитать здесь.
    Ответ написан
    2 комментария
  • Можно ли использовать «фишки» нового Python 3.11 в старых версиях?

    drygdryg
    @drygdryg
    Python-разработчик
    Возможно, вам подойдёт rich.traceback либо better-exceptions.
    https://habr.com/ru/company/wunderfund/blog/654991/
    Ответ написан
    Комментировать
  • Как узнать размер сообщения в байтах Aiogram Pyrhon?

    drygdryg
    @drygdryg
    Python-разработчик
    Получить текст сообщения как строку, затем закодировать её в кодировке UTF-8 (именно её использует Telegram в своём Bot API) и узнать длину получившейся байтовой строки. Можно написать для этого функцию:
    def text_size(text: str, encoding: str = 'utf-8') -> int:
        return len(text.encode(encoding))
    Ответ написан
    Комментировать
  • Можно ли в Pyppeteer использовать переменные?

    drygdryg
    @drygdryg
    Python-разработчик
    Вы смотрели в документацию для JavaScript-версии (Puppeteer), там в page.evaluate нужно передавать JavaScript-функцию или выражение. В Python-версии этот метод принимает строку с JS-кодом: https://miyakogi.github.io/pyppeteer/reference.htm...
    Здесь вы попытались смешать JS и Python — получилось что-то некорректное:
    page.evaluate((query), "console.log(query)", query)

    Вам следует подставлять переменные в строку с JS-кодом. Это можно сделать, например, с помощью f-строк:
    await page.evaluate(f'console.log("{query}")')
    Но учитывайте, что подстановка непроверенных данных в JS-код может вызвать проблемы с безопасностью (инъекции кода). Поэтому подставляйте значения в код только из проверенных источников или делайте валидацию значения перед подстановкой.
    Ответ написан
  • Как сделать проверку SQLite, Python?

    drygdryg
    @drygdryg
    Python-разработчик
    Когда вы уже создали таблицу и наполнили её данными о верификации чатов, при получении команды из какого-либо чата просто делайте запрос SELECT с нужным chat_id, и уже в коде Python проверяйте, какое значение у поля verification — не обязательно это делать средствами SQL.
    Ответ написан
    Комментировать
  • Как здесь правильно сгенерировать сигнатуру?

    drygdryg
    @drygdryg
    Python-разработчик
    В вашем коде на PHP для генерации подписи используются закодированные в JSON данные (функция json_encode). Но в Python-версии вы просто преобразуете словарь в строку (str(data).encode()), в результате чего получаете не JSON, а строковое представление (representation) словаря. Вам следует использовать модуль json для кодирования словаря в JSON:
    import hashlib
    import hmac
    import json
    
    secret_key = "6cc765db400218ab83394f4f3c8e00866b05a0vq"
    data = {
        'orderId': '6555214',
        'shopId': '4d499d82-2b99-4a7e-be26-5742c41e69e7'
    }
    signature = hmac.new(secret_key.encode(), json.dumps(data).encode(), hashlib.sha256).hexdigest()
    data['signature'] = signature

    Но если и это не даст желаемого результата, то обратите внимание на то, как работают кодировщики JSON в PHP и в Python, найдите различия. Возможно, в одном из них используются пробелы после разделителей, а в другом не используются — поэтому вы получаете разные JSON-строки для одних и тех же входных данных. В таком случае чтобы убрать пробелы после разделителей, нужно в json.encode нужно указать, какие использовать разделители (без пробелов):
    signature = hmac.new(secret_key.encode(), json.dumps(data, separators=(',', ':')).encode(), hashlib.sha256).hexdigest()
    Ответ написан
    1 комментарий
  • Как сделать запись вывода из консоли в файл по нажатию?

    drygdryg
    @drygdryg
    Python-разработчик
    Сохраняете перед выводом то, что выводите, в переменную, затем при нажатии клавиши записываете значение переменной в файл.
    Ответ написан
  • Почему телеграм бот (aiogram) не работает во время команды?

    drygdryg
    @drygdryg
    Python-разработчик
    Вы вызываете системную команду grep с помощью синхронной функции os.popen, из-за чего на время выполнения команды блокируется цикл событий asyncio, и ваш бот как бы зависает. Поэтому вам следует вызывать системные команды с помощью неблокирующей функции-корутины asyncio.create_subprocess_shell.
    https://stackoverflow.com/questions/63782892/using...
    Ответ написан
  • Почему телеграм бот на aiogram работает неправильно?

    drygdryg
    @drygdryg
    Python-разработчик
    Функция setRand() в вашем коде не изменяет глобальную переменную NUMBER, а лишь создаёт локальную переменную с таким же именем, перекрывающую глобальную переменную. Добавьте следующее в функцию, чтобы она изменяла значение глобальной переменной NUMBER:
    def setRand():
        global NUMBER
        NUMBER = random.randrange(10)
        print(NUMBER)


    Советую познакомиться с тем, как устроены области видимости в Python.
    Но, как упомянули в комментарии к вопросу, лучше не использовать механизм с глобальными переменными в этом коде, а найти более надёжное решение задачи. Думаю, что можно применить конечный автомат (FSM), который реализован в aiogram.
    Ответ написан
    Комментировать