Skip to content

캐싱

의존성 캐싱

uv는 이전 실행에서 이미 접근한 의존성을 다시 다운로드하고 빌드하는 것을 피하기 위해 적극적인 캐싱을 사용한다.

uv의 캐싱 방식은 의존성의 종류에 따라 달라진다:

  • 레지스트리 의존성 (예: PyPI에서 다운로드한 패키지)의 경우, uv는 HTTP 캐싱 헤더를 존중한다.
  • 직접 URL 의존성의 경우, uv는 HTTP 캐싱 헤더를 존중하며, URL 자체를 기반으로 캐싱한다.
  • Git 의존성의 경우, uv는 완전히 해결된 Git 커밋 해시를 기반으로 캐싱한다. 따라서 uv pip compile은 해결된 의존성 집합을 작성할 때 Git 의존성을 특정 커밋 해시로 고정한다.
  • 로컬 의존성의 경우, uv는 소스 아카이브(예: 로컬 .whl 또는 .tar.gz 파일)의 최종 수정 시간을 기반으로 캐싱한다. 디렉터리의 경우, uv는 pyproject.toml, setup.py, 또는 setup.cfg 파일의 최종 수정 시간을 기반으로 캐싱한다.

캐싱 문제가 발생할 경우, uv는 몇 가지 해결책을 제공한다:

  • 모든 의존성에 대해 캐시된 데이터를 강제로 재검증하려면, 어떤 커맨드에든 --refresh를 전달한다 (예: uv sync --refresh 또는 uv pip install --refresh ...).
  • 특정 의존성에 대해 캐시된 데이터를 강제로 재검증하려면, 어떤 커맨드에든 --refresh-package를 전달한다 (예: uv sync --refresh-package flask 또는 uv pip install --refresh-package flask ...).
  • 기존에 설치된 버전을 무시하고 강제로 재설치하려면, 설치 커맨드에 --reinstall을 전달한다 (예: uv sync --reinstall 또는 uv pip install --reinstall ...).

동적 메타데이터

기본적으로 uv는 루트 디렉토리의 pyproject.toml, setup.py, 또는 setup.cfg 파일이 변경된 경우에만 로컬 디렉토리 의존성(예: 편집 가능한 패키지)을 다시 빌드하고 재설치한다. 이는 휴리스틱 방식이며, 경우에 따라 원하는 것보다 재설치가 적게 발생할 수 있다.

특정 패키지의 캐시 키에 다른 정보를 포함하려면 tool.uv.cache-keys 아래에 캐시 키 항목을 추가할 수 있다. 이 항목은 파일 경로와 Git 커밋 해시를 모두 포함할 수 있다.

예를 들어, 프로젝트가 setuptools-scm을 사용하고 커밋 해시가 변경될 때마다 다시 빌드해야 한다면, 프로젝트의 pyproject.toml에 다음을 추가한다:

pyproject.toml
[tool.uv]
cache-keys = [{ git = { commit = true } }]

동적 메타데이터가 Git 태그 세트에서 정보를 가져오는 경우, 캐시 키에 태그를 포함하도록 확장할 수 있다:

pyproject.toml
[tool.uv]
cache-keys = [{ git = { commit = true, tags = true } }]

마찬가지로, 프로젝트가 requirements.txt에서 의존성을 읽어 오는 경우, 프로젝트의 pyproject.toml에 다음을 추가한다:

pyproject.toml
[tool.uv]
cache-keys = [{ file = "requirements.txt" }]

glob 크레이트의 구문을 따르는 글로브(glob)도 지원된다. 예를 들어, 프로젝트 디렉토리나 하위 디렉토리의 .toml 파일이 수정될 때마다 캐시를 무효화하려면 다음을 사용한다:

pyproject.toml
[tool.uv]
cache-keys = [{ file = "**/*.toml" }]

Note

글로브 사용은 비용이 많이 들 수 있다. uv는 파일 시스템을 탐색하여 변경된 파일이 있는지 확인해야 하기 때문이다. 이는 크거나 깊게 중첩된 디렉토리를 탐색해야 할 수도 있다.

마찬가지로, 프로젝트가 환경 변수에 의존하는 경우, 환경 변수가 변경될 때마다 캐시를 무효화하려면 프로젝트의 pyproject.toml에 다음을 추가한다:

pyproject.toml
[tool.uv]
cache-keys = [{ env = "MY_ENV_VAR" }]

만약 tool.uv.cache-keys로 커버되지 않는 dynamic 메타데이터를 사용하는 프로젝트가 있다면, tool.uv.reinstall-package 목록에 프로젝트를 추가하여 uv가 항상 다시 빌드하고 재설치하도록 지시할 수 있다:

pyproject.toml
[tool.uv]
reinstall-package = ["my-package"]

이렇게 하면 패키지의 pyproject.toml, setup.py, 또는 setup.cfg 파일이 변경되었는지 여부와 상관없이 uv는 매번 my-package를 다시 빌드하고 재설치한다.

캐시 안전성

동일한 가상 환경을 대상으로 여러 uv 커맨드를 동시에 실행해도 안전하다. uv의 캐시는 스레드 안전성을 보장하고, 추가 전용(append-only) 방식으로 설계되어 다중 동시 읽기/쓰기에 강력하다. uv는 설치 시 대상 가상 환경에 파일 기반 잠금을 적용하여 프로세스 간 동시 수정을 방지한다.

