Post

[Python] ๐Ÿ” Pylint๋กœ Python ์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌํ•˜๊ธฐ: ์„ค์น˜๋ถ€ํ„ฐ CI/CD ์—ฐ๋™๊นŒ์ง€

Pylint๋กœ Python ์ฝ”๋“œ์˜ ๋ฒ„๊ทธยท์Šคํƒ€์ผยท๋ณต์žก๋„๋ฅผ ์ž๋™ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. .pylintrc ์„ค์ •, VSCode ์—ฐ๋™, pre-commit CI/CD ํ†ตํ•ฉ๊นŒ์ง€ ์‹ค๋ฌด ๊ด€์ ์œผ๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

[Python] ๐Ÿ” Pylint๋กœ Python ์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌํ•˜๊ธฐ: ์„ค์น˜๋ถ€ํ„ฐ CI/CD ์—ฐ๋™๊นŒ์ง€

Pylint๋Š” Python ์ฝ”๋“œ์˜ ์˜ค๋ฅ˜ ๊ฒ€์ถœ, PEP 8 ์Šคํƒ€์ผ ์œ„๋ฐ˜, ์ฝ”๋“œ ๋ณต์žก๋„ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ •์  ๋ถ„์„ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ๋ฅผ ๋„˜์–ด ์ž ์žฌ์  ๋ฒ„๊ทธ๊นŒ์ง€ ํƒ์ง€ํ•˜๋ฉฐ, 10์  ๋งŒ์  ํ’ˆ์งˆ ์ ์ˆ˜๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” Pylint์˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•๋ถ€ํ„ฐ .pylintrc ์„ค์ •, VSCode ์—ฐ๋™, pre-commit CI/CD ํ†ตํ•ฉ๊นŒ์ง€ ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ” Pylint๋ž€?

Pylint๋Š” Python ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ ๋„ ํ’ˆ์งˆ ๋ฌธ์ œ๋ฅผ ํƒ์ง€ํ•˜๋Š” ์ •์  ์ฝ”๋“œ ๋ถ„์„(static analysis) ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ๊ธฐ๋ฅผ ๋„˜์–ด, ๋Ÿฐํƒ€์ž„ ์ด์ „์— ๋ฐœ๊ฒฌํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฒ„๊ทธ์™€ ์ž ์žฌ์  ์˜ค๋ฅ˜๊นŒ์ง€ ์žก์•„๋ƒ…๋‹ˆ๋‹ค.

์ฃผ์š” ๊ฒ€์‚ฌ ํ•ญ๋ชฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ๋ฌธ๋ฒ• ์˜ค๋ฅ˜ ๋ฐ ์ž ์žฌ์  ๋ฒ„๊ทธ โ€” ์ •์˜๋˜์ง€ ์•Š์€ ๋ณ€์ˆ˜, self ๋ˆ„๋ฝ, ์ž˜๋ชป๋œ import ๋“ฑ
  • PEP 8 ์ฝ”๋”ฉ ํ‘œ์ค€ ์œ„๋ฐ˜ โ€” ๋ช…๋ช… ๊ทœ์น™(snake_case, PascalCase), ์ค„ ๊ธธ์ด, ๊ณต๋ฐฑ ๋“ฑ
  • ์ฝ”๋“œ ๋ณต์žก๋„ โ€” ์ค‘๋ณต ์ฝ”๋“œ, ๋„ˆ๋ฌด ๊ธด ํ•จ์ˆ˜, ์ง€๋‚˜์น˜๊ฒŒ ๋งŽ์€ ์ธ์ž ๋“ฑ
  • ๋ฌธ์„œํ™” ๋ถ€์žฌ โ€” docstring ๋ฏธ์ž‘์„ฑ ๊ฒฝ๊ณ 
  • 10์  ๋งŒ์  ํ’ˆ์งˆ ์ ์ˆ˜ โ€” ์ฝ”๋“œ ์ „์ฒด์˜ ์ƒํƒœ๋ฅผ ์ˆ˜์น˜๋กœ ํ™•์ธ

