Coverage for src/robotide/controller/stepcontrollers.py: 67%

621 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 re 1ac

17 

18from .. import robotapi, utils 1ac

19from .basecontroller import _BaseController 1ac

20from .cellinfo import CellPosition, CellType, CellInfo, CellContent, ContentType, UPPERCASE_KWS 1ac

21from ..publish.messages import RideItemNameChanged 1ac

22from ..namespace.local_namespace import local_namespace 1ac

23from ..utils import variablematcher 1ac

24 

25BDD_ENGLISH = 'given|when|then|and|but' 1ac

26 

27def obtain_bdd_prefixes(language): 1ac

28 from robotide.lib.compat.parsing.language import Language 

29 lang = Language.from_name(language[0] if isinstance(language, list) else language) 

30 bdd_prefixes = [f"{x}|" for x in lang.bdd_prefixes] 

31 bdd_prefixes = "".join(bdd_prefixes).strip('|') 

32 return bdd_prefixes 

33 

34 

35class StepController(_BaseController): 1ac

36 

37 indent = None 1ac

38 

39 def __init__(self, parent, step): 1ac

40 self.continuing_kw = None 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

41 self._init(parent, step) 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

42 if hasattr(self.parent, 'language'): 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

43 self._language = self.parent.language[0] if isinstance(self.parent.language, list) else self.parent.language 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

44 else: 

45 self._language = 'en' 2Tc

46 if self._language and self._language.lower() not in ['en', 'english']: 46 ↛ 47line 46 didn't jump to line 47 because the condition on line 46 was never true2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

47 bdd_prefix = f"{obtain_bdd_prefixes(self._language)}|{BDD_ENGLISH}" 

48 else: 

49 bdd_prefix = BDD_ENGLISH 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

50 self._GIVEN_WHEN_THEN_MATCHER = re.compile(fr'^({bdd_prefix})\s*', re.IGNORECASE) 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

51 # print(f"DEBUG: stepcontrollers.py StepController INIT {self.parent.language}") 

52 self.step_controller_step.args = self._change_last_empty_to_empty_var( 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

53 self.step_controller_step.args, self.step_controller_step.comment) 

54 

55 def _init(self, parent, step): 1ac

56 self.parent = parent 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

57 self.step_controller_step = step 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

58 self.indent = [] 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

59 index = 0 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

60 if isinstance(self.step_controller_step, list): 60 ↛ 61line 60 didn't jump to line 61 because the condition on line 60 was never true2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

61 while index < len(self.step_controller_step) and self.step_controller_step[index] == '': 

62 self.indent.append('') 

63 elif isinstance(self.step_controller_step, robotapi.Step): 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

64 cells = self.step_controller_step.as_list() 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

65 for index in range(0, len(cells)): 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

66 if cells[index] == '': 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H HcFcnczcBcMcNcOcPc

67 self.increase_indent() 2a B y h e m n o pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcFb0bwb1b2b!bb Ob%b'b(b3bcc/ K PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y zcBcMcNcOcPc

68 else: 

69 self.step_controller_step.args = self.step_controller_step.comment = [] 2Tc

70 

71 @property 1ac

72 def display_name(self): 1ac

73 return 'Step' 

74 

75 @property 1ac

76 def datafile_controller(self): 1ac

77 return self.parent.datafile_controller 2k i p y I h q e m J n o d g A x Tc

78 

79 @staticmethod 1ac

80 def _change_last_empty_to_empty_var(args, comment): 1ac

81 if not args: # and not comment: 2a k i z j l r p B y v s w F h t u C D E q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H ]c^c_c`cHcFcnczcBcMcNcOcPc

