У многих из вас есть GIT- репозитории с кодом, в этой заметке я расскажу как сделать ваш Python код лучше.
В качестве примера я буду использовать этот репозиторий: https://github.com/Aykhan-sh/pandaseda
Форкнем его и попробуем сделать код лучше.
Улучшим читаемость кода
Улучшить читаемость вашего кода очень просто. Мы будем использовать библиотеки для синтаксического форматирования и проверки.
Для начала создадим в репозитории файлы конфигураций для flake8, mypy и black
Установим их для начала:
pip install black flake8 mypy
Разберем flake8. Flake8 — инструмент, позволяющий просканировать код проекта и обнаружить в нем стилистические ошибки и нарушения различных конвенций кода на Python.
Файл setup.cfg для flake8 и mypy
[flake8]
max-line-length = 120
exclude =.git,__pycache__,docs/source/conf.py,build,dist,tests
ignore = I101,D100,D101,D102,D103,D104,D105,D107,D401,E203,I900,N802,N806,N812,W503,S311,S605,S607,ISC003,ISC001,T101,T000,F541,PL123
per-file-ignores = __init__.py:F401,F403
[mypy]
ignore_missing_imports = True
disallow_untyped_defs = True
check_untyped_defs = True
warn_redundant_casts = True
no_implicit_optional = True
strict_optional = True
[mypy-tests.*]
ignore_errors = True
Блок [flake8]:
- max-line-length — максимальная длина строки
- exclude — список папок, которые исключаются из сканирования flake8
- ignore — список ошибок/ предупреждений, которые так же исключаются. Например: I101: The names in your from import are in the wrong order и D100 — Missing docstring
- per-file-ignores — исключить из сканирования определенный файл
flake8 запустить очень просто:
flake8
Помните, что flake8 не модифицирует код, а просто проверят его. Подправить ошибки придется в ручную.
Теперь поговорим про mypy. У Python нет обязательной статической типизации, но рекомендуется добавлять типы в аргументы функции и возвращаемые типы. Для этого просто запустим mypy и не забудьте подправить ошибки:
mypy .
Создадим файл pyproject.toml для black. black поможет форматировать ваш код в соответствии со стандартом.
Файл pyproject.toml
[tool.black]
line-length = 119
target-version = ['py36']
include = '\.pyi?$'
exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
'''
Разберём код:
- line-length — длина строки
- target-version — версии Python. py36 — Python 3.6, можно и для других версий.
- include — список того, что включаем в форматирование
- exclude — список того, что исключаем из форматирования
Запуск тоже очень простой:
black .
Рекомендую сохранить отредактированный файл. Так же я уже исправил все ошибки mypy. Взглянем, что же поменялось.
Так выглядел код до правки:
А так после правки:
Код стал читабельнее и теперь у нас статическая типизация. Особое внимание обратите на тип Union. Использовать его необходимо когда допускается использование не любых типов, а только некоторых. Перечислить их нужно в квадратных скобках.
isort
isort — это библиотека Python для сортировки импорта по алфавиту с автоматическим разделением на разделы и по типу.
Установка:
pip install isort
Использование:
isort .
Так выглядели наши импорты до правки:
А так после применения isort:
Так же рекомендую сохранить отредактированный файл.
pre-commit hook
Мы можем запускать black, flake8 и mypy вручную, но это не удобно. Мы можем автоматизировать процесс с помощью pre-commit hook.
Файл .pre-commit-config.yaml
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.19.4
hooks:
- id: pyupgrade
args: [ "--py38-plus" ]
- repo: https://github.com/pre-commit/mirrors-isort
rev: 1ba6bfc # Use the revision sha / tag you want to point at
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/psf/black
rev: 21.6b0
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: check-docstring-first
- id: check-json
- id: check-merge-conflict
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
- id: requirements-txt-fixer
- repo: https://github.com/pre-commit/mirrors-pylint
rev: 56b3cb4
hooks:
- id: pylint
args:
- --max-line-length=120
- --ignore-imports=yes
- -d duplicate-code
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
hooks:
- id: python-check-mock-methods
- id: python-use-type-annotations
- id: python-check-blanket-noqa
- id: python-use-type-annotations
- id: text-unicode-replacement-char
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 9feadeb
hooks:
- id: mypy
exclude: ^tests/
args:
[
--disallow-untyped-defs,
--check-untyped-defs,
--warn-redundant-casts,
--no-implicit-optional,
--strict-optional
]
Теперь каждый коммит будет запускаться наше форматирование и проверки. Теперь сделаем, что бы Github запускал их при каждом pull request.
Github Actions
Для наших целей будем использовать Github Action. Создадим файл ci.yaml
Файл .github/workflows/ci.yaml
name: Python package
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6]
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
# You can test your matrix by printing the current Python version
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements_dev.txt
- name: Run black
run:
black --check .
- name: Run flake8
run: flake8
- name: Run Mypy
run: mypy pandaseda
Основное внимание обратите на:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements_dev.txt
- name: Run black
run:
black --check .
- name: Run flake8
run: flake8
- name: Run Mypy
run: mypy pandaseda
Тут указаны наши проверки. Black тут запускаем с флагом check. Black не будет редактировать код, но выполнит проверку. Именно поэтому лучше сохранить файл после запуска black заранее.
Action теперь готов, его можно запустить при любом коммите. После запуска можно посмотреть ход выполнения и результат во вкладке Action.
В случае ошибок на почту будет отправлен email:
Саму ошибку можно так же посмотреть в Action:
Заключение
В этой заметке получилось рассмотреть несколько библиотек для работы с вашим кодом. Отдельно рассмотрели pre-commit hook и Github Actions.
Дополнительный материал
Разговоры о Data Science – закрытый канал для общения на тему карьеры, развития профессиональных навыков и применения навыков на работе.