파이썬 Ruff·Black 완벽 가이드: 포매팅과 린팅 자동화
파이썬 Ruff와 Black의 차이, 포매터·린터 선택 기준, 설치 명령과 pyproject.toml 설정, 저장·커밋·CI 자동화 및 기존 프로젝트 도입법을 설명합니다.

파이썬 코드 스타일을 자동으로 통일하려면 포매터와 린터의 역할을 먼저 나눠야 합니다. Black은 들여쓰기·줄바꿈·따옴표 같은 코드 모양을 일관되게 다시 작성하는 포매터이고, Ruff는 사용하지 않는 import·정의되지 않은 이름·코딩 규칙 위반 등을 찾는 린터이면서 자체 포매터도 제공합니다. 실무에서는 Black + Ruff 린터 또는 Ruff 포매터 + Ruff 린터 중 하나를 선택해 저장·커밋·CI 단계에서 같은 설정으로 실행하는 것이 핵심입니다.
핵심 요약
- 포매팅은 코드의 모양을 자동 통일하고, 린팅은 잠재 오류와 규칙 위반을 찾아냅니다.
- Black을 포매터로 쓴다면 Ruff는
check중심으로 사용합니다. - Ruff 하나로 통합한다면
ruff format과ruff check를 함께 실행합니다. - Black과 Ruff 포매터를 한 프로젝트에서 번갈아 실행하지 않는 것이 안전합니다.
- PEP 8을 기계적으로 전부 적용하기보다 프로젝트 내부의 일관된 규칙을 우선합니다.
코드 포매터와 린터는 무엇이 다른가요?
포매터는 같은 의미의 코드를 일정한 모양으로 다시 배치합니다. 긴 함수 호출을 여러 줄로 나누거나 공백과 들여쓰기를 정리해 사람마다 다른 손질 방식을 없앱니다. Black은 선택지를 의도적으로 제한해 누가 실행해도 예측 가능한 결과를 만드는 데 초점을 둡니다.
린터는 문법상 실행될 수 있더라도 문제가 될 만한 패턴을 규칙별로 찾습니다. 예를 들어 사용하지 않는 import, 정의되지 않은 이름, 불필요한 비교, 잘못된 import 순서 등을 보고합니다. Ruff 공식 문서에서 ruff check가 린터의 기본 진입점이며, --fix를 붙이면 안전하게 수정 가능한 항목을 자동 고칠 수 있다고 안내합니다.
| 구분 | 주요 목적 | 대표 명령 | 파일 변경 |
|---|---|---|---|
| Black | 코드 모양 통일 | black . |
기본 실행 시 변경 |
| Ruff 린터 | 규칙 위반·잠재 오류 탐지 | ruff check . |
--fix 사용 시 일부 변경 |
| Ruff 포매터 | Black과 유사한 스타일로 포매팅 | ruff format . |
기본 실행 시 변경 |
| mypy | 타입 불일치 검사 | mypy src |
변경하지 않음 |
Ruff와 Black이 모든 버그를 찾는 것은 아닙니다. 특히 인수와 반환값의 타입 관계는 mypy, 실제 실행 결과는 단위 테스트가 맡습니다.
Black + Ruff와 Ruff 단독 구성 중 무엇을 선택할까요?
이미 Black으로 포맷된 프로젝트라면 Black을 유지하고 Ruff를 린터와 import 정리 도구로 도입하는 방법이 변경 범위가 작습니다. 새 프로젝트에서 도구 수와 실행 시간을 줄이고 싶다면 Ruff 포매터와 린터를 함께 사용할 수 있습니다. Ruff 포매터는 Black을 대체하는 방향으로 설계됐지만 공식 문서는 두 포매터 사이에 의도적인 차이가 있으며 계속 번갈아 사용하도록 설계된 것은 아니라고 설명합니다.
| 상황 | 권장 구성 | 이유 |
|---|---|---|
| 기존 Black 프로젝트 | Black + Ruff check | 대규모 포맷 변경과 리뷰 소음을 줄임 |
| 새 프로젝트 | Ruff format + Ruff check | 설정과 실행 도구를 하나로 단순화 |
| 팀 표준이 Black | Black 유지 | 개인 취향보다 저장소 일관성이 중요 |
| 도입 여부 시험 | 검사 모드부터 | 파일을 바꾸지 않고 영향 범위 확인 |
PEP 8도 프로젝트 자체 지침이 충돌할 때 프로젝트 지침이 우선할 수 있으며, 전체 코드베이스의 일관성이 중요하다고 설명합니다. 따라서 어떤 도구가 절대적으로 더 낫다기보다 팀이 하나를 선택하고 같은 버전과 설정을 공유하는 것이 중요합니다.
가상환경에 설치하고 기본 명령 실행하기
먼저 프로젝트 가상환경을 활성화한 뒤 개발 의존성으로 설치합니다. 실행 파일 경로가 섞이는 문제를 피하려면 python -m 방식으로 Black을 실행할 수도 있습니다.
python -m pip install ruff black
# Ruff 린트 검사
ruff check .
# 수정 가능한 린트 오류 자동 수정
ruff check . --fix
# Black으로 포맷이 필요한지 검사만
python -m black . --check
# Black으로 실제 포매팅
python -m black .
# Ruff 포매터를 선택한 경우
ruff format --check .
ruff format .
--check는 파일을 고치지 않고 기준에 맞지 않으면 실패 상태를 반환하므로 CI에 적합합니다. 로컬에서는 실제 포매팅 명령을 실행한 뒤 검사 명령을 다시 실행하면 됩니다.
pyproject.toml에 공통 규칙 저장하기
명령마다 옵션을 길게 적으면 사람과 환경에 따라 결과가 달라집니다. 저장소 루트의 pyproject.toml에 지원 파이썬 버전과 줄 길이, 린트 규칙을 모아두면 편집기와 CI가 같은 기준을 사용할 수 있습니다.
Black을 포매터로 사용하는 예시
[tool.black]
line-length = 88
target-version = ["py311"]
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I"]
[tool.ruff.lint.isort]
known-first-party = ["my_app"]
여기서 Ruff는 린트와 import 정리를 담당하고 Black이 포맷을 담당합니다. 두 도구의 줄 길이를 맞추면 불필요한 충돌을 줄일 수 있습니다. 다만 포매터는 모든 긴 문자열이나 URL을 반드시 줄 길이 안으로 나누지는 못하므로 E501 같은 긴 줄 규칙을 켤 때는 실제 결과를 확인해야 합니다.
Ruff로 포매팅까지 통합하는 예시
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "UP"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
규칙 코드를 많이 켜는 것이 항상 좋은 것은 아닙니다. 기존 코드에 새 규칙을 한꺼번에 적용하면 수백 개 변경이 생겨 기능 수정과 섞일 수 있습니다. 먼저 Ruff의 기본 규칙과 명백한 오류 규칙으로 시작하고, 팀이 의미를 이해한 규칙만 단계적으로 추가하십시오.
저장, 커밋, CI에서 자동화하는 순서
개발자가 수동으로 기억하는 방식만으로는 누락이 생깁니다. 편집기에서는 저장할 때 포매터를 실행하고, 커밋 전에는 린트 검사를 수행하며, 원격 CI에서는 파일 변경 없이 --check 명령으로 최종 확인하는 구조가 안정적입니다.
- 코드를 작성하고 테스트를 추가합니다.
- 선택한 포매터 하나를 실행합니다.
ruff check . --fix로 안전한 자동 수정을 적용합니다.ruff check .결과 중 자동 수정되지 않은 문제를 검토합니다.- mypy와 pytest를 실행해 타입과 실제 동작을 확인합니다.
- CI에서는 포매터 검사, Ruff, mypy, pytest를 파일 변경 없이 실행합니다.
포매터가 테스트를 대신할 수는 없습니다. 스타일이 완벽해도 계산 결과나 예외 처리 흐름이 틀릴 수 있으므로 실제 동작 검증을 같은 파이프라인에 포함해야 합니다.
로컬과 서버의 도구 버전 차이를 막으려면 컨테이너에 개발 도구 버전을 고정하는 방법도 있습니다. 특히 팀원 운영체제가 다를 때 동일한 명령을 재현하기 쉽습니다.
기존 프로젝트에 안전하게 도입하는 방법
처음 도입할 때 포맷 변경과 기능 변경을 같은 커밋에 섞지 마십시오. 먼저 별도 브랜치에서 포매터의 검사 결과를 확인하고, 전체 포맷 전용 커밋을 만든 다음 기능 개발을 이어가면 코드 리뷰와 추적이 쉬워집니다.
- 현재 파이썬 버전과 제외할 생성 파일·마이그레이션 폴더를 정합니다.
--check로 변경될 파일과 린트 오류 수를 확인합니다.- 포매터 하나를 결정하고
pyproject.toml을 커밋합니다. - 포맷만 수행한 커밋을 기능 수정과 분리합니다.
- Ruff 규칙은 오류 위험이 큰 항목부터 조금씩 추가합니다.
- CI가 통과해야 병합되도록 저장소 규칙을 맞춥니다.
noqa 주석은 특정 경고가 설계상 불가피할 때만 사용하고, 파일 전체 무시는 최소화하십시오. 경고를 없애기 위해 무조건 자동 수정하기보다 해당 규칙이 무엇을 방지하는지 확인하는 과정이 필요합니다.
실수 방지 체크리스트
- Black과 Ruff 포매터 중 실제로 사용할 포매터를 하나로 정했는지 확인합니다.
- 개발자 PC와 CI가 같은
pyproject.toml을 읽는지 확인합니다. - 줄 길이와 대상 파이썬 버전 설정을 도구 간 맞춥니다.
- 자동 수정 전 커밋하거나 변경 내용을 확인할 수 있게 준비합니다.
- 생성 코드와 외부 코드 폴더를 필요한 범위에서 제외합니다.
- 기능 변경과 전체 포맷 변경을 한 커밋에 섞지 않습니다.
ruff check --fix후 남은 오류를 직접 검토합니다.- 포매팅·린팅과 함께 mypy·pytest도 실행합니다.
noqa와 규칙 무시에는 구체적인 이유를 남깁니다.
자주 묻는 질문
1. Ruff와 Black은 같은 도구인가요?
아닙니다. Black은 코드 포매터이고 Ruff는 린터와 포매터 기능을 제공합니다. Ruff의 check와 format도 서로 다른 역할입니다.
2. Ruff를 쓰면 Black이 반드시 필요 없나요?
Ruff 포매터를 선택하면 Black 없이 구성할 수 있습니다. 이미 Black을 쓰는 프로젝트라면 포매터는 Black으로 유지하고 Ruff 린터만 도입할 수도 있습니다.
3. Black과 Ruff format을 함께 실행해도 되나요?
일회성 비교는 가능하지만 지속적으로 번갈아 사용하는 것은 권장하기 어렵습니다. 세부 출력 차이로 코드가 반복 변경될 수 있으므로 하나를 선택하십시오.
4. Ruff가 코드를 자동으로 모두 고치나요?
아닙니다. --fix로 고칠 수 있는 규칙만 수정하며, 의미 판단이 필요한 오류는 개발자가 검토해야 합니다.
5. PEP 8을 완벽히 지키면 좋은 코드인가요?
가독성과 일관성에 도움은 되지만 정확한 로직과 설계를 보장하지 않습니다. PEP 8도 프로젝트 내부 일관성과 상황에 맞는 판단을 중요하게 봅니다.
6. line-length는 반드시 79여야 하나요?
PEP 8의 지침과 별개로 Black은 기본적으로 88을 사용합니다. 프로젝트가 선택한 포매터와 팀 규칙에 맞추고 관련 도구 설정을 동일하게 유지하십시오.
7. 저장할 때 자동 포매팅만 켜면 충분한가요?
저장 포매팅은 편리하지만 환경별 설정 누락이 있을 수 있습니다. CI에서 --check 검사를 추가해야 저장소 기준을 안정적으로 유지할 수 있습니다.
8. Ruff와 mypy의 검사는 어떻게 다른가요?
Ruff는 코드 규칙과 여러 잠재 오류를 찾고 mypy는 타입 힌트의 관계를 분석합니다. 검사 범위가 달라 함께 사용하는 편이 좋습니다.
9. 기존 프로젝트에서 오류가 너무 많이 나오면 어떻게 하나요?
기본 규칙과 새로 수정하는 파일부터 시작하십시오. 검사 범위와 규칙을 단계적으로 넓히면 대규모 수정과 무분별한 무시 설정을 피할 수 있습니다.
10. 포매팅 후 테스트를 다시 해야 하나요?
해야 합니다. 포매터는 의미를 보존하도록 설계되지만 배포 전에는 린트·타입 검사·단위 테스트를 함께 실행해 결과를 확인하는 것이 안전합니다.
공식 출처
공식 문서 확인일: 2026년 9월 9일. Ruff와 Black의 지원 옵션은 버전에 따라 달라질 수 있으므로 설치된 버전의 도움말과 공식 문서를 함께 확인하시기 바랍니다.