파이썬 import에서 상대 경로, 절대 경로에 의한 참조 알고 있다고 가정한다.
해당 글은 vscode에서 다른 디렉토리의 모듈을 불러올 때 sys.append()을 사용하기 싫은데 참조할만한 글이 sys.append()를 사용하는 경우만 있었던 상황을 위해 작성한 글이다.
문제상황
결론부터 얘기하자면, pycharm에서 모듈참조를 할 때 절대 경로로 참조를 하면 문제가 생기지 않는다. 하지만 vscode에서 참조를 할 때는 문제가 발생하는데, 이는 vscode에서 자동으로 PYTHONPATH에 실행할 workspacefoler의 경로를 추가해주지 않기 때문이다. (실행되는 .py파일이 디렉토리의 최상단 구조라면 문제는 발생하지 않는다.)
파이썬에서 import문을 통해 다른 모듈을 불러올 때 내부적으로 파일을 찾기 위해 파일을 탐색하는 순서는 다음과 같다.
- sys.modules
- built-in modules
- sys.path
PYTHONPATH 환경 변수에 경로를 추가하면, 파이썬은 내부적으로 PYTHONPATH에 등록된 경로들을 sys.path에 추가해준다. 즉, sys.append()코드를 사용하여 모듈을 불러올 위치를 load하는 것으로 자동으로 sys.append()를 해주는 효과를 볼 수 있다.
문제 상황 재현
ddpm/ 디렉토리에 존재하는 import_test.py에서 dataset_class/ 디렉토리의 duke_dataset.py 모듈에 접근할 때 ModuleNotFoundError 오류가 발생한다.
전체 디렉토리 구조는 다음과 같다.
/workspace/Model_Implementation
|-- CNN/
| |-- Lenet/
| | |-- model.py
| | `-- train.py
| `-- Resnet18/
| |-- DukeClassification/
| | |-- dataset/
| | | `-- duke_breast_ataset.py
| | |-- model/
| | | `-- Resnet18.py
| | `-- train/
| | `-- train.py
| `-- ResNet18_cifar10.ipynb
|-- DataHandling/
| `-- mnist_handling/
| `-- mnist_handling.ipynb
|-- GenerativeModel/
| |-- __init__.py
| |-- __pycache__/
| | `-- __init__.cpython-39.pyc
| |-- dataset_class/
| | |-- __pycache__/
| | | `-- duke_dataset.cpython-39.pyc
| | |-- duke_dataset.py
| | `-- rsna_breast_cancer.py
| |-- ddpm/
| | |-- import_test.py
| | |-- lucidrains/
| | | |-- attend.py
| | | |-- ddpm_lucidrains.py
| | | |-- fid_evaluation.py
| | | |-- train.py
| | | `-- version.py
| | |-- origin_ddpm/
| | | |-- ddpm.py
| | | |-- ddpm_for_breast.py
| | | |-- ddpm_for_flower102.py
| | | `-- sampling_test.py
| | `-- simple_diffusion/
| | |-- __init__.py
| | |-- simple_diffusion.ipynb
| | `-- simple_diffusion.py
| `-- normalize_test.py
|-- README.md
|-- Segmentation/
| `-- Unet/
| |-- data_read.py
| `-- unet.py
|-- __init__.py
`-- __pycache__/
`-- __init__.cpython-39.pyc
import_test.py
from Model_Implementation.GenerativeModel.dataset_class.duke_dataset import DukeDataset
dataset = DukeDataset()
import_test.py에서 코드를 실행하면 Model_Implementation 모듈이 존재하지 않다는 에러가 발생한다.
ModuleNotFoundError: No module named 'Model_Implementation'
PYTHONPATH를 사용하지 않았을 때 sys.path 출력 결과
root@39b243c21098:/workspace# /usr/bin/python /workspace/Model_Implementation/GenerativeModel/ddpm/import_test.py
['/workspace/Model_Implementation/GenerativeModel/ddpm', '/opt/conda/lib/python39.zip',
'/opt/conda/lib/python3.9', '/opt/conda/lib/python3.9/lib-dynload',
'/opt/conda/lib/python3.9/site-packages']
파이썬은 실행되는 파일의 위치를 sys.path에 추가하는데, 이 경우에서는 import_test.py가 실행되는 위치는 ddpm/ 디렉토리에 있기에 sys.path에는 '/workspace/Model_Implementation/GenerativeModel/ddpm' 가 추가되어있는 것을 확인할 수 있다. 그러나, 보다시피 /workspace/Model_Implementation/ 디렉토리는 sys.path에 존재하지 않으므로 모듈을 찾을 수 없는 상황이 발생하는 것이다.
sys.path의 첫 번째 값은 최초 실행시킨 스크립트가 위치한 디렉터리이다.
해결 방법
터미널에서 .py 파일 실행을 하는 경우
코드를 터미널에서 실행하는 경우는 vscode의 settings.json 파일에 해당 라인을 추가하면 된다.
settings.json은 ctrl + shift + p를 통해 진입할 수 있다.
settings.json파일에는 다음과 같이 내용을 작성한다.
{
"terminal.integrated.env.linux": {"PYTHONPATH": "${workspaceFolder}"}
}
이제 다시 sys.path를 print해보면 다음과 같다.
[
'/workspace/Model_Implementation/GenerativeModel/ddpm',
'/workspace', '/opt/conda/lib/python39.zip',
'/opt/conda/lib/python3.9',
'/opt/conda/lib/python3.9/lib-dynload',
'/opt/conda/lib/python3.9/site-packages'
]
/workspace가 경로에 추가된 것을 확인할 수 있다. 즉, VScode에서 $workspacefolder는 내가 디렉토리의 시작지점을 /workspace로 지정했던 것을 자동으로 찾아 PYTHONPATH에 추가하여 /workspace가 sys.path에 추가된 모습이다.
만약, 위처럼 settings.json을 입력했는데 잘 안된다면
이처럼 VScode로 관뢰되는 프로젝트의 폴더를 workspace로 따로 저장해서 들어가는지 확인을 할 필요가 있다. 만약 이와 같이 관리되는 프로젝트라면, 아래와 같은 절차를 따른다.
- 위 이미지처럼 'ctrl + ,' 를 입력하여 settings에 들어온다음 `terminal.integrated.env`를 검색해서 살펴보자.
- 그러면 각자 운영체제에 맞는 세팅을 Edit in settings.json을 눌러 할 수 있을 것이다.
따로 저장하여 관리되는 workspace의 json형태이다. 따로 worksapce를 저장하여 사용할 시, settings.json과 launch.json을 한 파일에서 관리하는 형태의 JSON이 나오게된다. 이 형태에 익숙하지 않다면, `ctrl + ,` 를 눌러서 Edit in settings.json을 누르는 것이 마음 편하다.
{
"folders": [
{
"path": "../프로젝트 이름",
}
],
"settings": {
"terminal.integrated.profiles.windows": {
"PowerShell": {
"source": "PowerShell",
"icon": "terminal-powershell",
},
"Command Prompt": {
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
],
"args": [],
"icon": "terminal-cmd"
},
"Git Bash": {
"source": "Git Bash"
},
},
"terminal.integrated.env.windows": {
"PYTHONPATH": "${workspaceFolder}"
}
},
"launch": {
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${fileDirname}",
"env": {"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"}
}
]
}
}
디버깅으로 .py 파일을 실행하는 경우
해당 경우에는 settings.json 파일의 내용을 공유하지 않기에 디버깅에서도 모듈의 위치를 올바르기 인식하려면 launch.json에 내용을 작성해야 한다.
위 이미지의 어떤 방법을 사용하던 디버깅으로 접근된다. 2번 이미지의 debug 탭은 launch.json을 생성하지 않았다면, 해당 이미지처럼 생기지 않았을 수 있다.
launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true,
"cwd": "${fileDirname}",
"env": {"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"}
}
]
}
참고자료
https://stackoverflow.com/questions/53653083/how-to-correctly-set-pythonpath-for-visual-studio-code
'Editor > Visual Studio Code' 카테고리의 다른 글
[VScode] venv 가상환경에서 pylint 사용하는 방법 (0) | 2024.03.01 |
---|---|
[VScode] Python Venv 경로 설정 옵션 (venvFolders, venvPath) (0) | 2024.03.01 |