요약
아스트랄이 uv와 ty를 실험적으로 연동해 스크립트 타입 검사와 uv check 명령을 내놓았습니다.
파이썬 패키지 관리자 uv와 타입 검사기 ty를 만드는 아스트랄이 두 도구의 실험적 연동을 공개했습니다. uv는 프로젝트 환경과 의존성을 알려 주고, ty는 코드를 분석하는 역할을 나눠 맡습니다. 아스트랄은 이것을 uv, Ruff, ty를 하나의 도구 모음으로 묶어 가는 단계라고 설명했습니다.
왜 중요한가
- 프로젝트와 다른 의존성을 쓰는 단독 스크립트도 자기 환경에 맞춰 제대로 타입 검사를 받게 됩니다.
- uv check는 잠금 파일에 적힌 ty 버전을 써서, 개발자와 CI가 버전을 따로 맞추지 않아도 됩니다.
- 앞으로 Ruff까지 합쳐 린트와 타입 검사를 명령 하나로 돌리겠다는 방향이 분명해졌습니다.
핵심 내용
- ty가 PEP 723(스크립트 안에 의존성을 적는 표준) 정보를 읽고, 스크립트마다 uv로 환경을 따로 준비합니다.
- 편집기에서도 스크립트의 의존성에 맞춰 자동 완성, 호버 정보, 정의로 이동이 동작합니다.
- uv check 명령은 환경 준비, 의존성 설치, ty 실행을 한 번에 처리합니다.
- 의존성 설치가 외부 코드를 실행할 수 있어서, 스크립트 환경 자동 준비는 당분간 사용자가 직접 켜야 합니다.
- 쓰지 않는 의존성 찾기처럼 uv와 ty의 정보를 합친 새 검사도 준비하고 있다고 밝혔습니다.
HN 반응
- 타입 검사기를 패키지 관리자에 합치면 사용자를 묶어 두게 된다는 우려가 나왔고, uv 개발에 참여하는 이용자는 종속은 목표가 아니라고 반박했습니다.
- 여러 이용자는 AI로 타입 주석을 달기 쉬워진 만큼 더 엄격한 Pyrefly가 낫다고 했고, ty가 경쟁에서 밀려 uv에 기댄다는 해석도 나왔습니다.
저는 파이썬 프로그래머입니다. Astral을 정말 좋아하고, Ruff는 훌륭하며 uv는 삶을 바꿔 놓았다고 생각합니다. 하지만 ty는 그렇게까지 마음에 들지 않습니다.
저는 타입 검사기가 타입을 검사하고, 검사하지 못할 때는 소리를 질러 주길 바랍니다. "점진적 타이핑(gradual typing)"은 원하지 않습니다. 어떤 것의 타입이 확실하지 않으면, 그 불확실성을 모델링해 놓고 잠재적 오류를 보여 주지 않을 게 아니라 실패로 처리해 주길 바랍니다. 지금은 에이전트의 시대라서, 여기저기 어노테이션을 더 붙이는 건 더 이상 큰 문제가 아닙니다.
Meta의 Pyrefly가 제가 원하는 걸 대체로 해 줍니다. 다만 Pyrefly도 썩 마음에 들지는 않습니다. 덜 유명한 패키지도 쓸 수 있는 범용 메커니즘을 제공하지 않고, 인기 있는 몇몇 패키지(Pydantic, Django, attrs)만 예외 처리해서 독점적인 지위를 주는 점이 싫습니다. 그래도 순수하게 타입 검사만 놓고 보면 훌륭합니다.
좋은 목표이긴 한데, 도구로 팔기는 어렵습니다. 바탕이 되는 타이핑 명세 자체가 아주 유연하고 점진적 타이핑을 허용하도록 설계돼 있으니까요. 게다가 파이썬 코드베이스는 타입이 전혀 없는 것부터 아주 촘촘하게 타입이 지정된 것까지 천차만별입니다.
Zuban은 써 보셨나요? 제가 마지막으로 선택지를 살펴봤을 때는 Pyrefly를 좋아하시는 이유와 비슷한 이유로 Zuban이 더 마음에 들었습니다. 최근에 다시 평가해 본 적은 없지만요.
그런데 Zuban은 1인 프로젝트라서 버스 팩터가 아마 1일 겁니다.
저는 uv 관련 작업은 전부 직접 하고, ty는 AI한테 맡겨 버립니다. 그렇게 하니 별문제가 별로 없더군요.
Astral의 도구들은 다 좋아하지만, CLI가 왜 이렇게 파편화돼 있는 느낌인지 모르겠습니다.
지금 ty는 uv에 통합되는데, ty는 기술적으로 ruff의 일부이기도 합니다 [1]. 그런데 ruff는 uv에 통합돼 있지 않습니다.
포매터는 ruff에 들어 있는데, uv에도 문서화되지 않은 "format" 명령이 있습니다. 결과는 같지 않고요.
사실 ruff도 uv에 통합돼 있긴 한데, "uv tool run ruff"로 호출해야 합니다.
"uv format"과 "uv lint"가 표준 명령이 되면 좋겠습니다.
[1] https://github.com/zed-extensions/pyrefly/issues/26#issuecomment-5720334055
uv format은 (실험 단계이긴 하지만) 이미 있고, Ruff를 호출하는 면에서는 기대하시는 대로 동작합니다. 그리고 ty에 해당하는 명령은uv check입니다.(ty가 Ruff의 "일부"라는 건 상당 부분 같은 기반 코드를 공유한다는 뜻이라, 소스 트리상으로 서로 밀접하게 붙어 있다는 의미입니다. 하지만 바이너리는 Ruff와 완전히 별개입니다.)
저는 아닙니다. 포매팅과 린팅은 패키지 매니저에 들어갈 게 아닙니다.
그런데 기사에서 말하는 사용 사례는 의존성이 선언된 독립 실행형 스크립트의 타입을 검사하는 것입니다. 그러니 패키지 관리와 타입 검사 도구가 어느 정도는 동시에 필요합니다.
uv는 프로젝트 전체를 관리합니다. 그냥 pip의 다른 버전이 아니에요.
Rust의 Cargo와 Elixir의 Mix가 둘 다 그런 식으로 동작합니다.
Cargo는 꼭 그렇지는 않습니다.
Rust 포매팅을 구현하는 건 rustfmt입니다. 다만 rustfmt는 rustup(Rust의 툴체인 관리자)으로도 배포되고, 거기서 cargo-fmt라는 별칭으로 노출되기 때문에
cargo fmt라는 cargo 하위 명령으로 동작합니다(어떤 크레이트에서든 쓸 수 있는 메커니즘입니다). 그래서 기술적으로는 "cargo의 일부"가 아닙니다.물론 이 모든 게 성격이 좀 다르긴 합니다. 컴파일러에만 집중하는 다른 언어 생태계와 달리, Rust는 cargo와 rustfmt를 비롯한 수많은 개발 도구를 공식 팀의 일부로 직접 관리하니까요.
사용자 입장과 운영 측면에서 보면 그렇게 동작하는 게 맞습니다. Mix도 도구를 하위 명령으로 호출한다는 점에서 똑같고요. 하지만 그건 중요하지 않습니다.
cargo와mix가 모든 걸 주도하는 기본 경험을 얻게 되니까요.이렇게 별개의 도구들이 뒤섞이는 건 마음에 들지 않습니다. ty는 지금 uv를 쓰지 않는 프로젝트에서도 아주 잘 쓸 수 있습니다. uv에는 고집스러운 특이점이 많고, 독자적인 락파일이 있고, 우리 중 많은 사람이 싫어하는 미묘한 부분들도 있습니다. ty가 별도 도구이기 때문에 평범한 pip나 다른 의존성 관리자(예: pip-tools)와도 잘 어울립니다.
그런데 짚어 둘 점은, ty가 uv에 통합될 필요도 없고 그 반대도 마찬가지라는 겁니다. 각자 독립된 도구로 두는 게 가장 자연스러워 보입니다.
놀랄 일도 아닙니다. Astral은 몇 년 전부터 uv로 락인(lock-in)을 만들고 싶어 했고, 당연히 가능한 한 모두를 자기네 "생태계"로 끌어들이려 하겠죠. 메인 파이썬에서 갈라져 나가는 일이 더 늘어나거나, 자기들이 장악한 "시장"을 지렛대로 삼는 일을 각오하세요.
파이썬 도구 생태계가 형편없는 상태라는 걸 생각하면 uv에 락인되는 게 그렇게 나쁜 일만은 아닙니다.
저는 별로 공감이 안 됩니다. 의존성이 상당히 많은 꽤 큰 프로젝트를 라이브러리이자 애플리케이션으로 둘 다 쓰면서 작업해 왔거든요. uv가 부실한 의존성·호환성 관리를 덮어 가리는 용도로 쓰이는 경우가 자주 보이는데, 그러면 그 문제가 스스로 강화됩니다. 최종 배포에만 엄격하게 쓴다면야 괜찮겠지만, 그렇다고 주의를 기울일 필요가 없어지는 건 아닙니다(없어져서도 안 되고요). 결국 파이썬 도구의 상태를 "Astral™의 uv를 쓰지 않으면 전부 망가진다"로 만들려는 시도로밖에 보이지 않습니다.
저는 uv 이전의 파이썬 도구도 전혀 문제없다고 느꼈습니다. rye 시절에 꽤 좋아했고 기능도 좋았는데, 지금은 uv가 더 낫다는 건 의심할 여지가 없습니다. 하지만 결국 저는 asdf로 파이썬 버전을 설치하고 python -m venv로 가상 환경을 만든 다음, 활성화해서 pip만 쓰면 필요한 건 다 얻었습니다.
uv 워크플로가 더 낫긴 하지만, Astral에 락인되든 뭐든 어떤 일이 벌어져서 문제가 되는 날이 오더라도 괜찮습니다(그 옛날 도구들이 계속 존재하는 한은요).
그렇다면 메인 파이썬이 형편없는 패키지 배포 방식을 표준화해서 고치는 속도를 더 내야죠. cargo를 대체하려는 사람은 아무도 없잖아요.
uv는 이제 막 3살이 됐으니 "몇 년"이라는 건 과장 같습니다. 그리고 락인은 이 프로젝트의 목표인 적이 없다고 생각합니다. uv는 파이썬 패키징 표준을 따르려고 웬만큼 무리를 해서라도 맞춥니다. uv를 개발하는 사람들이 그 표준 작업에도 참여하는 경우가 많으니까요. 따르지 않는 부분(uv.lock 같은)은 표준으로는 uv가 원하는 것을 정확히 표현할 수 없기 때문입니다.
(참고로 저는 uv와 파이썬 패키징 표준 양쪽 모두에서 일합니다.)
A가 B를 함의한다고 해서 B가 A를 함의하는 건 아닙니다. ty는 따로 써도 되고, 이번 변화가 그걸 막는 것도 아닙니다. 다만 uv check가 ty를 함께 쓰는 건 유용합니다.
타입 검사에는 ty를 쓰면서 의존성 관리에는 uv 말고 다른 걸 쓰는 프로젝트는 아마 극소수일 겁니다.
하지만 uv는 쓰고 ty는 안 쓰는 프로젝트는 아마 많을 겁니다.
그런 프로젝트 상당수는 CI에 도구를 하나 더 추가하자고 협상하고 흥정하는 일을 피하려는 이유도 있을 거라고 생각합니다. 특히 이런 대화가 비기술직 중간 관리자 여러 층을 거쳐 질질 끌려 다니는 대기업 환경에서는 더 그렇겠죠.
ty는 매력적인 선택지가 아닙니다. 동적 라이브러리 지원이 필요하면 mypy가 왕이고, 속도와 엄격한 규격 준수를 원하면 Pyrefly와 Zuban이 더 낫습니다.
ty가 처음 내세운 장점은 추론 능력이 강해서 타입이 없는 기존 코드베이스에 점진적으로 타입을 붙이는 데 유용하다는 것이었는데, AI 때문에 그게 의미가 없어졌습니다. 이제 기존 코드에 타입을 추가하는 건 별일도 아니니까요.
그게 맞는지는 잘 모르겠습니다.
그리고 기사에서는 자동으로 설치되지 않는다고 하니, 원하는 사람만 쓰게 되는 겁니다.
올해 들어 pyrefly가 점점 힘을 얻고 있었던 것 같아요. 저도 이번 주에 쓰기 시작했고요.
Astral이 타입 검사기 경쟁에서 졌다는 걸 깨닫고, 사람들이 쓸 이유를 만들려고 인기 있는 자기네 프로젝트에 끼워 넣는 걸로 보여요.
uv와 함께 이미 설치돼 있으면 사람들이 따로 타입 검사기를 찾아볼 이유가 줄어들고, 그냥 기본 옵션을 계속 쓰게 되겠죠.
공교롭게도 저희도 최근 한 달쯤 사이에 pyrefly로 옮겼습니다.
AI가 도입과 마이그레이션을 빠르게 해결해 주니, 그냥 가장 좋은 도구를 고르는 문제가 됐습니다. pyrefly는 필요한 건 다 갖췄고 ty보다 빠릅니다.
동감이에요. 더 나은 타입 검사 파티에 너무 늦게 왔다는 걸 깨닫고 해자(moat)를 넓히려는 것처럼 들려요.
사실 이제야 이걸 하고 있다는 게 좀 아이러니하기도 하고요.
uv의 전신인rye는 꽤 일찍부터ruff를 통합했거든요. 그런데 Astral은uv에 넣는 걸 계속 미적거렸고(아마ruff가 이미 이겼다고 봤기 때문이겠죠), 지금도ty가 통합된 다음에야 지원을 추가하려는 거잖아요.