__init__.py를 사용해도“패키지가 아닌 상대 가져 오기 시도”를 수정하는 방법
다음 디렉터리 구조로 PEP 328 을 따르려고합니다 .
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
에서 core_test.py
나는 다음과 같은 import 문을
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에서도 작동하지 않는 상대 경로 "및 " 상대 경로에서 모듈 가져 오기 "를 찾았 지만 도움이되지 않았습니다.
내가 여기에 빠진 것이 있습니까?
예. 패키지로 사용하지 않습니다.
python -m pkg.tests.core_test
Ignacio Vazquez-Abrams의 답변 에 대해 자세히 설명하려면 :
Python 가져 오기 메커니즘은 __name__
현재 파일을 기준으로 작동 합니다. 파일을 직접 실행하면 일반적인 이름이 없지만 "__main__"
대신 이름이 있습니다. 따라서 상대적 수입은 작동하지 않습니다.
Igancio가 제안했듯이 -m
옵션을 사용하여 실행할 수 있습니다. 스크립트로 실행될 패키지의 일부가있는 경우 __package__
속성을 사용하여 해당 파일에 패키지 계층 구조에 있어야하는 이름을 알릴 수도 있습니다 .
자세한 내용은 http://www.python.org/dev/peps/pep-0366/ 을 참조하십시오.
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__))))
스크립트를 실행하려는 방법에 따라 다릅니다.
고전적인 방식으로 명령 줄 에서 UnitTest 를 시작하려면 다음과 같이하십시오 .
python tests/core_test.py
그런 다음이 경우 'components' 및 'tests' 는 형제 폴더이므로 sys.path 모듈 의 insert 또는 append 메소드를 사용하여 상대 모듈을 가져올 수 있습니다 . 다음과 같은 것 :
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
이러한 경우에는 다음과 같이 간단히 상대 가져 오기를 사용할 수 있습니다.
from ..components.core import GameLoopEvents
You can finally mix the two approaches, so that your script will work no matter how it is called. For example:
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
In core_test.py, do the following:
import sys
sys.path.append('../components')
from core import GameLoopEvents
If your use case is for running tests, and it seams that it is, then you can do the following. Instead of running your test script as python core_test.py
use a testing framework such as pytest
. Then on the command line you can enter
$$ py.test
That will run the tests in your directory. This gets around the issue of __name__
being __main__
that was pointed out by @BrenBarn. Next, put an empty __init__.py
file into your test directory, this will make the test directory part of your package. Then you will be able to do
from ..components.core import GameLoopEvents
However, if you run your test script as a main program then things will fail once again. So just use the test runner. Maybe this also works with other test runners such as nosetests
but i haven't checked it. Hope this helps.
My quick-fix is to add the directory to the path:
import sys
sys.path.insert(0, '../components/')
Old thread. I found out that adding an __all__= ['submodule', ...]
to the __init__.py file and then using the from <CURRENT_MODULE> import *
in the target works fine.
You can use from pkg.components.core import GameLoopEvents
, for example I use pycharm, the below is my project structure image, I just import from the root package, then it works:
If someone is looking for a workaround, I stumbled upon one. Here's a bit of context. I wanted to test out one of the methods I've in a file. When I run it from within
if __name__ == "__main__":
it always complained of the relative imports. I tried to apply the above solutions, but failed to work, since there were many nested files, each with multiple imports.
Here's what I did. I just created a launcher, an external program that would import necessary methods and call them. Though, not a great solution, it works.
Try this
import components
from components import *
As Paolo said, we have 2 invocation methods:
1) python -m tests.core_test
2) python tests/core_test.py
One difference between them is sys.path[0] string. Since the interpret will search sys.path when doing import, we can do with 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>
And more after this, we can run core_test.py with other methods:
cd tests
python core_test.py
python -m core_test
...
Note, py36 tested only.
This approach worked for me and is less cluttered than some solutions:
try:
from ..components.core import GameLoopEvents
except ValueError:
from components.core import GameLoopEvents
The parent directory is in my PYTHONPATH, and there are __init__.py
files in the parent directory and this directory.
The above always worked in python 2, but python 3 sometimes hit an ImportError or ModuleNotFoundError (the latter is new in python 3.6 and a subclass of ImportError), so the following tweak works for me in both python 2 and 3:
try:
from ..components.core import GameLoopEvents
except ( ValueError, ImportError):
from components.core import GameLoopEvents
'IT박스' 카테고리의 다른 글
SQL Server : 첫 번째 행에 조인하는 방법 (0) | 2020.09.30 |
---|---|
JavaScript Date 객체에 30 분을 추가하는 방법은 무엇입니까? (0) | 2020.09.30 |
람다와 구별 ()? (0) | 2020.09.30 |
커밋 메시지 내 GitHub의 문제 번호에 연결 (0) | 2020.09.30 |
포트 번호가 지정된 scp (0) | 2020.09.30 |