robotframework-nl 3.1.0__tar.gz → 4.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,55 +1,26 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: robotframework-nl
3
- Version: 3.1.0
4
- Summary: robotnl is a proving ground to boost Robot framework closer to Natural Language.
3
+ Version: 4.0.0
4
+ Summary: RobotNL is a proving ground to boost Robot Framework closer to Natural Language.
5
5
  Author-email: Johan Foederer <github@famfoe.nl>
6
- License: BSD 3-Clause License
7
-
8
- Copyright (c) 2021, J. Foederer
9
- All rights reserved.
10
-
11
- Redistribution and use in source and binary forms, with or without
12
- modification, are permitted provided that the following conditions are met:
13
-
14
- 1. Redistributions of source code must retain the above copyright notice, this
15
- list of conditions and the following disclaimer.
16
-
17
- 2. Redistributions in binary form must reproduce the above copyright notice,
18
- this list of conditions and the following disclaimer in the documentation
19
- and/or other materials provided with the distribution.
20
-
21
- 3. Neither the name of the copyright holder nor the names of its
22
- contributors may be used to endorse or promote products derived from
23
- this software without specific prior written permission.
24
-
25
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
-
6
+ License-Expression: BSD-3-Clause
36
7
  Project-URL: Homepage, https://github.com/JFoederer/robotframeworkNL
37
8
  Keywords: robotframework,robot,testing,dsl
38
- Classifier: License :: OSI Approved :: BSD License
39
9
  Classifier: Programming Language :: Python :: 3
40
10
  Classifier: Operating System :: OS Independent
41
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.14
42
12
  Description-Content-Type: text/markdown
43
13
  License-File: LICENSE
44
14
  Requires-Dist: robotframework>=7.0
15
+ Dynamic: license-file
45
16
 
46
- # robotframeworkNL - the oneliner
47
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
17
+ # RobotNL - the oneliner
18
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
48
19
 
49
20
  ## Introduction
50
21
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
51
22
 
52
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
23
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
24
 
54
25
  ## Installation
55
26
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -100,17 +71,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
100
71
 
101
72
  ### Time constraints
102
73
 
103
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
74
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
104
75
 
105
76
  |**Example using time constaints**||||||
106
77
  |---|---|---|---|---|---|
107
78
  | Request elevator at floor | 3 |||||
108
79
  | Check that | elevator doors are closed | within | 20 seconds ||
109
80
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
81
+ | Check that | elevator doors are opened | within | same timespan ||
82
+
83
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
110
84
 
111
85
  ### Hybrid manual testing
112
86
 
113
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
87
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
114
88
 
115
89
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
116
90
 
@@ -1,10 +1,10 @@
1
- # robotframeworkNL - the oneliner
2
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
1
+ # RobotNL - the oneliner
2
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
3
3
 
4
4
  ## Introduction
5
5
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
6
6
 
7
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
7
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
8
8
 
9
9
  ## Installation
10
10
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -55,17 +55,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
55
55
 
56
56
  ### Time constraints
57
57
 
58
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
58
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
59
59
 
60
60
  |**Example using time constaints**||||||
61
61
  |---|---|---|---|---|---|
62
62
  | Request elevator at floor | 3 |||||
63
63
  | Check that | elevator doors are closed | within | 20 seconds ||
64
64
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
65
+ | Check that | elevator doors are opened | within | same timespan ||
66
+
67
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
65
68
 
66
69
  ### Hybrid manual testing
67
70
 
68
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
71
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
69
72
 
70
73
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
71
74
 
@@ -1,19 +1,19 @@
1
1
  [build-system]
2
2
  requires = [
3
- "setuptools>=61.0.0",
3
+ "setuptools>=83.0.0",
4
4
  "wheel"
5
5
  ]
6
6
  build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "robotframework-nl"
10
- version = "3.1.0"
11
- description = "robotnl is a proving ground to boost Robot framework closer to Natural Language."
10
+ version = "4.0.0"
11
+ description = "RobotNL is a proving ground to boost Robot Framework closer to Natural Language."
12
12
  readme = "README.md"
