Published on

pip install은 성공인데 실행하면 ModuleNotFoundError가 뜰 때 venv poetry conda 혼용으로 꼬인 인터프리터와 site-packages를 10분 만에 진단하고 확실히 고치는 체크리스트

Authors

서론

pip install requests는 분명 성공했는데, 막상 python app.py를 실행하면 ModuleNotFoundError: No module named 'requests'가 터지는 상황은 현업에서 정말 자주 나옵니다. 특히 로컬 개발 환경에서 venv, poetry, conda, pyenv, IDE(예: VSCode/PyCharm)까지 섞이면 “설치한 파이썬”과 “실행하는 파이썬”이 서로 달라지는 순간이 생깁니다.

이 글은 원인 분석을 길게 늘어놓기보다, 10분 안에 인터프리터와 site-packages 경로를 확정적으로 맞추는 체크리스트를 제공합니다. 핵심은 단 하나입니다.

  • pip가 설치한 환경python이 실행되는 환경이 같아야 한다.

증상 패턴: 설치는 되는데 import가 안 되는 전형적 시나리오

다음 중 하나라도 해당되면 거의 90%는 “환경 불일치”입니다.

  • pip install은 성공 로그가 뜨는데, 실행하면 ModuleNotFoundError
  • pip show 패키지는 나오는데 python -c "import 패키지"는 실패
  • 터미널에서는 되는데 VSCode/PyCharm에서만 실패(또는 반대)
  • poetry add로는 설치했는데 python app.py는 실패
  • conda activate myenv 했는데도 import가 안 됨

0분~2분: 가장 먼저 확인할 3줄(이게 끝인 경우가 많음)

아래 3개를 같은 터미널 세션에서 연속으로 실행하세요.

which python
python -V
python -m pip -V

해석 방법

  • which python이 가리키는 경로가 내가 의도한 가상환경/conda env의 python인지 확인
  • python -m pip -V 출력 예:
    • pip 24.x from /.../site-packages/pip (python 3.11)
    • 여기서 from /.../site-packages 경로가 현재 python의 site-packages여야 합니다.

> 결론: pip 단독 실행(pip install ...)은 믿지 마세요. 항상 **python -m pip**로 고정하면 “pip는 A에 설치, python은 B 실행” 사고를 크게 줄입니다.


2분~5분: 실행 중인 인터프리터와 sys.path를 눈으로 확정하기

프로젝트 루트에 env_check.py를 만들고 실행합니다.

# env_check.py
import sys
import site
import platform

print("=== interpreter ===")
print(sys.executable)
print(platform.python_version())

print("\n=== sys.path (top 10) ===")
for p in sys.path[:10]:
    print(p)

print("\n=== site-packages ===")
for p in site.getsitepackages():
    print(p)

print("\n=== user site ===")
print(site.getusersitepackages())
python env_check.py

여기서 봐야 할 포인트

  • sys.executable내가 생각한 python이 맞는가?
  • site.getsitepackages()에 찍힌 경로에 설치된 패키지가 있어야 합니다.
  • ~/.local/lib/pythonX.Y/site-packages(user site)가 섞이면, “어디에 설치됐는지”가 더 헷갈릴 수 있습니다.

5분~7분: venv/poetry/conda 혼용에서 자주 터지는 원인 7가지

1) pip가 다른 파이썬의 pip였다

가장 흔합니다.

  • (실수) pip install foo
  • (정답) python -m pip install foo

즉시 교정:

python -m pip install -U pip
python -m pip install foo
python -c "import foo; print(foo.__file__)"

2) conda activate를 했는데도 which python이 conda가 아니다

conda 초기화가 쉘에 제대로 반영되지 않으면 이런 일이 생깁니다.

conda info --envs
conda activate myenv
which python
python -m pip -V
  • which python/opt/homebrew/... 또는 ~/.pyenv/...를 가리키면 이미 꼬였습니다.
  • 해결은 보통 conda init zsh(또는 bash) 후 쉘 재시작.

3) poetry 프로젝트인데 poetry run 없이 시스템 python으로 실행했다

poetry는 가상환경을 별도로 만들고 관리합니다.

  • (실수) python app.py
  • (정답) poetry run python app.py

환경 확인:

poetry env info
poetry run which python
poetry run python -m pip -V

4) venv를 만들었지만 활성화가 안 된 상태에서 설치/실행했다

  • (실수) python -m venv .venv만 해놓고 activation을 안 함
# macOS/Linux
source .venv/bin/activate
which python
python -m pip -V

# Windows PowerShell
.\.venv\Scripts\Activate.ps1

5) VSCode 인터프리터가 터미널과 다르다

터미널에서 해결했는데 VSCode에서만 ModuleNotFoundError가 계속 나면 거의 이 케이스입니다.

  • VSCode Command Palette → Python: Select Interpreter
  • .venv/bin/python 또는 poetry env python을 명시적으로 선택

추가로, VSCode 터미널이 로그인 쉘이 아니라서 conda/pyenv init이 적용 안 되는 경우도 있습니다.

6) --user 설치가 섞여서 import 경로가 달라졌다

예: pip install --user foo로 설치하면 user site로 들어가고, 어떤 환경에서는 user site가 sys.path에 안 들어옵니다.

python -m pip show foo
python -c "import site; print(site.getusersitepackages())"