Tip: Pylint์˜ ๊ฒฝ๊ณ ๊ฐ€ ์ ˆ๋Œ€์ ์ธ ๊ธฐ์ค€์€ ์•„๋‹™๋‹ˆ๋‹ค. ์˜๋„๋œ ์ฝ”๋“œ๊ฐ€ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ”„๋กœ์ ํŠธ ์ƒํ™ฉ์— ๋งž๊ฒŒ ๊ทœ์น™์„ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.


โš–๏ธ Linter vs Formatter ์ฐจ์ด

์ฝ”๋“œ ํ’ˆ์งˆ ๋„๊ตฌ๋ฅผ ์ฒ˜์Œ ์ ‘ํ•  ๋•Œ ๊ฐ€์žฅ ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋ถ€๋ถ„์ด Linter์™€ Formatter์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.

๊ตฌ๋ถ„LinterFormatter
์—ญํ• ์ฝ”๋“œ์˜ ๋…ผ๋ฆฌ ์˜ค๋ฅ˜ยท์ž ์žฌ์  ๋ฒ„๊ทธ ํƒ์ง€์ฝ”๋“œ ์Šคํƒ€์ผยท๋ ˆ์ด์•„์›ƒ ์ž๋™ ์ •๋ฆฌ
๋™์ž‘๋ฌธ์ œ๋ฅผ ๋ณด๊ณ ํ•˜๊ณ  ์ˆ˜์ •์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜์ •
์˜ˆ์‹œ๋ฏธ์‚ฌ์šฉ ๋ณ€์ˆ˜, import ์˜ค๋ฅ˜, ๋ช…๋ช… ๊ทœ์น™ ์œ„๋ฐ˜๋“ค์—ฌ์“ฐ๊ธฐ ์ •๋ ฌ, ๋”ฐ์˜ดํ‘œ ํ†ต์ผ, ์ค„ ๋ฐ”๊ฟˆ
๋Œ€ํ‘œ ๋„๊ตฌPylint, Flake8, RuffBlack, YAPF, Ruff(format)

๐Ÿ“Š Python ์ฝ”๋“œ ํ’ˆ์งˆ ๋„๊ตฌ ๋น„๊ต

์‹ค๋ฌด์—์„œ ์ž์ฃผ ํ•จ๊ป˜ ์–ธ๊ธ‰๋˜๋Š” 4๊ฐ€์ง€ ๋„๊ตฌ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

๋„๊ตฌ๋ถ„๋ฅ˜ํŠน์ง•์†๋„
PylintLinter๊ฐ€์žฅ ์—„๊ฒฉ, ํ’ˆ์งˆ ์ ์ˆ˜ ์ œ๊ณต, ์‹ฌ์ธต ๋ถ„์„๋А๋ฆผ
Flake8Linter์•ˆ์ •์ , PEP 8 ์ค‘์‹ฌ, ์„ค์ • ๊ฐ„๋‹จ๋น ๋ฆ„
BlackFormatter์„ค์ • ์—†์ด ์ผ๊ด€๋œ ์Šคํƒ€์ผ ๊ฐ•์ œ, ํŒ€ ํ˜‘์—… ์ตœ์ ๋น ๋ฆ„
RuffLinter + FormatterRust ๊ธฐ๋ฐ˜, ๋งค์šฐ ๋น ๋ฆ„, Flake8+isort+Black ํ†ตํ•ฉ๋งค์šฐ ๋น ๋ฆ„
1
2
3
4
Flake8 โ”€ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ โ†’ ์˜ค๋ฅ˜ ๋ณด๊ณ 
Pylint โ”€ ์‹ฌ์ธต ๋ถ„์„   โ†’ ์˜ค๋ฅ˜ ๋ณด๊ณ  + ๊ฐœ์„  ์ œ์•ˆ + ํ’ˆ์งˆ ์ ์ˆ˜
Black  โ”€ ์ž๋™ ํฌ๋งทํŒ… โ†’ ์ฝ”๋“œ ์ง์ ‘ ์ˆ˜์ •
Ruff   โ”€ lint + format โ†’ ์œ„ ์„ธ ๋„๊ตฌ๋ฅผ ๋Œ€๋ถ€๋ถ„ ๋Œ€์ฒด

