In pytest, my testing script compares the calculated results with baseline results which are loaded via
SCRIPTLOC = os.path.dirname(__file__)
TESTBASELINE = os.path.join(SCRIPTLOC, 'baseline', 'baseline.csv')
baseline = pandas.DataFrame.from_csv(TESTBASELINE)
Is there a non-boilerplate way to tell pytest to start looking from the root directory of the script rather than get the absolute location through SCRIPTLOC?
If you are simply looking for the pytest equivalent of using __file__
, you can add the request
fixture to your test and use request.path
From the docs:
class FixtureRequest ... property path: Path Path where the test function was collected.
So an example might look like:
def test_script_loc(request):
baseline = request.path.parent.joinpath('baseline', 'baseline.cvs')
print(baseline)
If you're wanting to avoid boilerplate though, you're not going to gain much from doing this (assuming I understand what you mean by 'non-boilerplate')
Personally, I think using the fixture is more explicit (within pytest idioms), but I prefer to wrap the request manipulation in another fixture so I know that I'm explicitly grabbing sample test data just by looking at the method signature of a test.
Here's a snippet I use (modified to match your question, I use a subdirectory hierarchy):
# in conftest.py
import pytest
from pathlib import Path
@pytest.fixture(scope="module")
def script_loc(request):
'''Return the directory of the currently running test script'''
return request.path.parent
And sample usage
def test_script_loc(script_loc):
baseline = script_loc.joinpath('baseline/baseline.cvs')
print(baseline)
I've long since stopped supporting legacy Python and instead use pathlib
.
Given that, I no longer return LocalPath
objects nor depend on their API, but occassionally I still need to support platforms with pytest<=6.0
which do not yet have the request.path
property.
The pytest team is also planning to eventually deprecate py.path
and is porting their internals to the standard library pathlib
. This started as early as pytest 3.9.0 with the introduction of tmp_path
, though the actual removal of LocalPath
attributes may not happen for some time.
Until you can upgrade to pytest>=7.0
, it's easy enough to convert the LocalPath
to a Path
ourselves.
Here's a variant of the above example using a Path
object, tweak as it suits you:
# in conftest.py
import pytest
from pathlib import Path
@pytest.fixture(scope="module")
def script_loc(request):
'''Return the directory of the currently running test script'''
return Path(request.fspath).parent
And sample usage
def test_script_loc(script_loc):
baseline = script_loc.joinpath('baseline/baseline.cvs')
print(baseline)
For older versions of pytest that depend on py.path
and/or required Python 2.x support, the original version of this answer used the request.fspath
attribute to return an instance of py.path.LocalPath
.
From the docs:
class FixtureRequest ... fspath the file system path of the test module which collected this test.
So an example might look like:
def test_script_loc(request):
baseline = os.path.join(request.fspath.dirname, 'baseline', 'baseline.cvs')
print(baseline)
The fixture variant might appear as follows:
# in conftest.py
import pytest
@pytest.fixture(scope="module")
def script_loc(request):
'''Return the directory of the currently running test script'''
# uses .join instead of .dirname so we get a LocalPath object instead of
# a string. LocalPath.join calls normpath for us when joining the path
return request.fspath.join('..')
And sample usage:
def test_script_loc(script_loc):
baseline = script_loc.join('baseline/baseline.cvs')
print(baseline)
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