Задать вопрос
Ответы пользователя по тегу Python
  • Бот не отвечает на команды | disnake?

    Vindicar
    @Vindicar
    RTFM!
    RTFM!
    Why does on_message make my commands stop working?
    Overriding the default provided on_message forbids any extra commands from running. To fix this, add a bot.process_commands(message) line at the end of your on_message.


    disnake, ЕМНИП - форк discord.py, так что наверняка это верно и для него.
    Ответ написан
    Комментировать
  • Как запустить две функции параллельно в asyncio?

    Vindicar
    @Vindicar
    RTFM!
    Намудрил-то, намудрил-то...
    background_func() сделай асинхронной, run_in_executor() в ней нафиг не нужен, можно будет просто сделать await bot.send_message(...).
    time.sleep(), соответственно, меняешь на await asyncio.sleep().
    executor.start_polling() вызывай прямо в теле программы, без выкрутасов.

    Для запуска функции при старте бота опиши её как
    async def bot_startup(dp: Dispatcher):
    и передай её в параметре on_startup при вызове start_polling().
    А внутри bot_startup уже делай что нужно, например, asyncio.create_task(background_func()).
    Обрати внимание, без await - тогда background_func() будет работать параллельно боту.
    Ответ написан
    2 комментария
  • Как сделать так, чтобы данные, которые я пишу в тг бота, заполняли сперва первую строчку в таблице postgre?

    Vindicar
    @Vindicar
    RTFM!
    Почитай хотя бы про основы реляционных БД.
    У каждой таблицы должен быть первичный ключ - иными словами, такое поле/комбинация полей, которая будет уникальной для каждой записи.
    Тогда алгоритм будет такой: спрашиваешь пользователя, какую запись он хочет редактировать, запоминаешь её ключ, затем переходишь в режим редактирования, где поочерёдно спрашиваешь значения столбцов.
    Подразумевается, что ты знаешь, как сделать сценарий, чтобы бот последовательные сообщения обрабатывал по-разному. Если не знаешь - читай, как реализуется finite state machine (FSM) в выбранной тобой библиотеке.
    Ну и да:
    data = message.text.strip()
    cur.execute(f"INSERT INTO {tableName} ({column_name}) VALUES ('{data}')")

    Это - готовая SQL инъекция. И если вставку tableName и column_name еще можно оправдать (хотя ты их тоже не проверяешь на допустимость), то данные так вставлять нельзя. Есть правильный способ.
    Ответ написан
    Комментировать
  • Как в питоне обеспечить контроль целосности данных?

    Vindicar
    @Vindicar
    RTFM!
    С переменными так не прокатит. А вот с полями класса - при желании можно, если использовать property.
    Базовая идея простая - пусть сеттер свойства производит валидацию.
    Например, так
    class Person:
        def __init__(self, name: str):
            self._name: str = ''
            self.name = name
        
        @property
        def name(self) -> str:
            return self._name
        
        @name.setter
        def name(self, value: str) -> None:
            if not value:
                raise ValueError('Must not be empty')
            self._name = value

    Но писать такой бойлерплейт быстро надоест. Поэтому можем попробовать обобщить процесс.
    Например, так
    from typing import TypeVar, Type, Any, Annotated, Callable, Dict, get_args, get_origin
    
    T = TypeVar('T')
    ValidationRule = Callable[[Any], bool]
    ValidationRules = Dict[str, ValidationRule]
    
    class ValidatedProperty:
        """Экземпляры этого класса будут свойствами в валидируемых классах, и будут заниматься валидацией."""
        def __init__(self, name: str, storagename: str, rules: ValidationRules):
            self.name = name  # как называется свойство
            self.storagename = storagename  # где его хранить
            self.rules = rules  # какие правила применять
    
        def __get__(self, instance, owner=None):
            return getattr(instance, self.storagename)  # при чтении просто возвращаем свойство
        
        def __set__(self, instance, value):  # при записи валидируем
            for message, rule in self.rules.items():  
                if not rule(value):  # если правило нарушено, выкидываем исключение с сообщением
                    raise ValueError(f'{instance.__class__.__name__}.{self.name}: {message}')
            setattr(instance, self.storagename, value)
    
    
    def validated(klass: Type[T]) -> Type[T]:
        """Декоратор для валидируемых классов."""
        for name, annot in klass.__annotations__.items():  # проверяем список аннотаций в классе
            base = get_origin(annot) or annot
            if base is not Annotated:  # нас интересуют только те, которые помечены как Annotated
                continue
            args = get_args(annot)
            rules = [arg for arg in args if isinstance(arg, dict)]
            if not rules:  # и только если один (любой) из аргументов Annotated - словарь
                continue
            # в этом случае мы считаем, что словарь содержит правила валидации, и создаём свойство класса
            setattr(klass, name, ValidatedProperty(name, f'_{name}', rules[0]))
        return klass  # не забываем вернуть изменённый класс!
    
    
    @validated
    class Person:
        name: Annotated[str, {'must not be empty': lambda v: bool(v)}]
        age: Annotated[int, {'must be positive': lambda v: v > 0}]
    
        def __init__(self, name: str, age: int):
            self.name = name  # валидация отработает уже здесь
            self.age = age  # валидация отработает уже здесь
        
        def __repr__(self) -> str:
            return f'Person(name={self.name!r}, age={self.age!r})'
    
    try:
        Person('John Doe', 23)  # отработает успешно
    except Exception as err:
        print('Failed to create person 1')
        print(f'{err.__class__.__name__}: {err!s}')
    else:
        print('Person 1 created')
    
    try:
        Person('', 23)  # выкинет исключение
    except Exception as err:
        print('Failed to create person 2')
        print(f'{err.__class__.__name__}: {err!s}')
    else:
        print('Person 2 created')
    
    try:
        Person('Jane Doe', -23)  # выкинет исключение
    except Exception as err:
        print('Failed to create person 3')
        print(f'{err.__class__.__name__}: {err!s}')
    else:
        print('Person 3 created')
    
    p = Person('John Doe', 23)
    try:
        p.name = ''  # выкинет исключение
    except Exception as err:
        print('Failed to modify person')
        print(f'{err.__class__.__name__}: {err!s}')
    
    try:
        p.age = 0  # выкинет исключение
    except Exception as err:
        print('Failed to modify person')
        print(f'{err.__class__.__name__}: {err!s}')
    
    try:
        p.age = 24  # отработает успешно
    except Exception as err:
        print('Failed to modify person')
        print(f'{err.__class__.__name__}: {err!s}')
    
    print(p)
    print(vars(p))


    Это, конечно, велосипед, и пользоваться им я бы не посоветовал. Для валидации есть библиотеки типа pydantic.
    Плюс, как было указано выше, не всё и не всегда имеет смысл валидировать...

    А для работы с БД лучше использовать ORM. SqlAlchemy популярна, но есть и более простые, например, peewee или ponyorm.
    Ответ написан
    Комментировать
  • Как вернуть значения из синхронного колбека в corotine несколько раз?

    Vindicar
    @Vindicar
    RTFM!
    Я вижу два потенциальных источника проблем.
    1. Ты говоришь, что библиотека будет дёргать callback при изменении значения свойства. А когда она будет это делать?
    Ей ведь нужно выполнить для этого какой-то код, причём наверняка синхронный. Пусть какой-то метод, который проверит очередь событий, извлечёт оттуда новые и дёрнет соответствующие callbak'и. Этот код точно вызывается?
    2. Ты делаешь await iface.call_method('bla'). Ты уверен, что обновление свойства произойдёт после завершения await? Если оно произойдёт до, то твой вызов wait_property() не увидит обновлений. Возможно, стоит вешать callback до вызова call_method()?
    Ответ написан
    Комментировать
  • Как сделать чтобы при вводе неправильных данных выводилась ошибка и пользователь вводил данные сначала?

    Vindicar
    @Vindicar
    RTFM!
    Если ты разбираешь дату с помощью datetime.datetime.strptime(), то эта функция выбрасывает исключение ValueError при неправильной дате. Так что учись работать с исключениями.
    А дальше логика простая: заверни всё в цикл while True, при вводе правильной даты выходи из цикла по break.
    Ответ написан
    Комментировать
  • Вопрос по конструктору класса?

    Vindicar
    @Vindicar
    RTFM!
    К сожалению, functools.singledispatchmethod тут не поможет, так как он не справляется с аргументами-экземплярами того же класса.
    Ты можешь проверять переданные аргументы вручную...

    import typing as tp
    
    
    class Test:
        @tp.overload
        def __init__(self, x: int, y: str):
            ...  # тут не должно быть тела!
    
        @tp.overload
        def __init__(self, other: 'Test'):
            ...  # typehint в виде строки, так как класс Test еще не создан. Тела нет!
    
        def __init__(self, *args, **kwargs):  # настоящий конструктор
            # определяем, как нас вызвали
            if 'other' in kwargs:
                first_arg = kwargs['other']
                x, y = first_arg.x, first_arg.y
            elif 'x' in kwargs:
                x, y = kwargs.get('x'), kwargs.get('y')
            elif isinstance(args[0], Test):
                x, y = args[0].x, args[0].y
            else:
                x, y = args[0:2]
            self.x: int = x
            self.y: str = y
    
        def __repr__(self) -> str:
            return f'Test(x={self.x!r}, y={self.y!r})'
    
    # порядковая передача аргументов сработает
    t1 = Test(1, 'foo')
    t2 = Test(t1)
    print(t1, t2)
    # именованная передача аргументов сработает
    t3 = Test(x=2, y='bar')
    t4 = Test(other=t3)
    print(t3, t4)
    
    Test(3, y='baz')  # а вот это сломается...

    Но у тебя будет куча проблем с аргументами имеющими значение по умолчанию.
    Метод copy() будет куда практичнее и понятнее.
    Ответ написан
    Комментировать
  • Как правильно обработать исключение в AsyncIOScheduler?

    Vindicar
    @Vindicar
    RTFM!
    worker = Worker()
    await worker.run()

    Так исключение-то тут возникает, наверно?
    Вообще у тебя что-то странное творится - сначала выполняешь воркера, а потом по условию планируешь его повторное выполнение планировщиком.

    Ну а так, я бы просто обернул вызов worker.run() в свою подпрограмму, которая бы ловила исключения и обслуживала их как надо, и планировал уже её выполнение.
    Ответ написан
  • Как добавить HTTP proxy для telegram бота на pythonanywhere?

    Vindicar
    @Vindicar
    RTFM!
    В гугл!

    Не, кроме шуток. Гугл по "telethon proxy" первой же строкой выводит на страницу документации с примером.
    TelegramClient('anon', api_id, api_hash, proxy=("socks5", '127.0.0.1', 4444))

    В твоём случае будет скорее что-то типа proxy=('http', 'proxy.server',3128)
    Почему ты не осилил это найти?
    Ответ написан
    3 комментария
  • Библиотеке os выводит непонятные символы, что делать?

    Vindicar
    @Vindicar
    RTFM!
    Не "библиотека os", а процесс, который ты запускаешь. В какой кодировке он выводит текст, знает разве что он сам (вероятно, или windows-1251, или cp866). Но почти наверняка не в юникоде, с которым работает питон.
    Так что кодировку придётся выяснять опытным путём и самому полученную строку перекодировать.
    Ответ написан
    Комментировать
  • Что делать если функция не видит атрибут?

    Vindicar
    @Vindicar
    RTFM!
    Включи голову и подумай.
    if ai.SeparateByName(ai.text) is True:
        response = f'my name {ai.name}'
    ai.TextToSpeech(response)

    Если условие не выполнится, переменная response не будет определена. Нужно или дать ей альтернативное значение в ветке else, или дать значение по умолчанию до if. Ну или внести вызов TextToSpeech() внутрь if.

    Аналогично, ты определяешь атрибут ChatAI.text только в методе SpeechToText(), и только если распознавание прошло успешно. Если первая запись голоса или первое распознавание прошли неудачно, атрибут text определён не будет. В случае вторых и последующих - он сохранит своё прежнее значение, и ты не сможешь понять, это пользователь дважды повторил одно и то же, или бот тупит.
    Тебе нужно или определить ему какое-то значение по умолчанию в __init__(), или, что лучше, вообще не использовать атрибут, а возвращать это значение из метода через return.
    Ответ написан
    Комментировать
  • Как убрать ввод исходных чисел и операций при тестировании программы на python?

    Vindicar
    @Vindicar
    RTFM!
    if __name__ == '__main__':
    Разберись, как это работает.
    Потом заверни в первом файле всё, что ниже класса Calculator, в такой же if.
    Ответ написан
  • Как в Python перейти на другой диск?

    Vindicar
    @Vindicar
    RTFM!
    directory = ''
    Пустой путь = текущий каталог.
    Просто задай начальный каталог здесь.
    Ответ написан
    Комментировать
  • Как в Python, используя logging, записать в traceback пойманного исключения значения локальных переменных функции?

    Vindicar
    @Vindicar
    RTFM!
    Попробуй создать свой LoggerAdapter или Filter. Вообще в доках есть секция на эту тему, почитай, может, найдешь что полезное.
    По сути, схема работы logging такая:
    • Logger предоставляет интерфейс генерации логов приложению, и создаёт объект-запись.
    • LoggerAdapter вызывается логгером, чтобы дополнить запись специфичной для программы контекстной информацией.
    • Filter определяет, какие записи реально выводить в лог, и может их менять
    • Formatter делает из записи строку.
    • Handler записывает записи по назначению.


    Либо, если тебя устраивает вариант делать это вручную, ты можешь передать в параметр exc_info методов логгера кортеж вида (класс исключения, объект исключения, трейсбэк). Тогда ты можешь подставить свой трейсбэк вместо "родного".
    Ответ написан
    Комментировать
  • Можно ли как то избежать авторизацию в терминале?

    Vindicar
    @Vindicar
    RTFM!
    Если у тебя учётка именно бота, то
    1. Получаешь токен бота от BotFather
    2. Используешь метод sign_in() с параметром bot_token
    Ответ написан
    Комментировать
  • Почему pyinstaller не видит библиотеку docxcompose?

    Vindicar
    @Vindicar
    RTFM!
    pyinstaller имеет механизм hidden imports, позволяющий принудительно включить в архив пакет, чьё использование pyinstaller "не заметил". Если ты им не пользуешься - почитай, как, и попробуй добавить туда проблемную библиотеку.

    Кроме того, у тебя ошибка говорит об отсутствии файла данных (XML), а не файла с кодом. Для этого тоже есть отдельный механизм, почитай про него.
    Ответ написан
    Комментировать
  • Как найти наиболее повторяющийся элемент?

    Vindicar
    @Vindicar
    RTFM!
    В текущем виде это задание, а не вопрос.
    А так, итерация по списку, выбор интересующих элементов в массив, затем collections.Counter() и его уже анализируешь на предмет максимумов.
    Ответ написан
  • Как реализовать escape-последовательность в файле конфигурации.ini?

    Vindicar
    @Vindicar
    RTFM!
    Вариант 1. В доках на configparser написан пример синтаксиса для многострочного строкового значения. Сформируй исходное значение в файле корректно, и парсер выдаст то, что нужно, без дополнительных прибабахов.

    Вариант 2. error_message = error_message.replace(r'\n', '\n')
    Ответ написан
    Комментировать
  • Почему происходит 1 изменение но другое не происходит в word с python docx?

    Vindicar
    @Vindicar
    RTFM!
    Вполне возможно, что строка "Павлово-Посадский городской округ -" занимает несколько соседних runs.
    Тебе нужно сначала попробовать найти параграф, у котого в text эта строка вообще встречается. Если найдёшь - то тогда придётся как-то идентифицировать runs, в которых содержатся части этой строки, и обрабатывать их по кусочкам.

    Это, к слову, относится и к коротким строкам - никто не запрещает создать документ, где "местное" будет занимать 7 runs по одной букве каждый...
    Ответ написан
    Комментировать
  • Как вывести список из декоратора функции в Python?

    Vindicar
    @Vindicar
    RTFM!
    Просто сделай список из кортежей.
    calls = []
    func = 'sum'
    iterations = 9001
    time = 42.0
    calls.append( (func, iterations, time) )
    Ответ написан
    Комментировать