| Conditions | 17 |
| Total Lines | 148 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 7 | ||
| Bugs | 0 | Features | 4 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like Mapper.add_mapping() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*- |
||
| 141 | model, |
||
| 142 | model_getter, |
||
| 143 | model_property_notifier=None, |
||
| 144 | model_setter=None, |
||
| 145 | widget_property_name='', |
||
| 146 | widget_property_notifier=None, |
||
| 147 | converter=None): |
||
| 148 | """ |
||
| 149 | Adds a mapping. |
||
| 150 | |||
| 151 | Parameters |
||
| 152 | ========== |
||
| 153 | widget QtWidget A widget displaying some data. You want to map this |
||
| 154 | widget to model data |
||
| 155 | model object Instance of a class holding model data (e.g. a logic |
||
| 156 | or hardware module) |
||
| 157 | model_getter property/callable either a property holding the data to |
||
| 158 | be displayed in widget or a getter |
||
| 159 | method to retrieve data from the model |
||
| 160 | was changed. |
||
| 161 | model_property_notifier Signal A signal that is fired when the data |
||
| 162 | was changed. |
||
| 163 | Default: None. If None then data |
||
| 164 | changes are not monitored and the |
||
| 165 | widget is not updated. |
||
| 166 | model_setter callable A setter method which is called to set data to |
||
| 167 | the model. |
||
| 168 | If model_getter is a property the setter can be |
||
| 169 | determined from this property and model_setter |
||
| 170 | is ignored if it is None. If it is not None |
||
| 171 | always this callable is used. |
||
| 172 | Default: None |
||
| 173 | widget_property_name str The name of the pyqtProperty of the widget |
||
| 174 | used to map the data. |
||
| 175 | Default: '' |
||
| 176 | If it is an empty string the relevant |
||
| 177 | property is guessed from the widget's type. |
||
| 178 | widget_property_notifier Signal Notifier signal which is fired by the |
||
| 179 | widget when the data changed. If None |
||
| 180 | this is determined directly from the |
||
| 181 | property. |
||
| 182 | Example usage: |
||
| 183 | QLineEdit().editingFinished |
||
| 184 | Default: None |
||
| 185 | converter Converter converter instance for converting data between |
||
| 186 | widget display and model. |
||
| 187 | Default: None |
||
| 188 | |||
| 189 | """ |
||
| 190 | # guess widget property if not specified |
||
| 191 | if widget_property_name == '': |
||
| 192 | widget_property_name = self._get_property_from_widget(widget) |
||
| 193 | |||
| 194 | # define key of mapping |
||
| 195 | key = (widget, widget_property_name) |
||
| 196 | |||
| 197 | # check if already exists |
||
| 198 | if key in self._mappings: |
||
| 199 | raise Exception('Property {0} of widget {1} already mapped.' |
||
| 200 | ''.format(widget_property_name, repr(widget))) |
||
| 201 | |||
| 202 | # check if widget property is available |
||
| 203 | index = widget.metaObject().indexOfProperty(widget_property_name) |
||
| 204 | if index == -1: |
||
| 205 | raise Exception('Property ''{0}'' of widget ''{1}'' not ' |
||
| 206 | 'available.'.format(widget_property_name, |
||
| 207 | widget.__class__.__name__)) |
||
| 208 | |||
| 209 | meta_property = widget.metaObject().property(index) |
||
| 210 | |||
| 211 | # widget property notifier |
||
| 212 | if widget_property_notifier is None: |
||
| 213 | # check that widget property as a notify signal |
||
| 214 | if not meta_property.hasNotifySignal(): |
||
| 215 | raise Exception('Property ''{0}'' of widget ''{1}'' has ' |
||
| 216 | 'no notify signal.'.format( |
||
| 217 | widget_property_name, |
||
| 218 | widget.__class__.__name__)) |
||
| 219 | widget_property_notifier = getattr( |
||
| 220 | widget, |
||
| 221 | meta_property.notifySignal().name().data().decode('utf8')) |
||
| 222 | |||
| 223 | # check that widget property is readable |
||
| 224 | if not meta_property.isReadable(): |
||
| 225 | raise Exception('Property ''{0}'' of widget ''{1}'' is not ' |
||
| 226 | 'readable.'.format(widget_property_name, |
||
| 227 | widget.__class__.__name__)) |
||
| 228 | widget_property_getter = meta_property.read |
||
| 229 | # check that widget property is writable if requested |
||
| 230 | if not meta_property.isWritable(): |
||
| 231 | raise Exception('Property ''{0}'' of widget ''{1}'' is not ' |
||
| 232 | 'writable.'.format(widget_property_name, |
||
| 233 | widget.__class__.__name__)) |
||
| 234 | widget_property_setter = meta_property.write |
||
| 235 | |||
| 236 | if isinstance(model_getter, str): |
||
| 237 | # check if it is a property |
||
| 238 | attr = getattr(model.__class__, model_getter, None) |
||
| 239 | if attr is None: |
||
| 240 | raise Exception('Model has no attribute {0}'.format( |
||
| 241 | model_getter)) |
||
| 242 | if isinstance(attr, property): |
||
| 243 | # retrieve getter from property |
||
| 244 | model_property_name = model_getter |
||
| 245 | model_getter = functools.partial(attr.fget, model) |
||
| 246 | # if no setter was specified, get it from the property |
||
| 247 | if model_setter is None: |
||
| 248 | model_setter = functools.partial(attr.fset, model) |
||
| 249 | if model_getter is None: |
||
| 250 | raise Exception('Attribute {0} of model is readonly.' |
||
| 251 | ''.format(model_property_name)) |
||
| 252 | if isinstance(model_setter, str): |
||
| 253 | model_setter_name = model_setter |
||
| 254 | model_setter = getattr(model, model_setter) |
||
| 255 | if not callable(model_setter): |
||
| 256 | raise Exception('{0} is not callable'.format( |
||
| 257 | model_setter_name)) |
||
| 258 | if isinstance(model_property_notifier, str): |
||
| 259 | model_property_notifier = getattr(model, model_property_notifier) |
||
| 260 | |||
| 261 | # connect to widget property notifier |
||
| 262 | widget_property_notifier_slot = functools.partial( |
||
| 263 | self._on_widget_property_notification, key) |
||
| 264 | widget_property_notifier.connect(widget_property_notifier_slot) |
||
| 265 | |||
| 266 | # if model_notify_signal was specified, connect to it |
||
| 267 | model_property_notifier_slot = None |
||
| 268 | if model_property_notifier is not None: |
||
| 269 | model_property_notifier_slot = functools.partial( |
||
| 270 | self._on_model_notification, key) |
||
| 271 | model_property_notifier.connect(model_property_notifier_slot) |
||
| 272 | # save mapping |
||
| 273 | self._mappings[key] = { |
||
| 274 | 'widget_property_name': widget_property_name, |
||
| 275 | 'widget_property_getter': widget_property_getter, |
||
| 276 | 'widget_property_setter': widget_property_setter, |
||
| 277 | 'widget_property_notifier': widget_property_notifier, |
||
| 278 | 'widget_property_notifier_slot': widget_property_notifier_slot, |
||
| 279 | 'widget_property_notifications_disabled': False, |
||
| 280 | 'model': model, |
||
| 281 | 'model_property_setter': model_setter, |
||
| 282 | 'model_property_getter': model_getter, |
||
| 283 | 'model_property_notifier': model_property_notifier, |
||
| 284 | 'model_property_notifier_slot': model_property_notifier_slot, |
||
| 285 | 'model_property_notifications_disabled': False, |
||
| 286 | 'converter': converter} |
||
| 287 | |||
| 288 | def _on_widget_property_notification(self, key, *args): |
||
| 289 | """ |
||
| 461 |