Skip to content

Providing custom cache directory through ini option #2558

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@

.. towncrier release notes start


Pytest 3.2.0 (unreleased)
=========================

- New ``cache_dir`` ini option: sets a directory where stores content of cache plugin.
Default directory is ``.cache`` which is created in :ref:`rootdir <rootdir>`.
Directory may be relative or absolute path. If setting relative path, then directory
is created relative to :ref:`rootdir <rootdir>`. Additionally path may contain environment
variables, that will be expanded.


Pytest 3.1.3 (2017-07-03)
=========================

Expand Down
16 changes: 15 additions & 1 deletion _pytest/cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,31 @@
import py
import pytest
import json
import os
from os.path import sep as _sep, altsep as _altsep


class Cache(object):
def __init__(self, config):
self.config = config
self._cachedir = config.rootdir.join(".cache")
self._cachedir = Cache.cache_dir_from_config(config)
self.trace = config.trace.root.get("cache")
if config.getvalue("cacheclear"):
self.trace("clearing cachedir")
if self._cachedir.check():
self._cachedir.remove()
self._cachedir.mkdir()

@staticmethod
def cache_dir_from_config(config):
cache_dir = config.getini("cache_dir")
cache_dir = os.path.expanduser(cache_dir)
cache_dir = os.path.expandvars(cache_dir)
if os.path.isabs(cache_dir):
return py.path.local(cache_dir)
else:
return config.rootdir.join(cache_dir)

def makedir(self, name):
""" return a directory path object with the given name. If the
directory does not yet exist, it will be created. You can use it
Expand Down Expand Up @@ -171,6 +182,9 @@ def pytest_addoption(parser):
group.addoption(
'--cache-clear', action='store_true', dest="cacheclear",
help="remove all cache contents at start of test run.")
parser.addini(
"cache_dir", default='.cache',
help="cache directory path.")


def pytest_cmdline_main(config):
Expand Down
2 changes: 2 additions & 0 deletions doc/en/cache.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _`cache_provider`:

Cache: working with cross-testrun state
=======================================

Expand Down
12 changes: 11 additions & 1 deletion doc/en/customize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ Builtin configuration file options
from ``pytest.ini``/``tox.ini``/``setup.cfg`` of the project if any,
or up to the file-system root.


.. confval:: filterwarnings

.. versionadded:: 3.1
Expand All @@ -262,3 +261,14 @@ Builtin configuration file options

This tells pytest to ignore deprecation warnings and turn all other warnings
into errors. For more information please refer to :ref:`warnings`.

.. confval:: cache_dir

.. versionadded:: 3.2

Sets a directory where stores content of cache plugin. Default directory is
``.cache`` which is created in :ref:`rootdir <rootdir>`. Directory may be
relative or absolute path. If setting relative path, then directory is created
relative to :ref:`rootdir <rootdir>`. Additionally path may contain environment
variables, that will be expanded. For more information about cache plugin
please refer to :ref:`cache_provider`.
33 changes: 31 additions & 2 deletions testing/test_cache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import absolute_import, division, print_function
import sys

import py
import _pytest
import pytest
import os
Expand Down Expand Up @@ -87,7 +87,36 @@ def test_cachefuncarg(cache):
assert result.ret == 0
result.stdout.fnmatch_lines(["*1 passed*"])


def test_custom_rel_cache_dir(self, testdir):
rel_cache_dir = os.path.join('custom_cache_dir', 'subdir')
testdir.makeini("""
[pytest]
cache_dir = {cache_dir}
""".format(cache_dir=rel_cache_dir))
testdir.makepyfile(test_errored='def test_error():\n assert False')
testdir.runpytest()
assert testdir.tmpdir.join(rel_cache_dir).isdir()

def test_custom_abs_cache_dir(self, testdir, tmpdir_factory):
tmp = str(tmpdir_factory.mktemp('tmp'))
abs_cache_dir = os.path.join(tmp, 'custom_cache_dir')
testdir.makeini("""
[pytest]
cache_dir = {cache_dir}
""".format(cache_dir=abs_cache_dir))
testdir.makepyfile(test_errored='def test_error():\n assert False')
testdir.runpytest()
assert py.path.local(abs_cache_dir).isdir()

def test_custom_cache_dir_with_env_var(self, testdir, monkeypatch):
monkeypatch.setenv('env_var', 'custom_cache_dir')
testdir.makeini("""
[pytest]
cache_dir = {cache_dir}
""".format(cache_dir='$env_var'))
testdir.makepyfile(test_errored='def test_error():\n assert False')
testdir.runpytest()
assert testdir.tmpdir.join('custom_cache_dir').isdir()

def test_cache_reportheader(testdir):
testdir.makepyfile("""
Expand Down