6. Поиск определений ctags
● Основан на поиске определений в файле TAGS
● Генерация TAGS файла происходит внешней программой
● При изменении исходного кода необходимо
перегенерировать TAGS файл
● Чуть менее глупый grep
7. Пример генерации TAGS файла
$ ctags -a -e -f TAGS --tag-relative -R .
$(python -c "import sys; print('n'.join(sys.path)))
11. Проверка корректности flake8
$ flake8 examples/calc.py
examples/calc.py:3:1: E302 expected 2 blank lines, found 1
examples/calc.py:7:1: E302 expected 2 blank lines, found 1
examples/calc.py:13:1: E128 continuation line under-indented for visual indent
examples/calc.py:13:27: E901 SyntaxError: invalid syntax
examples/calc.py:14:5: E128 continuation line under-indented for visual indent
examples/calc.py:15:1: E901 TokenError: EOF in multi-line statement
12. Old school refactoring assistant
$ diff examples/calc.py <(autopep8 examples/calc.py)
18c17
< if __name__=='__main__':
---
> if __name__ == '__main__':
14. Статические анализаторы
● Работают на уровне AST программы
● Выводят тип конкретного выражения для определения
свойств узла
● Хорошо подходят для языков со статической типизацией
● Примеры
– libclang
– jedi
– tern
– merlin
15. Основные свойства
Pros
● Безопасные
● Единственное решение при
компиляции в native
● Хорошо решают проблемы
подсветки кода, рефакторинга
и проверки корректности
Cons
● Сложны в реализации
● Плохо интегрируются в
runtime
● Грамматика языка должна
быть контекстно-независимой
● Остро стоит проблема
кэширования
16. ●Вывод типов в языках с динамической
типизацией
● Основан на предположениях
● Type hinting
– python annotations
def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
– sphinx docs
:type options: list of str
:arg options: options for "rash daemon" command
17. Динамические анализаторы
● Обычно работают внутри запущенного процесса
● Часто интегрируются с REPL
● Анализируют исполняемый код вместо текста программ
● Примеры
– Slime
– IPython
– Pry
18.
19.
20. Основные свойства
Pros
● Легко реализовать для языков
с интроспекцией
● Нет проблемы
неопределённости типов
Cons
● Небезопасные в силу
исполнения кода
● В языках без интроспекции
необходимо декомпилировать
объект анализа
● При изменении кода
необходимо перезагружать
модули
● Плохо подходят для проверки
корректности и рефакторинга
21. Проблема синтаксических ошибок
Статические анализаторы могут решить проблему
использованием парсера, игнорирующего ошибки программы
при поиске кандидатов для дополнения, но учитывающего их
при проверки корректности
24. Предположения
● Небольшое количество побочных эффектов
● Отсутствие использования магии
– metaclasses
– setattr()
– __import__
– write to object.__dict__
26. Parser
● Предоставляет tree-like объект для работы с кодом
● Игнорирует синтаксические ошибки
● Пропускает большую часть операторов
● Дополнительно обрабатывает Array и Call
27. Вычисление python кода
● Алгоритм основан на ленивых вычислениях
● eval_statement – точка входа в статический анализатор
● Анализ кода происходит в обратном направлении от
„курсора“
29. Что происходит
● Evaluator.eval_statement пропускается, так как нет
присваивания
● Evaluator.eval_element ищет полный путь доступа через
атрибуты
● Evaluator.find_types ищет в AST определение datatime в
наиболее удалённой области видимости, находит в
глобальной области видимости import
● Используя логику import ищется модуль datetime
● find_types вызывается повторно в eval_element для поиска
внутри найденного модуля
30. Правила игры
● find_type вызывается для каждого обращения к атрибуту
● eval_statement вызывается для каждого
– обращения по индексу
– присваивания в области видимости
– вызова callable
● Вычисляются только необходимые операторы для поиска
дополнений
31. Дополнительные оптимизации
● Анализ операторов ограничивается поиском классов
● Дополнительно обрабатываются следующие методы
– __call__
– __bool__
– __mro__
– __getattribute__
● if работает только в случае isinstance
32. Дополнительные оптимизации
● Весь модуль сканируется на list append/insert
● Учитываются вызовы функций
def foo(bar):
bar. # completion here
foo(1)
● Предопределены результаты для стандартных
скомпилированных модулей
● Отдельная подсистема для дополнения импортов
33. Дополнительные оптимизации
● Parser cache основанный на pickle
● Счётчик рекурсии останавливает анализ на приемлемой
глубине
● Для упрощения эти модули потоконебезопасны
34. # This is never executed, but tricks static analyzers (PyDev, PyCharm,
# pylint, etc.) into knowing the types of these symbols, and what
# they contain.
STATICA_HACK = True
globals()['kcah_acitats'[::-1].upper()] = False
if STATICA_HACK: # pragma: no cover
from celery.app import shared_task # noqa