storage no more in setting.py, code is now in storage/__init__.py
This commit is contained in:
parent
18fc5db4ac
commit
22bfbb9fa4
17 changed files with 437 additions and 196 deletions
121
test/test_state.py
Normal file
121
test/test_state.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
|
||||||
|
OptionDescription
|
||||||
|
from pickle import dumps, loads
|
||||||
|
|
||||||
|
|
||||||
|
def _get_slots(opt):
|
||||||
|
slots = set()
|
||||||
|
for subclass in opt.__class__.__mro__:
|
||||||
|
if subclass is not object:
|
||||||
|
slots.update(subclass.__slots__)
|
||||||
|
return slots
|
||||||
|
|
||||||
|
|
||||||
|
def _no_state(opt):
|
||||||
|
for attr in _get_slots(opt):
|
||||||
|
if 'state' in attr:
|
||||||
|
try:
|
||||||
|
getattr(opt, attr)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise Exception('opt should have already attribute {0}'.format(attr))
|
||||||
|
|
||||||
|
|
||||||
|
def _diff_opt(opt1, opt2):
|
||||||
|
attr1 = set(_get_slots(opt1))
|
||||||
|
attr2 = set(_get_slots(opt2))
|
||||||
|
diff1 = attr1 - attr2
|
||||||
|
diff2 = attr2 - attr1
|
||||||
|
if diff1 != set():
|
||||||
|
raise Exception('more attribute in opt1 {0}'.format(list(diff1)))
|
||||||
|
if diff2 != set():
|
||||||
|
raise Exception('more attribute in opt2 {0}'.format(list(diff2)))
|
||||||
|
for attr in attr1:
|
||||||
|
if attr in ['_cache_paths']:
|
||||||
|
continue
|
||||||
|
err1 = False
|
||||||
|
err2 = False
|
||||||
|
val1 = None
|
||||||
|
val2 = None
|
||||||
|
try:
|
||||||
|
val1 = getattr(opt1, attr)
|
||||||
|
except:
|
||||||
|
err1 = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
val2 = getattr(opt2, attr)
|
||||||
|
except:
|
||||||
|
err2 = True
|
||||||
|
assert err1 == err2
|
||||||
|
if val1 is None:
|
||||||
|
assert val1 == val2
|
||||||
|
elif attr == '_children':
|
||||||
|
assert val1[0] == val2[0]
|
||||||
|
for index, _opt in enumerate(val1[1]):
|
||||||
|
assert _opt._name == val2[1][index]._name
|
||||||
|
elif attr == '_requires':
|
||||||
|
assert val1[0][0][0]._name == val2[0][0][0]._name
|
||||||
|
assert val1[0][0][1:] == val2[0][0][1:]
|
||||||
|
elif attr == '_opt':
|
||||||
|
assert val1._name == val2._name
|
||||||
|
elif attr == '_consistencies':
|
||||||
|
# dict is only a cache
|
||||||
|
if isinstance(val1, list):
|
||||||
|
for index, consistency in enumerate(val1):
|
||||||
|
assert consistency[0] == val2[index][0]
|
||||||
|
assert consistency[1]._name == val2[index][1]._name
|
||||||
|
else:
|
||||||
|
assert val1 == val2
|
||||||
|
|
||||||
|
|
||||||
|
def test_diff_opt():
|
||||||
|
b = BoolOption('b', '')
|
||||||
|
u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
|
||||||
|
#u.impl_add_consistency('not_equal', b)
|
||||||
|
s = SymLinkOption('s', u)
|
||||||
|
o = OptionDescription('o', '', [b, u, s])
|
||||||
|
o1 = OptionDescription('o1', '', [o])
|
||||||
|
|
||||||
|
a = dumps(o1)
|
||||||
|
q = loads(a)
|
||||||
|
_diff_opt(o1, q)
|
||||||
|
_diff_opt(o1.o, q.o)
|
||||||
|
_diff_opt(o1.o.b, q.o.b)
|
||||||
|
_diff_opt(o1.o.u, q.o.u)
|
||||||
|
_diff_opt(o1.o.s, q.o.s)
|
||||||
|
|
||||||
|
|
||||||
|
def test_diff_opt_cache():
|
||||||
|
b = BoolOption('b', '')
|
||||||
|
u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
|
||||||
|
u.impl_add_consistency('not_equal', b)
|
||||||
|
s = SymLinkOption('s', u)
|
||||||
|
o = OptionDescription('o', '', [b, u, s])
|
||||||
|
o1 = OptionDescription('o1', '', [o])
|
||||||
|
o1.impl_build_cache()
|
||||||
|
|
||||||
|
a = dumps(o1)
|
||||||
|
q = loads(a)
|
||||||
|
_diff_opt(o1, q)
|
||||||
|
_diff_opt(o1.o, q.o)
|
||||||
|
_diff_opt(o1.o.b, q.o.b)
|
||||||
|
_diff_opt(o1.o.u, q.o.u)
|
||||||
|
_diff_opt(o1.o.s, q.o.s)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_state_attr():
|
||||||
|
# all _state_xxx attributes should be deleted
|
||||||
|
b = BoolOption('b', '')
|
||||||
|
u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
|
||||||
|
s = SymLinkOption('s', u)
|
||||||
|
o = OptionDescription('o', '', [b, u, s])
|
||||||
|
o1 = OptionDescription('o1', '', [o])
|
||||||
|
|
||||||
|
a = dumps(o1)
|
||||||
|
q = loads(a)
|
||||||
|
_no_state(q)
|
||||||
|
_no_state(q.o)
|
||||||
|
_no_state(q.o.b)
|
||||||
|
_no_state(q.o.u)
|
||||||
|
_no_state(q.o.s)
|
|
@ -5,7 +5,7 @@ import autopath
|
||||||
from tiramisu.config import Config
|
from tiramisu.config import Config
|
||||||
from tiramisu.option import BoolOption, OptionDescription
|
from tiramisu.option import BoolOption, OptionDescription
|
||||||
from tiramisu.setting import owners
|
from tiramisu.setting import owners
|
||||||
from tiramisu.setting import list_sessions, delete_session
|
from tiramisu.storage import list_sessions, delete_session
|
||||||
|
|
||||||
|
|
||||||
def test_non_persistent():
|
def test_non_persistent():
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
import weakref
|
import weakref
|
||||||
from tiramisu.error import PropertiesOptionError, ConfigError
|
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||||
from tiramisu.option import OptionDescription, Option, SymLinkOption
|
from tiramisu.option import OptionDescription, Option, SymLinkOption
|
||||||
from tiramisu.setting import groups, Settings, default_encoding, get_storage
|
from tiramisu.setting import groups, Settings, default_encoding
|
||||||
|
from tiramisu.storage import get_storage
|
||||||
from tiramisu.value import Values
|
from tiramisu.value import Values
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
|
|
||||||
|
@ -535,9 +536,9 @@ class Config(CommonConfig):
|
||||||
:param persistent: if persistent, don't delete storage when leaving
|
:param persistent: if persistent, don't delete storage when leaving
|
||||||
:type persistent: `boolean`
|
:type persistent: `boolean`
|
||||||
"""
|
"""
|
||||||
storage = get_storage(self, session_id, persistent)
|
settings, values = get_storage(self, session_id, persistent)
|
||||||
self._impl_settings = Settings(self, storage)
|
self._impl_settings = Settings(self, settings)
|
||||||
self._impl_values = Values(self, storage)
|
self._impl_values = Values(self, values)
|
||||||
super(Config, self).__init__(descr, weakref.ref(self))
|
super(Config, self).__init__(descr, weakref.ref(self))
|
||||||
self._impl_build_all_paths()
|
self._impl_build_all_paths()
|
||||||
self._impl_meta = None
|
self._impl_meta = None
|
||||||
|
@ -575,9 +576,9 @@ class Config(CommonConfig):
|
||||||
# child._impl_meta = self
|
# child._impl_meta = self
|
||||||
|
|
||||||
# self._impl_children = children
|
# self._impl_children = children
|
||||||
# storage = get_storage(self, session_id, persistent)
|
# settings, values = get_storage(self, session_id, persistent)
|
||||||
# self._impl_settings = Settings(self, storage)
|
# self._impl_settings = Settings(self, settings)
|
||||||
# self._impl_values = Values(self, storage)
|
# self._impl_values = Values(self, values)
|
||||||
# self._impl_meta = None
|
# self._impl_meta = None
|
||||||
|
|
||||||
# def cfgimpl_get_children(self):
|
# def cfgimpl_get_children(self):
|
||||||
|
|
|
@ -658,7 +658,7 @@ else:
|
||||||
|
|
||||||
|
|
||||||
class SymLinkOption(BaseOption):
|
class SymLinkOption(BaseOption):
|
||||||
__slots__ = ('_name', '_opt', '_state_opt', '_consistencies')
|
__slots__ = ('_name', '_opt', '_state_opt')
|
||||||
_opt_type = 'symlink'
|
_opt_type = 'symlink'
|
||||||
#not return _opt consistencies
|
#not return _opt consistencies
|
||||||
_consistencies = {}
|
_consistencies = {}
|
||||||
|
|
|
@ -24,7 +24,7 @@ from time import time
|
||||||
from copy import copy
|
from copy import copy
|
||||||
import weakref
|
import weakref
|
||||||
from tiramisu.error import (RequirementError, PropertiesOptionError,
|
from tiramisu.error import (RequirementError, PropertiesOptionError,
|
||||||
ConstError, ConfigError)
|
ConstError)
|
||||||
from tiramisu.i18n import _
|
from tiramisu.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,26 +38,6 @@ rw_append = set(['frozen', 'disabled', 'validator', 'hidden'])
|
||||||
default_properties = ('expire', 'validator')
|
default_properties = ('expire', 'validator')
|
||||||
|
|
||||||
|
|
||||||
class StorageType:
|
|
||||||
default_storage = 'dictionary'
|
|
||||||
storage_type = None
|
|
||||||
|
|
||||||
def set_storage(self, name):
|
|
||||||
if self.storage_type is not None:
|
|
||||||
raise ConfigError(_('storage_type is already set, cannot rebind it'))
|
|
||||||
self.storage_type = name
|
|
||||||
|
|
||||||
def get_storage(self):
|
|
||||||
if self.storage_type is None:
|
|
||||||
self.storage_type = self.default_storage
|
|
||||||
storage = self.storage_type
|
|
||||||
return 'tiramisu.storage.{0}.storage'.format(
|
|
||||||
storage)
|
|
||||||
|
|
||||||
|
|
||||||
storage_type = StorageType()
|
|
||||||
|
|
||||||
|
|
||||||
class _NameSpace:
|
class _NameSpace:
|
||||||
"""convenient class that emulates a module
|
"""convenient class that emulates a module
|
||||||
and builds constants (that is, unique names)"""
|
and builds constants (that is, unique names)"""
|
||||||
|
@ -203,39 +183,6 @@ class Property(object):
|
||||||
return str(list(self._properties))
|
return str(list(self._properties))
|
||||||
|
|
||||||
|
|
||||||
def set_storage(name, **args):
|
|
||||||
storage_type.set_storage(name)
|
|
||||||
settings = __import__(storage_type.get_storage(), globals(), locals(),
|
|
||||||
['Setting']).Setting()
|
|
||||||
for option, value in args.items():
|
|
||||||
try:
|
|
||||||
getattr(settings, option)
|
|
||||||
setattr(settings, option, value)
|
|
||||||
except AttributeError:
|
|
||||||
raise ValueError(_('option {0} not already exists in storage {1}'
|
|
||||||
'').format(option, name))
|
|
||||||
|
|
||||||
|
|
||||||
def get_storage(context, session_id, persistent):
|
|
||||||
def gen_id(config):
|
|
||||||
return str(id(config)) + str(time())
|
|
||||||
|
|
||||||
if session_id is None:
|
|
||||||
session_id = gen_id(context)
|
|
||||||
return __import__(storage_type.get_storage(), globals(), locals(),
|
|
||||||
['Storage']).Storage(session_id, persistent)
|
|
||||||
|
|
||||||
|
|
||||||
def list_sessions():
|
|
||||||
return __import__(storage_type.get_storage(), globals(), locals(),
|
|
||||||
['list_sessions']).list_sessions()
|
|
||||||
|
|
||||||
|
|
||||||
def delete_session(session_id):
|
|
||||||
return __import__(storage_type.get_storage(), globals(), locals(),
|
|
||||||
['delete_session']).delete_session(session_id)
|
|
||||||
|
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
class Settings(object):
|
class Settings(object):
|
||||||
"``Config()``'s configuration options"
|
"``Config()``'s configuration options"
|
||||||
|
@ -254,9 +201,7 @@ class Settings(object):
|
||||||
# generic owner
|
# generic owner
|
||||||
self._owner = owners.user
|
self._owner = owners.user
|
||||||
self.context = weakref.ref(context)
|
self.context = weakref.ref(context)
|
||||||
import_lib = 'tiramisu.storage.{0}.setting'.format(storage.storage)
|
self._p_ = storage
|
||||||
self._p_ = __import__(import_lib, globals(), locals(), ['Settings']
|
|
||||||
).Settings(storage)
|
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
# properties methods
|
# properties methods
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# The original `Config` design model is unproudly borrowed from
|
||||||
|
# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
|
# the whole pypy projet is under MIT licence
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
"""Storage connections, executions and managements.
|
||||||
|
|
||||||
|
Storage is basic components used to set informations in DB
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from time import time
|
||||||
|
from tiramisu.error import ConfigError
|
||||||
|
from tiramisu.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
class StorageType(object):
|
||||||
|
default_storage = 'dictionary'
|
||||||
|
storage_type = None
|
||||||
|
mod = None
|
||||||
|
|
||||||
|
def set(self, name):
|
||||||
|
if self.storage_type is not None:
|
||||||
|
raise ConfigError(_('storage_type is already set, cannot rebind it'))
|
||||||
|
self.storage_type = name
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
if self.storage_type is None:
|
||||||
|
self.storage_type = self.default_storage
|
||||||
|
storage = self.storage_type
|
||||||
|
if self.mod is None:
|
||||||
|
modulepath = 'tiramisu.storage.{0}'.format(storage)
|
||||||
|
mod = __import__(modulepath)
|
||||||
|
for token in modulepath.split(".")[1:]:
|
||||||
|
mod = getattr(mod, token)
|
||||||
|
self.mod = mod
|
||||||
|
return self.mod
|
||||||
|
|
||||||
|
|
||||||
|
storage_type = StorageType()
|
||||||
|
|
||||||
|
|
||||||
|
def set_storage(name, **args):
|
||||||
|
storage_type.set(name)
|
||||||
|
settings = storage_type.get().Setting()
|
||||||
|
for option, value in args.items():
|
||||||
|
try:
|
||||||
|
getattr(settings, option)
|
||||||
|
setattr(settings, option, value)
|
||||||
|
except AttributeError:
|
||||||
|
raise ValueError(_('option {0} not already exists in storage {1}'
|
||||||
|
'').format(option, name))
|
||||||
|
|
||||||
|
|
||||||
|
def get_storage(context, session_id, persistent):
|
||||||
|
def gen_id(config):
|
||||||
|
return str(id(config)) + str(time())
|
||||||
|
|
||||||
|
if session_id is None:
|
||||||
|
session_id = gen_id(context)
|
||||||
|
imp = storage_type.get()
|
||||||
|
storage = imp.Storage(session_id, persistent)
|
||||||
|
return imp.Settings(storage), imp.Values(storage)
|
||||||
|
|
||||||
|
|
||||||
|
def list_sessions():
|
||||||
|
return storage_type.get().list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_session(session_id):
|
||||||
|
return storage_type.get().delete_session(session_id)
|
||||||
|
|
||||||
|
|
||||||
|
#__all__ = (,)
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"default plugin for storage: set it in a simple dictionary"
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ____________________________________________________________
|
||||||
|
from .value import Values
|
||||||
|
from .setting import Settings
|
||||||
|
from .storage import Storage, list_sessions, delete_session
|
||||||
|
|
||||||
|
__all__ = (Values, Settings, Storage, list_sessions, delete_session)
|
61
tiramisu/storage/dictionary/cache.py
Normal file
61
tiramisu/storage/dictionary/cache.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"default plugin for cache: set it in a simple dictionary"
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
|
||||||
|
class Cache(object):
|
||||||
|
__slots__ = ('_cache', 'storage')
|
||||||
|
key_is_path = False
|
||||||
|
|
||||||
|
def __init__(self, storage):
|
||||||
|
self._cache = {}
|
||||||
|
self.storage = storage
|
||||||
|
|
||||||
|
def setcache(self, cache_type, path, val, time):
|
||||||
|
self._cache[path] = (val, time)
|
||||||
|
|
||||||
|
def getcache(self, cache_type, path, exp):
|
||||||
|
value, created = self._cache[path]
|
||||||
|
if exp < created:
|
||||||
|
return True, value
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
def hascache(self, cache_type, path):
|
||||||
|
""" path is in the cache
|
||||||
|
|
||||||
|
:param cache_type: value | property
|
||||||
|
:param path: the path's option
|
||||||
|
"""
|
||||||
|
return path in self._cache
|
||||||
|
|
||||||
|
def reset_expired_cache(self, cache_type, exp):
|
||||||
|
for key in tuple(self._cache.keys()):
|
||||||
|
val, created = self._cache[key]
|
||||||
|
if exp > created:
|
||||||
|
del(self._cache[key])
|
||||||
|
|
||||||
|
def reset_all_cache(self, cache_type):
|
||||||
|
"empty the cache"
|
||||||
|
self._cache.clear()
|
||||||
|
|
||||||
|
def get_cached(self, cache_type, context):
|
||||||
|
"""return all values in a dictionary
|
||||||
|
example: {'path1': ('value1', 'time1'), 'path2': ('value2', 'time2')}
|
||||||
|
"""
|
||||||
|
return self._cache
|
|
@ -17,7 +17,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from tiramisu.storage.dictionary.storage import Cache
|
from .cache import Cache
|
||||||
|
|
||||||
|
|
||||||
class Settings(Cache):
|
class Settings(Cache):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"default plugin for cache: set it in a simple dictionary"
|
"default plugin for storage: set it in a simple dictionary"
|
||||||
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -38,7 +38,7 @@ def delete_session(session_id):
|
||||||
|
|
||||||
|
|
||||||
class Storage(object):
|
class Storage(object):
|
||||||
__slots__ = ('session_id',)
|
__slots__ = ('session_id', 'values', 'settings')
|
||||||
storage = 'dictionary'
|
storage = 'dictionary'
|
||||||
|
|
||||||
def __init__(self, session_id, persistent):
|
def __init__(self, session_id, persistent):
|
||||||
|
@ -54,45 +54,3 @@ class Storage(object):
|
||||||
_list_sessions.remove(self.session_id)
|
_list_sessions.remove(self.session_id)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Cache(object):
|
|
||||||
__slots__ = ('_cache', 'storage')
|
|
||||||
key_is_path = False
|
|
||||||
|
|
||||||
def __init__(self, storage):
|
|
||||||
self._cache = {}
|
|
||||||
self.storage = storage
|
|
||||||
|
|
||||||
def setcache(self, cache_type, path, val, time):
|
|
||||||
self._cache[path] = (val, time)
|
|
||||||
|
|
||||||
def getcache(self, cache_type, path, exp):
|
|
||||||
value, created = self._cache[path]
|
|
||||||
if exp < created:
|
|
||||||
return True, value
|
|
||||||
return False, None
|
|
||||||
|
|
||||||
def hascache(self, cache_type, path):
|
|
||||||
""" path is in the cache
|
|
||||||
|
|
||||||
:param cache_type: value | property
|
|
||||||
:param path: the path's option
|
|
||||||
"""
|
|
||||||
return path in self._cache
|
|
||||||
|
|
||||||
def reset_expired_cache(self, cache_type, exp):
|
|
||||||
for key in tuple(self._cache.keys()):
|
|
||||||
val, created = self._cache[key]
|
|
||||||
if exp > created:
|
|
||||||
del(self._cache[key])
|
|
||||||
|
|
||||||
def reset_all_cache(self, cache_type):
|
|
||||||
"empty the cache"
|
|
||||||
self._cache.clear()
|
|
||||||
|
|
||||||
def get_cached(self, cache_type, context):
|
|
||||||
"""return all values in a dictionary
|
|
||||||
example: {'path1': ('value1', 'time1'), 'path2': ('value2', 'time2')}
|
|
||||||
"""
|
|
||||||
return self._cache
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
||||||
from tiramisu.storage.dictionary.storage import Cache
|
from .cache import Cache
|
||||||
|
|
||||||
|
|
||||||
class Values(Cache):
|
class Values(Cache):
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"set storage in sqlite3"
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ____________________________________________________________
|
||||||
|
from .value import Values
|
||||||
|
from .setting import Settings
|
||||||
|
from .storage import Storage, list_sessions, delete_session
|
||||||
|
|
||||||
|
__all__ = (Values, Settings, Storage, list_sessions, delete_session)
|
98
tiramisu/storage/sqlite3/cache.py
Normal file
98
tiramisu/storage/sqlite3/cache.py
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"sqlite3 cache"
|
||||||
|
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# ____________________________________________________________
|
||||||
|
from pickle import dumps, loads
|
||||||
|
|
||||||
|
|
||||||
|
class Cache(object):
|
||||||
|
__slots__ = ('storage',)
|
||||||
|
key_is_path = True
|
||||||
|
|
||||||
|
def __init__(self, cache_type, storage):
|
||||||
|
self.storage = storage
|
||||||
|
cache_table = 'CREATE TABLE IF NOT EXISTS cache_{0}(path '.format(
|
||||||
|
cache_type)
|
||||||
|
cache_table += 'text primary key, value text, time real)'
|
||||||
|
self.storage.execute(cache_table)
|
||||||
|
|
||||||
|
# value
|
||||||
|
def _sqlite_decode_path(self, path):
|
||||||
|
if path == '_none':
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
def _sqlite_encode_path(self, path):
|
||||||
|
if path is None:
|
||||||
|
return '_none'
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
def _sqlite_decode(self, value):
|
||||||
|
return loads(value)
|
||||||
|
|
||||||
|
def _sqlite_encode(self, value):
|
||||||
|
if isinstance(value, list):
|
||||||
|
value = list(value)
|
||||||
|
return dumps(value)
|
||||||
|
|
||||||
|
def setcache(self, cache_type, path, val, time):
|
||||||
|
convert_value = self._sqlite_encode(val)
|
||||||
|
path = self._sqlite_encode_path(path)
|
||||||
|
self.storage.execute("DELETE FROM cache_{0} WHERE path = ?".format(
|
||||||
|
cache_type), (path,), False)
|
||||||
|
self.storage.execute("INSERT INTO cache_{0}(path, value, time) "
|
||||||
|
"VALUES (?, ?, ?)".format(cache_type),
|
||||||
|
(path, convert_value, time))
|
||||||
|
|
||||||
|
def getcache(self, cache_type, path, exp):
|
||||||
|
path = self._sqlite_encode_path(path)
|
||||||
|
cached = self.storage.select("SELECT value FROM cache_{0} WHERE "
|
||||||
|
"path = ? AND time >= ?".format(
|
||||||
|
cache_type), (path, exp))
|
||||||
|
if cached is None:
|
||||||
|
return False, None
|
||||||
|
else:
|
||||||
|
return True, self._sqlite_decode(cached[0])
|
||||||
|
|
||||||
|
def hascache(self, cache_type, path):
|
||||||
|
path = self._sqlite_encode_path(path)
|
||||||
|
return self.storage.select("SELECT value FROM cache_{0} WHERE "
|
||||||
|
"path = ?".format(cache_type),
|
||||||
|
(path,)) is not None
|
||||||
|
|
||||||
|
def reset_expired_cache(self, cache_type, exp):
|
||||||
|
self.storage.execute("DELETE FROM cache_{0} WHERE time < ?".format(
|
||||||
|
cache_type), (exp,))
|
||||||
|
|
||||||
|
def reset_all_cache(self, cache_type):
|
||||||
|
self.storage.execute("DELETE FROM cache_{0}".format(cache_type))
|
||||||
|
|
||||||
|
def get_cached(self, cache_type, context):
|
||||||
|
"""return all values in a dictionary
|
||||||
|
example: {'path1': ('value1', 'time1'), 'path2': ('value2', 'time2')}
|
||||||
|
"""
|
||||||
|
ret = {}
|
||||||
|
for path, value, time in self.storage.select("SELECT * FROM cache_{0}"
|
||||||
|
"".format(cache_type),
|
||||||
|
only_one=False):
|
||||||
|
path = self._sqlite_decode_path(path)
|
||||||
|
value = self._sqlite_decode(value)
|
||||||
|
ret[path] = (value, time)
|
||||||
|
return ret
|
|
@ -17,7 +17,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from tiramisu.storage.sqlite3.storage import Cache
|
from .cache import Cache
|
||||||
|
|
||||||
|
|
||||||
class Settings(Cache):
|
class Settings(Cache):
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
||||||
from pickle import dumps, loads
|
|
||||||
from os import unlink
|
from os import unlink
|
||||||
from os.path import basename, splitext, join
|
from os.path import basename, splitext, join
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
@ -79,81 +78,3 @@ class Storage(object):
|
||||||
self._conn.close()
|
self._conn.close()
|
||||||
if not self.persistent:
|
if not self.persistent:
|
||||||
delete_session(self._session_id)
|
delete_session(self._session_id)
|
||||||
|
|
||||||
|
|
||||||
class Cache(object):
|
|
||||||
__slots__ = ('storage',)
|
|
||||||
key_is_path = True
|
|
||||||
|
|
||||||
def __init__(self, cache_type, storage):
|
|
||||||
self.storage = storage
|
|
||||||
cache_table = 'CREATE TABLE IF NOT EXISTS cache_{0}(path '.format(
|
|
||||||
cache_type)
|
|
||||||
cache_table += 'text primary key, value text, time real)'
|
|
||||||
self.storage.execute(cache_table)
|
|
||||||
|
|
||||||
# value
|
|
||||||
def _sqlite_decode_path(self, path):
|
|
||||||
if path == '_none':
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return path
|
|
||||||
|
|
||||||
def _sqlite_encode_path(self, path):
|
|
||||||
if path is None:
|
|
||||||
return '_none'
|
|
||||||
else:
|
|
||||||
return path
|
|
||||||
|
|
||||||
def _sqlite_decode(self, value):
|
|
||||||
return loads(value)
|
|
||||||
|
|
||||||
def _sqlite_encode(self, value):
|
|
||||||
if isinstance(value, list):
|
|
||||||
value = list(value)
|
|
||||||
return dumps(value)
|
|
||||||
|
|
||||||
def setcache(self, cache_type, path, val, time):
|
|
||||||
convert_value = self._sqlite_encode(val)
|
|
||||||
path = self._sqlite_encode_path(path)
|
|
||||||
self.storage.execute("DELETE FROM cache_{0} WHERE path = ?".format(
|
|
||||||
cache_type), (path,), False)
|
|
||||||
self.storage.execute("INSERT INTO cache_{0}(path, value, time) "
|
|
||||||
"VALUES (?, ?, ?)".format(cache_type),
|
|
||||||
(path, convert_value, time))
|
|
||||||
|
|
||||||
def getcache(self, cache_type, path, exp):
|
|
||||||
path = self._sqlite_encode_path(path)
|
|
||||||
cached = self.storage.select("SELECT value FROM cache_{0} WHERE "
|
|
||||||
"path = ? AND time >= ?".format(
|
|
||||||
cache_type), (path, exp))
|
|
||||||
if cached is None:
|
|
||||||
return False, None
|
|
||||||
else:
|
|
||||||
return True, self._sqlite_decode(cached[0])
|
|
||||||
|
|
||||||
def hascache(self, cache_type, path):
|
|
||||||
path = self._sqlite_encode_path(path)
|
|
||||||
return self.storage.select("SELECT value FROM cache_{0} WHERE "
|
|
||||||
"path = ?".format(cache_type),
|
|
||||||
(path,)) is not None
|
|
||||||
|
|
||||||
def reset_expired_cache(self, cache_type, exp):
|
|
||||||
self.storage.execute("DELETE FROM cache_{0} WHERE time < ?".format(
|
|
||||||
cache_type), (exp,))
|
|
||||||
|
|
||||||
def reset_all_cache(self, cache_type):
|
|
||||||
self.storage.execute("DELETE FROM cache_{0}".format(cache_type))
|
|
||||||
|
|
||||||
def get_cached(self, cache_type, context):
|
|
||||||
"""return all values in a dictionary
|
|
||||||
example: {'path1': ('value1', 'time1'), 'path2': ('value2', 'time2')}
|
|
||||||
"""
|
|
||||||
ret = {}
|
|
||||||
for path, value, time in self.storage.select("SELECT * FROM cache_{0}"
|
|
||||||
"".format(cache_type),
|
|
||||||
only_one=False):
|
|
||||||
path = self._sqlite_decode_path(path)
|
|
||||||
value = self._sqlite_decode(value)
|
|
||||||
ret[path] = (value, time)
|
|
||||||
return ret
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#
|
#
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
||||||
from tiramisu.storage.sqlite3.storage import Cache
|
from .cache import Cache
|
||||||
from tiramisu.setting import owners
|
from tiramisu.setting import owners
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,7 @@ class Values(object):
|
||||||
"""
|
"""
|
||||||
self.context = weakref.ref(context)
|
self.context = weakref.ref(context)
|
||||||
# the storage type is dictionary or sqlite3
|
# the storage type is dictionary or sqlite3
|
||||||
import_lib = 'tiramisu.storage.{0}.value'.format(storage.storage)
|
self._p_ = storage
|
||||||
self._p_ = __import__(import_lib, globals(), locals(), ['Values'],
|
|
||||||
).Values(storage)
|
|
||||||
|
|
||||||
def _getdefault(self, opt):
|
def _getdefault(self, opt):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue