Skip to content

WHILE loop #4084

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
pekkaklarck opened this issue Sep 10, 2021 · 6 comments
Closed

WHILE loop #4084

pekkaklarck opened this issue Sep 10, 2021 · 6 comments

Comments

@pekkaklarck
Copy link
Member

We've had FOR loops for a long time and having WHILE loops would be handy as well. The most important use case would probably be implementing custom polling solutions. That would be more flexible and powerful syntax than what can be currently done with Wait Until Keyword Succeeds. The syntax would be something like this:

WHILE    <expression>
    Keyword
    Another Keyword
END

Naturally you should be able to nest WHILE loops with other control structures. For example, IF in combination with planned BREAK and CONTINUE (#4079) would often be useful.

@pekkaklarck pekkaklarck added this to the v5.0 milestone Sep 10, 2021
@pekkaklarck pekkaklarck changed the title WHILE loop WHILE loop Sep 20, 2021
pekkaklarck added a commit that referenced this issue Jan 10, 2022
- Add TRY/EXCEPT/FINALLY (#3075)
- Rename FOR ITERATION to ITERATION (fixes #4182)
- Add WHILE (#4084)
- Add RETURN (#4078)
- Add BREAK and CONTINUE (#4079)
pekkaklarck added a commit that referenced this issue Jan 10, 2022
Change was done as part of WHILE implementation (#4084). For some
more details see #4182.
pekkaklarck added a commit that referenced this issue Jan 14, 2022
Also enhance error reporting with IF/ELSE with invalid condition
and add more tests for handling WHILE afte failures.
pekkaklarck added a commit that referenced this issue Jan 14, 2022
WHILE loops (#4084) having condition already initially False will get
NOT RUN status. This was how WHILE worked earlier, but it was changed
recently when fixing problems with invalid conditions.

FOR loops that have nothing to iterate over will also get NOT RUN
status. In addition to that, their body is run once, with NOT RUN
status, to show what would have been executed. This fixes #4184.
pekkaklarck added a commit that referenced this issue Jan 14, 2022
- ExitForLoop -> BreakLoop
- ContinueForLoop -> ContinueLoop

New names are consistent with new BREAK and CONTINUE statements
(#4079) and work better with WHILE loops (#4084).
@pekkaklarck
Copy link
Member Author

This is now mostly ready. Remaining things to do are:

yanne added a commit that referenced this issue Jan 26, 2022
Also support try except as a container type in the flattening algorithm.

--foritem commandline option should be deprecated in 5.1

Relates to #4084 and #3075
@pekkaklarck
Copy link
Member Author

--flattenkeywords is now supported and that ought to be the last functional change related to this issue. Documentation still missing but that's covered by #4203.

@pekkaklarck
Copy link
Member Author

A problem with WHILE loops is that it is very easy to create a loop that never terminates. There could be a bug in the condition itself or code that should be updating a variable used in the condition could have problems. This is pretty severe problem, because the only way to stop such a rampant loop is stopping the whole execution forcefully. That means that that output.xml is broken and log.html cannot be created.

To ease avoiding infinite loops, we decided to allow limiting how many times or how long time a WHILE loop is executed. The idea is that if the limit is searched, the loop is not executed anymore and execution fails. The limit would be specified using an optional second argument limit that needed to be used as named argument like limit=<value>. The value could either contain the maximum number of loop iterations or the maximum time to try running the loop. The value should have same semantics as the retry argument used with Wait Until Keyword Succeeds:

WHILE    $condition    limit=20x
    Keyword

WHILE    $condition    limit=1 minute
    Keyword

To avoid infinite loops by default, it probably would be a good idea to have a default limit. That limit needed to be high enough to not affect normal valid usages but small enough to actually break the loop at some point. Probably something like 100 times would be good. It should be possible to disable the limit with level=NONE (case-insensitive value) as well.

Because execution would fail if the limit is reaches, this functionality couldn't be used for executing some keywords a certain number of times. That isn't a big loss because FOR IN RANGE loops can be used instead in such situations.

@pekkaklarck pekkaklarck reopened this Feb 15, 2022
@pekkaklarck
Copy link
Member Author

Implementing the limit functionality shouldn't be too complicated and we can do it still before RF 5.0. There aren't much open design decisions either. Only things I can think of are:

  • What postfix or postfixes to use when the limit is the number of iterations? Wait Until Keyword Succeeds supports x and times and for consistency they are probably good here as well. Something like limit=20 iterations could be nice in this context as well, but having too many of these probably isn't a good idea.
  • Should limit=20 be considered the max number of iterations (20 iterations) or the max time (20 seconds)? It's hard to choose and the best solution could be making it an error.

@pekkaklarck
Copy link
Member Author

On Slack not everyone was happy about the addition as there are use cases, especially when doing RPA, to have very long or even infinite loops. Endless loop requiring the execution to be forcefully stopped and leaving a broken output.xml and no log or report was nevertheless considered so bad that the limit functionality was added. Based on the feedback the default limit was raised to 10000 iterations, though.

It was also decided that just using a number like limit=100 means iterations. Prefixes like x or times are not allowed. It is still possible to use limit as a time by using e.g. limit=100s.

pekkaklarck added a commit that referenced this issue Mar 11, 2022
Makes it easier to configure it externally if needed. Part of #4084.
@pekkaklarck
Copy link
Member Author

The above commit made the default limit a module level constant. It's now fairly easy to configure it if needed:

from robot import run_cli
from robot.running import bodyrunner

bodyrunner.DEFAULT_WHILE_LIMIT = 10_000_000_000_000_000
run_cli()

This isn't ideal because you cannot simply disable the limit and because bodyrunner isn't part of the public API. We can add a better API for configuration in RF 5.1. Possibly there could also be a command line option controlling it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant