Coverage for src/robotide/controller/filecontrollers.py: 75%

945 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-06 10:40 +0100

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 

16import os 1ab

17import shutil 1ab

18import stat 1ab

19import subprocess 1ab

20import sys 1ab

21from itertools import chain 1ab

22from .dataloader import ExcludedDirectory, test_data 1ab

23from ..publish import (RideDataFileRemoved, RideInitFileRemoved, RideDataChangedToDirty, RideDataDirtyCleared, 1ab

24 RideSuiteAdded, RideItemSettingsChanged) 

25from ..publish.messages import RideDataFileSet, RideOpenResource 1ab

26from ..robotapi import TestDataDirectory, TestCaseFile, ResourceFile 1ab

27from .. import utils 1ab

28 

29from .basecontroller import WithUndoRedoStacks, _BaseController, WithNamespace, ControllerWithParent 1ab

30from .robotdata import new_test_case_file, new_test_data_directory 1ab

31from .settingcontrollers import (DocumentationController, FixtureController, TimeoutController, TemplateController, 1ab

32 DefaultTagsController, ForceTagsController, TestTagsController) 

33from .tablecontrollers import (VariableTableController, TestCaseTableController, KeywordTableController, 1ab

34 ImportSettingsController, MetadataListController) 

35from .macrocontrollers import TestCaseController, UserKeywordController 1ab

36 

37 

38def _get_controller(project, data, parent, tasks=False): 1ab

39 if isinstance(data, TestCaseFile): 2a V B A X Y p e M C { | } ~ ab0 [ 1 2 3 ] 4 5 6 bb

40 return TestCaseFileController(data, project, parent, tasks=tasks) 2a V B A p e M C { | } ~ ab0 [ 1 2 3 ] 4 5 6 bb

41 if isinstance(data, ExcludedDirectory): 41 ↛ 42line 41 didn't jump to line 42 because the condition on line 41 was never true1aXY

42 return ExcludedDirectoryController(data, project, parent) 

43 if isinstance(data, ResourceFile): 1aXY

44 from ..controller.project import Project 

45 from ..namespace import Namespace 

46 import tempfile 

47 if not data.parent: 47 ↛ 59line 47 didn't jump to line 59 because the condition on line 47 was always true

48 data.parent = Project(Namespace(data.settings), data.settings) 

49 content = bytes(f"*** Settings ***\n" 

50 f"Resource {data.source}\n\n" 

51 f"*** Test Cases ***\n" 

52 f"Empty\n" 

53 f" 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, tasks=tasks) 1aXY

61 

62 

63def data_controller(data, project, parent=None, tasks=False): 1ab

64 return _get_controller(project, data, parent, tasks=tasks) 2a V B A X Y p e M C { | } ~ ab0 [ 1 2 3 ] 4 5 6 bb

65 

66 

67def explorer_linux(folder): 1ab

68 try: 2,c

69 subprocess.Popen(["nautilus", folder]) 2,c

70 except OSError: 2,c

71 try: 2,c

72 subprocess.Popen(["dolphin", folder]) 2,c

73 except OSError: 2,c

74 try: 2,c

75 subprocess.Popen(["konqueror", folder]) 2,c

76 except OSError: 2,c

77 print("Could not launch explorer. Tried nautilus, dolphin and konqueror.") 2,c

78 

79 

80def explorer_mac(folder): 1ab

81 try: 2!e]b1c

82 subprocess.Popen(["finder", folder]) 2!e]b1c

83 except OSError: 2!e]b1c

84 subprocess.Popen(["open", folder]) 2!e]b1c

85 

86 

87def start_filemanager(path=None, tool=None): 1ab

88 if not os.path.exists(path): 2wf]b1c

89 return 2wf

90 if not os.path.isfile(path): 90 ↛ 91line 90 didn't jump to line 91 because the condition on line 90 was never true2]b1c

91 folder = path 

92 else: 

93 folder = os.path.dirname(path) 2]b1c

94 if tool: 2]b1c

95 try: 2]b

96 subprocess.Popen([tool, folder]) 2]b

97 return 

98 except OSError: 2]b

99 print(f"DEBUG: Error when launching tool={tool}") 2]b

100 if sys.platform == 'win32': 100 ↛ 101line 100 didn't jump to line 101 because the condition on line 100 was never true2]b1c

101 os.startfile(folder, 'explore') 

102 elif sys.platform.startswith('linux'): 102 ↛ 103line 102 didn't jump to line 103 because the condition on line 102 was never true2]b1c

103 explorer_linux(folder) 

104 else: 

105 explorer_mac(folder) 2]b1c

106 

107 

108class _FileSystemElement(object): 1ab

109 

110 def __init__(self, filename, directory): 1ab

111 self.filename = filename 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebmdh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

112 self.directory = directory 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebmdh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

113 self._stat = self._get_stat(filename) 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebmdh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

114 

115 @staticmethod 1ab

116 def _get_stat(path): 1ab

117 if path and os.path.isfile(path): 2a J K E V F D w x ^ U L s t v G u q r :c9b;cy jbP Q kblbR S T B A X Y _ obH cbdbeb-cPemdh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

118 stats = os.stat(path) 2a V F p e z ? M C mbN ` nbZ f c i k l j 0 [ 1 2 3 ] 4 5 6

119 return stats.st_mtime, stats.st_size 2a V F p e z ? M C mbN ` nbZ f c i k l j 0 [ 1 2 3 ] 4 5 6

120 return 0, 0 2a J K E D w x ^ U L s t v G u q r :c9b;cy jbP Q kblbR S T B A X Y _ obH cbdbeb-cPemdh g d m o n 7 8 9 fbgbhbe f c i k l j W @ pbqbrbsb{ | } ~ abbb! # $ % ' ( ) * + , - . / : ; =

121 

122 def refresh_stat(self): 1ab

123 self._stat = self._get_stat(self.filename) 2a :c9b;cP Q R S T -cPeh g d N f c i k l j

124 

125 def has_been_modified_on_disk(self): 1ab

126 return self._get_stat(self.filename) != self._stat 2M mbN nb

127 

128 def has_been_removed_from_disk(self): 1ab

129 return self._stat != (0, 0) and not self.exists() 

130 

131 def relative_path_to(self, other): 1ab

132 other_path = os.path.join(other.directory, other.filename) 2md

133 return os.path.relpath(other_path, start=self.directory).replace('\\', '/') 2md

134 

135 def is_readonly(self): 1ab

