개발

버전을 고정했더니 CI 가 깨졌다 — freeze 한 파이썬이 배포와 다르면


재현 가능한 빌드를 만들려고 의존성 버전을 전부 고정했다. requirements.txt 를 == 로 박고, 로컬에서 잘 도는 걸 확인한 뒤 올렸다. 그런데 CI 가 이렇게 실패했다.

ERROR: Ignored the following versions that require a different python version:
  2.5.0 Requires-Python >=3.12; 2.5.2 Requires-Python >=3.12
ERROR: Could not find a version that satisfies the requirement numpy==2.5.2
ERROR: No matching distribution found for numpy==2.5.2

파일에는 분명히 numpy==2.5.2 라고 적혀 있는데, 그 버전을 못 찾는다고 한다.

원인

numpy 는 2.5 부터 파이썬 3.12 이상만 지원한다.

내 개발 기계는 파이썬 3.14 였다. 거기서 설치된 numpy 2.5.2 를 그대로 고정했다. 그런데 배포와 CI 는 파이썬 3.11 이다. 3.11 에는 numpy 2.5 휠이 아예 없다. 그래서 설치 단계에서 멈춘다.

[로컬 3.14]   freeze  →  numpy==2.5.2 가 박힌다
[배포 3.11]   설치     →  2.5.x 는 3.12+ 전용, 설치 불가

로컬만 3.14 라 로컬에선 멀쩡했다. 문제는 배포 환경에서만 드러났다. 고정 파일이 잘못된 게 아니라, 잘못된 환경에서 고정한 것이다.

도구도 같은 함정에 빠진다

의존성 취약점을 점검하는 pip-audit 를 돌렸더니 똑같은 에러로 감사가 시작조차 안 됐다.

pip-audit -r requirements.txt
# → No matching distribution found for numpy==2.5.2

이 도구는 임시 가상환경을 만들어 requirements 를 설치해 본 뒤 감사한다. 그 가상환경의 파이썬이 3.11 이면, 역시 numpy 2.5 를 못 깔아 설치 단계에서 넘어진다.

즉 도구를 프로젝트와 다른 파이썬으로 돌리면, 도구가 배포 환경을 흉내 내지 못한다. 프로젝트 파이썬으로 돌려야 한다.

# 프로젝트 파이썬으로 실행
./.venv/Scripts/python -m pip_audit -r requirements.txt

확인

각 패키지가 어떤 파이썬을 요구하는지 보면 바로 드러난다.

import json, urllib.request
d = json.load(urllib.request.urlopen('https://pypi.org/pypi/numpy/2.5.2/json'))
print(d['info']['requires_python'])   # >=3.12

2.4.6 은 >=3.11, 2.5.2 는 >=3.12. 배포가 3.11 이면 2.4.x 가 마지막 호환 버전이다.

해결

배포에서 설치되는 버전으로 내렸다.

numpy==2.4.6   # 3.11+ 전용. 2.5.x 는 3.12+ 라 배포(3.11)에서 설치 불가

더 근본적으로는, 고정 파일을 배포와 같은 파이썬에서 만드는 것이다. 개발 기계에서 freeze 하지 말고, 배포와 같은 버전의 컨테이너 안에서 고정하면 이 어긋남이 애초에 생기지 않는다.

자동 갱신 봇이 되돌린다

의존성을 자동으로 올리는 봇은 배포가 3.11 인 걸 모른다. numpy 를 최신 2.5.x 로 올리는 요청을 계속 연다. 그 요청의 CI 는 매번 같은 이유로 빨간불이다.

봇에 상한을 알려 준다.

ignore:
  # numpy 2.5+ 는 3.12+ 전용. 배포가 3.11 이라 상향 요청은 통과 못 한다.
  - dependency-name: "numpy"
    versions: [">=2.5.0"]

파이썬을 3.12 이상으로 올리기로 하면, 그때 이 규칙을 지운다.

정리

  • pip freeze 로 만든 고정은 그 기계의 파이썬에 묶인다. 개발 기계가 배포보다 최신이면, 배포에서 안 깔리는 버전이 박힐 수 있다
  • 고정 파일은 배포와 같은 파이썬 환경에서 만든다
  • 취약점 점검 같은 도구도 프로젝트 파이썬으로 돌려야 배포 환경을 재현한다
  • 자동 갱신 봇에는 배포 환경과 맞지 않는 상향을 무시하도록 상한을 건다

버전을 고정할 땐 “무엇을 고정했나” 보다 “어디서 고정했나” 를 먼저 본다. 개발 기계는 배포보다 앞서 있는 경우가 많고, 그 차이는 로컬에서 끝까지 보이지 않는다.

댓글