해결)ImportError: attempted relative import with no known parent package

작성자: [관리자] 하얀설표

2024.11.17 17:51 (KST) 작성됨

2024.11.17 17:52 (KST) 수정됨






(2024.11.17) 수정됨.

에러

ImportError: attempted relative import with no known parent package

 

해결방법

환경변수에 추가되지 않은 위치에서 상대경로로 import를 시도하기 때문에 발생하는 에러다.
코드 실행시 환경변수에 적절한 경로가 추가되어 있어야 문제를 해결할 수 있다.

 

설명

샘플 경로

custompackage/
  |- __init__.py
  |- a.py
  |- b.py
  |- c.py

 

샘플 코드

샘플 코드라 별 내용이 없기 때문에 3개 파일의 내용을 한 번에 소개한다.

# a.py
def aa(): print('print aa')

# b.py
def bb(): print('print bb')

# c.py
from .a import aa
from .b import bb

aa()
bb()

 

__init__.py 는 파이썬 패키지임을 알리기 위한 빈 파일이고, a.py와 b.py는 각각 print 작업을 하는 함수를 1개씩 가지고 있다.

또한 a.py와 b.py의 함수를 불러와 실행하는 c.py를 실행하면 다음과 같이 에러가 발생하게 될텐데, 에러가 발생하는 이유는 환경변수에 추가되지 않은 경로에 직접 제작한 코드가 위치하기 때문이다.

Traceback (most recent call last):
  File "c:\seolpyo\custompackage\c.py", line 1, in <module>        
    from .a import aa
ImportError: attempted relative import with no known parent package

 

가장 간단한 방법은 OS의 환경변수에 자신이 작성한 코드가 위치하는 폴더 경로를 추가하는 것이다.

그러나 매번 환경변수를 추가하는 것도 귀찮기 때문에.. 다른 방법을 통해 파이썬 코드에서 알아서 자신의 경로를 추가한 다음 코드를 실행하게 만드는 것도 가능하다.

 

파이썬 코드가 알아서 자신의 경로를 추가하도록 하는 방법

 

파이썬에 기본으로 내장된 sys와 pathlib 패키지를 활용하는 것으로 문제 해결이 가능하다.

다음과 같이 4줄의 코드를 추가한 다음, 작성한 패키지를 상대경로가 아닌 from {package 폴더명}.{코드} import {함수} 형식으로 변경한 다음, 코드를 실행해보면 다음과 같이 정상 작동하는 것을 확인할 수 있다.

import sys # sys import 
from pathlib import Path # Path import 
path_dir = Path(__file__) # 현재 파일 경로 가져오기
while path_dir.name != 'custompackage': path_dir = path_dir.parent # 임의로 작성한 코드의 최상단 폴더 경로 가져오기
sys.path.append(path_dir.parent.__str__()) # 폴더의 부모 경로를 sys.path에 추가

from custompackage.a import aa # from {코드 위치 폴더명}.{코드 파일명} import {함수명}
from custompackage.b import bb

aa()
bb()

=> print aa
print bb

 

__str__() 명령을 사용하는 이유

이유는 간단한데, sys.path는 str object가 담겨있는 list이기 때문이다.
pathlib.Path를 사용하면  WindowsPath('c:/seolpyo')와 같은 class가 list에 들어가게 되는데, 이렇게 된 경우 경로 추가가 되지 않아 패키지를 import하지 못한다.

import sys
from pathlib import Path
path_dir = Path(__file__)
while path_dir.name != 'custompackage': path_dir = path_dir.parent
sys.path.append(path_dir.parent)
print(f'{sys.path=}')

from custompackage.a import aa
from custompackage.b import bb

aa()
bb()
=> sys.path=['c:\\seolpyo\\custompackage', 'C:\\Program Files\\Python312\\python312.zip', 'C:\\Program Files\\Python312\\DLLs', 'C:\\Program Files\\Python312\\Lib', 'C:\\Program Files\\Python312', 'C:\\seolpyo\\django5.0', 'C:\\seolpyo\\django5.0\\Lib\\site-packages', WindowsPath('c:/seolpyo')]
Traceback (most recent call last):
  File "c:\seolpyo\custompackage\c.py", line 8, in <module>
    from custompackage.a import aa
ModuleNotFoundError: No module named 'custompackage'

 

폴더가 아닌 폴더의 상위 경로를 추가하는 이유

다음과 같이 sys.path.append 작어베서 path_dir.parent가 아닌 path_dir을 추가하면 되지 않을까 생각이 드는게 당연하다.
그러나 다은과 같이 시도하면 마찬가지로 attempted relative import with no known parent package 에러가 발생한다.

import sys
from pathlib import Path
path_dir = Path(__file__)
while path_dir.name != 'custompackage': path_dir = path_dir.parent
sys.path.append(path_dir.__str__())

from .a import aa
from .b import bb

aa()
bb()

=> Traceback (most recent call last):
  File "c:\seolpyo\custompackage\c.py", line 7, in <module>
    from .a import aa
ImportError: attempted relative import with no known parent package

 

 






추천 (0)


글 목록

댓글을 달 수 없는 게시물입니다.


"분류없음" 카테고리의 #Python, #에러해결 관련 게시물