How do I tell pylint about a descriptor providing access to iterables, subscriptables?

Question:

I have a decorator that I can use to mark a read-only class property:

class class_ro_property(property):
    def __init__(self, getter:Callable):
        self._getter = getter

    def __get__(self, _, cls):
        return self._getter(cls)

class MyClass:
    @class_ro_property
    def my_property(cls):
        return [1, 2, 3]

The problem is that pylint doesn’t understand this at all. If I try to write:

for num in MyClass.my_property:
    print(num)

it will tell me:

E1133:0035:Non-iterable value MyClass.my_property is used in an iterating context

The same problem happens if I try to subscript it, ie MyClass.my_property[0].

Is there some way to tell pylint about the use of a descriptor here? If not, is there some way to tell pylint at the property definition (and not only where it’s used) not to complain about its use in an iterating context?

Asked By: Tom

||

Answers:

My suggestion would be to write a metaclass that defines the property:

class MyMetaClass(type):
    @property
    def my_property(cls):
        return [1, 2, 3]

class MyClass(metaclass=MyMetaClass):
    my_property = MyClassMeta.my_property

for num in MyClass.my_property:
    print(num)

Pylint is fine with that use of MyClass.my_property. Note that if you don’t need MyClass().my_property to get it on instances, you can omit the line my_property = MyClassMeta.my_property.

Answered By: Jasmijn

The straight answer is: that is a short-comming of the linter. A feature request should be open against "pylint" pointing to the fact it does not recognize descriptors.

That said, just strap a comment to skip linting where you are getting this problem as a workaround. Adding a comment like # pylint: disable=E1133 on the offending line should do the job.

When coding Python, one has to keep in mind that auxiliary tooling like linters and static type checkers do not have how to know everything that happens at runtime. Not recognizing a descriptor, like here, is a shortcoming of pylint, and they could implement the feature (though I doubt they will) – but there are other cases where that is not feasible at all.

(Judging by the other answer, pylint opts for special casing the property call, but ignores that property itself is just one use-case of descriptors)

By the way, I can’t find this specific error in the pylint error codes at http://pylint-messages.wikidot.com/all-codes – maybe it is provided by an specific extension? You might just want to throw away such an extension if it is doing more harm than good.

Answered By: jsbueno