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

    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 комментария
  • Как сделать поиск папки у которой будет промежуточный каталог?

    Vindicar
    @Vindicar
    RTFM!
    Рекурсивно перебирать все каталоги, для каждого каталога проверять совпадение пути с шаблоном.
    Ответ написан
    Комментировать
  • Можно ли в питоне с помощью модуля ctypes (или как-то по-другому) создать указатель на любой объект?

    Vindicar
    @Vindicar
    RTFM!
    Тебе не нужен для этого ctypes, просто присвой атрибут классу.
    class Test:
        def test(self):
            print(f"It's a-me, {self!r}!")
    
    
    t = Test()
    t.test()
    
    def alt(instance):
        print(f"My name is {instance}. You killed my parent process. Prepare to die.")
    
    
    Test.test = alt
    
    t.test()


    Правда, с builtin классами такое не прокатит.
    Ответ написан
  • Почему возникает ошибка при работе с Python и OpenCV?

    Vindicar
    @Vindicar
    RTFM!
    1. Не принимать предупреждения за ошибки.
    2. Работать на машине, где видяха поддерживает одну из указанных библиотек, и поставить на неё эту библиотеку.
    Ответ написан
    Комментировать
  • Как работает annotated-types в пределах Pydantic?

    Vindicar
    @Vindicar
    RTFM!
    Насколько я понял, annotated-types просто задаёт стандарт для описания правил валидации полей, и способ получения этого описания для класса. А уж как это описание будет использоваться, должна решать конкретная библиотека, которая этому стандарту следует. Т.е. annotated-types сам по себе ничего не проверяет.
    Впрочем, в тестах у них есть примитивный пример реализации.
    Ответ написан
    Комментировать
  • Как сделать так чтобы в scrapy, парсились дубликаты ссылок? То есть так чтобы каждая спаршенная ссылка, должна создать уникальный файл. Как?

    Vindicar
    @Vindicar
    RTFM!
    Перед открытием файла проверяй, существует ли он. Если существует, добавляй числовой суффикс, пока не найдёшь свободное имя. Для простоты можешь оформить это в виде функции, которая принимает исходное имя файла, а возвращает либо его же, либо скорректированный вариант.
    Для реализации pathlib в помощь.
    Ответ написан
    2 комментария
  • Можно ли задать несколько вариантов обработки для одного типа исключения?

    Vindicar
    @Vindicar
    RTFM!
    Подумай сам. Как питон поймёт, какой сценарий нужно вызывать? У него фактически есть только два ориентира - блок try, в котором произошло исключение, и класс исключения.
    Ответ написан
    Комментировать