Правильный ввод кортежа исключений / ошибок в python при использовании mypy - PullRequest
1 голос
/ 22 апреля 2020

Я написал свой собственный декоратор add_warning для печати сообщений об ошибках Costom при возникновении определенных ошибок. Декоратор принимает сообщение и тип ошибок, для которых нужно напечатать это сообщение. Я также хотел бы добавить набор текста к этому декоратору и проверить его, используя mypy. Это хорошо работает в случае, когда я просто выбрасываю простой Exception, когда использую Type[Exception]. Однако mypy жалуется, когда я использую другие ошибки, такие как OSError или AttributeError, говоря:

error: Argument "errors" to "add_warning" has incompatible type "Tuple[Type[OSError], Type[AttributeError]]"; expected "Union[str, Type[Exception], Tuple[Type[Any]]]".

Кто-нибудь знает, есть ли лучший способ, чем используйте Any или Tuple[Type[OSError], Type[AttributeError]] здесь? В частности, существует ли более общий тип для всех Python ошибок?

Ниже приведен код:

from functools import wraps
from typing import Union, Tuple, Callable, Type


def add_warning(message: str, flag: str = 'Info',
                errors: Union[str, Type[Exception], Tuple[Type[Exception]]] = 'all') -> Callable:
    """
    Add a warning message to a function, when certain error types occur.
    """
    if errors == 'all':
        errors = Exception

    def decorate(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
            except errors:
                warn(message, flag)
                return []
            else:
                return result
        return wrapper
    return decorate


def warn(message: str, flag: str = 'Info') -> None:
    """Print the colored warning message."""
    print(f"{flag}: {message}")


if __name__ == '__main__':

    @add_warning('This is another test warning.', flag='Error')
    def test_func1():
        raise Exception

    @add_warning('This is a test warning.', flag='Error', errors=(OSError, AttributeError))
    def test_func2():
        raise OSError

    test_func1()
    test_func2()

1 Ответ

1 голос
/ 22 апреля 2020

Проблема в том, что Tuple[Type[Exception] означает кортеж с одним значением. Вы хотите кортеж переменного размера, так что используйте эллипсы: Tuple[Type[Exception], ...] Следующее работает без жалоб mypy:

from functools import wraps
from typing import Union, Tuple, Callable, Type


def add_warning(message: str, flag: str = 'Info',
                errors: Union[str, Type[Exception], Tuple[Type[Exception], ...]] = 'all') -> Callable:
    """
    Add a warning message to a function, when certain error types occur.
    """
    if errors == 'all':
        errors = Exception

    def decorate(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
            except errors:
                warn(message, flag)
                return []
            else:
                return result
        return wrapper
    return decorate


def warn(message: str, flag: str = 'Info') -> None:
    """Print the colored warning message."""
    print(f"{flag}: {message}")


if __name__ == '__main__':

    @add_warning('This is another test warning.', flag='Error')
    def test_func1():
        raise Exception

    @add_warning('This is a test warning.', flag='Error', errors=(OSError, AttributeError))
    def test_func2():
        raise OSError

    test_func1()
    test_func2()
...