Coverage for src/robotide/controller/macrocontrollers.py: 88%
347 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
« 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.
16import os 1ab
17from itertools import chain 1ab
19from .. import robotapi 1ab
20from .arguments import parse_arguments_to_var_dict 1ab
21from .basecontroller import ControllerWithParent, WithUndoRedoStacks 1ab
22from .settingcontrollers import (DocumentationController, FixtureController, TagsController, TimeoutController, 1ab
23 TemplateController, ArgumentsController, ReturnValueController)
24from .stepcontrollers import ForLoopStepController, StepController, IntendedStepController 1ab
25from .tags import Tag 1ab
26from ..namespace.local_namespace import local_namespace 1ab
27from ..publish.messages import (RideItemStepsChanged, RideItemNameChanged, RideItemSettingsChanged, 1ab
28 RideUserKeywordRemoved)
29from ..spec.iteminfo import ResourceUserKeywordInfo, TestCaseUserKeywordInfo 1ab
30from ..utils import variablematcher 1ab
32KEYWORD_NAME_FIELD = 'Keyword Name' 1ab
33TESTCASE_NAME_FIELD = 'Test Case Name' 1ab
36def obtain_bdd_prefixes(language): 1ab
37 from robotide.lib.compat.parsing.language import Language
38 lang = Language.from_name(language[0] if isinstance(language, list) else language)
39 bdd_prefixes = lang.bdd_prefixes
40 return list(bdd_prefixes)
42def _empty_step(): 1ab
43 return robotapi.Step([]) 2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j dbebfbkcgblcmchbibX Q / : l m n o p q
46class ItemNameController(object): 1ab
48 def __init__(self, item): 1ab
49 self._item = item 2OdHc` wcncxcoce f g J IcJcKcLcK McNcFcTcG H ^ d L
51 def contains_keyword(self, name): 1ab
52 # print(f"DEBUG: macrocontrollers.py ItemNameController contains_keyword: item={self._item.name} search="
53 # f"{name}")
54 if isinstance(name, str): 2Hc` wcncxcoce f g J IcJcKcLcK McNcFcTcG H ^ d L
55 return self._item.name == name 2` wcncxcoce f g J IcJcKcLcK McNcFcG H ^ d L
56 return name.match(self._item.name) 2Hce f g J IcJcKcLcK McNcFcTcG H ^ d L
58 def contains_variable(self, name): 1ab
59 return variablematcher.value_contains_variable(self._item.name, name) 2` wcncxcoc
61 def replace_keyword(self, new_name, old_value=None): 1ab
62 # print(f"DEBUG: macrocontrollers.py replace_keyword new_name={new_name} old_value={old_value}")
63 self._item.rename(new_name) 1efgGH^d
65 def rename(self, new_name): 1ab
66 self._item.rename(new_name) 2Od
68 def notify_value_changed(self, old_name=None, new_name=None): 1ab
69 # print(f"DEBUG: macrocontrollers.py notify_value_changed item={self._item.name} old_name={old_name}")
70 if not new_name: 70 ↛ 71line 70 didn't jump to line 71 because the condition on line 70 was never true1efgGH^d
71 new_name=self._item.name
72 self._item.notify_name_changed(old_name=old_name, new_name=new_name) 1efgGH^d
74 @property 1ab
75 def parent(self): 1ab
76 return self._item 2Hcg FcTc
79class KeywordNameController(ItemNameController): 1ab
80 _name_field = KEYWORD_NAME_FIELD 1ab
83class TestCaseNameController(ItemNameController): 1ab
84 __test__ = False 1ab
85 _name_field = TESTCASE_NAME_FIELD 1ab
88class WithStepsController(ControllerWithParent, WithUndoRedoStacks): 1ab
90 def __init__(self, parent_controller, data): 1ab
91 self._parent = parent_controller 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
92 self.data = data 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
93 self._init(data) 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
94 self._has_steps_changed = True 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
95 self._steps_cached = None 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
96 self.datafile_controller.register_for_namespace_updates( 2a *d+dc ldmdHdj Y Z 0 y z UcIdpc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]brbsb] 2 | } ~ abbbPd3 R }b$ % u M JdKdOc7dLdk h i cb~b_ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchc8dndQdt S ' pbL icjc9d!d#d$dodpdRdqdrdsdtd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;dyczcAcBcSdTdUdCcDcEc=dVdacbcccdcyd
97 self.clear_cached_steps)
99 @property 1ab
100 def source(self): 1ab
101 return os.path.basename(self.data.source) if self.data.source else '' 2a _ HcMdWde l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d L @d
103 @property 1ab
104 def name(self): 1ab
105 return self.data.name 2a { T ? 6 c U ) * + , @ V 6cldmdHdj Y Z 0 y z UcIdpc6dVcOdrbsb] 2 | } ~ abbbPd3 R }bcedezd7dLdk h i cb~bHc[d]d^d_dMd` wcncxcoce l m n A r s B C o f p q D E F g J IcJcKcLcK McNcFcTcG H ^ d 8dndt ' L %dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd2eacbcccdc
107 @property 1ab
108 def steps(self): 1ab
109 if self._has_steps_changed: 2a { T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b`d6c*b+bW . [ 4 5 j 7c8c9cY Z 0 kejbtbubvbwbxbybzbAbBbkbCblbDbleEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/cme:c;c=c?c@crc[csctc]cucne^chbib_c`cvc{c|c}coe~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6bpeqerese7b8b9b!b#b$b%bteuevewe'b$ % u M Gck h i ~b_ Hc[d]d^d_dMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d v w x t S ' pbL BdCdDdEdFdGd
110 self._recreate_steps() 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
111 return self._steps_cached 2a { T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b`d6c*b+bW . [ 4 5 j 7c8c9cY Z 0 kejbtbubvbwbxbybzbAbBbkbCblbDbleEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/cme:c;c=c?c@crc[csctc]cucne^chbib_c`cvc{c|c}coe~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6bpeqerese7b8b9b!b#b$b%bteuevewe'b$ % u M Gck h i ~b_ Hc[d]d^d_dMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d v w x t S ' pbL BdCdDdEdFdGd
113 def set_parent(self, new_parent): 1ab
114 self.clear_cached_steps() 2UcVck h i cb
115 ControllerWithParent.set_parent(self, new_parent) 2UcVck h i cb
117 def _recreate_steps(self): 1ab
118 flattened_steps = [] 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
119 for step in self.data.steps: 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
120 if step.is_for_loop(): 120 ↛ 121line 120 didn't jump to line 121 because the condition on line 120 was never true2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
121 for_loop = ForLoopStepController(self, step)
122 flattened_steps.append(for_loop)
123 flattened_steps.extend(for_loop.steps)
124 else:
125 flattened_steps.append(StepController(self, step)) 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
126 self._steps_cached = flattened_steps 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
127 self._has_steps_changed = False 2a { T ? ( 6 c U ) qc* + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b$ % u M Gck h i ~b_ ` e l m n A N O P r s B C o f p q D E F g J K G H d v w x t ' L BdCdDdEdFdGd
129 def clear_cached_steps(self): 1ab
130 self._has_steps_changed = True 2a c 7 8 9 ! # 4 5 j jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobrcsctcucvcX Q ec/ : PcQcUcVcI ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'bk h i cbxeyezee l m n A N O P r s B C o f p q D E F g G H ^ d v w x fcgchc@d
131 self._steps_cached = None 2a c 7 8 9 ! # 4 5 j jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobrcsctcucvcX Q ec/ : PcQcUcVcI ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'bk h i cbxeyezee l m n A N O P r s B C o f p q D E F g G H ^ d v w x fcgchc@d
133 @property 1ab
134 def max_columns(self): 1ab
135 return max(chain((len(step) for step in self.steps), [0]))
137 def has_template(self): 1ab
138 return False 2qcAd(b)b6c*b+b
140 def step(self, index): 1ab
141 return self.steps[index] 2( 6 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : PcQc,b-b.bqb/bI :b;b=b?bSc; = 1 @b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'be l m n o p q
143 def index_of_step(self, step): 1ab
144 return [s.step_controller_step for s in self.steps].index(step) 2{ T U qcAd- V (b)b6c*b+bW . 4 5 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobI ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
146 def replace_step(self, index, new_step): 1ab
147 corrected_index = index
148 for i in range(index):
149 if isinstance(self.step(i), IntendedStepController):
150 corrected_index -= 1
151 self.data.steps[corrected_index] = new_step
152 self._has_steps_changed = True
154 def move_step_up(self, index): 1ab
155 self.step(index).move_up() 2jbybBbkbCblbDbEbFbmbnbobI = 1 RbSbTbUbVbWbXbYbZb0b1b8b9b!b#b$b%b'b
156 self._has_steps_changed = True 2jbybBbkbCblbDbEbFbmbnbobI = 1 RbSbTbUbVbWbXbYbZb0b1b8b9b!b#b$b%b'b
158 def move_step_down(self, index): 1ab
159 self.step(index).move_down() 2jbtbubvbwbxbzbAbkblbmbnbobI ; 1 GbHbIbJbKbLbMbNbObPbQb2b3b4b5b6b7b
160 self._has_steps_changed = True 2jbtbubvbwbxbzbAbkblbmbnbobI ; 1 GbHbIbJbKbLbMbNbObPbQb2b3b4b5b6b7b
162 def set_steps(self, steps): 1ab
163 self.data.steps = steps 2jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : y z I ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
164 self._has_steps_changed = True 2jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : y z I ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
166 def update_namespace(self): 1ab
167 self.datafile_controller.update_namespace() 2c pcOd] 2 3 R }bu zdk h i cbe l m n A N O P r s B C o f p q D E F g G H ^ d v w x fcgchcNd0d1d2d3d4d5dt S icjcyczcAcBcCcDcEc
169 def get_local_namespace(self): 1ab
170 return local_namespace(self, self.datafile_controller.namespace) 2a @deefe3e
172 def get_local_namespace_for_row(self, row): 1ab
173 # print(f"DEBUG: local namespace_for_row controller.namespace {self.datafile_controller.namespace} row {row}")
174 return local_namespace(self, self.datafile_controller.namespace, row) 2@dBdCdDdEdFdGd
176 def get_cell_info(self, row, col): 1ab
177 steps = self.steps 2{ T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b`d6c*b+bW . [ 4 5 I k h i v w x
178 if row < 0 or len(steps) <= row: 2{ T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b`d6c*b+bW . [ 4 5 I k h i v w x
179 return None 2`d
180 return steps[row].get_cell_info(col) 2{ T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b6c*b+bW . [ 4 5 I k h i v w x
182 def get_keyword_info(self, kw_name): 1ab
183 return self.datafile_controller.keyword_info(None, kw_name) 2{ T ? ( 6 c U ) qcAd* + , @ - 7 8 9 ! # V (b)b6c*b+bW . [ 4 5 I k h i v w x
185 def is_user_keyword(self, value): 1ab
186 return self.datafile_controller.is_user_keyword(None, value) 2{ T ? ( 6 c U ) qcAd* + , @ 7 8 9 ! # V (b)b6c*b+bW [ 4 5 I k h i v w x
188 def is_library_keyword(self, value): 1ab
189 return self.datafile_controller.is_library_keyword(None, value) 2( 6 c ) qcAd* + , 7 8 9 ! # (b)b6c*b+bW [ 4 5 I v w x
191 def delete(self): 1ab
192 self.datafile_controller.unregister_namespace_updates( 2c 2 3 R }bzdk h i cb
193 self.clear_cached_steps)
194 self._parent.delete(self) 2c 2 3 R }bzdk h i cb
195 self.notify_keyword_removed() 2c 2 3 R }bzdk h i cb
197 def rename(self, new_name): 1ab
198 # print(f"DEBUG: macrocontrollers.py WithStepsController rename BEFORE new_name={new_name} old_name={self.data.name}")
199 self.data.name = new_name.strip() 2Odcedee f g G H ^ d AeBe
200 self.mark_dirty() 2Odcedee f g G H ^ d AeBe
202 def copy(self, name): 1ab
203 new = self._parent.new(name) 2j Y Z 0 $ % u M t S ' pb
204 for orig, copied in zip(self.settings, new.settings): 2j Y Z 0 $ % u M t S ' pb
205 copied.set_from(orig) 2j Y Z 0 $ % u M t S ' pb
206 new.data.steps = [robotapi.Step(s.as_list()) for s in self.steps] 2j Y Z 0 $ % u M t S ' pb
207 new.notify_steps_changed() 2j Y Z 0 $ % u M t S ' pb
208 return new 2j Y Z 0 $ % u M t S ' pb
210 def get_empty_rows(self): 1ab
211 return [index for index, step in enumerate(self.steps) 2j RcX Q ecqb
212 if self._is_empty_step(step)]
214 @staticmethod 1ab
215 def _is_empty_step(step): 1ab
216 return step.as_list() in [[], ['']] 2j RcX Q ecqb
218 def remove_step(self, index): 1ab
219 self._remove_step(self.steps[index]) 2a 4 5 j rcsctcucvcX Q ec/ :
220 self._has_steps_changed = True 2a 4 5 j rcsctcucvcX Q ec/ :
222 def recreate(self): 1ab
223 self._parent.add(self) 1R
225 def _remove_step(self, step): 1ab
226 step.remove() 2a 4 5 j rcsctcucvcX Q ec/ :
227 self._has_steps_changed = True 2a 4 5 j rcsctcucvcX Q ec/ :
229 def add_step(self, index, step=None): 1ab
230 # print(f"\nDEBUG: WithStepsController enter add_step step={step}")
231 if step is None: 231 ↛ 233line 231 didn't jump to line 233 because the condition on line 231 was always true2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j dbebfbkcgblcmchbibX Q / : l m n o p q
232 step = _empty_step() 2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j dbebfbkcgblcmchbibX Q / : l m n o p q
233 if index == len(self.steps): 2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j dbebfbkcgblcmchbibX Q / : l m n o p q
234 self.data.steps.append(step) 2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j kclcmcQ l m n o p q
235 else:
236 previous_step = self.step(index) 2dbebfbgbhbibX Q / :
237 previous_step.insert_before(step) 2dbebfbgbhbibX Q / :
238 self._has_steps_changed = True 2T ? ( 6 c U ) * + , @ - 7 8 9 ! # V W . [ j dbebfbkcgblcmchbibX Q / : l m n o p q
240 def create_keyword(self, name, argstr): 1ab
241 name = self._remove_bdd_prefix(name) 2c rbsb] 2 | } ~ abbb3 R
242 validation = self.datafile_controller.validate_keyword_name(name) 2c rbsb] 2 | } ~ abbb3 R
243 if validation.error_message: 243 ↛ 244line 243 didn't jump to line 244 because the condition on line 243 was never true2c rbsb] 2 | } ~ abbb3 R
244 raise ValueError(validation.error_message)
245 return self.datafile_controller.create_keyword(name, argstr) 2c rbsb] 2 | } ~ abbb3 R
247 def _remove_bdd_prefix(self, name): 1ab
248 bdd_prefix = [] 2c rbsb] 2 | } ~ abbb3 R
249 language = self.language[0] if isinstance(self.language, list) else self.language 2c rbsb] 2 | } ~ abbb3 R
250 if language and language.lower() not in ['en', 'english']: 250 ↛ 251line 250 didn't jump to line 251 because the condition on line 250 was never true2c rbsb] 2 | } ~ abbb3 R
251 bdd_prefix = [f"{x.lower()} " for x in obtain_bdd_prefixes(language)]
252 bdd_prefix += ['given ', 'when ', 'then ', 'and ', 'but '] 2c rbsb] 2 | } ~ abbb3 R
253 # print(f"DEBUG: macrocontrollers.py WithStepsController _remove_bdd_prefix bdd_prefix={bdd_prefix}")
254 matcher = name.lower() 2c rbsb] 2 | } ~ abbb3 R
255 for match in bdd_prefix: 2c rbsb] 2 | } ~ abbb3 R
256 if matcher.startswith(match): 2c rbsb] 2 | } ~ abbb3 R
257 return name[len(match):] 2| } ~ abbb
258 return name 2c rbsb] 2 3 R
260 def create_test(self, name): 1ab
261 return self.datafile_controller.create_test(name) 2Pd}b
263 def extract_keyword(self, name, argstr, step_range): 1ab
264 extracted_steps = self._extract_steps(step_range) 1yz
265 self._replace_steps_with_kw(name, step_range) 1yz
266 self._create_extracted_kw(name, argstr, extracted_steps) 1yz
268 def get_raw_steps(self): 1ab
269 # Reveales inner state so can't be sure if cache is up-to-date
270 self._has_steps_changed = True 2jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : I ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
271 return self.data.steps 2jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : I ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
273 def set_raw_steps(self, steps): 1ab
274 self.set_steps(steps) 2jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbobdbebfbgbhbibX Q / : I ; = 1 GbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b
276 def _extract_steps(self, step_range): 1ab
277 rem_start, rem_end = step_range 1yz
278 extracted_steps = self.steps[rem_start:rem_end + 1] 1yz
279 return self._convert_controller_to_steps(extracted_steps) 1yz
281 @staticmethod 1ab
282 def _convert_controller_to_steps(step_controllers): 1ab
283 return [robotapi.Step(s.as_list()) for s in step_controllers] 1yz
285 def _replace_steps_with_kw(self, name, step_range): 1ab
286 steps_before_extraction_point = self._convert_controller_to_steps( 1yz
287 self.steps[:step_range[0]])
288 extracted_kw_step = [robotapi.Step([name])] 1yz
289 steps_after_extraction_point = self._convert_controller_to_steps( 1yz
290 self.steps[step_range[1] + 1:])
291 self.set_steps(steps_before_extraction_point + extracted_kw_step + 1yz
292 steps_after_extraction_point)
294 def _create_extracted_kw(self, name, argstr, extracted_steps): 1ab
295 controller = self.datafile_controller.create_keyword(name, argstr) 1yz
296 controller.set_steps(extracted_steps) 1yz
297 return controller 1yz
299 def validate_name(self, name): 1ab
300 return self._parent.validate_name(name, self)
302 def notify_name_changed(self, old_name=None, new_name=None): 1ab
303 self.update_namespace() 2Ode f g G H ^ d
304 self.mark_dirty() 2Ode f g G H ^ d
305 RideItemNameChanged(item=self, old_name=old_name, new_name=new_name).publish() 2Ode f g G H ^ d
307 def notify_keyword_removed(self): 1ab
308 self.update_namespace() 2c 2 3 R }bzdk h i cb
309 RideUserKeywordRemoved(datafile=self.datafile, name=self.name, item=self).publish() 2c 2 3 R }bzdk h i cb
310 self.notify_steps_changed() 2c 2 3 R }bzdk h i cb
312 def notify_settings_changed(self, old_name=None, new_name=None): 1ab
313 _ = old_name 2c pc] u r s d v w x fcgchcNd0d1d2d3d4d5dt S icjcyczcAcBcCcDcEc
314 _ = new_name 2c pc] u r s d v w x fcgchcNd0d1d2d3d4d5dt S icjcyczcAcBcCcDcEc
315 self.update_namespace() 2c pc] u r s d v w x fcgchcNd0d1d2d3d4d5dt S icjcyczcAcBcCcDcEc
316 self._notify(RideItemSettingsChanged) 2c pc] u r s d v w x fcgchcNd0d1d2d3d4d5dt S icjcyczcAcBcCcDcEc
318 def notify_steps_changed(self, old_name=None): 1ab
319 self._has_steps_changed = True 2a { T ? ( 6 c U ) * + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b2 3 R }b$ % u M zdk h i cbe l m n A B C o f p q D E F G H d t S ' pb
320 # print(f"DEBUG: macrocontrollers.py WithStepsController notify_steps_changed: ENTER old_name={old_name}"
321 # f" {self.parent} {self.source} {self} call self._notify")
322 self._notify(RideItemStepsChanged) 2a { T ? ( 6 c U ) * + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b2 3 R }b$ % u M zdk h i cbe l m n A B C o f p q D E F G H d t S ' pb
324 def _notify(self, messageclass): 1ab
325 self.mark_dirty() 2a { T ? ( 6 c U ) * + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQcpc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b] 2 3 R }b$ % u M zdk h i cbe l m n A r s B C o f p q D E F G H d v w x fcgchcNd0d1d2d3d4d5dt S ' pbicjcyczcAcBcCcDcEc
326 messageclass(item=self).publish() 2a { T ? ( 6 c U ) * + , @ - 7 8 9 ! # V (b)b*b+bW . [ 4 5 j 7c8c9cY Z 0 jbtbubvbwbxbybzbAbBbkbCblbDbEbFbmbnbob!c#cRcdbebfbkcgblc$c%c'cmc(c)c*c+c,c-c.c/c:c;c=c?c@crc[csctc]cuc^chbib_c`cvc{c|c}c~cadX Q ecbdcdddedfdgdhd/ idjd: y z PcQcpc^b,b-b_b.bqb/bI `b:b;b=b?bSc; = 1 {bkd|b@b[b]bGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b] 2 3 R }b$ % u M zdk h i cbe l m n A r s B C o f p q D E F G H d v w x fcgchcNd0d1d2d3d4d5dt S ' pbicjcyczcAcBcCcDcEc
329class TestCaseController(WithStepsController): 1ab
330 __test__ = False 1ab
332 _populator = robotapi.TestCasePopulator 1ab
333 filename = "" 1ab
335 def _init(self, test): 1ab
336 self._test = test 2a *d+dldmdHdj Y Z 0 Uc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]bPd}b$ % Oc7dk cb~be l m n A N O P r s B C o f p q D E F g J K d 8dndQd' pbL icjc9d!d#d$dRd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;d=dacbcccdcyd
337 self._run_passed = None 2a *d+dldmdHdj Y Z 0 Uc6dVc^b,b-b_b.bqb/b`b:b;b=b?b; = 1 {b|b@b[b]bPd}b$ % Oc7dk cb~be l m n A N O P r s B C o f p q D E F g J K d 8dndQd' pbL icjc9d!d#d$dRd%dWc'dudXcYcvd(dZc0c)d1c2c3cwd4c5cxd,d-d.d/d:d;d=dacbcccdcyd
339 def __eq__(self, other): 1ab
340 if self is other: 2ldmdHdOccbN O P r s ndQdacbcccdc
341 return True 2ldmdHdOcQd
342 if other.__class__ != self.__class__: 2cbN O P r s ndacbcccdc
343 return False 2N O P ndacbcccdc
344 return self._test == other._test 2cbr s
346 def __hash__(self): 1ab
347 return hash(repr(self)) 24e5e6e7e8e{ T U - V W . 4 5 icjc9d!d#d$d9e@d!e#e$e%e'e(eeeRd
349 @property 1ab
350 def longname(self): 1ab
351 return self.parent.parent.longname + '.' + self.data.name 2ldmd
353 @property 1ab
354 def test_name(self): 1ab
355 return TestCaseNameController(self) 2Od
357 @property 1ab
358 def tags(self): 1ab
359 return TagsController(self, self._test.tags) 2a j Y Z 0 Ce$ % ge~b_ Hc[d]d^d_dMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcXdYdZdG H ^ d Nd0d1d2d3d4d{d|d}d~dhe5die' pbL icjcaebejeWcudXcYcvdZc0c1c2c3cwd4c5cxd
361 @property 1ab
362 def force_tags(self): 1ab
363 return self.datafile_controller.force_tags 2j Y Z 0 $ % Nd0d1d2d3d4d{d|d}d~dhe5die' pbicjcaebejeWcudXcYcvdZc0c1c2c3cwd4c5cxd
365 @property 1ab
366 def test_tags(self): 1ab
367 return self.datafile_controller.test_tags 2j Y Z 0 $ % Nd0d1d2d3d4d{d|d}d~dhe5die' pbicjcaebejeWcudXcYcvdZc0c1c2c3cwd4c5cxd
369 @property 1ab
370 def default_tags(self): 1ab
371 return self.datafile_controller.default_tags 2j Y Z 0 $ % Nd{d|d}d~dicjcaebe
373 def add_tag(self, name): 1ab
374 self.tags.add(Tag(name)) 2Ce
376 @property 1ab
377 def settings(self): 1ab
378 return [ 2j Y Z 0 $ % ge~b_ Hc[d]d^d_dMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcXdYdZdG H ^ d ' pbL
379 self.documentation,
380 FixtureController(self, self._test.setup),
381 FixtureController(self, self._test.teardown),
382 TimeoutController(self, self._test.timeout),
383 TemplateController(self, self._test.template),
384 self.tags
385 ]
387 @property 1ab
388 def documentation(self): 1ab
389 return DocumentationController(self, self._test.doc) 2j Y Z 0 $ % ge~b_ Hc[d]d^d_dMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcXdYdZdG H ^ d ' pbL WcXcYcZc0c1c2c3c4c5c
391 def move_up(self): 1ab
392 return self._parent.move_up(self._test)
394 def move_down(self): 1ab
395 return self._parent.move_down(self._test)
397 def validate_test_name(self, name): 1ab
398 return self._parent.validate_name(name) 2acbcDeccdc
400 def validate_keyword_name(self, name): 1ab
401 return self.datafile_controller.validate_keyword_name(name)
403 @staticmethod 1ab
404 def get_local_variables(): 1ab
405 return {} 2{ T U - V W . 4 5 ` wcncxcoc@deeRd
407 def has_template(self): 1ab
408 template = self._get_template() 1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
409 if not template: 409 ↛ 410line 409 didn't jump to line 410 because the condition on line 409 was never true1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
410 return False
411 return bool(template.value) 1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
413 def _get_template(self): 1ab
414 template = self._test.template 1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
415 if template.value is not None: 415 ↛ 416line 415 didn't jump to line 416 because the condition on line 415 was never true1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
416 return template
417 return self.datafile_controller.get_template() 1{T?(6cU)*+,@-789!#VW.[45Ikhivwx
419 @property 1ab
420 def run_passed(self): 1ab
421 return self._run_passed
423 @run_passed.setter 1ab
424 def run_passed(self, value): 1ab
425 if value not in [True, False, None]:
426 self._run_passed = None # Test did not run
427 if value:
428 self._run_passed = True # Test execution passed
429 else:
430 self._run_passed = False # Test execution failed
433class UserKeywordController(WithStepsController): 1ab
434 _populator = robotapi.UserKeywordPopulator 1ab
435 _TEARDOWN_NOT_SET = object() 1ab
436 _teardown = _TEARDOWN_NOT_SET 1ab
437 _SETUP_NOT_SET = object() 1ab
438 _setup = _SETUP_NOT_SET 1ab
440 def _init(self, kw): 1ab
441 self.kw = kw 2a c y z Idpcrbsb] 2 | } ~ abbb3 R u M JdKdOcLdk h i _ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchct S L odpdqdrdsdtdyczcAcBcSdTdUdCcDcEcVdacbcccdcyd
442 # Needed for API compatibility in tag search
443 self.force_tags = [] 2a c y z Idpcrbsb] 2 | } ~ abbb3 R u M JdKdOcLdk h i _ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchct S L odpdqdrdsdtdyczcAcBcSdTdUdCcDcEcVdacbcccdcyd
444 self.default_tags = [] 2a c y z Idpcrbsb] 2 | } ~ abbb3 R u M JdKdOcLdk h i _ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchct S L odpdqdrdsdtdyczcAcBcSdTdUdCcDcEcVdacbcccdcyd
445 self.test_tags = [] 2a c y z Idpcrbsb] 2 | } ~ abbb3 R u M JdKdOcLdk h i _ e l m n A N O P r s B C o f p q D E F g J K d v w x fcgchct S L odpdqdrdsdtdyczcAcBcSdTdUdCcDcEcVdacbcccdcyd
447 def __eq__(self, other): 1ab
448 if self is other: 2c | } ~ abbbOch i acbcccdc
449 return True 2Oc
450 if other.__class__ != self.__class__: 2c | } ~ abbbh i acbcccdc
451 return False 2c | } ~ abbbacbcccdc
452 return self.kw == other.kw 1hi
454 def __hash__(self): 1ab
455 return hash(repr(self)) 2qcAd(b)b6c*b+bfeBdCdDdEdFdGdEeFeGeHeIeJeKeLeMeNeOePeodQeReSeTeUeVeWeXeYeZe0epdqdrd1esdtd
457 @property 1ab
458 def info(self): 1ab
459 if isinstance(self.datafile, robotapi.ResourceFile): 459 ↛ 461line 459 didn't jump to line 461 because the condition on line 459 was always true1^
460 return ResourceUserKeywordInfo(self.data) 1^
461 return TestCaseUserKeywordInfo(self.data)
463 @property 1ab
464 def keyword_name(self): 1ab
465 return KeywordNameController(self) 2Hc` wcncxcoce f g J IcJcKcLcK McNcFcTcG H ^ d L
467 def move_up(self): 1ab
468 return self._parent.move_up(self.kw) 2Kd
470 def move_down(self): 1ab
471 return self._parent.move_down(self.kw) 2Jd
473 @property 1ab
474 def settings(self): 1ab
475 result = [ 2u M Gc?d` wcncxcoct S
476 DocumentationController(self, self.kw.doc),
477 ArgumentsController(self, self.kw.args),
478 self.setup,
479 self.teardown,
480 ReturnValueController(self, self.kw.return_),
481 TimeoutController(self, self.kw.timeout),
482 TagsController(self, self.kw.tags),
483 ]
484 return result 2u M Gc?d` wcncxcoct S
486 @property 1ab
487 def setup(self): 1ab
488 if self._setup == self._SETUP_NOT_SET: 2u M Gc?d_ HcMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d t S L
489 self._setup = FixtureController(self, self.kw.setup_) 2u M Gc?d_ ` e l m n A N O P r s B C o f p q D E F g J K d t S L
490 return self._setup 2u M Gc?d_ HcMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d t S L
492 @property 1ab
493 def teardown(self): 1ab
494 if self._teardown == self._TEARDOWN_NOT_SET: 2u M Gc?d_ HcMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d t S L
495 self._teardown = FixtureController(self, self.kw.teardown) 2u M Gc?d_ ` e l m n A N O P r s B C o f p q D E F g J K d t S L
496 return self._teardown 2u M Gc?d_ HcMdWd` wcncxcoce l m n A N O P r s B C o f p q D E F g J IcJcKcLcK McNcFcTcXdYdZdG H ^ d t S L
498 @property 1ab
499 def arguments(self): 1ab
500 return ArgumentsController(self, self.kw.args) 2c pcrbsb] | } ~ abbbv w x fcgchcyczcAcBcCcDcEc
502 def validate_keyword_name(self, name): 1ab
503 return self._parent.validate_name(name) 2acbcDeccdc
505 def get_local_variables(self): 1ab
506 return parse_arguments_to_var_dict(self.kw.args.value, self.kw.name) 2qcAd(b)b6c*b+b` ncocfeBdCdDdEdFdGdEeFeGeHeIeJeKeLeMeNeOePeodQeReSeTeUeVeWeXeYeZe0epdqdrd1esdtd