Use a subdirectory in the TEMP directory to speed up tmpdir creation
Fix #105
This commit is contained in:
parent
8f4f2c665d
commit
0f52856f99
|
@ -4,6 +4,13 @@
|
||||||
- fix issue768: docstrings found in python modules were not setting up session
|
- fix issue768: docstrings found in python modules were not setting up session
|
||||||
fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR.
|
fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- added `tmpdir_factory`, a session-scoped fixture that can be used to create
|
||||||
|
directories under the base temporary directory. Previously this object was
|
||||||
|
installed as a `_tmpdirhandler` attribute of the `config` object, but now it
|
||||||
|
is part of the official API and using `config._tmpdirhandler` is
|
||||||
|
deprecated.
|
||||||
|
Thanks Bruno Oliveira for the PR.
|
||||||
|
|
||||||
- fix issue 808: pytest's internal assertion rewrite hook now implements the
|
- fix issue 808: pytest's internal assertion rewrite hook now implements the
|
||||||
optional PEP302 get_data API so tests can access data files next to them.
|
optional PEP302 get_data API so tests can access data files next to them.
|
||||||
Thanks xmo-odoo for request and example and Bruno Oliveira for
|
Thanks xmo-odoo for request and example and Bruno Oliveira for
|
||||||
|
|
|
@ -309,16 +309,18 @@ class HookRecorder:
|
||||||
self.calls[:] = []
|
self.calls[:] = []
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__linecomp(request):
|
@pytest.fixture
|
||||||
|
def linecomp(request):
|
||||||
return LineComp()
|
return LineComp()
|
||||||
|
|
||||||
|
|
||||||
def pytest_funcarg__LineMatcher(request):
|
def pytest_funcarg__LineMatcher(request):
|
||||||
return LineMatcher
|
return LineMatcher
|
||||||
|
|
||||||
def pytest_funcarg__testdir(request):
|
|
||||||
tmptestdir = Testdir(request)
|
|
||||||
return tmptestdir
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def testdir(request, tmpdir_factory):
|
||||||
|
return Testdir(request, tmpdir_factory)
|
||||||
|
|
||||||
|
|
||||||
rex_outcome = re.compile("(\d+) (\w+)")
|
rex_outcome = re.compile("(\d+) (\w+)")
|
||||||
|
@ -388,10 +390,10 @@ class Testdir:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request, tmpdir_factory):
|
||||||
self.request = request
|
self.request = request
|
||||||
# XXX remove duplication with tmpdir plugin
|
# XXX remove duplication with tmpdir plugin
|
||||||
basetmp = request.config._tmpdirhandler.ensuretemp("testdir")
|
basetmp = tmpdir_factory.ensuretemp("testdir")
|
||||||
name = request.function.__name__
|
name = request.function.__name__
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -6,7 +6,12 @@ import py
|
||||||
from _pytest.monkeypatch import monkeypatch
|
from _pytest.monkeypatch import monkeypatch
|
||||||
|
|
||||||
|
|
||||||
class TempdirHandler:
|
class TempdirFactory:
|
||||||
|
"""Factory for temporary directories under the common base temp directory.
|
||||||
|
|
||||||
|
The base directory can be configured using the ``--basetemp`` option.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.trace = config.trace.get("tmpdir")
|
self.trace = config.trace.get("tmpdir")
|
||||||
|
@ -22,6 +27,10 @@ class TempdirHandler:
|
||||||
return self.getbasetemp().ensure(string, dir=dir)
|
return self.getbasetemp().ensure(string, dir=dir)
|
||||||
|
|
||||||
def mktemp(self, basename, numbered=True):
|
def mktemp(self, basename, numbered=True):
|
||||||
|
"""Create a subdirectory of the base temporary directory and return it.
|
||||||
|
If ``numbered``, ensure the directory is unique by adding a number
|
||||||
|
prefix greater than any existing one.
|
||||||
|
"""
|
||||||
basetemp = self.getbasetemp()
|
basetemp = self.getbasetemp()
|
||||||
if not numbered:
|
if not numbered:
|
||||||
p = basetemp.mkdir(basename)
|
p = basetemp.mkdir(basename)
|
||||||
|
@ -51,15 +60,33 @@ class TempdirHandler:
|
||||||
def finish(self):
|
def finish(self):
|
||||||
self.trace("finish")
|
self.trace("finish")
|
||||||
|
|
||||||
|
# backward compatibility
|
||||||
|
TempdirHandler = TempdirFactory
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
"""Create a TempdirFactory and attach it to the config object.
|
||||||
|
|
||||||
|
This is to comply with existing plugins which expect the handler to be
|
||||||
|
available at pytest_configure time, but ideally should be moved entirely
|
||||||
|
to the tmpdir_factory session fixture.
|
||||||
|
"""
|
||||||
mp = monkeypatch()
|
mp = monkeypatch()
|
||||||
t = TempdirHandler(config)
|
t = TempdirFactory(config)
|
||||||
config._cleanup.extend([mp.undo, t.finish])
|
config._cleanup.extend([mp.undo, t.finish])
|
||||||
mp.setattr(config, '_tmpdirhandler', t, raising=False)
|
mp.setattr(config, '_tmpdirhandler', t, raising=False)
|
||||||
mp.setattr(pytest, 'ensuretemp', t.ensuretemp, raising=False)
|
mp.setattr(pytest, 'ensuretemp', t.ensuretemp, raising=False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def tmpdir_factory(request):
|
||||||
|
"""Return a TempdirFactory instance for the test session.
|
||||||
|
"""
|
||||||
|
return request.config._tmpdirhandler
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tmpdir(request):
|
def tmpdir(request, tmpdir_factory):
|
||||||
"""return a temporary directory path object
|
"""return a temporary directory path object
|
||||||
which is unique to each test function invocation,
|
which is unique to each test function invocation,
|
||||||
created as a sub directory of the base temporary
|
created as a sub directory of the base temporary
|
||||||
|
@ -71,5 +98,5 @@ def tmpdir(request):
|
||||||
MAXVAL = 30
|
MAXVAL = 30
|
||||||
if len(name) > MAXVAL:
|
if len(name) > MAXVAL:
|
||||||
name = name[:MAXVAL]
|
name = name[:MAXVAL]
|
||||||
x = request.config._tmpdirhandler.mktemp(name, numbered=True)
|
x = tmpdir_factory.mktemp(name, numbered=True)
|
||||||
return x
|
return x
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
Temporary directories and files
|
Temporary directories and files
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
The 'tmpdir' test function argument
|
The 'tmpdir' fixture
|
||||||
-----------------------------------
|
--------------------
|
||||||
|
|
||||||
You can use the ``tmpdir`` function argument which will
|
You can use the ``tmpdir`` fixture which will
|
||||||
provide a temporary directory unique to the test invocation,
|
provide a temporary directory unique to the test invocation,
|
||||||
created in the `base temporary directory`_.
|
created in the `base temporary directory`_.
|
||||||
|
|
||||||
|
@ -51,6 +51,44 @@ Running this would result in a passed test except for the last
|
||||||
test_tmpdir.py:7: AssertionError
|
test_tmpdir.py:7: AssertionError
|
||||||
======= 1 failed in 0.12 seconds ========
|
======= 1 failed in 0.12 seconds ========
|
||||||
|
|
||||||
|
|
||||||
|
The 'tmpdir_factory' fixture
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. versionadded:: 2.8
|
||||||
|
|
||||||
|
The ``tmpdir_factory`` is a session-scoped fixture which can be used
|
||||||
|
to create arbitrary temporary directories from any other fixture or test.
|
||||||
|
|
||||||
|
For example, suppose your test suite needs a large image on disk, which is
|
||||||
|
generated procedurally. Instead of computing the same image for each test
|
||||||
|
that uses it into its own ``tmpdir``, you can generate it once per-session
|
||||||
|
to save time:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
``tmpdir_factory`` instances have the following methods:
|
||||||
|
|
||||||
|
.. currentmodule:: _pytest.tmpdir
|
||||||
|
|
||||||
|
.. automethod:: TempdirFactory.mktemp
|
||||||
|
.. automethod:: TempdirFactory.getbasetemp
|
||||||
|
|
||||||
.. _`base temporary directory`:
|
.. _`base temporary directory`:
|
||||||
|
|
||||||
The default base temporary directory
|
The default base temporary directory
|
||||||
|
|
|
@ -555,7 +555,8 @@ class TestRequestBasic:
|
||||||
pass
|
pass
|
||||||
def test_function(request, farg):
|
def test_function(request, farg):
|
||||||
assert set(get_public_names(request.fixturenames)) == \
|
assert set(get_public_names(request.fixturenames)) == \
|
||||||
set(["tmpdir", "sarg", "arg1", "request", "farg"])
|
set(["tmpdir", "sarg", "arg1", "request", "farg",
|
||||||
|
"tmpdir_factory"])
|
||||||
""")
|
""")
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
|
@ -4,9 +4,9 @@ from _pytest.config import PytestPluginManager
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module", params=["global", "inpackage"])
|
@pytest.fixture(scope="module", params=["global", "inpackage"])
|
||||||
def basedir(request):
|
def basedir(request, tmpdir_factory):
|
||||||
from _pytest.tmpdir import tmpdir
|
from _pytest.tmpdir import tmpdir
|
||||||
tmpdir = tmpdir(request)
|
tmpdir = tmpdir(request, tmpdir_factory)
|
||||||
tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3")
|
tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3")
|
||||||
tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5")
|
tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5")
|
||||||
if request.param == "inpackage":
|
if request.param == "inpackage":
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import py
|
import py
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from _pytest.tmpdir import tmpdir, TempdirHandler
|
from _pytest.tmpdir import tmpdir, TempdirFactory
|
||||||
|
|
||||||
def test_funcarg(testdir):
|
def test_funcarg(testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
|
@ -13,16 +13,15 @@ def test_funcarg(testdir):
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
calls = reprec.getcalls("pytest_runtest_setup")
|
calls = reprec.getcalls("pytest_runtest_setup")
|
||||||
item = calls[0].item
|
item = calls[0].item
|
||||||
# pytest_unconfigure has deleted the TempdirHandler already
|
|
||||||
config = item.config
|
config = item.config
|
||||||
config._tmpdirhandler = TempdirHandler(config)
|
tmpdirhandler = TempdirFactory(config)
|
||||||
item._initrequest()
|
item._initrequest()
|
||||||
p = tmpdir(item._request)
|
p = tmpdir(item._request, tmpdirhandler)
|
||||||
assert p.check()
|
assert p.check()
|
||||||
bn = p.basename.strip("0123456789")
|
bn = p.basename.strip("0123456789")
|
||||||
assert bn.endswith("test_func_a_")
|
assert bn.endswith("test_func_a_")
|
||||||
item.name = "qwe/\\abc"
|
item.name = "qwe/\\abc"
|
||||||
p = tmpdir(item._request)
|
p = tmpdir(item._request, tmpdirhandler)
|
||||||
assert p.check()
|
assert p.check()
|
||||||
bn = p.basename.strip("0123456789")
|
bn = p.basename.strip("0123456789")
|
||||||
assert bn == "qwe__abc"
|
assert bn == "qwe__abc"
|
||||||
|
@ -38,7 +37,7 @@ class TestTempdirHandler:
|
||||||
def test_mktemp(self, testdir):
|
def test_mktemp(self, testdir):
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
config.option.basetemp = testdir.mkdir("hello")
|
config.option.basetemp = testdir.mkdir("hello")
|
||||||
t = TempdirHandler(config)
|
t = TempdirFactory(config)
|
||||||
tmp = t.mktemp("world")
|
tmp = t.mktemp("world")
|
||||||
assert tmp.relto(t.getbasetemp()) == "world0"
|
assert tmp.relto(t.getbasetemp()) == "world0"
|
||||||
tmp = t.mktemp("this")
|
tmp = t.mktemp("this")
|
||||||
|
@ -49,17 +48,19 @@ class TestTempdirHandler:
|
||||||
|
|
||||||
class TestConfigTmpdir:
|
class TestConfigTmpdir:
|
||||||
def test_getbasetemp_custom_removes_old(self, testdir):
|
def test_getbasetemp_custom_removes_old(self, testdir):
|
||||||
p = testdir.tmpdir.join("xyz")
|
mytemp = testdir.tmpdir.join("xyz")
|
||||||
config = testdir.parseconfigure("--basetemp=xyz")
|
p = testdir.makepyfile("""
|
||||||
b = config._tmpdirhandler.getbasetemp()
|
def test_1(tmpdir):
|
||||||
assert b == p
|
pass
|
||||||
h = b.ensure("hello")
|
""")
|
||||||
config._tmpdirhandler.getbasetemp()
|
testdir.runpytest(p, '--basetemp=%s' % mytemp)
|
||||||
assert h.check()
|
mytemp.check()
|
||||||
config = testdir.parseconfigure("--basetemp=xyz")
|
mytemp.ensure("hello")
|
||||||
b2 = config._tmpdirhandler.getbasetemp()
|
|
||||||
assert b2.check()
|
testdir.runpytest(p, '--basetemp=%s' % mytemp)
|
||||||
assert not h.check()
|
mytemp.check()
|
||||||
|
assert not mytemp.join("hello").check()
|
||||||
|
|
||||||
|
|
||||||
def test_basetemp(testdir):
|
def test_basetemp(testdir):
|
||||||
mytemp = testdir.tmpdir.mkdir("mytemp")
|
mytemp = testdir.tmpdir.mkdir("mytemp")
|
||||||
|
|
Loading…
Reference in New Issue