[ 글의 목적: 의존성 관리와 패키징을 위한 uv 세팅 부터 활용 기록, 린팅과 포맷팅을 동시에 지원하는 ruff 까지 같이하는 세팅 기록 ]
Uv, Ruff 모두 Astral(아스트랄) 회사의 오픈소스, 라이브러리이다.
python
생태계는 정말 "파이써닉" 한 방향으로 계속 진화하고 있다.poetry
만 해도 엇그제 같은데, 아스트랄의 제품들이 정말 무서울 정도로의 속도로 관련 오픈소스들을 압살하고 있다..! 제일 대표작 Uv, Ruff 오픈소스를 개괄적으로 살펴보자!
실제 세팅만 보고 싶다면 2. uv & ruff 설치와 세팅 을 바로 보면 됩니다~
"파이썬 생태계의 생산성을 높이는 고성능 개발 도구를 만든다" 라는 일념하에 세워진 아스트랄은 창업자 Charlie Marsh
가 “파이썬 툴링은 훨씬 더 빨라질 수 있다” 는 가설을 Ruff
로 스스로 검증하며 쏘아올려졌다. (상남자다..) - Announcing Astral, the company behind Ruff
23년 4월, "We’ve raised $4m in seed funding led by Accel" 라고 언급되어 있듯, "400만 달러 - 한화 약 57억" 을 시드받고 날개를 활짝 핀 것 같다. 도구는 오픈소스(무료)로 유지하고, 그 위에 유료 hosted service를 만든다는 유료화 목표가 있는 것 같다. 아마 클라우드를 도입할 것 같은데, 어떻게 BM을 만들지 미래가 정말 궁금하다.
대표적으로 아래 3개에 집중하고 있다. 출시 순서도 ruff -> uv -> pyx -> ty
이다. 이 글에서는 ruff
와 uv
만 다뤄보고자 한다.
Ruff
: 린팅·포매팅(편집기 통합 포함)uv
: 패키지/프로젝트/스크립트/도구/파이썬 버전까지 원스톱 관리pyx
: "Python-native package registry" -> 얘가 아스트랄의 첫번째 유료화 서비스이다. 아직 상용화는 안한 듯 하다. 클로즈 베타인지, 위시리스트를 받는 것 같다. - pyx: a Python-native package registry, now in Beta. 꽤 신박하니 소개 글 추천!ty
: 타입 체커, 얘는 진짜 핫하다. 2025-09-19 공개된 문서 - https://docs.astral.sh/ty/Poetry
는 수년간 꾸준히 발전하며 약 33.9k
개의 스타를 얻었지만, 2024년에 등장한 uv
는 불과 1년 만에 스타 개수가 36k를 넘어섰다. 나중에 다시 언급하겠지만, 나는 poetry
가 가상환경을 더 불편하게 업데이트 한 것에 좀 불편함이 있다.
2024년 10월 기준으로 PyPI
에서 전체 패키지 다운로드의 약 13.3%
가 uv를 통해 이루어졌고, uv 자체도 월 2천8백만 건 이상의 다운로드 수를 기록 하며 거대한 성장세를 증명하고 있다. 도대체 어떻게 한건가..
이 정도면 주작아닌가 싶을정도로 ruff 의 성장 기울기는 미쳤다. 불과 2년여 만에 ruff는 GitHub 스타 27k+ 를 돌파해 Black
을 포함한 기존 도구를 넘어섰다. 실제로 ruff는 주당 약 270개의 스타를 얻으며 핫한 프로젝트 1위에 올랐는데, 이는 Black의 스타 증가 속도(주당 약 107개)보다 두 배 이상 빠른 수치라고 한다. - AwesomePython
현재 Flake8, Black 등의 역할을 하나로 통합하면서도 수백만 건의 주간 다운로드를 보여주고 있다. 사실 이미 나도 린팅은 black
& flake8
버리고 ruff 로 갈아타버렸다. 사실 python 에서 린팅을 위해 사전 세팅이 꽤 많다. 그리고 이를 위한 써드파티나 플러그인도 필요하니, toml
에 종속적인 것을 위해 ruff
로 갈아타고, 자연스럽게 uv
로 스며들고 있다.
아스트랄의 미션과 비전에 얼라인하는 "초고속 패키지/프로젝트 매니저" 오픈소스를 만든 것이다. pip
, virtualenv
, pipx
, pyenv
, poetry
등과 같은 도구를 "일원화" 하는게 가장큰 목표이다. 그리고 첫 탄생과 다르게 이제 uv
만으로 라이브러리를 배포하고 버저닝 할 수 있다. (나에게는 이게 가장 큰 요인이었다.) 언급된 도구들 진짜 다 써본 것 같은데 개인적으로 아나콘다가 최악이다..
uv ill like uv 글에 따르면 "Initially Armin Ronacher started rye as a “cargo for python” to unify the fragmented python tooling landscape (for a great overview check out this talk by Anna-Lena Popkes)." 라고 언급되어 있다.
Armin Ronacher가 시작한 실험적 패키징 툴 Rye
가 있는데, Astral의 창업자 Charlie Marsh가 이 아이디어를 이어받아 uv를 통합 후속 프로젝트로 출시한 것 이다.
현재 빠르다고 하는 애들보다 더 빠르다고 한다. (pip 대비 10~100배). 근본적인 빠른 이유는 Rust
기반 컴파일 바이너리파일이기 때문인데, 여러 최적화 스킬이 있다. - uv: Python packaging in Rust
딥 위키에서 uv 를 보면 더 이해하기 쉽다. 시간있을때 https://deepwiki.com/search/-uv-python-installer-lets-thin_90419ea2-54e1-4a0d-81bd-8894df0eedb7 를 따라가면서 한 번 봐보자!
일단 pip
은 기본적으로 "순차적인 백트래킹" 방식으로 의존성 체크를 한다. 예로 1버전 시도 -> 충돌 -> 1.1버전 시도 이런식으로 말이다. 그렇기에 순환 참조를 포함한 복잡한 의존성 그래프에서는 최적의 조합을 찾지 못하거나 해결에 실패하는 '의존성 지옥(dependency hell)'에 빠질 수 있다. 게다가 이 과정에서 종종 전체 패키지 파일(wheel)을 다운로드하여 메타데이터를 확인해야 하므로 I/O 비용이 크다!
언급한대로 "SAT 해결기 기반 접근법" 을 사용한다. (SAT: Boolean Satisfiability Problem, 부울 충족 가능성 문제) 유사한 문제로 취급하는 PubGrub 알고리즘에서 영감을 받았다고 한다. - Resolver internals
rust 바이너리기반 훨등한 속도. Poetry Was Good, Uv Is Better: An MLOps Migration Story 에서 poetry
대비 CI/CD 속도가 기하급수적으로 빨라졌다는 (약 10배) 후기도 있다.
"찐 통합 툴". installer
, pyenv
, virtualenv
심플하게 할 수 있으며 (이상한) pipx
대신 uvx, uv tool
로 대신할 수 있다. uv publish
로 twine
없이 배포할 수 있다.
"표준 준수, 심플한 세팅". PEP 621/631
에 맞는 toml
하나로 패키지 메타데이터 + 의존성 관리가능! 특히 2024년 말 도입된 PEP 735(dependency groups 표준)
을 빠르게 지원.
uv sync, uv run
이 의존성 동기화를 "알아서 보장" 해줘서 workflow 의 몇 단계를 하나로 함축시킬 수 있음.
poetry
대신 uv
로 무조건 모든 프로젝트를 넘어가지는 않았다. 위 4가지 장점은 사실 poetry
도 매우 잘 해준다. 다만 poetry
가 내게 불편 포인트를 줬던건 1) 다중 python 버저닝을 따로 다루는 것, 2) 가상환경을 즈그들 방식대로 한다는 점.
이다.
사실 2번이 매우 열받는 포인트인데, source .venv ...
로 vscode 에게 가상환경 먹여줘야 할 때, 그리고 중앙관리식 가상환경을 쓰면 오히려 사용자인 내가 가끔 까먹는다. 이게 관성에 벗어나는 방식이라...
또, 프로덕션에서는 나는 굳이 uv
또는 poetry
를 사용해서 서버를 운영하지는 않는다. 추가 써드파티나 의존성을 전혀 하고 싶지 않아서 인데, uv
는 오히려 production 에서도 사용해볼까 한다.
CLI 커맨드가 꽤 많다. 그리고 생각보다 마냥 간단하지는 않다. uv lock --upgrade
과 같이 아니 왜 update
가 아닌건데? ㅎㅎ.
uv pip install
과 uv add
는 다르다. uv add
를 하고 uv sync
로 설치하는 흐름. 애매한 경계선에 있는 명령어들 때문에 헷갈릴 수 있다.
poetry
는 python
으로 만들어졌다. 근데 uv
는 rust
로 만들어졌다. 사실 python
생태계에서는 이게 꽤나 중요할지 모른다. rust
로 만들어진 python
을 위한 생태계 툴이라니,, 제 3의 기여자를 만들기 어렵다고 판단된다.
근데 아스트랄이 소통을 많이 하는 듯 하다. 다양한 장단점을 흡수하고 개선하며 정말 지속적으로 빠르게 발전하고 있다.
아스트랄의 시작이자, 이름을 알린 태초의 라이브러리, ruff는 기존에 Python 코드 품질 관리를 위해 Flake8, isort, pylint, Black 등 여러 도구를 조합해야 했던 불편함을 해결하고자 했다. 위에 언급한대로, 아스트랄은 "파이썬 툴링은 훨씬 더 빨라질 수 있다" 는 가설을 Ruff 로 (Charlie Marsh) 스스로 검증하며 시작됐다.
PEP8 을 따라가기위해 pycodestyle 검사 (사내룰, 구글 스타일 가이드 등) -> flake8 -> isort (import 정렬) -> 포맷팅엔 black 등의 순서로 진행했고, 각 세팅마저 달랐다. 나의 과거글 python - flake8, Black 도입, pre-commit & clean code-style 실천하기 에서도 정말 간단한 세팅에 노고가 좀 필요했다.
근데 ruff
요놈은 한 번 딸각에 해결한다. 더욱이 uv
랑 같이쓰면 세팅이 매우매우 깔끔하고 편해진다. poetry
쓰는 사람들도 ruff
는 바로 써보면 좋겠다. poetry
랑도 합이 잘 맞는다.
단순하게 Rust
기반이라서 빠른 것 보다, 핵심적으로 아래 3가지가 꼽힌다.
이러한 세심한 튜닝 덕분에 ruff는 Flake8 등의 10~100배 속도로 코드베이스를 토큰화 하고 검사하고 포맷팅할 수 있다!
ruff는 하나의 툴로 800개 이상의 린트 규칙(기존 Flake8 플러그인 다수 포함)을 제공하고, 코드 자동포맷팅 기능도 지원한다.
린팅, 포맷팅 속도가 거의 실시간이다. 대규모 코드베이스에서도 ruff를 돌리는 데 걸리는 시간은 블링크 수준이라, 실시간 피드백을 받기에 충분하다.
더 이상 프로젝트에 flake8, black, isort 등을 모두 설치하고 설정할 필요 없이 [tool.ruff] 하나의 설정으로 일관성 있게 관리할 수 있다.
ruff는 IDE/에디터 통합과 CI 연동이 잘 되어 있다! (탄생때부터 이걸 노린 듯하다.)
pre-commit
훅도 공식 지원하여 쉽게 품질 검증 파이프라인에 넣을 수 있다. ruff는 지금까지도 빠르게 진화하고 있다. 규칙 커버리지도 계속 늘어나고 있고, 향후 static type checker(ty)
까지 개발 중일 정도로 툴체인 확장을 모색하고 있다.
ruff는 기본적으로 모든 검사를 내장하고 있어, Flake8처럼 사용자가 간편하게 플러그인을 추가하는 방식은 지원하지 않는다.
Pylint
처럼 "정적 분석 수준에서 코드의 논리적 버그" 까지 잡아주는 기능은 ruff에는 없다. (ruff는 타입체커가 아니고 주로 스타일, 버그 패턴 위주 검사임).
ty
등과 캐미가 어떻게 되냐에 따라 굉장히 달라질 듯 하다.)
MacOS
기준
$ curl -LsSf https://astral.sh/uv/install.sh | sh
다른 공식자료들, 외부 자료들 때문과 PATH
때문이라도 로 brew 로 하지 않았으면 한다..
Rust
나 Python
이 없어도 uv
바이너리를 시스템에 설치해준다.
$ mkdir myproject && cd myproject
$ uv init .
타 써드파티와 매우 유사하다. init
을 하면 pyproject.toml
이 만들어지며 poetry
와 유사하게 [project]
메타데이터 및 의존성 섹션을 활용한다. README.md
, .python-version
과 git
까지 세팅해준다.
uv init --lib mylib # 라이브러리 템플릿
uv init --package mypkg # 패키징 가능한 프로젝트(기본 빌드 시스템 부여)
재미있는 포인트는, 라이브러리 템플릿, 패키징 가능한 플젝 템플릿도 바로 제공해준다.
uv python pin 3.13
과 같이 하며, 자동으로 관련 값들을 업데이트 해준다.
uv python list
로 내가 지금 설치한 python version 과 path 를 모두 한 눈에 확인할 수 있다. 좋다! 물론 이는 위 사진에서 cpython-3.13.0-... 을 보면 알겠지만 alias
를 포함한 것이다. (정확하게는 심볼릭 링크)
오피셜하게는 uv run
을 하면 가상환경과 프로젝트 세팅 & 인터프리터 세팅을 할 수 있다. 즉, 뭔가를 지금 플젝에 세팅한대로 python
을 실행할때, 마치 poetry run ...
처럼, uv run ...
을 하면 된다.
uv add fastapi
와 같이 패키지를 설치하며, 기존 가상환경이 없으면 add
만으로 바로 가상환경을 만든다.
결론적으로 "가상환경 activation은 source .venv/bin/activate
와 같이, 개인적으로 나에게 아주아주 익숙하고 편한 방식으로 관리할 수 있다. 진짜 이름마저 찰떡.
만약 패키지매니저가 처음이라면, lock
이 익숙하지 않을 수 있다. 간단하다. "모든 개발자·머신·배포 환경에서 동일한 설치 결과를 재현하기 위해" uv.lock
을 사용한다. 그래서 플랫폼(운영체제/아키텍처/파이썬 버전) 차이까지 고려한 보편(크로스플랫폼)적인 패키지 정보들을 제공한다.
uv lock
으로 lock file 을 만들고 기존 lock 과 uv lock --check
로 최신성만 빠르게 검사할 수 있다. uv run --locked
와 uv sync --locked
으로 엄격한 모드로 실행하고 싱크를 맞추게 할 수 있다.
그리고 add
와 pip install
핵심 차이는 아래와 같다. (lock file 갱신 여부 차이)
- `uv add`: pyproject/lockfile **갱신** + .venv 설치
- `uv pip install`: lockfile **미갱신**(실험/임시 설치에 유용)
uv.lock
이 있다면 uv sync
한 번 으로 가능하다. (사실 이건 poetry
도 그럼). 락파일이 있다면 그 버전 그대로 설치하고, 락파일이 없고 pyproject.toml
만 있다면 uv sync
하기 전에 uv lock
으로 명시적 생성 후 실행하는 것을 추천한다.
그 외 아스트랄 uv 공식 docs의 Features 에서 확인하길 바란다. uv tree
, uv build
, uv publish
사실 poetry
랑 거의 동일하다고 느껴진다.
uv
를 쓴다고 가정하고, ruff
를 설치할땐 아래와 같이 한다. "--group" 이 앞서 언급한 PEP 735(dependency groups 표준)
이다.
$ uv add --group dev ruff
위 사진과 같이 dependencies.dev
섹션에 추가 된다. poetry add -D ruff
와 동일한 맥락이다. 근데 설치없이 uv
의 uvx
를 통해 바로 실행할 수 있다! (이는 비추천)
uvx ruff check
uvx ruff format
린팅
ruff check . # 재귀적으로 모든 파이썬 파일 검사
ruff check path/to/file.py # 특정 파일
ruff check . --fix # 자동 수정 가능한 항목만 적용
ruff check --unsafe-fixes # 비적용이지만 제안 표시
ruff check --fix --unsafe-fixes # 실제 적용
포맷팅
ruff format # 코드 포맷
ruff format --check --diff # CI에서 포맷 불일치 검출
Migrating to ruff from black and flake8 글과 같이 ruff의 목표는 Black, Flake8, isort 등을 모두 대체하는 것 이므로 굳이 기존 린터/포매터를 함께 쓸 필요는 없다.
Black 대체: 만약 기존에 Black으로 포맷팅해오던 프로젝트라면, ruff
설치 후 ruff check --diff
실행과 black
실행의 차이점 파악. 상호 세팅 차이가 있는 것을 업데이트 하고 (포메팅 규칙) black
을 삭제하면 된다.
Flake8/기타 린터 대체: 맥락은 거의 위와 동일하다. Flake8 설정(.flake8이나 setup.cfg의 [flake8] 섹션 등, 와 이거 진짜 개인적으로 싫다.)
그 외는 아래 표를 살펴보자!
도구 / 플러그인 | ruff로 대체 가능? | ruff 규칙 접두사 | 참고 |
---|---|---|---|
Flake8 | 예 | F (Pyflakes), E/W (pycodestyle) | 대부분의 조건에서 완벽하게 대체 가능합니다. |
Black | 예 (포맷터) | ruff format | 99.9% 이상 호환되지만 일부 의도된 차이점이 있습니다. |
isort | 예 | I | 임포트 정렬 기능이 내장되어 있습니다. |
pyupgrade | 예 | UP | 최신 파이썬 문법을 제안합니다. |
flake8-bugbear | 예 | B | 잠재적인 버그와 설계 문제를 찾아냅니다. |
flake8-comprehensions | 예 | C4 | 더 관용적인 컴프리헨션 작성을 돕습니다. |
pydocstyle | 예 | D | 독스트링 컨벤션을 강제합니다. |
flake8-bandit | 예 | S | 일반적인 보안 문제를 확인합니다. |
Pylint | 부분적으로 | PL | ruff는 완벽한 대체재가 아니며, 규칙 집합이 다릅니다. |
사용자 정의 플러그인 | 아니요 | 해당 없음 | ruff는 서드파티 플러그인을 지원하지 않으며, 규칙은 핵심 프로젝트에 기여해야 합니다. |
pre-commit hook 이 뭔가요?! 한다면 -> python - flake8, Black 도입, pre-commit & clean code-style 실천하기 글을 참조해 주세요!
.toml
에 세팅하기# ================================================================
# Ruff (Linter & Formatter) Settings
# ================================================================
[tool.ruff]
# 수정에서 제외할 파일 및 디렉토리 목록
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
"*/migrations/*.py",
]
# 한 줄의 최대 글자 수
line-length = 120
# --- Linter (코드 분석기) 설정 ---
[tool.ruff.lint]
# 활성화할 규칙 선택:
# E, W: pycodestyle (에러, 경고)
# F: Pyflakes (논리적 오류)
# I: isort (import 정렬)
select = ["E", "F", "W", "I"]
ignore = []
# 모든 수정 가능한 규칙을 자동으로 고치도록 설정
fixable = ["ALL"]
unfixable = []
# --- Formatter (코드 포맷터) 설정 ---
[tool.ruff.format]
# Black과 유사한 포맷팅 스타일을 따릅니다.
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
# --- 플러그인별 상세 설정 ---
[tool.ruff.lint.isort]
# 프로젝트에서 사용하는 서드파티 라이브러리 목록
known-third-party = ["django", "rest_framework", "graphene_django"]
# --- 파일/디렉토리별 규칙 무시 설정 ---
[tool.ruff.lint.per-file-ignores]
# settings 파일: 와일드카드 import 허용
"config/settings/*" = ["F403", "F405"]
# __init__.py 파일: 하위 모듈 노출을 위한 미사용/와일드카드 import 허용
"**/__init__.py" = ["F401", "F403"]
# 테스트 파일: 가독성을 위해 긴 줄 허용
"**/test_*.py" = ["E501"]
# 긴 문자열이 많은 파일들, 줄 길이(E501) 등 규칙 무시
"utils/(모자이크)/*" = ["E501", "W291", "W293"]
"batch/*" = ["E501", "W291", "W293"]
"artifacts/*" = ["E501", "W291", "W293"]
# 기타 특정 파일들의 줄 길이(E501) 규칙 무시
"utils/(모자이크).py" = ["E501"]
"config/(모자이크)/(모자이크).py" = ["E501"]
"config/(모자이크).py" = ["E501"]
"apps/(모자이크).py" = ["E501", "W291"]
위는 실제 내가 프로젝트에 적용해서 사용하는 ruff
세팅이다. 통으로 수정을 제외하는 디렉토리, 한 줄 최대 글자 수, 활성화 린팅 그룹 세팅과 포맷팅 세팅, 자체 플러그인, 자체 써드파티, 특정 파일의 특정 규칙만 무시하기!
[tool.ruff.lint]
에서 I
를 추가했기에 import
역시 isort
대로 린팅&포맷팅을 한다.
https://github.com/astral-sh/uv-pre-commit 에서 uv 관련된 pre-commit 들을 볼 수 있다. 특히 배포환경에서는 uv 등의 패키지매니저를 굳이 사용하지 않을때 중요한건 requirements.txt
을 lock
file 에 준하게 strict 한 버전으로 만들어야 한다는 것! 그래서 아래와 같은 pre-commit 을 사용할 수 있다!
- repo: https://github.com/astral-sh/uv-pre-commit
# uv version.
rev: 0.8.22
hooks:
- id: uv-export
uv export --format requirements.txt --all-groups --output-file requirements.txt
로 dev 그룹을 포함한, dev를 제외하려면 --no-dev
, lock file 기준의 requirements file을 얻을 수 있다.
uv export --format requirements-txt --all-groups > requirements.txt
로도 가능하다.
이 정도 pre-commit 은 세팅하자.
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.13.2" # 사용하고자 하는 ruff 버전 태그
hooks:
- id: ruff-check # 린트 검사 (--fix 없을 경우 검사만)
args: [--fix] # 자동수정 활성화 - 권장
- id: ruff-format # 포매팅 (Black 대체)
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
CI/CD 파이프라인에 추가할때 위와 같이 넣으면 된다!
.vscode
에서도 쓰려면.vscode/settings.json
에 아래 설정값을 추가해보자!
{
"[python]": {
// 1. 기본 포맷터를 'ruff'로 지정합니다.
"editor.defaultFormatter": "charliermarsh.ruff",
// 2. 파일을 저장할 때마다 자동으로 포맷팅을 실행합니다.
"editor.formatOnSave": true,
// 3. 저장 시 추가적인 코드 액션을 실행합니다.
"editor.codeActionsOnSave": {
// 3a. 수정 가능한 모든 린트 오류를 자동으로 수정합니다.
"source.fixAll.ruff": "always",
// 3b. isort 규칙에 따라 임포트 구문을 자동으로 정렬합니다.
"source.organizeImports.ruff": "always"
}
},
// 4. ruff가 프로젝트의 가상 환경을 올바르게 인식하도록 인터프리터 경로를 지정합니다.
// 이렇게 하면 ruff가 설치된 패키지를 정확히 인지하고 'import' 관련 오류를 줄일 수 있습니다.
"ruff.interpreter": ["${workspaceFolder}/.venv/bin/python"],
// 5. (선택 사항) ruff 실행 시 추가 인자를 전달할 수 있습니다.
// 예: 특정 설정 파일을 강제하거나, preview 기능을 활성화할 때 유용합니다.
"ruff.lint.args": ["--config=pyproject.toml", "--preview"],
"ruff.format.args": ["--config=pyproject.toml", "--preview"]
}
uv init .
uv add --group dev ruff pre-commit
uv lock
uv sync --all-groups
# requirements.txt 만들기
uv export --format requirements-txt --all-groups > requirements.txt
# .toml 에 최소한의 ruff 세팅
[tool.ruff]
line-length = 120
[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = []
[tool.ruff.format]
# Black 호환 기본값 권장. 필요 시만 조정.
uv run ruff check # 린팅
# 자동 수정, 포맷팅
uv run ruff check . --fix
uv run ruff check . --fix --unsafe-fixes # 위험도가 높은 자동수정까지 허용
pre-commit
에 등록해서 사용하기# .pre-commit-config.yaml (예: ruff 전용 리포지토리 사용)
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.13.2"
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
uv run pre-commit run --all-files
name: ci
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# uv 설치 + 캐시
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true # 선택사항이지만 명시 권장
# 프로젝트 환경을 락 기준으로 정확히 동기화 (dev 포함)
- run: uv sync --locked --all-groups
# 포맷 확인(자동 수정 금지). 방금 sync 했으므로 run은 no-sync로 빠르게
- run: uv run --no-sync ruff format . --check
# 린트(gh 어노테이션). 마찬가지로 no-sync
- run: uv run --no-sync ruff check . --output-format=github
PS. github CI/CD 에서 testing 때문에 uv 를 사용하지, 진짜 ruff만 쓸꺼면 uv 필요 없다!
PS. .vscode/settings.json
를 쓰는 것은 비추천한다. 무지성 날코드 후 오토세이브로 구원받는 습관을 들이게 된다. 내 얘기가 맞다.
Poetry -> uv로 넘어갔는데 진짜 개인적으로는 너무 편하네요
특히 파이썬 독립적이어서 버전별 테스트도 너무 좋고 uv + pep 723 조합 최고.
uv run만 있으면 비개발자분이 의존성 문제가 훨씬 줄어들고, 하드링크 사용하니 설치 중복도 줄고...