82 return [] 2a i z j l r p B y v s w F h t u C D E q e m n o d g f A pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcScUcVcWcTc: ; = ocAcpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H `cFcnczcBcMcNcOcPc

83 if comment: 2a k i z j p B y v s w h t u q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb0bwb1b2bb Ob%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcSc: ; = ocpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H ]c^c_cHcFcnczcBcMcNcOcPc

84 return args 2a pbP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ gcmchcIcicCbHbDbEbbbTbUbVbIbzbsbtbhbubvb3 Cc#bDc$bEcJb- . 6bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* wb]cnc

85 return args[:-1] + ['${EMPTY}'] if args[-1] == '' else args 2a k i z j p B y v s w h t u q e m n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb0bwb1b2bb Ob%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S RcSc: ; = ocpc{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxcqckclc~bO G H ^c_cHcFcnczcBcMcNcOcPc

86 

87 def get_keyword_info(self, kw): 1ac

88 if not kw: 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

89 return None 1kijlrpByIvswFhqeJf

90 return self.parent.get_keyword_info(kw) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

91 

92 def __eq__(self, other): 1ac

93 if self is other: 2TcHcFc

94 return True 2Tc

95 if not isinstance(other, StepController): 95 ↛ 96line 95 didn't jump to line 96 because the condition on line 95 was never true2HcFc

96 return False 

97 return self._steps_are_equal(self.step_controller_step, other.step_controller_step) 2HcFc

98 

99 @staticmethod 1ac

100 def _steps_are_equal(fst, snd): 1ac

101 if fst is snd: 101 ↛ 102line 101 didn't jump to line 102 because the condition on line 101 was never true2HcFc

102 return True 

103 if not snd: 103 ↛ 104line 103 didn't jump to line 104 because the condition on line 103 was never true2HcFc

104 return False 

105 return (fst.assign == snd.assign and 2HcFc

106 fst.name == snd.name and 

107 fst.args == snd.args) 

108 

109 def get_value(self, col): 1ac

110 values = self.as_list() 2a k i z j l r p B y I v s w F h t u C D E q e m J n o d g f A x pb)b*b+bRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWb3 #b$bJb- . 6b7bZb/b8b9bAbBbobKbZ 0 LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b5b-b+ PbQb4b: ; = T U V W X Y O G H

111 if len(values) <= col: 2a k i z j l r p B y I v s w F h t u C D E q e m J n o d g f A x pb)b*b+bRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWb3 #b$bJb- . 6b7bZb/b8b9bAbBbobKbZ 0 LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b5b-b+ PbQb4b: ; = T U V W X Y O G H

112 return '' 2a k i z j l r p B y I v s w F h t u C D E q e J d g f pb)bCbSbDbEbzb3 #b- . /bAbBbZ 0 * Fb5b+ PbQbT U V W X Y

113 return values[col] 2a k i z j l r p B y I v s w F h t u C D E q e m J n o d g f A x )b*b+bRbyb_ GbHbbbTbUbVbIbzbWb3 #b$bJb6b7bZb8b9bAbBbobKbZ 0 LbMbNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b5b-b+ PbQb4b: ; = O G H

114 

115 def get_cell_info(self, col): 1ac

116 position = self._get_cell_position(col) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

117 content = self._get_content_with_type(col, position) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

118 if content.type == ContentType.COMMENTED: 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

119 return self._build_cell_info(content, CellPosition(CellType.OPTIONAL, None)) 1zjl

120 return self._build_cell_info(content, position) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

121 

122 @property 1ac

123 def assignments(self): 1ac

124 return self.step_controller_step.assign 2r y I h t u C D E J d g f A x b G H zcBcMcNcOcPc

125 

126 def is_assigning(self, value): 1ac

127 for assignment in self.assignments: 2r y I h t u C D E J d g f A x b G H zcBc

128 if assignment.replace('=', '').strip() == value.replace('=', '').strip(): 2y I h d g f A x b zcBc

129 return True 2h g f x zc

130 if value.strip().endswith('='): 130 ↛ 131line 130 didn't jump to line 131 because the condition on line 130 was never true2r y I h t u C D E J d g f A x b G H zcBc

131 return True 

132 return False 2r y I h t u C D E J d g f A x b G H zcBc

133 

134 def _build_cell_info(self, content, position): 1ac

135 return CellInfo(content, position) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

136 

137 def _get_cell_position(self, column): 1ac

138 col = column 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

139 if self.parent.has_template(): 139 ↛ 140line 139 didn't jump to line 140 because the condition on line 139 was never true1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

140 return CellPosition(CellType.UNKNOWN, None) 

141 column -= len(self.step_controller_step.assign) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

142 value_at_col = self.get_value(col) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

143 info = self.get_keyword_info(value_at_col) # Getting info for the keyword cell 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

144 keyword_col = col if col >= self._keyword_column else self._keyword_column 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

145 if info: 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

146 casesensitive = (value_at_col.upper() != value_at_col and value_at_col.upper() in UPPERCASE_KWS) 1kizjlrpyIvswFtuCDEqemJnodfAxb:;=OGH

147 if casesensitive: 147 ↛ 148line 147 didn't jump to line 148 because the condition on line 147 was never true1kizjlrpyIvswFtuCDEqemJnodfAxb:;=OGH

148 return CellPosition(CellType.UNKNOWN, ContentType.STRING) 

149 return CellPosition(CellType.KEYWORD, None) 1kizjlrpyIvswFtuCDEqemJnodfAxb:;=OGH

150 else: 

151 while not info and keyword_col > 0 and keyword_col > self._keyword_column: 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

152 keyword_col -= 1 1kizjlrpByIvswFhtuqemJnodgfAxbOGH

153 value_at_col = self.get_value(keyword_col) 1kizjlrpByIvswFhtuqemJnodgfAxbOGH

154 info = self.get_keyword_info(value_at_col) # Getting info for the previous cell 1kizjlrpByIvswFhtuqemJnodgfAxbOGH

155 casesensitive = (value_at_col.upper() != value_at_col and value_at_col.upper() in UPPERCASE_KWS) 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

156 if casesensitive: 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

157 return CellPosition(CellType.UNKNOWN, None) 1e

158 if info: 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

159 args = info.arguments 1kizjlrpByIvswFhtuqemJnodgfAxbOGH

160 else: 

161 args = [] 1rtuCDEJgfGH

162 value_at_col = self.get_value(col) 1rtuCDEJgfGH

163 if self.keyword == '...' and self._index() > 0: # Any block starting with ... is in error 163 ↛ 164line 163 didn't jump to line 164 because the condition on line 163 was never true1rtuCDEJgfGH

164 if value_at_col == '...': 

165 drow = 1 

166 self.continuing_kw = self.parent.step(self._index()-drow).keyword 

167 while self.continuing_kw == '...' and self._index()-drow > 0: 

168 drow += 1 

169 self.continuing_kw = self.parent.step(self._index() - drow).keyword 

170 info = self.get_keyword_info(self.continuing_kw) # Getting info for the previous step kw 

171 if info: 

172 args = info.arguments 

173 args_amount = len(args) 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

174 if (column > keyword_col and (self.get_value(keyword_col) == "FOR" or self.get_value(keyword_col) == "VAR") 174 ↛ 178line 174 didn't jump to line 178 because the condition on line 174 was never true1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

175 and self.is_assigning(value_at_col)): 

176 # print(f"DEBUG: stepcontrollers.py StepController _get_cell_position VAR or FOR assign " 

177 # f"value_at_col={value_at_col}") 

178 return CellPosition(CellType.ASSIGN, None) 

179 if column <= keyword_col and self.is_assigning(value_at_col): 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

180 return CellPosition(CellType.ASSIGN, None) 1gf

181 if col < keyword_col: 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

182 return CellPosition(CellType.UNKNOWN, None) 1J

183 if not info and not self.is_assigning(value_at_col)\ 1kizjlrpByIvswFhtuCDEqemJnodgfAxbOGH

184 and not self.is_assigning(self.get_value(self._keyword_column)) and col >= keyword_col: 

185 return CellPosition(CellType.UNKNOWN, None) 1rtuCDEGH

186 if args_amount == 0: 1kizjlrpByIvswFhtuqemJnodgfAxbOGH

187 return CellPosition(CellType.MUST_BE_EMPTY, None) 1FJO

188 mandatory_args_amount = self._number_of_mandatory_arguments(args, args_amount) 1kizjlrpByIvswhtuqemJnodgfAxbGH

189 """ 1kizjlrpByIvswhtuqemJnodgfAxbGH

190 # DEBUG: This causes @ or & cells unknown, disable for now  

191 if self._has_list_or_dict_var_value_before(col - 1): 

192 return CellPosition(CellType.UNKNOWN, None) 

193 """ 

194 if col <= keyword_col + mandatory_args_amount: 1kizjlrpByIvswhtuqemJnodgfAxbGH

195 return CellPosition(CellType.MANDATORY, args[col-keyword_col - 1]) 1kizrpByIvtuqmJnoxGH

196 if col >= keyword_col + args_amount - mandatory_args_amount and self._last_argument_is_varargs(args): 1kizjlyIvswhedgfAxb

197 # print(f"DEBUG: stepcontrollers _get_cell_position last is vararg={args[-1]}") 

198 return CellPosition(CellType.OPTIONAL, args[-1]) 1jlyIswedgfAxb

199 if keyword_col + mandatory_args_amount < col <= keyword_col + args_amount: 1kizvshdAx

200 return CellPosition(CellType.OPTIONAL, args[col-keyword_col-1]) 1kizvshdAx

201 return CellPosition(CellType.MUST_BE_EMPTY, None) 1kiv

202 

203 def _number_of_mandatory_arguments(self, args, args_amount): 1ac

204 defaults = [arg for arg in args if '=' in arg] 1kizjlrpByIvswhtuqemJnodgfAxbGH

205 n = args_amount - len(defaults) 1kizjlrpByIvswhtuqemJnodgfAxbGH

206 # detect if @{}, named only indicator is present and decrease counter 

207 for arg in args: 1kizjlrpByIvswhtuqemJnodgfAxbGH

208 if arg == '@{}' or arg.startswith('*'): 1kizjlrpByIvswhtuqemJnodgfAxbGH

209 n -= 1 1jlyIswedgfAxb

210 break 1jlyIswedgfAxb

211 if self._last_argument_is_varargs(args): 1kizjlrpByIvswhtuqemJnodgfAxbGH

212 n -= 1 1jlyIswedgfAxb

213 return n if n >= 0 else 0 1kizjlrpByIvswhtuqemJnodgfAxbGH

214 

215 @staticmethod 1ac

216 def _last_argument_is_varargs(args): 1ac

217 return args[-1].startswith('*') or args[-1].startswith('&{') 1kizjlrpByIvswhtuqemJnodgfAxbGH

218 

219 """ 1ac

220 # DEBUG: This is not used anywhere 

221 def _has_list_or_dict_var_value_before(self, arg_index): 

222 if self.args: 

223 for idx, value in enumerate(self.args): 

224 if idx > arg_index: 

225 return False 

226 if variablematcher.is_list_variable(value) and \ 

227 not variablematcher.is_list_variable_subitem(value): 

228 return True 

229 if robotapi.is_dict_var(value) and \ 

230 not variablematcher.is_dict_var_access(value): 

231 return True 

232 return False 

233 """ 

234 

235 def _get_content_with_type(self, col, position): 1ac

236 value = self.get_value(col) 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

237 if self._is_commented(col): 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

238 return CellContent(ContentType.COMMENTED, value) 1zjl

239 last_none_empty = self._get_last_none_empty_col_idx() 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

240 if isinstance(last_none_empty, int) and last_none_empty < col: 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

241 return CellContent(ContentType.EMPTY, value) 1kirpyIvswFqeJf

242 if variablematcher.is_variable(value): 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

243 if self._is_unknow_variable(value, position): 1kipyIhqemJnodgfAx

244 return CellContent(ContentType.UNKNOWN_VARIABLE, value) 1kiyIemJnodgAx

245 return CellContent(ContentType.VARIABLE, value) 1phqgfx

246 if self.is_user_keyword(value): 1kizjlrpByIvswFtuCDEqemJnodfAxb:;=OGH

247 return CellContent( 1kizrpvswFqAx:;=OGH

248 ContentType.USER_KEYWORD, value, 

249 self.get_keyword_info(value).source) 

250 if self.is_library_keyword(value): 1jlrByIvswtuCDEemJnodfAxbOGH

251 return CellContent( 1jlyItuCDEemJnodfAxb

252 ContentType.LIBRARY_KEYWORD, value, 

253 self.get_keyword_info(value).source) 

254 if value == 'END': # DEBUG Don't consider start column (col == 0 and) 254 ↛ 255line 254 didn't jump to line 255 because the condition on line 254 was never true1rByIvswtuCDEeJdfAxbOGH

255 return CellContent(ContentType.END, value) 

256 return CellContent(ContentType.STRING, value) 1rByIvswtuCDEeJdfAxbOGH

257 

258 def _is_unknow_variable(self, value, position): 1ac

259 if position.type == CellType.ASSIGN: 1kipyIhqemJnodgfAx

260 return False 1gf

261 try: 1kipyIhqemJnodgAx

262 is_known = self._get_local_namespace().has_name(value) 1kipyIhqemJnodgAx

263 except AttributeError: 

264 return False 

265 if is_known: 1kipyIhqemJnodgAx

266 return False 1x

267 inner_value = value[2:-1] 1kipyIhqemJnodgAx

268 modified = re.split(r'\W', inner_value, 1)[0] 1kipyIhqemJnodgAx

269 return not self._get_local_namespace().has_name('%s{%s}' % (value[0], modified)) 1kipyIhqemJnodgAx

270 

271 def _get_local_namespace(self): 1ac

272 index = self.parent.index_of_step(self.step_controller_step) 1kipyIhqemJnodgAx

273 return local_namespace( 1kipyIhqemJnodgAx

274 self.parent, self.datafile_controller.namespace, index) 

275 

276 def _get_last_none_empty_col_idx(self): 1ac

277 values = self.as_list() 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

278 for i in reversed(range(len(values))): 278 ↛ 281line 278 didn't jump to line 281 because the loop on line 278 didn't complete1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

279 if values[i].strip() != '': 279 ↛ 278line 279 didn't jump to line 278 because the condition on line 279 was always true1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

280 return i 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

281 return None 

282 

283 def is_modifiable(self): 1ac

284 return self.datafile_controller.is_modifiable() 2Tc

285 

286 def is_user_keyword(self, value): 1ac

287 return self.parent.is_user_keyword(value) 1kizjlrpByIvswFtuCDEqemJnodfAxb:;=OGH

288 

289 def is_library_keyword(self, value): 1ac

290 return self.parent.is_library_keyword(value) 1jlrByIvswtuCDEemJnodfAxbOGH

291 

292 def as_list(self): 1ac

293 # print(f"\nDEBUG: Stepcontrollers enter as_list") 

294 return self.step_controller_step.as_list() 2a k i z j l r p B y I v s w F h t u C D E q e m J n o d g f A x pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb{c- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcQcNb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb|c}c~cad( R 7 8 M N 9 bdcdddedS RcScUcVc: ; = pcYcZc0c1cT U V .bW X Y O G H HcfdFcgd

295 

296 def contains_variable(self, name): 1ac

297 return any(variablematcher.value_contains_variable(item, name) 2pcYcZc0c1c

298 for item in self.as_list()) 

299 

300 def contains_variable_assignment(self, name): 1ac

301 return any(variablematcher.value_contains_variable(item, "%s=" % name) 2pcYcZc0c1c

302 for item in self.as_list()) 

303 

304 def contains_keyword(self, name): 1ac

305 for item in [self.keyword or ''] + self.args: 2ocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b,c-c.c/c:c;c=c?c@c[cnc

306 matching = self._kw_name_match(item, name) 2ocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b,c-c.c/c:c;c=c?c@c[cnc

307 if matching is not None: 2ocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b,c-c.c/c:c;c=c?c@c[cnc

308 return matching 2oc2c3c+c4c{bT U V @b|b.bW }bX Y [b]b^bqc5c6cXckclc~b,c-c.c/c:c;c=c@c[cnc

309 return False 2ocAc7c2c3c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b?cnc

310 """  

311 return any(self._kw_name_match(item, name) 

312 for item in [self.keyword or ''] + self.args) 

313 """ 

314 

315 def _kw_name_match(self, item, expected): 1ac

316 if isinstance(expected, str): 2ocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b,c-c.c/c:c;c=c?c@c[cnc

317 return utils.eq(item, expected) or (self._GIVEN_WHEN_THEN_MATCHER.match(item) and 2ocAc7c2c3c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~b,c-c.c/c:c;c=c?c@c[cnc

318 utils.eq(self._GIVEN_WHEN_THEN_MATCHER.sub('', item), expected)) 

319 matcher = expected.match(item) 2ocAc7c2c3c+c4c8c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~bnc

320 # if matcher: 

321 # old_prefix = matcher.group(1) 

322 # print(f"DEBUG: stepcontrollers.py StepController kw_name_match: RE expected={expected}" 

323 # f" matcher={matcher} old_prefix={old_prefix}") 

324 return matcher 2ocAc7c2c3c+c4c8c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~bnc

325 

326 def replace_keyword(self, new_name, old_name): 1ac

327 # DEBUG: Create setters for Step.name and Step.args 

328 new_match = self._kw_name_match(self.keyword or '', old_name) 2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

329 if new_match: 2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

330 # print(f"DEBUG: stepcontrollers.py StepController replace_keyword: ACTUAL CHANGE old_name={old_name}" 

331 # f" new_name={new_name} new_match={new_match}") 

332 self.step_controller_step.name = self.step_controller_step.cells[self.step_controller_step.inner_kw_pos] = \ 2{bT U V @b|b.bW }bX Y [b]b^b~b

333 self._kw_name_replace(self.keyword, new_name, old_name) 

334 for index, value in enumerate(self.args): 2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

335 if self._kw_name_match(value, old_name): 2@b.b[b]b^b

336 self.step_controller_step.args[index] = self.step_controller_step.cells[ 2.b

337 self.step_controller_step.inner_kw_pos + 1 + index] = \ 

338 self._kw_name_replace(value, new_name, old_name) 

339 

340 def _kw_name_replace(self, old_value, new_match, old_match): 1ac

341 # Here we should have a match for keywords prefixed with resource name 

342 # print(f"DEBUG: stepcontrollers.py StepController _kw_name_replace: ENTER old_value={old_value}" 

343 # f" old_match={old_match} new_match={new_match}") 

344 old_prefix_matcher = self._GIVEN_WHEN_THEN_MATCHER.match(old_value) 2{bT U V @b|b.bW }bX Y [b]b^b~b

345 if not old_prefix_matcher: 2{bT U V @b|b.bW }bX Y [b]b^b~b

346 return new_match 2{b@b|b.b}b[b]b^b~b

347 old_prefix = old_prefix_matcher.group(0) 1TUVWXY

348 old_match_matcher = self._GIVEN_WHEN_THEN_MATCHER.match(old_match) 1TUVWXY

349 if old_match_matcher and old_match_matcher.group(0) == old_prefix: 1TUVWXY

350 return new_match 1X

351 return old_prefix + new_match 1TUVWY

352 

353 @property 1ac

354 def datafile(self): 1ac

355 return self.parent.datafile 2Xcnc

356 

357 @property 1ac

358 def keyword(self): 1ac

359 return self.step_controller_step.name 2k i z j l r p B y I v s w F h t u C D E q e m J n o d g f A x RbHbEbIbKbLbMbb Wc: ; = ocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~bO G H nc

360 

361 @property 1ac

362 def assign(self): 1ac

363 return self.step_controller_step.assign 

364 

365 @property 1ac

366 def args(self): 1ac

367 return self.step_controller_step.args 2CbDbocAc7c2c3c+c4c8cpcYcZc0c1c{bT U V @brcsctcucvc|b.bW }bX Y [b]b^bwcxc9c!c#c$cqc5c6cXc%c'c(c)ckclc*c~bnc

368 

369 @property 1ac

370 def vars(self): 1ac

371 return self.step_controller_step.vars 

372 

373 def change(self, col, new_value): 1ac

374 cells = self.as_list() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

375 if col >= len(cells): 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

376 cells = cells + ['' for _ in range(col - len(cells) + 1)] 2a i z j l r p B v s w F h t u C D E q d g f pbCbSbDbEbzb3 - . AbBbZ 0 * Fb5b+ PbQbT U V W X Y

377 cells[col] = new_value 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

378 comment = self._get_comment(cells) 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

379 if comment: 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

380 cells.pop() 2z yb_ GbWbhb! Fb+

381 self.recreate(cells, comment) 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbyb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . AbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

382 

383 def insert_value_before(self, col, new_value): 1ac

384 self.shift_right(col) 2j l bbsbtbhbubvb$ Z 0 ! % +

385 self.change(col, new_value) 2j l bbsbtbhbubvb$ Z 0 ! % +

386 

387 def comment(self): 1ac

388 col = self._first_non_empty_cell() # .step_controller_step.inner_kw_pos 2j l sbtbhbubvb$ Z 0 ! %

389 self.insert_value_before(col, 'Comment') 2j l sbtbhbubvb$ Z 0 ! %

390 

391 def sharp_comment(self): 1ac

392 col = self._first_non_empty_cell() 2yb_

393 self.insert_sharp_comment(col) 2yb_

394 

395 def insert_sharp_comment(self, col): 1ac

396 cell_value = self.get_value(col) 2yb_

397 new_value = "# " + cell_value 2yb_

398 self.change(col, new_value) 2yb_

399 

400 def sharp_uncomment(self): 1ac

401 col = self._first_non_empty_cell() 1_

402 self.remove_sharp_comment(col) 1_

403 

404 def remove_sharp_comment(self, col): 1ac

405 cell_value = self.get_value(col) 1_

406 if cell_value.startswith('#'): 406 ↛ 409line 406 didn't jump to line 409 because the condition on line 406 was always true1_

407 new_value = cell_value.lstrip('#').lstrip(' ').replace('\\ ', ' ') 1_

408 else: 

409 return 

410 self.change(col, new_value) 1_

411 

412 def _is_commented(self, col): 1ac

413 if self._has_comment_keyword(): 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

414 return col > self._keyword_column 1jl

415 for i in range(min(col + 1, len(self.as_list()))): 1kizrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

416 if self.get_value(i).startswith('#'): 1kizrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

417 return True 1z

418 return False 1kizrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

419 

420 def _first_non_empty_cell(self): 1ac

421 index = self.step_controller_step.first_non_empty_cell() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) _b`b? L @ Q 2 qbrb, yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

