itsource

__init_.py를 사용하더라도 "비패키지 내 상대 Import 시도"를 수정하는 방법

mycopycode 2022. 9. 11. 18:29
반응형

__init_.py를 사용하더라도 "비패키지 내 상대 Import 시도"를 수정하는 방법

PEP 328을 따르려고 합니다.디렉토리 구조는 다음과 같습니다.

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

»core_test.py과 같은 수입 를 가지고 있습니다.

from ..components.core import GameLoopEvents

다만, 실행시에 다음의 에러가 표시됩니다.

tests$ python core_test.py 
Traceback (most recent call last):
  File "core_test.py", line 3, in <module>
    from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

검색해보니 '_init_.py' 와 '상대 경로에서 모듈 Import' 가 있었는데 도움이 되지 않았습니다.

제가 놓치고 있는 게 있나요?

Ignacio Vazquez-Abrams의 답변에 대해 자세히 설명하겠습니다.

은 Python Import, Python Import에 합니다.__name__현재 파일 중 하나입니다.직접 하면, 그통상의 않고, 「」가 됩니다."__main__"대신 그 이름으로.그래서 상대적인 수입은 효과가 없다.

대로 Igancio를 하여 수 .-m 「」를 사용.__package__해당 파일에 패키지 계층에서 어떤 이름을 가져야 하는지 알려주는 속성입니다.

상세한 것에 대하여는, http://www.python.org/dev/peps/pep-0366/ 를 참조해 주세요.

네, 패키지로 사용하는 게 아닙니다.

python -m pkg.tests.core_test

스크립트의 기동 방법에 따라 다릅니다.

명령줄에서 표준 방식으로 UnitTest를 시작하려면 다음 절차를 따릅니다.

python tests/core_test.py

이 경우 components tests는 형제 폴더이므로 sys.path 모듈의 insert 또는 append 메서드를 사용하여 상대 모듈을 Import할 수 있습니다.예를 들어 다음과 같습니다.

import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents

이외의 경우는, 「-m」인수로 스크립트를 기동할 수 있습니다(이 경우는 패키지에 대해 이야기하고 있기 때문에, 확장자 「.py」를 붙이지 말아 주세요).

python -m pkg.tests.core_test

이 경우 상대 Import를 그대로 사용할 수 있습니다.

from ..components.core import GameLoopEvents

최종적으로 두 가지 접근 방식을 혼합할 수 있으므로 스크립트가 어떻게 호출되든 작동합니다.예를 들어 다음과 같습니다.

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        from components.core import GameLoopEvents
    else:
        from ..components.core import GameLoopEvents

하시면 됩니다.import components.core를 「」에 하는 는, 행해집니다.sys.path:

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))

core_test.py에서 다음을 수행합니다.

import sys
sys.path.append('../components')
from core import GameLoopEvents

문제는 당신의 테스트 방법에 있습니다.

는 시도했다python core_test.py

ValueError라는 에러가 표시됩니다. 비패키지에서의 상대적인 Import를 시도했다.

이유: 비패키지 소스에서 패키지를 테스트하고 있습니다.

패키지 소스에서 모듈을 테스트합니다.

이게 프로젝트 구조라면

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

cd pkg

python -m tests.core_test # dont use .py

또는 외부 pkg/

python -m pkg.tests.core_test

★★★.같은 디렉토리의 폴더에서 Import 하려면 , 스텝백마다 1개씩 추가합니다.

hi/
  hello.py
how.py

how.py

from .hi import hello

예를 들어 hello에서 방법을 Import할 경우.화이

from .. import how

사용 사례가 테스트 실행용이고, 테스트 실행용이면 다음 작업을 수행할 수 있습니다.를 「」로 에, 「」로 실행합니다.python core_test.py등 such such such such such such such such such such such such such such such such such such such 등의 테스트 틀을 하다 등의 틀을 pytest에 "Data"를 할 수

$$ py.test

그러면 디렉토리에서 테스트가 실행됩니다.는 ' 하다'라는 으로 전개되고 있습니다.__name__존존 __main__@BrenBarn b @BrenBarn 。다음 빈 , ᄂ자, ᄂ자, ᄂ다를 .__init__.py테스트 디렉토리에 파일을 저장하면 테스트 디렉토리가 패키지의 일부가 됩니다.은 할 수 거예요.

from ..components.core import GameLoopEvents

그러나 테스트 스크립트를 메인 프로그램으로 실행하면 다시 실패하게 됩니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ 수 있을 이다.nosetests도움이 되기를 .이게 도움이 됐으면 좋겠다.

빠른 수정은 다음 디렉토리에 경로를 추가하는 것입니다.

import sys
sys.path.insert(0, '../components/')

Paolo가 말했듯이, 두 가지 호출 방법이 있습니다.

1) python -m tests.core_test
2) python tests/core_test.py

이들 사이의 1가지 차이점은 sys.path[0] 문자열입니다.Import 시 해석은 sys.path를 검색하기 때문에 다음과 같이 할 수 있습니다.tests/core_test.py:

if __name__ == '__main__':
    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
    from components import core
    <other stuff>

그 후 다른 방법으로 core_test.py를 실행할 수 있습니다.

cd tests
python core_test.py
python -m core_test
...

참고: py36 테스트만 완료됨.

'아까'를 붙이면__all__= ['submodule', ...]__init_.py 파일로 전송하고 나서from <CURRENT_MODULE> import *정상적으로 동작합니다.

하시면 됩니다.from pkg.components.core import GameLoopEvents팥소하다수입하다

여기에 이미지 설명 입력

이 접근방식은 나에게 효과가 있었고 일부 솔루션보다 덜 복잡했다.

try:
  from ..components.core import GameLoopEvents
except ValueError:
  from components.core import GameLoopEvents

는 PYTONPATH에 PYTONPATH가 .__init__.py파일을 부모 디렉토리와 이 디렉토리의 파일.

위의 내용은 항상 python 2에서 동작하지만 python 3은 ImportError 또는 ModuleNotFoundError(python 3.6 및 ImportError의 서브클래스)에 히트하는 경우가 있습니다.따라서 다음 트윗은 python 2와 3 모두에서 동작합니다.

try:
  from ..components.core import GameLoopEvents
except ( ValueError, ImportError):
  from components.core import GameLoopEvents

이거 드셔보세요

import components
from components import *

이미 모든 것을 모듈로 표시했기 때문에 python module로 기동하면 상대 참조를 사용할 필요가 없습니다.

대신

from ..components.core import GameLoopEvents

단순하게

from pkg.components.core import GameLoopEvents

pkg의 부모로부터 실행할 때는, 다음을 사용합니다.

python -m pkg.tests.core_test

누군가 해결 방법을 찾고 있다면, 나는 우연히 하나를 발견했다.여기 문맥이 있습니다.파일에 있는 방법 중 하나를 테스트해 보고 싶었어요.내부에서 실행할 때

if __name__ == "__main__":

상대적인 수입에 대해 항상 불평했다.위의 솔루션을 적용하려고 했지만 여러 개의 Import가 포함된 중첩된 파일이 많아 작동하지 않았습니다.

내가 한 일은 이렇다.필요한 메서드를 가져오고 호출하는 외부 프로그램인 런처를 방금 만들었습니다.좋은 해결책은 아니지만, 효과가 있다.

여기 모든 사람을 화나게 할 방법이 있지만 꽤 잘 된다.테스트 실행 시:

ln -s ../components components

그럼 평소처럼 컴포넌트를 Import해 주세요.

나에게만 효과가 있었다.패키지 을 부모 디렉토리에 명시적으로 설정하고 부모 디렉토리를 sys.path에 추가해야 했습니다.

from os import path
import sys
if __package__ is None:
    sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
    __package__= "myparent"

from .subdir import something # the . can now be resolved

이것으로 스크립트를 직접 실행할 수 있게 되었습니다.python myscript.py.

python <main module>.py상대 Import에서는 동작하지 않습니다.

이 문제는 를 실행할 때 상대적인 Import가 동작하지 않는다는 것입니다.__main__명령줄에서의 모듈

python <main_module>.py

