'py.test: Temporary folder for the session scope
The tmpdir fixture in py.test uses the function scope and thus isn't available in a fixture with a broader scope such as session. However, this would be useful for some cases such as setting up a temporary PostgreSQL server (which of course shouldn't be recreated for each test).
Is there any clean way to get a temporary folder for a broader scope that does not involve writing my own fixture and accessing internal APIs of py.test?
Solution 1:[1]
Since pytest release 2.8 and above the session-scoped tmpdir_factory fixture is available. See the example below from the documentation.
# contents of conftest.py
import pytest
@pytest.fixture(scope='session')
def image_file(tmpdir_factory):
img = compute_expensive_image()
fn = tmpdir_factory.mktemp('data').join('img.png')
img.save(str(fn))
return fn
# contents of test_image.py
def test_histogram(image_file):
img = load_image(image_file)
# compute and test histogram
Solution 2:[2]
I add a finalizer when I want to delete all temporary folders created in session.
_tmp_factory = None
@pytest.fixture(scope="session")
def tmp_factory(request, tmpdir_factory):
global _tmp_factory
if _tmp_factory is None:
_tmp_factory = tmpdir_factory
request.addfinalizer(cleanup)
return _tmp_factory
def cleanup():
root = _tmp_factory.getbasetemp().strpath
print "Cleaning all temporary folders from %s" % root
shutil.rmtree(root)
def test_deleting_temp(tmp_factory):
root_a = tmp_factory.mktemp('A')
root_a.join('foo.txt').write('hello world A')
root_b = tmp_factory.mktemp('B')
root_b.join('bar.txt').write('hello world B')
for root, _, files in os.walk(tmp_factory.getbasetemp().strpath):
for name in files:
print(os.path.join(root, name))
The output should be like:
/tmp/pytest-of-agp/pytest-0/.lock
/tmp/pytest-of-agp/pytest-0/A0/foo.txt
/tmp/pytest-of-agp/pytest-0/B0/bar.txt
Cleaning all temporary folders from /tmp/pytest-of-agp/pytest-0
Solution 3:[3]
Here's another approach. It looks like pytest doesn't remove temporary directories after test runs. The following is a regular function-scoped fixture.
# conftest.py
TMPDIRS = list()
@pytest.fixture
def tmpdir_session(tmpdir):
"""A tmpdir fixture for the session scope. Persists throughout the session."""
if not TMPDIRS:
TMPDIRS.append(tmpdir)
return TMPDIRS[0]
And to have persistent temporary directories across modules instead of the whole pytest session:
# conftest.py
TMPDIRS = dict()
@pytest.fixture
def tmpdir_module(request, tmpdir):
"""A tmpdir fixture for the module scope. Persists throughout the module."""
return TMPDIRS.setdefault(request.module.__name__, tmpdir)
Edit:
Here's another solution that doesn't involve global variables. pytest 1.8.0 introduced a tmpdir_factory fixture that we can use:
@pytest.fixture(scope='module')
def tmpdir_module(request, tmpdir_factory):
"""A tmpdir fixture for the module scope. Persists throughout the module."""
return tmpdir_factory.mktemp(request.module.__name__)
@pytest.fixture(scope='session')
def tmpdir_session(request, tmpdir_factory):
"""A tmpdir fixture for the session scope. Persists throughout the pytest session."""
return tmpdir_factory.mktemp(request.session.name)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mehraban |
| Solution 2 | asterio gonzalez |
| Solution 3 |
