프로그래밍/Python

CLI로 Python 실행시 No module named 오류 해결방법

Lou Park 2022. 6. 6. 15:32

# ModuleNotFoundError

PyCharm같은 통합개발환경(IDE)에서 편하게 개발할때는 이슈가 없었는데, VS code로 docker에 띄울 배치 스크립트를 개발하던 중 문제가 생겼다. 가상환경(Virtual Environment)을 구성하여 활성화시키고, 실행시켰는데 모듈을 찾을 수 없다는 것이다.

python .\my_game\batch1.py
Traceback (most recent call last):
  File "C:\Users\ASUS\PycharmProjects\RankingServer\batch\my_game\batch1.py", line 6, in <module>
    from libs.task.TaskManager import TaskManager
ModuleNotFoundError: No module named 'libs.task'

 

프로젝트 구조는 다음과 같았다. 상위 폴더의 모듈을 어떻게 import할까...검색도 해봤지만 그건 어리석은 방법인것 같고PyCharm에서는되고 그냥 venv 활성화 시켜서 돌리려는데 안되는거니 자세히 찾아보았다.

batch/
├── libs/
│   └── tasks/
│       └── TaskManager.py
└── my_game/
    └── batch1.py

 

# 원인은 PYTHONPATH

PyCharm PYATHONPATH 관련 옵션

Python에서 모듈을 찾을때 PYTHONPATH를 기준으로 탐색하는데, PyCharm에서는 Configurations에 자세히보면 현재 프로젝트 루트를 PYTHONPATH에 자동으로 더해주고 있다. 그래서 libs/tasks를 찾을때 아무런 문제가 없었던 것이다.

 

# PYTHONPATH란 무엇일까?

PYTHONPATH는 환경변수다. Python 개발을 하면서 pip를 통해서 패키지를 다운받기도하지만 여러 모듈을 직접 만들기도한다. 하지만 직접 Installable하게 배포하지는 않고 프로젝트에 PythonPackage로 만들어서 추가하기만하는데, 이때 PYTHONPATH를 기준으로 모듈들을 찾을 수 있게 된다. python3 공식 문서의 표현은 모듈 파일의 기본 검색 경로를 늘린다(Augment the default search path for module files.)라고한다.

 

실행 환경에서 등록되어있는 PYTHONPATH를 출력하려면 sys.path를 이용하면된다.

import sys
print(sys.path)

위 사진처럼 venv 환경안에서 sys.path를 조회해보면 제일 앞에 RankingServer\batch라고 나오는데, 이건 최종적으로 추가 된 것이고 원래는 이게 존재하지 않아 libs/tasks를 찾을 수 없었다. 

 

# PYTHONPATH를 추가해보자

■ 임시 해결책

StackOverFlow를 찾아보면 단기적인 해결책들이 눈에 보인다. 다음처럼 소스코드 가장 위에 sys.path.append로 PYTHONPATH를 추가시켜주는 방법이다. 하지만 추천하지 않는다. 환경변수 추가 한번만 해주면 될 걸 이런식으로 땜빵하려고하면 코드가 얼마나 더러워질까!

sys.path.append(os.path.join(os.getcwd(), ".."))

 

■ 진짜 해결책 : venv activate시에 환경변수 등록

docker 같은 독립적인 환경에서는 python을 오로지 그 프로젝트에만 쓸 수 있다. 그렇다면 컨테이너의 환경 변수에 PYTHONPATH를 등록해도 문제없다. 하지만 여러 python 프로젝트들을 개발하는 내 컴퓨터에...PYTHONPATH를 개발하는 프로젝트마다 추가할 수는 없을 것이다.

 

그래서 virtual environment를 사용하는 것이고, 그 속에서 PYTHONPATH를 추가해주면 깔끔해진다.

venv/
└── Scripts/
    ├── activate
    ├── activate.bat
    ├── Activate.ps1
    └── ...

Windows 컴퓨터를 기준으로 venv 폴더안을 보면 activate 관련 파일들이 저렇게 있는데... activate.bat을 손봐주면 된다.

[activate.bat]
...

if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%

set PATH=%VIRTUAL_ENV%\Scripts;%PATH%

# 이 라인에 내 프로젝트의 root path를 등록
set PYTHONPATH=C:\Users\ASUS\PycharmProjects\RankingServer\batch

:END
if defined _OLD_CODEPAGE (
    "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul
    set _OLD_CODEPAGE=
)

...

중간에 환경변수를 설정하는 부분을 참고하면된다. Powershell을 사용하시는 분들이라면 이렇게 해도 적용이 안될거다. (바로 내가 그 Powershell 쓰는 사람이었기때문에...30분 더 헤맸다) 추가로 Powershell 사용자는 Activate.ps1 파일도 수정해주어야한다.

 

[Activate.ps1]
...
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"

# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive

$env:PYTHONPATH = "C:\Users\ASUS\PycharmProjects\RankingServer\batch"

# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir

...

중간에 $env:PYTHONPATH 부분을 추가해주면된다. 그러고 venv 활성화 시켜주면 아마 될거다.

 

# Docker는요?

WORKDIR /batch

RUN pip3 install -r requirements.txt
COPY . .

ENV PYTHONPATH=/batch

WORKDIR로 설정한 부분을 ENV에 추가만 해주면된다.

 

 

 

참고자료

https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH

https://bic-berkeley.github.io/psych-214-fall-2016/using_pythonpath.html