PEP 338에 명확하게 기재되어 있습니다.

2.5b1의 릴리스는 이러한 PEP와 PEP 328 사이의 놀라운 상호작용을 보여주었다. 즉, 주 모듈에서는 명시적인 상대적 수입이 작동하지 않는다.이것은 상대적인 수입에 의존하는 사실 때문이다.__name__패키지 계층에서 현재 모듈의 위치를 확인합니다.에서는 ""의 값"__name__ 있다'__main__'따라서 명시적인 상대 Import는 항상 실패합니다(패키지 내의 모듈에 대해서만 기능하기 때문에).

원인

이 문제는 실제로는 -m 스위치만의 문제는 아닙니다.문제는 상대적인 수입이 다음 기준에 따른다는 것이다.__name__메인 에서는 " " " 입니다__name__ __main__따라서 메인 모듈은 Python 모듈 네임스페이스에서 실제로 어디에 들어가는지없기 때문어플리케이션의 메인 모듈로부터의 상대 Import는 현재 정상적으로 동작할 없습니다(이것은 이론상으로는 -m 스위치를 통해 실행되는 메인 모듈에서는 적어도 수정이 가능하지만 직접 실행되는 파일과 인터랙티브 인터프리터는 완전히 O입니다).행운을 빈다).

자세한 내용은 Python 3의 Relative imports를 참조하십시오.

이것은 매우 혼란스럽고, IDE를 pycharm과 같이 사용하면 조금 더 혼란스러울 수 있습니다.나에게 효과가 있었던 것: 1. pycharm 프로젝트 설정을 작성한다(VE 또는 python 디렉토리에서 python을 실행하고 있는 경우) 2.당신이 정의한 방식에는 잘못된 것이 없습니다.folder1.file1 Import 클래스에서 동작하는 경우도 있습니다.

정상적으로 동작하지 않는 경우는, import folder1.file1 3 을 사용합니다.환경변수는 시스템에서 올바르게 언급하거나 명령줄 인수로 지정해야 합니다.

저도 비슷한 문제가 있었습니다.소프트웨어 엔지니어로서 여기서 제안하는 솔루션 중 일부는 이상적이지 않다고 생각합니다.상대적인 Import를 원할 경우 시도/제외하지 않고 절대 Import를 실행하는 것이 좋습니다.또한 프로그램을 실행하려면 sys.path를 변경할 필요가 없습니다.

게다가 프로그램은, 현재의 작업 디렉토리나 기동 방법에 관계없이, 항상 기능합니다.

따라서 새로운 실험적인 Import 라이브러리를 만들었습니다.Ultra Import는 코드를 어떻게 실행하든 상관없이 파일 시스템 기반 Import를 허용합니다.

원래 질문에서 core_test.py를 다음과 같이 변경합니다.

import ultraimport
GameLoopEvents = ultraimport('__dir__/../components/core.py', 'GameLoopEvents')
print(GameLoopEvents)

검사를 어떻게 실행하든 상관없이 항상 찾을 수 있어요

$ python -m tests.core_test
<class 'core.GameLoopEvents'>
 python ./tests/core_test.py 
<class 'core.GameLoopEvents'>

이 예제를 git repo의 예제 폴더에 넣었습니다.

도서관이 실험적이기 때문에 피드백에 관심이 있습니다.저는 효과가 있지만 아직 널리 테스트되지는 않았습니다.

프로젝트 구조가 다음과 같은 경우:

   project
     |
     | --- module1
     |      |
     |      file1.py
     |
     |-----module2
     |     |
     |     file2.py

file2.py 내에서 file1.py을 Import할 경우 file2에서 Import할 수 있습니다.py:

import sys
sys.path.append('.')

import file2

왜, 어떻게 된 건지 아직 모르겠지만, 나한테는 효과가 있었어.

코드에는 다음이 포함되어 있습니다.if __name__ == "__main__"」를 사용하는이 좋습니다sys.path.append()문제를 해결합니다.

언급URL : https://stackoverflow.com/questions/11536764/how-to-fix-attempted-relative-import-in-non-package-even-with-init-py

반응형