422 return index 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) _b`b? L @ Q 2 qbrb, yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3bcc/ K 5b-b+ PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

423 

424 @property 1ac

425 def _keyword_column(self): 1ac

426 return self.step_controller_step.inner_kw_pos # ._first_non_empty_cell() 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

427 

428 def recalculate_keyword_column(self): 1ac

429 index = self._first_non_empty_cell() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

430 cells = self.as_list() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

431 if 0 < len(cells) == index: 431 ↛ 432line 431 didn't jump to line 432 because the condition on line 431 was never true2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

432 self.step_controller_step.inner_kw_pos = index - 1 

433 return 

434 if index < len(cells) and cells[index] == '': 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

435 return 23 obOb

436 while index < len(cells) and (len(cells[index]) > 0 and cells[index][0] in ['$', '@', '&', '%']): 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

437 index += 1 2h g f pb*b+bGb3 $bJbmbnbobZ 0 ~ 6 R M N S

438 self.step_controller_step.inner_kw_pos = index 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

439 

440 def _has_comment_keyword(self): 1ac

441 if self.keyword is None: 441 ↛ 442line 441 didn't jump to line 442 because the condition on line 441 was never true1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

442 return False 

443 return self.keyword.strip().lower() == "comment" or self.keyword.strip().lower() == 'builtin.comment' 1kizjlrpByIvswFhtuCDEqemJnodgfAxb:;=OGH

444 

445 def uncomment(self): 1ac

446 index_of_comment = self._first_non_empty_cell() 2$ ycZ 0 ! %

447 if self.step_controller_step.as_list()[index_of_comment].lower() == 'comment' or\ 2$ ycZ 0 ! %

448 self.step_controller_step.as_list()[index_of_comment].lower() == 'builtin.comment': 

449 self.shift_left(index_of_comment, True) 1$Z0!%

450 self.recalculate_keyword_column() 1$Z0!%

451 

452 def shift_right(self, from_column): 1ac

453 cells = self.as_list() 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb/b8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

454 comment = self._get_comment(cells) 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb/b8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

455 if len(cells) > from_column: 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb/b8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

456 if comment: 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

457 cells.pop() 2^ ) hb7b! wb

458 cells = cells[:from_column] + [''] + cells[from_column:] 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

459 self.recreate(cells, comment) 2j l lb^ ) L 2 bbsbtbhbubvb3 6b7bZb8b9b$ Z 0 ! % wbb %b'b(b/ K + xbfb1 5 # ' 6 ( R 7 M N 9 S

460 

461 def shift_left(self, from_column, delete=False): 1ac

462 cells = self.as_list() 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

463 while not delete and from_column > 0 and cells[from_column] != '': 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

464 from_column -= 1 2P ab] cbQ b K gbjb# ~ ' 6 kb(

465 if not delete and from_column == 0 and cells[from_column] != '': 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

466 return 1K46

467 if len(cells) > from_column: 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

468 cells = cells[:from_column] + cells[from_column + 1:] 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

469 self.recreate(cells) 2)b*b+bP ab] cb? L @ Q 2 3 #b$b$ Z 0 ! % Nbwbb XbK + dbibebgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S

470 

471 @staticmethod 1ac

472 def first_non_empty_cell(cells): 1ac

473 index = 0 

474 while index < len(cells) and cells[index] == '': 

475 index += 1 

476 return index 

477 

478 def insert_before(self, new_step): 1ac

479 steps = self.parent.get_raw_steps() 2P ) ? L @ Q 2 Ybacqbrb, gcmchcic- . mbnbbc* b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

480 index = steps.index(self.step_controller_step) 2P ) ? L @ Q 2 Ybacqbrb, gcmchcic- . mbnbbc* b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

481 if not new_step or not new_step.as_list(): 2P ) ? L @ Q 2 Ybacqbrb, gcmchcic- . mbnbbc* b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

482 new_step = robotapi.Step([]) 2gcmchcic- . mbnbbc*

483 if index > 0: 2P ) ? L @ Q 2 Ybacqbrb, gcmchcic- . mbnbbc* b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

484 upper_indent = steps[index-1].first_non_empty_cell() # self.first_non_empty_cell(steps[index-1].as_list()) 2P ) ? L @ Q 2 Yb, gchcicmbnbbcb / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

485 current_indent = new_step.first_non_empty_cell() # self.first_non_empty_cell(new_step.as_list()) 2P ) ? L @ Q 2 Yb, gchcicmbnbbcb / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

486 delta_indent = upper_indent - current_indent 2P ) ? L @ Q 2 Yb, gchcicmbnbbcb / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

487 if delta_indent > 0: 2P ) ? L @ Q 2 Yb, gchcicmbnbbcb / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

488 e_list = [] 2L @ 2 hcK ` 1 { | 4 } 5 R 7 M N 9 S

