20 from itertools
import chain
22 import subprocess32
as 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
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
43 if isinstance(data, TestCaseFile):
45 if isinstance(data, ExcludedDirectory):
47 if isinstance(data, ResourceFile):
48 from ..controller.project
import Project
49 from ..namespace
import Namespace
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",
55 stub = tempfile.NamedTemporaryFile(delete=
False)
58 data.parent.load_data(stub.name)
75 if path
and os.path.isfile(path):
77 return stat.st_mtime, stat.st_size
87 return self.
_stat_stat != (0, 0)
and not self.
existsexists()
90 other_path = os.path.join(other.directory, other.filename)
91 return os.path.relpath(other_path, start=self.
directorydirectory).replace(
'\\',
'/')
94 return not os.access(self.
filenamefilename, os.W_OK)
103 return os.path.splitext(os.path.basename(self.
filenamefilename))[0]
116 def __init__(self, data, project=None, parent=None):
121 project.resource_file_controller_factory
129 if hasattr(self.
datadata,
'initfile'):
149 return self.
datadata.name
158 ss = self.
datadata.setting_table
167 _setting_table = property
170 return self.
datadata.setting_table
173 force_tags = property
204 return chain([self], (df
for df
in self.
_project_project.datafiles
208 datafile_controller = property
237 return WithNamespace.is_user_keyword(self, self.
datafiledatafiledatafile, value)
240 return WithNamespace.is_library_keyword(self, self.
datafiledatafiledatafile, value)
243 return WithNamespace.keyword_info(self, self.
datadata, keyword_name)
246 if not self.
dirtydirty:
247 self.
dirtydirty =
True
253 self.
dirtydirty =
False
261 if isinstance(item, TestCaseController):
264 elif isinstance(item, UserKeywordController):
272 index_difference = self.
teststeststests.sort()
275 return index_difference
283 return index_difference
291 return index_difference
323 return os.path.splitext(self.
filenamefilename)[1].replace(
'.',
'')
326 self.
datadata.source = utils.replace_extension(self.
filenamefilename, format)
335 from .ctrlcommands
import SaveFile
338 self.
datadata.source = os.path.join(self.directory,
'%s.%s' % (basename, self.
get_formatget_format()))
340 self.
executeexecute(SaveFile())
341 if old_file != self.
filenamefilename:
345 path = path
or self.
filenamefilename
346 os.chmod(path, stat.S_IWRITE)
350 path = path
or self.
filenamefilename
351 if os.path.exists(path):
352 if sys.platform ==
'win32':
355 os.startfile(
r"%s" % os.path.dirname(path),
'explore')
356 elif sys.platform.startswith(
'linux'):
362 subprocess.Popen([
"nautilus",
"{}".format(
363 os.path.dirname(path))])
364 except OSError
or FileNotFoundError:
367 [
"dolphin",
"{}".format(os.path.dirname(path))])
368 except OSError
or FileNotFoundError:
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.")
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))])
385 path = path
or self.
filenamefilename
386 if os.path.exists(path):
390 shutil.rmtree(path
or self.
datadata.directory)
393 self.
_project_project.change_format(self, format)
396 self.
_project_project.change_format_recursive(self, format)
412 test.notify_steps_changed()
417 for datafile
in child.iter_datafiles():
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)
443 default_dir = property
446 return self.
datadata.source
449 display_name = property
452 return self.
datadata.name
466 return [child
for child
in self.
childrenchildren
if
467 isinstance(child, TestDataDirectoryController)
or
468 isinstance(child, TestCaseFileController)]
475 if suite.contains_tests():
483 namestring =
'.'.join(names)
484 if not namestring.startswith(self.
namenamename):
489 res = suite.find_controller_by_names(namestring[len(self.
namenamename)+1:].split(
'.'), testname)
503 return data.source
and os.path.isdir(data.source)
and self.
_namespace_namespace
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
521 if os.path.isdir(filename):
524 r = self.
_namespace_namespace.get_resource(filename, report_status=
False)
536 return resource
and (resource.setting_table
or resource.variable_table
or
537 resource.keyword_table
or os.stat(resource.source)[6] == 0)
541 resource_control.parent = self
542 return resource_control
545 already_in_use = [c.filename
for c
in children] + [initfile]
546 already_in_use += [c.directory
for c
in children]
550 return [os.path.join(path, f)
for f
in os.listdir(path)]
553 assert controller
not in self.
childrenchildren
554 self.
childrenchildren.append(controller)
557 return self.
datadata.initfile
is not None
560 self.
datadata.initfile = os.path.join(self.
datadata.source,
'__init__.%s'
573 self.
datadata.children.append(datafile)
574 datafile.parent = self.
datadata
590 self.
datadata.initfile =
None
597 self.
_project_project.remove_resource(resource)
601 self.
_project_project.remove_datafile(self)
606 if controller
in self.
childrenchildren:
610 child.remove_child(controller)
613 return ctrl.filename.startswith(self.
directorydirectory)
616 return any(
True for s
in [self] + self.
childrenchildren
617 if s.is_directory_suite()
and s.directory == directory)
621 resource_import[1].
remove()
629 for imp
in df.imports:
636 for imp
in all_imports:
637 if imp.get_imported_controller() == res
and imp.parent.parent
not in ctrls:
642 if controller.children:
643 for child
in controller.children:
645 elif isinstance(controller, ResourceFileController):
646 resources.append(controller)
651 if controller.children:
652 for child
in controller.children:
654 resources.append(controller)
658 res_dir = os.path.dirname(res.filename)
666 target.insert_to_test_data_directory(res)
671 if not isinstance(s, TestDataDirectoryController):
673 if res.filename.startswith(s.directory):
678 for dirname
in res_dir[len(self.
directorydirectory):].split(os.sep):
681 target_dir = os.path.join(target.directory, dirname)
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)
690 if res
not in self.
childrenchildren:
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)
704 self.
parentparent.children[index] = result
708 controllers: list[TestCaseController] = []
710 if isinstance(child,TestCaseFileController)
or isinstance(child,TestDataDirectoryController):
711 controllers += child.retrieve_test_controllers()
722 class TestCaseFileController(_FileSystemElement, _DataController):
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)
730 sett = _DataController._settings(self)
756 names =
'.'.join(names)
757 if not names.startswith(self.
namenamename):
759 if len(self.
namenamename) < len(names)
and not names.startswith(self.
namenamename+
'.'):
764 if test.name == node_testname:
769 default_tags = property
781 return self.
teststeststests.validate_name(name)
784 if controller
is self:
788 self.
_project_project.remove_datafile(self)
797 return self.
datadata.setting_table.test_template
802 controllers.append(test_ctrl)
825 if other.filename == source:
830 resource_model = self.
_namespace_namespace.find_resource_with_import(import_)
831 if not resource_model:
833 res = self.
findfind(resource_model)
835 res = self.
createcreate(resource_model)
836 self.
_project_project.insert_into_suite_structure(res)
837 assert(res
is not None)
862 def __init__(self, data, project=None, parent=None, resource_file_controller_factory=None):
863 if resource_file_controller_factory:
868 _FileSystemElement.__init__(self, data.source
if data
else None, data.directory)
869 _DataController.__init__(self, data, project,
871 if self.
parentparent
and self
not in self.
parentparent.children:
872 self.
parentparent.add_child(self)
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:
890 return path.replace(
'/', os.sep)
893 display_name = property
896 _, tail = os.path.split(self.
datadata.source)
903 self.
_modify_file_name_modify_file_name(
lambda: _DataController.set_format(self, format),
904 lambda imp: imp.change_format(format))
907 self.
_modify_file_name_modify_file_name(
lambda: _DataController.set_basename(self, basename),
908 lambda imp: imp.unresolve())
912 self.
_modify_file_name_modify_file_name(
lambda: _DataController.set_basename(self, basename),
913 lambda imp: imp.change_name(os.path.basename(old),
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()
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)
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.'
947 self.
_project_project.remove_resource(self)
958 for _import
in [imp
for imp
in self.
importsimportsimports
if imp.is_resource]:
959 _import.import_loaded_or_modified()
982 if imp.get_imported_controller()
is self:
988 for imp
in df.imports:
995 class ExcludedDirectoryController(_FileSystemElement, ControllerWithParent, WithNamespace):
1003 self.
_project_project.resource_file_controller_factory
1012 _FileSystemElement.__init__(self,
'', data.directory)
1021 ss = self.
datadata.setting_table
1030 _setting_table = property
1033 return self.
datadata.setting_table
1036 force_tags = property
1048 return WithNamespace.keyword_info(self, self.
datadata, keyword_name)
1050 @overrides(_BaseController)
1069 return self.
datadata.name
1075 self.
childrenchildren.append(child)
def _set_namespace_from(self, controller)
def execute(self, command)
Raised when data is dirty and you are trying to do an operation that requires undirty data.
_resource_file_controller_factory
def remove_from_excludes(self)
def is_directory_suite(self)
def keyword_info(self, keyword_name)
def __init__(self, data, project, parent)
def add_child(self, child)
_all_resource_imports_resolved
def __init__(self, namespace, project)
def is_all_resource_file_imports_resolved(self)
def _find_with_source(self, source)
def set_all_resource_imports_unresolved(self)
def remove(self, controller)
def set_all_resource_imports_resolved(self)
def create(self, data, parent=None)
def find_with_import(self, import_)
def validate_name(self, name)
def _unresolve_all_if_none_existing(self)
def _to_os_style(self, path)
def __init__(self, data, project=None, parent=None, resource_file_controller_factory=None)
def set_basename(self, basename)
def set_format(self, format)
_resource_file_controller_factory
def remove_known_import(self, _import)
def _modify_file_name(self, modification, notification)
def add_known_import(self, _import)
def remove_static_imports_to_this(self)
def set_basename_and_modify_imports(self, basename)
def _resolve_known_imports(self)
def _find_parent_for(self, project, source)
def remove_child(self, controller)
def find_controller_by_names(self, names, node_testname=None)
def validate_test_name(self, name)
def find_controller_by_longname(self, longname, node_testname=None)
def create_test(self, name)
def __init__(self, data, project=None, parent=None)
def remove_child(self, controller)
def retrieve_test_controllers(self)
def add_child(self, child)
def set_format(self, format)
def _resource_controller(self, resource)
def insert_to_test_data_directory(self, res)
def _add_directory_children(self, children, path, initfile)
def find_controller_by_longname(self, longname, testname=None)
def new_test_data_directory(self, path)
def _create_target_dir_controller(self, res, res_dir, target)
def new_resource(self, path)
def remove_from_model(self)
def _is_valid_resource(self, resource)
def add_child(self, controller)
def notify_suite_added(self, suite)
def _is_inside_test_data_directory(self, directory)
def is_directory_suite(self)
def _find_resources_recursively(self, controller)
def _add_directory_child(self, children, filename)
def _get_unknown_files_in_directory(self, children, path, initfile)
def _is_robot_ignored_name(self, filename)
def _directory_controller(self, path)
def _get_recursive_imports(self)
def is_inside_top_suite(self, ctrl)
def _find_closest_directory(self, res)
def new_test_case_file(self, path)
def __init__(self, data, project=None, parent=None)
def remove_child(self, controller)
def _children(self, data)
def _get_filenames_in_directory(self, path)
def _find_controllers_recursively(self, controller)
def remove_static_imports_to_this(self)
def _remove_resources(self)
def _filename(self, data)
def _new_data_controller(self, datafile)
def find_controller_by_names(self, names, testname)
def _can_add_directory_children(self, data)
def retrieve_test_controllers(self)
def restore_keyword_order(self, index_difference)
_testcase_table_controller
def validate_keyword_name(self, name)
def notify_steps_changed(self)
def is_directory_suite(self)
_keywords_table_controller
def _children(self, data)
def remove_from_filesystem(self, path=None)
def remove_readonly(self, path=None)
def __init__(self, data, project=None, parent=None)
def notify_settings_changed(self)
_resource_file_controller_factory
def add_test_or_keyword(self, item)
def get_keyword_names(self)
def open_filemanager(self, path=None)
def set_datafile(self, datafile)
def save_with_new_format_recursive(self, format)
def create_keyword(self, name, argstr='')
def set_basename(self, basename)
def is_same_format(self, format)
def save_with_new_format(self, format)
def get_local_variables(self)
def is_inside_top_suite(self, res)
def set_format(self, format)
_variables_table_controller
def keyword_info(self, keyword_name)
def remove_folder_from_filesystem(self, path=None)
def is_library_keyword(self, value)
def restore_variable_order(self, index_difference)
def is_user_keyword(self, value)
def restore_test_order(self, index_difference)
def resource_import_modified(self, path)
def has_been_modified_on_disk(self)
def __init__(self, filename, directory)
def _get_stat(self, path)
source
Deprecated, use filename or directory instead.
def has_been_removed_from_disk(self)
def relative_path_to(self, other)
Sent when datafile changes from serialized version.
Sent when datafiles dirty marking is cleared.
Set when a whole datafile is replaced with new one in a controller.
Sent when a new resource has finished loading.
def TestData(source, parent=None, settings=None)
Parses a file or directory to a corresponding model object.
def DataController(data, project, parent=None)
def _get_controller(project, data, parent)
def NewTestCaseFile(path)
def NewTestDataDirectory(path)