huge use of weakrefs to remove memoryleaks due to circular references

This commit is contained in:
Emmanuel Garette 2013-08-27 11:39:32 +02:00
parent 36def6533f
commit acd27fb56c
5 changed files with 73 additions and 65 deletions

View file

@ -54,9 +54,9 @@ def test_delete_session_persistent():
pass pass
else: else:
from tiramisu.setting import list_sessions, delete_session from tiramisu.setting import list_sessions, delete_session
assert 'test_persistent' in list_sessions assert 'test_persistent' in list_sessions()
delete_session('test_persistent') delete_session('test_persistent')
assert 'test_persistent' not in list_sessions assert 'test_persistent' not in list_sessions()
def test_create_persistent_retrieve(): def test_create_persistent_retrieve():
@ -68,14 +68,14 @@ def test_create_persistent_retrieve():
# storage is not persistent # storage is not persistent
pass pass
else: else:
assert c.b is False assert c.b is None
c.b = True c.b = True
assert c.b is True assert c.b is True
del(c) del(c)
c = Config(o, session_id='test_persistent', persistent=True) c = Config(o, session_id='test_persistent', persistent=True)
assert c.b is True assert c.b is True
from tiramisu.setting import list_sessions, delete_session from tiramisu.setting import list_sessions, delete_session
assert 'test_persistent' in list_sessions assert 'test_persistent' in list_sessions()
delete_session('test_persistent') delete_session('test_persistent')
c = Config(o, session_id='test_persistent', persistent=True) c = Config(o, session_id='test_persistent', persistent=True)
assert c.b is False assert c.b is None

View file