136 return not os.access(self.filename, os.W_OK) 2a bc2c3cccdc?b4cecfcgchc5c=c[b^b_b`b{b6cacmcncocic?cjc|bkc7c8cZb=b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcO N #b(b;b9cLcMc!cBbEbtbiblc

137 

138 def exists(self): 1ab

139 return self.filename and os.path.isfile(self.filename) 2a bc2c3cccdc?b4cecfcgchc5c=c[b^b_b`b{b6cacmcncocic?cjc|bkcE F D s t v G u q r :c9b;cndodpd#c$c%c_eqdrdsdtdudvdwdxdydzdAdBdCdDd`eEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d{e4d5d6d7d8d9d!d#d$d%d'd|e(d)d*d+d,d-d.d/d:d}e;d=d?d@d[d]d~e^d_d`d{d|d}d~daebeafce'c(c7c8cP Q R S T )bZb=b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJch g d m o n deeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDebfcfdfefEeFeGeHeIeJeKeffgfhfifLeMeNcOcPcQcRcScTcUcVc)cWcXc*c7 8 9 KcO p e z N Z #b(b;b9cLcMc!cFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbBbEbtbf c i k l j .c@c[c]c^c_c`cW @ iblc

140 

141 @property 1ab

142 def basename(self): 1ab

143 return os.path.splitext(os.path.basename(self.filename))[0] 

144 

145 @property 1ab

146 def source(self): 1ab

147 """Deprecated, use ``filename`` or ``directory`` instead.""" 

148 # DEBUG: remove when backwards compatibility with plugin API can break 

149 return self.filename or self.directory 2a y ebWbxbybiblc

150 

151 

152class _DataController(_BaseController, WithUndoRedoStacks, WithNamespace): 1ab

153 directory = None 1ab

154 

155 def __init__(self, data, project=None, parent=None): 1ab

156 self.data = data 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

157 self._variables_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

158 self._testcase_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

159 self._keywords_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

160 self._imports = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

161 self._project = project 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

162 if project: 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

163 self._set_namespace_from(project) 1aJKEVFDyHhgdmonpez?Nfciklj

164 self._resource_file_controller_factory =\ 1aJKEVFDyHhgdmonpez?Nfciklj

165 project.resource_file_controller_factory 

166 else: 

167 self._resource_file_controller_factory = None 2a J K w x ^ U L s t v G u q r jbP Q kblbR S T B A X Y _ obcbdbeb7 8 9 fbgbhbM C mb` nbZ W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

168 self.parent = parent 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

169 try: 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

170 self._language = self.data._language 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

171 # print(f"DEBUG: filecontrollers.py _DataController language set = {self._language}") 

172 except AttributeError: 2a 7 8 9 fbgbhb

173 self._language = ['en'] 2a 7 8 9 fbgbhb

174 self.set_datafile(data) 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

175 self.dirty = False 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

176 self.children = self._children(data) 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

177 # Filename needs to be set when creating a new datafile 

178 if hasattr(self.data, 'initfile'): 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

179 self.filename = self.data.initfile 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

180 else: 

181 self.filename = self.data.source 2a J K E V F D w x L s t v G u q r jbP Q kblbR S T B A h g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

182 

183 def set_datafile(self, datafile): 1ab

184 self.data = datafile 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

185 self._variables_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

186 self._testcase_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

187 self._keywords_table_controller = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

188 self._imports = None 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

189 RideDataFileSet(item=self).publish() 2a J K E V F D w x ^ U L s t v G u q r y jbP Q kblbR S T B A X Y _ obH cbdbebh g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

190 

191 def _children(self, data): 1ab

192 _ = data 2a J K E V F D w x L s t v G u q r jbP Q kblbR S T B A h g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

193 return [] 2a J K E V F D w x L s t v G u q r jbP Q kblbR S T B A h g d m o n 7 8 9 fbgbhbp e z ? M C mbN ` nbZ f c i k l j W @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

194 

195 @property 1ab

196 def name(self): 1ab

197 return self.data.name 2a xfzbfdE F D w x ^ U L G y #eY Zbz :bAbI Dbubvbwbj Ne{c|ciblc

198 

199 @property 1ab

200 def settings(self): 1ab

201 return self.internal_settings() 2Yc_ C *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbyb

202 

203 def internal_settings(self): 1ab

204 ss = self.data.setting_table 2Yc_ C *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

205 return [DocumentationController(self, ss.doc), 2Yc_ C *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

206 FixtureController(self, ss.suite_setup), 

207 FixtureController(self, ss.suite_teardown), 

208 FixtureController(self, ss.test_setup), 

209 FixtureController(self, ss.test_teardown), 

210 self.force_tags, self.test_tags] 

211 

212 @property 1ab

213 def setting_table(self): 1ab

214 return self.data.setting_table 29b#c$c%cYc_ }c~cC *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxb.c@c[c]c^c_cQeReSeTeUe`c$eadgdybW @ hdVe%e

215 

216 @property 1ab

217 def force_tags(self): 1ab

218 return ForceTagsController(self, self.setting_table.force_tags) 29b#c$c%cYc_ }c~cC *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxb.c@c[c]c^c_cQeReSeTeUe`c$eadgdybW @ hdVe%e

219 

220 @property 1ab

221 def test_tags(self): 1ab

222 return TestTagsController(self, self.setting_table.test_tags) 29b#c$c%cYc_ }c~cC *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxb.c@c[c]c^c_cQeReSeTeUe`c$eadgdybW @ hdVe%e

223 

224 @property 1ab

225 def variables(self): 1ab

226 if self._variables_table_controller is None: 2a 7c8c=bLcMc!cAbVbI Db@bbd

227 self._variables_table_controller = VariableTableController(self, self.data.variable_table) 2a 7c8c=bLcMcAb

228 return self._variables_table_controller 2a 7c8c=bLcMc!cAbVbI Db@bbd

229 

230 @property 1ab

231 def tests(self): 1ab

232 if self._testcase_table_controller is None: 2a J yfzfAfBfCfDfK w x L 9b+ccd)b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJc)c*c` #b(b;b9c*b!b$b+b,b-b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbadgdybWe2 ! # $ % ' ( {c@bbd

233 self._testcase_table_controller = TestCaseTableController(self, self.data.testcase_table) 2a J K w x L +ccd)b}b)c*c` #b*bFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYbXbxbadyb2 ! # $ % ' (