13
13
  authors = [{ name = "Johan Foederer", email = "github@famfoe.nl" }]
14
- license = { file = "LICENSE" }
14
+ license = "BSD-3-Clause"
15
+ license-files = ["LICENSE"]
15
16
  classifiers = [
16
- "License :: OSI Approved :: BSD License",
17
17
  "Programming Language :: Python :: 3",
18
18
  "Operating System :: OS Independent",
19
19
  ]
@@ -21,7 +21,7 @@ keywords = ["robotframework", "robot", "testing", "dsl"]
21
21
  dependencies = [
22
22
  "robotframework >= 7.0",
23
23
  ]
24
- requires-python = ">=3.8"
24
+ requires-python = ">=3.14"
25
25
 
26
26
  [tool.setuptools]
27
27
  packages = ["robotnl"]
@@ -1,55 +1,26 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: robotframework-nl
3
- Version: 3.1.0
4
- Summary: robotnl is a proving ground to boost Robot framework closer to Natural Language.
3
+ Version: 4.0.0
4
+ Summary: RobotNL is a proving ground to boost Robot Framework closer to Natural Language.
5
5
  Author-email: Johan Foederer <github@famfoe.nl>
6
- License: BSD 3-Clause License
7
-
8
- Copyright (c) 2021, J. Foederer
9
- All rights reserved.
10
-
11
- Redistribution and use in source and binary forms, with or without
12
- modification, are permitted provided that the following conditions are met:
13
-
14
- 1. Redistributions of source code must retain the above copyright notice, this
15
- list of conditions and the following disclaimer.
16
-
17
- 2. Redistributions in binary form must reproduce the above copyright notice,
18
- this list of conditions and the following disclaimer in the documentation
19
- and/or other materials provided with the distribution.
20
-
21
- 3. Neither the name of the copyright holder nor the names of its
22
- contributors may be used to endorse or promote products derived from
23
- this software without specific prior written permission.
24
-
25
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
-
6
+ License-Expression: BSD-3-Clause
36
7
  Project-URL: Homepage, https://github.com/JFoederer/robotframeworkNL
37
8
  Keywords: robotframework,robot,testing,dsl
38
- Classifier: License :: OSI Approved :: BSD License
39
9
  Classifier: Programming Language :: Python :: 3
40
10
  Classifier: Operating System :: OS Independent
41
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.14
42
12
  Description-Content-Type: text/markdown
43
13
  License-File: LICENSE
44
14
  Requires-Dist: robotframework>=7.0
15
+ Dynamic: license-file
45
16
 
46
- # robotframeworkNL - the oneliner
47
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
17
+ # RobotNL - the oneliner
18
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
48
19
 
49
20
  ## Introduction
50
21
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
51
22
 
52
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
23
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
24
 
54
25
  ## Installation
55
26
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -100,17 +71,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
100
71
 
101
72
  ### Time constraints
102
73
 
103
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
74
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
104
75
 
105
76
  |**Example using time constaints**||||||
106
77
  |---|---|---|---|---|---|
107
78
  | Request elevator at floor | 3 |||||
108
79
  | Check that | elevator doors are closed | within | 20 seconds ||
109
80
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
81
+ | Check that | elevator doors are opened | within | same timespan ||
82
+
83
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
110
84
 
111
85
  ### Hybrid manual testing
112
86
 
113
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
87
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
114
88
 
115
89
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
116
90
 
@@ -48,7 +48,25 @@ class CheckFailed(RuntimeError):
48
48
  class RobotChecks:
49
49
  ROBOT_LIBRARY_SCOPE = "GLOBAL"
50
50
  def __init__(self):
51
+ self.ROBOT_LIBRARY_LISTENER = self
51
52
  self.__gui = None