Tip: 2026๋…„ ํ˜„์žฌ๋Š” Ruff ๋‹จ๋… ์‚ฌ์šฉ์œผ๋กœ lintยทformatยทimport ์ •๋ฆฌ๊นŒ์ง€ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด ์ฆ๊ฐ€ ์ค‘์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Pylint๋Š” Ruff๊ฐ€ ํƒ์ง€ํ•˜์ง€ ๋ชปํ•˜๋Š” ์‹ฌ์ธต ๋ถ„์„(์ฝ”๋“œ ๋ƒ„์ƒˆ, ๋ณต์žก๋„, ํ’ˆ์งˆ ์ ์ˆ˜)์—์„œ ์—ฌ์ „ํžˆ ๊ฐ•์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿš€ ์„ค์น˜ ๋ฐ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

์„ค์น˜

1
pip install pylint

๊ฐ€์ƒ ํ™˜๊ฒฝ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ™˜๊ฒฝ ํ™œ์„ฑํ™” ํ›„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install pylint

ํŒŒ์ผ ๋ถ„์„

1
2
3
4
5
6
7
8
# ๋‹จ์ผ ํŒŒ์ผ ๋ถ„์„
pylint my_script.py

# ๋ชจ๋“ˆ ์ „์ฒด ๋ถ„์„
pylint my_package/

# ์—ฌ๋Ÿฌ ํŒŒ์ผ ๋™์‹œ ๋ถ„์„
pylint src/main.py src/utils.py

์ถœ๋ ฅ ๊ฒฐ๊ณผ ์˜ˆ์‹œ

1
2
3
4
5
6
my_script.py:5:0: C0304: Final newline missing (missing-final-newline)
my_script.py:10:4: W0611: Unused import os (unused-import)
my_script.py:15:0: E1101: Module 'os' has no 'pathh' member (no-member)

-----------------------------------
Your code has been rated at 6.50/10

์ถœ๋ ฅ ํ˜•์‹์€ ํŒŒ์ผ๋ช…:์ค„๋ฒˆํ˜ธ:์ปฌ๋Ÿผ:๋ฉ”์‹œ์ง€์ฝ”๋“œ: ์„ค๋ช… (์ฝ”๋“œ๋ช…) ์ž…๋‹ˆ๋‹ค.


๐Ÿ“‹ ๋ฉ”์‹œ์ง€ ์œ ํ˜•๊ณผ ์ฝ”๋“œ ์ดํ•ดํ•˜๊ธฐ

Pylint ๋ฉ”์‹œ์ง€๋Š” ์•ŒํŒŒ๋ฒณ ์ ‘๋‘์‚ฌ๋กœ ์‹ฌ๊ฐ๋„๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

์ ‘๋‘์‚ฌ์œ ํ˜•์˜๋ฏธ
CConventionPEP 8 ๋“ฑ ์ฝ”๋”ฉ ๊ทœ์น™ ์œ„๋ฐ˜
WWarning์ž ์žฌ์  ๋ฌธ์ œ, ๊ฐœ์„  ๊ถŒ์žฅ
EError๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋กœ ์ด์–ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ๋ฒ„๊ทธ
RRefactor๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•œ ์ฝ”๋“œ ๊ตฌ์กฐ
FFatal๋ถ„์„ ์ž์ฒด๋ฅผ ๋ง‰๋Š” ์น˜๋ช…์  ์˜ค๋ฅ˜

์ž์ฃผ ๋งˆ์ฃผ์น˜๋Š” ๋ฉ”์‹œ์ง€ ์ฝ”๋“œ

