Уже есть сотни великих Крючки около. Но что, если мы хотим еще один? Ну, читая Официальные документы Это отличное место для начала (и ссылки в будущем).
Что я хочу:
- показать пример Как можно разработать конкретную идею
- Опишите подводные камни, которые удивили меня больше всего (и как их преодолеть)
- привлечь внимание на такой замечательный инструмент, который
Предварительный коммит
является
Тема, которую я выбрал для иллюстрации – это выражения присваивания (PEP572). И вниз по линии я создадим три разных крючка для этого.
Препараты
Для экспериментов с крючками, уже существующими в дикой природе, вам понадобится только один репозиторий Git. И тогда вы настроили его для установки/использования крючков откуда-то еще.
Но чтобы написать свои собственные, должны быть два отдельных репозитория.
Давай начнем.
Если вы не установили Предварительный коммит в систему/окружающую среду – см. Документация о том, как это сделать.
Начните с базовой структуры, как это (две папки с git init)
[~/code/temp/try-pre-commit] $ tree -a -L 2 . ├── code │ └── .git └── hooks └── .git
- Создать манекен Крючки/.pre-Compad-tooks.yaml
$ touch hooks/.pre-commit-hooks.yaml
- Создать манекен код/эксперименты.txt.
$ touch code/experiments.txt
- CD в Код папка и инициализация Предварительный коммит (Не позволяйте этой второй установке запутать вас, он отличается от установки в систему/среду. Это обладает хранилищем – широкий, один файл HIT крючка, на самом деле)
$ cd code $ pre-commit install pre-commit installed at .git/hooks/pre-commit
Вот как это должно выглядеть сейчас
[~/code/temp/try-pre-commit] $ tree -a -L 2 . ├── code │ ├── experiments.txt │ └── .git └── hooks ├── .git └── .pre-commit-hooks.yaml
Пример 1: овладеть
Первый крючок будет очень простым, используя существующие возможности структуры. Я назову это “Walrus-grep”.
Обновление Крючки/.pre-Compad-tooks.yaml
- id: walrus-grep name: walrus-grep description: Warn about assignment expressions entry: "language: pygrep
Pygrep это кроссплатформенная версия Греп Отказ
Вход Принимает Regexp чего-то, чего вы не хотите совершать. В моем случае я использовал «: =» – шаблон без фактического регенерации волшебных или убегающих символов.
Обновление код/эксперименты.txt.
text file a := 1
Самый удобный способ эксперимента с try-repo
команда. Это позволяет тестировать крючки без комбинга .PRE-COMPY-TOUCKS.YAML Каждый раз и без закрепления до редакции позже в .Pre-Compad-config.yaml Отказ
Мы можем либо поставить файлы каждый раз перед запуском проверки или использования try-repo
Команда с --all-файлы
флаг.
[master][~/code/temp/try-pre-commit/code] $ pre-commit try-repo ../hooks walrus-grep --verbose --all-files
Это произошло, потому что крючки Reppo не имеют ни одного фиксации – нет ничего головы, чтобы указать. Совершать .PRE-COMPY-TOUCKS.YAML и повторить.
Смотрите ” (нет файлов, чтобы проверить) “? Часто это было бы правдой, чеки могут иметь заранее определенные ограничения E.g. Расширение файла, путь, игнорировать параметры. Но у нас есть наш Experiments.txt файл и не ожидайте ни одного из них!
Готча: --all-файлы
Флаг больше похоже на «все отслеживается , не только поэтапные файлы». Итак, в любом случае, вы должны добавить файлы в Git перед запуском проверки.
В конце концов! ” Не удалось «это то, что нам нужно было доказать, что крюк Grep»: = «Внутри какого-то случайных поэтапных файлов. Так что здесь неудача – это хорошо.
Но думать об этом ситуации далеко от идеала:
- Во-первых, мы на самом деле не хотим поймать »: = “Внутри текстовых файлов, только в Python Code
- Во-вторых, что если «: =» происходит внутри комментариев, Docstrings, строки?
Для «только код Python» здесь есть Типы: [Python]
Вариант, который я добавлю в .PRE-COMPY-TOURSS.YAML
- id: walrus-grep ... types: [python]
Мы видим: « (нет файлов для проверки) пропущены « Опять же, но сейчас ожидается.
Дважды проверить
$ mv experiments.txt experiments.py $ git add experiments.py $ pre-commit try-repo ../hooks walrus-grep --verbose --all-files
И у нас наша возлюбленная неудача обратно.
Что касается второй озабоченности: «: =« Внутри комментариев или Docstrings, нам потребуется что-то другое.
Пример 2: Аст
Второй крюк будет анализировать синтаксическое дерево, чтобы найти точный тип узла. Я назову это “Walrus-AST”.
Отказ от ответственности: Этот будет работать только в среде Python 3.8 (Beta1 в настоящее время доступна для тестирования).
Обновление Крючки/.pre-Compad-tooks.yaml
... - id: walrus-ast name: walrus-ast description: Warn about assignment expressions entry: walrus-ast language: python types: [python]
а также эксперименты
# .py file with `:=` (Python3.8 syntax) (x := 123)
Сам крючок будет в Крючки/Walrus_ast.py.
import argparse import ast def check(filename): with open(filename) as f: contents = f.read() try: tree = ast.parse(contents) except SyntaxError: print('SyntaxError, continue') return for node in ast.walk(tree): if isinstance(node, ast.NamedExpr): return node.lineno def main(): parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs='*') args = parser.parse_args() for filename in args.filenames: lineno = check(filename) if lineno: print(f"{filename}:{lineno}") return 1 return 0 if __name__ == '__main__': exit(main())
Что мы можем или не можем сделать здесь? Правила на документацию просты
Крючок должен выйти из ненулевой ошибки или изменить файлы в рабочем каталоге
Что нужно отметить:
Выход ()
с некоторым кодом («0» – это когда все в порядке) – решит ли крючок терпит неудачу или нет- Проверяет как
Если __name__:
и имена, какГлавная ()
илиПроверьте ()
не требуются (то есть вы можете иметь бесполезный файл сВыход (1)
как его единственное содержимое) - Имя анализа файлов необходимы, если вы хотите иметь возможность ограничить по имени файла. Не требуется, но приятно иметь
Сейчас беги try-repo
С новым крючком
$ pre-commit try-repo ../hooks walrus-ast --verbose --all-files
«Справочник». ‘ не устанавливается ». Что случилось?
Оказывается, (в случае (в случае сценариев Python) мы должны описать, как установить его как обычно, с setup.py или pyproject.toml Отказ
Создать Крючки/Setup.py.
from setuptools import setup setup( name="hooks", py_modules=["walrus_ast",], entry_points={ 'console_scripts': [ "walrus-ast=walrus_ast:main", ], }, )
Примечание: вместо py_modules.
Вы можете использовать что-то вроде пакеты = Find_packages (".")
или что-нибудь еще, что вы привыкли делать в Setup.py.
Отслеживать оба новых файла в Git
$ git add setup.py $ git add walrus_ast.py
Теперь рабочий каталог должен выглядеть так
[master][~/code/temp/try-pre-commit/hooks] $ tree -a -L 1 . ├── .git ├── .pre-commit-hooks.yaml ├── setup.py └── walrus_ast.py
Попробуйте запустить его снова
$ pre-commit try-repo ../hooks walrus-ast --verbose --all-files
Напоминание о том, как Эксперименты .py Выглядит:
# .py file with `:=` (Python3.8 syntax) (x := 123)
«: =» Действительно на второй линии, а один из комментариев не сообщается. Спасибо, АСТ!
Примечание: И если вы забыли, что это Python3.8 единственное – вы получите (надеюсь) некоторые указания. В этом случае крючок не работает, но не должен останавливать других от выполнения своей работы.
Пример 3: Меньше негативности, больше возможностей!
Это было не мое намерение остановить вас от использования выражений присваивания, скорее играть с новыми вещами и описывать процесс.
Давайте приблизимся к идее от противоположного направления и найдите место, где может соответствовать моржу. Благодаря этот твит И очень интересно Библиотека Чейз Стивенс мы можем найти такие места.
Создать Крючки/Walrus_opportunity.py.
import astpath def main(): search_path = "//Assign[targets/Name/@id = following-sibling::*[1][name(.) = 'If']/test/Name/@id]" found = astpath.search('.', search_path, print_matches=True, after_context=1) return len(found) if __name__ == "__main__": exit(main())
Здесь Astpath использует XPath Чтобы найти узлы AST.
Обновление Setup.py.
from setuptools import setup setup( name="hooks", py_modules=["walrus_ast", "walrus_opportunity"], entry_points={ 'console_scripts': [ "walrus-ast=walrus_ast:main", "walrus-opportunity=walrus_opportunity:main" ], }, install_requires=[ # Dep. for `walrus-opportunity` "astpath[xpath]", ], )
Обновление Крючки/.pre-Compad-tooks.yaml
- id: walrus-opportunity name: walrus-opportunity description: Warn if you could have used ":=" somewhere entry: walrus-opportunity language: python types: [python]
Обновление Код/Experiments.py.
# .py file with `:=` (Python3.8 syntax) (x := 123) # missed chance to use `:=` x = calculate() if x: print(f"found {x}")
и бегите
$ pre-commit try-repo ../hooks walrus-opportunity --verbose --all-files
Упаковка
Если вы решите, что локальное развитие сделано: Толчок Крючки Папка к Ваше репо (например, на Github ), создайте код/.pre-compad-config.yaml
repos: - repo: https://github.com//pre-commit-hooks rev: or hooks: - id: walrus-grep - id: walrus-ast - id: walrus-opportunity
И теперь вы должны быть в состоянии использовать Git от Код Репо как обычно: изменить файлы, сцену и совершить их. Перед каждым заимством Git будет запустить скрипт от код/.git/hooks/Предварительный коммит Отказ И Предварительный коммит Framework должен показать отчет и разрешить коммит, если все в порядке, или показать отчет, а прервать коммит, если некоторые проверки вернули ненулевые или файлы, были изменены.
Приложение
Подробнее о AST посетителей и работа на дереве здесь . Благодаря Соттилю Энтони за такую чудесную рамку.
Оригинал: “https://dev.to/gyermolenko/writing-hooks-for-pre-commit-framework-5dpf”