@ -20,6 +20,7 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
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, \
BaseInformation BaseInformation
@ -47,14 +48,14 @@ class SubConfig(BaseInformation):
).format(type(descr))) ).format(type(descr)))
self._impl_descr = descr self._impl_descr = descr
# sub option descriptions # sub option descriptions
if not isinstance(context, SubConfig): if not isinstance(context, weakref.ReferenceType):
raise ValueError('context must be a SubConfig') raise ValueError('context must be a Weakref')
self._impl_context = context self._impl_context = context
self._impl_path = subpath self._impl_path = subpath
def cfgimpl_reset_cache(self, only_expired=False, only=('values', def cfgimpl_reset_cache(self, only_expired=False, only=('values',
'settings')): 'settings')):
self.cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only) self._cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only)
def cfgimpl_get_home_by_path(self, path, force_permissive=False, def cfgimpl_get_home_by_path(self, path, force_permissive=False,
force_properties=None): force_properties=None):
@ -148,8 +149,8 @@ class SubConfig(BaseInformation):
__repr__ = __str__ __repr__ = __str__
def cfgimpl_get_context(self): def _cfgimpl_get_context(self):
return self._impl_context return self._impl_context()
def cfgimpl_get_description(self): def cfgimpl_get_description(self):
if self._impl_descr is None: if self._impl_descr is None:
@ -159,10 +160,10 @@ class SubConfig(BaseInformation):
return self._impl_descr return self._impl_descr
def cfgimpl_get_settings(self): def cfgimpl_get_settings(self):
return self.cfgimpl_get_context()._impl_settings return self._cfgimpl_get_context()._impl_settings
def cfgimpl_get_values(self): def cfgimpl_get_values(self):
return self.cfgimpl_get_context()._impl_values return self._cfgimpl_get_context()._impl_values
# ____________________________________________________________ # ____________________________________________________________
# attribute methods # attribute methods
@ -186,7 +187,7 @@ class SubConfig(BaseInformation):
self.cfgimpl_get_values().setitem(child, value, path, self.cfgimpl_get_values().setitem(child, value, path,
force_permissive=force_permissive) force_permissive=force_permissive)
else: else:
context = self.cfgimpl_get_context() context = self._cfgimpl_get_context()
path = context.cfgimpl_get_description().impl_get_path_by_opt( path = context.cfgimpl_get_description().impl_get_path_by_opt(
child._opt) child._opt)
context._setattr(path, value, force_permissive=force_permissive) context._setattr(path, value, force_permissive=force_permissive)
@ -222,7 +223,7 @@ class SubConfig(BaseInformation):
subpath = self._impl_path + '.' + name subpath = self._impl_path + '.' + name
# symlink options # symlink options
if isinstance(opt_or_descr, SymLinkOption): if isinstance(opt_or_descr, SymLinkOption):
context = self.cfgimpl_get_context() context = self._cfgimpl_get_context()
path = context.cfgimpl_get_description().impl_get_path_by_opt( path = context.cfgimpl_get_description().impl_get_path_by_opt(
opt_or_descr._opt) opt_or_descr._opt)
return context._getattr(path, validate=validate, return context._getattr(path, validate=validate,
@ -233,7 +234,7 @@ class SubConfig(BaseInformation):
opt_or_descr, True, False, path=subpath, opt_or_descr, True, False, path=subpath,
force_permissive=force_permissive, force_permissive=force_permissive,
force_properties=force_properties) force_properties=force_properties)
return SubConfig(opt_or_descr, self.cfgimpl_get_context(), subpath) return SubConfig(opt_or_descr, self._impl_context, subpath)
else: else:
return self.cfgimpl_get_values().getitem( return self.cfgimpl_get_values().getitem(
opt_or_descr, path=subpath, opt_or_descr, path=subpath,
@ -250,7 +251,7 @@ class SubConfig(BaseInformation):
:param byvalue: filter by the option's value :param byvalue: filter by the option's value
:returns: list of matching Option objects :returns: list of matching Option objects
""" """
return self.cfgimpl_get_context()._find(bytype, byname, byvalue, return self._cfgimpl_get_context()._find(bytype, byname, byvalue,
first=False, first=False,
type_=type_, type_=type_,
_subpath=self.cfgimpl_get_path() _subpath=self.cfgimpl_get_path()
@ -266,7 +267,7 @@ class SubConfig(BaseInformation):
:param byvalue: filter by the option's value :param byvalue: filter by the option's value
:returns: list of matching Option objects :returns: list of matching Option objects
""" """
return self.cfgimpl_get_context()._find( return self._cfgimpl_get_context()._find(
bytype, byname, byvalue, first=True, type_=type_, bytype, byname, byvalue, first=True, type_=type_,
_subpath=self.cfgimpl_get_path(), display_error=display_error) _subpath=self.cfgimpl_get_path(), display_error=display_error)
@ -400,14 +401,14 @@ class SubConfig(BaseInformation):
"option")) "option"))
if withoption is not None: if withoption is not None:
mypath = self.cfgimpl_get_path() mypath = self.cfgimpl_get_path()
for path in self.cfgimpl_get_context()._find(bytype=Option, for path in self._cfgimpl_get_context()._find(bytype=Option,
byname=withoption, byname=withoption,
byvalue=withvalue, byvalue=withvalue,
first=False, first=False,
type_='path', type_='path',
_subpath=mypath): _subpath=mypath):
path = '.'.join(path.split('.')[:-1]) path = '.'.join(path.split('.')[:-1])
opt = self.cfgimpl_get_context().cfgimpl_get_description( opt = self._cfgimpl_get_context().cfgimpl_get_description(
).impl_get_opt_by_path(path) ).impl_get_opt_by_path(path)
if mypath is not None: if mypath is not None:
if mypath == path: if mypath == path:
@ -453,7 +454,7 @@ class SubConfig(BaseInformation):
def cfgimpl_get_path(self): def cfgimpl_get_path(self):
descr = self.cfgimpl_get_description() descr = self.cfgimpl_get_description()
context_descr = self.cfgimpl_get_context().cfgimpl_get_description() context_descr = self._cfgimpl_get_context().cfgimpl_get_description()
return context_descr.impl_get_path_by_opt(descr) return context_descr.impl_get_path_by_opt(descr)
@ -504,7 +505,7 @@ class CommonConfig(SubConfig):
# ____________________________________________________________ # ____________________________________________________________
class Config(CommonConfig): class Config(CommonConfig):
"main configuration management entry" "main configuration management entry"
__slots__ = tuple() __slots__ = ('__weakref__', )
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
@ -522,7 +523,7 @@ class Config(CommonConfig):
storage = get_storage(self, session_id, persistent) storage = get_storage(self, session_id, persistent)
self._impl_settings = Settings(self, storage) self._impl_settings = Settings(self, storage)
self._impl_values = Values(self, storage) self._impl_values = Values(self, storage)
super(Config, self).__init__(descr, 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
self._impl_informations = {} self._impl_informations = {}

View file

@ -22,6 +22,7 @@
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
from copy import copy from copy import copy
import weakref
from tiramisu.error import (RequirementError, PropertiesOptionError, from tiramisu.error import (RequirementError, PropertiesOptionError,
ConstError, ConfigError) ConstError, ConfigError)
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -253,7 +254,7 @@ class Settings(object):
""" """
# generic owner # generic owner
self._owner = owners.user self._owner = owners.user
self.context = context self.context = weakref.ref(context)
import_lib = 'tiramisu.storage.{0}.setting'.format(storage.storage) import_lib = 'tiramisu.storage.{0}.setting'.format(storage.storage)
self._p_ = __import__(import_lib, globals(), locals(), ['Settings'], self._p_ = __import__(import_lib, globals(), locals(), ['Settings'],
-1).Settings(storage) -1).Settings(storage)
@ -287,7 +288,7 @@ class Settings(object):
if opt is not None and _path is None: if opt is not None and _path is None:
_path = self._get_opt_path(opt) _path = self._get_opt_path(opt)
self._p_.reset_properties(_path) self._p_.reset_properties(_path)
self.context.cfgimpl_reset_cache() self.context().cfgimpl_reset_cache()
def _getproperties(self, opt=None, path=None, is_apply_req=True): def _getproperties(self, opt=None, path=None, is_apply_req=True):
if opt is None: if opt is None:
@ -337,7 +338,7 @@ class Settings(object):
self._p_.reset_properties(path) self._p_.reset_properties(path)
else: else:
self._p_.setproperties(path, properties) self._p_.setproperties(path, properties)
self.context.cfgimpl_reset_cache() self.context().cfgimpl_reset_cache()
#____________________________________________________________ #____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, is_write, path, def validate_properties(self, opt_or_descr, is_descr, is_write, path,
@ -377,7 +378,7 @@ class Settings(object):
properties -= frozenset(('mandatory', 'frozen')) properties -= frozenset(('mandatory', 'frozen'))
else: else:
if 'mandatory' in properties and \ if 'mandatory' in properties and \
not self.context.cfgimpl_get_values()._isempty( not self.context().cfgimpl_get_values()._isempty(
opt_or_descr, value): opt_or_descr, value):
properties.remove('mandatory') properties.remove('mandatory')
if is_write and 'everything_frozen' in self_properties: if is_write and 'everything_frozen' in self_properties:
@ -494,7 +495,7 @@ class Settings(object):
" '{0}' with requirement on: " " '{0}' with requirement on: "
"'{1}'").format(path, reqpath)) "'{1}'").format(path, reqpath))
try: try:
value = self.context._getattr(reqpath, value = self.context()._getattr(reqpath,
force_permissive=True) force_permissive=True)
except PropertiesOptionError, err: except PropertiesOptionError, err:
if not transitive: if not transitive:
@ -519,4 +520,4 @@ class Settings(object):
return calc_properties return calc_properties
def _get_opt_path(self, opt): def _get_opt_path(self, opt):
return self.context.cfgimpl_get_description().impl_get_path_by_opt(opt) return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt)

