Skip to content

Bug: raising a nested error class causes spurious ‘member is not assignable’ error #1968

Closed
@sietse

Description

@sietse

First off, thank you all for the delightful mypy tool. I really enjoy it every day I use it. ^_^

As for the bug report, mypy gives a spurious error in this scenario:

I have a class Shift with, nested inside it, the exception class
Shift.AlreadyCovered. The Shift.cover() method, which is annotated to
return None, will raise self.AlreadyCovered under certain circumstances. A
mypy check then complains that Member "AlreadyCovered" is not assignable.
See cover1 in the example below.

Mypy does not give an error in these variants:

  • a method is not annotated to return None (cover2)
  • a method raises an exception defined outside the current class (cover3)
  • a method raises an exception defined outside the current class via a
    reference defined inside the current class. (cover4)

Minimal example of the error:

class Shift:

    # A nested exception class defined inside the current class
    class AlreadyCovered(Exception):
        pass
    # If a method is annotated to return None, then raising the nested
    # exception class gives a mypy error
    #     x.py: note: In member "cover1" of class "Shift":
    #     x.py:11: error: Member "AlreadyCovered" is not assignable
    def cover1(self) -> None:
        raise self.AlreadyCovered  # <-- ERROR HERE

The variants that don't raise errors:

# An exception class defined outside the main (Shift) class
class OuterAlreadyCovered(Exception):
    pass

class Shift:

    # A nested exception class defined inside the current class
    class AlreadyCovered(Exception):
        pass

    # If a method is not annotated to return None, then mypy is okay
    # with raising the nested exception class
    def cover2(self):
        raise self.AlreadyCovered

    # Raising an exception defined outside the current class is fine.
    def cover3(self) -> None:
        raise OuterAlreadyCovered

    # Raising a reference defined inside the current class to an
    # exception defined outside the class is fine.
    def cover4(self) -> None:
        raise self.BorrowedAlreadyCovered

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions