we can serialize Config now

This commit is contained in:
Emmanuel Garette 2013-09-22 20:57:52 +02:00
parent 972dff0a1c
commit c84d13a1c6
17 changed files with 354 additions and 108 deletions

View File

@ -327,23 +327,23 @@ def test_reset_properties():
cfg = Config(descr) cfg = Config(descr)
setting = cfg.cfgimpl_get_settings() setting = cfg.cfgimpl_get_settings()
option = cfg.cfgimpl_get_description().gc.dummy option = cfg.cfgimpl_get_description().gc.dummy
assert setting._p_.get_properties(cfg) == {} assert setting._p_.get_modified_properties() == {}
setting.append('frozen') setting.append('frozen')
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'cache', 'validator'))} assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'cache', 'validator'))}
setting.reset() setting.reset()
assert setting._p_.get_properties(cfg) == {} assert setting._p_.get_modified_properties() == {}
setting[option].append('test') setting[option].append('test')
assert setting._p_.get_properties(cfg) == {'gc.dummy': set(('test',))} assert setting._p_.get_modified_properties() == {'gc.dummy': set(('test',))}
setting.reset() setting.reset()
assert setting._p_.get_properties(cfg) == {'gc.dummy': set(('test',))} assert setting._p_.get_modified_properties() == {'gc.dummy': set(('test',))}
setting.append('frozen') setting.append('frozen')
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))} assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))}
setting.reset(option) setting.reset(option)
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator', 'cache'))} assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache'))}
setting[option].append('test') setting[option].append('test')
assert setting._p_.get_properties(cfg) == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))} assert setting._p_.get_modified_properties() == {None: set(('frozen', 'expire', 'validator', 'cache')), 'gc.dummy': set(('test',))}
setting.reset(all_properties=True) setting.reset(all_properties=True)
assert setting._p_.get_properties(cfg) == {} assert setting._p_.get_modified_properties() == {}
raises(ValueError, 'setting.reset(all_properties=True, opt=option)') raises(ValueError, 'setting.reset(all_properties=True, opt=option)')
a = descr.wantref a = descr.wantref
setting[a].append('test') setting[a].append('test')

View File

@ -1,5 +1,9 @@
from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \ from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
OptionDescription OptionDescription
from tiramisu.config import Config
from tiramisu.setting import owners
from tiramisu.storage import delete_session
from tiramisu.error import ConfigError
from pickle import dumps, loads from pickle import dumps, loads
@ -152,3 +156,95 @@ def test_no_state_attr():
_no_state(q.o.b) _no_state(q.o.b)
_no_state(q.o.u) _no_state(q.o.u)
_no_state(q.o.s) _no_state(q.o.s)
def test_state_config():
val1 = BoolOption('val1', "")
maconfig = OptionDescription('rootconfig', '', [val1])
try:
cfg = Config(maconfig, persistent=True, session_id='29090931')
except ValueError:
cfg = Config(maconfig, session_id='29090931')
cfg._impl_test = True
a = dumps(cfg)
q = loads(a)
_diff_opt(maconfig, q.cfgimpl_get_description())
assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values()
assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties()
assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives()
try:
delete_session('29090931')
except ConfigError:
pass
def test_state_properties():
val1 = BoolOption('val1', "")
maconfig = OptionDescription('rootconfig', '', [val1])
try:
cfg = Config(maconfig, persistent=True, session_id='29090932')
except ValueError:
cfg = Config(maconfig, session_id='29090932')
cfg._impl_test = True
cfg.read_write()
cfg.cfgimpl_get_settings()[val1].append('test')
a = dumps(cfg)
q = loads(a)
_diff_opt(maconfig, q.cfgimpl_get_description())
assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values()
assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties()
assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives()
try:
delete_session('29090931')
except ConfigError:
pass
def test_state_values():
val1 = BoolOption('val1', "")
maconfig = OptionDescription('rootconfig', '', [val1])
try:
cfg = Config(maconfig, persistent=True, session_id='29090933')
except ValueError:
cfg = Config(maconfig, session_id='29090933')
cfg._impl_test = True
cfg.val1 = True
a = dumps(cfg)
q = loads(a)
_diff_opt(maconfig, q.cfgimpl_get_description())
assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values()
assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties()
assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives()
q.val1 = False
#assert cfg.val1 is True
assert q.val1 is False
try:
delete_session('29090931')
except ConfigError:
pass
def test_state_values_owner():
val1 = BoolOption('val1', "")
maconfig = OptionDescription('rootconfig', '', [val1])
try:
cfg = Config(maconfig, persistent=True, session_id='29090934')
except ValueError:
cfg = Config(maconfig, session_id='29090934')
cfg._impl_test = True
owners.addowner('newowner')
cfg.cfgimpl_get_settings().setowner(owners.newowner)
cfg.val1 = True
a = dumps(cfg)
q = loads(a)
_diff_opt(maconfig, q.cfgimpl_get_description())
assert cfg.cfgimpl_get_values().get_modified_values() == q.cfgimpl_get_values().get_modified_values()
assert cfg.cfgimpl_get_settings().get_modified_properties() == q.cfgimpl_get_settings().get_modified_properties()
assert cfg.cfgimpl_get_settings().get_modified_permissives() == q.cfgimpl_get_settings().get_modified_permissives()
q.val1 = False
nval1 = q.cfgimpl_get_description().val1
assert q.getowner(nval1) == owners.newowner
try:
delete_session('29090931')
except ConfigError:
pass