53
+ self.scope_depth = 0
54
+ self.nested_timespans = {}
55
+
56
+ def _start_suite(self, data, result):
57
+ self.scope_depth = 0
58
+ self.nested_timespans = {}
59
+ _end_suite = _start_suite
60
+
61
+ def _start_keyword(self, data, result):
62
+ self.scope_depth += 1
63
+
64
+ def _end_keyword(self, data, result):
65
+ if self.scope_depth + 1 in self.nested_timespans:
66
+ # use depth+1 because 'check that' itself is also a keyword. The +1
67
+ # keeps all check thats on the same level grouped.
68
+ self.nested_timespans.pop(self.scope_depth + 1)
69
+ self.scope_depth -= 1
52
70
 
53
71
  @property
54
72
  def _gui(self):
@@ -74,7 +92,7 @@ class RobotChecks:
74
92
  point where it was able to check the requirement it was testing for.
75
93
  """
76
94
  try:
77
- return RobotChecks.__execute_check("Precondition", *args)
95
+ return self.__execute_check("Precondition", *args)
78
96
  except CheckFailed as failure:
79
97
  failure.ROBOT_CONTINUE_ON_FAILURE = False
80
98
  raise failure
@@ -91,7 +109,7 @@ class RobotChecks:
91
109
  the cause of failure.
92
110
  """
93
111
  try:
94
- return RobotChecks.__execute_check("Postcondition", *args)
112
+ return self.__execute_check("Postcondition", *args)
95
113
  except CheckFailed as failure:
96
114
  failure.ROBOT_CONTINUE_ON_FAILURE = False
97
115
  raise failure
@@ -108,16 +126,19 @@ class RobotChecks:
108
126
  Check that has two basic forms.
109
127
  - A single keyword (with its arguments) can be evaluated to a truth value
110
128
  - Two values or keywords (with their arguments) can be evaluated using an operator. It will
111
- then have the form Check that ``<keyword or value>`` ``<operator>`` ``<keyword or value>``.
129
+ then have the form: Check that ``<keyword or value>`` ``<operator>`` ``<keyword or value>``.
112
130
 
113
- Operator can be any Robot keyword taking exactly two values (left and right operands) as
114
- input. A number of predefined operators on numeric, string and list types are included in
115
- this library.
131
+ Operator can be any Robot keyword taking at least one argument as input. The first argument is
132
+ placed on the left side of the operator, the left operand. Any following arguments are placed
133
+ to the right of the operator and form the right operands. A keyword with its argument values is
134
+ treated as a single operand. A number of predefined operators on numeric, string and list types
135
+ are included in this library.
116
136
 
117
137
  Examples:
118
138
  | `Check that` | 3 | `=` | 3 |
119
139
  | `Check that` | _Two times_ | 6 | `equals` | 12 |
120
140
  | `Check that` | _Two times_ | 5 | `≠` | _Two times_ | 7 |
141
+ | `Check that` | _the shoe box_ | _contains 2 items_ |
121
142
  | `Check that` | _Earth exists_ |
122
143
 
123
144
  'Two times' in these examples is assumed to be defined as a Robot keyword that takes one
@@ -129,16 +150,26 @@ class RobotChecks:
129
150
  This will cause the condition to be reevaluated until it becomes true, or until
130
151
  the specified time has passed. In the latter case the test case will fail.
131
152
 
153
+ Multiple checks can be linked to the same time constraint by using ``same timespan``
154
+ as the time constraint value. Suppose the previous time constraint was 5 seconds
155
+ and that check took 2 seconds to complete. If the next check uses
156
+ ``within same timespan``, then this check has the remaining 3 seconds to
157
+ complete.
158
+
132
159
  Example with time constraint:
133
160
  | `Check that` | _condition is true_ | within | 1 minute 30 seconds |
134
161
 
135
162
  Elevator example:
136
- | `Check that` | _elevator doors are closed_ |
137
163
  | _Request elevator at floor_ | 3 |
