협업에서 중요한건 바로 컨벤션이다.
하지만 말로는 규칙이 지켜지지 않는 법
그렇기 때문에 우리는 강제적인 컨벤션 적용을 위한 린터와 포메터를 사용한다.
파이썬도 이러한 린터가 존재하는데,
문제는 제법 여러개로 파편화 되어있다는 것이다.
파이썬에서 명시한 코딩 스타일(PEP 8)을 위해 Flake8을 쓰고,
코드를 정해진 스타일로 자동 정렬하기 위해 Black을 돌리고,
Import 순서를 맞추기 위해 isort를 실행한다.
도구가 많을수록 설정 관리가 복잡하고, 서로 따로 노는 애들이다 보니 느리다.
이런 파편화된 도구의 세계에 Ruff가 등장했다.
Rust 언어로 작성되고, 위에서 명시한 여러 도구들의 역할을 한번에 해주는 All-in-one 도구다.
Rust 기반이니깐 속도도 빠르고, 설정 파일이 하나로 통합되니깐 관리하기도 편하다.
설치또한 간단하다
pip install ruff
사용법
ruff의 핵심 기능은 2가지로 코드 점검(Lint)와 포맷팅(Formatting)이다.
Lint 실행은 다음의 커맨드로 실행한다.
ruff check .
만약 문제가 있다면 커맨드로 친절하게 알려주는데, 대부분의 문제는 --fix 명령어를 주는 것으로 자동으로 처리해준다.
또한 format 명령어를 통해 코드 스타일을 일관되게 정리하는데,
ruff format .
여러 도구들의 통합이 목적이었던 만큼, 기존에 Lint 도구였던 Black 스타일과 유사하게 수정해준다.
설정 방법
Ruff는 프로젝트 루트 디렉터리에 있는 pyproject.toml 파일을 인식해서 모든 설정을 관리한다.
참고로 규칙이 너무 많아서 자주 쓰는거 위주로 설명을 하겠다.
[tool.ruff.lint]
# Flake8(E, F) 규칙과 isort(I) 규칙을 모두 활성화
select = ["E", "F", "I"]
# 특정 규칙 무시하기
# E501: 줄 길이가 88자를 초과해도 경고하지 않음 (포맷터가 처리하므로)
# F841: 사용하지 않는 변수 경고 (개발 중에는 흔히 발생하므로 임시 비활성화)
ignore = ["E501", "F841"]
# 특정 파일에서는 특정 규칙만 무시
[tool.ruff.lint.per-file-ignores]
# 테스트 코드(__init__.py, test_*.py)에서는 F841(미사용 변수)을 무시
"__init__.py" = ["F841"]
"tests/*.py" = ["F841"]
규칙은 select 방식으로 적용할 규칙 세트를 선택한다.
여러 도구를 통합하는 만큼 설정도 다른 도구의 기능을 쉽게 가져오는 형태로 구성되는데
"E": pycodestyle = PEP 8 스타일 가이드 위반
"W": pycodestyle = PEP 8 스타일 경고
"f": Pyflakes = 논리적 오류(미사용 변수, 정의안된 이름 등...)
"I": isort = import 문 순서 및 그룹화
"UP": pyupgrade = 구식 Python 문법을 최신 문법으로 수정 제안
그 외에도 flake8 계열에 bugbear, builtins, simplify, pathlib, bandit 등
코드 품질을 높이기 위한 인기있는 플러그인 그룹을 지원한다.
포멧터 설정
lint를 설정 했다면 포멧터도 설정이 가능한데
기본적인 컨벤션만 지키는 정도로 충분하다 생각하니 간단히 따옴표 형식과 라인 수 정도만 가져간다.
[tool.ruff.format]
# Black의 기본값과 동일
quote-style = "double"
line-length = 88
제외항목 설정
[tool.ruff]
# 검사할 대상 파일 확장자 (기본값에 .pyi 등이 포함됨)
src = ["src", "tests"]
# 검사에서 제외할 폴더나 파일
exclude = [
".git",
".venv",
"build",
"dist",
"__pypackages__",
]
개발 환경 통합
매번 수동으로 터미널에서 수행하는건 복잡하니 Ruff는 VS code를 기준으로 확장 플러그인을 지원한다.
VS code에서 확장 플러그인을 설치하고, settings.json을 수정하거나 설정 메뉴에서
기본 포맷터를 지정하고 저장 시 자동 포멧팅 설정을 키는 것으로 자동 체크가 가능하다.
{
// 1. Ruff를 기본 포맷터로 지정
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
},
// 2. 저장 시 Ruff의 'fix' 기능(린팅 수정) 활성화
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit"
}
}
만약 다른 사람들은 확장 플러그인을 설치 안하거나 설정이 제각각이 되는 경우
pre-commit을 이용해서 commit 직전에 코드 품질 검사를 강제 시킬 수 있다.
pip install pre-commit
깃허브 CI 배포시 검증
이후에도 github CI시 자동으로 lint 하도록 커맨드를 지정하거나 할 수 있지만...
애초에 올라간 시점부터 검증하기보다는 그 전에 commit전 수행되는게 더욱 권장되긴 한다.
물론 가장 좋은건 2중으로 방어하는 것이다.