234 return self._testcase_table_controller 2a J yfzfAfBfCfDfK w x L 9b+ccd)b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJc)c*c` #b(b;b9c*b!b$b+b,b-b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbadgdybWe2 ! # $ % ' ( {c@bbd

235 

236 @property 1ab

237 def datafile(self): 1ab

238 return self.data 2a bc2c3cccdc?b4cecidjdfcgchc5c=c[b^b_b`b{b6cacmckdncocic?cjc|bkcw x L 9b#c$c%cXeYeZe'c(c7c8c+cddedcd)b/bYfZf0f1f2f0e3f4fNcOcPcQcRcScTcUcVc)cWcXc*c}c~c5f1e2eEf3eN #b(b;b9cLcMc!cCbWbtbf c i k l j 4e5e6eld7eadgdybWeFfGfHfIfJfKfLfMf6f7f8f9f!f#f$f%f'f(f)f*f0 +f,f[ -f.f/f:f;f=f?fNf@f[f1 2 3 ] 4 ]f5 6 bb! # $ % ' ( ) * + , - . / : ; = {c|c

239 

240 @property 1ab

241 def datafiles(self): 1ab

242 return chain([self], (df for df in self._project.datafiles 2a zbh g d m o n O *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbc ybib

243 if df != self)) 

244 

245 @property 1ab

246 def datafile_controller(self): 1ab

247 return self 2a J K bc2c3cccdc?b4cecidjdfcgchc5c=c[b^b_b`b{b6cacmckdncocic?cjc|bkcw x L :c9b;cndodpd#c$c%c_eqdrdsdtdudvdwdxdydzdAdBdCdDd`eEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d{e4d5d6d7d8d9d!d#d$d%d'd|e(d)d*d+d,d-d.d/d:d}e;d=d?d@d[d]d~e^d_d`d{d|d}d~daebeafce'e(e)e*e8e+e,e-e.e/e:eXeYeZe'c(c7c8cP Q R S T +cddedcd)b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJch g d m n deeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDebfcfdfefEeFeGeHeIeJeKeffgfhfifLeMeNcOcPcQcRcScTcUcVc)cWcXc*c}c~c1e2eEf3e;e=eO N ` Z #b(b;b9cLcMc!c*b!b$b+b,b-b:b.b%b'bAbVbI DbjfFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j 4e5e6e.c@c[c]c^c_cQeReSeTeUe`c$eld7eadgdybW @ pbqbrbsb{ | } ~ abhdVe%e^fWeFfGfHfIfJf_fKfLfMf0 1 2 3 4 5 6 ! # $ % ' ( ) * + , - . / : ; = {c|cib/clc

248 

249 @property 1ab

250 def keywords(self): 1ab

251 if self._keywords_table_controller is None: 2a ?b9b'c(cddedZbNcOcPcQcRcScTcUcVcWcXcZ #b(b;b!b$b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j ld7eyb0 1 3 4 5 6 ) * + , - . / : ; = |cOfPf@bbd

252 self._keywords_table_controller = KeywordTableController(self, self.data.keyword_table) 2a 9b'c(cddedZbNcOcPcQcRcScTcUcVcWcXcZ #b(b!bFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYbXbxbf c i k l j ldyb0 1 3 4 5 6 ) * + , - . / : ; =

253 return self._keywords_table_controller 2a ?b9b'c(cddedZbNcOcPcQcRcScTcUcVcWcXcZ #b(b;b!b$b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j ld7eyb0 1 3 4 5 6 ) * + , - . / : ; = |cOfPf@bbd

254 

255 @property 1ab

256 def imports(self): 1ab

257 if not self._imports: 2a zb[b^b_b`b{bE F D h g d m o n 0eO z AbVbI Dbf c i k l j ib/cQflc

258 self._imports = ImportSettingsController(self, self.data.setting_table, 2a zb[bE F D h g d m o n 0eO z AbI f c i k l j ib

259 self._resource_file_controller_factory) 

260 return self._imports 2a zb[b^b_b`b{bE F D h g d m o n 0eO z AbVbI Dbf c i k l j ib/cQflc

261 

262 @property 1ab

263 def metadata(self): 1ab

264 return MetadataListController(self, self.data.setting_table) 

265 

266 def is_user_keyword(self, datafile, value): 1ab

267 _ = datafile 2bc2c3cccdc?b4cecidjdfcgchc5c[b^b_b`b{b6cacmckdncocicjc|bkc/b#b(b;bf c i

268 # print(f"DEBUG: filecontrollers.py _DataController is_user_keyword datafile={datafile} " 

269 # f" value={value}") 

270 return WithNamespace.is_user_keyword(self, self.datafile, value) 2bc2c3cccdc?b4cecidjdfcgchc5c[b^b_b`b{b6cacmckdncocicjc|bkc/b#b(b;bf c i

271 

272 def is_library_keyword(self, datafile, value): 1ab

273 _ = datafile 2ccdc?becidjdfcgchc[b^b_b`b{bacmckdncocicjc|bkc/bf c i

274 return WithNamespace.is_library_keyword(self, self.datafile, value) 2ccdc?becidjdfcgchc[b^b_b`b{bacmckdncocicjc|bkc/bf c i

275 

276 def keyword_info(self, datafile, keyword_name): 1ab

277 _ = datafile 2bc2c3cccdc?b4cecidjdfcgchc5c=c[b^b_b`b{b6cacmckdncocic?cjc|bkc/b#b(b;b*b!b$b+b,b-b:b.b%b'bAbVbI DbjfFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i yb

278 return WithNamespace.keyword_info(self, self.data, keyword_name) 2bc2c3cccdc?b4cecidjdfcgchc5c=c[b^b_b`b{b6cacmckdncocic?cjc|bkc/b#b(b;b*b!b$b+b,b-b:b.b%b'bAbVbI DbjfFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i yb

279 

280 def mark_dirty(self): 1ab

281 if not self.dirty: 2a bc2c3cccdc?b4cecfcgchc5c=c[b^b_b`b{b6cacmcncocic?cjc|bkcw x L 9bndodpd#c$c%cqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,d-d.d/d:d;d=d?d@d[d]d^d_d`d{d|d}d~daebece'e(e)e*e8e+e,e-e.e/e:ekflfXeYemfZenfofOe'c(c7c8c+cddedcd)bB A cb-cpfqfZb=b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJcd m n deeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNcOcPcQcRcScTcUcVc)cWcXc*c}c~crfsf1e2e3etf;e=eO #b(b;b9cLcMc!cFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbBbEbtbxbf c i k l j 4e5e6e.c@c[c]c^c_c`cld7eadgdW hd! # $ % ' ( ) * + , - . / : ; = {c|c@bbd/c

282 self.dirty = True 2a bcac|bw x L 9bndodpd#c$c%cqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,d-d.d/d:d;d=d?d@d[d]d^d_d`d{d|d}d~daebece'e(e)e*e8e+e,e-e.e/e:ekflfXeYemfZenfofOe'c(c7c8c+cddedcd)bB A cb-cpfqfZb=b}bd m n deeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNcOcPcQcRcScTcUcVc)cWcXc*c}c~crfsf1e2e3etf;e=eO #b(bFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbBbtbxbf c i k l j 4e5e6e.c@c[c]c^c_c`cldW hd! # $ % ' ( ) * + , - . / : ; = {c|c@bbd/c

283 RideDataChangedToDirty(datafile=self).publish() 2a bcac|bw x L 9bndodpd#c$c%cqdrdsdtdudvdwdxdydzdAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d4d5d6d7d8d9d!d#d$d%d'd(d)d*d+d,d-d.d/d:d;d=d?d@d[d]d^d_d`d{d|d}d~daebece'e(e)e*e8e+e,e-e.e/e:ekflfXeYemfZenfofOe'c(c7c8c+cddedcd)bB A cb-cpfqfZb=b}bd m n deeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDeEeFeGeHeIeJeKeLeMeNcOcPcQcRcScTcUcVc)cWcXc*c}c~crfsf1e2e3etf;e=eO #b(bFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbBbtbxbf c i k l j 4e5e6e.c@c[c]c^c_c`cldW hd! # $ % ' ( ) * + , - . / : ; = {c|c@bbd/c

284 

285 def unmark_dirty(self): 1ab

286 self.refresh_stat() 2a :c9b;cP Q R S T -cPeh g d N f c i k l j

287 if self.dirty: 2a :c9b;cP Q R S T -cPeh g d N f c i k l j

288 self.dirty = False 29b-cf c i k l j

289 # print(f"DEBUG: filecontrollers unmark_dirty PUBLISH RideDataDirtyCleared") 

290 RideDataDirtyCleared(datafile=self).publish() 29b-cf c i k l j

291 

292 @property 1ab

293 def is_dirty(self): 1ab

294 return self.dirty 2We

295 

296 def create_keyword(self, name, argstr=''): 1ab

297 return self.keywords.new(name, argstr) 2?b'c(cddedNcOcPcQcRcScTcUcVcWcXcf c i k l j ) * + , - . / : ; = |c

298 

299 def add_test_or_keyword(self, item): 1ab

300 if isinstance(item, TestCaseController): 2+c)b#b(b;b9cLcMc!c

301 self.tests.add(item) 2+c)b9c

302 item.set_parent(self.tests) 2+c)b9c

303 elif isinstance(item, UserKeywordController): 2#b(b;bLcMc!c

304 self.keywords.add(item) 2#b(b;b

305 item.set_parent(self.keywords) 2#b(b;b

306 else: 

307 self.variables.add_variable(item.name, item.value, item.comment) 2LcMc!c

308 

309 def sort_tests(self): 1ab

310 if self.tests: 310 ↛ 315line 310 didn't jump to line 315 because the condition on line 310 was always true2)b

311 index_difference = self.tests.sort() 2)b

312 self.mark_dirty() 2)b

313 RideDataFileSet(item=self).publish() 2)b

314 return index_difference 2)b

315 return None 

316 

317 def sort_keywords(self): 1ab

318 if self.keywords: 318 ↛ 323line 318 didn't jump to line 323 because the condition on line 318 was always true2Zb

319 index_difference = self.keywords.sort() 2Zb

320 self.mark_dirty() 2Zb

321 RideDataFileSet(item=self).publish() 2Zb

322 return index_difference 2Zb

323 return None 

324 

325 def sort_variables(self): 1ab

326 if self.variables: 326 ↛ 331line 326 didn't jump to line 331 because the condition on line 326 was always true2=b

327 index_difference = self.variables.sort() 2=b

328 self.mark_dirty() 2=b

329 RideDataFileSet(item=self).publish() 2=b

330 return index_difference 2=b

331 return None 

332 

333 def restore_test_order(self, index_difference): 1ab

334 if self.tests and index_difference: 334 ↛ exitline 334 didn't return from function 'restore_test_order' because the condition on line 334 was always true2)b

335 self.tests.restore_test_order(index_difference) 2)b

336 self.mark_dirty() 2)b

337 RideDataFileSet(item=self).publish() 2)b

338 

339 def restore_keyword_order(self, index_difference): 1ab

340 if self.keywords and index_difference: 340 ↛ exitline 340 didn't return from function 'restore_keyword_order' because the condition on line 340 was always true2Zb

341 self.keywords.restore_keyword_order(index_difference) 2Zb

342 self.mark_dirty() 2Zb

343 RideDataFileSet(item=self).publish() 2Zb

344 

345 def restore_variable_order(self, index_difference): 1ab

346 if self.variables and index_difference: 346 ↛ exitline 346 didn't return from function 'restore_variable_order' because the condition on line 346 was always true2=b

347 self.variables.restore_variable_order(index_difference) 2=b

348 self.mark_dirty() 2=b

349 RideDataFileSet(item=self).publish() 2=b

350 

351 def get_keyword_names(self): 1ab

352 if self.keywords: 352 ↛ 354line 352 didn't jump to line 354 because the condition on line 352 was always true2Zbxb

353 return [kw.name for kw in self.keywords.items] 2Zbxb

354 return None 

355 

356 def has_format(self): 1ab