138
- | `Check that` | _elevator floor_ | `equals` | 3 | within | 20 seconds |
139
- | `Check that` | _offset to floor level in mm_ | `≤` | 5 | within | 3 seconds |
164
+ | `Check that` | _elevator doors are closed_ | within | 20 seconds |
165
+ | `Check that` | _elevator floor_ | `equals` | 3 | within | 1 minute |
166
+ | `Check that` | _elevator doors are opened_ | within | same timespan |
167
+
168
+ In the elevator example, the doors should be closed within 20 seconds after requesting a
169
+ floor. Then the elevator can take a maximum of 1 minute to reach the floor and open its
170
+ doors. `Check that` will continue as soon as the condition is detected.
140
171
  """
141
- return RobotChecks.__execute_check("Requirement", *args)
172
+ return self.__execute_check("Requirement", *args)
142
173
  RUN_KW_REGISTER.register_run_keyword('robotnl', check_that.__name__, args_to_process=0, deprecation_warning=False)
143
174
 
144
175
  def check_manual(self, checkRequestText=""):
@@ -210,8 +241,7 @@ class RobotChecks:
210
241
  except Exception as e:
211
242
  BuiltIn().log_to_console("Error in interactive keyword '%s'\n\n%s" % (newInput, e))
212
243
 
213
- @staticmethod
214
- def __execute_check(checkType, *args):
244
+ def __execute_check(self, checkType, *args):
215
245
  """
216
246
  Parse arguments for check keyword to determine its operands, evaluate them and execute the
217
247
  check.
@@ -223,14 +253,35 @@ class RobotChecks:
223
253
  TimeOutInSeconds = 0
224
254
  TimeRemaining = True
225
255
  s_TimeConstraint = ""
256
+ StartTime = time.perf_counter()
226
257
  if len(Arguments) >= 2 and str(Arguments[-2]).lower() == 'within':
227
- EvaluatedTimeArg = RobotChecks.__evaluateOperand([Arguments[-1]])[0]
228
- TimeOutInSeconds = timestr_to_secs(EvaluatedTimeArg)
229
- s_TimeConstraint = Arguments[-1]
258
+ timearg = Arguments[-1]
230
259
  Arguments = Arguments[:-2]
260
+ running_timespan_start, running_timespan, s_TimeConstraint =self.nested_timespans.get(
261
+ self.scope_depth, (None, None, ''))
262
+ if str(timearg).lower() == 'same timespan':
263
+ if running_timespan is None:
264
+ BuiltIn().fail("Joint timespan expected, but was not set before this check.")
265
+ TimeOutInSeconds = round(running_timespan_start + running_timespan - StartTime, ndigits=3)
266
+
267
+ remaining = self._human_time(0 if TimeOutInSeconds < 0 else TimeOutInSeconds)
268
+ BuiltIn().log(f"Reusing joint timespan: {s_TimeConstraint}\n"
269
+ f"Must complete within the remaining {remaining}")
270
+ else:
271
+ try:
272
+ EvaluatedTimeArg, s_TimeConstraint = RobotChecks.__evaluateOperand([timearg])
273
+ TimeOutInSeconds = timestr_to_secs(EvaluatedTimeArg)
274
+ except:
275
+ # End any running timespan on error
276
+ if self.scope_depth in self.nested_timespans:
277
+ self.nested_timespans.pop(self.scope_depth)
278
+ raise
279
+ if is_keyword(timearg):
280
+ s_TimeConstraint = f"{timearg} [{secs_to_timestr(TimeOutInSeconds)}]"
281
+ self.nested_timespans[self.scope_depth] = (StartTime, TimeOutInSeconds, s_TimeConstraint)
231
282
 
232
283
  if not len(Arguments):
233
- BuiltIn().fail("%s check failed. There was nothing to check." % checkType)
284
+ BuiltIn().fail(f"{checkType} check failed. There was nothing to check.")
234
285
 
235
286
  ############################################################################################
236
287
  # Build expression
@@ -263,8 +314,6 @@ class RobotChecks:
263
314
  # Evaluate expression
264
315
  EvaluatedResult = None
