I am having some trouble figuring out how to do relative imports in Python. I am currently working on my first major project so I want to do it right using unit tests. However, I am having trouble with my file structure and relative imports.
Here is my current structure:
App/
__init__.py
src/
__init__.py
person.py
tests/
__init__.py
person_tests.py
What I want to do is be able to import person.py into person_tests.py for the unit tests. I have attempted the following:
from . import person
from .. import person
from .App.src import person
from ..App.src import person
from ..src.person import *
from ..src import person
from .src import person
Every one of the above throws either a syntax error or
ValueError: Attempted relative import in non-package
Can someone please clarify this for me?
Edit: Python version is 2.7. Edit: I would like to be able to use this with say unittest or nose.
My guess (and I'll delete this if I'm wrong) is that you're trying to use person_tests.py
as a top-level script, rather than as a module inside a package, by doing something like this:
$ cd App/tests
$ python person_tests.py
In that case, person_tests
does not end up as App.tests.person_tests
, but as just __main__
(or, with minor variations, as the top-level person_tests
, which has the same basic issues). So, ..
does not refer to App
, and therefore there is no way to get to person
as a relative import.
More generally, nothing on PYTHONPATH
, including .
, should ever be in the middle of any package directory, or things will get broken.
The right answer is to not do that. Do something like this:
$ python -m App.tests.person_tests
Or write a top-level (outside the package) script that imports the module, and run that top-level script.
Just as abarnert says, you can not excute the script as main for the relative import based on the current name of the script. Quoted from the doc:
Note that both explicit and implicit relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application should always use absolute imports.
.
represents the current package and ..
represents the parent package. So some of your import statement is wrong.
from . import person # wrong for no person module in package tests
from .. import person # wrong for no person module in package app
from .App.src import person # wrong for no app package in package tests
from ..App.src import person # wrong for no app package in package app
from ..src.person import * # right
from ..src import person # right
from .src import person # wrong
You can refer PEP328 for the standard of relative import.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With