1
0
forked from VimPlug/jedi

Remove old version of FS cache automatically

This commit is contained in:
Takafumi Arakaki
2013-03-19 21:32:01 +01:00
parent 960dd38e2c
commit f8d3339f2f
3 changed files with 66 additions and 4 deletions

View File

@@ -25,6 +25,7 @@ try:
import cPickle as pickle import cPickle as pickle
except: except:
import pickle import pickle
import shutil
from jedi._compatibility import json from jedi._compatibility import json
from jedi import settings from jedi import settings
@@ -219,6 +220,20 @@ def save_module(path, name, parser, pickling=True):
class _ModulePickling(object): class _ModulePickling(object):
version = 1
"""
Version number (integer) for file system cache.
Increment this number when there are any incompatible changes in
parser representation classes. For example, the following changes
are regarded as incompatible.
- Class name is changed.
- Class is moved to another module.
- Defined slot of the class is changed.
"""
def __init__(self): def __init__(self):
self.__index = None self.__index = None
self.py_version = '%s.%s' % sys.version_info[:2] self.py_version = '%s.%s' % sys.version_info[:2]
@@ -259,9 +274,16 @@ class _ModulePickling(object):
if self.__index is None: if self.__index is None:
try: try:
with open(self._get_path('index.json')) as f: with open(self._get_path('index.json')) as f:
self.__index = json.load(f) data = json.load(f)
except IOError: except IOError:
self.__index = {} self.__index = {}
else:
# 0 means version is not defined (= always delete cache):
if data.get('version', 0) < self.version:
self.delete_cache()
self.__index = {}
else:
self.__index = data['index']
return self.__index return self.__index
def _remove_old_modules(self): def _remove_old_modules(self):
@@ -272,10 +294,14 @@ class _ModulePickling(object):
self._index # reload index self._index # reload index
def _flush_index(self): def _flush_index(self):
data = {'version': self.version, 'index': self._index}
with open(self._get_path('index.json'), 'w') as f: with open(self._get_path('index.json'), 'w') as f:
json.dump(self._index, f) json.dump(data, f)
self.__index = None self.__index = None
def delete_cache(self):
shutil.rmtree(settings.cache_directory)
def _get_hashed_path(self, path): def _get_hashed_path(self, path):
return self._get_path('%s_%s.pkl' % (self.py_version, hash(path))) return self._get_path('%s_%s.pkl' % (self.py_version, hash(path)))

View File

@@ -65,6 +65,18 @@ def pytest_generate_tests(metafunc):
refactor.collect_dir_tests(base_dir, test_files)) refactor.collect_dir_tests(base_dir, test_files))
@pytest.fixture()
def isolated_jedi_cache(monkeypatch, tmpdir):
"""
Set `jedi.settings.cache_directory` to a temporary directory during test.
Same as `clean_jedi_cache`, but create the temporary directory for
each test case (scope='function').
"""
settings = base.jedi.settings
monkeypatch.setattr(settings, 'cache_directory', str(tmpdir))
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def clean_jedi_cache(request): def clean_jedi_cache(request):
""" """

View File

@@ -1,3 +1,5 @@
import pytest
from jedi import settings from jedi import settings
from jedi.cache import ParserCacheItem, _ModulePickling from jedi.cache import ParserCacheItem, _ModulePickling
@@ -21,10 +23,32 @@ def test_modulepickling_change_cache_dir(monkeypatch, tmpdir):
monkeypatch.setattr(settings, 'cache_directory', dir_1) monkeypatch.setattr(settings, 'cache_directory', dir_1)
ModulePickling.save_module(path_1, item_1) ModulePickling.save_module(path_1, item_1)
cached = ModulePickling.load_module(path_1, item_1.change_time - 1) cached = load_stored_item(ModulePickling, path_1, item_1)
assert cached == item_1.parser assert cached == item_1.parser
monkeypatch.setattr(settings, 'cache_directory', dir_2) monkeypatch.setattr(settings, 'cache_directory', dir_2)
ModulePickling.save_module(path_2, item_2) ModulePickling.save_module(path_2, item_2)
cached = ModulePickling.load_module(path_1, item_1.change_time - 1) cached = load_stored_item(ModulePickling, path_1, item_1)
assert cached is None assert cached is None
def load_stored_item(cache, path, item):
"""Load `item` stored at `path` in `cache`."""
return cache.load_module(path, item.change_time - 1)
@pytest.mark.usefixtures("isolated_jedi_cache")
def test_modulepickling_delete_incompatible_cache():
item = ParserCacheItem('fake parser')
path = 'fake path'
cache1 = _ModulePickling()
cache1.version = 1
cache1.save_module(path, item)
cached1 = load_stored_item(cache1, path, item)
assert cached1 == item.parser
cache2 = _ModulePickling()
cache2.version = 2
cached2 = load_stored_item(cache2, path, item)
assert cached2 is None