guilatrova / tryceratops

A linter to prevent exception handling antipatterns in Python (limited only for those who like dinosaurs).
MIT License
427 stars 25 forks source link

TRY003 docs should include an example for `ExceptionGroup` as well #68

Open lanzz opened 1 year ago

lanzz commented 1 year ago

Disclaimer: I'm actually using ruff, which ports this violation from tryceratops, but looking at the source it looks like tryceratops will also emit a TRY003 violation when raising ExceptionGroup with a literal message.

The example given for Exception will not work with ExceptionGroup, because ExceptionGroup.__new__ still expects the message argument even if __init__ is overridden:

class MyExceptionGroup(ExceptionGroup):

    def __init__(self, excs):
        super().__init__('Baked-in message', excs)

ex = MyExceptionGroup([Exception()])

# TypeError: BaseExceptionGroup.__new__() takes exactly 2 arguments (1 given)

Overriding __new__ instead of __init__ works:

class MyExceptionGroup(ExceptionGroup):

    def __new__(cls, excs):
        return super().__new__(cls, 'Baked-in message', excs)

ex = MyExceptionGroup([Exception()])
str(ex)    # 'Baked-in message (1 sub-exception)'

But I'm struggling with proper type annotations for MyExceptionGroup:

import typing

ExceptionT_co = typing.TypeVar('ExceptionT_co', bound=Exception, covariant=True)

class MyExceptionGroup(ExceptionGroup[ExceptionT_co]):

    def __new__(cls, excs: typing.Sequence[ExceptionT_co]) -> typing.Self:
        return super().__new__(cls, 'Baked-in message', excs)

# line 9: error: Value of type variable "Self" of "__new__" of "ExceptionGroup" cannot be "Self"  [type-var]
# line 9: error: Argument 3 to "__new__" of "ExceptionGroup" has incompatible type "Sequence[ExceptionT_co]"; expected "Sequence[_ExceptionT_co]"  [arg-type]

_ExceptionT_co is defined as TypeVar('_ExceptionT_co', bound=Exception, covariant=True) in typeshed, which is literally the same type definition as the one I'm trying to use, but mypy still won't accept it, and I'm totally stumped about the "value of type variable Self cannot be Self" error.