Задать вопрос
  • Ошибка IndexError: list index out of range. Что делать?

    Vindicar
    @Vindicar
    RTFM!
    Включить голову и подумать, что же ещё.
    value = call.data.upper().split('/')
    Ты ожидаешь, что call.data будет содержать хотя бы один знак /, тогда value будет содержать два элемента - с индексом 0 и индексом 1. Раз IndexError, значит, скорее всего, value содержит только один элемент. А это слуится если call.data не содержит разделителя, в твоём случае /.
    b1 = types.InlineKeyboardButton('USD/EUR', callback_data='usdeur')

    Ну собственно, ты и задаёшь значения callback_data, не содержащие /. Вот и вся разгадка.
    Ответ написан
    Комментировать
  • Как сделать команду которую может использовать только владелец сервера?

    Vindicar
    @Vindicar
    RTFM!
    Читаем доки на has_guild_permissions().
    Similar to has_permissions(), but operates on guild wide permissions instead of the current channel permissions.


    "Работает похоже на has_permissions()"? Окей, тыц по ссылке.
    A check() that is added that checks if the member has all of the permissions necessary.
    Note that this check operates on the current channel permissions, not the guild wide permissions.
    The permissions passed in must be exactly like the properties shown under discord.Permissions.

    И пример кода
    @bot.command()
    @commands.has_permissions(manage_messages=True)  # имя параметра должно быть взято из discord.Permissions
    async def test(ctx):
        await ctx.send('You can manage messages.')

    Тыц по ссылке discord.Permissions, видим большоооой список разрешений. Читаем внимательно, owner нет, но в самом верху есть administrator.
    Значит, нужно has_guild_permissions(administrator=True).

    Делов на две минуты.
    Ответ написан
    1 комментарий
  • Как преобразовать html страницу в картинку на стороне сервера?

    Vindicar
    @Vindicar
    RTFM!
    а браузера на сервере не будет.

    Нет ножек - нет мультиков (с)
    Ты или используешь готовый движок HTML рендеринга и исполнения скриптов (т.е. браузер), или пишешь свой.
    Сразу скажу, последнее - нереально.

    Лучше зайди с другой стороны. Ты можешь использовать matplotlib для генерации статического изображения, так как он умеет не только графики, но и TeX-разметку для формул. А уже это изображение можно закэшировать и вставлять в HTML или в PDF, по желанию юзера.
    Ответ написан
    Комментировать
  • Какое различие между этими функциями?

    Vindicar
    @Vindicar
    RTFM!
    ЕМНИП, нормальное (второе) объявление будет автоматически поднято в начало текущего блока, что позволит вызывать функцию до её формального объявления.
    В первом случае это просто присваивание значения константе, а значит, функция будет доступна только ниже.
    Ответ написан
    Комментировать
  • Как сделать функцию горячих клавиш в telegram боте?

    Vindicar
    @Vindicar
    RTFM!
    Не надо пытаться описывать обработчик в обработчике. Это никогда не сработает так, как ты ожидаешь.
    Если бы дал себе труд погуглить, вышел бы на register_next_step_handler() и как им пользоваться.

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

    Vindicar
    @Vindicar
    RTFM!
    Ты просто не понимаешь сути первичного ключа.
    Это значение, которое однозначно идентифицирует строку, независимо от наличия и количества других строк в таблице. И точка. Он не должен меняться вообще за время жизни строки.
    Бывают случаи, когда у нас уже есть уникальное значение, которое можно использовать как ключ.
    Но куда чаще используются синтетические ключи, т.е. просто числа, которые пользователь по-хорошему и видеть-то не должен никогда. А раз так, то какая разница, есть ли дырки в нумерации?
    Я больше скажу, иногда сплошная нумерация - это слабое место в системе.
    Ответ написан
    Комментировать
  • Как реализовать передачу данных между компьютером и сервером?

    Vindicar
    @Vindicar
    RTFM!
    У пользователя белого IP не будет почти гарантированно, это не бесплатное удовольствие и далеко не все провайдеры его вообще предоставляют.
    PythonAnywhere также жёстко ограничивает адреса, на которые можно обращаться бесплатному аккаунту. Так что при таких вводных особо ничего не поделаешь.
    Хотя можно инвертировать - пусть пользовали стучатся на сервер по старому доброму HTTP, а твоё приложение это обслуживает.

    Вообще встаёт вопрос, а нахрена такая архитектура? Зачем пользователю вообще запускать у себя твоё приложение? Ботнет мутишь?
    Ответ написан
  • Почему не парсятся ссылки на python?

    Vindicar
    @Vindicar
    RTFM!
    Ну значит тут что-то накосячил:
    images = [img.strip() for img in lines[2][8:].split(',')]

    Не видя перед собой примера данных, трудно сказать что именно.

    EDIT: Проблема в строке lines = article.strip().split('\n')
    Ты почему-то думаешь, что у тебя весь текст статьи будет на одной строке. Это далеко не так.
    Единственный маркер, который у тебя есть - Images: в начале одной из строк. И да, если такое встретится в тексте статьи - парсер сломается.
    Ответ написан
    1 комментарий
  • Как войти в аккаунт на сайте с помощью python requests?

    Vindicar
    @Vindicar
    RTFM!
    Добавь заголовки запроса, в качестве реферера поставь тот же URL.
    Как это сделать, читай в доках requests.
    Ответ написан
    Комментировать
  • Почему то при запуске кода в pycharm срабатывает ошибка 0, и тг бот не реагирует на команды. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Учи азы программирования.
    Exit code 0 в практически любой операционной системе означает, что программа завершилась без ошибок. Это относится и к программам на питоне - они завершаются с кодом 0, если выполнение спокойно дошло до конца файла без непойманных исключений. Есть ещё функция sys.exit(), но про неё сам почитаешь.

    А в твоём случае ты накосячил в обёртке тела программы. Правильно будет
    if __name__ == "__main__":
    Тоже советую погуглить и почитать, что это, как работает, и зачем оно.
    Ответ написан
    5 комментариев
  • Не работают кнопки в discord.py, что делать?

    Vindicar
    @Vindicar
    RTFM!
    @Code.bot.command()
    На момент выполнения этого декоратора класс ещё не закончил создаваться, а значит, не был присвоен имени Code.
    Почитай документацию на либу, как правильно создавать коги и каким декоратором в них отмечать команды.
    Для discord.py это @commands.command().
    Ответ написан
  • Как вы боритесь с циклическими импортами в Python?

    Vindicar
    @Vindicar
    RTFM!
    Если речь идёт об импорте только ради type hinting, то typing.TYPE_CHEKING в помощь.
    Ответ написан
    Комментировать
  • Как обработку данных вывести в отдельный route?

    Vindicar
    @Vindicar
    RTFM!
    Код у тебя странный. asyncio.get_event_loop().run_forever() не будет вызвано, так как app.run() блокирует программу. run_ssh_command() использует asyncio только для ожидания. А смысл?

    Имей ввиду, Flask запускает каждый роут в отдельном event loop, так что фоновую задачу через create_task() запустить не выйдет.
    Тебе нужно будет запустить отдельный воркер в отдельном потоке. Задачей этого воркера будет выполнять ssh команды, а также сообщать текущий статус команды и результат её выполнения. Так что API у воркера должно быть несложное.
    Очередь (queue.Queue) команд принимает на вход описание команды, которую нужно выполнить, и какой-то ID запроса (чтобы понять, где чья команда).
    Воркер ждёт значение из очереди, выполняет команду, и помещает отклик команды в хранилище ответов вместе с ID. Соответственно должен быть метод, который по ID проверит наличие ответа в хранилище, и вернёт его, если он есть. Хранилище стоит защить мьютексом (threading.Lock), и время от времени чистить от старых ответов.

    Соответственно во Flask ты делаешь отдельный роут, который принимает ID запроса, и дергаёт этот метод воркера на предмет наличия ответа. А на стороне клиента дёргаешь этот роут периодически, пока не получишь ответ в удобном для тебя формате (например, JSON).
    Вот пример реализации воркера

    from typing import Union, Dict
    import threading
    import time
    import queue
    import uuid
    import paramiko
    
    
    class SSHWorker(threading.Thread):
        def __init__(self, hostname: str, username: str, password: str):
            super().__init__(daemon=True)
            self.__client = paramiko.SSHClient()
            self.__client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.__hostinfo = (hostname, username, password)  # если сохраним эти данные, можно будет сделать реконнект
            self.__commands = queue.Queue(maxsize=10)  # очередь на выполнение не более 10 команд
            self.__responses = {}  # ответы команд
            self.__response_lock = threading.Lock()
            self.__run = True  
        
        def add_command(self, command: str) -> Union[str, None]:
            """Добавляет в очередь команду и возвращает её уникальный id, если это прошло успешно. Иначе вернёт None."""
            cmdid = str(uuid.uuid4())
            try:
                self.__commands.put_nowait((cmdid, command))
            except queue.Full:
                return None
            else:
                return cmdid
        
        def check_command(self, cmdid: str) -> Union[dict, None]:
            """Проверяет, выполнилась ли команда. Вернёт None если нет, или ответ если да."""
            with self.__response_lock:
                return self.__responses.get(cmdid, default=None)
        
        def stop(self) -> None:
            """Говорит потоку остановиться. Фактическая остановка произойдёт позднее, смотря по таймауту ожидания команды."""
            self.__run = False
        
        def run(self) -> None:
            self.__client.connect(self.__hostinfo[0], username=self.__hostinfo[1], password=self.__hostinfo[2])
            while self.__run:
                try:
                    cmdid, command = self.__commands.get(timeout=5.0)  # есть ли команда в очереди?
                except queue.Empty:  # нет
                    # это позволяет остановить поток, если self.__run станет False, а также удалить старые незапрошенные ответы
                    too_old = time.monotonic() - 300.0  # удаляем все ответы старее 300 секунд, чтобы память не утекала
                    with self.__response_lock:
                        for cmdid, response in list(self.__responses.items()):
                            if response['timestamp'] < too_old:
                                del self.__responses[cmdid]
                else:  # что-то есть - выполняем
                    try:
                        stdin, stdout, stderr = self.__client.exec_command(f'/sbin/{command}', get_pty=True)
                        time.sleep(4.0)
                        response = stdout.read().decode('utf-8')
                    except Exception as err:
                        with self.__response_lock:
                            self.__responses[cmdid] = {'success': False, 'error': f'[{err.__class__.__name__}]: {err!s}', 'timestamp': time.monotonic()}
                    else:
                        with self.__response_lock:
                            self.__responses[cmdid] = {'success': True, 'output': response, 'timestamp': time.monotonic()}
                    self.__commands.task_done()


    Ну и да, ты спалил данные SSH. =)
    Ответ написан
  • Есть ли способ аннотировать аргументы метода переменной класса?

    Vindicar
    @Vindicar
    RTFM!
    Если у тебя config может различаться во время выполнения, то нельзя. Статический анализ не выполняет анализируемый код.
    Ответ написан
  • Почему бот телеграмма завершается сам по себе?

    Vindicar
    @Vindicar
    RTFM!
    У тебя bot.polling() почему-то с отступом. Как будто он внутри save_vk_id_to_database().
    Проверь код ещё раз. Отступы в питоне критичны!
    Ответ написан
    Комментировать
  • Как заставить клиента ждать запуска сервера?

    Vindicar
    @Vindicar
    RTFM!
    Ну если простейшее решение...
    Таймаут на connect(), connect() завернуть в try-except, который ловит socket.timeout и спит несколько секунд. Всё это завернуть в while True.
    Ответ написан
    Комментировать
  • Как устроена бибилотека aiogram внутри а именно FSM?

    Vindicar
    @Vindicar
    RTFM!
    Ну конкретно по вопросу: можно сделать обоснованную догадку, если знаком с понятием "конечный автомат".
    Это нечто, обладающее набором состояний. В рамках состояния автомат выполняет определённую деятельность и/или ждёт определённого события.
    Автомат может переходить из состояния в состояние по внешнему сигналу. При этом правила перехода зависят от сигнала И от состояния. Иными словами, автомат может реагировать по разному на один и тот же сигнал, в зависимости от своего состояния.

    Пример: часы-будильник. У них могут быть четыре состояния:
    - будильник выключен (только часы)
    - будильник включен (ожидание времени следующего звонка)
    - звучит звонок
    - досыпание
    И три события:
    - сменилась минута
    - пользователь нажал кнопку "вкл-выкл"
    - пользователь нажал кнопку досыпания
    Схему переходов между состояниями можешь придумать сам. В частности, событие "сменилась минута" будет обрабатываться по-разному в каждом из состояний.

    Это базовое понятие. В твоём случае автомат - это StateGroup, его отдельные состояние - это State, а сигналы - события бота, привязанные к автомату. Важно понимать, что у тебя, скорее всего, будет много копий автомата - по одной на каждого пользователя.

    Далее возникает вопрос: а что если нам нужно передавать какие-то данные из состояния в состояние? Вот тут возникает понятие контекста автомата, т.е. какого-то набора данных, которые могут читаться и изменяться при его работе. Это FSMContext.

    Наконец, сугубо практический вопрос: автомат должен "помнить", в каком он состоянии, и должен хранить свой контекст. Где он будет это делать? Вот тут на помощь приходят классы Storage. В частности, MemoryStorage хранит эти данные в памяти. Ненадёжно, не переживает перезапуск бота, но работает быстро и удобно при отладке.

    Попробуй реализовать очень простого бота с автоматом состояний, не используя State, а храня состояние для пользователя самостоятельно. Например, в словаре вида userid: (состояние, контекст). И проверяй вручную состояние и контекст при обработке событий. Тогда поймёшь, что примерно происходит внутри FSM.
    Ответ написан
    2 комментария
  • Проблема с этим Введите корректный числовой код?

    Vindicar
    @Vindicar
    RTFM!
    Используй user: disnake.Member вместо id: int, удобнее будет. И почитай доки на тему.
    Ответ написан
  • В чем заключается ошибка и как ее исправить?

    Vindicar
    @Vindicar
    RTFM!
    Дополню ответ Сергей Горностаев
    cursor2.execute("SELECT sneakers_model FROM user_inventory WHERE sneakers_model = ?", (random_sneakers[0]))

    А надо
    cursor2.execute("SELECT sneakers_model FROM user_inventory WHERE sneakers_model = ?", (random_sneakers[0],))

    Без запятой у тебя просто строка передаётся, и поэтому функция каждый символ считает за отдельное значение. Вот и получается 17 символов в строке = 17 значений, а место одно.
    С запятой ты передаёшь кортеж из одной строки. Одна строка - одно место.
    Ответ написан
    Комментировать
  • Кнопка и окно ввода в разных классах, не получается добавить кнопке возможность вставлять знаки в Entry объект?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, какой виджет за что отвечает? Что такое inputBox? В чём его роль? В идеале одним предложением.

    Во-вторых, не следует лазать в кишки класса без нужды. Вместо этого имеет смысл добавить этому классу удобный метод, который сделает всё что нужно, с пониманием внутреннего устройства класса. Тогда те, кто класс использует, не должны будут знать его внутреннее устройство - только его видимый интерфейс (методы, свойства). Это называется инкапсуляция.
    Ответ написан
    2 комментария