import os
import tempfile
import unittest
from importlib import reload
import diskcache
import pytest
from diskcache import Cache, UNKNOWN
from outlines.caching import CloudpickleDisk
@pytest.fixture
def temp_dir():
"""Create a temporary directory for testing."""
directory = tempfile.mkdtemp()
yield directory
@pytest.fixture
def refresh_environment():
"""Refresh the test environment.
This deletes any reference to `outlines` in the modules dictionary and unsets the
`OUTLINES_CACHE_DIR` environment variable if set. This is necessary because we
are using a module variable to hold the cache.
"""
import sys
for key in list(sys.modules.keys()):
if "outlines" in key:
del sys.modules[key]
try:
del os.environ["OUTLINES_CACHE_DIR"]
except KeyError:
pass
@pytest.fixture
def test_cache(refresh_environment):
"""Initialize a temporary cache and delete it after the test has run."""
with tempfile.TemporaryDirectory() as tempdir:
os.environ["OUTLINES_CACHE_DIR"] = tempdir
import outlines
memory = outlines.get_cache()
assert memory.directory == tempdir
yield outlines.caching.cache()
memory.clear()
def test_get_cache(test_cache):
import outlines
memory = outlines.get_cache()
assert isinstance(memory, diskcache.Cache)
store = list()
@test_cache
def f(x):
store.append(1)
return x
f(1)
store_size = len(store)
f(1)
assert len(store) == store_size
f(2)
assert len(store) == store_size + 1
def test_disable_cache(test_cache):
"""Make sure that we can disable the cache."""
import outlines
outlines.disable_cache()
store = list()
@test_cache
def f(x):
store.append(1)
return x
f(1)
store_size = len(store)
f(1)
assert len(store) == store_size + 1
def test_clear_cache(test_cache):
"""Make sure that we can clear the cache."""
import outlines
store = list()
@test_cache
def f(x):
store.append(1)
return x
f(1)
store_size = len(store)
f(1)
assert len(store) == store_size
outlines.clear_cache()
f(1)
assert len(store) == store_size + 1
def test_version_upgrade_cache_invalidate(test_cache, mocker):
"""Ensure we can change the signature of a cached function if we upgrade the version"""
import outlines.caching
def simulate_restart_outlines():
outlines.caching.get_cache.cache_clear()
mocker.patch("outlines._version.__version__", new="0.0.0")
simulate_restart_outlines()
@test_cache
def foo():
return (1, 2, 3)
a, b, c = foo()
simulate_restart_outlines()
@test_cache
def foo():
return (1, 2)
with pytest.raises(ValueError):
a, b = foo()
mocker.patch("outlines._version.__version__", new="0.0.1")
simulate_restart_outlines()
@test_cache
def foo():
return (1, 2)
a, b = foo()
def test_cache_disabled_decorator(test_cache):
"""Ensure cache can be disabled in a local scope"""
from outlines.caching import cache_disabled
mock = unittest.mock.MagicMock()
@test_cache
def fn():
mock()
return 1
fn()
assert mock.call_count == 1
fn()
assert mock.call_count == 1
with cache_disabled():
fn()
assert mock.call_count == 2
fn()
assert mock.call_count == 2
@pytest.fixture
def temp_cache_dir():
import os
import tempfile
import outlines.caching
with tempfile.TemporaryDirectory() as tempdir:
os.environ["OUTLINES_CACHE_DIR"] = tempdir
outlines.caching.get_cache.cache_clear()
reload(outlines)
cache_status = outlines.caching._caching_enabled
try:
outlines.caching._caching_enabled = True
yield
finally:
outlines.caching._caching_enabled = cache_status