Robot Framework Integrated Development Environment (RIDE)
filecontrollers.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 os
17 import shutil
18 import stat
19 import sys
20 from itertools import chain
21 try:
22  import subprocess32 as subprocess
23 except ImportError:
24  import subprocess
25 from .dataloader import ExcludedDirectory, TestData
26 from ..publish import (RideDataFileRemoved, RideInitFileRemoved, RideDataChangedToDirty, RideDataDirtyCleared,
27  RideSuiteAdded, RideItemSettingsChanged)
28 from ..publish.messages import RideDataFileSet, RideOpenResource
29 from ..robotapi import TestDataDirectory, TestCaseFile, ResourceFile
30 from .. import utils
31 
32 from .basecontroller import WithUndoRedoStacks, _BaseController, WithNamespace, ControllerWithParent
33 from .robotdata import NewTestCaseFile, NewTestDataDirectory
34 from ..utils import overrides
35 from .settingcontrollers import (DocumentationController, FixtureController, TimeoutController, TemplateController,
36  DefaultTagsController, ForceTagsController)
37 from .tablecontrollers import (VariableTableController, TestCaseTableController, KeywordTableController,
38  ImportSettingsController, MetadataListController)
39 from .macrocontrollers import TestCaseController, UserKeywordController
40 
41 
42 def _get_controller(project, data, parent):
43  if isinstance(data, TestCaseFile):
44  return TestCaseFileController(data, project, parent)
45  if isinstance(data, ExcludedDirectory):
46  return ExcludedDirectoryController(data, project, parent)
47  if isinstance(data, ResourceFile):
48  from ..controller.project import Project
49  from ..namespace import Namespace
50  import tempfile
51  if not data.parent:
52  data.parent = Project(Namespace(data._settings), data._settings)
53  content= bytes(f"*** Settings ***\nResource {data.source}\n\n*** Test Cases ***\nEmpty\n No Operation\n",
54  encoding='utf-8')
55  stub = tempfile.NamedTemporaryFile(delete=False)
56  with stub:
57  stub.write(content)
58  data.parent.load_data(stub.name)
59  return TestCaseFileController(data, project, data.parent) # DEBUG Here we create a dummy Project
60  return TestDataDirectoryController(data, project, parent)
61 
62 
63 def DataController(data, project, parent=None):
64  return _get_controller(project, data, parent)
65 
66 
68 
69  def __init__(self, filename, directory):
70  self.filenamefilename = filename
71  self.directorydirectory = directory
72  self._stat_stat = self._get_stat_get_stat(filename)
73 
74  def _get_stat(self, path):
75  if path and os.path.isfile(path):
76  stat = os.stat(path)
77  return stat.st_mtime, stat.st_size
78  return 0, 0
79 
80  def refresh_stat(self):
81  self._stat_stat = self._get_stat_get_stat(self.filenamefilename)
82 
84  return self._get_stat_get_stat(self.filenamefilename) != self._stat_stat
85 
87  return self._stat_stat != (0, 0) and not self.existsexists()
88 
89  def relative_path_to(self, other):
90  other_path = os.path.join(other.directory, other.filename)
91  return os.path.relpath(other_path, start=self.directorydirectory).replace('\\', '/')
92 
93  def is_readonly(self):
94  return not os.access(self.filenamefilename, os.W_OK)
95 
96  def exists(self):
97  return self.filenamefilename and os.path.isfile(self.filenamefilename)
98 
99  @property
100  basename = property
101 
102  def basename(self):
103  return os.path.splitext(os.path.basename(self.filenamefilename))[0]
104 
105  @property
106 
107  source = property
108 
109  def source(self):
110  # Todo: remove when backwards compatibility with plugin API can break
111  return self.filenamefilename or self.directorydirectory
112 
113 
115 
116  def __init__(self, data, project=None, parent=None):
117  self._project_project = project
118  if project:
119  self._set_namespace_from_set_namespace_from(project)
120  self._resource_file_controller_factory_resource_file_controller_factory =\
121  project.resource_file_controller_factory
122  else:
123  self._resource_file_controller_factory_resource_file_controller_factory = None
124  self.parentparent = parent
125  self.set_datafileset_datafile(data)
126  self.dirtydirty = False
127  self.childrenchildren = self._children_children(data)
128  # Filename needs to be set when creating a new datafile
129  if hasattr(self.datadata, 'initfile'):
130  self.filenamefilename = self.datadata.initfile
131  else:
132  self.filenamefilename = self.datadata.source
133 
134  def set_datafile(self, datafile):
135  self.datadata = datafile
136  self._variables_table_controller_variables_table_controller = None
137  self._testcase_table_controller_testcase_table_controller = None
138  self._keywords_table_controller_keywords_table_controller = None
139  self._imports_imports = None
140  RideDataFileSet(item=self).publish()
141 
142  def _children(self, data):
143  return []
144 
145  @property
146  name = property
147 
148  def name(self):
149  return self.datadata.name
150 
151  @property
152  settings = property
153 
154  def settings(self):
155  return self._settings_settings()
156 
157  def _settings(self):
158  ss = self.datadata.setting_table
159  return [DocumentationController(self, ss.doc),
160  FixtureController(self, ss.suite_setup),
161  FixtureController(self, ss.suite_teardown),
162  FixtureController(self, ss.test_setup),
163  FixtureController(self, ss.test_teardown),
164  self.force_tagsforce_tagsforce_tags]
165 
166  @property
167  _setting_table = property
168 
169  def _setting_table(self):
170  return self.datadata.setting_table
171 
172  @property
173  force_tags = property
174 
175  def force_tags(self):
176  return ForceTagsController(self, self._setting_table_setting_table_setting_table.force_tags)
177 
178  @property
179  variables = property
180 
181  def variables(self):
182  if self._variables_table_controller_variables_table_controller is None:
183  self._variables_table_controller_variables_table_controller = VariableTableController(self, self.datadata.variable_table)
184  return self._variables_table_controller_variables_table_controller
185 
186  @property
187  tests = property
188 
189  def tests(self):
190  if self._testcase_table_controller_testcase_table_controller is None:
191  self._testcase_table_controller_testcase_table_controller = TestCaseTableController(self, self.datadata.testcase_table)
192  return self._testcase_table_controller_testcase_table_controller
193 
194  @property
195  datafile = property
196 
197  def datafile(self):
198  return self.datadata
199 
200  @property
201  datafiles = property
202 
203  def datafiles(self):
204  return chain([self], (df for df in self._project_project.datafiles
205  if df != self))
206 
207  @property
208  datafile_controller = property
209 
211  return self
212 
213  @property
214  keywords = property
215 
216  def keywords(self):
217  if self._keywords_table_controller_keywords_table_controller is None:
218  self._keywords_table_controller_keywords_table_controller = KeywordTableController(self, self.datadata.keyword_table)
219  return self._keywords_table_controller_keywords_table_controller
220 
221  @property
222  imports = property
223 
224  def imports(self):
225  if not self._imports_imports:
226  self._imports_imports = ImportSettingsController(self, self.datadata.setting_table,
227  self._resource_file_controller_factory_resource_file_controller_factory)
228  return self._imports_imports
229 
230  @property
231  metadata = property
232 
233  def metadata(self):
234  return MetadataListController(self, self.datadata.setting_table)
235 
236  def is_user_keyword(self, value):
237  return WithNamespace.is_user_keyword(self, self.datafiledatafiledatafile, value)
238 
239  def is_library_keyword(self, value):
240  return WithNamespace.is_library_keyword(self, self.datafiledatafiledatafile, value)
241 
242  def keyword_info(self, keyword_name):
243  return WithNamespace.keyword_info(self, self.datadata, keyword_name)
244 
245  def mark_dirty(self):
246  if not self.dirtydirty:
247  self.dirtydirty = True
248  RideDataChangedToDirty(datafile=self).publish()
249 
250  def unmark_dirty(self):
251  self.refresh_stat()
252  if self.dirtydirty:
253  self.dirtydirty = False
254  # print(f"DEBUG: filecontrollers unmark_dirty PUBLISH RideDataDirtyCleared")
255  RideDataDirtyCleared(datafile=self).publish()
256 
257  def create_keyword(self, name, argstr=''):
258  return self.keywordskeywordskeywords.new(name, argstr)
259 
260  def add_test_or_keyword(self, item):
261  if isinstance(item, TestCaseController):
262  self.teststeststests.add(item)
263  item.set_parent(self.teststeststests)
264  elif isinstance(item, UserKeywordController):
265  self.keywordskeywordskeywords.add(item)
266  item.set_parent(self.keywordskeywordskeywords)
267  else:
268  self.variablesvariablesvariables.add_variable(item.name, item.value, item.comment)
269 
270  def sort_tests(self):
271  if self.teststeststests:
272  index_difference = self.teststeststests.sort()
273  self.mark_dirtymark_dirty()
274  RideDataFileSet(item=self).publish()
275  return index_difference
276  return None
277 
278  def sort_keywords(self):
279  if self.keywordskeywordskeywords:
280  index_difference = self.keywordskeywordskeywords.sort()
281  self.mark_dirtymark_dirty()
282  RideDataFileSet(item=self).publish()
283  return index_difference
284  return None
285 
286  def sort_variables(self):
287  if self.variablesvariablesvariables:
288  index_difference = self.variablesvariablesvariables.sort()
289  self.mark_dirtymark_dirty()
290  RideDataFileSet(item=self).publish()
291  return index_difference
292  return None
293 
294  def restore_test_order(self, index_difference):
295  if self.teststeststests and index_difference:
296  self.teststeststests.restore_test_order(index_difference)
297  self.mark_dirtymark_dirty()
298  RideDataFileSet(item=self).publish()
299 
300  def restore_keyword_order(self, index_difference):
301  if self.keywordskeywordskeywords and index_difference:
302  self.keywordskeywordskeywords.restore_keyword_order(index_difference)
303  self.mark_dirtymark_dirty()
304  RideDataFileSet(item=self).publish()
305 
306  def restore_variable_order(self, index_difference):
307  if self.variablesvariablesvariables and index_difference:
308  self.variablesvariablesvariables.restore_variable_order(index_difference)
309  self.mark_dirtymark_dirty()
310  RideDataFileSet(item=self).publish()
311 
312  def get_keyword_names(self):
313  if self.keywordskeywordskeywords:
314  return [kw.name for kw in self.keywordskeywordskeywords._items]
315  return None
316 
317  def has_format(self):
318  return True
319 
320  def get_format(self):
321  if not self.filenamefilename:
322  return None
323  return os.path.splitext(self.filenamefilename)[1].replace('.', '')
324 
325  def set_format(self, format):
326  self.datadata.source = utils.replace_extension(self.filenamefilename, format)
327  self.filenamefilename = self.datadata.source
328 
329  def is_same_format(self, format):
330  if format and self.has_formathas_format():
331  return format.lower() == self.get_formatget_format().lower()
332  return False
333 
334  def set_basename(self, basename):
335  from .ctrlcommands import SaveFile
336 
337  old_file = self.filenamefilename
338  self.datadata.source = os.path.join(self.directory, '%s.%s' % (basename, self.get_formatget_format()))
339  self.filenamefilename = self.datadata.source
340  self.executeexecute(SaveFile())
341  if old_file != self.filenamefilename:
342  self.remove_from_filesystemremove_from_filesystem(old_file)
343 
344  def remove_readonly(self, path=None):
345  path = path or self.filenamefilename
346  os.chmod(path, stat.S_IWRITE)
347 
348  def open_filemanager(self, path=None):
349  # tested on Win7 x64
350  path = path or self.filenamefilename
351  if os.path.exists(path):
352  if sys.platform == 'win32':
353  # There was encoding errors if directory had unicode chars
354  # TODO test on all OS directory names with accented chars, for example 'ccedilla'
355  os.startfile(r"%s" % os.path.dirname(path), 'explore')
356  elif sys.platform.startswith('linux'):
357  # how to detect which explorer is used?
358  # nautilus, dolphin, konqueror
359  # TODO check if explorer exists
360  # TODO get prefered explorer from preferences
361  try:
362  subprocess.Popen(["nautilus", "{}".format(
363  os.path.dirname(path))])
364  except OSError or FileNotFoundError:
365  try:
366  subprocess.Popen(
367  ["dolphin", "{}".format(os.path.dirname(path))])
368  except OSError or FileNotFoundError:
369  try:
370  subprocess.Popen(
371  ["konqueror", "{}".format(
372  os.path.dirname(path))])
373  except OSError or FileNotFoundError:
374  print("Could not launch explorer. Tried nautilus, "
375  "dolphin and konqueror.")
376  else:
377  try:
378  subprocess.Popen(["finder", "{}".format(
379  os.path.dirname(path))])
380  except OSError or FileNotFoundError:
381  subprocess.Popen(["open", "{}".format(
382  os.path.dirname(path))])
383 
384  def remove_from_filesystem(self, path=None):
385  path = path or self.filenamefilename
386  if os.path.exists(path):
387  os.remove(path)
388 
389  def remove_folder_from_filesystem(self, path=None):
390  shutil.rmtree(path or self.datadata.directory)
391 
392  def save_with_new_format(self, format):
393  self._project_project.change_format(self, format)
394 
396  self._project_project.change_format_recursive(self, format)
397 
398  def validate_keyword_name(self, name):
399  return self.keywordskeywordskeywords.validate_name(name)
400 
402  return False
403 
404  def resource_import_modified(self, path):
405  return self._project_project.resource_import_modified(path, self.directory)
406 
408  RideItemSettingsChanged(item=self).publish()
409 
411  for test in self.teststeststests:
412  test.notify_steps_changed()
413 
414  def iter_datafiles(self):
415  yield self
416  for child in self.childrenchildren:
417  for datafile in child.iter_datafiles():
418  yield datafile
419 
420  def save(self):
421  self._project_project.save(self)
422 
424  return {}
425 
426  def is_inside_top_suite(self, res):
427  return False
428 
429 
431 
432  def __init__(self, data, project=None, parent=None):
433  dir_ = data.directory
434  dir_ = os.path.abspath(dir_) if isinstance(dir_, str) else dir_
435  _FileSystemElement.__init__(self, self._filename_filename(data), dir_)
436  _DataController.__init__(self, data, project, parent)
437  self._dir_controllers_dir_controllers = {}
438 
439  def _filename(self, data):
440  return data.initfile
441 
442  @property
443  default_dir = property
444 
445  def default_dir(self):
446  return self.datadata.source
447 
448  @property
449  display_name = property
450 
451  def display_name(self):
452  return self.datadata.name
453 
454  @property
455  longname = property
456 
457  def longname(self):
458  if self.parentparent:
459  return self.parentparent.longname + '.' + self.display_namedisplay_namedisplay_namedisplay_namedisplay_name
461 
462  @property
463  suites = property
464 
465  def suites(self):
466  return [child for child in self.childrenchildren if
467  isinstance(child, TestDataDirectoryController) or
468  isinstance(child, TestCaseFileController)]
469 
470  def add_child(self, child):
471  self.childrenchildren.append(child)
472 
473  def contains_tests(self):
474  for suite in self.suitessuitessuites:
475  if suite.contains_tests():
476  return True
477  return False
478 
479  def find_controller_by_longname(self, longname, testname = None):
480  return self.find_controller_by_namesfind_controller_by_names(longname.split("."), testname)
481 
482  def find_controller_by_names(self, names, testname):
483  namestring = '.'.join(names)
484  if not namestring.startswith(self.namenamename):
485  return None
486  if namestring == self.namenamename:
487  return self
488  for suite in self.suitessuitessuites:
489  res = suite.find_controller_by_names(namestring[len(self.namenamename)+1:].split('.'), testname)
490  if res:
491  return res
492 
493  def is_excluded(self):
494  return self._project_project.is_excluded(self.sourcesourcesource) if self._project_project else False
495 
496  def _children(self, data):
497  children = [DataController(child, self._project_project, self) for child in data.children]
498  if self._can_add_directory_children_can_add_directory_children(data):
499  self._add_directory_children_add_directory_children(children, data.source, data.initfile)
500  return children
501 
503  return data.source and os.path.isdir(data.source) and self._namespace_namespace
504 
505  def _add_directory_children(self, children, path, initfile):
506  if not children:
507  return
508  for filename in self._get_unknown_files_in_directory_get_unknown_files_in_directory(children, path, initfile):
509  if not self._is_robot_ignored_name_is_robot_ignored_name(filename):
510  self._add_directory_child_add_directory_child(children, filename)
511 
512  def _is_robot_ignored_name(self, filename):
513  base = os.path.basename(filename)
514  robotformat = (".txt", ".robot", ".resource", ".rst", " .rest", ".tsv", ".htm", ".html")
515  nonrobot_file = os.path.isfile(filename) and not base.endswith(robotformat)
516  hidden = base.startswith('.')
517  private = base.startswith('_')
518  return hidden or private or nonrobot_file
519 
520  def _add_directory_child(self, children, filename):
521  if os.path.isdir(filename):
522  children.append(self._directory_controller_directory_controller(filename))
523  else:
524  r = self._namespace_namespace.get_resource(filename, report_status=False)
525  if self._is_valid_resource_is_valid_resource(r):
526  children.append(self._resource_controller_resource_controller(r))
527 
528  def _directory_controller(self, path):
529  dc = TestDataDirectoryController(TestDataDirectory(source=path),
530  project=self._project_project,
531  parent=self)
532  self._add_directory_children_add_directory_children(dc.children, dc.source, None)
533  return dc
534 
535  def _is_valid_resource(self, resource):
536  return resource and (resource.setting_table or resource.variable_table or
537  resource.keyword_table or os.stat(resource.source)[6] == 0)
538 
539  def _resource_controller(self, resource):
540  resource_control = self._resource_file_controller_factory_resource_file_controller_factory.create(resource)
541  resource_control.parent = self
542  return resource_control
543 
544  def _get_unknown_files_in_directory(self, children, path, initfile):
545  already_in_use = [c.filename for c in children] + [initfile]
546  already_in_use += [c.directory for c in children]
547  return [f for f in self._get_filenames_in_directory_get_filenames_in_directory(path) if f not in already_in_use]
548 
550  return [os.path.join(path, f) for f in os.listdir(path)]
551 
552  def add_child(self, controller):
553  assert controller not in self.childrenchildren
554  self.childrenchildren.append(controller)
555 
556  def has_format(self):
557  return self.datadata.initfile is not None
558 
559  def set_format(self, format):
560  self.datadata.initfile = os.path.join(self.datadata.source, '__init__.%s'
561  % format.lower())
562  self.filenamefilenamefilenamefilename = self.datadata.initfile
563 
564  def new_test_case_file(self, path):
565  ctrl = self._new_data_controller_new_data_controller(NewTestCaseFile(path))
566  ctrl.mark_dirty()
567  return ctrl
568 
569  def new_test_data_directory(self, path):
570  return self._new_data_controller_new_data_controller(NewTestDataDirectory(path))
571 
572  def _new_data_controller(self, datafile):
573  self.datadata.children.append(datafile)
574  datafile.parent = self.datadata
575  self.childrenchildren.append(DataController(datafile, self._project_project, self))
576  return self.childrenchildren[-1]
577 
578  def notify_suite_added(self, suite):
579  RideSuiteAdded(parent=self, suite=suite).publish()
580 
582  return True
583 
584  def reload(self):
585  self.__init____init____init____init__(TestDataDirectory(source=self.directorydirectory, parent=self.datadata.parent).populate(),
586  self._project_project, parent=self.parentparent)
587 
588  def remove(self):
589  path = self.filenamefilenamefilenamefilename
590  self.datadata.initfile = None
591  self._stat_stat_stat = self._get_stat_get_stat(None)
592  self.reloadreload()
593  RideInitFileRemoved(path=path, datafile=self).publish()
594 
595  def _remove_resources(self):
596  for resource in self._find_resources_recursively_find_resources_recursively(self):
597  self._project_project.remove_resource(resource)
598  RideDataFileRemoved(path=resource.filename, datafile=resource).publish()
599 
600  def remove_from_model(self):
601  self._project_project.remove_datafile(self)
602  self._remove_resources_remove_resources()
603  RideDataFileRemoved(path=self.filenamefilenamefilenamefilename, datafile=self).publish()
604 
605  def remove_child(self, controller):
606  if controller in self.childrenchildren:
607  self.childrenchildren.remove(controller)
608  else:
609  for child in self.childrenchildren:
610  child.remove_child(controller)
611 
612  def is_inside_top_suite(self, ctrl):
613  return ctrl.filename.startswith(self.directorydirectory)
614 
615  def _is_inside_test_data_directory(self, directory):
616  return any(True for s in [self] + self.childrenchildren
617  if s.is_directory_suite() and s.directory == directory)
618 
620  for resource_import in self.get_where_usedget_where_used():
621  resource_import[1].remove()
622 
623  def get_where_used(self):
624  for imp in self._get_recursive_imports_get_recursive_imports():
625  yield imp
626 
627  def _all_imports(self):
628  for df in self.datafilesdatafilesdatafiles:
629  for imp in df.imports:
630  yield imp
631 
633  all_imports = self._all_imports_all_imports()
634  ctrls = self._find_controllers_recursively_find_controllers_recursively(self)
635  for res in self._find_resources_recursively_find_resources_recursively(self):
636  for imp in all_imports:
637  if imp.get_imported_controller() == res and imp.parent.parent not in ctrls:
638  yield res, imp
639 
640  def _find_resources_recursively(self, controller):
641  resources = []
642  if controller.children:
643  for child in controller.children:
644  resources += self._find_resources_recursively_find_resources_recursively(child)
645  elif isinstance(controller, ResourceFileController):
646  resources.append(controller)
647  return resources
648 
649  def _find_controllers_recursively(self, controller):
650  resources = []
651  if controller.children:
652  for child in controller.children:
653  resources += self._find_controllers_recursively_find_controllers_recursively(child)
654  resources.append(controller)
655  return resources
656 
658  res_dir = os.path.dirname(res.filename)
659  if res_dir in self._dir_controllers_dir_controllers:
660  self._dir_controllers_dir_controllers[res_dir].add_child(res)
661  else:
662  target = self._find_closest_directory_find_closest_directory(res)
663  if target is self:
664  self._create_target_dir_controller_create_target_dir_controller(res, res_dir, target)
665  else:
666  target.insert_to_test_data_directory(res)
667 
668  def _find_closest_directory(self, res):
669  target = self
670  for s in self.iter_datafilesiter_datafiles():
671  if not isinstance(s, TestDataDirectoryController):
672  continue
673  if res.filename.startswith(s.directory):
674  target = s
675  return target
676 
677  def _create_target_dir_controller(self, res, res_dir, target):
678  for dirname in res_dir[len(self.directorydirectory):].split(os.sep):
679  if not dirname:
680  continue
681  target_dir = os.path.join(target.directory, dirname)
682  dir_ctrl = TestDataDirectoryController(TestDataDirectory(source=target_dir),
683  self._project_project, self)
684  target._dir_controllers[target.directory] = dir_ctrl
685  target.add_child(dir_ctrl)
686  if target_dir == res_dir:
687  dir_ctrl.add_child(res)
688  return
689  target = dir_ctrl
690  if res not in self.childrenchildren:
691  self.add_childadd_childadd_child(res)
692 
693  def new_resource(self, path):
694  ctrl = self._project_project.new_resource(path, parent=self)
695  ctrl.mark_dirty()
696  return ctrl
697 
698  def exclude(self):
699  if self._project_project.is_datafile_dirty(self):
701  self._project_project._settings.excludes.update_excludes([self.directorydirectory])
702  index = self.parentparent.children.index(self)
703  result = ExcludedDirectoryController(self.datadata, self._project_project, self.parentparent)
704  self.parentparent.children[index] = result
705  return result
706 
708  controllers: list[TestCaseController] = []
709  for child in self.childrenchildren:
710  if isinstance(child,TestCaseFileController) or isinstance(child,TestDataDirectoryController):
711  controllers += child.retrieve_test_controllers()
712  return controllers
713 
714 
715 
719  pass
720 
721 
722 class TestCaseFileController(_FileSystemElement, _DataController):
723 
724  def __init__(self, data, project=None, parent=None):
725  _FileSystemElement.__init__(self, data.source if data else None, data.directory)
726  _DataController.__init__(self, data, project, parent)
727 
728  def _settings(self):
729  ss = self._setting_table_setting_table_setting_table
730  sett = _DataController._settings(self)
731  sett.insert(-1, TemplateController(self, ss.test_template))
732  sett.insert(-1, TimeoutController(self, ss.test_timeout))
733  return sett + [self.default_tagsdefault_tagsdefault_tags]
734 
735  @property
736  longname = property
737 
738  def longname(self):
739  if self.parentparent:
740  return self.parentparent.longname + '.' + self.namenamename
741  return self.namenamename
742 
743  @property
744  suites = property
745 
746  def suites(self):
747  return ()
748 
749  def contains_tests(self):
750  return bool(self.teststeststests)
751 
752  def find_controller_by_longname(self, longname, node_testname = None):
753  return self.find_controller_by_namesfind_controller_by_names(longname.split("."), node_testname)
754 
755  def find_controller_by_names(self, names, node_testname = None):
756  names = '.'.join(names)
757  if not names.startswith(self.namenamename):
758  return None
759  if len(self.namenamename) < len(names) and not names.startswith(self.namenamename+'.'):
760  return None
761  if len(names) == 1:
762  return self
763  for test in self.teststeststests:
764  if test.name == node_testname:
765  return test
766  return None
767 
768  @property
769  default_tags = property
770 
771  def default_tags(self):
772  return DefaultTagsController(self, self._setting_table_setting_table_setting_table.default_tags)
773 
774  def is_modifiable(self):
775  return not self.existsexists() or not self.is_readonlyis_readonly()
776 
777  def create_test(self, name):
778  return self.teststeststests.new(name)
779 
780  def validate_test_name(self, name):
781  return self.teststeststests.validate_name(name)
782 
783  def remove_child(self, controller):
784  if controller is self:
785  self.removeremove()
786 
787  def remove(self):
788  self._project_project.remove_datafile(self)
789  RideDataFileRemoved(path=self.filenamefilenamefilename, datafile=self).publish()
790 
791  def reload(self):
792  self.__init____init____init____init__(TestCaseFile(parent=self.datadata.parent, source=self.filenamefilenamefilename).populate(),
793  project=self._project_project,
794  parent=self.parentparent)
795 
796  def get_template(self):
797  return self.datadata.setting_table.test_template
798 
800  controllers = []
801  for test_ctrl in iter(self.teststeststests):
802  controllers.append(test_ctrl)
803  return controllers
804 
805 
807 
808  def __init__(self, namespace, project):
809  self._resources_resources = []
810  self._namespace_namespace = namespace
811  self._project_project = project
812  self._all_resource_imports_resolved_all_resource_imports_resolved = False
813 
814  @property
815  resources = property
816 
817  def resources(self):
818  return self._resources_resources
819 
820  def find(self, data):
821  return self._find_with_source_find_with_source(data.source)
822 
823  def _find_with_source(self, source):
824  for other in self.resourcesresourcesresources:
825  if other.filename == source:
826  return other
827  return None
828 
829  def find_with_import(self, import_):
830  resource_model = self._namespace_namespace.find_resource_with_import(import_)
831  if not resource_model:
832  return None
833  res = self.findfind(resource_model)
834  if not res:
835  res = self.createcreate(resource_model)
836  self._project_project.insert_into_suite_structure(res)
837  assert(res is not None)
838  return res
839 
840  def create(self, data, parent=None):
841  rfc = ResourceFileController(data, self._project_project, parent, self)
842  self.resourcesresourcesresources.append(rfc)
843  self.set_all_resource_imports_unresolvedset_all_resource_imports_unresolved()
844  return rfc
845 
847  self._all_resource_imports_resolved_all_resource_imports_resolved = True
848 
850  self._all_resource_imports_resolved_all_resource_imports_resolved = False
851 
853  return self._all_resource_imports_resolved_all_resource_imports_resolved
854 
855  def remove(self, controller):
856  self._resources_resources.remove(controller)
857  self.set_all_resource_imports_unresolvedset_all_resource_imports_unresolved()
858 
859 
861 
862  def __init__(self, data, project=None, parent=None, resource_file_controller_factory=None):
863  if resource_file_controller_factory:
864  self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory = resource_file_controller_factory
865  else:
866  self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory = ResourceFileControllerFactory(self._namespace_namespace, project)
867  self._known_imports_known_imports = set()
868  _FileSystemElement.__init__(self, data.source if data else None, data.directory)
869  _DataController.__init__(self, data, project,
870  parent or self._find_parent_for_find_parent_for(project, data.source))
871  if self.parentparent and self not in self.parentparent.children:
872  self.parentparent.add_child(self)
873  self._unresolve_all_if_none_existing_unresolve_all_if_none_existing()
874 
876  if not self.existsexists() and self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory:
877  self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory.set_all_resource_imports_unresolved()
878  # Some import may have referred to this none existing resource
879 
880  def _find_parent_for(self, project, source):
881  if not project:
882  return None
883  dir = os.path.dirname(source)
884  for ctrl in project.datafiles:
885  if ctrl.is_directory_suite() and self._to_os_style_to_os_style(ctrl.directory) == dir:
886  return ctrl
887  return None
888 
889  def _to_os_style(self, path):
890  return path.replace('/', os.sep)
891 
892  @property
893  display_name = property
894 
895  def display_name(self):
896  _, tail = os.path.split(self.datadata.source)
897  return tail
898 
899  def is_modifiable(self):
900  return not self.existsexists() or not self.is_readonlyis_readonly()
901 
902  def set_format(self, format):
903  self._modify_file_name_modify_file_name(lambda: _DataController.set_format(self, format),
904  lambda imp: imp.change_format(format))
905 
906  def set_basename(self, basename):
907  self._modify_file_name_modify_file_name(lambda: _DataController.set_basename(self, basename),
908  lambda imp: imp.unresolve())
909 
910  def set_basename_and_modify_imports(self, basename):
911  old = self.filenamefilenamefilename
912  self._modify_file_name_modify_file_name(lambda: _DataController.set_basename(self, basename),
913  lambda imp: imp.change_name(os.path.basename(old),
914  os.path.basename(self.filenamefilenamefilename)))
915 
917  name = os.path.basename(self.filenamefilenamefilename)
918  # have to resolve imports before deleting
919  # see: http://code.google.com/p/robotframework-ride/issues/detail?id=1119
920  imports = [import_ for import_ in self.get_where_usedget_where_used()]
921  for resource_import in imports:
922  if resource_import.name.endswith(name):
923  resource_import.remove()
924 
925  def _modify_file_name(self, modification, notification):
926  old = self.filenamefilenamefilename
927  modification()
928  resource_imports = [resource_import_ for resource_import_ in self.get_where_usedget_where_used()]
929  for resource_import in resource_imports:
930  notification(resource_import)
931  self._namespace_namespace.resource_filename_changed(old, self.filenamefilenamefilename)
932 
933  def _settings(self):
934  return [DocumentationController(self, self.datadata.setting_table.doc)]
935 
936  def validate_name(self, name):
937  for uk in self.datadata.keyword_table.keywords:
938  if uk != name and utils.eq(uk.name, name):
939  return 'User keyword with this name already exists.'
940  return None
941 
942  def reload(self):
943  self.__init____init____init____init__(ResourceFile(source=self.filenamefilenamefilename).populate(), self._project_project,
944  parent=self.parentparent)
945 
946  def remove(self):
947  self._project_project.remove_resource(self)
948  RideDataFileRemoved(path=self.filenamefilenamefilename, datafile=self).publish()
949 
950  def remove_known_import(self, _import):
951  self._known_imports_known_imports.remove(_import)
952 
953  def add_known_import(self, _import):
954  self._known_imports_known_imports.add(_import)
955 
956  def notify_opened(self):
957  RideOpenResource(path=self.filenamefilenamefilename, datafile=self).publish()
958  for _import in [imp for imp in self.importsimportsimports if imp.is_resource]:
959  _import.import_loaded_or_modified()
960 
961  def is_used(self):
962  if self._known_imports_known_imports:
963  return True
964  if not self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory:
965  return False
966  if self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory.is_all_resource_file_imports_resolved():
967  return False
968  return any(self._resolve_known_imports_resolve_known_imports())
969 
970  def get_where_used(self):
971  if self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory.is_all_resource_file_imports_resolved():
972  source = self._known_imports_known_imports
973  else:
974  source = self._resolve_known_imports_resolve_known_imports()
975 
976  for usage in source:
977  yield usage
978 
979 
981  for imp in self._all_imports_all_imports():
982  if imp.get_imported_controller() is self:
983  yield imp
984  self._resource_file_controller_factory_resource_file_controller_factory_resource_file_controller_factory.set_all_resource_imports_resolved()
985 
986  def _all_imports(self):
987  for df in self.datafilesdatafilesdatafiles:
988  for imp in df.imports:
989  yield imp
990 
991  def remove_child(self, controller):
992  pass
993 
994 
995 class ExcludedDirectoryController(_FileSystemElement, ControllerWithParent, WithNamespace):
996 
997  def __init__(self, data, project, parent):
998  self.datadata = data
999  self._project_project = project
1000  if self._project_project:
1001  self._set_namespace_from_set_namespace_from(self._project_project)
1002  self._resource_file_controller_factory_resource_file_controller_factory =\
1003  self._project_project.resource_file_controller_factory
1004  else:
1005  self._resource_file_controller_factory_resource_file_controller_factory = None
1006  self._parent_parent_parent = parent
1007  self.childrenchildren = []
1008  self.keywordskeywords = []
1009  self.variablesvariables = tuple()
1010  self.teststests = tuple()
1011  self.importsimports = tuple()
1012  _FileSystemElement.__init__(self, '', data.directory)
1013 
1014  @property
1015  settings = property
1016 
1017  def settings(self):
1018  return self._settings_settings()
1019 
1020  def _settings(self):
1021  ss = self.datadata.setting_table
1022  return [DocumentationController(self, ss.doc),
1023  FixtureController(self, ss.suite_setup),
1024  FixtureController(self, ss.suite_teardown),
1025  FixtureController(self, ss.test_setup),
1026  FixtureController(self, ss.test_teardown),
1027  self.force_tagsforce_tagsforce_tags]
1028 
1029  @property
1030  _setting_table = property
1031 
1032  def _setting_table(self):
1033  return self.datadata.setting_table
1034 
1035  @property
1036  force_tags = property
1037 
1038  def force_tags(self):
1039  return ForceTagsController(self, self._setting_table_setting_table_setting_table.force_tags)
1040 
1041  @property
1042  dirty = property
1043 
1044  def dirty(self):
1045  return False
1046 
1047  def keyword_info(self, keyword_name):
1048  return WithNamespace.keyword_info(self, self.datadata, keyword_name)
1049 
1050  @overrides(_BaseController)
1051  def is_excluded(self):
1052  return True
1053 
1055  self._project_project._settings.excludes.remove_path(self.sourcesourcesource)
1056  index = self.parentparentparent.children.index(self)
1057  td = TestData(self.datadata.source, self.parentparentparent.data, self._project_project._settings)
1058  result = TestDataDirectoryController(td, self._project_project, self.parentparentparent)
1059  self.parentparentparent.children[index] = result
1060  return result
1061 
1062  def iter_datafiles(self):
1063  return [self]
1064 
1065  @property
1066  name = property
1067 
1068  def name(self):
1069  return self.datadata.name
1070 
1072  return True
1073 
1074  def add_child(self, child):
1075  self.childrenchildren.append(child)
Raised when data is dirty and you are trying to do an operation that requires undirty data.
def __init__(self, data, project=None, parent=None, resource_file_controller_factory=None)
def _modify_file_name(self, modification, notification)
def find_controller_by_names(self, names, node_testname=None)
def find_controller_by_longname(self, longname, node_testname=None)
def __init__(self, data, project=None, parent=None)
def _get_unknown_files_in_directory(self, children, path, initfile)
def __init__(self, data, project=None, parent=None)
def __init__(self, data, project=None, parent=None)
source
Deprecated, use filename or directory instead.
Sent when datafile changes from serialized version.
Definition: messages.py:377
Sent when datafiles dirty marking is cleared.
Definition: messages.py:272
Set when a whole datafile is replaced with new one in a controller.
Definition: messages.py:383
Sent when a new resource has finished loading.
Definition: messages.py:292
def TestData(source, parent=None, settings=None)
Parses a file or directory to a corresponding model object.
Definition: dataloader.py:127
def DataController(data, project, parent=None)
def _get_controller(project, data, parent)