• Как организовать клиент-клиент соединение на python через socket?

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

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала твоя лесенка из if-elif-elif-... - плохое решение.
    Сделай нормальную структуру данных вместо пачки переменных. Используй словарь, или ещё что. Например, такого вида:
    # словарь, где ключ - строка с названием пунка отправления, а значение - ещё словарь,
    #   где ключ - строка с названием пункта назначения, а значение - список,
    #     где элементы - пары строк ("время отправления", "время прибытия")
    # Тогда с таким словарём можно будет работать так:
    bus_timetable: dict[str, dict[str, list[tuple[str, str]]]] = {
        # ты словарь заполняешь по результатам парсинга, ну и то хорошо
        # я для примера запишу прямо так
        'Владимир' : {
            'Муром': [
                ('8:00', '11:00'),
                ('9:00', '12:00'),
                ('10:00', '13:00'),
            ],
        },
    }
    point_from = 'Владимир'
    point_to = 'Муром'
    # для примера вывожу в консоль, для бота перепишешь сам
    print(f'Автобус из {point_from} в {point_to}')  
    for departure, arrival in bus_timetable[point_from][point_to]:
        print(f'Отходит в {departure}, прибывает в {arrival}')

    Тогда тебе не потребуется делать кучу веток для разных городов, достаточно лишь определить значения point_from и point_to. Более того, ты можешь просто перечислить ключи внешнего словаря при создании кнопок:
    kbd_from = types.ReplyKeyboardMarkup(resize_keyboard=True)
    buttons = [types.KeyboardButton(point_from) for point_from in bus_timetable]  # список кнопок
    kbd_from.add(*buttons)  # если надо добавить все кнопки сразу

    Похожий приём возможен и для определения кнопок для городов назначения.

    А теперь по тому, как сделать выбор. Тут есть два варианта, но давай пока поговорим о ReplyKeyboardMarkup, которую ты используешь.
    Если ты хочешь использовать ReplyKeyboardMarkup, то стоит помнить - её кнопки дают тот же эффект, как если бы пользователь просто ввёл текст кнопки сам. Поэтому тебе потребуется использовать register_next_step_handler(). Ты не привёл код своей попытки, но в целом идея несложная. В основном обработчике события ты проверяешь, что текст сообщения содержится в bus_timetable (оператор in в помощь) - это значит, что текст сообщения содержит название известного боту города.
    Тогда ты делаешь вызов register_next_step_handler() и ставишь обработчик второго сообщения. Единственное "но": тебе нужно будет обработчику передать первый выбранный город. Это будет выглядеть как-то так:
    @bot.message_handler(content_types=['text'])
    def first_message_handler(message):
        if message.text in bus_timetable:  # назвали известный город? Это пункт отправления
            kbd = ...  # тут определяешь клавиатуру, опираясь на города в bus_timetable[message.text]
            response = bot.reply_to(message, "А теперь назовите пункт назначения", reply_markup=kbd)
            # обрати внимание: все параметры после указания функции second_message_handler будут
            # переданы в эту функцию при её вызове. А вызвана она будет, когда пользователь ответит.
            bot.register_next_step_handler(response, second_message_handler, message.text)
        elif ...  # нам назвали не город - тут можно проверить другие команды
    
    def second_message_handler(message, point_from):
        # а эта функция будет вызвана только когда пользователь уже назвал пункт отправления
        # point_from будет содержать название города, отправленное пользователем.
        if message.text in bus_timetable[point_from]:  # нам назвали допустимый пункт назначения
            bus_rides = bus_timetable[point_from][message.text]  # список рейсов
            ...  # дальше перебираем список bus_rides и выводим его пользователю
        else:  # пользователь назвал что-то другое
            ...  # говорим пользователю, что он дурак
    Ответ написан
    1 комментарий
  • Как определить область в потоке видео и среагировать на обнаружение?

    Vindicar
    @Vindicar
    RTFM!
    Ну так и скажи, "я хочу написать чит для Dead By Daylight, помогите!"
    Сделай полярное преобразование нужного куска экрана. Тогда нужная полоса превратится в вертикальную, и её легко можно будет выбрать обрезкой, а индикатор будет двигаться не по кругу, а по вертикали, и его движение будет проще анализировать.
    Впрочем, приколюхи вроде докторского безумия, которые меняет положение и направление движения индикатора, собьют твой алгоритм. А ещё есть скилл-чеки, у которых просто нет идеальной зоны, только хорошая.
    Ответ написан
    2 комментария
  • Как правильно проксировать запрос при коннекте к aiosmtplib?

    Vindicar
    @Vindicar
    RTFM!
    Погоди-ка, а параметр sock на что? Он есть и у функции send(), и у конструктора SMTP(). Подготовь запроксированный экземпляр socket.socket и отдай туда.
    Судя по упомянутому в комментах issue, нужно будет самому закрыть этот сокет, когда закончишь работу с SMTP.

    Нет, конечно, есть варианты жёстче. Например, отнаследоваться от SMTP, переопределить _create_connection(), и заменить/пропатчить self.loop так, чтобы вместо self.loop.create_connection() вызывалась твоя корутина. В ней уже формировать сокет как тебе надо.
    Но мне кажется, проще поработать с sock.
    Ответ написан
    Комментировать
  • Возможно ли создать асинхронную функцию чтобы отправлять в неё данные постепенно без await?

    Vindicar
    @Vindicar
    RTFM!
    asyncio.Queue в помощь. Чтобы синхронно помещать туда элементы, или используй put_nowait(), или выкручивайся с вызовом put() через create_task().

    Но у меня прямой вопрос: а как ты, собственно, собираешься выполнять синхронную g() в асинхронной программе? Потому что если через потоки, то про совет выше можешь забыть.
    Ответ написан
  • Как использовать SSH вместо VPN?

    Vindicar
    @Vindicar
    RTFM!
    А конфиг сервера позволяет динамический проброс портов (AllowTcpForwarding yes)? Там обновлений не было? Может, несколько конфигов конфликтуют? Например, в autorized_keys можно прописать no-port-forwarding или restrict.

    Ну и самая идея такая себе. Многие провайдеры шейпят SSH, жёстко ограничивая максимальную скорость - в терминале поработать можно, а как туннель использовать - нет. Так что даже если раньше работало, может перестать в любой момент.
    Ответ написан
    Комментировать
  • Почему Telegram бот не отвечает?

    Vindicar
    @Vindicar
    RTFM!
    Ну тебе же английским по белому написано:
    RuntimeError: This Application was not initialized via `Application.initialize`!

    Нужно перед вызовом application.start() добавить аналогичный вызов initialize().

    И да, ты пытаешься трогать элементы управления своего окна из другого потока. Так нельзя.
    Ответ написан
    Комментировать
  • Как в numpy максимально быстро изменить структуру данных в массиве?

    Vindicar
    @Vindicar
    RTFM!
    CUDA тут не нужна, просто не следует перебирать массив numpy питоновскими циклами.
    Если есть возможность - выражай желаемое через операции над массивом в целом. Тогда цикл организует numpy, и он это делает через нативный код, ЕМНИП - работает в разы быстрее.
    Подход ниже сожрёт больше памяти, но зато короткий, выразительный и использует только средства numpy.
    image = cv2.imread("image.png")
    image = image.astype(numpy.uint32)  # смена типа нужна, иначе при сдвиге потеряются разряды
    image_clone = (image[..., 0] << 16) | (image[..., 1] << 8) | image[..., 2]

    Если хочется заморочиться по памяти:
    image = cv2.imread("image.png")
    image_clone = numpy.zeros(image.shape[:2], numpy.uint32)
    # краткие формы операций не создают новый массив, а изменяют существующий по месту
    image_clone |= image[..., 0]
    image_clone <<= 8
    image_clone |= image[..., 1]
    image_clone <<= 8
    image_clone |= image[..., 2]


    P.S.: как там, у imread() починили уже неумение работать с юникодными путями?
    Ответ написан
    Комментировать
  • Как сделать чтобы дискорд бот сидел с телефона?

    Vindicar
    @Vindicar
    RTFM!
    Такой механизм не предусмотрен библиотекой. Быстрый гугл по discord.py phone status показывает, что для этого приходится патчить код класса discord.gateway.DiscordWebSoсket, чтобы при отправке пакета identify устройство/клиент идентифицировалось как 'Discord Android'.
    В связи с этим вопрос: тебе оно вот прямо нужно? Или это просто понты?
    Мненада!11

    Более-менее вменяемым (в плане риска что-то сломать при обновлении библиотеки) мне показался такой вариант со стэковерфлоу.
    from discord.gateway import DiscordWebSocket
    
    
    class MyDiscordWebSocket(DiscordWebSocket):
        async def send_as_json(self, data):
            if data.get('op') == self.IDENTIFY:
                if data.get('d', {}).get('properties', {}).get('$browser') is not None:
                    data['d']['properties']['$browser'] = 'Discord Android'
                    data['d']['properties']['$device'] = 'Discord Android'
            return await super().send_as_json(data)
    
    
    DiscordWebSocket.from_client = MyDiscordWebSocket.from_client

    Пробуй на свой страх и риск.


    И это, завязывай с упоминаниями юзеров в вопросах. Это хороший способ заставить людей тебя игнорировать.
    Ответ написан
    Комментировать
  • Почему возникает ошибка при создании Telegram бота?

    Vindicar
    @Vindicar
    RTFM!
    Открываем официальные примеры, находим простейший эхобот, и начинаем с него.
    В частности, смотрим, каким методом запускается работа бота.
    Спойлер
    bot.infinity_polling()
    Ответ написан
    Комментировать
  • Бот для уведомлений с ютуба не работает больше 3х дней, где я мог ошибиться?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, научись регистрировать проблемы. Почитай про logging, как его настраивать. Расставь в боте и в парсере try-except и записывай в лог возникающие ошибки. Тогда у тебя будет текст ошибки, с которым уже можно как-то работать.

    Но я подозреваю, что дело в доступе к базе Sqlite из двух процессов. Sqlite, в отличие от "взрослых" БД, не является ни процессо-, ни даже потоко-безопасной. К ней можно безопасно обращаться только строго по очереди.
    Как только звёзды сойдутся так, что оба твоих процесса обращаются к базе одновременно - кому-то из них не повезёт. Если не повезёт парсеру, ты просто не увидишь инфу о новом видео при этом запуске. Если не повезёт боту - бот упадёт.

    Тут вопрос такой: а нужна ли вообще тут БД? Если да, то для чего она нужна?
    yt-dlp, к сожалению, синхронный - но ты ведь можешь выполнять этот код через run_in_executor(). Тогда получится интегрировать парсер прямо в бот, и отправлять сообщения немедленно.

    Альтернативно, можно схитрить так: сделать боту учётку на ютубе, подписать его на нужные каналы и настроить уведомления о новых видео по почте, а в боте мониторить почтовый ящик через email-monitor или подобное.
    Ответ написан
    Комментировать
  • Если у человека нет определённой роли, как сделать так, чтобы другие определённые роли в таком случае отнимались?

    Vindicar
    @Vindicar
    RTFM!
    При снятии реакции снимать все последующие роли. Для этого обработчик события должен знать, какие роли последующие для какой реакции. Т.е. ты должен как-то это прописать.
    Ответ написан
    2 комментария
  • Зачем вообще нужна библиотека python turtle в реальной практике?

    Vindicar
    @Vindicar
    RTFM!
    Обучение. Многие языки для школьников основаны на принципе "черепашки". Сам начинал с LogoWriter и L-Graph, но есть и другие.
    А тут сразу можно привыкнуть к синтаксису питона, заодно.
    Ответ написан
    Комментировать
  • Как сделать кнопку в discord.py БЕЗ класса Client?

    Vindicar
    @Vindicar
    RTFM!
    Класс Bot - потомок класса Client, и может всё то же, что и Client.
    Bot в доках
    Represents a Discord bot.

    This class is a subclass of discord.Client and as a result anything that you can do with a discord.Client you can do with this bot.
    Ответ написан
  • Почему не получается закрыть окно в PyQt5?

    Vindicar
    @Vindicar
    RTFM!
    Ну у твоего класса действительно есть только метод setupUi(), и нет метода close(). Неудивительно, что Питон этот метод тоже не находит.
    Я с Qt не знаком, поэтому поинтересуюсь: а MyMindow точно должно наследоваться от object? Может, от какого другого класса?

    А вообще выглядит всё так, словно этому коду место в MainWindow.
    Ответ написан
    Комментировать
  • Как получить данные с сайта росреестра?

    Vindicar
    @Vindicar
    RTFM!
    Правило номер ноль при парсинге: при любых проблемах сохраняй на диск то, что тебе пришло в ответе от сервера.
    То, что ты видишь в браузере - это не обязательно то же самое, что браузер получил от сайта.
    То, что браузер получил от сайта - это не обязательно то же самое, что requests получит от сайта.

    В данном случае, и requests и браузер получают в ответе вот это:
    <body style="height: 100%; width:100%;">
    <div id=app style="height: 100%; width:100%;"></div>
    <script src=js/chunk-vendors.c1d200da.js></script>
    <script src=js/chunk-common.adcda62e.js></script>
    <script src=js/chunk-esri.caf28189.js></script>
    <script src=js/index.ca134891.js></script>
    </body>

    Как видишь, нужного элемента тут просто нет, потому что он создаётся динамически, через JavaScript. А BS не выполняет скрипты.

    Варианта только два:
    1. Выяснять, каким запросом сайт подтягивает данные для этого, научиться этот запрос делать самостоятельно и вытаскивать искомые данные из полученного. Медленно и трудно на подготовительном этапе, зато потом работает сравнительно быстро... если, конечно, сайт защиту от парсинга не поставит.
    2. Запускать управляемый браузер, дать ему загрузить страницу и выполнить скрипты, а потом уже искать нужные данные. Быстрое решение в плане разработки, но более медленное и ресурсоёмкое в дальнейшем использовании.
    Ответ написан
    Комментировать
  • Как отрыть ссылку с помощью flet с регистром?

    Vindicar
    @Vindicar
    RTFM!
    Твоя ссылка парсится так:
    1. nullsbrawl - схема
    2. createAndJoinRoom - адрес узла, точнее, доменное имя. Доменные имена не имеют регистра, насколько я знаю, т.е. habr.com и HABR.COM - одно и то же имя. Вероятно, поэтому оно и преобразуется в нижний регистр.
    3. пустой путь к ресурсу - подразумевается корневой ресурс
    4. всё, что после ? - параметры запроса

    Ты можешь попробовать изменить ссылку так: nullsbrawl:///createAndJoinRoom?....
    Обрати внимание на дополнительный слэш. Эта ссылка парсится так:
    1. nullsbrawl - схема
    2. адрес узла пустой
    3. createAndJoinRoom - путь к ресурсу на указанном узле. Пути регистрозависимы в URL, а потому его трогать не будут.
    4. всё, что после ? - параметры запроса
    Ответ написан
  • Почему питоновский скрипт сам по себе рабочий, а в виде службы - нет?

    Vindicar
    @Vindicar
    RTFM!
    Виртуальное окружение в проекте есть? Если да, то запускать скрипт надо не системным питоном, а питоном из этого окружения.
    EDIT1:
    Если из командной строки дать pyhon3 /home/lxm213/script.py, то скрипт работает штатно и без ошибок

    Т.е. скрипт запускаешь в системном окружении, а не в виртуальном. ОК, тогда по идее он должен работать...
    Но встаёт вопрос: как ты ставил schedule? Просто pip install schedule? Из-под рута ставил или с правами просто пользователя?
    Если ставил из-под рута, то библиотека будет установлена в системный интерпретатор и будет доступна всем пользователям.
    Если ставил не из-под рута, то, возможно, pip поставил её куда-то в твой домашний каталог - я знаю, что под виндой он так делает. Тогда библиотека доступна только если запускать скрипт из-под твоего пользователя.

    Отсюда три возможных решения:
    1. Создать виртуальное окружение для проекта, поставить библиотеку в это виртуальное окружение (используя местный pip), запускать скрипт через python3 из этого окружения.
    2. Если библиотека была поставлена без рут-прав, указать в .service-файле, что скрипт надо запускать от имени твоего пользователя, а не от имени root.
    3. Убедиться, что библиотека поставлена в системный интерпретатор. При необходимости поставить её с рут-правами. Тогда скрипт будет работать из-под любого пользователя.
    Ответ написан
    9 комментариев
  • Aiogram3.8.0 Как можно сделать команды, которые будут без префикса не используя startwith?

    Vindicar
    @Vindicar
    RTFM!
    # с пробелом - параметры, без пробела просто совпадение.
    if message.text.startswith('command' + ' ') or message.text == 'command':
        ...

    Ну и разумеется, это надо проверять не деревом if-elif-else, а чем-то более вменяемым, чтобы можно было сразу параметры разбирать.
    Ответ написан
    Комментировать
  • Обработка params ?fields в апи запросе для вывода в response?

    Vindicar
    @Vindicar
    RTFM!
    Рекурсивно делай. Опиши требуемую функцию:
    def filter_fields(obj: dict[str, ...], fields: list[str]) -> dict[str, ...]:
        """obj - фильтруемый словарь, fields - множество полей, которые надо оставить."""
        ...

    Проблема в том, что поля могут быть вложенным. Тогда первым делом составляешь набор нужных тебе полей верхнего уровня:
    top_level_fields = {}
    for f in fields:
        top, _, bottom = f.partition('.')
        top_level_fields.setdefault(top, [])
        if bottom is not None:
            top_level_fields[top].append(bottom)

    Для
    fields=['boardId', 'name', 'Data.Matches.t.id', 'Data.Matches.m']
    в top_level_fields получишь
    { 'boardId': [], 'name': [], 'Data': ['Matches.t.id', 'Matches.m']}

    Дальше перебираешь поля, собираешь их значения в один мешок и смотришь, есть ли для них нижележащие поля:
    output = {}
    for top, bottom in top_level_fields.items():
        if bottom:
            output[top] = filter_fields(obj[top], bottom)  # что делать, если ключа top нет?
        else:
            output[top] = obj[top]

    Таким образом наберёшь всё, что надо.
    Ответ написан
    Комментировать