Comment 6 for bug 1825435

Jay Pipes (jaypipes) wrote :

Matt, could this patch have anything to do with this you think?

https://github.com/openstack/oslo.config/commit/6c951ed373f443727a8ea2d10d346ad769285aa2

It's changing out the base class for ConfigOpts and GroupAttr. When I looked at the collections.abc implementations in Python2 and Python3.7, I noticed there were some differences in how the base classes that comprise collections.abc.Mapping "calculate" attributes.

In the case of Python2, there is a _hasattr() module-level function that is used to determine if a particular attribute *or* method exists. For example, one of the base metaclasses that collections.Mapping derives from is Container, which uses this _hasattr() function to determine if the subclass overrides the __contains__ magic method:

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if _hasattr(C, "__contains__"):
                return True
    return NotImplemented

https://github.com/python/cpython/blob/2.7/Lib/_abcoll.py#L116

Compare this to the Python3.7 Container class's similar implementation:

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            return _check_methods(C, "__contains__")
    return NotImplemented

https://github.com/python/cpython/blob/3.7/Lib/_collections_abc.py#L385

If we look at Python2's _hasattr() compared to Python3.7's _check_methods() function, we see some differences:

Python2:

def _hasattr(C, attr):
    try:
        return any(attr in B.__dict__ for B in C.__mro__)
    except AttributeError:
        # Old-style class
    return hasattr(C, attr)

Python 3.7:

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

Given the stacktrace that seems to be occurring, I think it might be worthwhile to revert https://github.com/openstack/oslo.config/commit/6c951ed373f443727a8ea2d10d346ad769285aa2 and see if that might indeed be the culprit here.

Just a thought,

-jay