357 return True 2a `f

358 

359 def get_format(self): 1ab

360 if not self.filename: 360 ↛ 361line 360 didn't jump to line 361 because the condition on line 360 was never true2a jbP Q kblbR S T Rfh g d

361 return None 

362 return os.path.splitext(self.filename)[1].replace('.', '') 2a jbP Q kblbR S T Rfh g d

363 

364 def set_format(self, formatt): 1ab

365 self.data.source = utils.replace_extension(self.filename, formatt) 2a Sfm o n

366 self.filename = self.data.source 2a Sfm o n

367 

368 def is_same_format(self, formatt): 1ab

369 if formatt and self.has_format(): 

370 return formatt.lower() == self.get_format().lower() 

371 return False 

372 

373 def set_basename(self, basename): 1ab

374 from .ctrlcommands import SaveFile 1PQRSThgd

375 

376 old_file = self.filename 1PQRSThgd

377 self.data.source = os.path.join(self.directory, '%s.%s' % (basename, self.get_format())) 1PQRSThgd

378 self.filename = self.data.source 1PQRSThgd

379 self.execute(SaveFile()) 1PQRSThgd

380 if old_file != self.filename: 380 ↛ exitline 380 didn't return from function 'set_basename' because the condition on line 380 was always true1PQRSThgd

381 self.remove_from_filesystem(old_file) 1PQRSThgd

382 

383 def remove_readonly(self, path=None): 1ab

384 path = path or self.filename 

385 os.chmod(path, stat.S_IWRITE) 

386 

387 def open_filemanager(self, path=None, tool=None): 1ab

388 path = path or self.filename 

389 start_filemanager(path, tool) 

390 

391 def remove_from_filesystem(self, path=None): 1ab

392 path = path or self.filename 2KcO

393 if os.path.exists(path): 393 ↛ exitline 393 didn't return from function 'remove_from_filesystem' because the condition on line 393 was always true2KcO

394 os.remove(path) 2KcO

395 

396 def remove_folder_from_filesystem(self, path=None): 1ab

397 shutil.rmtree(path or self.data.directory) 

398 

399 def save_with_new_format(self, formatt): 1ab

400 self._project.change_format(self, formatt) 

401 

402 def save_with_new_format_recursive(self, formatt): 1ab

403 self._project.change_format_recursive(self, formatt) 

404 

405 def validate_keyword_name(self, name): 1ab

406 return self.keywords.validate_name(name) 2?bNcOcPcQcRcScTcUcVcWcXc

407 

408 def is_directory_suite(self): 1ab

409 return False 1ahgdmon

410 

411 def resource_import_modified(self, path): 1ab

412 return self._project.resource_import_modified(path, self.directory) 28ef c i k l j /c

413 

414 def notify_settings_changed(self, old_name=None): 1ab

415 _ = old_name 2ubvbwbxbW

416 RideItemSettingsChanged(item=self).publish() 2ubvbwbxbW

417 

418 def notify_steps_changed(self): 1ab

419 for test in self.tests: 

420 test.notify_steps_changed() 

421 

422 def iter_datafiles(self): 1ab

423 yield self 2a zbfdV s t v u q r y ?eZb}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJch g d m o n O e *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j ybNeib

424 for child in self.children: 2a zbfdV s t v u q r y ?eZb}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJch g d m o n O e *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j ybNeib

425 for datafile in child.iter_datafiles(): 2a zbfds t q r y ?eZb}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJcO e AbVbI DbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbf c i k l j ybNeib

426 yield datafile 2a zbfds t q r y ?eZb}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJcO e AbVbI DbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbf c i k l j ybNeib

427 

428 def save(self): 1ab

429 self._project.save(self) 2a :c9b;cN f c i k l j

430 

431 @staticmethod 1ab

432 def get_local_variables(): 1ab

433 return {} 2[ Nf] bb

434 

435 def is_inside_top_suite(self, res): 1ab

436 _ = res 

437 return False 

438 

439 @staticmethod 1ab

440 def refresh_stat(): 1ab

441 return NotImplemented 

442 

443 

444class TestDataDirectoryController(_DataController, _FileSystemElement, _BaseController): 1ab

445 __test__ = False 1ab

446 

447 def __init__(self, data, project=None, parent=None, tasks=False): 1ab

448 dir_ = data.directory 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

449 dir_ = os.path.abspath(dir_) if isinstance(dir_, str) else dir_ 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

450 _FileSystemElement.__init__(self, self._filename(data), dir_) 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

451 _DataController.__init__(self, data, project, parent) 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

452 self._dir_controllers = {} 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

453 self.tasks = tasks 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

454 

455 @staticmethod 1ab

456 def _filename(data): 1ab

457 return data.initfile 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

458 

459 @property 1ab

460 def default_dir(self): 1ab

461 return self.data.source 2ob

462 

463 @property 1ab

464 def display_name(self): 1ab

465 return self.data.name 2a dbyb

466 

467 @property 1ab

468 def language(self): 1ab

469 return self._language 

470 

471 @property 1ab

472 def longname(self): 1ab

473 if self.parent: 2db

474 return self.parent.longname + '.' + self.display_name 2db

475 return self.display_name 2db

476 

477 @property 1ab

478 def suites(self): 1ab

479 return [child for child in self.children if 2a xfw x U Oe0e

480 isinstance(child, TestDataDirectoryController) or 

481 isinstance(child, TestCaseFileController)] 

482 

483 def add_child(self, controller): 1ab

484 assert controller not in self.children 1awxUstvuqrefciklj

485 self.children.append(controller) 1awxUstvuqrefciklj

486 

487 def contains_tests(self): 1ab

488 for suite in self.suites: 

489 if suite.contains_tests(): 489 ↛ 488line 489 didn't jump to line 488 because the condition on line 489 was always true

490 return True 

491 return False 

492 

493 def find_controller_by_longname(self, longname, testname=None): 1ab

494 return self.find_controller_by_names(longname.split("."), testname) 1wx^U

495 

496 def find_controller_by_names(self, names, testname): 1ab

497 namestring = '.'.join(names) 1wx^U

498 if not namestring.startswith(self.name): 498 ↛ 499line 498 didn't jump to line 499 because the condition on line 498 was never true1wx^U

499 return None 

500 if namestring == self.name: 1wx^U

501 return self 1^U

502 for suite in self.suites: 502 ↛ exitline 502 didn't return from function 'find_controller_by_names' because the loop on line 502 didn't complete1wxU

503 res = suite.find_controller_by_names(namestring[len(self.name)+1:].split('.'), testname) 1wxU

504 if res: 1wxU

505 return res 1wxU

506 

507 def is_excluded(self): 1ab

508 return self._project.is_excluded(self.source) if self._project else False 

509 

510 def _children(self, data): 1ab

511 children = [data_controller(child, self._project, self) for child in data.children] 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

512 if self._can_add_directory_children(data): 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

513 self._add_directory_children(children, data.source, data.initfile) 1aype

514 return children 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

515 

516 def _can_add_directory_children(self, data): 1ab

517 return data.source and os.path.isdir(data.source) and self.namespace 2a J K w x ^ U s t v G u q r y B A X Y _ obH cbdbebp e M C

518 

519 def _add_directory_children(self, children, path, initfile): 1ab

520 if not children: 1aype

521 return 1ay

522 for filename in self._get_unknown_files_in_directory(children, path, initfile): 1ape

523 if not self._is_robot_ignored_name(filename): 1ape

524 self._add_directory_child(children, filename) 1ape

525 

526 @staticmethod 1ab

527 def _is_robot_ignored_name(filename): 1ab

528 base = os.path.basename(filename) 1ape

529 robotformat = (".txt", ".robot", ".resource", ".rst", " .rest", ".tsv") # Removed ".htm", ".html" 1ape

530 nonrobot_file = os.path.isfile(filename) and not base.endswith(robotformat) 1ape

531 hidden = base.startswith('.') 1ape

532 private = base.startswith('_') 1ape

533 return hidden or private or nonrobot_file 1ape

534 

535 def _add_directory_child(self, children, filename): 1ab

536 if os.path.isdir(filename): 1ape

537 children.append(self._directory_controller(filename)) 

538 else: 

539 r = self.namespace.get_resource(filename, report_status=False) 1ape

540 if self._is_valid_resource(r): 1ape

541 children.append(self._resource_controller(r)) 1ape

542 

543 def _directory_controller(self, path): 1ab

544 dc = TestDataDirectoryController(TestDataDirectory(source=path), 

545 project=self._project, 

546 parent=self) 

547 self._add_directory_children(dc.children, dc.source, None) 

548 return dc 

549 

550 @staticmethod 1ab

551 def _is_valid_resource(resource): 1ab

552 return resource and (resource.setting_table or resource.variable_table or 1ape

553 resource.keyword_table or os.stat(resource.source)[6] == 0) 

554 

555 def _resource_controller(self, resource): 1ab

556 resource_control = self._resource_file_controller_factory.create(resource) 1ape

557 resource_control.parent = self 1ape

558 return resource_control 1ape

559 

560 def _get_unknown_files_in_directory(self, children, path, initfile): 1ab

561 already_in_use = [c.filename for c in children] + [initfile] 1ape

562 already_in_use += [c.directory for c in children] 1ape

563 return [f for f in self._get_filenames_in_directory(path) if f not in already_in_use] 1ape

564 

565 @staticmethod 1ab

566 def _get_filenames_in_directory(path): 1ab

567 return [os.path.join(path, f) for f in os.listdir(path)] 1ape

568 

569 def has_format(self): 1ab

570 return self.data.initfile is not None 2a cbebe

571 

572 def set_format(self, formatt): 1ab

573 self.data.initfile = os.path.join(self.data.source, '__init__.%s' 2a eb

574 % formatt.lower()) 

575 self.filename = self.data.initfile 2a eb

576 

577 def new_test_case_file(self, path): 1ab

578 ctrl = self._new_data_controller(new_test_case_file(path, tasks=self.tasks)) 1BA

579 ctrl.mark_dirty() 1BA

580 return ctrl 1BA

581 

582 def new_test_data_directory(self, path): 1ab

583 return self._new_data_controller(new_test_data_directory(path, tasks=self.tasks)) 1XY

584 

585 def _new_data_controller(self, datafile): 1ab

586 self.data.children.append(datafile) 1BAXY

587 datafile.parent = self.data 1BAXY

588 self.children.append(data_controller(datafile, self._project, self, tasks=self.tasks)) 1BAXY

589 return self.children[-1] 1BAXY

590 

591 def notify_suite_added(self, suite): 1ab

592 RideSuiteAdded(parent=self, suite=suite).publish() 1AX

593 

594 def is_directory_suite(self): 1ab

595 return True 1aefciklj

596 

597 def reload(self): 1ab

598 self.__init__(TestDataDirectory(source=self.directory, parent=self.data.parent, tasks=self.tasks).populate(), 1eC

599 self._project, parent=self.parent) 

600 

601 def remove(self): 1ab

602 path = self.filename 1e

603 self.data.initfile = None 1e

604 self._stat = self._get_stat(None) 1e

605 self.reload() 1e

606 RideInitFileRemoved(path=path, datafile=self).publish() 1e

607 

608 def _remove_resources(self): 1ab

609 for resource in self._find_resources_recursively(self): 

610 self._project.remove_resource(resource) 

611 RideDataFileRemoved(path=resource.filename, datafile=resource).publish() 

612 

613 def remove_from_model(self): 1ab

614 self._project.remove_datafile(self) 

615 self._remove_resources() 

616 RideDataFileRemoved(path=self.filename, datafile=self).publish() 

617 

618 def remove_child(self, controller): 1ab

619 if controller in self.children: 619 ↛ 622line 619 didn't jump to line 622 because the condition on line 619 was always true1p

620 self.children.remove(controller) 1p

621 else: 

622 for child in self.children: 

623 child.remove_child(controller) 

624 

625 def is_inside_top_suite(self, ctrl): 1ab

626 return ctrl.filename.startswith(self.directory) 1astvGuqrfciklj

627 

628 def _is_inside_test_data_directory(self, directory): 1ab

629 return any(True for s in [self] + self.children 

630 if s.is_directory_suite() and s.directory == directory) 

631 

632 def remove_static_imports_to_this(self): 1ab

633 for resource_import in self.get_where_used(): 

634 resource_import[1].remove() 

635 

636 def get_where_used(self): 1ab

637 for imp in self._get_recursive_imports(): 

638 yield imp 

639 

640 def _all_imports(self): 1ab

641 for df in self.datafiles: 

642 for imp in df.imports: 

643 yield imp 

644 

645 def _get_recursive_imports(self): 1ab

646 all_imports = self._all_imports() 

647 ctrls = self._find_controllers_recursively(self) 

648 for res in self._find_resources_recursively(self): 

649 for imp in all_imports: 

650 if imp.get_imported_controller() == res and imp.parent.parent not in ctrls: 

651 yield res, imp 

652 

653 def _find_resources_recursively(self, controller): 1ab

654 resources = [] 

655 if controller.children: 

656 for child in controller.children: 

657 resources += self._find_resources_recursively(child) 

658 elif isinstance(controller, ResourceFileController): 

659 resources.append(controller) 

660 return resources 

661 

662 def _find_controllers_recursively(self, controller): 1ab

663 resources = [] 

664 if controller.children: 

665 for child in controller.children: 

666 resources += self._find_controllers_recursively(child) 

667 resources.append(controller) 

668 return resources 

669 

670 def insert_to_test_data_directory(self, res): 1ab

671 res_dir = os.path.dirname(res.filename) 1astvuqrfciklj

672 if res_dir in self._dir_controllers: 672 ↛ 673line 672 didn't jump to line 673 because the condition on line 672 was never true1astvuqrfciklj

673 self._dir_controllers[res_dir].add_child(res) 

674 else: 

675 target = self._find_closest_directory(res) 1astvuqrfciklj

676 if target is self: 1astvuqrfciklj

677 self._create_target_dir_controller(res, res_dir, target) 1astvuqrfciklj

678 else: 

679 target.insert_to_test_data_directory(res) 1astqr

680 

681 def _find_closest_directory(self, res): 1ab

682 target = self 1astvuqrfciklj

683 for s in self.iter_datafiles(): 1astvuqrfciklj

684 if not isinstance(s, TestDataDirectoryController): 1astvuqrfciklj

685 continue 1asqrfciklj

686 if res.filename.startswith(s.directory): 1astvuqrfciklj

687 target = s 1astvuqrfciklj

688 return target 1astvuqrfciklj

689 

690 def _create_target_dir_controller(self, res, res_dir, target): 1ab

691 for dirname in res_dir[len(self.directory):].split(os.sep): 1astvuqrfciklj

692 if not dirname: 1astvuqrfciklj

693 continue 1astvuqrfciklj

694 target_dir = os.path.join(target.directory, dirname) 1stvuqr

695 dir_ctrl = TestDataDirectoryController(TestDataDirectory(source=target_dir, tasks=self.tasks), 1stvuqr

696 self._project, self, tasks=self.tasks) 

697 target._dir_controllers[target.directory] = dir_ctrl 1stvuqr

698 target.add_child(dir_ctrl) 1stvuqr

699 if target_dir == res_dir: 1stvuqr

700 dir_ctrl.add_child(res) 1stvuqr

701 return 1stvuqr

702 target = dir_ctrl 1uq

703 if res not in self.children: 1aqrfciklj

704 self.add_child(res) 1qr

705 

706 def new_resource(self, path): 1ab

707 ctrl = self._project.new_resource(path, parent=self) 

708 ctrl.mark_dirty() 

709 return ctrl 

710 

711 def exclude(self): 1ab

712 if self._project.is_datafile_dirty(self): 2y OeH

713 raise DirtyRobotDataException() 2Oe

714 self._project.internal_settings.excludes.update_excludes([self.directory]) 1yH

715 index = self.parent.children.index(self) 1yH

716 result = ExcludedDirectoryController(self.data, self._project, self.parent) 1yH

717 self.parent.children[index] = result 1yH

718 return result 1yH

719 

720 def retrieve_test_controllers(self): 1ab

721 controllers: list[TestCaseController] = [] 

722 for child in self.children: 

723 if isinstance(child, TestCaseFileController) or isinstance(child, TestDataDirectoryController): 

724 controllers += child.retrieve_test_controllers() 

725 return controllers 

726 

727 

728class DirtyRobotDataException(Exception): 1ab

729 """ 

730 Raised when data is dirty, and you are trying to do an operation that requires undirty data. 

731 """ 

732 pass 1ab

733 

734 

735class TestCaseFileController(_FileSystemElement, _DataController): 1ab

736 __test__ = False 1ab

737 

738 def __init__(self, data, project=None, parent=None, tasks=False, lang=''): 1ab

739 _FileSystemElement.__init__(self, data.source if data else None, data.directory) 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

740 _DataController.__init__(self, data, project, parent) 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

741 self.tasks = tasks 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

742 self._language = lang if lang else self.get_language_from_settings() 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

743 

744 def internal_settings(self): 1ab

745 ss = self.setting_table 2Yc*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

746 sett = _DataController.internal_settings(self) 2Yc*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

747 sett.insert(-1, TemplateController(self, ss.test_template)) 2Yc*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

748 sett.insert(-1, TimeoutController(self, ss.test_timeout)) 2Yc*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

749 return sett + [self.default_tags] 2Yc*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxbyb

750 

751 def get_language_from_settings(self): 1ab

752 from ..preferences import RideSettings 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

753 _settings = RideSettings() 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

754 lang = _settings.get('doc language', '') 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

755 self.file_language = lang 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

756 return lang 2a J K V w x L jbP Q kblbR S T B A h g d m o n fbgbhbp e ? M C mbN ` nbW @ pbqbrbsb{ | } ~ ab0 [ 1 2 3 ] 4 5 6 bb! # $ % ' ( ) * + , - . / : ; =

757 

758 @property 1ab

759 def longname(self): 1ab

760 if self.parent: 2w x #e

761 return self.parent.longname + '.' + self.name 2#e

762 return self.name 2w x #e

763 

764 @property 1ab

765 def suites(self): 1ab

766 return () 

767 

768 @property 1ab

769 def preamble(self): 1ab

770 return self.data.preamble 

771 

772 @property 1ab

773 def language(self): 1ab

774 return self.data.language 2a { | } ~ ab

775 

776 def contains_tests(self): 1ab

777 return bool(self.tests) 

778 

779 def find_controller_by_longname(self, longname, node_testname=None): 1ab

780 return self.find_controller_by_names(longname.split("."), node_testname) 1L

781 

782 def find_controller_by_names(self, names, node_testname=None): 1ab

783 names = '.'.join(names) 1wxL

784 if not names.startswith(self.name): 1wxL

785 return None 1x

786 if len(self.name) < len(names) and not names.startswith(self.name+'.'): 1wxL

787 return None 1w

788 if len(names) == 1: 788 ↛ 789line 788 didn't jump to line 789 because the condition on line 788 was never true1wxL

789 return self 

790 for test in self.tests: 790 ↛ 793line 790 didn't jump to line 793 because the loop on line 790 didn't complete1wxL