단, 다른 uv 커맨드가 실행 중일 때 uv 캐시를 수정하는 것(예: uv cache clean)은 안전하지 않다. 또한 캐시를 직접 수정하는 것(예: 파일이나 디렉토리 삭제)은 절대 안전하지 않다.

캐시 정리

uv는 캐시에서 엔트리를 제거하는 몇 가지 방법을 제공한다:

  • uv cache clean은 캐시 디렉토리의 모든 엔트리를 제거해 캐시를 완전히 비운다.
  • uv cache clean ruffruff 패키지와 관련된 모든 캐시 엔트리를 제거한다. 특정 패키지나 제한된 패키지 집합의 캐시를 무효화할 때 유용하다.
  • uv cache prune사용되지 않는 모든 캐시 엔트리를 제거한다. 예를 들어, 캐시 디렉토리에는 이전 uv 버전에서 생성되었지만 더 이상 필요하지 않은 엔트리가 포함될 수 있다. uv cache prune은 주기적으로 실행해 캐시 디렉토리를 깔끔하게 유지하는 데 안전하게 사용할 수 있다.

지속적 통합 환경에서의 캐싱

GitHub Actions나 GitLab CI 같은 지속적 통합 환경에서는 패키지 설치 결과물을 캐싱해 이후 실행 속도를 높이는 것이 일반적이다.

기본적으로 uv는 소스에서 빌드한 휠과 직접 다운로드한 사전 빌드 휠을 모두 캐싱해 고성능 패키지 설치를 가능하게 한다.

하지만 지속적 통합 환경에서는 사전 빌드 휠을 유지하는 것이 바람직하지 않을 수 있다. uv를 사용할 때, 사전 빌드 휠을 캐시에서 제외하고 매번 레지스트리에서 다시 다운로드하는 것이 더 빠른 경우가 많다. 반면, 소스에서 빌드한 휠은 캐싱하는 것이 유용한데, 특히 확장 모듈의 경우 휠 빌드 과정이 비용이 많이 들기 때문이다.

이런 캐싱 전략을 지원하기 위해 uv는 uv cache prune --ci 커맨드를 제공한다. 이 커맨드는 캐시에서 모든 사전 빌드 휠과 압축 해제된 소스 배포판을 제거하지만, 소스에서 빌드된 휠은 유지한다. 최대 캐시 효율성을 보장하려면 지속적 통합 작업이 끝날 때 uv cache prune --ci를 실행하는 것을 권장한다. 예시는 GitHub 통합 가이드를 참고한다.

캐시 디렉터리

uv는 다음 순서에 따라 캐시 디렉터리를 결정한다:

  1. --no-cache 옵션을 지정한 경우, 임시 캐시 디렉터리를 사용한다.
  2. --cache-dir, UV_CACHE_DIR, 또는 tool.uv.cache-dir을 통해 특정 캐시 디렉터리를 지정한다.
  3. 시스템에 적합한 캐시 디렉터리를 사용한다. 예를 들어 Unix에서는 $XDG_CACHE_HOME/uv 또는 $HOME/.cache/uv, Windows에서는 %LOCALAPPDATA%\uv\cache를 사용한다.

Note

uv는 항상 캐시 디렉터리가 필요하다. --no-cache를 지정하더라도, uv는 해당 실행 내에서 데이터를 공유하기 위해 임시 캐시를 사용한다.

대부분의 경우 --no-cache 대신 --refresh를 사용해야 한다. --refresh는 캐시를 업데이트하지만 캐시에서 읽지는 않기 때문에 후속 작업에 유리하다.

캐시 디렉터리는 uv가 작업 중인 Python 환경과 동일한 파일 시스템에 위치해야 성능에 유리하다. 그렇지 않으면 uv는 캐시에서 환경으로 파일을 링크하지 못하고 느린 복사 작업으로 대체해야 한다.

캐시 버전 관리

uv 캐시는 여러 버킷으로 구성된다. 예를 들어, 휠 파일용 버킷, 소스 배포판용 버킷, Git 저장소용 버킷 등이 있다. 각 버킷은 버전이 지정되어 있어, 릴리스에서 캐시 형식에 호환되지 않는 변경이 있을 경우 uv는 해당 버킷을 읽거나 쓰지 않는다.

예를 들어, uv 0.4.13에서는 코어 메타데이터 버킷에 호환되지 않는 변경이 포함되었다. 이에 따라 버킷 버전이 v12에서 v13으로 증가했다. 캐시 버전 내에서는 변경 사항이 앞뒤로 호환되도록 보장된다.

캐시 형식의 변경은 캐시 버전의 변경과 함께 이루어지므로, 여러 버전의 uv가 동일한 캐시 디렉터리를 안전하게 읽고 쓸 수 있다. 그러나 특정 uv 릴리스 간에 캐시 버전이 변경된 경우, 해당 릴리스는 동일한 기본 캐시 항목을 공유하지 못할 수 있다.

예를 들어, uv 0.4.12와 uv 0.4.13은 단일 공유 캐시를 사용해도 안전하지만, 캐시 버전 변경으로 인해 코어 메타데이터 버킷에 중복 항목이 포함될 수 있다.