Skip to content

Checking for abstractmethod implementation fails to consider MRO for builtins #79244

Open

Description

@anntzer
mannequin
BPO 35063
Nosy @anntzer, @tirkarthi, @iritkatriel

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2018-10-25.08:51:44.892>
labels = ['type-bug', 'library', '3.9', '3.10', '3.11']
title = 'Checking for abstractmethod implementation fails to consider MRO for builtins'
updated_at = <Date 2021-12-06.13:46:09.435>
user = 'https://github.com/anntzer'

bugs.python.org fields:

activity = <Date 2021-12-06.13:46:09.435>
actor = 'iritkatriel'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2018-10-25.08:51:44.892>
creator = 'Antony.Lee'
dependencies = []
files = []
hgrepos = []
issue_num = 35063
keywords = []
message_count = 2.0
messages = ['328419', '407805']
nosy_count = 3.0
nosy_names = ['Antony.Lee', 'xtreak', 'iritkatriel']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue35063'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

Activity

  1. anntzer commented on Oct 25, 2018

    anntzermannequin
    MannequinAuthor

    When checking whether a class implements all abstractmethods (to know whether the class can be instantiated), one should only consider methods that come *before* the abstractmethod in the MRO -- methods that come after cannot be said to override the abstractmethod. Indeed, this is currently the case:

        from abc import ABC, abstractmethod
    
        class NeedsFoo(ABC):
            foo = abstractmethod(lambda self: None)
    
        class HasFoo(ABC):
            foo = lambda self: None
    
        class FooImplFirst(HasFoo, NeedsFoo): pass
        class FooImplSecond(NeedsFoo, HasFoo): pass
    
        FooImplFirst()
        try: FooImplSecond()
        except TypeError: pass
        else: raise Exception("Expected error")

    Here FooImplFirst correctly overrides the foo method (using the HasFoo mixin first), so can be instantiated; FooImplSecond doesn't (by the MRO, FooImplSecond().foo would resolve to the abstract implementation), and we get a TypeError on instantiation.

    However, this is not the case when considering builtins:

        from abc import ABC, abstractmethod
    
        class NeedsKeys(ABC):
            keys = abstractmethod(lambda self: None)
    
        HasKeys = dict  # dict has a keys method.
    
        class KeysImplFirst(HasKeys, NeedsKeys): pass
        class KeysImplSecond(NeedsKeys, HasKeys): pass
    
        KeysImplFirst()
        try: KeysImplSecond()
        except TypeError: pass
        else: raise Exception("Expected error")

    This example differs from the first only by having dict be the mixin that provides the keys method. However, running this example shows that KeysImplSecond() will incorrectly succeed: the ABC machinery does not realize that the keys method has not been overridden.

    (Alternatively, one could say that "providing the method later in the MRO" is also sufficient; I think that goes against the expectations about ABCs but at least consistency between the non-builtin and builtin cases would be better.)

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Oct 25, 2018
  3. iritkatriel commented on Dec 6, 2021

    @iritkatriel
    Member

    See also bpo-37927.

  4. added
    3.11only security fixes
    type-bugAn unexpected behavior, bug, or error
    and removed on Dec 6, 2021
  5. transferred this issue fromon Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of life3.11only security fixes3.9 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions