pylint-bot / pylint-unofficial

UNOFFICIAL playground for pylint github migration
0 stars 0 forks source link

[regression] False positive for no-member in 1.5.0 #709

Open pylint-bot opened 8 years ago

pylint-bot commented 8 years ago

Originally reported by: Rémi Alvergnat (BitBucket: Toilal, GitHub: @Toilal?)


I'm trying to reproduce in a small environment, but it currently occurs in https://github.com/Toilal/rebulk. (I've disabled no-member as a workaround)

It was working properly on 1.4.x


pylint-bot commented 8 years ago

Original comment by BitBucket: dmand, GitHub: @dmand?:


Okay, so here's the smaller code sample for reproducing one of false positives from the repo (this one was taken from rebulk.rules and truncated a bit).

from abc import ABCMeta, abstractmethod
from types import GeneratorType

import six

def is_iterable(obj):
    return hasattr(obj, '__iter__') and not isinstance(obj, str) or isinstance(obj, GeneratorType)

@six.add_metaclass(ABCMeta)
class Consequence(object):
    @abstractmethod
    def then(self, matches, when_response, context):
        pass

class AppendTags(Consequence):
    def __init__(self, tags):
        self.tags = tags
        self.remove = RemoveMatch()

    def then(self, matches, when_response, context):
        removed = self.remove.then(matches, when_response, context)
        if is_iterable(removed):
            removed = list(removed)
            for match in removed:
                match.tags.extend(self.tags)
        elif removed:
            removed.tags.extend(self.tags)  # Error: Instance of 'list' has no 'tags' member (no-member)

class RemoveMatch(Consequence):
    def then(self, matches, when_response, context):
        if is_iterable(when_response):
            ret = []
            when_response = list(when_response)
            for match in when_response:
                if match in matches:
                    matches.remove(match)
                    ret.append(match)
            return ret
        else:
            if when_response in matches:
                matches.remove(when_response)
                return when_response

The trouble comes from the fact that RemoveMatch.then method can return either a list or its second argument value. And in AppendTags.then pylint is unable to see the assertion made with if-statement, so it emits the warning about possible list value of removed not having tags member.

Possible solutions:

pylint-bot commented 8 years ago

Original comment by Marcin Barczyński (BitBucket: marcinbarczynski, GitHub: @marcinbarczynski?):


More examples in python 2.7:

#!python

try:
    open("a")
except Exception as e:
    if isinstance(e, OSError):
        print e.errno

pylint 1.5 prints: [E1101(no-member), ] Instance of 'Exception' has no 'errno' member

#!python

import Queue
from multiprocessing.managers import SyncManager

SyncManager.register('LifoQueue', Queue.LifoQueue)

[E1101(no-member), ] Class 'SyncManager' has no 'register' member