489 for _ in range(1, delta_indent): 489 ↛ 490line 489 didn't jump to line 490 because the loop on line 489 never started2L @ 2 hcK ` 1 { | 4 } 5 R 7 M N 9 S

490 e_list.append('') 

491 new_step = robotapi.Step(e_list + new_step.as_list(indent=True)) 2L @ 2 hcK ` 1 { | 4 } 5 R 7 M N 9 S

492 elif delta_indent < 0 and len(new_step.as_list()) > 1: 2P ) ? L Q Yb, gcicmbnbbcb / K 1 4 ;b=b?b[ R 8 M N S

493 for _ in range(delta_indent, 0): 2? L / ;b[ R 8 M N S

494 if new_step.as_list()[0] == '': 494 ↛ 493line 494 didn't jump to line 493 because the condition on line 494 was always true2? L / ;b[ R 8 M N S

495 new_step = robotapi.Step(new_step.as_list(indent=True)[1:]) 2? L / ;b[ R 8 M N S

496 elif delta_indent == 0 and len(steps[index-1].as_list()) > upper_indent: 2P ) L Q Yb, gcicmbnbbcb K 1 4 =b?bR M N S

497 if steps[index-1].as_list()[upper_indent-1] in ['END'] \ 2P ) L Q Yb, gcicmbnbbcb K 1 4 =b?bR M N S

498 or steps[index-1].as_list()[upper_indent] in ['FOR']: 

499 new_step = robotapi.Step([''] + new_step.as_list(indent=True)) 1PQK1MN

500 self.parent.set_raw_steps(steps[:index] + [new_step] + steps[index:]) 2P ) ? L @ Q 2 Yb, gchcicmbnbbcb / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

501 else: 

502 current_indent = len(new_step.indent) 2Ybacqbrb, mc- . * b K 4 8 M N

503 delta_indent = current_indent - len(self.step_controller_step.indent) 2Ybacqbrb, mc- . * b K 4 8 M N

504 if delta_indent > 0: 2Ybacqbrb, mc- . * b K 4 8 M N

505 for _ in range(0, delta_indent): 18MN

506 if new_step.as_list()[0] == '': 506 ↛ 505line 506 didn't jump to line 505 because the condition on line 506 was always true18MN

507 new_step = robotapi.Step(new_step.as_list(indent=False)[1:]) 18MN

508 else: 

509 new_step = robotapi.Step(new_step.as_list(indent=False)) 2Ybacqbrb, mc- . * b K 4

510 self.parent.set_raw_steps([new_step] + steps[index:]) 2Ybacqbrb, mc- . * b K 4 8 M N

511 

512 def insert_after(self, new_step): 1ac

513 steps = self.parent.get_raw_steps() 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

514 index = steps.index(self.step_controller_step) + 1 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

515 if not self._is_end_step(new_step.as_list()): 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

516 if self._is_intended_step(steps[index-1].as_list()): 2P ab] cb^ _b`bL Q qbrb, b ccK dbibebfbgbdcecfcjb# ~ ' 6 kb(

