• При разбиении пути возникает ошибка. Как пофиксить?

    Vindicar
    @Vindicar
    RTFM!
    Читай документацию же.
    The return value is a tuple (type, encoding) where type is None if the type can’t be guessed (missing or unknown suffix) or a string of the form 'type/subtype', usable for a MIME content-type header.

    Т.е. для неизвестных типов у тебя в ftype попадёт None, а ты этого не проверяешь.

    EDIT: А вообще есть смысл делать guess_type()? Если у тебя тип файла известен заранее, то можно захардкодить и правильный mime-тип.
    Ответ написан
    Комментировать
  • Как изменить по имени сортировку списка?

    Vindicar
    @Vindicar
    RTFM!
    Потому что сортировка строк (например, имён файлов) - это лексикографическое сравнение. В этом сравнении "б" > "аааааааааа", просто потому что "б" > "а". Другое дело, что у человеков очень странные представления о порядке, и компьютеру трудно к ним адаптироваться.

    Если тебе нужен т.н. естественный порядок (natural sorting), тебе нужно как-то выцепить из имени тот кусок, по которому нужно делать сравнение. Например, так:
    import re
    PARTS = re.compile(r'^(.+?)(?:(\d+)\D+)?$')
    
    def natural_sort_key(fname: str):
        "Функция извлекает из имени файла описание, по которому его надо сортировать."
        prefix, index = PARTS.match(fname).groups()
        return (prefix, int(index) if index else 0)
    
    
    lst.sort(key=natural_sort_key)
    Ответ написан
  • Что я делаю не так с register_message_handler в aiogram?

    Vindicar
    @Vindicar
    RTFM!

    dp.register_message_handler(answer3, state=get_answer.answer3)
    db.register_message_handler(answer4, state=get_answer.answer4)

    У тебя в паре месте перепутано dp и db.
    Короткие названия они такие... коварные.
    Ответ написан
  • Для чего нужен lock в python? Как работает данный пример кода?

    Vindicar
    @Vindicar
    RTFM!
    Это объясняется тем, что в базовом питоне потоки не вполне честные - они конкурируют за global interpreter lock, так что код выполняется всё равно поочерёдно. Так что многопоточность в питоне полезна с точки зрения распараллеливания, но не ускорения. ЕМНИП, есть реализации питона, в которых нет этой GIL problem.
    Но нужно иметь ввиду, что этот GIL блокирует только элементарные операции (как в твоём примере), тогда как явное использование lock может накрывать целые блоки кода, состоящие из нескольких операций с защищаемым ресурсом.

    Вот тебе пример:
    import threading
    import time
    
    class Data:
        def __init__(self):
            self.x: int = 0
            self.y: int = 0
    
    
    do_sleep = False
    run = True
    
    
    def reader(d: Data):
        while run:
            x, y = d.x, d.y
            # по идее это условие не должно выполниться никогда
            if (x != 0) != (y != 0):  
                print(f'Got x={x} and y={y}')
            else:
                print(f'OK {x}', end='\x08\x08\x08\x08')
    
    
    def writer(d: Data):
        while run:
            if d.x == 0:
                d.x = 1
                if do_sleep: pass
                d.y = 1
            else:
                d.x = 0
                if do_sleep: pass
                d.y = 0
    
    
    do_sleep = False
    instance = Data()
    reader_thread = threading.Thread(target=reader, args=(instance,), daemon=True)
    writer_thread = threading.Thread(target=writer, args=(instance,), daemon=True)
    reader_thread.start()
    writer_thread.start()
    try:
        input()
    finally:
        run = False
        reader_thread.join()
        writer_thread.join()


    На моей машине, если if do_sleep: pass закомментировать, то в консоли высвечивается только OK - иными словами, присваивание двух полей выполняется достаточно быстро, чтобы поток не успел переключиться в промежутке. Как следствие, reader() всегда видит либо x=0 y=0, либо x=1 y=1.
    Но если if do_sleep: pass оставить, то выполнение тела цикла замедляется достаточно, чтобы поток успел переключиться - и, как следствие, reader() начинает видеть структуру данных Data в неконсистентном состоянии, когда x=0 y=1 или когда x=1 y=0.
    И вот чтобы не гадать "успеет - не успеет", нужно в таких случаях защищать связные серии обращений к структуре с помощью мьютекса, ну или в питоновских терминах - Lock.
    Ответ написан
    Комментировать
  • Почеум при использывании функции click() библиотеки pyautogui курсор не кликает?

    Vindicar
    @Vindicar
    RTFM!
    А ты уверен, что на момент выполнения click() окно браузера уже существует? Сколько времени он открывается?
    И вообще, открывать URL кликом по закреплённой закладке - ну такое себе. Чем тебе webbrowser.open() не угодил?
    Ответ написан
    1 комментарий
  • Атрибуты дочернего класса в родительском?

    Vindicar
    @Vindicar
    RTFM!
    Нет, так как код CacheManager вообще ничего не знает про свои дочерние классы.
    С другой стороны, почему у тебя все методы декорированы staticmethod? Если бы это был classmethod, то тогда при вызове Info.extract метод extract() хотя бы смог бы понять, что его вызывает на классе Info, а не CacheManager.
    Ответ написан
  • Как с Python получить текст из DOCX с сохранением форматирования?

    Vindicar
    @Vindicar
    RTFM!
    Ну смотри. В DOCX текст хранится в виде интервалов (runs), где интервал - это последовательность символов с одинаковым форматированием. Можно получить список интервалов в абзаце через свойство docparagraph.runs.
    А дальше для каждого интервала определяешь интересующие тебя свойства форматирования, достаёшь текст, и имитируешь это форматирование с помощью markdown (ну или какие там ещё языки разметки поддерживает нужный тебе мессенджер). Результаты склеиваешь в одну строку и отправляешь.

    Кое-что есть в документации, но она явно неполная, так что остальное придётся искать в исходниках классов Paragraph и Run.
    Ответ написан
    3 комментария
  • Как удалить пакеты которые не используются в проекте из виртуального окружения?

    Vindicar
    @Vindicar
    RTFM!
    Потому что надёжного метода анализа зависимостей нет.
    Импорты в питоне могут быть условными, выполняться в разное время, или вообще выполняться динамически через importlib.
    Я бы сказал, вспомнить, какие пакеты тебе требуются, очистить окружение, поставить их, погонять приложение и пособирать недостающее.

    А на будущее - когда тестируешь пакет, делай отдельную ветку в системе управления версиями, и отдельное окружение. Только когда пакет устоялся, делаешь merge.
    Ответ написан
    Комментировать
  • Как исправить ошибку взаемодействия Дискорд бота и окна?

    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 = сложность кода). И, соответственно, смотреть, что для тебя важнее.
    Ответ написан
    Комментировать