View file

@ -52,7 +52,10 @@ class Storage(object):
_list_sessions.append(self.session_id) _list_sessions.append(self.session_id)
def __del__(self): def __del__(self):
try:
_list_sessions.remove(self.session_id) _list_sessions.remove(self.session_id)
except AttributeError:
pass
class Cache(object): class Cache(object):

View file

@ -19,6 +19,7 @@
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
from copy import copy from copy import copy
import weakref
from tiramisu.error import ConfigError, SlaveError from tiramisu.error import ConfigError, SlaveError
from tiramisu.setting import owners, multitypes, expires_time from tiramisu.setting import owners, multitypes, expires_time
from tiramisu.autolib import carry_out_calculation from tiramisu.autolib import carry_out_calculation
@ -40,7 +41,7 @@ class Values(object):
:param context: the context is the home config's values :param context: the context is the home config's values
""" """
self.context = 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) import_lib = 'tiramisu.storage.{0}.value'.format(storage.storage)
self._p_ = __import__(import_lib, globals(), locals(), ['Values'], self._p_ = __import__(import_lib, globals(), locals(), ['Values'],
@ -52,7 +53,7 @@ class Values(object):
:param opt: the `option.Option()` object :param opt: the `option.Option()` object
""" """
meta = self.context.cfgimpl_get_meta() meta = self.context().cfgimpl_get_meta()
if meta is not None: if meta is not None:
value = meta.cfgimpl_get_values()[opt] value = meta.cfgimpl_get_values()[opt]
else: else:
@ -105,10 +106,10 @@ class Values(object):
if path is None: if path is None:
path = self._get_opt_path(opt) path = self._get_opt_path(opt)
if self._p_.hasvalue(path): if self._p_.hasvalue(path):
setting = self.context.cfgimpl_get_settings() setting = self.context().cfgimpl_get_settings()
opt.impl_validate(opt.impl_getdefault(), self.context, opt.impl_validate(opt.impl_getdefault(), self.context(),
'validator' in setting) 'validator' in setting)
self.context.cfgimpl_reset_cache() self.context().cfgimpl_reset_cache()
if (opt.impl_is_multi() and if (opt.impl_is_multi() and
opt.impl_get_multitype() == multitypes.master): opt.impl_get_multitype() == multitypes.master):
for slave in opt.impl_get_master_slaves(): for slave in opt.impl_get_master_slaves():
@ -136,7 +137,7 @@ class Values(object):
callback, callback_params = opt._callback callback, callback_params = opt._callback
if callback_params is None: if callback_params is None:
callback_params = {} callback_params = {}
return carry_out_calculation(opt._name, config=self.context, return carry_out_calculation(opt._name, config=self.context(),
callback=callback, callback=callback,
callback_params=callback_params, callback_params=callback_params,
index=index) index=index)
@ -160,7 +161,7 @@ class Values(object):
return value return value
val = self._getitem(opt, path, validate, force_permissive, force_properties, val = self._getitem(opt, path, validate, force_permissive, force_properties,
validate_properties) validate_properties)
if 'expire' in self.context.cfgimpl_get_settings() and validate and \ if 'expire' in self.context().cfgimpl_get_settings() and validate and \
validate_properties and force_permissive is False and \ validate_properties and force_permissive is False and \
force_properties is None: force_properties is None:
if ntime is None: if ntime is None:
@ -172,7 +173,7 @@ class Values(object):
def _getitem(self, opt, path, validate, force_permissive, force_properties, def _getitem(self, opt, path, validate, force_permissive, force_properties,
validate_properties): validate_properties):
# options with callbacks # options with callbacks
setting = self.context.cfgimpl_get_settings() setting = self.context().cfgimpl_get_settings()
is_frozen = 'frozen' in setting[opt] is_frozen = 'frozen' in setting[opt]
# if value is callback and is not set # if value is callback and is not set
# or frozen with force_default_on_freeze # or frozen with force_default_on_freeze
@ -183,7 +184,7 @@ class Values(object):
if (opt.impl_is_multi() and if (opt.impl_is_multi() and
opt.impl_get_multitype() == multitypes.slave): opt.impl_get_multitype() == multitypes.slave):
masterp = self._get_opt_path(opt.impl_get_master_slaves()) masterp = self._get_opt_path(opt.impl_get_master_slaves())
mastervalue = getattr(self.context, masterp) mastervalue = getattr(self.context(), masterp)
lenmaster = len(mastervalue) lenmaster = len(mastervalue)
if lenmaster == 0: if lenmaster == 0:
value = [] value = []
@ -203,11 +204,11 @@ class Values(object):
elif is_frozen and 'force_default_on_freeze' in setting[opt]: elif is_frozen and 'force_default_on_freeze' in setting[opt]:
value = self._getdefault(opt) value = self._getdefault(opt)
if opt.impl_is_multi(): if opt.impl_is_multi():
value = Multi(value, self.context, opt, path, validate) value = Multi(value, self.context(), opt, path, validate)
else: else:
value = self._getvalue(opt, path, validate) value = self._getvalue(opt, path, validate)
if validate: if validate:
opt.impl_validate(value, self.context, 'validator' in setting) opt.impl_validate(value, self.context(), 'validator' in setting)
if self._is_default_owner(path) and \ if self._is_default_owner(path) and \
'force_store_value' in setting[opt]: 'force_store_value' in setting[opt]:
self.setitem(opt, value, path, is_write=False) self.setitem(opt, value, path, is_write=False)
@ -225,8 +226,8 @@ class Values(object):
# is_write is, for example, used with "force_store_value" # is_write is, for example, used with "force_store_value"
# user didn't change value, so not write # user didn't change value, so not write
# valid opt # valid opt
opt.impl_validate(value, self.context, opt.impl_validate(value, self.context(),
'validator' in self.context.cfgimpl_get_settings()) 'validator' in self.context().cfgimpl_get_settings())
if opt.impl_is_multi() and not isinstance(value, Multi): if opt.impl_is_multi() and not isinstance(value, Multi):
value = Multi(value, self.context, opt, path) value = Multi(value, self.context, opt, path)
self._setvalue(opt, path, value, force_permissive=force_permissive, self._setvalue(opt, path, value, force_permissive=force_permissive,
@ -235,14 +236,14 @@ class Values(object):
def _setvalue(self, opt, path, value, force_permissive=False, def _setvalue(self, opt, path, value, force_permissive=False,
force_properties=None, force_properties=None,
is_write=True, validate_properties=True): is_write=True, validate_properties=True):
self.context.cfgimpl_reset_cache() self.context().cfgimpl_reset_cache()
if validate_properties: if validate_properties:
setting = self.context.cfgimpl_get_settings() setting = self.context().cfgimpl_get_settings()
setting.validate_properties(opt, False, is_write, setting.validate_properties(opt, False, is_write,
value=value, path=path, value=value, path=path,
force_permissive=force_permissive, force_permissive=force_permissive,
force_properties=force_properties) force_properties=force_properties)
owner = self.context.cfgimpl_get_settings().getowner() owner = self.context().cfgimpl_get_settings().getowner()
self._p_.setvalue(path, value, owner) self._p_.setvalue(path, value, owner)
def getowner(self, opt): def getowner(self, opt):
@ -259,7 +260,7 @@ class Values(object):
def _getowner(self, path): def _getowner(self, path):
owner = self._p_.getowner(path, owners.default) owner = self._p_.getowner(path, owners.default)
meta = self.context.cfgimpl_get_meta() meta = self.context().cfgimpl_get_meta()
if owner is owners.default and meta is not None: if owner is owners.default and meta is not None:
owner = meta.cfgimpl_get_values()._getowner(path) owner = meta.cfgimpl_get_values()._getowner(path)
return owner return owner
@ -311,7 +312,7 @@ class Values(object):
:param opt: the `option.Option` object :param opt: the `option.Option` object
:returns: a string with points like "gc.dummy.my_option" :returns: a string with points like "gc.dummy.my_option"
""" """
return self.context.cfgimpl_get_description().impl_get_path_by_opt(opt) return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt)
# ____________________________________________________________ # ____________________________________________________________
# multi types # multi types
@ -330,6 +331,8 @@ class Multi(list):
""" """
self.opt = opt self.opt = opt
self.path = path self.path = path
if not isinstance(context, weakref.ReferenceType):
raise ValueError('context must be a Weakref')
self.context = context self.context = context
if not isinstance(value, list): if not isinstance(value, list):
value = [value] value = [value]
@ -341,13 +344,13 @@ class Multi(list):
def _valid_slave(self, value): def _valid_slave(self, value):
#if slave, had values until master's one #if slave, had values until master's one
masterp = self.context.cfgimpl_get_description().impl_get_path_by_opt( masterp = self.context().cfgimpl_get_description().impl_get_path_by_opt(
self.opt.impl_get_master_slaves()) self.opt.impl_get_master_slaves())
mastervalue = getattr(self.context, masterp) mastervalue = getattr(self.context(), masterp)
masterlen = len(mastervalue) masterlen = len(mastervalue)
valuelen = len(value) valuelen = len(value)
if valuelen > masterlen or (valuelen < masterlen and if valuelen > masterlen or (valuelen < masterlen and
not self.context.cfgimpl_get_values( not self.context().cfgimpl_get_values(
)._is_default_owner(self.path)): )._is_default_owner(self.path)):
raise SlaveError(_("invalid len for the slave: {0}" raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format( " which has {1} as master").format(
@ -360,7 +363,7 @@ class Multi(list):
def _valid_master(self, value): def _valid_master(self, value):
masterlen = len(value) masterlen = len(value)
values = self.context.cfgimpl_get_values() values = self.context().cfgimpl_get_values()
for slave in self.opt._master_slaves: for slave in self.opt._master_slaves:
path = values._get_opt_path(slave) path = values._get_opt_path(slave)
if not values._is_default_owner(path): if not values._is_default_owner(path):
@ -379,7 +382,7 @@ class Multi(list):
self._validate(value) self._validate(value)
#assume not checking mandatory property #assume not checking mandatory property
super(Multi, self).__setitem__(key, value) super(Multi, self).__setitem__(key, value)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def append(self, value, force=False): def append(self, value, force=False):
"""the list value can be updated (appened) """the list value can be updated (appened)
@ -390,7 +393,7 @@ class Multi(list):
raise SlaveError(_("cannot append a value on a multi option {0}" raise SlaveError(_("cannot append a value on a multi option {0}"
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.impl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
values = self.context.cfgimpl_get_values() values = self.context().cfgimpl_get_values()
if value is None and self.opt.impl_has_callback(): if value is None and self.opt.impl_has_callback():
value = values._getcallback_value(self.opt) value = values._getcallback_value(self.opt)
#Force None il return a list #Force None il return a list
@ -398,7 +401,7 @@ class Multi(list):
value = None value = None
self._validate(value) self._validate(value)
super(Multi, self).append(value) super(Multi, self).append(value)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
if not force and self.opt.impl_get_multitype() == multitypes.master: if not force and self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves(): for slave in self.opt.impl_get_master_slaves():
path = values._get_opt_path(slave) path = values._get_opt_path(slave)
@ -425,7 +428,7 @@ class Multi(list):
raise SlaveError(_("cannot sort multi option {0} if master or slave" raise SlaveError(_("cannot sort multi option {0} if master or slave"
"").format(self.opt._name)) "").format(self.opt._name))
super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse) super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def reverse(self): def reverse(self):
if self.opt.impl_get_multitype() in [multitypes.slave, if self.opt.impl_get_multitype() in [multitypes.slave,
@ -433,7 +436,7 @@ class Multi(list):
raise SlaveError(_("cannot reverse multi option {0} if master or " raise SlaveError(_("cannot reverse multi option {0} if master or "
"slave").format(self.opt._name)) "slave").format(self.opt._name))
super(Multi, self).reverse() super(Multi, self).reverse()
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def insert(self, index, obj): def insert(self, index, obj):
if self.opt.impl_get_multitype() in [multitypes.slave, if self.opt.impl_get_multitype() in [multitypes.slave,
@ -441,7 +444,7 @@ class Multi(list):
raise SlaveError(_("cannot insert multi option {0} if master or " raise SlaveError(_("cannot insert multi option {0} if master or "
"slave").format(self.opt._name)) "slave").format(self.opt._name))
super(Multi, self).insert(index, obj) super(Multi, self).insert(index, obj)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def extend(self, iterable): def extend(self, iterable):
if self.opt.impl_get_multitype() in [multitypes.slave, if self.opt.impl_get_multitype() in [multitypes.slave,
@ -449,7 +452,7 @@ class Multi(list):
raise SlaveError(_("cannot extend multi option {0} if master or " raise SlaveError(_("cannot extend multi option {0} if master or "
"slave").format(self.opt._name)) "slave").format(self.opt._name))
super(Multi, self).extend(iterable) super(Multi, self).extend(iterable)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def _validate(self, value): def _validate(self, value):
if value is not None: if value is not None:
@ -474,7 +477,7 @@ class Multi(list):
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.impl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves(): for slave in self.opt.impl_get_master_slaves():
values = self.context.cfgimpl_get_values() values = self.context().cfgimpl_get_values()
if not values.is_default_owner(slave): if not values.is_default_owner(slave):
#get multi without valid properties #get multi without valid properties
values.getitem(slave, values.getitem(slave,
@ -482,5 +485,5 @@ class Multi(list):
).pop(key, force=True) ).pop(key, force=True)
#set value without valid properties #set value without valid properties
ret = super(Multi, self).pop(key) ret = super(Multi, self).pop(key)
self.context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force) self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
return ret return ret