
같이 보던 사내 파이썬 모듈에 함수는 20개가 넘는데 docstring이 붙은 건 몇 개 안 됐다.
테스트 커버리지는 pytest-cov로 매번 재면서 문서화는 감으로만 판단하고 있었다.
나는 같은 개념의 도구가 분명 있을 거라 보고 찾다가 interrogate를 골랐다. 이름값(테스트 커버리지=coverage.py, 문서화 커버리지=interrogate) 대응이 딱 떨어져서 마음에 들었다.
1. interrogate가 뭔지
interrogate는 파이썬 코드베이스를 훑어서 모듈/클래스/함수/메서드에 docstring이 있는지 없는지를 세고, 전체 대비 비율(커버리지 %)을 뽑아주는 도구다.
테스트 커버리지 도구(coverage.py)랑 발상이 똑같다. 대상이 테스트 실행 라인이 아니라 docstring일 뿐이다.
설치는 pip 한 줄이다.
pip install interrogate
버전은 1.7.0을 썼다. Python 3.8 이상이면 된다고 나와 있고, 실제로는 3.13에서도 문제없이 돌아갔다.
2. 예제 프로젝트로 기본 실행
빈 프로젝트로는 감이 안 와서 함수 6개, 클래스 2개짜리 작은 모듈(mypkg/orders.py)을 만들고, 그중 일부만 일부러 docstring을 비워뒀다.
$ interrogate mypkg
RESULT: FAILED (minimum: 80.0%, actual: 40.0%)
기본 기준선(fail-under)이 80%라서 40%면 바로 FAILED가 뜨고 종료 코드도 1이다.
숫자만 보면 뭐가 문제인지 안 보이니 -vv(상세 모드)로 다시 돌렸다.
$ interrogate -vv mypkg
------------------------------ Detailed Coverage -------------------------------
| Name | Status |
|----------------------------------------------------|-------------------------|
| orders.py (module) | COVERED |
| Order (L7) | COVERED |
| calc_total (L15) | COVERED |
| apply_discount (L20) | MISSED |
| OrderBook (L24) | MISSED |
| OrderBook.__init__ (L25) | MISSED |
| OrderBook.add (L28) | MISSED |
| OrderBook.summary (L31) | COVERED |
| OrderBook._internal_check (L35) | MISSED |
|----------------------------------------------------|-------------------------|
| TOTAL | 4/10 = 40.0% |
파일명, 클래스명, 메서드명, 줄 번호까지 항목별로 COVERED/MISSED가 그대로 나온다. 어디부터 손대야 할지 이 표 하나로 끝난다.
3. 옵션으로 줄여봤는데 예상과 달랐던 지점
private 메서드까지 다 세는 게 너무 빡빡하다 싶어서 -p(private 무시), -i(init 메서드 무시), -m(매직 메서드 무시)를 붙여 다시 돌렸다.
$ interrogate -i -m -p mypkg
RESULT: FAILED (minimum: 80.0%, actual: 44.4%)
40.0% → 44.4%로 겨우 4.4%p만 올랐다. -p가 private 다 걸러줄 줄 알았는데 거의 그대로였다.
문서를 다시 읽어보니 -p는 언더스코어 두 개(__)로 시작하는 진짜 private만 봐준다. 코드에 있던 _internal_check는 언더스코어 한 개짜리라 대상이 아니었다.
이름 규칙 하나 차이로 옵션이 안 먹힌 셈이다. 결국 옵션에 기대지 않고 docstring을 직접 채우는 쪽으로 방향을 바꿨다.
4. docstring을 채워서 다시 측정
apply_discount, OrderBook, OrderBook.add, __init__.py 모듈, _internal_check까지 한 줄씩 docstring을 달고 다시 돌렸다.
$ interrogate mypkg
RESULT: PASSED (minimum: 80.0%, actual: 90.0%)
10개 항목 중 9개가 COVERED로 바뀌면서 90.0%까지 올라갔다. 기본 기준선 80%는 이 시점에서 이미 통과다.

5. pyproject.toml로 설정 고정
매번 -i -p 같은 옵션을 손으로 치는 게 번거로워서, 프로젝트 설정 파일에 박아두는 쪽을 골랐다. CI에서도 같은 기준을 그대로 쓸 수 있어서다.
[tool.interrogate]
ignore-init-method = true
ignore-init-module = false
fail-under = 90
exclude = ["tests", "setup.py"]
verbose = 1
$ interrogate -c pyproject.toml mypkg
| Name | Total | Miss | Cover | Cover% |
|----------------------|-------------|------------|-------------|--------------|
| __init__.py | 1 | 0 | 1 | 100% |
| orders.py | 8 | 0 | 8 | 100% |
|----------------------|-------------|------------|-------------|--------------|
| TOTAL | 9 | 0 | 9 | 100.0% |
RESULT: PASSED (minimum: 90.0%, actual: 100.0%)
ignore-init-method를 켜니 측정 대상이 10개에서 9개로 줄면서 100.0%가 됐다. 기준선도 90%로 올려 잡았는데 그대로 통과했다.
배지 이미지도 한 줄로 뽑힌다.
$ interrogate --generate-badge . mypkg
Generated badge to /interrogate_badge.svg
README에 붙이는 용도라 SVG로 나온다. GitHub Actions에 넣으면 PR마다 커버리지 배지가 자동으로 갱신된다.
6. 막혔던 부분 - 커맨드를 못 찾을 때
pip install은 잘 끝났는데 정작 interrogate 명령이 안 먹힌 적이 있었다.
$ interrogate --version
zsh: command not found: interrogate
원인은 pip가 실행 파일을 깔아준 scripts 디렉토리가 PATH에 안 잡혀 있어서였다.
python -m interrogate --version
python -m으로 모듈 실행하면 PATH 문제와 무관하게 바로 된다. pip install --user를 쓰거나 가상환경 밖에서 설치했을 때 자주 겪는 상황이라 기억해둘 만하다.
정리
- interrogate는 테스트 커버리지 도구랑 같은 방식으로 docstring 커버리지를 %로 뽑아준다.
- -vv를 쓰면 어떤 함수/클래스가 빠졌는지 줄 번호까지 바로 나온다.
- -p, -i, -m 같은 무시 옵션은 이름 규칙(언더스코어 개수)을 정확히 봐야 원하는 만큼 줄어든다.
- pyproject.toml에 [tool.interrogate] 설정을 박아두면 로컬/CI에서 같은 기준을 그대로 쓸 수 있다.
- 명령이 안 먹히면 python -m interrogate로 우회하면 된다.
관련 글:
- [CLI] hyperfine 사용법 - 명령어 실행 시간 벤치마크 (파이썬 시작 시간에 속은 기록)
- [ABAP] SMW0에 등록 시 MIME 오류 해결.
- [ABAP] URL 접근하여 데이터 얻는 방법
- [BTP] SAP Business Application Studio 구독
테스트는 macOS 26.5, Python 3.13.12, interrogate 1.7.0 기준이다. 다음엔 GitHub Actions에 fail-under 게이트로 직접 물려봐야겠다.
'개발 도구' 카테고리의 다른 글
| [Vulture] 파이썬 미사용 코드 찾기와 오탐 처리 (Linux, Python 3.11) (0) | 2026.09.17 |
|---|---|
| [CLI] hyperfine 사용법 - 명령어 실행 시간 벤치마크 (파이썬 시작 시간에 속은 기록) (0) | 2026.09.02 |