Reputation: 1829
I am using py.test
to test my python code. The relevant structure of my project is
-myproject
file.py
file2.py
-test/
input.txt
input2.dat
test_part.py
-regress/
file2_old.py
__init__.py
-test/
test_file2_regression.py
test_part.py
imports file
and file2
and test_file2_regression.py
imports file2
and regress.file2_old
. If I run pytest
in the console, I get the import errors, that the packages don't exist. Running python -m pytest
on the other hand works perfectly fine, but only if I run it from the myproject/
directory.
What is the correct way to do this, to get it working from anywhere in my project? I already tried modifying the PYTHONPATH
but I honestly have no idea how to properly do it.
Further information:
I don't have any setup files, and my __init__
s are just empty files. If manipulating the PYTHONPATH
is necessary it needs to be done relative to myproject
as I use it on several machines. I am running python 2.7.
I already check out:
but it didn't really help me.
Upvotes: 3
Views: 523
Reputation: 1829
The solution which works with the pytest
command from any directory in the project is to include before the imports in the test*.py
files:
import os
from sys import path
PATH = os.path.abspath(os.path.dirname(__file__))
path.append(os.path.join(PATH, os.pardir, os.pardir))
where the proper number of os.pardir
is used to navigate to the project directory, from there the __init__.py
files allow to import the modules.
Both argv[0]
and inspect.getsourcefile
don't provide the necessary information. argv[0]
contains the location of the used py.test
module and the getsourcefile
method simply returns None
.
Edit: since Python 3.4 we can use instead of os.path
the modern pathlib
:
from pathlib import Path
from sys import path
PATH = Path(__file__).resolve()
path.append(PATH.parents[2])
Upvotes: 2
Reputation: 1914
Having the same issue and similar success in searching for "the best way of doing this", I concluded for myself to avoid the situation whenever possible (by running the actual scripts consequently from top level), but to answer your question, my current approach (for instance for unit testing from a parallel folder) is
from sys import argv, path
from os.path import dirname, join
path.append(join(dirname(argv[0]), ".."))
This makes the interpreter also search in the folder above where the script is started. Another approach (instead of using argv
) is to use the introspect
module to obtain the filename. These work better for me than using __file__
, as the latter is not always defined.
Edit 29.10.:
Alternative to argv[0]
is to use
from inspect import getsourcefile
from sys import path
from os.path import dirname, join
this_file = getsourcefile(lambda _: None)
path.append(join(dirname(this_file), ".."))
I hope this will work at least for the requested purpose, see also How do I get the path of the current executed file in Python?.
The simplest - if it works in your case - is of course:
from os.path import dirname, join
path.append(join(dirname(__file__), ".."))
Upvotes: 1