Задать вопрос
  • Как исправить ошибку взаемодействия Дискорд бота и окна?

    Vindicar
    @Vindicar
    RTFM!
    #
        loop = asyncio.get_event_loop()
        loop.create_task(process_bot_queue())
        loop.run_forever()

    Что вообще вот этот код делает в теле программы, если у тебя вызов create_window() не вернёт управление, пока окно GUI не будет закрыто?
    Ответ написан
    Комментировать
  • Можно ли поставить паузу и продолжить?

    Vindicar
    @Vindicar
    RTFM!
    цикл for, функция range(), функция time.sleep()
    Ответ написан
    Комментировать
  • Не меняется параметр call.data в тг-боте, почему и где я допустил ошибку?

    Vindicar
    @Vindicar
    RTFM!
    @dp.callback_query_handler()
    async def callback(call):
      await call.message.answer(f'Понял Принял! Теперь напиши пожалуйста, в каком городе будем смотреть {call.data}')
      print(call.data)
      @dp.message_handler(content_types=['text'])  # обработчик событий объявлен внутри другого?
      async def city(message: types.Message):

    Это НЕ будет работать так, как ты ожидаешь. При каждом выполнении callback() будет попытка добавить ещё один обработчик, но предыдущие обработчики так и останутся. А поскольку вызывается обычно только самый первый обработчик, то только самый первый вариант и будет обрабатываться.

    Открой для себя Finite State Machine, ну и в целом получи хоть какое-то представление как работает используемая тобой библиотека, что в ней можно делать, а что нельзя.
    Ответ написан
  • Как исправить ошибку взаимодействия окна и дискорд бота?

    Vindicar
    @Vindicar
    RTFM!
    В коде нет работы с потоками, ты даже не импортируешь threading.
    Нужно понимать три вещи:
    1. Рабочий цикл бота займёт весь поток, равно как и рабочий цикл tkinter. Совместить их практически невозможно (технически можно, но это очень нетривиально).
    2. Элементы GUI должны создаваться и использоваться строго в одном и том же потоке.
    3. Нельзя делать await вызовы из одного потока в другой.

    Поэтому я бы посоветовал такое грубое, но простое решение:
    В одном потоке потоке создавай event loop (сам! это важно!) и запускай бота. В другом потоке создавай и запускай GUI.
    Какой поток должен быть главным - скорее всего не принципиально. Попробуй оба варианта.
    Используй пару очередей (queue.Queue) для синхронизации между потоками.

    Одна очередь будет периодически проверяться в потоке GUI с помощью root.after(). Почитай документацию на этот метод, но если коротко - он позволяет запланировать вызов функции в потоке GUI через время. Эта очередь будет содержать сведения о том, что нужно обновить в GUI.
    Формат и смысл сведений определи сам. Это может быть что-то высокоуровневое в духе "есть сообщение от пользователя такого-то с таким-то текстом", и пусть поток gui сам разбирается, что с этим делать. Это может быть и что-то более низкоуровневое, типа "задай такому-то свойству у такого-то элемента управления такое-то значение". Я бы посоветовал первый вариант - он позволит разделить логику программы чётко на две части.
    Код проверки будет примерно вида
    def check_gui_queue():
        try:
            while True:
                command = gui_queue.get_nowait()  # проверяем, есть ли команда для GUI
                gui_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # как-то обрабатываем команду
        except queue.Empty:  # команды нет
            root.after(100, check_gui_queue)  # даём GUI поработать спокойно 100 мс

    Разумеется, если ты завернёшь GUI в класс (что имеет смысл) код немного изменится. Но суть останется прежней.

    Другая очередь будет содержать команды для бота. Периодически проверяй её в потоке asyncio с помощью простого кода вида
    async def check_bot_queue():
        while True:
            try:
                command = bot_queue.get_nowait()  # проверяем, есть ли новая команда для бота
            except queue.Empty:
                await asyncio.sleep(0.1)  # нет - даём другим корутинам поработать 100 мс
            else:
                bot_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # есть - как-то её обрабатываем

    Эту корутину запустишь через create_task(), и она позволит коду GUI организовывать вызовы в коде бота.

    Разумеется, придётся подумать, как аккуратно сделать, чтобы эти две функции не разрослись в дикую простыню из if-elif-else. Но общий принцип примерно такой.
    Время ожидания команды можно увеличить - это замедлит время реакции пре передаче данных между потоками, но уменьшит холостую нагрузку на систему.
    Ответ написан
    Комментировать
  • Как получать значение атрибута, обращаясь к экзмепляру класса?

    Vindicar
    @Vindicar
    RTFM!
    Есть несколько способов.
    1. Пусть твой класс наследуется от collections.abc.MutableSequence и сам реализует минимально нужный набор методов (__getitem__, __setitem__, __delitem__, __len__, insert). Остальные методы списка MutableSequence реализует за тебя. Разумеется, если твое поле - не список, то нужно будет наследоваться от другого класса.
    2. Если твой класс всегда будет полем другого класса, ты можешь реализовать метод __get__(). Через него работают свойства (property). Но имей ввиду, что в этом случае ты вообще никогда не сможешь обратиться к чему-либо кроме того поля, которое возвращаешь.
    Ответ написан
    Комментировать
  • Почему при исполнении импортированого кода исполняется код из другого импорта?

    Vindicar
    @Vindicar
    RTFM!
    xx_RuBiCoN_xx, ну потому что надо не просто копипастить код, а документацию изучать, чтобы понимать, за что отвечает каждая часть твоего кода.
    @bot.callback_query_handler(func=lambda call: True)

    Параметр func должен содержать ссылку на функцию-фильтр, которая определит, должен ли данный обработчик вызываться для данного callback query. При этом вызовется первый подходящий обработчик, т.е. первый обработчик, у котого фильтр вернёт True.
    У тебя везде понатыкано lambda call: True, т.е. "для любого query вызывать этот обработчик". Как следствие, первый объявленный "универсальный" обработчик вызывается всегда и для всего. На имя функции боту наплевать.

    Самый простой способ разделить код на два обработчика - убедиться, что call.data имеет хорошо различимые значения. Например, добавить префикс: у кнопок для одного обработчика call.data пусть всегда начинается с "btn1.", а у другого с "btn2.". Тогда можно будет написать функцию-фильтр вида lambda call: call.data.startswith('btn1.') и т.п.
    Ответ написан
    2 комментария
  • Как правильно сделать вывод данных из sqlite3?

    Vindicar
    @Vindicar
    RTFM!
    Category ID пробелы в именах столбцов - не лучшая идея. У тебя точно толбец так называется? Если да, то оберни имя столбца в `бэктики` (обычно на клавише Ё).
    Ну и да, сдаётся мне, что 'call.data' не будет работать так, как ты это ожидаешь.
    Ответ написан
    Комментировать
  • Как перенести информацию с формы на форму в рамках ООП C#?

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

    Разумеется, свойства необходимы, если мы планируем использовать паттерн Наблюдатель(Observer), который в C# реализуется через интерфейсы INotifyPropertyChanged и INotifyPropertyChanging. Если вкратце - если мы хотим, чтобы другие объекты могли подписаться на наш объект, и получать уведомления об изменении его состояния. Тут всё понятно - сеттер свойства будет эти уведомления рассылать.

    Также свойства могут выручить, если мы потом захотим изменить способ хранения данных, но не захотим изменять "внешний вид" (интерфейс) объекта. Тогда в геттер свойства можно будет поместить код, который пересчитает "внутреннее" представление свойства во "внешнее".

    В случае примитивных data transfer objects, как User в твоём примере, я не вижу особенного смысла в использовании свойств ради свойств. Я бы даже сделал его struct, а не class, но это уже пусть спецы по C# меня поправят.

    Вообще, любую рекомендацию по проектированию нужно рассматривать не как заповедь, а как некий размен (trade-off): мы выигрываем в X, но проигрываем в Y (зачастую Y = сложность кода). И, соответственно, смотреть, что для тебя важнее.
    Ответ написан
    Комментировать
  • Progress bar как вывести результат?

    Vindicar
    @Vindicar
    RTFM!
    Оставаясь в рамках стандартного терминала - никак.
    Под никсами для сложного интерфейса в терминале есть ncurses, под виндой придётся искать аналог.
    Я бы сказал, если нужно что-то сложнее print() - осваивай tkinter. Если написать программу с умом, то можно будет сделать гибридное приложение, которое будет показывать GUI при обычном запуске, и работать в консоли при запуске с параметрами. Это если такое требуется, конечно - я фз какой у тебя сценарий использования.

    UPD: есть вариант использовать для вывода прогрессбара stderr, а для вывода результатов stdout, но в терминале они всё равно перемешаются.
    Ответ написан
    Комментировать
  • Ошибка sqlite3.IntegrityError: UNIQUE constraint failed: users.user_id Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Ты добавляешь уже существующего пользователя.
    Прочитай про запрос INSERT ... ON CONFLICT DO ... .
    Тут есть два варианта:
    INSERT ... ON CONFLICT DO UPDATE (он же UPSERT), чтобы обновить данные о пользователе.
    INSERT ... ON CONFLICT DO NOTHING, чтобы молча проигнорировать уже существующего пользователя.
    Ответ написан
    Комментировать
  • Как исправить ошибку с регулярными выражениями?

    Vindicar
    @Vindicar
    RTFM!
    Ну так почитай основы.
    Во-первых, используй r-строки, чтобы не натыкаться на проблемы с символом \.
    Во-вторых, изучи зарезервированные символы регулярных выражений, а именно: ( ) [ ] ^ $ . ? * +. Если тебе нужен этот символ как просто символ, его надо экранировать! Т.е. если тебе нужно совпадение с символом ?, надо писать \?.
    В-третьих, для поиска символа из указанного набора используются квадратные скобки, т.е. [abc] совпадёт с одним символом из указанных: a, b или c. Для задания диапазона можно сделать так: [a-z]. Это зачастую короче.
    В-четвёртых, для поиска символа НЕ из указанного набора используется такой синтаксис: [^abc]
    В-пятых, есть заранее заданные наборы. Например, \w описывает словесные символы (буквы, цифры и подчёркивание), \d описывает цифры, и т.д. Аналогично, \W и \D описывают всё кроме словесных символов и цифр, соотв.
    Тогда у тебя будет два варианта
    Если подчёркивание - не проблема:
    re.sub(r'\W', '', 'test:_:test', re.I)  # даст test_test

    Если подчёркивание тоже нужно убрать:
    re.sub(r'[\W_]', '', 'test:_:test', re.I)  # даст testtest
    Ответ написан
    1 комментарий
  • Нужно текст, который пользователь написал с FSM передавать определенному пользователю?

    Vindicar
    @Vindicar
    RTFM!
    1. "Нужно текст, который пользователь написал с FSM передавать определенному пользователю?"
    Нет, не нужно. На будущее: формулируй вопрос по-человечески. Туда же оформление кода - этого требуют правила ресурса.

    2. По теме: у тебя в коде есть пример отправки сообщения пользователю с известным ID.
    await bot.send_message(message.chat.id, 'Здравствуйте, какой продукт вы хотите преобрести?')

    В чём проблема сделать по аналогии?
    Ответ написан
  • Не работает код ошибки Python Bot?

    Vindicar
    @Vindicar
    RTFM!
    group_members = await bot.get_chat_member(group_id)

    Я подозреваю, что ты хотел вызвать bot.get_chat_members()
    Ответ написан
    Комментировать
  • Почему код не работает асинхронно?

    Vindicar
    @Vindicar
    RTFM!
    async def parse_card(card):
        d = dict()
        # из карточки берется html
        # "вставляется" в объект супа
        # и возвращается словарь
        # внутри этой функции не используются await
        return d


    Ну а ты что хочешь-то? Асинхронность в питоне предназначена для распараллеливания операций ввода-вывода (и сводимых к ним), а не для параллельного выполнения расчётов. У тебя parse_card() всё равно что синхронная.
    Ответ написан
    1 комментарий
  • Проблема с созданием телеграм бота Python aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Проблема с созданием телеграм бота Python aiogram?

    Да, проблема.

    Читай про finite state machine в aiogram.
    Ответ написан
    Комментировать
  • Как вернуть значение из класса?

    Vindicar
    @Vindicar
    RTFM!
    Плохо гуглил. Впрочем, если гуглил по запросу "вернуть значение из класса" (что есть бессмыслица) вместо хотя бы "строковое представление объекта", то неудивительно.
    Ответ написан
    Комментировать
  • Как разделить код на несколько файлов?

    Vindicar
    @Vindicar
    RTFM!
    У тебя будет проблема с циклическим импортом: основной файл будет импортировать модули с функциями, но этим модулям будет требоваться экземпляр бота, описанный в основном файле. Эту проблему можно обойти так:
    # submodule_1.py  - модуль, содержащий часть функций бота
    def setup(bot):  
        # bot - объект бота. Можешь добавить и другие полезные параметры, такие как:
        # - объект logging.Logger для журналирования
        # - объект соединения с БД
        # - ну и что там ещё тебе потребуется
    
        # все обработчики событий объявляем ВНУТРИ setup()
        # тогда они смогут ссылаться на переданные параметры
        @bot.command('/start')  # например, чтобы использовать декораторы
        def on_start(message):
            message.reply('foobar')
    # мы описали функцию setup(), но здесь мы её не вызываем!
    
    
    # main.py - основной файл бота
    bot = ...  # создаём объект бота
    
    import submodule_1  # импортируем модуль с функциями
    # при вызове setup() будут заданы обработчики событий, описанные в ней
    submodule_1.setup(bot)  # функции передаём объект бота (и другие объекты, если она их ожидает)
    # функцию setup() нужно вызывать не более одного раза!
    # так можно добавлять столько модулей, сколько требуется.
    
    bot.run()  # дальше бота запускаем как обычно
    Ответ написан
    2 комментария
  • Реально ли выдать CoolDown на команду по условию discord py?

    Vindicar
    @Vindicar
    RTFM!
    f"SELECT premium FROM premusers WHERE id = {ctx.guild.id}"

    Используй параметризованные запросы, а не форматирование.

    А что касается кулдауна - достаточно почитать документацию.

    @discord.app_commands.checks.dynamic_cooldown(factory, *, key=...)

    If a factory function is given, it must be a function that accepts a single parameter of type discord.Interaction and must return a Cooldown or None. If None is returned then that cooldown is effectively bypassed.

    Выделение моё.
    Т.е. тебе надо написать функцию, которая принимает объект типа discord.Interaction и возвращает или объект Cooldown, описывающий, какой кулдаун надо применить, или None, если кулдауна быть не должно. Потом передаёшь эту функцию как параметр декоратора dynamic_cooldown, и готово. Пример есть по ссылке.
    Ответ написан
    1 комментарий