์ฝ”๋“œ์ด๋ฆ„์„ค๋ช…
C0301line-too-long์ค„ ๊ธธ์ด ์ดˆ๊ณผ (๊ธฐ๋ณธ 100์ž)
C0114missing-module-docstring๋ชจ๋“ˆ docstring ์—†์Œ
C0116missing-function-docstringํ•จ์ˆ˜ docstring ์—†์Œ
W0611unused-import์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” import
W0612unused-variable์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ณ€์ˆ˜
W1203logging-fstring๋กœ๊น…์— f-string ์‚ฌ์šฉ (lazy loading ๋ถˆ๊ฐ€)
E0401import-error๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ
E1101no-member์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ/๋ฉ”์„œ๋“œ ์ ‘๊ทผ
R0913too-many-argumentsํ•จ์ˆ˜ ์ธ์ž ์ˆ˜ ์ดˆ๊ณผ (๊ธฐ๋ณธ 5๊ฐœ)
R1705no-else-returnreturn ํ›„ ๋ถˆํ•„์š”ํ•œ else ๋ธ”๋ก

โš™๏ธ .pylintrc ์„ค์ • ํŒŒ์ผ

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— .pylintrc ํŒŒ์ผ์„ ๋‘๋ฉด ํŒ€ ์ „์ฒด์— ์ผ๊ด€๋œ ๊ทœ์น™์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ

1
pylint --generate-rcfile > .pylintrc

์ฃผ์š” ์„ค์ • ํ•ญ๋ชฉ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[MASTER]
# ๊ฐ€์ƒํ™˜๊ฒฝ, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฒฝ๋กœ ์ถ”๊ฐ€
init-hook='import sys; sys.path.insert(0, "src")'

# ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ (0 = CPU ์ˆ˜์— ๋งž๊ฒŒ ์ž๋™)
jobs=0

[MESSAGES CONTROL]
# ๋น„ํ™œ์„ฑํ™”ํ•  ๋ฉ”์‹œ์ง€ ์ฝ”๋“œ (์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„)
disable=
    C0114,  # missing-module-docstring
    C0115,  # missing-class-docstring
    C0116,  # missing-function-docstring
    W1203   # logging-fstring

[FORMAT]
# ํ•œ ์ค„ ์ตœ๋Œ€ ๊ธธ์ด (PEP 8 ๊ธฐ๋ณธ๊ฐ’ 79, ์‹ค๋ฌด 100~120 ๊ถŒ์žฅ)
max-line-length=120

# ๋“ค์—ฌ์“ฐ๊ธฐ ๋‹จ์œ„
indent-string='    '

[DESIGN]
# ํ•จ์ˆ˜ ์ตœ๋Œ€ ์ธ์ž ์ˆ˜
max-args=7

# ํ•จ์ˆ˜ ์ตœ๋Œ€ ์ค„ ์ˆ˜
max-statements=50

[TYPECHECK]
# ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํƒ€์ž… ์ฒดํฌ ์˜ค๋ฅ˜ ๋ฌด์‹œ
ignored-modules=numpy,pandas,pydantic

๐Ÿ”• ๊ฒฝ๊ณ  ๋น„ํ™œ์„ฑํ™” ๋ฐฉ๋ฒ•

ํ”„๋กœ์ ํŠธ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ํŠน์ • ์ฝ”๋“œ์—๋งŒ ๊ทœ์น™์„ ๋น„ํ™œ์„ฑํ™”ํ•  ๋•Œ ์ธ๋ผ์ธ ์ฃผ์„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

1์ค„ ๋น„ํ™œ์„ฑํ™”

1
import os  # pylint: disable=unused-import

๋ธ”๋ก ๋‹จ์œ„ ๋น„ํ™œ์„ฑํ™”

1
2
3
4
# pylint: disable=too-many-arguments
def complex_function(a, b, c, d, e, f):
    pass
# pylint: enable=too-many-arguments

ํŒŒ์ผ ์ „์ฒด ๋น„ํ™œ์„ฑํ™”

ํŒŒ์ผ ์ตœ์ƒ๋‹จ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

1
# pylint: disable=missing-module-docstring,missing-function-docstring

