• Как правильно реализовать очередь?

    Vindicar
    @Vindicar
    RTFM!
    Я вижу в тегах aiohttp, так что предполагаю, что код у тебя асинхронный.
    Мне тут как-то доводилось отвечать на подобный вопрос, может, и тебе пригодится...
    Идея простая - ты держишь долгоиграющую задачу, которая мониторит очередь запросов, и выбирает запросы из очереди один за другим. При этом каждый элемент очереди содержит future, в которое будет помещен результат работы корутины, и которое получает код, обратившийся к ресурсу.
    Я попробовал оформить это в виде декоратора, который автоматически троттлит обращения к функции. Возможно, код неоптимален, и его придётся допилить.
    Код

    import typing
    import asyncio
    import functools
    
    
    def throttled(delay: float, measure: typing.Literal['end_to_start', 'start_to_start'] = 'start_to_start'):
        def decorator(actual_func: typing.Coroutine) -> typing.Coroutine:
            queue = None
            task = None
            
            async def _single_query(future, args, kwargs):
                try:
                    result = await actual_func(*args, **kwargs)  # тут делаем асинхронное обращение к сервису
                except BaseException as err:
                    future.set_exception(err)  # была ошибка - теперь await future выкинет исключение
                else:
                    future.set_result(result)  # полуен результат - await future вернёт его
            
            async def _work_loop():
                nonlocal queue
                nonlocal task
                while True:
                    try:
                        # ждем, пока не придёт запрос, или пока не закончится таймаут
                        future, args, kwargs = await asyncio.wait_for(queue.get(), delay)
                    except asyncio.TimeoutError:  # новые запросы долго не приходят, сворачиваем работу, чтобы не тратить ресурсы
                        queue = None
                        task = None
                        return
                    single_task = _single_query(future, args, kwargs)
                    if measure == 'start_to_start':
                        asyncio.create_task(single_task)
                    else:
                        await single_task
                    queue.task_done()  # каждому успешному get() соответствует task_done()
                    await asyncio.sleep(delay)
            
            @functools.wraps(actual_func)
            async def query(*args, **kwargs):
                nonlocal queue  # обращение к переменной выше уровнем, но не глобальной
                nonlocal task
                future = asyncio.Future()  # Future просигналит, когда наш запрос будет обслужен
                if task is None:  # либо это первый запрос, либо запросы долго не приходили, и мы свернули работу
                    queue = asyncio.Queue()
                    task = asyncio.create_task(_work_loop())
                await queue.put((future, args, kwargs))
                return await future
            
            return query
        
        return decorator



    Пример использования:
    # delay - минимальный интервал между запросами в секундах
    # measure - как мерять интервалы между запросами: начало-начало или конец-начало
    @throttled(delay=5.0, measure='start_to_start')
    async def my_coroutine(*args, **kwargs) -> ReturnValue:
        ...

    При этом если задекорировать несколько функций, каждая из них будет иметь свою очередь задач.
    Минус - задача мониторинга будет висеть некоторое время после последнего запроса. А именно, пока таймаут между запросами не истечет.
    Ответ написан
    3 комментария
  • Почему энтри объект игнорирует запросы?

    Vindicar
    @Vindicar
    RTFM!
    зашитая в кнопку команда объектом энтри игнорируется

    Ты в обработчике кнопки сам создаёшь новый экземпляр класса Put_Entry (который является виджетом), нигде его не размещаешь, а просто что-то с ним делаешь. Конечно, уже существующие экземпляры от этого никак не изменяются - твоя кнопка про них ничего не знает и никак их не трогает.

    Короче, читай учебник, для начала. У тебя, похоже, полнейшая каша в голове. Разбирайся в понятиях области видимости и времени жизни, для начала - тогда будет понятнее, что где хранить и что куда передавать.
    Не говоря уже о том, что я тебе уже два раза показывал, как хоть немного правильно создавать свои UI-классы, но как об стенку горох.
    Ответ написан
    4 комментария
  • Данные из буфера не обновляются, что сделать?

    Vindicar
    @Vindicar
    RTFM!
    Сейчас код сначала получает текст, содержащий координаты точек из буфера обмена, потом разбирает и проверяет каждую строку и переспрашивает нужна ли она, а потом уже входит в цикл while True, где он их прокликивает и ожидает нажатия w или q.
    Нужно всю ту часть, где определяются координаты, а также сам код прокликивания внести внутрь ветки w.

    Как именно - спрашивай у того, кто написал код.
    Ответ написан
    Комментировать
  • Как раскодировать hex строку зная на какие размеры разбиты в ней данные?

    Vindicar
    @Vindicar
    RTFM!
    В hex один байт - всегда два символа. Я бы сделал byte_list = hex_string.split(':'), тогда можно будет прочитать i-й байт как int(byte_list[i], 16)
    Ответ написан
  • Как реализовать перенос строки MarkdownV2?

    Vindicar
    @Vindicar
    RTFM!
    https://www.markdownguide.org/basic-syntax/#line-breaks
    To create a line break or new line (<br>), end a line with two or more spaces, and then type return.

    Попробуй два пробела перед переносом строки, т.е. ' \n'
    Ответ написан
    Комментировать
  • Как выйти из цикла в другой функции?

    Vindicar
    @Vindicar
    RTFM!
    Никак*. Осознай, что операторы выполняются последовательно. Пока start_stop(True) не закончит выполнение, time.sleep() даже не начнёт выполняться, не говоря уже о последующем. А start_stop(True) не закончит выполнение никогда, потому что ты сделал вечный цикл.

    Также меня несколько настораживает поставленный тобой тег aiogram, потому что использование time.sleep() в асинхронных приложениях - плохая идея. Это наводит на мысль, что тебе стоит сначала понять как следует работу асинхронных приложений. Вот одиндругой) из моих старых ответов, может поможет начать.
    *

    Можно организовать несколько потоков выполнения через threading или же вести асинхронную разработку на корутинах. Смешивать эти два подхода очень не советую, так что сначала определись, который использовать.
    Ответ написан
    3 комментария
  • Как отложить выполнение функции в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Создай через create_task() долго работающую задачу, которая будет периодически опрашивать запланированные расссылки, искать те, которые "уже пора" и запускать их на выполнение. А потом спать некоторое время до очередной проверки. Эта задача должна стартовать параллельно с ботом.
    Такой способ может вносить погрешность в точное время рассылки (условно, проверяешь раз в час - время можно задать только с точностью до часа). Но зато он гораздо менее рискован. Упрощённо, если ты сделал await asyncio.sleep(сколько_нужно), а за это время бот упал и был перезапущен, бот просто не "вспомнит" о ранее запланированных, но не выполненных рассылках.
    Ответ написан
    Комментировать
  • Как сделать проверку роли у пользователя и выдачи второй роли, если первая роль есть?

    Vindicar
    @Vindicar
    RTFM!
    Программа не работает как именно? Отсутствие реакции? Сообщение об ошибке? Комп встаёт со стола и идёт искать Сару Коннор?
    Далее, ты проверил, on_guild_update() вообще вызывается? Хотя бы временный print() в начало вставь.
    Потому что если почитать документацию, там английским по белому написано:
    This requires Intents.guilds to be enabled.

    Какие интенты ты задаёшь боту?

    Ещё важнее: а причём тут вообще on_guild_update()? Это событие отрабатывает, когда изменяются настройки сервера, а из твоего описания следует, что тебя интересуют роли участников. За это отвечает on_member_update().

    Короче, нужно прояснить происходящее.
    Ответ написан
    Комментировать
  • Как выделить память по заданному адресу?

    Vindicar
    @Vindicar
    RTFM!
    Первый вопрос: а на кой тебе это?
    Второй вопрос: ты имеешь ввиду логический адрес, или физический?

    Если логический, то дёрни функцию WinAPI VirtualAlloc(). Но имей ввиду две вещи:
    1. Адрес будет округлён вниз до размера страницы памяти, т.е. твой искомый адрес может оказаться в середине страницы или даже ближе к концу. Возможно, стоит выделить память с запасом.
    2. Разумеется, если одна из запрошенных тобой страниц уже занята какой-то памятью, то ничего не поделаешь.

    Память по фиксированному физическому адресу для клиентского приложения выделить нереально. Тут скорее нужно драйвер писать.
    Ответ написан
    Комментировать
  • Как понять когда ставить пробел в строках,а когда нет в Питоне?

    Vindicar
    @Vindicar
    RTFM!
    Дополню ответ выше: для print() поведение можно настроить параметром sep. Например:
    print(1, 2, 3)  # 1 2 3
    print(1, 2, 3, sep='')  # 123
    print(1, 2, 3, sep=', ')  # 1, 2, 3

    А еще есть параметр end:
    print(1, 2, 3)  # 1 2 3 с переводом на новую строку
    print(1, 2, 3, end='')  # 1 2 3 без перевода на новую строку
    print(1, 2, 3, end=':')  # 1 2 3: без перевода на новую строку

    Так что строку, выводимую print(*args), можно описать так:
    sep.join(str(arg) for arg in args) + end
    Ответ написан
    1 комментарий
  • Выводит ошибку, как можно исправить? (Error code: 400. Description: Bad Request: chat not found)?

    Vindicar
    @Vindicar
    RTFM!
    Как читать трейсбэк? Он состоит из записей вида:
    v                         в каком файле ошибка                           v   v строка v    v     функция    v
    File "/home/maksim/.local/lib/python3.10/site-packages/telebot/__init__.py", line 1074, in __threaded_polling
    self.worker_pool.raise_exceptions()
    ^   оператор, вызвавший ошибку    ^

    Смотрим записи по одной, сверу вниз, и ищем те, которые относятся к твоему коду. У тебя только одна такая запись:
    File "/home/maksim/Загрузки/Python/Квест/Квест.py", line 33, in questions
    bot.send_message(_id, 'Комфортно ли вам находиться в обществе?', reply_markup=markup)

    Почему именно эта? Потому что только в ней путь к файлу не ссылается на lib/python
    Значит, ошибка именно в строке
    bot.send_message(_id, 'Комфортно ли вам находиться в обществе?', reply_markup=markup)

    Текст ошибки звучит как chat not found. Т.е. не найден чат с таким идентификатором, который ту указал. А значит, в переменной _id содержится неправильное значение. Выясняй, как оно туда попало.
    Ответ написан
    Комментировать
  • Как можно исправить странную ошибку в коде python?

    Vindicar
    @Vindicar
    RTFM!
    description(400)
    это что?

    EDIT: а не, SQLite такое позволяет. У тебя ошибка в другом месте:
    category_id INTEGER NO NULL
    "NOT NULL", а не "NO NULL"
    Ответ написан
  • Как в Python можно изменить запись в CSV?

    Vindicar
    @Vindicar
    RTFM!
    Нет, по-простому нельзя. Единственный простой подход (который показал выше Максим Припадчев) - загрузить целиком в память, там изменить, потом выгрузить назад. Для больших CSV файлов это ресурсоёмко.

    CSV вообще не предназначен для долговременного хранения данных - скорее, для импорта/экспорта.

    Ты мог бы попытаться использовать методы tell() и seek(), чтобы "запомнить" позицию удаляемой строки, а затем в цикле копировать всё что идёт после, "пододвинув" содержимое внутри файла, а потом уже дописать в конец изменённую строку. Но это всё равно долго.

    Лучше импортируй файл в базу SQLite, и работай в дальнейшем уже с ней.
    Ответ написан
    3 комментария
  • Как произвольно трансформировать изображение в Python?

    Vindicar
    @Vindicar
    RTFM!
    Скажи спасибо, что я делал такую лабораторную работу X)
    Код
    # -*- coding: utf-8 -*-
    import sys
    import numpy  # pip install numpy
    import cv2  # pip install opencv-python
    
    def loadImg(fname : str) -> numpy.ndarray:  # грузит файл
        data = numpy.fromfile(fname, dtype=numpy.uint8)
        img = cv2.imdecode(data, cv2.IMREAD_COLOR)
        if img is None:
            raise IOError("Not an image file")
        return img
    
    class Clicker:  # класс для выбора точек на экране
        def __init__(self, name: str, image: numpy.ndarray):
            self.wnd = name
            self.image = image
            self.clicks = []
            self.markersize = 5
            self.markercolor = (255,0,255)
            cv2.namedWindow(self.wnd, cv2.WINDOW_AUTOSIZE)
            cv2.setMouseCallback(self.wnd, self._click)
        
        def draw(self):  # рисует точки на изображении и выводит их на экран
            copy = self.image.copy()
            color = self.markercolor
            radius = self.markersize
            for x,y in self.clicks:
                cv2.circle(copy, (x,y), radius, color, 1)
                cv2.line(copy, (x-radius,y), (x+radius,y), color, 1)
                cv2.line(copy, (x,y-radius), (x,y+radius), color, 1)
            cv2.imshow(self.wnd, copy)
        
        def _click(self, event, x, y, flags, param):
            if event == cv2.EVENT_LBUTTONDOWN:  # левый клик - поставить точку
                self.clicks.append((x,y))
            elif event == cv2.EVENT_RBUTTONDOWN:  # правый клик - сбросить последнюю точку
                if self.clicks:
                    del self.clicks[-1]
            else:
                return
            self.draw()
        
        def close(self):
            cv2.destroyWindow(self.wnd)
        
        def __enter__(self):
            self.draw()
            return self
        
        def __exit__(self, exctype, excvalue, traceback):
            self.close()
    
    try:
        image = loadImg('times-square.jpg')  # изображение, внутрь которого вписываем другое
        poster = loadImg('lena.png')  # изображение, которое вписываем в первое
    except IOError:
        print('Ошибка загрузки файла.')
        sys.exit(1)
    # эта часть только для ручного ввода координат
    # если они уже есть, то это не нужно.
    with Clicker('Select area', image) as clicker:
        # четыре точки ставятся строго по часовой, начиная слева-сверху 
        while len(clicker.clicks) < 4:  # пока не получили четыре точки - угла
            if cv2.waitKey(100) == 27:
                print('Отменено')
                sys.exit(0)
        pts = numpy.array(clicker.clicks, dtype=numpy.float32)  # координаты углов тут
    # вписываем изображение
    height, width = poster.shape[:2]
    srcpoints = numpy.array([  # углы вставляемого изображения в том же порядке по часовой
        (0,0),
        (width-1, 0),
        (width-1, height-1),
        (0, height-1),
    ], dtype=numpy.float32)
    # матрица преобразования сопоставляет четыре точки второго изображения с точками первого
    # по сути, она позволяет перейти от второго изображения к первому
    matrix = cv2.getPerspectiveTransform(srcpoints, pts)  # порядок аргументов важен, иначе переход будет наоборот
    # применяем матрицу ко второму изображению. Но теперь надо убрать чёрные поля.
    warped = cv2.warpPerspective(poster, matrix, (image.shape[1], image.shape[0]))
    # делаем маску для переноса пикселей с warped на image
    # мы хотим перенести только пиксели, на которые пришлись пиксели второго изображения
    mask = numpy.zeros(image.shape, dtype=numpy.uint8)  # рисовать можно только на обычном изображении
    # закрашиваем пиксели внутри выбранного ранее четырёхугольника
    cv2.fillPoly(mask, pts.reshape(1, -1, 2).astype(numpy.int32), (1,1,1))
    mask.dtype = bool  # а для переноса нам нужна логическая маска
    # маска готова, переносим. numpy рулит, правда ведь?
    image[mask] = warped[mask]
    # показываем результат
    cv2.imshow('Result', image)
    cv2.waitKey()


    Если коротко: находишь точки, которым надо сопоставить углы "вставыша". Перечисляешь их в том же порядке, что и эти углы. Находишь матрицу перспективного преобразования. Применяешь матрицу к вставышу, получаешь чёрное изображение, на котором вставыш расположен в нужном месте. Переносишь пиксели с этого изображения на картинку с экраном.
    Ответ написан
    3 комментария
  • При запуске элементарного кода(правильного) на vkbottle выдает огромное количество ошибок. Что делать?

    Vindicar
    @Vindicar
    RTFM!
    aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host api.vk.com:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1002)')]

    У тебя или провайдер сильно хитропопый, или вирусня на компе. Самоподписанных сертификатов в цепочке сертификатов для любого нормального сайта быть не должно и точка, а для контакта тем более. Так что кто-то пытается перехватить соединение. Кто - без понятия. Проверь на заведомо чистой машине и работая через VPN, также проверь список установленных корневых сертификатов, нет ли там чего странного. Как - написано в гугле.
    Ответ написан
  • Часто ли телеграм боты подвергаются атакам и как вы этого избегаете?

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала что значит "атака"? Какую угрозу ты ожидаешь? Потому что ответы будут ОЧЕНЬ разные в зависимости от этого.

    IP бота можно будет попробовать узнать, если ты знаешь, что бот проходит по ссылкам, которые ты можешь ему отправить. Тогда, скинув боту ссылку на свой сайт, можно будет посмотреть, какие адреса заходили в этот момент.
    Если бот такого не делает, то скорее всего никак.

    Зафлудить бота запросами? С одного аккаунта не получится, а с многих - недёшево. Кому ты нужен за такие деньги?

    Потыкать команды бота на пример SQL-инъекции? Если бот вообще использует БД, достаточно использовать стандартные средства подстановки параметров в запросы, а не колхозить SQL чере зформатирование строк.

    Угнать бота? Не пости его токен никуда. Если хранишь исходный код в какой-то системе хранения версий - храни токен в отдельном файле и добавь его в исключения. Если есть подозрение, что токен уже уплыл - меняй его у BotFather. А угон акка разработчика - это другая песня уже.

    Короче, ответь хотя бы для себя на вопросы:
    1. чего конкретно боишься?
    2. кому конкретно ты нужен?
    Ответ написан
    2 комментария
  • Что делать если не загружается кога discord.py?

    Vindicar
    @Vindicar
    RTFM!
    for filename in os.listdir("./cogs"):
    Ты ищешь подкаталог cogs в текущем рабочем каталоге программы.
    Это не то же самое, что и каталог, где находится программа.
    Ты уверен, что у тебя путь к нужному каталогу?
    from pathlib import Path
    import sys
    # каталог скрипта
    SCRIPT_DIR = Path(sys.argv[0]).parent.resolve()
    # каталог с когами
    COGS_DIR = SCRIPT_DIR / 'cogs'
    # список имён когов
    COGS = [f.stem for f in COGS_DIR.glob('*.py')]
    Ответ написан
    Комментировать
  • Как верно настроить вероятность в мини - игре?

    Vindicar
    @Vindicar
    RTFM!
    0. Главное: вопрос у тебя звучит "Как верно настроить вероятность". В коде ровно одна строчка с random, и ты не объясняешь что она делает. Собственно, и правила игры (т.е. желаемое поведение кода) ты не озвучил. Что такое "подкрутка"? Что тут посоветуешь...
    1. Если ты ловишь себя на том, что создаёшь переменные вида mine_3, mine_4, mine_5, а дальше делаешь x = eval(f"mine_{mines_kolv}[{now_state}]") тебе нужна индексируемая коллекция! Список или кортеж. Тем более что списки ты уже используешь, значит, знаешь, что это такое. Неужели "список из списков" - это такая сложная концепция?
    2. У тебя в самом первом SQL-запросе подстановка параметров выполняется корректно, а дальше идёт ересь с использованием %-форматирования. Не надо так.
    3. У тебя куча таблиц, из которых ты вытаскиваешь по одному значению. Если эти значения всегда требуются вместе, почему не объединить их в одну таблицу?

    Короче, лучшее, что тут можно посоветовать - выкинуть этот код полностью (он исправлению не поддаётся), отложить бота, подучить язык и его средства, в частности, структуры данных и приёмы работы с ними. А потом уже вернуться к боту. Так хотя бы не будешь спотыкаться на простых операциях.
    Ответ написан
    Комментировать
  • Почему не удаётся найти путь?

    Vindicar
    @Vindicar
    RTFM!
    AudioSegment.converter = f"{os.getcwd()}\\ffmpeg.exe"

    Ты уверен, что файл лежит в текущем каталоге? Это не то же самое, что каталог программы.
    Если тебе нужен каталог программы, лучше его и взять:
    from pathlib import Path
    import sys 
    
    SCRIPT_DIR = Path(sys.argv[0]).parent.resolve()
    FFMPEG = SCRIPT_DIR / 'ffmpeg.exe'  # чтобы не париться с разделителем каталогов (/ или \)
    Ответ написан
    Комментировать