Python 3.12로 올렸더니 ModuleNotFoundError: No module named 'distutils'가 난 이유
문제 발생
Python 3.11에서 문제없던 빌드 스크립트가 3.12에서 첫 줄부터 죽었습니다. 우리 코드에는 distutils가 없었고, 오래된 의존성 하나가 내부에서 쓰고 있었습니다.
ModuleNotFoundError: No module named 'distutils'원인 분석
두 가지 변경이 겹쳤습니다.
첫째, distutils가 3.12에서 표준 라이브러리에서 제거됐습니다. PEP 632로 예고된 일이고, 3.10부터 경고가 나오고 있었습니다. 같은 릴리스에서 asynchat, asyncore, imp도 함께 사라졌습니다 — imp는 오래된 플러그인 로더에서 아직 흔히 보입니다.
둘째, venv가 더 이상 setuptools를 기본 설치하지 않습니다. 이게 문제를 헷갈리게 만듭니다. setuptools는 자체적으로 distutils를 제공하므로, 예전에는 가상환경만 만들면 setuptools가 딸려오고 그 안의 distutils가 import돼서 표준 라이브러리에서 빠진 뒤에도 한동안 동작하는 것처럼 보였습니다. 3.12에서는 그 우연한 안전망까지 없어져 두 변경이 동시에 드러납니다. pkg_resources, easy_install도 같은 이유로 사라집니다.
해결 방안
- 어디서 쓰는지부터 찾습니다. 우리 코드가 아니라 의존성일 확률이 높습니다.
grep -rn "import distutils\|from distutils" .
python -X importtime -c "import your_package" 2>&1 | grep distutils- 표준 대체재로 옮깁니다. 대부분 한 줄 치환입니다.
| 예전 | 대체 |
|---|---|
distutils.version.LooseVersion | packaging.version.Version |
distutils.spawn.find_executable | shutil.which |
distutils.dir_util.copy_tree | shutil.copytree(dirs_exist_ok=True) |
distutils.util.strtobool | 직접 구현(값 목록이 짧습니다) |
imp | importlib |
- 당장 급하면
setuptools를 명시적으로 설치합니다. 임시방편입니다 —setuptools가 제공하는distutils셰임도 영구적이지 않습니다.
pip install setuptools- CI에서 경고를 에러로 올려 미리 잡습니다. 3.10~3.11 시절에
DeprecationWarning으로 나오던 것이 3.12에서ModuleNotFoundError가 된 것이므로, 경고를 무시하지 않았다면 미리 알 수 있었습니다.
python -W error::DeprecationWarning -m pytest- 가상환경이 예전과 다르다는 것을 문서에 적어둡니다.
python -m venv로 만든 환경에pip만 있고setuptools가 없다는 사실은, 팀에서 한 번은 반드시 누군가를 붙잡습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.