Может ли API сказать Pylint, чтобы он не жаловался в коде клиента?

У меня есть код в классе многоразового использования, который изменяет некоторые типы. Вот упрощенная версия.

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

В реальном коде "current_count" - это переменная, а не фиксированная строка, поэтому я не написал:

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

Теперь, когда мои клиенты приходят использовать новую функцию, Pylint в ужасе прыгает вверх и вниз.

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()

Каждый класс, который использует эту новую функцию, подвергается наказанию, и я вынужден отключить сообщение в каждой ссылке. Я бы СЕЙЧАС поместил некоторый код в API, чтобы Pylint успокоился, когда есть неизвестные ссылки на этот класс.

Увы, документация Pylint... ммм... не такого качества, чтобы мне было понятно, и я не смог найти там никаких предложений.

Итак, все сводится к следующему: могу ли я указать pylint в своем коде API на отключение правила E1101 по отношению к этому классу всякий раз, когда клиент обращается к нему? Есть ли другое решение?

3 ответа

Решение

Вот мое решение, вдохновленное примером из рецепта кулинарной книги ActiveState, приведенным в ответе Yoni H.

В класс Foo я добавил этот бесполезный __getattr__ метод.

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))

Это должно быть почти неотличимо от предыдущей версии. Он не должен вызываться при нормальном ходе событий, но этого достаточно, чтобы убедить Пилинта молчать об этой ошибке.

ps Вы можете ворчать, что этот код не очень красивый. Я разделяю это мнение. Но я думаю, что его преимущества для клиента перевешивают его запах кода.

После одного из ваших комментариев, поскольку вы собираетесь использовать тип Enumerated, почему бы не взглянуть на этот вопрос SO или этот рецепт кулинарной книги ActiveState?

Из личных предпочтений я бы выбрал добавление перечислимых типов в класс, как один из ответов в вопросе SO (бесстыдно скопировано для контекста):

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")

С практической точки зрения, почему предположение о том, что пилинт (или любой ворс) должен молчать? Учитывая смещение между ложными срабатываниями и ложными отрицаниями, линты должны отдавать предпочтение первым. Мне кажется, что из-за того, что Pylint выражает свои результаты в виде баллов, люди считают, что их следует максимизировать, но призовых за "победу" не существует.

С другой стороны, конструкция, на которую она жалуется, безусловно, некрасива. Я понимаю, что server_api упрощен для нашего удобства, но вам действительно нужно копаться с пространством имен модуля? Из кода вашего клиента видно, что current_count Имя метода жестко запрограммировано, почему не на сервере?

Другие вопросы по тегам