VSCode, Python3.7: ошибка без элемента pylint с пользовательским оформленным классом

#python-3.x #visual-studio-code #pylint

#python-3.x #visual-studio-code #pylint

Вопрос:

Недавно я переместил метод экземпляра из его определения класса и поместил его в качестве глобальной функции (в примере: deco_function), чтобы иметь возможность снова использовать его в разных классах. Смотрите Следующий код для подробного объяснения и воспроизведения ошибок:

 def deco_function(cls):
    
    def inner_fct(self):
        print('do something')

    cls.deco_function = inner_fct
    return cls

@deco_function
class Something:

    def __init__(self):
        print('init')
        self.deco_function()
        print('done')

if __name__ == '__main__':
    a = Something()
  

Код работает нормально, печать

 init
do something
done
  

однако VSCode подчеркивает self.deco_function() красным цветом, а pylint указывает, что экземпляр ‘Something’ не имеет элемента ‘deco_function’.

Есть ли обходной путь, запрещающий pylint отмечать это или заставляющий VSCode распознавать deco_function как элемент экземпляра?

Спасибо за любой совет.

Ответ №1:

Вы должны использовать плагин PyLint, чтобы указать, какие члены класса генерируются во время выполнения

Создайте файл pylint_decorator.py где-нибудь на вашем PYTHONPATH

 import astroid
from astroid import MANAGER

def register(linter):
  # Needed for registering the plugin.
  pass

def transform(cls):
  if not cls.decorators: return
  if any(map(lambda x: x.name == 'deco_function', cls.decorators.nodes)):
    extension_module = astroid.parse("""
def deco_function(self):
  pass
""")
    for name, objs in extension_module.locals.items():
      cls.locals[name] = objs

MANAGER.register_transform(astroid.ClassDef, transform)
  

затем настройте VSC со следующим параметром

 "python.linting.pylintArgs": ["--load-plugins", "pylint_decorator"]
  

Это работает только в том случае, если вы используете @deco_function синтаксис.

Если вы вызовете функцию декоратора, PyLint не увидит использование декоратора

 # this use will not be catched by the plugin
class Something:
    def __init__(self):
        print('init')
        self.deco_function()
        print('done')
Something = deco_function(Something)
  

Комментарии:

1. Кажется, есть еще один недостаток: <class 'UnboundLocalError'>: local variable 'extension_module' referenced before assignmentpylint(astroid-error) есть идеи? Теперь эта ошибка появляется в любом модуле, который я открываю…

2. Я обнаружил, что astroid также отслеживает декораторов, поэтому нет необходимости называть явные классы

3. что вы увидите, если используете команду pylint -E --load-plugins pylint-decorator deco_test.py . Является ли ваш отступ в плагине идентичным предоставленному коду?

4. Я думаю, у меня был неправильный отступ внутри astroid.parse() метода. Ошибка больше не отображается, но pylint, похоже, стал более чувствительным… : D много замечаний.

5. Явная команда вызывает ImportError : No module named 'pylint_decorator' ошибку. Это странно, поскольку, похоже, это все равно работает.