265
316
 
266
- StartTime = time.perf_counter()
267
- TimeLeft = TimeOutInSeconds
268
317
  PollMax = 20 # After 20s people start wondering: "Is it still going?" Time for an update.
269
318
  PollMin = min(PollMax/8, TimeOutInSeconds*3/100) # Shortest delay is 3% of the target time.
270
319
  PollDelay = PollMin # Initial poll delay will be 2x PollMin
@@ -312,8 +361,14 @@ class RobotChecks:
312
361
  ReportString = f"{checkType} check on '{s_LeftOperand} {OperatorKeyword} {s_RightOperand}'"
313
362
 
314
363
  if s_TimeConstraint:
315
- ReportString += " within %s" % secs_to_timestr(TimeOutInSeconds)
364
+ running_start, timespan, timestr = self.nested_timespans.get(self.scope_depth, (None, None, ''))
365
+ if TimeRemaining and running_start != StartTime:
366
+ elapsed = time.perf_counter() - running_start
367
+ BuiltIn().log(f"Check completed {self._human_time(elapsed)} into the alotted timespan ({timestr})")
368
+ ReportString += f" within {timestr}"
316
369
  if not TimeRemaining and EvaluatedResult == "passed":
370
+ overshoot = time.perf_counter() - (running_start + timespan)
371
+ BuiltIn().log(f"Check completed {self._human_time(overshoot)} too late")
317
372
  ReportString += " (too late)"
318
373
  raise CheckFailed(ReportString)
319
374
 
@@ -356,3 +411,10 @@ class RobotChecks:
356
411
  s_Operand += f" [{s_Value}]"
357
412
 
358
413
  return Value, s_Operand
414
+
415
+ @staticmethod
416
+ def _human_time(time_in_seconds: float):
417
+ """return a human readable string for a time in seconds"""
418
+ SKIP_MILLI = 10 # Do not report milliseconds for timespans above SKIP_MILLI seconds
419
+ rounded_time = int(time_in_seconds) if time_in_seconds > SKIP_MILLI else round(time_in_seconds, ndigits=3)
420
+ return secs_to_timestr(rounded_time)
@@ -35,6 +35,7 @@ from robot.api.deco import keyword as robot_keyword
35
35
  from robot.utils import type_name
36
36
  from robot.running.arguments import TypeConverter
37
37
 
38
+ from annotationlib import get_annotations, Format
38
39
  from functools import wraps
39
40
  from typing import TypeVar, Generic, Union
40
41
 
@@ -102,7 +103,7 @@ class InlineKeywordConverter(TypeConverter):
102
103
 
103
104
  def _convert(self, value):
104
105
  if not is_keyword(value):
105
- raise ValueError
106
+ raise ValueError("Not a keyword")
106
107
  BuiltIn().log(f"Evaluating argument as keyword [{value}]")
107
108
  result = BuiltIn().run_keyword(value)
108
109
  BuiltIn().log(f"{value} → {result}")
@@ -116,11 +117,16 @@ class InlineKeywordConverter(TypeConverter):
116
117
 
117
118
  return result
118
119
 
119
-
120
120
  def keyword(name=None, tags=(), types=()):
121
121
  def decorator(func):
122
- for var, type_ in func.__annotations__.items():
123
- func.__annotations__[var] = Union[type_, InlineKeyword[type_]]
122
+ annotations = get_annotations(func, format=Format.VALUE)
123
+ for var, type_ in annotations.items():
124
+ annotations[var] = Union[type_, InlineKeyword[type_]]
125
+
126
+ def new_annotate(self, format=Format.VALUE):
127
+ return annotations
128
+ func.__annotate__ = new_annotate
129
+
124
130
  @robot_keyword(name, tags, types)
125
131
  @wraps(func)
126
132
  def wrapped(*args, **kwargs):
@@ -0,0 +1 @@
1
+ VERSION = '4.0.0'
@@ -1 +0,0 @@
1
- VERSION = '3.1.0'