Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 01df2a4

Browse files
authored
Fix validating EXCEPT AS with data_only=True #4208 (#4209)
1 parent 945d136 commit 01df2a4

File tree

4 files changed

+59
-29
lines changed

4 files changed

+59
-29
lines changed

atest/robot/running/try_except/invalid_try_except.robot

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ Default EXCEPT not last
2828
Multiple default EXCEPTs
2929
TRY:FAIL EXCEPT:NOT RUN EXCEPT:NOT RUN ELSE:NOT RUN
3030

31-
AS not the second last token
31+
AS requires variable
32+
TRY:FAIL EXCEPT:NOT RUN
33+
34+
AS accepts only one variable
3235
TRY:FAIL EXCEPT:NOT RUN
3336

3437
Invalid AS variable

atest/testdata/running/try_except/invalid_try_except.robot

+10-2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,16 @@ Multiple default EXCEPTs
7676
Fail Should not be executed
7777
END
7878

79-
AS not the second last token
80-
[Documentation] FAIL EXCEPT's AS marker must be second to last.
79+
AS requires variable
80+
[Documentation] FAIL EXCEPT's AS requires variable.
81+
TRY
82+
Fail Should not be executed
83+
EXCEPT AS
84+
Fail Should not be executed
85+
END
86+
87+
AS accepts only one variable
88+
[Documentation] FAIL EXCEPT's AS accepts only one variable.
8189
TRY
8290
Fail Should not be executed
8391
EXCEPT AS foo ${foo}

src/robot/parsing/model/statements.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -947,11 +947,13 @@ def variable(self):
947947
def validate(self):
948948
as_token = self.get_token(Token.AS)
949949
if as_token:
950-
if as_token is not self.tokens[-2]:
951-
self.errors += ("EXCEPT's AS marker must be second to last.",)
952-
var = self.tokens[-1].value
953-
if not is_scalar_assign(var):
954-
self.errors += (f"EXCEPT's AS variable '{var}' is invalid.",)
950+
variables = self.get_tokens(Token.VARIABLE)
951+
if not variables:
952+
self.errors += ("EXCEPT's AS requires variable.",)
953+
elif len(variables) > 1:
954+
self.errors += ("EXCEPT's AS accepts only one variable.",)
955+
elif not is_scalar_assign(variables[0].value):
956+
self.errors += (f"EXCEPT's AS variable '{variables[0].value}' is invalid.",)
955957

956958

957959
@Statement.register

utest/parsing/test_model.py

+38-21
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,17 @@ def test_invalid(self):
648648
assert_model(node, expected)
649649

650650

651+
class RemoveNonDataTokensVisitor(ModelVisitor):
652+
def visit_Statement(self, node):
653+
node.tokens = node.data_tokens
654+
655+
651656
class TestTry(unittest.TestCase):
652657

653658
def test_try_except_else_finally(self):
654-
model = get_model('''\
659+
for data_only in [True, False]:
660+
with self.subTest(data_only=data_only):
661+
model = get_model('''\
655662
*** Test Cases ***
656663
Example
657664
TRY
@@ -665,30 +672,40 @@ def test_try_except_else_finally(self):
665672
FINALLY
666673
Log finally here!
667674
END
668-
''', data_only=True)
669-
node = model.sections[0].body[0].body[0]
670-
expected = Try(
671-
header=TryHeader([Token(Token.TRY, 'TRY', 3, 4)]),
672-
body=[KeywordCall([Token(Token.KEYWORD, 'Fail', 4, 8), Token(Token.ARGUMENT, 'Oh no!', 4, 16)])],
673-
next=Try(
674-
header=ExceptHeader([Token(Token.EXCEPT, 'EXCEPT', 5, 4), Token(Token.ARGUMENT, 'does not match', 5, 13)]),
675-
body=[KeywordCall((Token(Token.KEYWORD, 'No operation', 6, 8),))],
676-
next=Try(
677-
header=ExceptHeader((Token(Token.EXCEPT, 'EXCEPT', 7, 4), Token(Token.AS, 'AS', 7, 14), Token(Token.VARIABLE, '${exp}', 7, 20))),
678-
body=[KeywordCall((Token(Token.KEYWORD, 'Log', 8, 8), Token(Token.ARGUMENT, 'Catch', 8, 15)))],
675+
''', data_only=data_only)
676+
node = model.sections[0].body[0].body[0]
677+
expected = Try(
678+
header=TryHeader([Token(Token.TRY, 'TRY', 3, 4)]),
679+
body=[KeywordCall([Token(Token.KEYWORD, 'Fail', 4, 8),
680+
Token(Token.ARGUMENT, 'Oh no!', 4, 16)])],
679681
next=Try(
680-
header=ElseHeader((Token(Token.ELSE, 'ELSE', 9, 4),)),
681-
body=[KeywordCall((Token(Token.KEYWORD, 'No operation', 10, 8),))],
682+
header=ExceptHeader([Token(Token.EXCEPT, 'EXCEPT', 5, 4),
683+
Token(Token.ARGUMENT, 'does not match', 5, 13)]),
684+
body=[KeywordCall((Token(Token.KEYWORD, 'No operation', 6, 8),))],
682685
next=Try(
683-
header=FinallyHeader((Token(Token.FINALLY, 'FINALLY', 11, 4),)),
684-
body=[KeywordCall((Token(Token.KEYWORD, 'Log', 12, 8), Token(Token.ARGUMENT, 'finally here!', 12, 15)))]
686+
header=ExceptHeader((Token(Token.EXCEPT, 'EXCEPT', 7, 4),
687+
Token(Token.AS, 'AS', 7, 14),
688+
Token(Token.VARIABLE, '${exp}', 7, 20))),
689+
body=[KeywordCall((Token(Token.KEYWORD, 'Log', 8, 8),
690+
Token(Token.ARGUMENT, 'Catch', 8, 15)))],
691+
next=Try(
692+
header=ElseHeader((Token(Token.ELSE, 'ELSE', 9, 4),)),
693+
body=[KeywordCall((Token(Token.KEYWORD, 'No operation', 10, 8),))],
694+
next=Try(
695+
header=FinallyHeader((Token(Token.FINALLY, 'FINALLY', 11, 4),)),
696+
body=[KeywordCall((Token(Token.KEYWORD, 'Log', 12, 8),
697+
Token(Token.ARGUMENT, 'finally here!', 12, 15)))]
698+
)
699+
)
685700
)
686-
)
701+
),
702+
end=End([Token(Token.END, 'END', 13, 4)])
687703
)
688-
),
689-
end=End([Token(Token.END, 'END', 13, 4)])
690-
)
691-
assert_model(node, expected)
704+
705+
if not data_only:
706+
RemoveNonDataTokensVisitor().visit(node)
707+
708+
assert_model(node, expected)
692709

693710

694711
class TestVariables(unittest.TestCase):

0 commit comments

Comments
 (0)