View File

@ -24,7 +24,8 @@ 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 from tiramisu.setting import groups, Settings, default_encoding
from tiramisu.storage import get_storages from tiramisu.storage import get_storages, get_storage, set_storage, \
_impl_getstate_setting
from tiramisu.value import Values from tiramisu.value import Values
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -521,7 +522,7 @@ class CommonConfig(SubConfig):
# ____________________________________________________________ # ____________________________________________________________
class Config(CommonConfig): class Config(CommonConfig):
"main configuration management entry" "main configuration management entry"
__slots__ = ('__weakref__', ) __slots__ = ('__weakref__', '_impl_test')
def __init__(self, descr, session_id=None, persistent=False): def __init__(self, descr, session_id=None, persistent=False):
""" Configuration option management master class """ Configuration option management master class
@ -542,6 +543,43 @@ class Config(CommonConfig):
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
#undocumented option used only in test script
self._impl_test = False
def __getstate__(self):
if self._impl_meta is not None:
raise ConfigError('cannot serialize Config with meta')
slots = set()
for subclass in self.__class__.__mro__:
if subclass is not object:
slots.update(subclass.__slots__)
slots -= frozenset(['_impl_context', '__weakref__'])
state = {}
for slot in slots:
try:
state[slot] = getattr(self, slot)
except AttributeError:
pass
storage = self._impl_values._p_._storage
if not storage.serializable:
raise ConfigError('this storage is not serialisable, could be a '
'none persistent storage')
state['_storage'] = {'session_id': storage.session_id,
'persistent': storage.persistent}
state['_impl_setting'] = _impl_getstate_setting()
return state
def __setstate__(self, state):
for key, value in state.items():
if key not in ['_storage', '_impl_setting']:
setattr(self, key, value)
set_storage(**state['_impl_setting'])
self._impl_context = weakref.ref(self)
self._impl_settings.context = weakref.ref(self)
self._impl_values.context = weakref.ref(self)
storage = get_storage(test=self._impl_test, **state['_storage'])
self._impl_values._impl_setstate(storage)
self._impl_settings._impl_setstate(storage)
def cfgimpl_reset_cache(self, def cfgimpl_reset_cache(self,
only_expired=False, only_expired=False,

View File

@ -242,8 +242,9 @@ class BaseOption(object):
:param descr: the parent :class:`tiramisu.option.OptionDescription` :param descr: the parent :class:`tiramisu.option.OptionDescription`
""" """
self._stated = True self._stated = True
self._impl_convert_consistencies(descr) for func in dir(self):
self._impl_convert_requires(descr) if func.startswith('_impl_convert_'):
getattr(self, func)(descr)
try: try:
self._state_readonly = self._readonly self._state_readonly = self._readonly
except AttributeError: except AttributeError:
@ -294,8 +295,9 @@ class BaseOption(object):
:type descr: :class:`tiramisu.option.OptionDescription` :type descr: :class:`tiramisu.option.OptionDescription`
""" """
self._impl_convert_consistencies(descr, load=True) for func in dir(self):
self._impl_convert_requires(descr, load=True) if func.startswith('_impl_convert_'):
getattr(self, func)(descr, load=True)
try: try:
self._readonly = self._state_readonly self._readonly = self._state_readonly
del(self._state_readonly) del(self._state_readonly)
@ -595,23 +597,6 @@ class Option(BaseOption):
else: else:
self._state_callback = (callback, cllbck_prms) self._state_callback = (callback, cllbck_prms)
# serialize
def _impl_getstate(self, descr):
"""the under the hood stuff that need to be done
before the serialization.
"""
self._stated = True
self._impl_convert_callbacks(descr)
super(Option, self)._impl_getstate(descr)
# unserialize
def _impl_setstate(self, descr):
"""the under the hood stuff that need to be done
before the serialization.
"""
self._impl_convert_callbacks(descr, load=True)
super(Option, self)._impl_setstate(descr)
class ChoiceOption(Option): class ChoiceOption(Option):
"""represents a choice out of several objects. """represents a choice out of several objects.

View File

@ -105,7 +105,7 @@ rw_remove = set(['permissive', 'everything_frozen', 'mandatory'])
# ____________________________________________________________ # ____________________________________________________________
class _NameSpace: class _NameSpace(object):
"""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)
when attribute is added, we cannot delete it when attribute is added, we cannot delete it
@ -591,3 +591,23 @@ class Settings(object):
:returns: path :returns: path
""" """
return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt) return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt)
def get_modified_properties(self):
return self._p_.get_modified_properties()
def get_modified_permissives(self):
return self._p_.get_modified_permissives()
def __getstate__(self):
return {'_p_': self._p_, '_owner': str(self._owner)}
def _impl_setstate(self, storage):
self._p_._storage = storage
def __setstate__(self, states):
self._p_ = states['_p_']
try:
self._owner = getattr(owners, states['_owner'])
except AttributeError:
owners.addowner(states['_owner'])
self._owner = getattr(owners, states['_owner'])

View File

@ -68,7 +68,7 @@ class StorageType(object):
storage_type = StorageType() storage_type = StorageType()
def set_storage(name, **args): def set_storage(name, **kwargs):
"""Change storage's configuration """Change storage's configuration
:params name: is the storage name. If storage is already set, cannot :params name: is the storage name. If storage is already set, cannot
@ -77,16 +77,31 @@ def set_storage(name, **args):
Other attributes are differents according to the selected storage's name Other attributes are differents according to the selected storage's name
""" """
storage_type.set(name) storage_type.set(name)
settings = storage_type.get().Setting() setting = storage_type.get().setting
for option, value in args.items(): for option, value in kwargs.items():
try: try:
getattr(settings, option) getattr(setting, option)
setattr(settings, option, value) setattr(setting, option, value)
except AttributeError: except AttributeError:
raise ValueError(_('option {0} not already exists in storage {1}' raise ValueError(_('option {0} not already exists in storage {1}'
'').format(option, name)) '').format(option, name))
def _impl_getstate_setting():
setting = storage_type.get().setting
state = {'name': storage_type.storage_type}
for var in dir(setting):
if not var.startswith('_'):
state[var] = getattr(setting, var)
return state
def get_storage(session_id, persistent, test):
"""all used when __setstate__ a Config
"""
return storage_type.get().Storage(session_id, persistent, test)
def get_storages(context, session_id, persistent): def get_storages(context, session_id, persistent):
def gen_id(config): def gen_id(config):
return str(id(config)) + str(time()) return str(id(config)) + str(time())

View File

@ -26,6 +26,6 @@ use it. But if something goes wrong, you will lost your modifications.
""" """
from .value import Values from .value import Values
from .setting import Settings from .setting import Settings
from .storage import Setting, Storage, list_sessions, delete_session from .storage import setting, Storage, list_sessions, delete_session
__all__ = (Setting, Values, Settings, Storage, list_sessions, delete_session) __all__ = (setting, Values, Settings, Storage, list_sessions, delete_session)

View File

@ -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 ..cache import Cache from ..util import Cache
class Settings(Cache): class Settings(Cache):
@ -50,12 +50,21 @@ class Settings(Cache):
except KeyError: except KeyError:
pass pass
def get_properties(self, context):
return self._properties
# permissive # permissive
def setpermissive(self, path, permissive): def setpermissive(self, path, permissive):
self._permissives[path] = frozenset(permissive) self._permissives[path] = frozenset(permissive)
def getpermissive(self, path=None): def getpermissive(self, path=None):
return self._permissives.get(path, frozenset()) return self._permissives.get(path, frozenset())
def get_modified_properties(self):
"""return all modified settings in a dictionary
example: {'path1': set(['prop1', 'prop2'])}
"""
return self._properties
def get_modified_permissives(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
return self._permissives

View File

@ -18,9 +18,10 @@
# ____________________________________________________________ # ____________________________________________________________
from tiramisu.i18n import _ from tiramisu.i18n import _
from tiramisu.error import ConfigError from tiramisu.error import ConfigError
from ..util import SerializeObject
class Setting(object): class Setting(SerializeObject):
"""Dictionary storage has no particular setting. """Dictionary storage has no particular setting.
""" """
pass pass
@ -39,15 +40,18 @@ def delete_session(session_id):
class Storage(object): class Storage(object):
__slots__ = ('session_id', 'values', 'settings') __slots__ = ('session_id', 'persistent')
storage = 'dictionary' storage = 'dictionary'
#if object could be serializable
serializable = True
def __init__(self, session_id, persistent): def __init__(self, session_id, persistent, test=False):
if session_id in _list_sessions: if not test and session_id in _list_sessions:
raise ValueError(_('session already used')) raise ValueError(_('session already used'))
if persistent: if persistent:
raise ValueError(_('a dictionary cannot be persistent')) raise ValueError(_('a dictionary cannot be persistent'))
self.session_id = session_id self.session_id = session_id
self.persistent = persistent
_list_sessions.append(self.session_id) _list_sessions.append(self.session_id)
def __del__(self): def __del__(self):

View File

@ -18,7 +18,7 @@
# #
# ____________________________________________________________ # ____________________________________________________________
from ..cache import Cache from ..util import Cache
class Values(Cache): class Values(Cache):

View File

@ -24,6 +24,6 @@ You should not configure differents Configs with same session_id.
""" """
from .value import Values from .value import Values
from .setting import Settings from .setting import Settings
from .storage import Setting, Storage, list_sessions, delete_session from .storage import setting, Storage, list_sessions, delete_session
__all__ = (Setting, Values, Settings, Storage, list_sessions, delete_session) __all__ = (setting, Values, Settings, Storage, list_sessions, delete_session)

View File

@ -30,22 +30,22 @@ class Settings(Sqlite3DB):
permissives_table += 'primary key, permissives text)' permissives_table += 'primary key, permissives text)'
# should init cache too # should init cache too
super(Settings, self).__init__(storage) super(Settings, self).__init__(storage)
self.storage.execute(settings_table, commit=False) self._storage.execute(settings_table, commit=False)
self.storage.execute(permissives_table) self._storage.execute(permissives_table)
# propertives # propertives
def setproperties(self, path, properties): def setproperties(self, path, properties):
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("DELETE FROM property WHERE path = ?", (path,), self._storage.execute("DELETE FROM property WHERE path = ?", (path,),
False) False)
self.storage.execute("INSERT INTO property(path, properties) VALUES " self._storage.execute("INSERT INTO property(path, properties) VALUES "
"(?, ?)", (path, "(?, ?)", (path,
self._sqlite_encode(properties))) self._sqlite_encode(properties)))
def getproperties(self, path, default_properties): def getproperties(self, path, default_properties):
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
value = self.storage.select("SELECT properties FROM property WHERE " value = self._storage.select("SELECT properties FROM property WHERE "
"path = ?", (path,)) "path = ?", (path,))
if value is None: if value is None:
return set(default_properties) return set(default_properties)
else: else:
@ -53,42 +53,53 @@ class Settings(Sqlite3DB):
def hasproperties(self, path): def hasproperties(self, path):
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
return self.storage.select("SELECT properties FROM property WHERE " return self._storage.select("SELECT properties FROM property WHERE "
"path = ?", (path,)) is not None "path = ?", (path,)) is not None
def reset_all_propertives(self): def reset_all_propertives(self):
self.storage.execute("DELETE FROM property") self._storage.execute("DELETE FROM property")
def reset_properties(self, path): def reset_properties(self, path):
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("DELETE FROM property WHERE path = ?", (path,)) self._storage.execute("DELETE FROM property WHERE path = ?", (path,))
def get_properties(self, context):
"""return all properties in a dictionary
"""
ret = {}
for path, properties in self.storage.select("SELECT * FROM property",
only_one=False):
path = self._sqlite_decode_path(path)
properties = self._sqlite_decode(properties)
ret[path] = properties
return ret
# permissive # permissive
def setpermissive(self, path, permissive): def setpermissive(self, path, permissive):
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("DELETE FROM permissive WHERE path = ?", (path,), self._storage.execute("DELETE FROM permissive WHERE path = ?", (path,),
False) False)
self.storage.execute("INSERT INTO permissive(path, permissives) " self._storage.execute("INSERT INTO permissive(path, permissives) "
"VALUES (?, ?)", (path, "VALUES (?, ?)", (path,
self._sqlite_encode(permissive) self._sqlite_encode(permissive)
)) ))
def getpermissive(self, path='_none'): def getpermissive(self, path='_none'):
permissives = self.storage.select("SELECT permissives FROM " permissives = self._storage.select("SELECT permissives FROM "
"permissive WHERE path = ?", "permissive WHERE path = ?",
(path,)) (path,))
if permissives is None: if permissives is None:
return frozenset() return frozenset()
else: else:
return frozenset(self._sqlite_decode(permissives[0])) return frozenset(self._sqlite_decode(permissives[0]))
def get_modified_properties(self):
"""return all modified settings in a dictionary
example: {'path1': set(['prop1', 'prop2'])}
"""
ret = {}
for path, properties in self._storage.select("SELECT * FROM property",
only_one=False):
path = self._sqlite_decode_path(path)
ret[path] = self._sqlite_decode(properties)
return ret
def get_modified_permissives(self):
"""return all modified permissives in a dictionary
example: {'path1': set(['perm1', 'perm2'])}
"""
ret = {}
for path, permissives in self._storage.select("SELECT * FROM permissive",
only_one=False):
path = self._sqlite_decode_path(path)
ret[path] = self._sqlite_decode(permissives)
return ret

View File

@ -17,8 +17,11 @@
# 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 cPickle import loads, dumps try:
from ..cache import Cache from cPickle import loads, dumps
except ImportError:
from pickle import loads, dumps
from ..util import Cache
class Sqlite3DB(Cache): class Sqlite3DB(Cache):

View File

@ -22,9 +22,10 @@ from os import unlink
from os.path import basename, splitext, join from os.path import basename, splitext, join
import sqlite3 import sqlite3
from glob import glob from glob import glob
from ..util import SerializeObject
class Setting(object): class Setting(SerializeObject):
""":param extension: database file extension (by default: db) """:param extension: database file extension (by default: db)
:param dir_database: root database directory (by default: /tmp) :param dir_database: root database directory (by default: /tmp)
""" """
@ -52,13 +53,17 @@ def delete_session(session_id):
class Storage(object): class Storage(object):
__slots__ = ('_conn', '_cursor', 'persistent', '_session_id') __slots__ = ('_conn', '_cursor', 'persistent', 'session_id', 'serializable')
storage = 'sqlite3' storage = 'sqlite3'
def __init__(self, session_id, persistent): def __init__(self, session_id, persistent, test=False):
self.persistent = persistent self.persistent = persistent
self._session_id = session_id if self.persistent:
self._conn = sqlite3.connect(_gen_filename(self._session_id)) self.serializable = True
else:
self.serializable = False
self.session_id = session_id
self._conn = sqlite3.connect(_gen_filename(self.session_id))
self._conn.text_factory = str self._conn.text_factory = str
self._cursor = self._conn.cursor() self._cursor = self._conn.cursor()
@ -80,4 +85,4 @@ class Storage(object):
self._cursor.close() self._cursor.close()
self._conn.close() self._conn.close()
if not self.persistent: if not self.persistent:
delete_session(self._session_id) delete_session(self.session_id)

View File

@ -32,11 +32,11 @@ class Values(Sqlite3DB):
super(Values, self).__init__(storage) super(Values, self).__init__(storage)
values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary ' values_table = 'CREATE TABLE IF NOT EXISTS value(path text primary '
values_table += 'key, value text, owner text)' values_table += 'key, value text, owner text)'
self.storage.execute(values_table, commit=False) self._storage.execute(values_table, commit=False)
informations_table = 'CREATE TABLE IF NOT EXISTS information(key text primary ' informations_table = 'CREATE TABLE IF NOT EXISTS information(key text primary '
informations_table += 'key, value text)' informations_table += 'key, value text)'
self.storage.execute(informations_table) self._storage.execute(informations_table)
for owner in self.storage.select("SELECT DISTINCT owner FROM value", tuple(), False): for owner in self._storage.select("SELECT DISTINCT owner FROM value", tuple(), False):
try: try:
getattr(owners, owner[0]) getattr(owners, owner[0])
except AttributeError: except AttributeError:
@ -44,7 +44,7 @@ class Values(Sqlite3DB):
# sqlite # sqlite
def _sqlite_select(self, path): def _sqlite_select(self, path):
return self.storage.select("SELECT value FROM value WHERE path = ?", return self._storage.select("SELECT value FROM value WHERE path = ?",
(path,)) (path,))
# value # value
@ -54,7 +54,7 @@ class Values(Sqlite3DB):
""" """
self.resetvalue(path) self.resetvalue(path)
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("INSERT INTO value(path, value, owner) VALUES " self._storage.execute("INSERT INTO value(path, value, owner) VALUES "
"(?, ?, ?)", (path, self._sqlite_encode(value), "(?, ?, ?)", (path, self._sqlite_encode(value),
str(owner))) str(owner)))
@ -76,14 +76,14 @@ class Values(Sqlite3DB):
"""remove value means delete value in storage """remove value means delete value in storage
""" """
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("DELETE FROM value WHERE path = ?", (path,)) self._storage.execute("DELETE FROM value WHERE path = ?", (path,))
def get_modified_values(self): def get_modified_values(self):
"""return all values in a dictionary """return all values in a dictionary
example: {option1: (owner, 'value1'), option2: (owner, 'value2')} example: {option1: (owner, 'value1'), option2: (owner, 'value2')}
""" """
ret = {} ret = {}
for path, value, owner in self.storage.select("SELECT * FROM value", for path, value, owner in self._storage.select("SELECT * FROM value",
only_one=False): only_one=False):
path = self._sqlite_decode_path(path) path = self._sqlite_decode_path(path)
owner = getattr(owners, owner) owner = getattr(owners, owner)
@ -97,7 +97,7 @@ class Values(Sqlite3DB):
"""change owner for an option """change owner for an option
""" """
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
self.storage.execute("UPDATE value SET owner = ? WHERE path = ?", self._storage.execute("UPDATE value SET owner = ? WHERE path = ?",
(str(owner), path)) (str(owner), path))
def getowner(self, path, default): def getowner(self, path, default):
@ -105,7 +105,7 @@ class Values(Sqlite3DB):
return: owner object return: owner object
""" """
path = self._sqlite_encode_path(path) path = self._sqlite_encode_path(path)
owner = self.storage.select("SELECT owner FROM value WHERE path = ?", owner = self._storage.select("SELECT owner FROM value WHERE path = ?",
(path,)) (path,))
if owner is None: if owner is None:
return default return default
@ -125,9 +125,9 @@ class Values(Sqlite3DB):
:param key: information's key (ex: "help", "doc" :param key: information's key (ex: "help", "doc"
:param value: information's value (ex: "the help string") :param value: information's value (ex: "the help string")
""" """
self.storage.execute("DELETE FROM information WHERE key = ?", (key,), self._storage.execute("DELETE FROM information WHERE key = ?", (key,),
False) False)
self.storage.execute("INSERT INTO information(key, value) VALUES " self._storage.execute("INSERT INTO information(key, value) VALUES "
"(?, ?)", (key, self._sqlite_encode(value))) "(?, ?)", (key, self._sqlite_encode(value)))
def get_information(self, key): def get_information(self, key):
@ -135,7 +135,7 @@ class Values(Sqlite3DB):
:param key: the item string (ex: "help") :param key: the item string (ex: "help")
""" """
value = self.storage.select("SELECT value FROM information WHERE key = ?", value = self._storage.select("SELECT value FROM information WHERE key = ?",
(key,)) (key,))
if value is None: if value is None:
raise ValueError("not found") raise ValueError("not found")

View File

@ -17,15 +17,65 @@
# 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.setting import owners
class SerializeObject(object):
def __getstate__(self):
ret = {}
for key in dir(self):
if not key.startswith('__'):
ret[key] = getattr(self, key)
return ret
class Cache(object): class Cache(object):
__slots__ = ('_cache', 'storage') __slots__ = ('_cache', '_storage')
key_is_path = False key_is_path = False
def __init__(self, storage): def __init__(self, storage):
self._cache = {} self._cache = {}
self.storage = storage self._storage = storage
def __getstate__(self):
slots = set()
for subclass in self.__class__.__mro__:
if subclass is not object:
slots.update(subclass.__slots__)
slots -= frozenset(['__weakref__', '_storage'])
states = {}
for slot in slots:
try:
value = getattr(self, slot)
#value has owners object, need 'str()' it
if slot == '_values':
_value = {}
for key, values in value.items():
vals = list(values)
vals[0] = str(vals[0])
_value[key] = tuple(vals)
states[slot] = _value
else:
states[slot] = value
except AttributeError:
pass
return states
def __setstate__(self, states):
for key, value in states.items():
#value has owners object, need to reconstruct it
if key == '_values':
_value = {}
for key_, values_ in value.items():
vals = list(values_)
try:
vals[0] = getattr(owners, vals[0])
except AttributeError:
owners.addowner(vals[0])
vals[0] = getattr(owners, vals[0])
_value[key_] = tuple(vals)
value = _value
setattr(self, key, value)
def setcache(self, path, val, time): def setcache(self, path, val, time):
self._cache[path] = (val, time) self._cache[path] = (val, time)

View File

@ -204,7 +204,9 @@ class Values(object):
if not no_value_slave: if not no_value_slave:
try: try:
value = self._getcallback_value(opt, max_len=lenmaster) value = self._getcallback_value(opt, max_len=lenmaster)
except ConfigError as config_error: except ConfigError as err:
# cannot assign config_err directly in python 3.3
config_error = err
value = None value = None
# should not raise PropertiesOptionError if option is # should not raise PropertiesOptionError if option is
# mandatory # mandatory
@ -359,6 +361,14 @@ class Values(object):
raise ValueError(_("information's item" raise ValueError(_("information's item"
" not found: {0}").format(key)) " not found: {0}").format(key))
def __getstate__(self):
return {'_p_': self._p_}
def _impl_setstate(self, storage):
self._p_._storage = storage
def __setstate__(self, states):
self._p_ = states['_p_']
# ____________________________________________________________ # ____________________________________________________________
# multi types # multi types
@ -386,7 +396,7 @@ class Multi(list):
value = [value] value = [value]
if validate and self.opt.impl_get_multitype() == multitypes.slave: if validate and self.opt.impl_get_multitype() == multitypes.slave:
value = self._valid_slave(value, setitem) value = self._valid_slave(value, setitem)
elif self.opt.impl_get_multitype() == multitypes.master: elif validate and self.opt.impl_get_multitype() == multitypes.master:
self._valid_master(value) self._valid_master(value)
super(Multi, self).__init__(value) super(Multi, self).__init__(value)