791 if test.name == node_testname: 791 ↛ 790line 791 didn't jump to line 790 because the condition on line 791 was always true1wxL

792 return test 1wxL

793 return None 

794 

795 @property 1ab

796 def default_tags(self): 1ab

797 return DefaultTagsController(self, self.setting_table.default_tags) 29b#c$c%cYc}c~c*b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb2b3b4bBbEbtbxb.cQeReSeTeUeybW @ hdVe

798 

799 def is_modifiable(self): 1ab

800 return not self.exists() or not self.is_readonly() 2a bc2c3cccdc?b4cecfcgchc5c=c[b^b_b`b{b6cacmcncocic?cjc|bkc:c9b;cndodpd#c$c%c_eqdrdsdtdudvdwdxdydzdAdBdCdDd`eEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd0d1d2d3d{e4d5d6d7d8d9d!d#d$d%d'd|e(d)d*d+d,d-d.d/d:d}e;d=d?d@d[d]d~e^d_d`d{d|d}d~daebeafce'c(c7c8cP Q R S T )b}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJcdeeefegeheiejekelemeneoepeqereseteuevewexeyezeAeBeCeDebfcfdfefEeFeGeHeIeJeKeffgfhfifLeMeNcOcPcQcRcScTcUcVc)cWcXc*cfbgbhbN (b;b9cMc!cFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbBbEb.c@c[c]c^c_c`cW @

801 

802 def create_test(self, name): 1ab

803 return self.tests.new(name) 2a w x L cd)c*c! # $ % ' ( {c

804 

805 def validate_test_name(self, name): 1ab

806 return self.tests.validate_name(name) 

807 

808 def remove_child(self, controller): 1ab

809 if controller is self: 

810 self.remove() 

811 

812 def remove(self): 1ab

813 self._project.remove_datafile(self) 1p?

814 RideDataFileRemoved(path=self.filename, datafile=self).publish() 1p?

815 

816 def reload(self): 1ab

817 self.__init__(TestCaseFile(parent=self.data.parent, source=self.filename, tasks=self.tasks, 1`

818 language=self._language).populate(), 

819 project=self._project, 

820 parent=self.parent) 

821 

822 def get_template(self): 1ab

823 return self.data.setting_table.test_template 2bc2c3cccdc?b4cecfcgchc5c=c[b^b_b`b{b6cic?cjc|bkc/b#b(b;bf c i

824 

825 def exclude(self): 1ab

826 if self._project.is_datafile_dirty(self): 

827 raise DirtyRobotDataException() 

828 self._project.internal_settings.excludes.update_excludes([self.source]) 

829 if self.parent and self.parent.children: 

830 index = self.parent.children.index(self) 

831 result = ExcludedFileController(self.data, self._project, self.parent) 

832 if self.parent and self.parent.children: 

833 self.parent.children[index] = result 

834 return result 

835 

836 def retrieve_test_controllers(self): 1ab

837 controllers = [] 

838 for test_ctrl in iter(self.tests): 

839 controllers.append(test_ctrl) 

840 return controllers 

841 

842 

843class ResourceFileControllerFactory(object): 1ab

844 

845 def __init__(self, namespace, project): 1ab

846 self._resources = [] 2a @eV s t v G u q r h g d m o n 7 8 9 p e z ? N Z [e]e^e

847 self._namespace = namespace 2a @eV s t v G u q r h g d m o n 7 8 9 p e z ? N Z [e]e^e

848 self._project = project 2a @eV s t v G u q r h g d m o n 7 8 9 p e z ? N Z [e]e^e

849 self._all_resource_imports_resolved = False 2a @eV s t v G u q r h g d m o n 7 8 9 p e z ? N Z [e]e^e

850 

851 @property 1ab

852 def resources(self): 1ab

853 return self._resources 2a zbfdE V F D s t v G u q r y Zb}bpcqcrcsctcuc/bvcwcxcyczcAcBcCcDcEcFcGcHcIcJch g d m o n Zc0cKcO p e z *b!b$b+b,b-b:b.b%b'bAbVbI DbFbGbHbIbJbubvbwbKbLbMbNbObCbPbQbRbSbTbUbYb5b6b7b8bXb0b1bWb~b2b3b4bBbEbtbxbf c i k l j ybNe@bib

854 

855 def find(self, data): 1ab

856 return self._find_with_source(data.source) 2a zbE F D h g d m o n Zc0cO z I f c i k l j ib

857 

858 def _find_with_source(self, source): 1ab

859 for other in self.resources: 2a zbE F D h g d m o n Zc0cO z I f c i k l j ib

860 if other.filename == source: 2a zbD h g d m o n Zc0cO I f c i k l j ib

861 return other 2a zbD h g d m o n Zc0cO I f c k l j ib

862 return None 1aEFDzfciklj

863 

864 def find_with_import(self, import_): 1ab

865 resource_model = self._namespace.find_resource_with_import(import_) 2a zbh g d m o n Zcuf0cO I f c i k l j ib/c

866 if not resource_model: 2a zbh g d m o n Zcuf0cO I f c i k l j ib/c

867 return None 2a h g o ufi /c

868 res = self.find(resource_model) 2a zbh g d m o n Zc0cO I f c k l j ib

869 if not res: 869 ↛ 870line 869 didn't jump to line 870 because the condition on line 869 was never true2a zbh g d m o n Zc0cO I f c k l j ib

870 res = self.create(resource_model) 

871 self._project.insert_into_suite_structure(res) 

872 assert(res is not None) 2a zbh g d m o n Zc0cO I f c k l j ib

873 return res 2a zbh g d m o n Zc0cO I f c k l j ib

874 

875 def create(self, data, parent=None): 1ab

876 rfc = ResourceFileController(data, self._project, parent, self) 1aEFDhgdmonpezfciklj

877 self.resources.append(rfc) 1aEFDhgdmonpezfciklj

878 self.set_all_resource_imports_unresolved() 1aEFDhgdmonpezfciklj

879 return rfc 1aEFDhgdmonpezfciklj

880 

881 def set_all_resource_imports_resolved(self): 1ab

882 self._all_resource_imports_resolved = True 2a zbh g d m o n O I c 9evfib

883 

884 def set_all_resource_imports_unresolved(self): 1ab

885 self._all_resource_imports_resolved = False 2a E F D h g d m o n KcO p e z f c i k l j 9evf

886 

887 def is_all_resource_file_imports_resolved(self): 1ab

888 return self._all_resource_imports_resolved 2a zbh g d m o n O I c 9evf@biblc

889 

890 def remove(self, controller): 1ab

891 self._resources.remove(controller) 2KcO z 9e

892 self.set_all_resource_imports_unresolved() 2KcO z 9e

893 

894 

895class ResourceFileController(_FileSystemElement, _DataController): 1ab

896 

897 def __init__(self, data, project=None, parent=None, resource_file_controller_factory=None): 1ab

898 if resource_file_controller_factory: 1aEFDstvGuqrhgdmon789pezZfciklj

899 self._resource_file_controller_factory = resource_file_controller_factory 1aEFDhgdmonpezfciklj

900 else: 

901 self._resource_file_controller_factory = ResourceFileControllerFactory(self.namespace, project) 1astvGuqr789Z

902 self._known_imports = set() 1aEFDstvGuqrhgdmon789pezZfciklj

903 _FileSystemElement.__init__(self, data.source if data else None, data.directory) 1aEFDstvGuqrhgdmon789pezZfciklj

904 _DataController.__init__(self, data, project, 1aEFDstvGuqrhgdmon789pezZfciklj

905 parent or self._find_parent_for(project, data.source)) 

906 if self.parent and self not in self.parent.children: 1aEFDstvGuqrhgdmon789pezZfciklj

907 self.parent.add_child(self) 1aeZfciklj

908 self._unresolve_all_if_none_existing() 1aEFDstvGuqrhgdmon789pezZfciklj

909 

910 def _unresolve_all_if_none_existing(self): 1ab

911 if not self.exists() and self._resource_file_controller_factory: 1aEFDstvGuqrhgdmon789pezZfciklj

912 self._resource_file_controller_factory.set_all_resource_imports_unresolved() 1aEDhgdmonfciklj

913 # Some import may have referred to this none existing resource 

914 

915 def _find_parent_for(self, project, source): 1ab

916 if not project: 1aEFDstvGuqrhgdmon789pezfciklj

917 return None 1astvGuqr789

918 ddir = os.path.dirname(source) 1aEFDhgdmonpezfciklj

919 for ctrl in project.datafiles: 1aEFDhgdmonpezfciklj

920 if ctrl.is_directory_suite() and self._to_os_style(ctrl.directory) == ddir: 1ahgdmonefciklj

921 return ctrl 1aefciklj

922 return None 1aEFDhgdmonpez

923 

924 @staticmethod 1ab

925 def _to_os_style(path): 1ab

926 return path.replace('/', os.sep) 1aefciklj

927 

928 @property 1ab

929 def display_name(self): 1ab

930 _, tail = os.path.split(self.data.source) 2a TfybUfVfWfXf@bib

931 return tail 2a TfybUfVfWfXf@bib

932 

933 @property 1ab

934 def language(self): 1ab

935 return self._language 

936 

937 def is_modifiable(self): 1ab

938 return not self.exists() or not self.is_readonly() 2a Zb=bh g d 7 8 9 KcO #bLctbf c i k l j iblc

939 

940 def set_format(self, formatt): 1ab

941 self._modify_file_name(lambda: _DataController.set_format(self, formatt), 1amon

942 lambda imp: imp.change_format(formatt)) 

943 

944 def set_basename(self, basename): 1ab

945 self._modify_file_name(lambda: _DataController.set_basename(self, basename), 1h

946 lambda imp: imp.unresolve()) 

947 

948 def set_basename_and_modify_imports(self, basename): 1ab

949 old = self.filename 1gd

950 self._modify_file_name(lambda: _DataController.set_basename(self, basename), 1gd

951 lambda imp: imp.change_name(os.path.basename(old), 

952 os.path.basename(self.filename))) 

953 

954 def remove_static_imports_to_this(self): 1ab

955 name = os.path.basename(self.filename) 1O

956 # have to resolve imports before deleting 

957 # see: http://code.google.com/p/robotframework-ride/issues/detail?id=1119 

958 imports = [import_ for import_ in self.get_where_used()] 1O

959 for resource_import in imports: 1O

960 if resource_import.name.endswith(name): 960 ↛ 959line 960 didn't jump to line 959 because the condition on line 960 was always true1O

961 resource_import.remove() 1O

962 

963 def _modify_file_name(self, modification, notification): 1ab

964 old = self.filename 1ahgdmon

965 modification() 1ahgdmon

966 resource_imports = [resource_import_ for resource_import_ in self.get_where_used()] 1ahgdmon

967 for resource_import in resource_imports: 1ahgdmon

968 notification(resource_import) 1hgdmon

969 self.namespace.resource_filename_changed(old, self.filename) 1ahgdmon

970 

971 def internal_settings(self): 1ab

972 return [DocumentationController(self, self.data.setting_table.doc)] 2AbVbI DbXb0b1bWb~b2b3b4bBbEbtbyb

973 

974 def validate_name(self, name): 1ab

975 for uk in self.data.keyword_table.keywords: 

976 if uk != name and utils.eq(uk.name, name): 

977 return 'User keyword with this name already exists.' 

978 return None 

979 

980 def reload(self): 1ab

981 self.__init__(ResourceFile(source=self.filename).populate(), self._project, 1Z

982 parent=self.parent) 

983 

984 def remove(self): 1ab

985 self._project.remove_resource(self) 2KcO z

986 RideDataFileRemoved(path=self.filename, datafile=self).publish() 2KcO z

987 

988 def remove_known_import(self, _import): 1ab

989 self._known_imports.remove(_import) 1hgdmonOcj

990 

991 def add_known_import(self, _import): 1ab

992 self._known_imports.add(_import) 2a zbh g d m o n Zc0cO I f c k l j ib

993 

994 def notify_opened(self): 1ab

995 RideOpenResource(path=self.filename, datafile=self).publish() 1aEFDzfciklj

996 for _import in [imp for imp in self.imports if imp.is_resource]: 996 ↛ 997line 996 didn't jump to line 997 because the loop on line 996 never started1aEFDzfciklj

997 _import.import_loaded_or_modified() 

998 

999 def is_used(self): 1ab

1000 if self._known_imports: 2a zbfdc @b

1001 return True 2a fdc

1002 if not self._resource_file_controller_factory: 1002 ↛ 1003line 1002 didn't jump to line 1003 because the condition on line 1002 was never true2a zbc @b

1003 return False 

1004 if self._resource_file_controller_factory.is_all_resource_file_imports_resolved(): 2a zbc @b

1005 return False 2a c @b

1006 return any(self._resolve_known_imports()) 2a zbc

1007 

1008 def get_where_used(self): 1ab

1009 if self._resource_file_controller_factory.is_all_resource_file_imports_resolved(): 2a h g d m o n O I iblc

1010 source = self._known_imports 2I lc

1011 else: 

1012 source = self._resolve_known_imports() 2a h g d m o n O I ib

1013 

1014 for usage in source: 2a h g d m o n O I iblc

1015 yield usage 2h g d m o n O I iblc

1016 

1017 def _resolve_known_imports(self): 1ab

1018 for imp in self._all_imports(): 2a zbh g d m o n O I c ib

1019 if imp.get_imported_controller() is self: 2a zbh g d m o n O I c ib

1020 yield imp 2a h g d m o n O I ib

1021 self._resource_file_controller_factory.set_all_resource_imports_resolved() 2a zbh g d m o n O I c ib

1022 

1023 def _all_imports(self): 1ab

1024 for df in self.datafiles: 2a zbh g d m o n O I c ib

1025 for imp in df.imports: 2a zbh g d m o n O I c ib

1026 yield imp 2a zbh g d m o n O I c ib

1027 

1028 def remove_child(self, controller): 1ab

1029 """ Does not have children """ 

1030 pass 

1031 

1032 def exclude(self): 1ab

1033 if self._project.is_datafile_dirty(self): 

1034 raise DirtyRobotDataException() 

1035 self._project.internal_settings.excludes.update_excludes([self.source]) 

1036 if self.parent and self.parent.children: 

1037 index = self.parent.children.index(self) 

1038 result = ExcludedFileController(self.data, self._project, self.parent) 

1039 if self.parent and self.parent.children: 

1040 self.parent.children[index] = result 

1041 return result 

1042 

1043 

1044class ExcludedDirectoryController(_FileSystemElement, ControllerWithParent, WithNamespace): 1ab

1045 

1046 def __init__(self, data, project, parent): 1ab

1047 self.data = data 1yH

1048 self._project = project 1yH

1049 if self._project: 1049 ↛ 1053line 1049 didn't jump to line 1053 because the condition on line 1049 was always true1yH

1050 self._set_namespace_from(self._project) 1yH

1051 self._resource_file_controller_factory = self._project.resource_file_controller_factory 1yH

1052 else: 

1053 self._resource_file_controller_factory = None 

1054 self._parent = parent 1yH

1055 self.children = [] 1yH

1056 self.keywords = [] 1yH

1057 self.variables = tuple() 1yH

1058 self.tests = tuple() 1yH

1059 self.imports = tuple() 1yH

1060 _FileSystemElement.__init__(self, '', data.directory) 1yH

1061 

1062 @property 1ab

1063 def settings(self): 1ab

1064 return self.internal_settings() 

1065 

1066 def internal_settings(self): 1ab

1067 ss = self.data.setting_table 

1068 return [DocumentationController(self, ss.doc), 

1069 FixtureController(self, ss.suite_setup), 

1070 FixtureController(self, ss.suite_teardown), 

1071 FixtureController(self, ss.test_setup), 

1072 FixtureController(self, ss.test_teardown), 

1073 self.force_tags, self.test_tags] 

1074 

1075 @property 1ab

1076 def setting_table(self): 1ab

1077 return self.data.setting_table 

1078 

1079 @property 1ab

1080 def force_tags(self): 1ab

1081 return ForceTagsController(self, self.setting_table.force_tags) 

1082 

1083 @property 1ab

1084 def test_tags(self): 1ab

1085 return TestTagsController(self, self.setting_table.test_tags) 

1086 

1087 @property 1ab

1088 def dirty(self): 1ab

1089 return False 

1090 

1091 def keyword_info(self, datafile, keyword_name): 1ab

1092 _ = datafile 

1093 return WithNamespace.keyword_info(self, self.data, keyword_name) 

1094 

1095 def is_excluded(self): 1ab

1096 return True 1H

1097 

1098 def remove_from_excludes(self): 1ab

1099 self._project.internal_settings.excludes.remove_path(self.source) 1y

1100 index = self.parent.children.index(self) 1y

1101 td = test_data(self.data.source, self.parent.data, self._project.internal_settings) 1y

1102 # We can reach here not from Directory, so proper test must be done 

1103 if isinstance(td, TestDataDirectory): 1103 ↛ 1105line 1103 didn't jump to line 1105 because the condition on line 1103 was always true1y

1104 result = TestDataDirectoryController(td, self._project, self.parent) 1y

1105 elif isinstance(td, ResourceFile): 

1106 result = ResourceFileController(td, self._project, self.parent) 

1107 else: 

1108 result = TestCaseFileController(td, self._project, self.parent) 

1109 self.parent.children[index] = result 1y

1110 return result 1y

1111 

1112 def iter_datafiles(self): 1ab

1113 return [self] 1y

1114 

1115 @property 1ab

1116 def name(self): 1ab

1117 return self.data.name 1y

1118 

1119 @staticmethod 1ab

1120 def is_directory_suite(): 1ab

1121 return True 

1122 

1123 def add_child(self, child): 1ab

1124 self.children.append(child) 

1125 

1126 

1127class ExcludedFileController(_FileSystemElement, _DataController): 1ab

1128 __test__ = False 1ab

1129 

1130 def __init__(self, data, project, parent): 1ab

1131 self.data = data 

1132 self._project = project 

1133 if self._project: 

1134 self._set_namespace_from(self._project) 

1135 self._resource_file_controller_factory = self._project.resource_file_controller_factory 

1136 else: 

1137 self._resource_file_controller_factory = None 

1138 self._parent = parent 

1139 self.children = [] 

1140 self._variables_table_controller = None 

1141 self._testcase_table_controller = None 

1142 self._keywords_table_controller = None 

1143 _FileSystemElement.__init__(self, data.source if data else None, data.directory) 

1144 # _DataController.__init__(self, data, project, parent) 

1145 

1146 def internal_settings(self): 1ab

1147 ss = self.setting_table 

1148 sett = _DataController.internal_settings(self) 

1149 sett.insert(-1, TemplateController(self, ss.test_template)) 

1150 sett.insert(-1, TimeoutController(self, ss.test_timeout)) 

1151 return sett + [self.default_tags, self.force_tags, self.test_tags] # OK doing some cheating here ;) 

1152 

1153 @property 1ab

1154 def longname(self): 1ab

1155 if self.parent: 

1156 return self.parent.longname + '.' + self.name 

1157 return self.name 

1158 

1159 @property 1ab

1160 def suites(self): 1ab

1161 return () 

1162 

1163 @property 1ab

1164 def tests(self): 1ab

1165 return () 

1166 

1167 @property 1ab

1168 def imports(self): 1ab

1169 return () 

1170 

1171 @property 1ab

1172 def datafile(self): 1ab

1173 return None 

1174 

1175 def contains_tests(self): 1ab

1176 return False 

1177 

1178 def find_controller_by_longname(self, longname, node_testname=None): 1ab

1179 return self.find_controller_by_names(longname.split("."), node_testname) 

1180 

1181 def find_controller_by_names(self, names, node_testname=None): 1ab

1182 names = '.'.join(names) 

1183 if not names.startswith(self.name): 

1184 return None 

1185 if len(self.name) < len(names) and not names.startswith(self.name + '.'): 

1186 return None 

1187 if len(names) == 1: 

1188 return self 

1189 for test in self.tests: 

1190 if test.name == node_testname: 

1191 return test 

1192 return None 

1193 

1194 @property 1ab

1195 def default_tags(self): 1ab

1196 return None # DefaultTagsController(self, self.setting_table.default_tags) 

1197 

1198 def is_modifiable(self): 1ab

1199 return not self.exists() or not self.is_readonly() 

1200 

1201 def create_test(self, name): 1ab

1202 return self.tests.new(name) 

1203 

1204 def validate_test_name(self, name): 1ab

1205 return self.tests.validate_name(name) 

1206 

1207 def remove_child(self, controller): 1ab

1208 if controller is self: 

1209 self.remove() 

1210 

1211 def remove(self): 1ab

1212 self._project.remove_datafile(self) 

1213 RideDataFileRemoved(path=self.filename, datafile=self).publish() 

1214 

1215 def reload(self): 1ab

1216 self.__init__(TestCaseFile(parent=self.data.parent, source=self.filename, language=self._language).populate(), 

1217 project=self._project, 

1218 parent=self._parent) 

1219 

1220 def get_template(self): 1ab

1221 return self.data.setting_table.test_template 

1222 

1223 @property 1ab

1224 def settings(self): 1ab

1225 return self.internal_settings() 

1226 

1227 @property 1ab

1228 def setting_table(self): 1ab

1229 return self.data.setting_table 

1230 

1231 @property 1ab

1232 def force_tags(self): # Yes, I know this is impossible, but is Exclude file, right? 1ab

1233 return None # ForceTagsController(self, self.setting_table.force_tags) 

1234 

1235 @property 1ab

1236 def test_tags(self): # Yes, I know this is impossible, but is Exclude file, right? 1ab

1237 return None 

1238 

1239 @property 1ab

1240 def dirty(self): 1ab

1241 return False 

1242 

1243 def keyword_info(self, datafile, keyword_name): 1ab

1244 return NotImplemented 

1245 # _ = datafile 

1246 # return WithNamespace.keyword_info(self, self.data, keyword_name) 

1247 

1248 def is_excluded(self): 1ab

1249 return True 

1250 

1251 def remove_from_excludes(self): 1ab

1252 self._project.internal_settings.excludes.remove_path(self.source) 

1253 if self._parent.children: 

1254 index = self._parent.children.index(self) 

1255 td = test_data(self.data.source, self._parent.data, self._project.internal_settings) 

1256 # We can reach here not from Directory, so proper test must be done 

1257 if isinstance(td, TestDataDirectory): 

1258 result = TestDataDirectoryController(td, self._project, self._parent) 

1259 elif isinstance(td, ResourceFile): 

1260 result = ResourceFileController(td, self._project, self._parent) 

1261 else: 

1262 result = TestCaseFileController(td, self._project, self._parent) 

1263 if self._parent.children: 

1264 self._parent.children[index] = result 

1265 return result 

1266 

1267 def iter_datafiles(self): 1ab

1268 return [] 

1269 

1270 @property 1ab

1271 def name(self): 1ab

1272 return self.data.name 

1273 

1274 def add_child(self, child): 1ab

1275 self.children.append(child)