517 if not self._is_intended_step(new_step.as_list()): 2P ab] L Q dbibebgbdc# ~ ' 6 kb(

518 new_step.increase_indent() # shift_right(0) # DEBUG Hard coded! 2P ab] Q dbibebgb# ~

519 else: 

520 if self._is_intended_step(new_step.as_list()) and isinstance(new_step, StepController): 520 ↛ 521line 520 didn't jump to line 521 because the condition on line 520 was never true2] cb^ _b`bqbrb, b ccK dbebfbecfcjb# ~ 6

521 new_step.decrease_indent() # shift_left(1) # DEBUG Hard coded! 

522 self.parent.set_raw_steps(steps[:index] + [new_step] + steps[index:]) 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

523 

524 def remove_empty_columns_from_end(self): 1ac

525 cells = self.as_list() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbGbCbSbHbDbEbbbTbUbVbIbzbWb3 Jb- . AbBbmbnbobKbZ 0 LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

526 while cells != [] and cells[-1].strip() == '': 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbGbCbSbHbDbEbbbTbUbVbIbzbWb3 Jb- . AbBbmbnbobKbZ 0 LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

527 cells.pop() 2zb3 - . AbBbobOb

528 self.recreate(cells) 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRbGbCbSbHbDbEbbbTbUbVbIbzbWb3 Jb- . AbBbmbnbobKbZ 0 LbMb* Nb,bFb:b0b1b2b!bXbOb3b5b-b+ PbQb4bT U V W X Y

529 

530 def remove_empty_columns_from_beginning(self): 1ac

531 cells = self.step_controller_step.as_list() 

532 if cells != [] and cells[0].strip() == '': 

533 cells = cells[1:] 

534 self.recreate(cells) 

535 

536 def remove(self): 1ac

537 self.parent.data.steps.remove(self.step_controller_step) 2a A x pbP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, CcGcDcEcZbmbnbobbc* b cc/ K dbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S

538 self.parent.clear_cached_steps() 2a A x pbP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, CcGcDcEcZbmbnbobbc* b cc/ K dbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S

539 

540 def move_up(self): 1ac

541 previous_step = self.parent.step(self._index() - 1) 2P ) ? L @ Q 2 Ybacqbrb, b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

542 self.remove() 2P ) ? L @ Q 2 Ybacqbrb, b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

543 previous_step.insert_before(self.step_controller_step) 2P ) ? L @ Q 2 Ybacqbrb, b / K ` 1 { | 4 } 5 ;b=b?b[ R 7 8 M N 9 S

544 

545 def move_down(self): 1ac

546 next_step = self.parent.step(self._index() + 1) 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

547 self.remove() 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

548 next_step.insert_after(self.step_controller_step) 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

549 

550 def _index(self): 1ac

551 return self.parent.index_of_step(self.step_controller_step) 2P ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, b cc/ K dbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S

552 

553 def has_only_comment(self): 1ac

554 non_empty_cells = [cell for cell 

555 in self.step_controller_step.as_list() if cell.strip() != ''] 

556 return len(non_empty_cells) == 1 and \ 

557 non_empty_cells[0].startswith('#') 

558 

559 def _get_comment(self, cells): 1ac

560 if not cells: 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRblb^ ) L 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . 6b7bZb/b8b9bAbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bxbfb1 5 # ' 6 ( R 7 M N 9 S T U V W X Y

561 return None 13

562 return cells[-1].strip() if cells[-1].startswith('#') else None 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pbRblb^ ) L 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Jb- . 6b7bZb/b8b9bAbBbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bxbfb1 5 # ' 6 ( R 7 M N 9 S T U V W X Y

563 

564 def recreate(self, cells, comment=None): 1ac

565 self.step_controller_step.__init__(cells, comment) 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

566 self.recalculate_keyword_column() 2a k i z j l r p B v s w F h t u C D E q e m n o d g f pb)b*b+bRbP ab] cblb^ ) ? L @ Q 2 yb_ GbCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 #b$bJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ Z 0 ! % LbMb* Nb,bFb:b0bwb1b2b!bb XbOb%b'b(b3b/ K 5b-b+ PbQb4bdbibebxbfbgbjb` 1 { | 4 } 5 [ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y

567 

568 def _is_partial_for_loop_step(self, cells): 1ac

569 return cells and (cells[self._keyword_column].replace(' ', '').upper() == ':FOR' 

570 or cells[self._keyword_column] == 'FOR') 

571 

572 def _is_for_loop(self): 1ac

573 return self.keyword == 'FOR' 

574 

575 def _is_intended_step(self, cells): 1ac

576 return cells and not cells[0].strip() and any(c.strip() for c in cells) and self._index() > 0 2P ab] cb^ _b`bL Q qbrb, b ccK dbibebfbgbdcecfcjb# ~ ' 6 kb(

577 

578 @staticmethod 1ac

579 def _is_end_step(cells): 1ac

580 return cells and ('END' in cells) # cells[0] == 'END' # DEBUG: Improve check 2P ab] cblb^ _b`bL Q qbrb, b ccK dbibebjcxbfbgbdcecfcjb# ~ ' 6 kb(