โš ๏ธ ์ธ๋ผ์ธ ๋น„ํ™œ์„ฑํ™”๋ฅผ ๋‚จ์šฉํ•˜๋ฉด Pylint์˜ ํšจ๊ณผ๊ฐ€ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋ถˆํ•„์š”ํ•œ ๊ฒฝ๊ณ ๋งŒ ์„ ํƒ์ ์œผ๋กœ ๋„๊ณ , ๊ฐ€๋Šฅํ•˜๋ฉด .pylintrc์—์„œ ํ”„๋กœ์ ํŠธ ์ „์ฒด ๊ธฐ์ค€์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ–ฅ๏ธ VSCode ์—ฐ๋™

settings.json ์„ค์ •

.vscode/settings.json์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
{
  "python.linting.enabled": true,
  "python.linting.pylintEnabled": true,
  "python.linting.pylintArgs": [
    "--disable", "C0301",
    "--max-line-length", "120"
  ]
}

์ €์žฅ ์‹œ ์ž๋™ ๊ฒ€์‚ฌ

1
2
3
4
{
  "editor.formatOnSave": true,
  "python.linting.lintOnSave": true
}

Tip: VSCode์˜ Python ํ™•์žฅ(ms-python.python)์„ ์„ค์น˜ํ•˜๋ฉด ํŽธ์ง‘ ์ค‘ ์‹ค์‹œ๊ฐ„์œผ๋กœ Pylint ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.


๐Ÿ”— pre-commit์œผ๋กœ CI/CD ํ†ตํ•ฉ

์ปค๋ฐ‹ ์‹œ์ ์— Pylint๋ฅผ ์ž๋™ ์‹คํ–‰ํ•˜๋ฉด, ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ๋Š” ์ปค๋ฐ‹ ์ž์ฒด๊ฐ€ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

pre-commit ์„ค์น˜

1
pip install pre-commit

.pre-commit-config.yaml ์ž‘์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
repos:
  - repo: https://github.com/pycqa/pylint
    rev: v3.3.0
    hooks:
      - id: pylint
        args:
          - "--max-line-length=120"
          - "--disable=C0114,C0115,C0116"
        additional_dependencies:
          - pydantic
          - pyyaml
          - requests

ํ›… ์„ค์น˜ ๋ฐ ์‹คํ–‰

1
2
3
4
5
# ํ›… ์„ค์น˜ (์ตœ์ดˆ 1ํšŒ)
pre-commit install

# ์ „์ฒด ํŒŒ์ผ ์ˆ˜๋™ ์‹คํ–‰
pre-commit run --all-files

์ดํ›„ git commit ์‹œ ์ž๋™์œผ๋กœ Pylint๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ, ์˜ค๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉด ์ปค๋ฐ‹์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

GitHub Actions ํ†ตํ•ฉ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name: Lint

on: [push, pull_request]

jobs:
  pylint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install pylint
      - run: pylint src/ --fail-under=8.0

--fail-under=8.0 ์˜ต์…˜์œผ๋กœ ํ’ˆ์งˆ ์ ์ˆ˜๊ฐ€ 8์  ๋ฏธ๋งŒ์ด๋ฉด CI๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ’ก ์‹ค๋ฌด ์ ์šฉ ํŒ

์ ์ง„์  ๋„์ž… ์ „๋žต

๊ธฐ์กด ํ”„๋กœ์ ํŠธ์— Pylint๋ฅผ ๋„์ž…ํ•  ๋•Œ๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ชจ๋“  ๊ทœ์น™์„ ๊ฐ•์ œํ•˜๋ฉด ์ˆ˜๋ฐฑ ๊ฐœ์˜ ์˜ค๋ฅ˜๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ˆœ์„œ๋กœ ๋‹จ๊ณ„์ ์œผ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

  1. E(Error) ๋จผ์ € โ€” ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋กœ ์ด์–ด์ง€๋Š” ์น˜๋ช…์  ๋ฌธ์ œ ์šฐ์„  ํ•ด๊ฒฐ
  2. W(Warning) ๋‹ค์Œ โ€” ์ž ์žฌ์  ๋ฒ„๊ทธ์™€ ๊ฐœ์„  ๊ถŒ์žฅ ์‚ฌํ•ญ ์ฒ˜๋ฆฌ
  3. C/R ๋งˆ์ง€๋ง‰ โ€” ์ฝ”๋”ฉ ๊ทœ์น™๊ณผ ๋ฆฌํŒฉํ† ๋ง์€ ์—ฌ์œ ๋ฅผ ๋‘๊ณ  ๊ฐœ์„ 

