Question

I have some code in a reusable class that modifies some types. Here's a simplified version.

class Foo:
    def __init__(self):
        self.count = 0

    def increment(self):
        self.count += 1

# Add another method outside of the class definition.
# Pylint doesn't care about this, and rates this file 10/10.

Foo.__dict__["current_count"] = lambda self: self.count

In the real code, "current_count" is a variable, not a fixed string, which is why I didn't write:

Foo.current_count = lambda self: self.count # Cannot do in my scenario.

Now, when my clients come to use the new function, Pylint jumps up and down in horror.

import server_api

def main():
    foo_count = server_api.Foo()
    foo_count.increment()


    print foo_count.current_count()
    # Pylint complains here:
    #     E1101:  8:main: Instance of 'Foo' has no 'current_count' member
    # I don't want to have to tell pylint to disable that message in every client.

main()

Every class that uses this new function gets chastised, and I am forced to disable the message in every reference. I would RATHER put some code in the API to tell Pylint to chill when there are unknown references on this class.

Alas, the pylint documentation is... ummm... not of a quality conducive to my understanding, and I have been unable to find any suggestions there.

So boiling it down: Can I tell pylint in my API code to turn off the E1101 rule in relation to this class, whenever a client refers to it? Is there another solution?

Was it helpful?

Solution

Here is my solution inspired by the example in ActiveState cookbook recipe, provided in Yoni H's answer.

To the Foo class, I added this useless __getattr__ method.

def __getattr__(self, name):
    # This is only called when the normal mechanism fails, so in practice should never be called.
    # It is only provided to satisfy pylint that it is okay not to raise E1101 errors in the client code.
    raise AttributeError("%r instance has no attribute %r" % (self, name))

This should be nigh indistinguishable from the previous version. It should not be called in the normal course of events, but it is enough to persuade pylint to remain quiet about this error.

p.s. You are allowed to grumble that this code isn't very pretty. I share that opinion. But I think its benefits for the client outweigh its code smell.

OTHER TIPS

Following one your comments, since you're going for an Enumerated type, why not have a look at this SO question, or this ActiveState cookbook recipe?

Out of personal preference, I'd choose adding the enumerated types into the class, just like one of the answers in SO question (copied shamelessly for context):

class Animal:
   def __init__(self, name):
       self.name = name

   def __str__(self):
       return self.name

   def __repr__(self):
       return "<Animal: %s>" % self

Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")

Pragmatically speaking, why the assumption that pylint (or any lint) should be silent? Given a bias between false positives and false negatives, lints should prefer the former. It seems to me that because Pylint expresses its results as a score that people assume it should be maximized, but there is no prize for "winning".

On the other hand, the construct it is complaining about is certainly ugly. I understand that the server_api is simplified for our convenience, but do you really need to muck about with the module namespace? From your client code it appears that the current_count method name is hard coded, why not in the server?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top