581 

582 def _recreate_as_intended_step(self, for_loop_step, cells, comment, index): 1ac

583 self.remove() 

584 for_loop_step.add_step(robotapi.Step(cells[:], comment)) 

585 self._recreate_next_step(index) 

586 

587 def _recreate_next_step(self, index): 1ac

588 if len(self.parent.steps) > index + 1: 

589 next_step = self.parent.step(index + 1) 

590 next_step.recreate(next_step.as_list()) 

591 

592 def notify_value_changed(self, old_name=None, new_name=None): 1ac

593 # print(f"DEBUG: stepcontrollers.py StepController notify_value_changed: ENTER old_name={old_name}" 

594 # f" parent={self.parent.name} new_name={new_name} calling self.parent.notify_steps_changed()") 

595 if old_name is not None: 595 ↛ 597line 595 didn't jump to line 597 because the condition on line 595 was always true2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

596 RideItemNameChanged(item=self, old_name=old_name, new_name=new_name).publish() 2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

597 self.parent.notify_steps_changed(old_name) 2{bT U V @b|b.bW }bX Y [b]b^bkclc~b

598 

599 def increase_indent(self): 1ac

600 self.indent.append('') 2a B y h e m n o pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcFb0bwb1b2b!bb Ob%b'b(b3bcc/ K PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y zcBcMcNcOcPc

