outlines
1import os2import tempfile3
4import diskcache5import pytest6
7
8@pytest.fixture9def refresh_environment():10"""Refresh the test environment.11
12This deletes any reference to `outlines` in the modules dictionary and unsets the
13`OUTLINES_CACHE_DIR` environment variable if set. This is necessary because we
14are using a module variable to hold the cache.
15
16"""
17import sys18
19for key in list(sys.modules.keys()):20if "outlines" in key:21del sys.modules[key]22
23try:24del os.environ["OUTLINES_CACHE_DIR"]25except KeyError:26pass27
28
29@pytest.fixture30def test_cache(refresh_environment):31"""Initialize a temporary cache and delete it after the test has run."""32with tempfile.TemporaryDirectory() as tempdir:33os.environ["OUTLINES_CACHE_DIR"] = tempdir34import outlines35
36memory = outlines.get_cache()37assert memory.directory == tempdir38
39yield outlines.caching.cache()40
41memory.clear()42
43
44def test_get_cache(test_cache):45import outlines46
47memory = outlines.get_cache()48assert isinstance(memory, diskcache.Cache)49
50# If the cache is enabled then the size51# of `store` should not increase the52# second time `f` is called.53store = list()54
55@test_cache56def f(x):57store.append(1)58return x59
60f(1)61store_size = len(store)62
63f(1)64assert len(store) == store_size65
66f(2)67assert len(store) == store_size + 168
69
70def test_disable_cache(test_cache):71"""Make sure that we can disable the cache."""72import outlines73
74outlines.disable_cache()75
76# If the cache is disabled then the size77# of `store` should increase every time78# `f` is called.79store = list()80
81@test_cache82def f(x):83store.append(1)84return x85
86f(1)87store_size = len(store)88f(1)89assert len(store) == store_size + 190
91
92def test_clear_cache(test_cache):93"""Make sure that we can clear the cache."""94import outlines95
96store = list()97
98@test_cache99def f(x):100store.append(1)101return x102
103# The size of `store` does not increase since104# `f` is cached after the first run.105f(1)106store_size = len(store)107f(1)108assert len(store) == store_size109
110# The size of `store` should increase if we call `f`111# after clearing the cache.112outlines.clear_cache()113f(1)114assert len(store) == store_size + 1115
116
117def test_version_upgrade_cache_invalidate(test_cache, mocker):118"""Ensure we can change the signature of a cached function if we upgrade the version"""119
120import outlines.caching121
122def simulate_restart_outlines():123# clearing in-memory lru_cache which returns the diskcache in124# order to simulate a reload, we're not clearing the diskcache itself125outlines.caching.get_cache.cache_clear()126
127mocker.patch("outlines._version.__version__", new="0.0.0")128simulate_restart_outlines()129
130# initialize cache with signature of Tuple-of-3131@test_cache132def foo():133return (1, 2, 3)134
135a, b, c = foo()136
137# "restart" outlines without upgrading version138simulate_restart_outlines()139
140# change signature to Tuple-of-2141@test_cache142def foo():143return (1, 2)144
145# assert without version upgrade, old, bad cache is used146with pytest.raises(ValueError):147a, b = foo()148
149# "restart" outlines WITH version upgrade150mocker.patch("outlines._version.__version__", new="0.0.1")151simulate_restart_outlines()152
153# change signature to Tuple-of-2154@test_cache155def foo():156return (1, 2)157
158# assert with version upgrade, old cache is invalidated and new cache is used159a, b = foo()160