Задать вопрос
  • Как отрыть ссылку с помощью 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]

    Таким образом наберёшь всё, что надо.
    Ответ написан
    Комментировать
  • Как получить содержимое сообщения до его редактирования в discord через requests?

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

    Vindicar
    @Vindicar
    RTFM!
    Проверь, не одинаковые ли значения в user_id и poroh.
    Если так, проверяй, откуда берётся значение user_id.

    EDIT: Когда ты нажимаешь на "Да", это отдельное сообщение - отправленное от тебя!
    Т.е. server() вызывается дважды, один раз для запустившего (после выбора карты), второй раз для тебя (ответ да или нет). Это, к слову, несёт в себе ещё одну проблему - если два человека попросят запустить сервер одноврнменно, боту будет тяжело понять, на чей запрос ты ответил.
    Тебе надо использовать не ReplyKeyboardMarkup, а InlineKeyboardMarkup, так как там можно привязать к кнопке дополнительную инфу (строку), по которой бот сможет потом понять, к какому сообщению относилась кнопка.
    Ответ написан
  • Где найти ошибку в коде?

    Vindicar
    @Vindicar
    RTFM!
    Почитай про импорты в питоне, какой-нибудь толковый учебник (типа Лутца).
    Ты делаешь относительный импорт (import .something), но это можно использовать только в крупных модулях проекта, а не в корневых файлах. Импортируй как обычно, без точки.
    Ответ написан
    Комментировать
  • Взаимодействие методов внутри класса?

    Vindicar
    @Vindicar
    RTFM!
    # Ты заявляешь следущее:
    # "метод udar должен вызываться на экземпляре объекта (self) с двумя параметрами: hp и dmg"
    def udar(self,hp,dmg):
        print("Наносит урон с руки")
        # при этом метод не использует переданные параметры?
        rep = self.hp - self.dmg  # почему self.dmg? Боец бьёт себя?
        return "Осталось здоровья: " + rep
    
    
    # а ниже у тебя:
    # метод udar() фактически вызывается с одним параметром: другим бойцом
    boec.udar(boec2)


    Твоя проблема та же, что и всех новичков: ты не озаботился сформулировать обязанности метода, что должен делать это метод с точки зрения решаемой программой задачи.
    Например, сейчас у тебя путаница: метод имитирует нанесение удара бойцом self по бойцу, переданному как параметр? Или же наоборот, удар бойцом, переданным как параметр, по бойцу self? И уж точно не нужно прикручивать сюда ещё и вывод текста в консоль, это посторонняя обязанность, не относящаяся к классу бойца.

    Вот моя идея (может, несколько усложнённая, но, надеюсь, понятная):
    class Fighter:
        def __init__(self, name: str, hp: int, damage: int):  # указывай типы параметров - так проще понять, что нужно методу
            """Конструктор инициализирует экземпляр бойца заданными значениями."""
            self.name: str = name
            self.hp: int = hp
            self.damage: int = damage
        
        def is_defeated(self) -> bool:
            """Возвращает True, если боец не может более сражаться."""
            return self.hp <= 0  # в простейшем случае, если у бойца не осталось HP
    
        def calculate_attack_on(self, other: 'Fighter') -> int:
            """Метод определяет, сколько урона наш боец (self) нанесёт бойцу other. Возвращает число очков урона."""
            # сейчас урон всегда одинаков, но потом тут можно будет прикрутить что-то посложнее
            # например, рандомный урон в диапазоне, или бонусы/малусы против конкретных бойцов, или ещё что
            return self.damage  
    
        def receive_damage(self, damage: int) -> int:
            """Метод определяет, сколько HP наш боец (self) потеряет, получив урон damage, и уменьшает его здоровье. Возвращает число фактически потерянных очков здоровья."""
            # сейчас метод просто вычитает урон из очков здоровья. 
            # но потом при желании можно добавить, например, механику "последний шанс", 
            # когда первый "смертельный" удар оставляет бойца на 1 хп. Или сопротивление/уязвимость к урону, или ещё что.
            lost = min(self.hp, damage)  # если у нас 1 очко здоровья, мы не можем потерять 10
            self.hp -= lost
            return lost
    
        def attack_other(self, target: 'Fighter') -> int:
            """Проводит атаку нашего бойца (self) по другому бойцу (target). Возвращает нанесённый урон."""
            attack_damage = self.calculate_attack_on(target)
            actual_damage = target.receive_damage(attack_damage)
            return actual_damage

    Как видишь, у каждого метода есть свой достаточно чётко очерченный круг обязанностей. Хотя, конечно, можно придраться и сказать, что receive_damage() делает две вещи и его стоит разбить на два метода.
    Названия методов должны однозначно указывать, что они делают. Например, udar ничего не говорит о том, кто кого ударяет, тогда как attack_other намекает, что атаку производит тот, у кого вызвали метод, в адрес того, кого передали как параметр метода. То же самое касается параметров методов.
    Весь вывод вынесен из класса, это не его обязанность:
    boec = Fighter("вася",200,22)
    boec2 = Fighter("bob",100,19)
    print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
    dmg = boec.attach_other(boec2)
    print(f'{boec.name} нанёс {dmg} урона {boec2.name}')
    print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
    Ответ написан
    2 комментария
  • Как ускорить запуск .exe файла?

    Vindicar
    @Vindicar
    RTFM!
    Если проблема именно в "юзер сбит с толку", то её можно обойти, а не решить. Я, например, когда писал гуишную программу, завязанную на numpy, scipy и matplotlib, в итоге плюнул и сделал простой splash screen, который показывается при загрузке и пред-импортирует требуемые модули, показывая прогрессбар. А у pyinstaller есть опция --splash, которая будет показывать прогресс распаковки.

    А так - профилируй приложение, выясняй, на чём задержка. Добавь отладочный вывод в самое начало скрипта, до импортов, чтобы понять, идёт ли задержка на этапе запуска интерпретатора, или на этапе ипорта модулей.
    Ответ написан
    Комментировать
  • Как прослушать несколько портов в python?

    Vindicar
    @Vindicar
    RTFM!
    Можно, открыв несколько сокетов и проверяя их все.
    Но начиная с определенного числа команд проще будет использовать SSH или иную форму удалённого управления.
    Ответ написан
    Комментировать
  • Есть ли датасеты текстур майнкрафта до 12.2 включительно с указанными айдишниками от mcpi,?

    Vindicar
    @Vindicar
    RTFM!
    %APPDATA%\.minecraft\versions\{Версия}\client.jar
    Открываешь его винраром или другим архиватором (jar - это zip-архив).
    Идёшь в assets\minecraft\textures\block
    профит.
    Ответ написан
    2 комментария
  • Как отсортировать элементы с определенным id в mongodb (pymongo) и записать их в список?

    Vindicar
    @Vindicar
    RTFM!
    В первом случае ты ищешь все элементы, у которых server_id НЕ совпадает (!=) с message.guild.id.
    Во втором случае ты ищешь все элементы, у которых server_id совпадает с message.guild.id.

    Исходя из твоего результата, я бы сказал, что у тебя в базе нет элемента с таким id. Ты уверен, что он там есть? Что насчёт типов данных - нет ли тут косяка, вроде "храню id как строку, а передаю при поиске как целое число"?

    И да, говори правильно. То, что ты делаешь - поиск/фильтрация, а не сортировка.
    Ответ написан
  • Как обрабатывать ошибки в асинхронном коде?

    Vindicar
    @Vindicar
    RTFM!
    try: 
        loop.create_task(exc())
    except ZeroDivisionError as ex:
        print(f"Ошибка {ex} обработана")

    1. Ты создаёшь задачу на базе корутины exc(). Созданная задача не выполнится немедленно, а только встанет в очередь исполнения (хотя в питоне 3.12 это поведение можно изменить, но по умолчанию это так). При этом с корутиной ассоциируется future-объект, который находится в состоянии "ожидание", так как корутина ещё не завершила работу.
    2. Ты проверяешь, не возникло ли исключение в процессе создания задачи. Это может произойти, только если exc() - не корутина. В остальных случаях операция будет успешна независимо от содержания exc(), так как см. пункт 1.
    3. Ты вызываешь loop.run_forever(). Рабочий цикл (loop) смотрит в очередь исполнения, и видит в нём только корутину exc(). Она получает управление.
    4. Корутина exc() выбрасывает исключение, но не ловит его. Ассоциированный с корутиной future-объект переходит из состояния "ожидание" в состояние "отказ", и сохраняет информацию об исключении. exc() завершает работу.
    5. Рабочий цикл проверяет, кто хранит ссылку на task - и понимает, что никто. Как следствие, даже в будущем никто не сможет узнать, что корутина выкинула исключение. Поскольку рабочий цикл - штука типовая, он понятия не имеет, что делала наша корутина и как надо реагировать на исключение в ней. А потому единственный вариант для него - написать в журнал работы о непойманном исключении и надеяться, что программист это увидит и поправит.
    task = asyncio.create_task(exc())
    try:
        # await asyncio.gather(task)  # <- gather() не нужно, если у тебя одна задача
        await task
    except ZeroDivisionError as ex:
        print(f"Ошибка {ex} обработана")

    1. Ты создаёшь задачу (успешно), а потом с помощью await-вызова просишь дождаться её завершения и получить результат.
    2. Корутина main() приостанавливает своё выполнение и сохраняет свой контекст, а также встаёт в очередь, ожидая, когда сработает future-объект, связанный с task.
    3. Рабочий цикл (loop) asyncio смотрит в очередь выполнения и видит, что корутина exc() готова выполняться (она не находится в await вызове, а только начала работу).
    4. Корутина exc() получает управление, выполняется, и генерирует исключение, которое не поймано внутри этой корутины. Future-объект, связанный с этой корутиной, переходит из состояния "ожидание" в состояние "отказ", и сохраняет информацию об исключении. Корутина exc() завершает выполнение. При этом о её future-объекте знает корутина main(), поэтому рабочий цикл не дёргается по этому поводу - у main() будет возможность отреагировать на происходящее.
    5. Рабочий цикл (loop) смотрит в очередь выполнения и видит, что там только корутина main(), причём она готова выполняться - future-объект, который она ждёт, более не находится в состоянии ожидания.
    6. Корутина main() получает управление и восстанавливает свой контекст, продолжая с того места, где она остановилась. Так как future-объект находится в состоянии "отказ", оператор await читает из него информацию об исключении и перевыбрасывает это исключение внутри main().
    7. Это исключение обрабатывается блоком try-except в main() как обычно.
    Ответ написан
    Комментировать
  • Почему когда отвечаю на сообщение в чате, сообщение не присылается пользователю в бота обртано?

    Vindicar
    @Vindicar
    RTFM!
    У тебя handle_message() стоит первым - поэтому бот будет пытаться использовать его для любых текстовых сообщений. А поскольку у тебя там тупо if, без какой-либо реакции на неожиданные сообщения, то если if не выполнился, бот молча ничего не сделает.
    Ответ написан
    Комментировать
  • Как отправлять данные пользователю из бота telegram?

    Vindicar
    @Vindicar
    RTFM!
    У тебя, походу, button() прописан как обработчик для всех кнопок. А вот внутри него не прописана ветка для data == 'send_purchase'. На текущем шаге добавь во ВСЕ цепочки if ... elif ... elif ... ветку else, которая выводит отладочное сообщение - тогда хоть будет понятно, какой обработчик вызвался и с каким значением.
    Ответ написан
    1 комментарий
  • Как сделать свять вежду python игрой и сайтом на html?

    Vindicar
    @Vindicar
    RTFM!
    1. Ты должен выбрать себе схему URL, по аналогии с тем, как это делает телеграм с его схемой tg:// или стим (steam://).
    2. Научись упаковывать свою игру в exe-файл с помощью любого упаковщика - например, auto-py-to-exe.
    3. Подразумевается, что игра уже установлена на компьютере пользователя. При установке она регистрирует себя как обработчик для данной схемы. Это делается по-разному для винды и для линукса.
    Для винды нужно будет залезть в реестр через стандартный модуль registry

    Тебе нужно создать ключ реестра HKEY_CLASSES_ROOT/ИмяТвоейСхемы. Убедись, что такого ключа нет, перед тем как его создавать!
    В ключе создаёшь строковое значение с именем URL Protocol и пустым значением.
    Создаёшь вложенный ключ: HKEY_CLASSES_ROOT/ИмяТвоейСхемы/shell
    Внутри вложенного ключа создаёшь строковое значение с именем command и значением такого вида: "C:\путь\к\твоей\игре.exe" "%1"

    После этого при попытке ввести в браузере ссылку, начинающуюся с твоей схемы, должна запуститься твоя игра.
    3. Твоя игра должна проверять параметры командной строки (читай про sys.argv). Если игра запущена без параметров - её запустили просто ярлыком. Если игра запущена с одним параметром, и он начинается с твоей схемы - её запустил клик по ссылке. Разбирай текст ссылки в параметре и решай, что игра должна сделать.

    Технически, ты не обязан сам лезть в реестр в python-скрипте - ты можешь сделать это ручками через regedit или поручить это установщику, типа NullSoft. Он же позаботится о том, чтобы снести созданные ключи при удалении игры.
    Я бы сначала попробовал зарегистрировать URL вручную, убедился что это работает, а потом уже игрался бы с установщиком.
    Ответ написан
    Комментировать
  • SyntaxError: 'await' outside function. Как исправить ошибку кода, который должен пересылать удаленные сообщения в телеграмме в избранное?

    Vindicar
    @Vindicar
    RTFM!
    await client.run_until_disconnected()
    Эта строка где находится? Вне функции? А почему?
    Выглядит как будто ей место в main().
    Ответ написан
    Комментировать
  • Как обойти ошибку Tcl_AsyncDelete: async handler deleted by the wrong thread?

    Vindicar
    @Vindicar
    RTFM!
    Поясню ответ выше: насколько я знаю, графические интерфейсы строго однопоточны. Как минимум под Windows это так, а потому ни один графический фреймворк не поддерживает обращение к окнам и их элементам из других потоков.
    Как следствие, если ты хочешь организовать фоновый поток с "обратной связью" в GUI, обычно требуется использовать очередь, например, queue.Queue. В эту очередь фоновый поток должен класть сообщения, объясняющие, что надо сделать - например, сведения о прогрессе операции, или команды на смену состояния, или ещё что. Это зависит от твоей задачи.
    Тогда основной поток программы, который и отвечает за GUI, должен использовать средства фреймворка для периодической проверки очереди на предмет сообщений. Например, в обычном tkinter это будет реализовано через метод after().
    Если в очереди есть сообщения, основной поток читает их и выполняет соответствующие действия - например, меняет положение прогресс-бара, включает/выключает кнопки, и т.д.
    Если фоновый (рабочий) поток живёт долго, то может иметь смысл организовать вторую очередь для передачи команд из GUI-потока в рабочий. Идея та же самая: рабочий поток ждёт появления команды в своей входной очереди, и выполняет её, а потом сбрасывает уведомления в исходящую очередь.
    Ответ написан
    Комментировать
  • Как вывести роли discord сервера, кроме заблокированных?

    Vindicar
    @Vindicar
    RTFM!
    В discord.py ты можешь просто сравнивать роли. Но ты пытаешься сделать это вручную...
    Если заглянуть в исходники либы, то можно увидеть, что там проверяется свойство position. Причем вроде как меньший position означает меньшие привилегии, с поправкой на то что роль @everyone меньше всех.
    Тогда решением твоей задачи будет:
    1. Определить список ролей твоего токена на рассматриваемом сервере.
    2. Определить наибольший position среди этих ролей.
    3. Получить список всех ролей на рассматриваемом сервере.
    4. Отсеять роли, у которых position больше твоего наибольшего.

    Если я напутал и меньший position означает большую роль, то логика примерно та же самое, только меняешь больше на меньше.
    Ответ написан
  • Как добавить фон скрипту, запускаемому через консоль?

    Vindicar
    @Vindicar
    RTFM!
    Полноценную картинку в консоли не покажешь, тут тебе не линукс. Но ASCII-арт можно - вопрос только как разделить вывод текста игры и вывод ascii-арта. Например, сделать два логических "окна" в одном терминале.

    Ставишь пакет windows-curses, после этого можно будет и на винде использовать стандартный модуль curses. Он и это умеет, и цветной вывод.
    Ответ написан
    Комментировать