This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author finnjavier08
Recipients finnjavier08
Date 2021-08-18.02:06:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1629252402.72.0.293302326241.issue44941@roundup.psfhosted.org>
In-reply-to
Content
In _collections_abc.py is a private function titled `_check_methods`. It takes a class and a number of method names (as strings), checks if the class has all of the methods, and returns NotImplemented if any are missing. The code is below:

```
def _check_methods(C, *methods):
    mro = C.__mro__
    for method in methods:
        for B in mro:
            if method in B.__dict__:
                if B.__dict__[method] is None:
                    return NotImplemented
                break
        else:
            return NotImplemented
    return True
```

This is an incredibly convenient function (referred to as check_methods here on out) for creating abstract base classes, and is much simpler than using `hasattr` for each method you want to check. For example:

```
>>> from abc import ABCMeta
>>> # Without check_methods
>>> class A(metaclass=ABCMeta):
...     @classmethod
...     def __subclasshook__(cls, subclass):
...         return (hasattr(subclass, 'foo') and
...                 callable(subclass.foo) and
...                 hasattr(subclass, 'bar') and
...                 callable(subclass.bar) or
...                 NotImplemented)
...
>>> # With check_methods
>>> class B(metaclass=ABCMeta):
...     @classmethod
...     def __subclasshook(cls, subclass):
...         return check_methods(subclass, 'foo', 'bar')
...
>>>
```

This would be a great function to add to the standard lib, perhaps in the `abc` module.

One problem with `check_methods` as defined in _collections_abc.py is that it doesn't check if the name is callable. Also, type hints and more readable variables may be desirable. The final code, if implemented, may look something like this:

```
# In imports section: from typing import Literal
def check_methods(Class: type, *methods: str) -> Literal[True, NotImplemented]:
    """Check if class `Class` has methods `methods`."""
    mro = Class.__mro__
    for method in methods:
        for Base in mro:
            if (attr := getattr(Base, method, None)) is not None:
                if not callable(attr):
                    return NotImplemented
                break
        else:
            return NotImplemented
    return True
```

Again, this would be a great function to add to the `abc` module or a similar one.
History
Date User Action Args
2021-08-18 02:06:42finnjavier08setrecipients: + finnjavier08
2021-08-18 02:06:42finnjavier08setmessageid: <1629252402.72.0.293302326241.issue44941@roundup.psfhosted.org>
2021-08-18 02:06:42finnjavier08linkissue44941 messages
2021-08-18 02:06:42finnjavier08create