pylint icon indicating copy to clipboard operation
pylint copied to clipboard

False positive ``not-an-iterable`` with ``attr.s`` inheritance when base class is not an ``attr.s`` class

Open pradyunsg opened this issue 6 years ago • 5 comments

Steps to reproduce

Run pylint on the following file:

"""Minimal repro for pylint's not-an-iterable error.
"""
from typing import List

import attr


class Model(object):
    """Basic model showing pylint's not-an-iterable error.
    """

    @classmethod
    def attributes(cls):
        # type: () -> List[str]
        """Get attributes of a model.
        """
        # The iteration here triggers the warning
        return [a.name for a in attr.fields(cls)]


@attr.s
class Basic(Model):
    """Basic model that's inherited, showing pylint's not-an-iterable error.
    """
    hello = attr.ib()  # type: str

assert Basic.attributes() == "hello"

Current behavior

An error (not-an-iterable) is found:

pylint_reproducer.py:18:32: E1133: Non-iterable value attr.fields(cls) is used in an iterating context (not-an-iterable)

Expected behavior

No errors are raised, as the code is valid and works.

pylint --version output

pylint 2.3.1
astroid 2.2.5
Python 3.7.3 (default, Mar 27 2019, 09:23:15)
[Clang 10.0.1 (clang-1001.0.46.3)]

pradyunsg avatar Jun 27 '19 10:06 pradyunsg

Adding an @attr.s on the base Model class works in the example above -- it seems to be a case of pylint's logic for attrs magic, not considering base classes somehow.

FWIW, my actual Model class has __init__() so I am doing attr.s(init=False).

pradyunsg avatar Jun 27 '19 10:06 pradyunsg

Thanks for the report!

PCManticore avatar Jul 06 '19 08:07 PCManticore

I am seeing issues with inheritance in the following code:

from abc import ABC

import attr


@attr.s(auto_attribs=True)
class AttrBase:
    member: int


class AttrSub(AttrBase):
    pass


if __name__ == "__main__":
    attr_sub = AttrSub(1)
    print(attr_sub.member)

Pylint results:

> pylint --disable=all --enable=no-member .\test.py
************* Module test
test.py:17:10: E1101: Instance of 'AttrSub' has no 'member' member (no-member)

Pylint version:

pylint 2.5.3
astroid 2.4.2
Python 3.7.4 

Should I report it as a separate issue?

tmr232 avatar Aug 18 '20 09:08 tmr232

Possibly related to https://github.com/PyCQA/astroid/issues/1330 in astroid 2.10

Pierre-Sassoulas avatar Feb 02 '22 09:02 Pierre-Sassoulas

When we infer attr.fields in the unannotated base class, we get nodes.None: attrs = getattr(cls, "__attrs_attrs__", None). If we annotate the base class, we infer an iterable.

We could check to see if any child classes of the class being checked have the annotation, but this would fail if the parent and child classes are in separate files.

Also note that in the example above, calling Model.attributes() raises attr.exceptions.NotAnAttrsClassError: <class '__main__.Model'> is not an attrs-decorated class.

This is definitely a false positive but I do not immediately see a solution and my suggestion is to annotate the base class as well.

areveny avatar Feb 27 '22 21:02 areveny