7) 프로젝트 내부에 패키지 이름과 같은 파일/폴더가 있어서 shadowing

예를 들어 requests.py 파일이 프로젝트에 있으면 import requests가 외부 패키지 대신 로컬 파일을 잡을 수 있습니다.

python -c "import requests; print(requests.__file__)"

7분~10분: 확실히 고치는 방법(상황별 처방전)

여기부터는 “진단”이 끝났다는 가정 하에, 가장 안전하고 재발이 적은 고정 방법을 제시합니다.

1) venv 기반으로 통일(가장 단순하고 범용)

# 1) 기존 꼬인 환경이 있으면 제거(프로젝트 로컬 venv만)
rm -rf .venv

# 2) 새로 생성
python -m venv .venv

# 3) 활성화
source .venv/bin/activate

# 4) pip는 반드시 python -m pip로
python -m pip install -U pip
python -m pip install -r requirements.txt

# 5) 검증
python -c "import pkgutil; print('ok')"
python -c "import requests; print(requests.__version__)"

Best Practice

  • 팀 규칙으로 pip 대신 python -m pip 사용을 강제(문서/스크립트에 반영)
  • requirements.txtpip freeze로만 관리하지 말고, 상위 의존성/하위 의존성 정책을 정해 운영

2) poetry로 통일(의존성/락 파일이 중요한 팀에 추천)

# 가상환경 위치를 프로젝트 안으로 고정(가시성↑)
poetry config virtualenvs.in-project true

# 새 환경 구성
poetry install

# 실행은 항상 poetry run
poetry run python -c "import requests; print(requests.__version__)"
poetry run python app.py

자주 하는 실수 방지

  • README에 실행 커맨드를 python app.py로 써두면 100% 사고 납니다.
  • 반드시 poetry run ... 또는 poetry shell 기반으로 안내하세요.

3) conda로 통일(과학/ML 스택, OS별 바이너리 의존성 많을 때)

conda create -n myenv python=3.11 -y
conda activate myenv

# pip를 쓰더라도 conda env 안에서 python -m pip로
python -m pip install -r requirements.txt

python -c "import numpy; print(numpy.__version__)"

  • conda 패키지와 pip 패키지를 섞을 때 충돌이 날 수 있으니, 가능하면 conda-forge 우선 전략을 정하세요.

트러블슈팅: 그래도 안 될 때 바로 먹히는 강력한 확인 커맨드

1) 특정 모듈이 “어디에 설치됐는지” 파일 경로로 확정

python -c "import importlib.util; spec=importlib.util.find_spec('requests'); print(spec.origin if spec else 'NOT FOUND')"
  • NOT FOUND면 현재 인터프리터 sys.path 어디에도 없습니다.
  • 경로가 나오면, 그 경로가 기대한 venv/conda/poetry 아래인지 확인하세요.

2) pip가 설치한 파일 목록 확인

python -m pip show -f requests

3) 실행 커맨드 자체를 고정(쉘 alias/스크립트)

예: make run으로 통일하면 사람마다 다른 커맨드로 실행하는 사고가 줄어듭니다.

# Makefile
run:
	poetry run python app.py

check-env:
	poetry run python env_check.py

재발 방지 체크리스트(팀 운영 관점)

  1. 프로젝트가 선택한 단 하나의 환경 도구를 README 첫 줄에 명시(venv/poetry/conda 중 택1)
  2. 모든 설치 문서에서 pip install 대신 python -m pip install 사용
  3. VSCode 사용 팀이면 .vscode/settings.json에 인터프리터 경로를 프로젝트 기준으로 고정
  4. CI에서 python -c "import ..." 스모크 테스트를 넣어 “설치 성공/실행 실패”를 조기에 차단
  5. 패키지 import가 느려져서 장애/지연으로 이어지는 케이스도 있으니, 배포 환경에서는 import 비용을 측정/최적화하는 습관을 들이세요. 예를 들어 서버리스에서는 import 병목이 곧 콜드 스타트로 직결됩니다: AWS Lambda Python 콜드 스타트가 갑자기 2~5초로 늘어날 때 컨테이너 이미지 레이어 의존성 import 병목과 Provisioned Concurrency로 80% 줄이는 실전 가이드

추가로, 비동기 서비스에서 환경 꼬임으로 특정 모듈 import가 실패하면 태스크 정리/종료 시점에 이상한 경고가 연쇄적으로 보일 때가 있습니다. 그런 경우 아래 글의 “종료/취소 처리” 체크도 함께 보면 디버깅 시간이 줄어듭니다: Python asyncio Task was destroyed but it is pending 경고 원인 5가지와 완벽 해결법


결론

pip install이 성공했는데 ModuleNotFoundError가 뜨는 문제는 대부분 설치한 인터프리터와 실행하는 인터프리터가 다르기 때문입니다. 해결은 어렵지 않습니다.

  • 1단계: which python, python -m pip -V, sys.executable실행 주체를 확정
  • 2단계: venv/poetry/conda 중 하나로 통일하고 실행 커맨드를 고정
  • 3단계: 팀 문서/CI/IDE 설정으로 재발을 구조적으로 차단

지금 바로 터미널을 열고 python -m pip -V를 실행해 보세요. 출력된 site-packages 경로가 “내가 믿고 있는 환경”과 다르다면, 이 글의 체크리스트대로 10분 안에 깔끔하게 정상화할 수 있습니다.