601 return len(self.indent) 2a B y h e m n o pb)b*b+bRbJcKcP ab] cblb^ ) _b`b? L @ Q 2 Ybacqbrb, yb_ GbgcmchcIcicCbSbHbDbEbbbTbUbVbIbzbWbsbtbhbubvb3 Cc#bGcDc$bEcJb- . 6b7bZb/b8b9bAbBbmbnbobKb$ ycZ 0 ! % bcLbMb* LcFb0bwb1b2b!bb Ob%b'b(b3bcc/ K PbQb4bdbibebjcxbfbgbdcecfcjb` 1 { | 4 } 5 ;b=b?b[ # ~ ' 6 kb( R 7 8 M N 9 S T U V W X Y zcBcMcNcOcPc

602 

603 def decrease_indent(self): 1ac

604 self.indent = self.indent[:-1] if len(self.indent) > 0 else [] 

605 return len(self.indent) 

606 

607 @property 1ac

608 def steps(self): 1ac

609 return [IntendedStepController(self, sub_step) 

610 for sub_step in self.get_raw_steps()] 

611 

612 def __len__(self): 1ac

613 return len(self.step_controller_step) 

614 

615 

616class ForLoopStepController(StepController): 1ac

617 

618 def __init__(self, parent, step): 1ac

619 StepController.__init__(self, parent, step) 

620 self.inner_kw_pos = self._first_non_empty_cell() 

621 

622 @property 1ac

623 def name(self): 1ac

624 return self.parent.name 

625 

626 @property 1ac

627 def assignments(self): 1ac

628 return self.step_controller_step.vars 

629 

630 """ 1ac

631 @property 

632 def _keyword_column(self): 

633 return self.inner_kw_pos 

634 """ 

635 

636 def move_up(self): 1ac

637 previous_step = self.parent.step(self._index() - 1) 

638 if isinstance(previous_step, ForLoopStepController): 

639 self._swap_forloop_headers(previous_step) 

640 else: 

641 self.get_raw_steps().insert(0, previous_step.step_controller_step) 

642 previous_step.remove() 

643 

644 def _swap_forloop_headers(self, previous_step): 1ac

645 previous_step.step_controller_step.steps = self.step_controller_step.steps 

646 self.step_controller_step.steps = [] 

647 steps = self.parent.get_raw_steps() 

648 i = steps.index(self.step_controller_step) 

649 steps[i - 1] = self.step_controller_step 

650 steps[i] = previous_step.step_controller_step 

651 self.parent.set_raw_steps(steps) 

652 

653 def move_down(self): 1ac

654 next_step = self.step(self._index() + 1) 

655 next_step.move_up() 

656 if len(self.step_controller_step.steps) == 0: 

657 self._recreate_complete_for_loop_header(cells=self.as_list()) 

658 

659 def insert_after(self, new_step): 1ac

660 self.get_raw_steps().insert(0, new_step) 

661 

662 def step(self, index): 1ac

663 return self.parent.step(index) 

664 

665 def _has_comment_keyword(self): 1ac

666 return False 

667 

668 def get_raw_steps(self): 1ac

669 return self.step_controller_step.steps 

670 

671 def set_raw_steps(self, steps): 1ac

672 self.step_controller_step.steps = steps 

673 

674 def _get_cell_position(self, col): 1ac

675 until_range = len(self.step_controller_step.vars) + 1 

676 flavor = self.step_controller_step.flavor 

677 if col == self._keyword_column: 

678 return CellPosition(CellType.KEYWORD, None) 

679 if col < self._keyword_column + until_range: 

680 return CellPosition(CellType.ASSIGN, self.step_controller_step.vars[:]) 

681 if col == self._keyword_column + until_range: 

682 return CellPosition(CellType.MANDATORY, None) 

683 if 'IN RANGE' not in flavor: 

684 return CellPosition(CellType.OPTIONAL, None) 

685 if col <= self._keyword_column + until_range + 1: 

686 return CellPosition(CellType.MANDATORY, None) 

687 if col <= self._keyword_column + until_range + 3: 

688 return CellPosition(CellType.OPTIONAL, None) 

689 return CellPosition(CellType.MUST_BE_EMPTY, None) 

690 

691 def get_cell_info(self, col): 1ac

692 position = self._get_cell_position(col) 

693 content = self._get_content_with_type(col, position) 

694 return self._build_cell_info(content, position) 

695 

696 def _build_cell_info(self, content, position): 1ac

697 return CellInfo(content, position, for_loop=True) 

698 

699 @property 1ac

700 def steps(self): 1ac

701 return [IntendedStepController(self, sub_step) 

702 for sub_step in self.get_raw_steps()] 

703 

704 def index_of_step(self, step): 1ac

705 index_in_for_loop = self.get_raw_steps().index(step) 

706 return self._index() + index_in_for_loop + 1 

707 

708 def _get_comment(self, cells): 1ac

709 return None 

710 

711 def comment(self): 1ac

712 print(f"\nDEBUG: ForLoopStepController RAW STEPS: {self.get_raw_steps()}") 

713 for i in self.get_raw_steps(): 

714 print(f"\nDEBUG: ForLoopStepController PRINT STEPS: {i.as_list()}") 

715 col = self.step_controller_step.inner_kw_pos 

716 header = self.as_list() 

717 if col > 0: 

718 self._replace_with_new_cells(header[0:col-1] + ['Comment'] + header[col:]) 

719 else: 

720 self._replace_with_new_cells(['Comment'] + header) 

721 

722 def contains_keyword(self, name): 1ac

723 return False 

724 

725 def add_step(self, step): 1ac

726 print(f"\nDEBUG: ForLoopStepController enter add_step step={step.as_list()}") 

727 self.get_raw_steps().append(step) 

728 

729 def recreate(self, cells, comment=None, delete=False): 1ac

730 kw_index = None 

731 for idx in range(0, len(cells)): 

732 if cells[idx] == '': 

733 continue 

734 if cells[idx] == 'FOR': 

735 kw_index = idx 

736 break 

737 if kw_index and not delete: # Avoid IndentedStep when DeleteCells 

738 if comment: 

739 self._recreate_complete_for_loop_header(['', cells[:], comment[:]]) 

740 else: 

741 self._recreate_complete_for_loop_header([''] + cells) 

742 else: 

743 new_cells = cells[:] 

744 index = self._index() 

745 self.parent.replace_step(index, robotapi.Step(new_cells, comment)) 

746 self.recalculate_keyword_column() 

747 

748 def _recreate_complete_for_loop_header(self, cells): 1ac

749 self.step_controller_step.__init__(self.parent, cells[:]) 

750 

751 def remove(self): 1ac

752 steps = self.parent.data.steps 

753 index = steps.index(self.step_controller_step) 

754 steps.remove(self.step_controller_step) 

755 self.parent.data.steps = \ 

756 steps[:index] + self.get_raw_steps() + steps[index:] 

757 self.step_controller_step.steps = [] 

758 

759 def _represent_valid_for_loop_header(self, cells): 1ac

760 if not cells: 

761 return False 

762 if cells[0] != self.as_list()[0]: 

763 return False 

764 in_token_index = len(self.vars) + 1 

765 if len(cells) <= in_token_index: 

766 return False 

767 if len(self.as_list()) <= in_token_index: 

768 return False 

769 if cells[in_token_index] != self.as_list()[in_token_index]: 

770 return False 

771 return True 

772 

773 def _replace_with_new_cells(self, cells): 1ac

774 index = self.parent.index_of_step(self.step_controller_step) 

775 self.parent.replace_step(index, robotapi.Step(cells)) 

776 self.get_raw_steps().reverse() 

777 for substep in self.steps: 

778 self.parent.add_step(index + 1, robotapi.Step(substep.as_list())) 

779 

780 def notify_steps_changed(self): 1ac

781 self.notify_value_changed() 

782 

783 def has_template(self): 1ac

784 return self.parent.has_template() 

785 

786 

787class IntendedStepController(StepController): 1ac

788 

789 _invalid = False 1ac

790 

791 def _get_cell_position(self, col): 1ac

792 if col < self._keyword_column: 

793 return CellPosition(CellType.MUST_BE_EMPTY, None) 

794 return StepController._get_cell_position(self, col) 

795 

796 def _get_local_namespace(self): 1ac

797 p = self.parent.parent 

798 index = p.index_of_step(self.step_controller_step) 

799 return local_namespace(p, self.datafile_controller.namespace, index) 

800 

801 def _get_content_with_type(self, col, position): 1ac

802 if col < self._keyword_column: 

803 return CellContent(ContentType.EMPTY, None) 

804 return StepController._get_content_with_type(self, col, position) 

805 

806 def recreate(self, cells, comment=None, delete=False): 1ac

807 if (cells == [] or cells[0] == '') and not delete: # Avoid IndentedStep when DeleteCells 

808 self.step_controller_step.__init__(cells[:], comment=comment) 

809 if self.step_controller_step not in self.parent.get_raw_steps(): 

810 self.parent.add_step(self.step_controller_step) 

811 else: 

812 self.step_controller_step.__init__(cells[:], comment=comment) 

813 if self.step_controller_step not in self.parent.get_raw_steps(): 

814 self.parent.add_step(self.step_controller_step) 

815 if not delete: 

816 self._recreate_as_normal_step(cells, comment) 

817 self.recalculate_keyword_column() 

818 

819 def _recreate_as_normal_step(self, cells, comment=None): 1ac

820 steps = self.parent.steps 

821 index = [s.step_controller_step for s in steps].index(self.step_controller_step) 

822 for i, step in reversed(list(enumerate(steps))): 

823 if i == index: 

824 break 

825 step.replace_with_normal_step(i, step.as_list()) 

826 self.replace_with_normal_step(index, cells, comment) 

827 

828 def replace_with_normal_step(self, index, cells=None, comment=None): 1ac

829 index_of_parent = self.parent.parent.index_of_step(self.parent.step_controller_step) 

830 self.parent.parent.add_step( 

831 index_of_parent + index + 2, 

832 robotapi.Step(cells or self.as_list(), comment=comment)) 

833 self.parent.get_raw_steps().pop(index) 

834 

835 def remove(self): 1ac

836 self.parent.get_raw_steps().remove(self.step_controller_step) 

837 

838 def remove_empty_columns_from_end(self): 1ac

839 if self._invalid: 

840 return 

841 StepController.remove_empty_columns_from_end(self)