Robot Framework Integrated Development Environment (RIDE)
settingcontrollers.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 import re
17 from itertools import chain
18 from os import linesep
19 
20 from .. import robotapi, utils
21 from ..publish.messages import (RideImportSettingChanged,RideImportSettingRemoved, RideVariableUpdated,
22  RideItemSettingsChanged, RideImportSettingAdded)
23 from ..utils import overrides, variablematcher
24 from .basecontroller import ControllerWithParent
25 from .tags import Tag, ForcedTag, DefaultTag
26 
27 
29  def __init__(self, parent_controller, data):
30  self._parent_parent_parent = parent_controller
31  self._data_data = data
32  self.labellabel = self._label_label(self._data_data)
33  self._init(self._data_data)
34 
35  def _label(self, data):
36  label = data.setting_name
37  if label.startswith('['):
38  return label[1:-1]
39  return label
40 
41  @property
42  _value = property
43 
44  def _value(self):
45  return [v.replace('|', '\\|') for v in self.as_listas_list()[1:]]
46 
47  @property
48  value = property
49 
50  def value(self):
51  value = self._value_value_value
52  if self._data_data.comment:
53  value.pop()
54  return ' | '.join(value)
55 
56  @property
57  display_value = property
58 
59  def display_value(self):
60  return ' | ' .join(self._value_value_value)
61 
62  def as_list(self):
63  # print(f"\nDEBUG: _SettingController enter as_list")
64  return self._data_data.as_list()
65 
66  @property
67  comment = property
68 
69  def comment(self):
70  return self._data_data.comment
71 
72  @property
73  keyword_name = property
74 
75  def keyword_name(self):
76  return ''
77 
78  def contains_keyword(self, name):
79  istring = isinstance(name, str)
80  matcher = name.match if not istring else lambda i: utils.eq(i, name)
81  return self._contains_keyword_contains_keyword(matcher)
82 
83  def _contains_keyword(self, matcher_function):
84  return any(matcher_function(item or '') for item in self.as_listas_list())
85 
86  def contains_variable(self, name):
87  return variablematcher.value_contains_variable(self.valuevaluevalue, name)
88 
89  @property
90  is_set = property
91 
92  def is_set(self):
93  return self._data_data.is_set()
94 
95  def set_from(self, other):
96  if other.is_set:
97  self.set_valueset_value(other.value)
98  self.set_commentset_comment(other.comment)
99 
100  def set_value(self, value):
101  if self._changed_changed(value):
102  self._set_set(value)
103  self.mark_dirtymark_dirty()
104  RideItemSettingsChanged(item=self._parent_parent_parent).publish()
105 
106  def set_comment(self, comment):
107  if comment != self.commentcommentcomment:
108  if not isinstance(comment, robotapi.Comment):
109  comment = robotapi.Comment(comment)
110  self._data_data.comment = comment
111  self.mark_dirtymark_dirty()
112 
114  self._parent_parent_parent.notify_settings_changed()
115 
116  def clear(self):
117  self._data_data.reset()
118  self.mark_dirtymark_dirty()
119 
120  def _changed(self, value):
121  return value != self._data_data.value
122 
123  def _set(self, value):
124  self._data_data.value = value
125 
126  def _split_from_separators(self, value):
127  return utils.split_value(value)
128 
129 
131 
134  _regexps = (re.compile(r'(\\+)r\\n'),
135  re.compile(r'(\\+)n'),
136  re.compile(r'(\\+)r'),
137  re.compile(r'(\\+) '))
138 
139  def _init(self, doc):
140  self._doc_doc = doc
141 
142  @property
143  value = property
144 
145  def value(self):
146  return self._doc_doc.value
147 
148  @overrides(_SettingController)
149  def contains_keyword(self, name):
150  return False
151 
153  return self._unescape_newlines_and_whitespaces_unescape_newlines_and_whitespaces(self.valuevaluevaluevaluevalue)
154 
155  def _set_editable_value(self, value):
156  self.set_valueset_value(self._escape_newlines_and_leading_hash_escape_newlines_and_leading_hash(value))
157 
158  editable_value = property(_get_editable_value, _set_editable_value)
159 
160  @property
161  visible_value = property
162 
163  def visible_value(self):
164  return utils.html_format(utils.unescape(self.valuevaluevaluevaluevalue))
165 
167  for regexp in self._regexps_regexps:
168  if regexp.pattern.endswith(' '):
169  item = regexp.sub(self._whitespace_replacer_whitespace_replacer, item)
170  else:
171  item = regexp.sub(self._newline_replacer_newline_replacer, item)
172  return item
173 
174  def _whitespace_replacer(self, match):
175  return self._replacer_replacer(' ', match)
176 
177  def _newline_replacer(self, match):
178  return self._replacer_replacer(linesep, match)
179 
180  def _replacer(self, char, match):
181  slashes = len(match.group(1))
182  if slashes % 2 == 1:
183  return '\\' * (slashes - 1) + char
184  return match.group()
185 
187  for newline in ('\r\n', '\n', '\r'):
188  item = item.replace(newline, '\\n')
189  if item.strip().startswith('#'):
190  item = '\\' + item
191  return item
192 
193 
195 
196  def _init(self, fixture):
197  self._fixture_fixture = fixture
198 
199  @property
200  keyword_name = property
201 
202  def keyword_name(self):
203  return self._fixture_fixture.name
204 
205  def replace_keyword(self, new_name, old_value=None):
206  self._fixture_fixture.name = new_name
207  self.mark_dirtymark_dirty()
208 
209  def _changed(self, value):
210  name, args = self._parse_parse(value)
211  return self._fixture_fixture.name != name or self._fixture_fixture.args != args
212 
213  def _set(self, value):
214  name, args = self._parse_parse(value)
215  self._fixture_fixture.name = name
216  self._fixture_fixture.args = args
217 
218  def _parse(self, value):
219  value = self._split_from_separators_split_from_separators(value)
220  return (value[0], value[1:]) if value else ('', [])
221 
222 
224 
225  def _init(self, tags):
226  self._tags_tags = tags
227 
228  def empty_tag(self):
229  return Tag(None, controller=self)
230 
231  def _changed(self, value):
232  return self._tags_tags.value != self._split_from_separators_split_from_separators(value)
233 
234  def set_from(self, other):
235  if other.is_set and other._tags.value is not None:
236  self.set_valueset_value(other.value)
237  self.set_commentset_comment(other.comment)
238 
239  def _set(self, value):
240  self._tags_tags.value = self._split_from_separators_split_from_separators(value)
241 
242  def add(self, tag):
243  if self._tags_tags.value is None:
244  self._tags_tags.value = []
245  tag.set_index(len(self._tags_tags.value))
246  self._tags_tags.value.append(tag.name)
247 
248  def remove(self, tag):
249  if tag in self._tags_tags.value:
250  self._tags_tags.value.remove(tag)
251 
252  def __iter__(self):
253  forced = self._parent_parent_parent.force_tags
254  if self._tags_tags.value is None:
255  return chain(forced, self._parent_parent_parent.default_tags).__iter__()
256  if len(self._tags_tags.value) == 0:
257  return chain(forced, [Tag('', controller=self)])
258  own_tags = (Tag(t, index, self)
259  for index, t in enumerate(self._tags_tags.value))
260  return chain(forced, own_tags).__iter__()
261 
262  @property
263  is_set = property
264 
265  def is_set(self):
266  return any(self)
267 
268  @property
269  display_value = property
270 
271  def display_value(self):
272  return ' | ' .join(tag.name.replace('|', '\\|') for tag in self)
273 
274 
276 
277  def empty_tag(self):
278  return DefaultTag(None, controller=self)
279 
280  def __iter__(self):
281  if self._tags_tags.value is None:
282  return [].__iter__()
283  return (DefaultTag(t, index, self)
284  for index, t in enumerate(self._tags_tags.value)).__iter__()
285 
286 
288 
289  def empty_tag(self):
290  return ForcedTag(None, controller=self)
291 
292  def __iter__(self):
293  return self._recursive_gather_from_recursive_gather_from(self.parentparentparent, []).__iter__()
294 
295  def __eq__(self, other):
296  if self is other:
297  return True
298  if other is None:
299  return False
300  if not isinstance(other, self.__class__):
301  return False
302  return self._tags_tags_tags == other._tags
303 
304  def _recursive_gather_from(self, obj, result):
305  if obj is None:
306  return result
307  try:
308  force_tags = obj._setting_table.force_tags
309  # print(f"DEBUG: SettingsController _recursive_gather_from force_tags={force_tags}")
310  except AttributeError: # In the case of a .resource file, there is no Forced Tags fields
311  # print(f"DEBUG: SettingsController _recursive_gather_from resource AttributeError")
312  # force_tags = dict(value=None)
313  return result
314  # print(f"DEBUG: SettingsController _recursive_gather_from force_tags={force_tags}, obj.parent={obj.parent}")
315  return self._recursive_gather_from_recursive_gather_from(
316  obj.parent,
317  self._gather_from_data_gather_from_data(force_tags, obj.force_tags) + result)
318 
319  def _gather_from_data(self, tags, parent):
320  if tags.value is None:
321  return []
322  # print(f"DEBUG: SettingsController _gather_from_data entry tags={tags.value}")
323  return [ForcedTag(t, index, parent)
324  for index, t in enumerate(tags.value)]
325 
326 
328 
329  def _init(self, timeout):
330  self._timeout_timeout = timeout
331 
332  def _changed(self, value):
333  val, msg = self._parse_parse(value)
334  return self._timeout_timeout.value != val or self._timeout_timeout.message != msg
335 
336  def _set(self, value):
337  value, message = self._parse_parse(value)
338  self._timeout_timeout.value = value
339  self._timeout_timeout.message = message
340 
341  def _parse(self, value):
342  parts = value.split('|', 1)
343  val = parts[0].strip() if parts else ''
344  msg = parts[1].strip() if len(parts) == 2 else ''
345  return val, msg
346 
347 
349 
350  def _init(self, template):
351  self._template_template = template
352 
353  def _set(self, value):
354  _SettingController._set(self, value)
355  self._parent_parent_parent.notify_steps_changed()
356 
357  def clear(self):
358  _SettingController.clear(self)
359  self._parent_parent_parent.notify_steps_changed()
360 
361  @property
362  keyword_name = property
363 
364  def keyword_name(self):
365  return self._template_template.value
366 
367  def replace_keyword(self, new_name, old_name=None):
368  self._template_template.value = new_name
369  self.mark_dirtymark_dirty()
370 
371 
373 
374  def _init(self, args):
375  self._args_args = args
376 
377  def _changed(self, value):
378  return self._args_args.value != self._split_from_separators_split_from_separators(value)
379 
380  def _set(self, value):
381  self._args_args.value = self._split_from_separators_split_from_separators(value)
382  self._parent_parent_parent.notify_settings_changed()
383 
384  def clear(self):
385  _SettingController.clear(self)
386  self._parent_parent_parent.notify_settings_changed()
387 
388 
390 
391  def _init(self, return_):
392  self._return_return = return_
393 
394  def _label(self, data):
395  return 'Return Value'
396 
397  def _changed(self, value):
398  return self._return_return.value != self._split_from_separators_split_from_separators(value)
399 
400  def _set(self, value):
401  self._return_return.value = self._split_from_separators_split_from_separators(value)
402 
403 
405 
406  def _init(self, meta):
407  self._meta_meta = meta
408 
409  @property
410  name = property
411 
412  def name(self):
413  return self._meta_meta.name
414 
415  @property
416  value = property
417 
418  def value(self):
419  return self._meta_meta.value
420 
421  def set_value(self, name, value):
422  self._meta_meta.name = name
423  self._meta_meta.value = value
424  self._parent_parent_parent.mark_dirty()
425 
426 
428 
429  def _init(self, var):
430  self._var_var = var
431 
432  def _label(self, data):
433  return ''
434 
435  def __ne__(self, other):
436  return not (self == other)
437 
438  @property
439  name = property
440 
441  def name(self):
442  return self._var_var.name
443 
444  @property
445  value = property
446 
447  def value(self):
448  return self._var_var.value
449 
450  @property
451  comment = property
452 
453  def comment(self):
454  return self._var_var.comment
455 
456  @property
457  data = property
458 
459  def data(self):
460  return self._data_data
461 
462  @property
463  index = property
464 
465  def index(self):
466  return self.parentparentparent.index(self)
467 
468  def set_value(self, name, value):
469  if isinstance(value, str):
470  value = [value]
471  self._var_var.name = name
472  self._var_var.value = value
473  self._parent_parent_parent.mark_dirty()
474 
475  def has_data(self):
476  return self._data_data.has_data()
477 
478  def delete(self):
479  self._parent_parent_parent.remove_var(self)
480 
482  RideVariableUpdated(item=self).publish()
483 
485  self.parentparentparent.notify_variable_added(self)
486 
487  def validate_name(self, new_name):
488  if variablematcher.is_scalar_variable(self.namenamename):
489  return self.parentparentparent.validate_scalar_variable_name(new_name, self)
490  if variablematcher.is_dict_variable(self.namenamename):
491  return self.parentparentparent.validate_dict_variable_name(new_name, self)
492  return self.parentparentparent.validate_list_variable_name(new_name, self)
493 
494  def move_up(self):
495  return self._parent_parent_parent.move_up(self.indexindexindex)
496 
497  def move_down(self):
498  return self._parent_parent_parent.move_down(self.indexindexindex)
499 
500  def __eq__(self, other):
501  if self is other:
502  return True
503  if other.__class__ != self.__class__:
504  return False
505  return self._var_var == other._var
506 
507  def __hash__(self):
508  return hash(self._var_var) + 1
509 
510 
511 def ImportController(parent, import_):
512  if import_.type == 'Resource':
513  return ResourceImportController(parent, import_)
514  elif import_.type == 'Library':
515  return LibraryImportController(parent, import_)
516  return VariablesImportController(parent, import_)
517 
518 
520 
521  def _init(self, import_):
522  self._import_import = import_
523  self.typetype = self._import_import.type
524 
525  def _label(self, data):
526  return data.type
527 
528  @property
529  name = property
530 
531  def name(self):
532  return self._import_import.name
533 
534  @property
535  alias = property
536 
537  def alias(self):
538  return self._import_import.alias or ''
539 
540  @property
541  args = property
542 
543  def args(self):
544  return self._import_import.args or []
545 
546  @property
547  display_value = property
548 
549  def display_value(self):
550  value = self.argsargsargs + (['WITH NAME', self.aliasaliasalias] if self.aliasaliasalias else [])
551  return ' | '.join(value)
552 
553  @property
554  dirty = property
555 
556  def dirty(self):
557  return self._parent_parent_parent.dirty
558 
559  def has_error(self):
560  return False
561 
563  return None
564 
565  def set_value(self, name, args=None, alias=''):
566  self._import_import.name = name
567  self._import_import.args = utils.split_value(args or [])
568  self._import_import.alias = alias
569  self._parent_parent_parent.mark_dirty()
570  self.publish_editedpublish_edited()
571  self.import_loaded_or_modifiedimport_loaded_or_modified()
572  return self
573 
575  self._parent_parent_parent.notify_imports_modified()
576  if not self.is_resource:
577  return
578  self._parent_parent_parent.resource_import_modified(self.namenamename)
579 
580  def remove(self):
581  self.parentparentparent.remove_import_data(self._import_import)
582 
583  def publish_added(self):
585  datafile=self.datafile_controllerdatafile_controllerdatafile_controller,
586  import_controller=self, type=self.typetype.lower()).publish()
587 
588  def publish_edited(self):
590  datafile=self.datafile_controllerdatafile_controllerdatafile_controller,
591  import_controller=self, type=self.typetype.lower()).publish()
592 
593  def publish_removed(self):
594  RideImportSettingRemoved(datafile=self.datafile_controllerdatafile_controllerdatafile_controller,
595  import_controller=self,
596  type=self.typetype.lower()).publish()
597 
598 
600  is_resource = True
601 
604  _resolved_import = False
605 
608  _previous_imported_controller = None
609 
610  def set_value(self, name, args=None, alias=''):
611  self._previous_imported_controller_previous_imported_controller = self.get_imported_controllerget_imported_controllerget_imported_controller()
612  self.unresolveunresolve()
613  _ImportController.set_value(self, name, args, alias)
614 
616  if not self._resolved_import_resolved_import_resolved_import:
617  self._imported_resource_controller_imported_resource_controller = \
618  self.parentparentparent.resource_file_controller_factory.find_with_import(
619  self._import_import)
620  if self._imported_resource_controller_imported_resource_controller:
621  self._imported_resource_controller_imported_resource_controller.add_known_import(self)
622  self._resolved_import_resolved_import_resolved_import = True
623  return self._imported_resource_controller_imported_resource_controller
624 
625  @overrides(_ImportController)
626  def has_error(self):
627  # un-resolve before checking import errors
628  self.unresolveunresolve()
629  return self.get_imported_controllerget_imported_controllerget_imported_controller() is None
630 
631  @overrides(_ImportController)
632  def publish_added(self):
633  # Resolve the import <-> ResourceFileController link
634  self.get_imported_controllerget_imported_controllerget_imported_controller()
635  _ImportController.publish_added(self)
636 
637  @overrides(_ImportController)
638  def publish_removed(self):
639  self._previous_imported_controller_previous_imported_controller = self.get_imported_controllerget_imported_controllerget_imported_controller()
640  # Unresolve the import <-> ResourceFileController link
641  self.unresolveunresolve()
642  self._prevent_resolve_prevent_resolve()
643  _ImportController.publish_removed(self)
644 
645  def _prevent_resolve(self):
646  self._resolved_import_resolved_import_resolved_import = True
647  self._imported_resource_controller_imported_resource_controller = None
648 
650  return self._previous_imported_controller_previous_imported_controller
651 
652  def unresolve(self):
653  if self._resolved_import_resolved_import_resolved_import and self._imported_resource_controller_imported_resource_controller:
654  self._imported_resource_controller_imported_resource_controller.remove_known_import(self)
655  self._resolved_import_resolved_import_resolved_import = False
656 
657  def contains_filename(self, filename):
658  return self.namenamename.endswith(filename)
659 
660  def change_name(self, old_name, new_name):
661  if self.contains_filenamecontains_filename(old_name):
662  self.set_valueset_valueset_valueset_value(self.namenamename[:-len(old_name)] + new_name)
663  else:
664  # If original result has changed and this import relies on
665  # variables, can't know if import is still resolved
666  self.unresolveunresolve()
667 
668  def change_format(self, format):
669  if self._has_format_has_format():
670  self.set_valueset_valueset_valueset_value(utils.replace_extension(self.namenamename, format))
671  else:
672  self.unresolveunresolve()
673 
674  def _has_format(self):
675  parts = self.namenamename.rsplit('.', 1)
676  if len(parts) == 1:
677  return False
678  return parts[-1].lower() in ['html', 'txt', 'tsv', 'robot', 'resource']
679 
680 
682  is_resource = False
683 
684  @overrides(_ImportController)
685  def has_error(self):
686  return not self.parentparentparent.parent.is_library_import_ok(self._data_data)
687 
688 
690  is_resource = False
691 
692  @overrides(_ImportController)
693  def has_error(self):
694  return not self.parentparentparent.parent.is_variables_import_ok(self._data_data)
Sent whenever an import setting is added.
Definition: messages.py:354
Sent whenever a value of import setting is changed.
Definition: messages.py:363
Sent whenever a value of import setting is removed.
Definition: messages.py:372
Sent when the state of a variable is changed.
Definition: messages.py:469