4

My code uses the commonly used cached_property class from werkzeug. Consider the following snippet:

from werkzeug import cached_property

class SampleClass(object):
    @cached_property
    def list_prop(self):
        return [1, 2]

sample = SampleClass()
for item in sample.list_prop:
    print item

I use pylint in my CI process. If I run the pylint not-an-iterable check on this code, it fails even though the code is perfectly fine.

$ pylint --disable=all --enable=not-an-iterable prop.py
************* Module prop
E:  9,12: Non-iterable value sample.list_prop is used in an iterating context (not-an-iterable)

pylint works well when checking the same code with the built-in @property decorator instead of @cached_property:

class SampleClass(object):
    @property
    def list_prop(self):
        return [1, 2]

What should I do to help pylint overcome this false positive?

Alon
  • 625
  • 7
  • 13
  • If you are not using Python 3, then your classes should descend from `object`. If you are using Python 3, then you can (probably) apply a suitable type annotation, though whether `pylint` is smart enough to understand that is a bit of an open question. In any event, you can always use a `# pylint: disable` comment. – Kevin Feb 05 '17 at 00:18
  • I am using Python 2.7 and inheritance from `object`. The sample here was missing it. I will edit the code snippets. @Kevin - I am not sure why you believe this inheritance should make the difference in this case. – Alon Feb 05 '17 at 00:30
  • The descriptor protocol does not work if you do not inherit from `object`. That causes all manner of things to break down including `@property` and similar toys. – Kevin Feb 05 '17 at 06:04

2 Answers2

3

Looks like you are importing cached_property incorrectly. It lives in werkzeug.utils. pylint caught that error: E: 1, 0: No name 'cached_property' in module 'werkzeug' (no-name-in-module). Here's the fixed code:

from werkzeug.utils import cached_property

class SampleClass(object):
    @cached_property
    def list_prop(self):
        return [1, 2]

sample = SampleClass()
for item in sample.list_prop:
    print item

When I run pylint after applying this fix, it stops complaining:

$ pylint test
No config file found, using default configuration
************* Module test
C:  1, 0: Missing module docstring (missing-docstring)
C:  3, 0: Missing class docstring (missing-docstring)
C:  5, 4: Missing method docstring (missing-docstring)
R:  3, 0: Too few public methods (1/2) (too-few-public-methods)
C:  8, 0: Invalid constant name "sample" (invalid-name)
Srikanth
  • 973
  • 2
  • 9
  • 19
  • 1
    The import is actually correct but it uses a [custom dynamic import mechanism](https://github.com/pallets/werkzeug/blob/2b2d921eea7d1f896ce436ec5238890abe8b81bf/werkzeug/__init__.py#L115) which pylint will not infer. Importing `cached_property` from its actual location works like a charm! – Alon Feb 05 '17 at 00:44
1

I face the same problem when I use the Django+ pylint : the code is as follows:

queryset = A.objects.filter(col_a='a',col_b='b')

It will show error message:

Non-iterable value queryset is used in an iterating context (not-an-iterable)

My solution is as follows(+all()):

queryset = A.objects.filter(col_a='a',col_b='b').all()

It actually solved my problem, I know it seems has no much related to the issue but I google 'pylint + Non-iterable', this page will be on the top of search result, so I want to put the solution here,thanks

Deft-pawN
  • 943
  • 10
  • 12