1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
""" An object that can be initialized from a preferences node. """
# Standard library imports.
import logging
# Enthought library imports.
from traits.api import HasTraits, Instance, Str, Unicode
# Local imports.
from .i_preferences import IPreferences
from .package_globals import get_default_preferences
# Logging.
logger = logging.getLogger(__name__)
class PreferencesHelper(HasTraits):
""" An object that can be initialized from a preferences node. """
#### 'PreferencesHelper' interface ########################################
# The preferences node used by the helper. If this trait is not set then
# the package-global default preferences node is used.
#
# fixme: This introduces a 'sneaky' global reference to the preferences
# node!
preferences = Instance(IPreferences)
# The path to the preference node that contains the preferences that we
# use to initialize instances of this class.
preferences_path = Str
###########################################################################
# 'object' interface.
###########################################################################
def __init__(self, **traits):
""" Constructor. """
super(PreferencesHelper, self).__init__(**traits)
# Initialize the object's traits from the preferences node.
if self.preferences:
self._initialize(self.preferences)
return
###########################################################################
# Private interface.
###########################################################################
#### Trait initializers ###################################################
def _preferences_default(self):
""" Trait initializer. """
# If no specific preferences node is set then we use the package-wide
# global node.
return get_default_preferences()
#### Trait change handlers ################################################
def _anytrait_changed(self, trait_name, old, new):
""" Static trait change handler. """
# If we were the one that set the trait (because the underlying
# preferences node changed) then do nothing.
if self.preferences and self._is_preference_trait(trait_name):
self.preferences.set('%s.%s' % (self._get_path(), trait_name), new)
return
def _preferences_changed(self, old, new):
""" Static trait change handler. """
# Stop listening to the old preferences node.
if old is not None:
old.remove_preferences_listener(
self._preferences_changed_listener, self._get_path()
)
if new is not None:
# Initialize with the new preferences node (this also adds a
# listener for preferences being changed in the new node).
self._initialize(new, notify=True)
return
#### Other observer pattern listeners #####################################
def _preferences_changed_listener(self, node, key, old, new):
""" Listener called when a preference value is changed. """
if key in self.trait_names():
setattr(self, key, self._get_value(key, new))
return
#### Methods ##############################################################
def _get_path(self):
""" Return the path to our preferences node. """
if len(self.preferences_path) > 0:
path = self.preferences_path
else:
path = getattr(self, 'PREFERENCES_PATH', None)
if path is None:
raise SystemError('no preferences path, %s' % self)
else:
logger.warn('DEPRECATED: use "preferences_path" %s' % self)
return path
def _get_value(self, trait_name, value):
""" Get the actual value to set.
This method makes sure that any required work is done to convert the
preference value from a string. Str traits or those with the metadata
'is_str=True' will just be passed the string itself.
"""
trait = self.trait(trait_name)
handler = trait.handler
# If the trait type is 'Str' or Unicode then we just take the raw value.
if isinstance(handler, (Str, Unicode)) or trait.is_str:
pass
# Otherwise, we eval it!
else:
try:
value = eval(value)
# If the eval fails then there is probably a syntax error, but
# we will let the handler validation throw the exception.
except:
pass
if handler.validate is not None:
# Any traits have a validator of None.
validated = handler.validate(self, trait_name, value)
else:
validated = value
return validated
def _initialize(self, preferences, notify=False):
""" Initialize the object's traits from the preferences node. """
path = self._get_path()
keys = preferences.keys(path)
traits_to_set = {}
for trait_name in self.trait_names():
if trait_name in keys:
key = '%s.%s' % (path, trait_name)
value = self._get_value(trait_name, preferences.get(key))
traits_to_set[trait_name] = value
self.set(trait_change_notify=notify, **traits_to_set)
# Listen for changes to the node's preferences.
preferences.add_preferences_listener(
self._preferences_changed_listener, path
)
return
# fixme: Pretty much duplicated in 'PreferencesPage' (except for the
# class name of course!).
def _is_preference_trait(self, trait_name):
""" Return True if a trait represents a preference value. """
if trait_name.startswith('_') or trait_name.endswith('_') \
or trait_name in PreferencesHelper.class_traits():
return False
return True
#### EOF ######################################################################
|