์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜ ํ•ด๊ฒฐ

์˜ค๋ฅ˜์›์ธํ•ด๊ฒฐ์ฑ…
E0401 import-error๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ.pylintrc์˜ init-hook์œผ๋กœ ๊ฒฝ๋กœ ์ถ”๊ฐ€
W1203 logging-fstring๋กœ๊น…์— f-string ์‚ฌ์šฉlogger.info("๊ฐ’: %s", value) ํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝ
R1705 no-else-returnreturn ํ›„ else ๋ธ”๋กelse ์ œ๊ฑฐ ํ›„ ๋“ค์—ฌ์“ฐ๊ธฐ ๊ฐ์†Œ
C0301 line-too-long์ค„ ๊ธธ์ด ์ดˆ๊ณผmax-line-length ์กฐ์ • ๋˜๋Š” ์ค„ ๋ฐ”๊ฟˆ

Pyreverse๋กœ UML ๋‹ค์ด์–ด๊ทธ๋žจ ์ƒ์„ฑ

Pylint ํŒจํ‚ค์ง€์— ํฌํ•จ๋œ pyreverse๋กœ ํด๋ž˜์Šค ๊ตฌ์กฐ๋ฅผ ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Graphviz ์„ค์น˜ ํ›„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
pip install pylint
brew install graphviz  # macOS

pyreverse -o png -p MyProject my_package/

classes_MyProject.png์™€ packages_MyProject.png ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


โ“ ์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ

Q. Pylint์™€ Flake8 ์ค‘ ๋ฌด์—‡์„ ์จ์•ผ ํ•˜๋‚˜์š”?

๊ฐ„๋‹จํ•œ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ๊ฐ€ ๋ชฉ์ ์ด๋ผ๋ฉด Flake8์ด ๋น ๋ฅด๊ณ  ์„ค์ •์ด ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ž ์žฌ์  ๋ฒ„๊ทธ ํƒ์ง€, ์ฝ”๋“œ ๋ณต์žก๋„ ๋ถ„์„, ํ’ˆ์งˆ ์ ์ˆ˜๊นŒ์ง€ ํ•„์š”ํ•˜๋‹ค๋ฉด Pylint๊ฐ€ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ๋Š” ๋‘ ๋„๊ตฌ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์ตœ๊ทผ์—๋Š” Ruff๋กœ ํ†ตํ•ฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

Q. Pylint ์ ์ˆ˜ 10์ ์„ ๋ชฉํ‘œ๋กœ ํ•ด์•ผ ํ•˜๋‚˜์š”?

์•„๋‹™๋‹ˆ๋‹ค. 10์ ์ด ํ•ญ์ƒ ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์˜๋ฏธํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ํŒ€์˜ ๊ธฐ์ค€(์˜ˆ: 8.0 ์ด์ƒ)์„ ์„ค์ •ํ•˜๊ณ , ์ ์ˆ˜๋ณด๋‹ค๋Š” EยทW ์˜ค๋ฅ˜ 0๊ฑด์„ ๋ชฉํ‘œ๋กœ ์‚ผ๋Š” ๊ฒƒ์ด ๋” ์‹ค์šฉ์ ์ž…๋‹ˆ๋‹ค.

Q. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(numpy, pandas) ์‚ฌ์šฉ ์‹œ E0401 ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋‚˜์˜ต๋‹ˆ๋‹ค.

.pylintrc์˜ [TYPECHECK] ์„น์…˜์— ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

1
2
[TYPECHECK]
ignored-modules=numpy,pandas,torch,tensorflow

Q. pre-commit ์‚ฌ์šฉ ์‹œ ๊ฐ€์ƒํ™˜๊ฒฝ ํŒจํ‚ค์ง€๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

.pre-commit-config.yaml์˜ additional_dependencies์— ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
additional_dependencies:
  - pydantic
  - sqlalchemy
  - fastapi
This post is licensed under CC BY 4.0 by the author.