robotframework 6.1rc1__zip → 7.0a1__zip

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.
Files changed (288) hide show
  1. {robotframework-6.1rc1/src/robotframework.egg-info → robotframework-7.0a1}/PKG-INFO +3 -6
  2. {robotframework-6.1rc1 → robotframework-7.0a1}/setup.py +2 -5
  3. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/interfaces.py +36 -49
  4. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/parsing.py +4 -2
  5. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/gatherfailed.py +2 -2
  6. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/languages.py +61 -25
  7. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/settings.py +8 -5
  8. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.css +4 -0
  9. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.html +9 -1
  10. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/model.js +2 -4
  11. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/testdata.js +10 -3
  12. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/template.py +3 -3
  13. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/builder.py +0 -8
  14. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/datatypes.py +9 -10
  15. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/htmlutils.py +4 -7
  16. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/jsonbuilder.py +14 -10
  17. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/model.py +13 -25
  18. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/robotbuilder.py +14 -4
  19. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/xmlbuilder.py +8 -8
  20. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/xmlwriter.py +12 -38
  21. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/BuiltIn.py +215 -189
  22. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Collections.py +2 -9
  23. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/DateTime.py +1 -1
  24. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/OperatingSystem.py +4 -3
  25. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Process.py +26 -27
  26. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Remote.py +40 -36
  27. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/String.py +4 -4
  28. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/XML.py +7 -8
  29. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/__init__.py +2 -2
  30. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/dialogs_py.py +14 -2
  31. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/__init__.py +4 -4
  32. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/body.py +14 -6
  33. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/configurer.py +19 -15
  34. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/control.py +155 -85
  35. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/filter.py +31 -25
  36. robotframework-7.0a1/src/robot/model/keyword.py +70 -0
  37. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/message.py +19 -10
  38. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/modelobject.py +2 -8
  39. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/modifier.py +1 -1
  40. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/namepatterns.py +3 -25
  41. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/stats.py +9 -15
  42. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tags.py +1 -1
  43. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/testcase.py +12 -21
  44. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/testsuite.py +43 -24
  45. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/visitor.py +35 -8
  46. robotframework-7.0a1/src/robot/output/console/dotted.py +90 -0
  47. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/quiet.py +3 -2
  48. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/verbose.py +60 -60
  49. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/debugfile.py +36 -23
  50. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/filelogger.py +16 -13
  51. robotframework-7.0a1/src/robot/output/listeners.py +586 -0
  52. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/logger.py +164 -77
  53. robotframework-7.0a1/src/robot/output/loggerapi.py +152 -0
  54. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/loggerhelper.py +23 -56
  55. robotframework-7.0a1/src/robot/output/output.py +158 -0
  56. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/stdoutlogsplitter.py +8 -5
  57. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/xmllogger.py +163 -109
  58. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/blocklexers.py +17 -13
  59. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/context.py +12 -2
  60. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/lexer.py +1 -1
  61. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/settings.py +6 -3
  62. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/statementlexers.py +39 -10
  63. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/tokens.py +27 -29
  64. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/blocks.py +19 -6
  65. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/statements.py +184 -84
  66. robotframework-7.0a1/src/robot/parsing/model/visitor.py +102 -0
  67. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/expandkeywordmatcher.py +1 -1
  68. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsbuildingcontext.py +8 -6
  69. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsmodelbuilders.py +88 -61
  70. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/stringcache.py +4 -3
  71. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/xunitwriter.py +15 -21
  72. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/__init__.py +3 -2
  73. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/configurer.py +12 -9
  74. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/flattenkeywordmatcher.py +8 -8
  75. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/keywordremover.py +71 -54
  76. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/merger.py +1 -1
  77. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/model.py +400 -316
  78. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/modeldeprecation.py +9 -3
  79. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/resultbuilder.py +21 -23
  80. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/xmlelementhandlers.py +76 -40
  81. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/run.py +1 -1
  82. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/__init__.py +1 -1
  83. robotframework-7.0a1/src/robot/running/arguments/argumentconverter.py +101 -0
  84. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentmapper.py +16 -14
  85. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentparser.py +3 -1
  86. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentresolver.py +41 -33
  87. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentspec.py +24 -90
  88. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentvalidator.py +34 -27
  89. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/customconverters.py +14 -11
  90. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/embedded.py +23 -26
  91. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/typeconverters.py +210 -220
  92. robotframework-7.0a1/src/robot/running/arguments/typeinfo.py +367 -0
  93. robotframework-7.0a1/src/robot/running/arguments/typevalidator.py +62 -0
  94. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/bodyrunner.py +83 -68
  95. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/builders.py +15 -25
  96. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/parsers.py +15 -10
  97. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/settings.py +9 -17
  98. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/transformers.py +166 -308
  99. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/context.py +80 -25
  100. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/handlers.py +11 -16
  101. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/handlerstore.py +1 -1
  102. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/librarykeywordrunner.py +9 -17
  103. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/model.py +156 -36
  104. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/namespace.py +18 -19
  105. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/statusreporter.py +13 -12
  106. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/suiterunner.py +18 -21
  107. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/testlibraries.py +35 -39
  108. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/usererrorhandler.py +8 -8
  109. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/userkeyword.py +13 -8
  110. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/userkeywordrunner.py +18 -21
  111. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/testdoc.py +18 -13
  112. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/__init__.py +50 -35
  113. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/connectioncache.py +64 -59
  114. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/encodingsniffer.py +9 -4
  115. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/escaping.py +11 -9
  116. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/markupwriters.py +20 -13
  117. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/normalizing.py +9 -24
  118. robotframework-7.0a1/src/robot/utils/notset.py +33 -0
  119. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/platform.py +15 -5
  120. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotpath.py +1 -0
  121. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robottime.py +120 -88
  122. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robottypes.py +16 -31
  123. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/setter.py +0 -5
  124. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/text.py +7 -4
  125. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/unic.py +2 -2
  126. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/__init__.py +2 -2
  127. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/assigner.py +17 -19
  128. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/evaluation.py +20 -17
  129. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/filesetter.py +80 -80
  130. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/replacer.py +33 -36
  131. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/scopes.py +3 -3
  132. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/search.py +66 -41
  133. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/store.py +14 -16
  134. robotframework-7.0a1/src/robot/variables/tablesetter.py +164 -0
  135. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/variables.py +1 -1
  136. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/version.py +1 -1
  137. {robotframework-6.1rc1 → robotframework-7.0a1/src/robotframework.egg-info}/PKG-INFO +3 -6
  138. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/SOURCES.txt +3 -4
  139. {robotframework-6.1rc1 → robotframework-7.0a1}/tasks.py +6 -6
  140. robotframework-6.1rc1/src/robot/libraries/Reserved.py +0 -48
  141. robotframework-6.1rc1/src/robot/model/keyword.py +0 -173
  142. robotframework-6.1rc1/src/robot/output/console/dotted.py +0 -90
  143. robotframework-6.1rc1/src/robot/output/listenerarguments.py +0 -165
  144. robotframework-6.1rc1/src/robot/output/listenermethods.py +0 -113
  145. robotframework-6.1rc1/src/robot/output/listeners.py +0 -174
  146. robotframework-6.1rc1/src/robot/output/output.py +0 -95
  147. robotframework-6.1rc1/src/robot/parsing/model/visitor.py +0 -67
  148. robotframework-6.1rc1/src/robot/running/arguments/argumentconverter.py +0 -79
  149. robotframework-6.1rc1/src/robot/running/arguments/typevalidator.py +0 -56
  150. robotframework-6.1rc1/src/robot/running/modelcombiner.py +0 -32
  151. robotframework-6.1rc1/src/robot/variables/tablesetter.py +0 -156
  152. {robotframework-6.1rc1 → robotframework-7.0a1}/AUTHORS.rst +0 -0
  153. {robotframework-6.1rc1 → robotframework-7.0a1}/BUILD.rst +0 -0
  154. {robotframework-6.1rc1 → robotframework-7.0a1}/CONTRIBUTING.rst +0 -0
  155. {robotframework-6.1rc1 → robotframework-7.0a1}/COPYRIGHT.txt +0 -0
  156. {robotframework-6.1rc1 → robotframework-7.0a1}/INSTALL.rst +0 -0
  157. {robotframework-6.1rc1 → robotframework-7.0a1}/LICENSE.txt +0 -0
  158. {robotframework-6.1rc1 → robotframework-7.0a1}/MANIFEST.in +0 -0
  159. {robotframework-6.1rc1 → robotframework-7.0a1}/README.rst +0 -0
  160. {robotframework-6.1rc1 → robotframework-7.0a1}/setup.cfg +0 -0
  161. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/__init__.py +0 -0
  162. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/__main__.py +0 -0
  163. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/__init__.py +0 -0
  164. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/deco.py +0 -0
  165. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/exceptions.py +0 -0
  166. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/logger.py +0 -0
  167. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/__init__.py +0 -0
  168. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/errors.py +0 -0
  169. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/__init__.py +0 -0
  170. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/__init__.py +0 -0
  171. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/js_disabled.css +0 -0
  172. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/storage.js +0 -0
  173. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/htmlfilewriter.py +0 -0
  174. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/jsonwriter.py +0 -0
  175. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/__init__.py +0 -0
  176. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
  177. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.min.js +0 -0
  178. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
  179. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
  180. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
  181. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/__init__.py +0 -0
  182. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
  183. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/libdoc.css +0 -0
  184. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/libdoc.html +0 -0
  185. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/print.css +0 -0
  186. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/pygments.css +0 -0
  187. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/__init__.py +0 -0
  188. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/common.css +0 -0
  189. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/doc_formatting.css +0 -0
  190. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/fileloading.js +0 -0
  191. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.js +0 -0
  192. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/print.css +0 -0
  193. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/report.css +0 -0
  194. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/report.html +0 -0
  195. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/util.js +0 -0
  196. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/view.js +0 -0
  197. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/__init__.py +0 -0
  198. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/testdoc.css +0 -0
  199. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/testdoc.html +0 -0
  200. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdoc.py +0 -0
  201. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/__init__.py +0 -0
  202. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/consoleviewer.py +0 -0
  203. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/htmlwriter.py +0 -0
  204. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/jsonwriter.py +0 -0
  205. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/output.py +0 -0
  206. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/standardtypes.py +0 -0
  207. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/writer.py +0 -0
  208. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Dialogs.py +0 -0
  209. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Easter.py +0 -0
  210. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Screenshot.py +0 -0
  211. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Telnet.py +0 -0
  212. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/fixture.py +0 -0
  213. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/itemlist.py +0 -0
  214. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/metadata.py +0 -0
  215. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/statistics.py +0 -0
  216. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/suitestatistics.py +0 -0
  217. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tagsetter.py +0 -0
  218. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tagstatistics.py +0 -0
  219. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/totalstatistics.py +0 -0
  220. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/__init__.py +0 -0
  221. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/__init__.py +0 -0
  222. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/highlighting.py +0 -0
  223. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/librarylogger.py +0 -0
  224. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/pyloggingconf.py +0 -0
  225. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/__init__.py +0 -0
  226. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/__init__.py +0 -0
  227. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/tokenizer.py +0 -0
  228. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/__init__.py +0 -0
  229. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/__init__.py +0 -0
  230. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/blockparsers.py +0 -0
  231. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/fileparser.py +0 -0
  232. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/parser.py +0 -0
  233. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/suitestructure.py +0 -0
  234. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/pythonpathsetter.py +0 -0
  235. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/rebot.py +0 -0
  236. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/__init__.py +0 -0
  237. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsexecutionresult.py +0 -0
  238. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jswriter.py +0 -0
  239. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/logreportwriters.py +0 -0
  240. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/outputwriter.py +0 -0
  241. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/resultwriter.py +0 -0
  242. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/executionerrors.py +0 -0
  243. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/executionresult.py +0 -0
  244. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/messagefilter.py +0 -0
  245. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/suiteteardownfailed.py +0 -0
  246. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/visitor.py +0 -0
  247. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/__init__.py +0 -0
  248. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/__init__.py +0 -0
  249. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/dynamicmethods.py +0 -0
  250. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/importer.py +0 -0
  251. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/libraryscopes.py +0 -0
  252. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/outputcapture.py +0 -0
  253. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/randomizer.py +0 -0
  254. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/runkwregister.py +0 -0
  255. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/signalhandler.py +0 -0
  256. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/status.py +0 -0
  257. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/__init__.py +0 -0
  258. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/posix.py +0 -0
  259. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/windows.py +0 -0
  260. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/application.py +0 -0
  261. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/argumentparser.py +0 -0
  262. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/asserts.py +0 -0
  263. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/charwidth.py +0 -0
  264. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/compress.py +0 -0
  265. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/dotdict.py +0 -0
  266. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/encoding.py +0 -0
  267. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/error.py +0 -0
  268. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/etreewrapper.py +0 -0
  269. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/filereader.py +0 -0
  270. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/frange.py +0 -0
  271. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/htmlformatters.py +0 -0
  272. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/importer.py +0 -0
  273. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/markuputils.py +0 -0
  274. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/match.py +0 -0
  275. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/misc.py +0 -0
  276. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/recommendations.py +0 -0
  277. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/restreader.py +0 -0
  278. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotenv.py +0 -0
  279. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotinspect.py +0 -0
  280. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotio.py +0 -0
  281. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/sortable.py +0 -0
  282. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/typehints.py +0 -0
  283. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/finders.py +0 -0
  284. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/notfound.py +0 -0
  285. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/resolvable.py +0 -0
  286. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/dependency_links.txt +0 -0
  287. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/entry_points.txt +0 -0
  288. {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/top_level.txt +0 -0
@@ -32,45 +32,39 @@ be imported via the :mod:`robot.running` module.
32
32
 
33
33
  __ http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface
34
34
  __ http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results
35
-
36
35
  """
37
36
 
38
- import sys
39
37
  import warnings
40
38
  from collections import OrderedDict
41
39
  from datetime import datetime, timedelta
42
40
  from itertools import chain
43
41
  from pathlib import Path
44
- from typing import Generic, Mapping, Sequence, Type, Union, TypeVar
45
-
46
- if sys.version_info >= (3, 8):
47
- from typing import Literal
42
+ from typing import Generic, Literal, Mapping, Sequence, Type, Union, TypeVar
48
43
 
49
44
  from robot import model
50
- from robot.model import (BodyItem, create_fixture, DataDict, Keywords, Tags,
51
- SuiteVisitor, TotalStatistics, TotalStatisticsBuilder,
52
- TestCases, TestSuites)
53
- from robot.utils import copy_signature, get_elapsed_time, KnownAtRuntime, setter
45
+ from robot.model import (BodyItem, create_fixture, DataDict, SuiteVisitor, Tags,
46
+ TestSuites, TotalStatistics, TotalStatisticsBuilder)
47
+ from robot.utils import copy_signature, KnownAtRuntime, setter
54
48
 
55
49
  from .configurer import SuiteConfigurer
56
50
  from .messagefilter import MessageFilter
57
- from .modeldeprecation import deprecated, DeprecatedAttributesMixin
51
+ from .modeldeprecation import DeprecatedAttributesMixin
58
52
  from .keywordremover import KeywordRemover
59
53
  from .suiteteardownfailed import SuiteTeardownFailed, SuiteTeardownFailureHandler
60
54
 
55
+
61
56
  IT = TypeVar('IT', bound='IfBranch|TryBranch')
62
57
  FW = TypeVar('FW', bound='ForIteration|WhileIteration')
58
+ BodyItemParent = Union['TestSuite', 'TestCase', 'Keyword', 'For', 'ForIteration', 'If',
59
+ 'IfBranch', 'Try', 'TryBranch', 'While', 'WhileIteration', None]
63
60
 
64
- BodyItemParent = Union['TestSuite', 'TestCase', 'For', 'ForIteration', 'If', 'IfBranch',
65
- 'Try', 'TryBranch', 'While', 'WhileIteration', None]
66
61
 
67
-
68
- class Body(model.BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Return', 'Continue',
69
- 'Break', 'Message', 'Error']):
62
+ class Body(model.BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
63
+ 'Continue', 'Break', 'Message', 'Error']):
70
64
  __slots__ = []
71
65
 
72
66
 
73
- class Branches(model.BaseBranches['Keyword', 'For', 'While', 'If', 'Try', 'Return',
67
+ class Branches(model.BaseBranches['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
74
68
  'Continue', 'Break', 'Message', 'Error', IT]):
75
69
  __slots__ = []
76
70
 
@@ -80,7 +74,7 @@ class IterationType(Generic[FW]):
80
74
  pass
81
75
 
82
76
 
83
- class Iterations(model.BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Return',
77
+ class Iterations(model.BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
84
78
  'Continue', 'Break', 'Message', 'Error'], IterationType[FW]):
85
79
  __slots__ = ['iteration_class']
86
80
  iteration_type: Type[FW] = KnownAtRuntime
@@ -109,65 +103,142 @@ class StatusMixin:
109
103
  SKIP = 'SKIP'
110
104
  NOT_RUN = 'NOT RUN'
111
105
  NOT_SET = 'NOT SET'
112
- starttime: 'str|None'
113
- endtime: 'str|None'
114
106
  __slots__ = ()
115
107
 
116
108
  @property
117
- def elapsedtime(self) -> int:
118
- """Total execution time in milliseconds.
109
+ def start_time(self) -> 'datetime|None':
110
+ """Execution start time as a ``datetime`` or as a ``None`` if not set.
111
+
112
+ If start time is not set, it is calculated based :attr:`end_time`
113
+ and :attr:`elapsed_time` if possible.
119
114
 
120
- This attribute will be replaced by :attr:`elapsed_time` in the future.
115
+ Can be set either directly as a ``datetime`` or as a string in ISO 8601
116
+ format.
117
+
118
+ New in Robot Framework 6.1. Heavily enhanced in Robot Framework 7.0.
121
119
  """
122
- return get_elapsed_time(self.starttime, self.endtime)
120
+ if self._start_time:
121
+ return self._start_time
122
+ if self._end_time:
123
+ return self._end_time - self.elapsed_time
124
+ return None
125
+
126
+ @start_time.setter
127
+ def start_time(self, start_time: 'datetime|str|None'):
128
+ if isinstance(start_time, str):
129
+ start_time = datetime.fromisoformat(start_time)
130
+ self._start_time = start_time
131
+
132
+ @property
133
+ def end_time(self) -> 'datetime|None':
134
+ """Execution end time as a ``datetime`` or as a ``None`` if not set.
135
+
136
+ If end time is not set, it is calculated based :attr:`start_time`
137
+ and :attr:`elapsed_time` if possible.
138
+
139
+ Can be set either directly as a ``datetime`` or as a string in ISO 8601
140
+ format.
141
+
142
+ New in Robot Framework 6.1. Heavily enhanced in Robot Framework 7.0.
143
+ """
144
+ if self._end_time:
145
+ return self._end_time
146
+ if self._start_time:
147
+ return self._start_time + self.elapsed_time
148
+ return None
149
+
150
+ @end_time.setter
151
+ def end_time(self, end_time: 'datetime|str|None'):
152
+ if isinstance(end_time, str):
153
+ end_time = datetime.fromisoformat(end_time)
154
+ self._end_time = end_time
123
155
 
124
156
  @property
125
157
  def elapsed_time(self) -> timedelta:
126
158
  """Total execution time as a ``timedelta``.
127
159
 
128
- This attribute will replace :attr:`elapsedtime` in the future.
160
+ If not set, calculated based on :attr:`start_time` and :attr:`end_time`
161
+ if possible. If that fails, calculated based on the elapsed time of
162
+ child items.
163
+
164
+ Can be set either directly as a ``timedelta`` or as an integer or a float
165
+ representing seconds.
129
166
 
130
- New in Robot Framework 6.1.
167
+ New in Robot Framework 6.1. Heavily enhanced in Robot Framework 7.0.
131
168
  """
132
- return timedelta(milliseconds=self.elapsedtime)
169
+ if self._elapsed_time is not None:
170
+ return self._elapsed_time
171
+ if self._start_time and self._end_time:
172
+ return self._end_time - self._start_time
173
+ return self._elapsed_time_from_children()
174
+
175
+ def _elapsed_time_from_children(self) -> timedelta:
176
+ elapsed = timedelta()
177
+ for child in self.body:
178
+ if hasattr(child, 'elapsed_time'):
179
+ elapsed += child.elapsed_time
180
+ if getattr(self, 'has_setup', False):
181
+ elapsed += self.setup.elapsed_time
182
+ if getattr(self, 'has_teardown', False):
183
+ elapsed += self.teardown.elapsed_time
184
+ return elapsed
185
+
186
+ @elapsed_time.setter
187
+ def elapsed_time(self, elapsed_time: 'timedelta|int|float|None'):
188
+ if isinstance(elapsed_time, (int, float)):
189
+ elapsed_time = timedelta(seconds=elapsed_time)
190
+ self._elapsed_time = elapsed_time
133
191
 
134
192
  @property
135
- def start_time(self) -> 'datetime|None':
136
- """Execution start time as a ``datetime`` or as ``None`` if not set.
193
+ def starttime(self) -> 'str|None':
194
+ """Execution start time as a string or as a ``None`` if not set.
137
195
 
138
- This attribute will replace :attr:`starttime` in the future.
196
+ The string format is ``%Y%m%d %H:%M:%S.%f``.
139
197
 
140
- New in Robot Framework 6.1.
198
+ Considered deprecated starting from Robot Framework 7.0.
199
+ :attr:`start_time` should be used instead.
141
200
  """
142
- return self._timestr_to_datetime(self.starttime) if self.starttime else None
201
+ return self._datetime_to_timestr(self.start_time)
143
202
 
144
- @start_time.setter
145
- def start_time(self, start_time: 'datetime|None'):
146
- self.starttime = self._datetime_to_timestr(start_time) if start_time else None
203
+ @starttime.setter
204
+ def starttime(self, starttime: 'str|None'):
205
+ self.start_time = self._timestr_to_datetime(starttime)
147
206
 
148
207
  @property
149
- def end_time(self) -> 'datetime|None':
150
- """Execution end time as a ``datetime`` or as ``None`` if not set.
208
+ def endtime(self) -> 'str|None':
209
+ """Execution end time as a string or as a ``None`` if not set.
151
210
 
152
- This attribute will replace :attr:`endtime` in the future.
211
+ The string format is ``%Y%m%d %H:%M:%S.%f``.
153
212
 
154
- New in Robot Framework 6.1.
213
+ Considered deprecated starting from Robot Framework 7.0.
214
+ :attr:`end_time` should be used instead.
155
215
  """
156
- return self._timestr_to_datetime(self.endtime) if self.endtime else None
216
+ return self._datetime_to_timestr(self.end_time)
157
217
 
158
- @end_time.setter
159
- def end_time(self, end_time: 'datetime|None'):
160
- self.endtime = self._datetime_to_timestr(end_time) if end_time else None
218
+ @endtime.setter
219
+ def endtime(self, endtime: 'str|None'):
220
+ self.end_time = self._timestr_to_datetime(endtime)
221
+
222
+ @property
223
+ def elapsedtime(self) -> int:
224
+ """Total execution time in milliseconds.
225
+
226
+ Considered deprecated starting from Robot Framework 7.0.
227
+ :attr:`elapsed_time` should be used instead.
228
+ """
229
+ return round(self.elapsed_time.total_seconds() * 1000)
161
230
 
162
- def _timestr_to_datetime(self, ts: str) -> datetime:
163
- micro = int(ts[18:]) * 1000
231
+ def _timestr_to_datetime(self, ts: 'str|None') -> 'datetime|None':
232
+ if not ts:
233
+ return None
234
+ ts = ts.ljust(24, '0')
164
235
  return datetime(int(ts[:4]), int(ts[4:6]), int(ts[6:8]),
165
- int(ts[9:11]), int(ts[12:14]), int(ts[15:17]), micro)
236
+ int(ts[9:11]), int(ts[12:14]), int(ts[15:17]), int(ts[18:24]))
166
237
 
167
- def _datetime_to_timestr(self, dt: datetime) -> str:
168
- millis = int(round(dt.microsecond, -3) / 1000)
169
- return (f'{dt.year}{dt.month:02}{dt.day:02} '
170
- f'{dt.hour:02}:{dt.minute:02}.{dt.second:02}.{millis}')
238
+ def _datetime_to_timestr(self, dt: 'datetime|None') -> 'str|None':
239
+ if not dt:
240
+ return None
241
+ return dt.isoformat(' ', timespec='milliseconds').replace('-', '')
171
242
 
172
243
  @property
173
244
  def passed(self) -> bool:
@@ -196,7 +267,7 @@ class StatusMixin:
196
267
  return self.status == self.SKIP
197
268
 
198
269
  @skipped.setter
199
- def skipped(self, skipped: 'Literal[True]'):
270
+ def skipped(self, skipped: Literal[True]):
200
271
  if not skipped:
201
272
  raise ValueError(f"`skipped` value must be truthy, got '{skipped}'.")
202
273
  self.status = self.SKIP
@@ -210,7 +281,7 @@ class StatusMixin:
210
281
  return self.status == self.NOT_RUN
211
282
 
212
283
  @not_run.setter
213
- def not_run(self, not_run: 'Literal[True]'):
284
+ def not_run(self, not_run: Literal[True]):
214
285
  if not not_run:
215
286
  raise ValueError(f"`not_run` value must be truthy, got '{not_run}'.")
216
287
  self.status = self.NOT_RUN
@@ -220,22 +291,32 @@ class ForIteration(BodyItem, StatusMixin, DeprecatedAttributesMixin):
220
291
  """Represents one FOR loop iteration."""
221
292
  type = BodyItem.ITERATION
222
293
  body_class = Body
223
- repr_args = ('variables',)
224
- __slots__ = ['variables', 'status', 'starttime', 'endtime', 'doc']
294
+ repr_args = ('assign',)
295
+ __slots__ = ['assign', 'message', 'status', '_start_time', '_end_time',
296
+ '_elapsed_time']
225
297
 
226
- def __init__(self, variables: 'Mapping[str, str]|None' = None,
298
+ def __init__(self, assign: 'Mapping[str, str]|None' = None,
227
299
  status: str = 'FAIL',
228
- starttime: 'str|None' = None,
229
- endtime: 'str|None' = None,
230
- doc: str = '',
300
+ message: str = '',
301
+ start_time: 'datetime|str|None' = None,
302
+ end_time: 'datetime|str|None' = None,
303
+ elapsed_time: 'timedelta|int|float|None' = None,
231
304
  parent: BodyItemParent = None):
232
- self.variables = OrderedDict(variables or ())
305
+ self.assign = OrderedDict(assign or ())
233
306
  self.parent = parent
234
307
  self.status = status
235
- self.starttime = starttime
236
- self.endtime = endtime
237
- self.doc = doc
238
- self.body = []
308
+ self.message = message
309
+ self.start_time = start_time
310
+ self.end_time = end_time
311
+ self.elapsed_time = elapsed_time
312
+ self.body = ()
313
+
314
+ @property
315
+ def variables(self) -> 'Mapping[str, str]': # TODO: Remove in RF 8.0.
316
+ """Deprecated since Robot Framework 7.0. Use :attr:`assign` instead."""
317
+ warnings.warn("'ForIteration.variables' is deprecated and will be removed in "
318
+ "Robot Framework 8.0. Use 'ForIteration.assign' instead.")
319
+ return self.assign
239
320
 
240
321
  @setter
241
322
  def body(self, body: 'Sequence[BodyItem|DataDict]') -> Body:
@@ -245,67 +326,62 @@ class ForIteration(BodyItem, StatusMixin, DeprecatedAttributesMixin):
245
326
  visitor.visit_for_iteration(self)
246
327
 
247
328
  @property
248
- @deprecated
249
- def name(self) -> str:
250
- return ', '.join('%s = %s' % item for item in self.variables.items())
329
+ def _log_name(self):
330
+ return ', '.join(f'{name} = {value}' for name, value in self.assign.items())
251
331
 
252
332
 
253
333
  @Body.register
254
334
  class For(model.For, StatusMixin, DeprecatedAttributesMixin):
255
335
  iteration_class = ForIteration
256
336
  iterations_class = Iterations[iteration_class]
257
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
337
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
258
338
 
259
- def __init__(self, variables: Sequence[str] = (),
260
- flavor: "Literal['IN', 'IN RANGE', 'IN ENUMERATE', 'IN ZIP']" = 'IN',
339
+ def __init__(self, assign: Sequence[str] = (),
340
+ flavor: Literal['IN', 'IN RANGE', 'IN ENUMERATE', 'IN ZIP'] = 'IN',
261
341
  values: Sequence[str] = (),
262
342
  start: 'str|None' = None,
263
343
  mode: 'str|None' = None,
264
344
  fill: 'str|None' = None,
265
345
  status: str = 'FAIL',
266
- starttime: 'str|None' = None,
267
- endtime: 'str|None' = None,
268
- doc: str = '',
346
+ message: str = '',
347
+ start_time: 'datetime|str|None' = None,
348
+ end_time: 'datetime|str|None' = None,
349
+ elapsed_time: 'timedelta|int|float|None' = None,
269
350
  parent: BodyItemParent = None):
270
- super().__init__(variables, flavor, values, start, mode, fill, parent)
351
+ super().__init__(assign, flavor, values, start, mode, fill, parent)
271
352
  self.status = status
272
- self.starttime = starttime
273
- self.endtime = endtime
274
- self.doc = doc
353
+ self.message = message
354
+ self.start_time = start_time
355
+ self.end_time = end_time
356
+ self.elapsed_time = elapsed_time
275
357
 
276
358
  @setter
277
359
  def body(self, iterations: 'Sequence[ForIteration|DataDict]') -> iterations_class:
278
360
  return self.iterations_class(self.iteration_class, self, iterations)
279
361
 
280
362
  @property
281
- @deprecated
282
- def name(self) -> str:
283
- variables = ' | '.join(self.variables)
284
- values = ' | '.join(self.values)
285
- for name, value in [('start', self.start),
286
- ('mode', self.mode),
287
- ('fill', self.fill)]:
288
- if value is not None:
289
- values += f' | {name}={value}'
290
- return f'{variables} {self.flavor} [ {values} ]'
363
+ def _log_name(self):
364
+ return str(self)[7:] # Drop 'FOR ' prefix.
291
365
 
292
366
 
293
367
  class WhileIteration(BodyItem, StatusMixin, DeprecatedAttributesMixin):
294
368
  """Represents one WHILE loop iteration."""
295
369
  type = BodyItem.ITERATION
296
370
  body_class = Body
297
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
371
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
298
372
 
299
373
  def __init__(self, status: str = 'FAIL',
300
- starttime: 'str|None' = None,
301
- endtime: 'str|None' = None,
302
- doc: str = '',
374
+ message: str = '',
375
+ start_time: 'datetime|str|None' = None,
376
+ end_time: 'datetime|str|None' = None,
377
+ elapsed_time: 'timedelta|int|float|None' = None,
303
378
  parent: BodyItemParent = None):
304
379
  self.parent = parent
305
380
  self.status = status
306
- self.starttime = starttime
307
- self.endtime = endtime
308
- self.doc = doc
381
+ self.message = message
382
+ self.start_time = start_time
383
+ self.end_time = end_time
384
+ self.elapsed_time = elapsed_time
309
385
  self.body = ()
310
386
 
311
387
  @setter
@@ -315,72 +391,60 @@ class WhileIteration(BodyItem, StatusMixin, DeprecatedAttributesMixin):
315
391
  def visit(self, visitor: SuiteVisitor):
316
392
  visitor.visit_while_iteration(self)
317
393
 
318
- @property
319
- @deprecated
320
- def name(self) -> str:
321
- return ''
322
-
323
394
 
324
395
  @Body.register
325
396
  class While(model.While, StatusMixin, DeprecatedAttributesMixin):
326
397
  iteration_class = WhileIteration
327
398
  iterations_class = Iterations[iteration_class]
328
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
399
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
329
400
 
330
401
  def __init__(self, condition: 'str|None' = None,
331
402
  limit: 'str|None' = None,
332
403
  on_limit: 'str|None' = None,
333
404
  on_limit_message: 'str|None' = None,
334
405
  status: str = 'FAIL',
335
- starttime: 'str|None' = None,
336
- endtime: 'str|None' = None,
337
- doc: str = '',
406
+ message: str = '',
407
+ start_time: 'datetime|str|None' = None,
408
+ end_time: 'datetime|str|None' = None,
409
+ elapsed_time: 'timedelta|int|float|None' = None,
338
410
  parent: BodyItemParent = None):
339
411
  super().__init__(condition, limit, on_limit, on_limit_message, parent)
340
412
  self.status = status
341
- self.starttime = starttime
342
- self.endtime = endtime
343
- self.doc = doc
413
+ self.message = message
414
+ self.start_time = start_time
415
+ self.end_time = end_time
416
+ self.elapsed_time = elapsed_time
344
417
 
345
418
  @setter
346
419
  def body(self, iterations: 'Sequence[WhileIteration|DataDict]') -> iterations_class:
347
420
  return self.iterations_class(self.iteration_class, self, iterations)
348
421
 
349
422
  @property
350
- @deprecated
351
- def name(self) -> str:
352
- parts = []
353
- if self.condition:
354
- parts.append(self.condition)
355
- if self.limit:
356
- parts.append(f'limit={self.limit}')
357
- if self.on_limit:
358
- parts.append(f'on_limit={self.on_limit}')
359
- if self.on_limit_message:
360
- parts.append(f'on_limit_message={self.on_limit_message}')
361
- return ' | '.join(parts)
423
+ def _log_name(self):
424
+ return str(self)[9:] # Drop 'WHILE ' prefix.
362
425
 
363
426
 
364
427
  class IfBranch(model.IfBranch, StatusMixin, DeprecatedAttributesMixin):
365
428
  body_class = Body
366
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
429
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
367
430
 
368
431
  def __init__(self, type: str = BodyItem.IF,
369
432
  condition: 'str|None' = None,
370
433
  status: str = 'FAIL',
371
- starttime: 'str|None' = None,
372
- endtime: 'str|None' = None,
373
- doc: str = '',
434
+ message: str = '',
435
+ start_time: 'datetime|str|None' = None,
436
+ end_time: 'datetime|str|None' = None,
437
+ elapsed_time: 'timedelta|int|float|None' = None,
374
438
  parent: BodyItemParent = None):
375
439
  super().__init__(type, condition, parent)
376
440
  self.status = status
377
- self.starttime = starttime
378
- self.endtime = endtime
379
- self.doc = doc
441
+ self.message = message
442
+ self.start_time = start_time
443
+ self.end_time = end_time
444
+ self.elapsed_time = elapsed_time
380
445
 
381
446
  @property
382
- @deprecated
383
- def name(self) -> str:
447
+ def _log_name(self):
384
448
  return self.condition or ''
385
449
 
386
450
 
@@ -388,85 +452,124 @@ class IfBranch(model.IfBranch, StatusMixin, DeprecatedAttributesMixin):
388
452
  class If(model.If, StatusMixin, DeprecatedAttributesMixin):
389
453
  branch_class = IfBranch
390
454
  branches_class = Branches[branch_class]
391
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
455
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
392
456
 
393
457
  def __init__(self, status: str = 'FAIL',
394
- starttime: 'str|None' = None,
395
- endtime: 'str|None' = None,
396
- doc: str = '',
458
+ message: str = '',
459
+ start_time: 'datetime|str|None' = None,
460
+ end_time: 'datetime|str|None' = None,
461
+ elapsed_time: 'timedelta|int|float|None' = None,
397
462
  parent: BodyItemParent = None):
398
463
  super().__init__(parent)
399
464
  self.status = status
400
- self.starttime = starttime
401
- self.endtime = endtime
402
- self.doc = doc
465
+ self.message = message
466
+ self.start_time = start_time
467
+ self.end_time = end_time
468
+ self.elapsed_time = elapsed_time
403
469
 
404
470
 
405
471
  class TryBranch(model.TryBranch, StatusMixin, DeprecatedAttributesMixin):
406
472
  body_class = Body
407
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
473
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
408
474
 
409
475
  def __init__(self, type: str = BodyItem.TRY,
410
476
  patterns: Sequence[str] = (),
411
477
  pattern_type: 'str|None' = None,
412
- variable: 'str|None' = None,
478
+ assign: 'str|None' = None,
413
479
  status: str = 'FAIL',
414
- starttime: 'str|None' = None,
415
- endtime: 'str|None' = None,
416
- doc: str = '',
480
+ message: str = '',
481
+ start_time: 'datetime|str|None' = None,
482
+ end_time: 'datetime|str|None' = None,
483
+ elapsed_time: 'timedelta|int|float|None' = None,
417
484
  parent: BodyItemParent = None):
418
- super().__init__(type, patterns, pattern_type, variable, parent)
485
+ super().__init__(type, patterns, pattern_type, assign, parent)
419
486
  self.status = status
420
- self.starttime = starttime
421
- self.endtime = endtime
422
- self.doc = doc
487
+ self.message = message
488
+ self.start_time = start_time
489
+ self.end_time = end_time
490
+ self.elapsed_time = elapsed_time
423
491
 
424
492
  @property
425
- @deprecated
426
- def name(self) -> str:
427
- patterns = list(self.patterns)
428
- if self.pattern_type:
429
- patterns.append(f'type={self.pattern_type}')
430
- parts = []
431
- if patterns:
432
- parts.append(' | '.join(patterns))
433
- if self.variable:
434
- parts.append(f'AS {self.variable}')
435
- return ' '.join(parts)
493
+ def _log_name(self):
494
+ return str(self)[len(self.type)+4:] # Drop '<type> ' prefix.
436
495
 
437
496
 
438
497
  @Body.register
439
498
  class Try(model.Try, StatusMixin, DeprecatedAttributesMixin):
440
499
  branch_class = TryBranch
441
500
  branches_class = Branches[branch_class]
442
- __slots__ = ['status', 'starttime', 'endtime', 'doc']
501
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
443
502
 
444
503
  def __init__(self, status: str = 'FAIL',
445
- starttime: 'str|None' = None,
446
- endtime: 'str|None' = None,
447
- doc: str = '',
504
+ message: str = '',
505
+ start_time: 'datetime|str|None' = None,
506
+ end_time: 'datetime|str|None' = None,
507
+ elapsed_time: 'timedelta|int|float|None' = None,
448
508
  parent: BodyItemParent = None):
449
509
  super().__init__(parent)
450
510
  self.status = status
451
- self.starttime = starttime
452
- self.endtime = endtime
453
- self.doc = doc
511
+ self.message = message
512
+ self.start_time = start_time
513
+ self.end_time = end_time
514
+ self.elapsed_time = elapsed_time
515
+
516
+
517
+ @Body.register
518
+ class Var(model.Var, StatusMixin, DeprecatedAttributesMixin):
519
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
520
+ body_class = Body
521
+
522
+ def __init__(self, name: str = '',
523
+ value: 'str|Sequence[str]' = (),
524
+ scope: 'str|None' = None,
525
+ separator: 'str|None' = None,
526
+ status: str = 'FAIL',
527
+ message: str = '',
528
+ start_time: 'datetime|str|None' = None,
529
+ end_time: 'datetime|str|None' = None,
530
+ elapsed_time: 'timedelta|int|float|None' = None,
531
+ parent: BodyItemParent = None):
532
+ super().__init__(name, value, scope, separator, parent)
533
+ self.status = status
534
+ self.message = message
535
+ self.start_time = start_time
536
+ self.end_time = end_time
537
+ self.elapsed_time = elapsed_time
538
+ self.body = ()
539
+
540
+ @setter
541
+ def body(self, body: 'Sequence[BodyItem|DataDict]') -> Body:
542
+ """Child keywords and messages as a :class:`~.Body` object.
543
+
544
+ Typically empty. Only contains something if running VAR has failed
545
+ due to a syntax error or listeners have logged messages or executed
546
+ keywords.
547
+ """
548
+ return self.body_class(self, body)
549
+
550
+ @property
551
+ def _log_name(self):
552
+ return str(self)[7:] # Drop 'VAR ' prefix.
454
553
 
455
554
 
456
555
  @Body.register
457
556
  class Return(model.Return, StatusMixin, DeprecatedAttributesMixin):
458
- __slots__ = ['status', 'starttime', 'endtime']
557
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
459
558
  body_class = Body
460
559
 
461
560
  def __init__(self, values: Sequence[str] = (),
462
561
  status: str = 'FAIL',
463
- starttime: 'str|None' = None,
464
- endtime: 'str|None' = None,
562
+ message: str = '',
563
+ start_time: 'datetime|str|None' = None,
564
+ end_time: 'datetime|str|None' = None,
565
+ elapsed_time: 'timedelta|int|float|None' = None,
465
566
  parent: BodyItemParent = None):
466
567
  super().__init__(values, parent)
467
568
  self.status = status
468
- self.starttime = starttime
469
- self.endtime = endtime
569
+ self.message = message
570
+ self.start_time = start_time
571
+ self.end_time = end_time
572
+ self.elapsed_time = elapsed_time
470
573
  self.body = ()
471
574
 
472
575
  @setter
@@ -479,30 +582,24 @@ class Return(model.Return, StatusMixin, DeprecatedAttributesMixin):
479
582
  """
480
583
  return self.body_class(self, body)
481
584
 
482
- @property
483
- @deprecated
484
- def args(self) -> 'tuple[str, ...]':
485
- return self.values
486
-
487
- @property
488
- @deprecated
489
- def doc(self) -> str:
490
- return ''
491
-
492
585
 
493
586
  @Body.register
494
587
  class Continue(model.Continue, StatusMixin, DeprecatedAttributesMixin):
495
- __slots__ = ['status', 'starttime', 'endtime']
588
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
496
589
  body_class = Body
497
590
 
498
591
  def __init__(self, status: str = 'FAIL',
499
- starttime: 'str|None' = None,
500
- endtime: 'str|None' = None,
592
+ message: str = '',
593
+ start_time: 'datetime|str|None' = None,
594
+ end_time: 'datetime|str|None' = None,
595
+ elapsed_time: 'timedelta|int|float|None' = None,
501
596
  parent: BodyItemParent = None):
502
597
  super().__init__(parent)
503
598
  self.status = status
504
- self.starttime = starttime
505
- self.endtime = endtime
599
+ self.message = message
600
+ self.start_time = start_time
601
+ self.end_time = end_time
602
+ self.elapsed_time = elapsed_time
506
603
  self.body = ()
507
604
 
508
605
  @setter
@@ -515,30 +612,24 @@ class Continue(model.Continue, StatusMixin, DeprecatedAttributesMixin):
515
612
  """
516
613
  return self.body_class(self, body)
517
614
 
518
- @property
519
- @deprecated
520
- def args(self) -> 'tuple[str, ...]':
521
- return ()
522
-
523
- @property
524
- @deprecated
525
- def doc(self) -> str:
526
- return ''
527
-
528
615
 
529
616
  @Body.register
530
617
  class Break(model.Break, StatusMixin, DeprecatedAttributesMixin):
531
- __slots__ = ['status', 'starttime', 'endtime']
618
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
532
619
  body_class = Body
533
620
 
534
621
  def __init__(self, status: str = 'FAIL',
535
- starttime: 'str|None' = None,
536
- endtime: 'str|None' = None,
622
+ message: str = '',
623
+ start_time: 'datetime|str|None' = None,
624
+ end_time: 'datetime|str|None' = None,
625
+ elapsed_time: 'timedelta|int|float|None' = None,
537
626
  parent: BodyItemParent = None):
538
627
  super().__init__(parent)
539
628
  self.status = status
540
- self.starttime = starttime
541
- self.endtime = endtime
629
+ self.message = message
630
+ self.start_time = start_time
631
+ self.end_time = end_time
632
+ self.elapsed_time = elapsed_time
542
633
  self.body = ()
543
634
 
544
635
  @setter
@@ -551,31 +642,25 @@ class Break(model.Break, StatusMixin, DeprecatedAttributesMixin):
551
642
  """
552
643
  return self.body_class(self, body)
553
644
 
554
- @property
555
- @deprecated
556
- def args(self) -> 'tuple[str, ...]':
557
- return ()
558
-
559
- @property
560
- @deprecated
561
- def doc(self) -> str:
562
- return ''
563
-
564
645
 
565
646
  @Body.register
566
647
  class Error(model.Error, StatusMixin, DeprecatedAttributesMixin):
567
- __slots__ = ['status', 'starttime', 'endtime']
648
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
568
649
  body_class = Body
569
650
 
570
651
  def __init__(self, values: Sequence[str] = (),
571
652
  status: str = 'FAIL',
572
- starttime: 'str|None' = None,
573
- endtime: 'str|None' = None,
653
+ message: str = '',
654
+ start_time: 'datetime|str|None' = None,
655
+ end_time: 'datetime|str|None' = None,
656
+ elapsed_time: 'timedelta|int|float|None' = None,
574
657
  parent: BodyItemParent = None):
575
658
  super().__init__(values, parent)
576
659
  self.status = status
577
- self.starttime = starttime
578
- self.endtime = endtime
660
+ self.message = message
661
+ self.start_time = start_time
662
+ self.end_time = end_time
663
+ self.elapsed_time = elapsed_time
579
664
  self.body = ()
580
665
 
581
666
  @setter
@@ -586,21 +671,6 @@ class Error(model.Error, StatusMixin, DeprecatedAttributesMixin):
586
671
  """
587
672
  return self.body_class(self, body)
588
673
 
589
- @property
590
- @deprecated
591
- def kwname(self) -> str:
592
- return self.values[0]
593
-
594
- @property
595
- @deprecated
596
- def args(self) -> 'tuple[str, ...]':
597
- return self.values[1:]
598
-
599
- @property
600
- @deprecated
601
- def doc(self) -> 'str':
602
- return ''
603
-
604
674
 
605
675
  @Body.register
606
676
  @Branches.register
@@ -608,11 +678,12 @@ class Error(model.Error, StatusMixin, DeprecatedAttributesMixin):
608
678
  class Keyword(model.Keyword, StatusMixin):
609
679
  """Represents an executed library or user keyword."""
610
680
  body_class = Body
611
- __slots__ = ['kwname', 'libname', 'doc', 'timeout', 'status', '_teardown',
612
- 'starttime', 'endtime', 'message', 'sourcename']
681
+ __slots__ = ['owner', 'source_name', 'doc', 'timeout', 'status', 'message',
682
+ '_start_time', '_end_time', '_elapsed_time', '_setup', '_teardown']
613
683
 
614
- def __init__(self, kwname: str = '',
615
- libname: str = '',
684
+ def __init__(self, name: 'str|None' = '',
685
+ owner: 'str|None' = None,
686
+ source_name: 'str|None' = None,
616
687
  doc: str = '',
617
688
  args: Sequence[str] = (),
618
689
  assign: Sequence[str] = (),
@@ -620,25 +691,25 @@ class Keyword(model.Keyword, StatusMixin):
620
691
  timeout: 'str|None' = None,
621
692
  type: str = BodyItem.KEYWORD,
622
693
  status: str = 'FAIL',
623
- starttime: 'str|None' = None,
624
- endtime: 'str|None' = None,
625
- sourcename: 'str|None' = None,
694
+ message: str = '',
695
+ start_time: 'datetime|str|None' = None,
696
+ end_time: 'datetime|str|None' = None,
697
+ elapsed_time: 'timedelta|int|float|None' = None,
626
698
  parent: BodyItemParent = None):
627
- super().__init__(None, args, assign, type, parent)
628
- #: Name of the keyword without library or resource name.
629
- self.kwname = kwname
699
+ super().__init__(name, args, assign, type, parent)
630
700
  #: Name of the library or resource containing this keyword.
631
- self.libname = libname
701
+ self.owner = owner
702
+ #: Original name of keyword with embedded arguments.
703
+ self.source_name = source_name
632
704
  self.doc = doc
633
705
  self.tags = tags
634
706
  self.timeout = timeout
635
707
  self.status = status
636
- self.starttime = starttime
637
- self.endtime = endtime
638
- #: Keyword status message. Used only if suite teardowns fails.
639
- self.message = ''
640
- #: Original name of keyword with embedded arguments.
641
- self.sourcename = sourcename
708
+ self.message = message
709
+ self.start_time = start_time
710
+ self.end_time = end_time
711
+ self.elapsed_time = elapsed_time
712
+ self._setup = None
642
713
  self._teardown = None
643
714
  self.body = ()
644
715
 
@@ -651,21 +722,6 @@ class Keyword(model.Keyword, StatusMixin):
651
722
  """
652
723
  return self.body_class(self, body)
653
724
 
654
- @property
655
- def keywords(self) -> Keywords:
656
- """Deprecated since Robot Framework 4.0.
657
-
658
- Use :attr:`body` or :attr:`teardown` instead.
659
- """
660
- keywords = self.body.filter(messages=False)
661
- if self.teardown:
662
- keywords.append(self.teardown)
663
- return Keywords(self, keywords)
664
-
665
- @keywords.setter
666
- def keywords(self, keywords):
667
- Keywords.raise_deprecation_error()
668
-
669
725
  @property
670
726
  def messages(self) -> 'list[Message]':
671
727
  """Keyword's messages.
@@ -676,38 +732,72 @@ class Keyword(model.Keyword, StatusMixin):
676
732
  return self.body.filter(messages=True) # type: ignore
677
733
 
678
734
  @property
679
- def children(self) -> 'list[BodyItem]':
680
- """List of child keywords and messages in creation order.
735
+ def full_name(self) -> 'str|None':
736
+ """Keyword name in format ``owner.name``.
681
737
 
682
- Deprecated since Robot Framework 4.0. Use :attr:`body` instead.
738
+ Just ``name`` if :attr:`owner` is not set. In practice this is the
739
+ case only with user keywords in the suite file.
740
+
741
+ Cannot be set directly. Set :attr:`name` and :attr:`owner` separately
742
+ instead.
743
+
744
+ Notice that prior to Robot Framework 7.0, the ``name`` attribute contained
745
+ the full name and keyword and owner names were in ``kwname`` and ``libname``,
746
+ respectively.
683
747
  """
684
- warnings.warn("'Keyword.children' is deprecated. Use 'Keyword.body' instead.")
685
- return list(self.body)
748
+ return f'{self.owner}.{self.name}' if self.owner else self.name
686
749
 
750
+ # TODO: Deprecate 'kwname', 'libname' and 'sourcename' loudly in RF 8.
687
751
  @property
688
- def name(self) -> 'str|None':
689
- """Keyword name in format ``libname.kwname``.
752
+ def kwname(self) -> 'str|None':
753
+ """Deprecated since Robot Framework 7.0. Use :attr:`name` instead."""
754
+ return self.name
690
755
 
691
- Just ``kwname`` if :attr:`libname` is empty. In practice that is the
692
- case only with user keywords in the same file as the executed test case
693
- or test suite.
756
+ @kwname.setter
757
+ def kwname(self, name: 'str|None'):
758
+ self.name = name
759
+
760
+ @property
761
+ def libname(self) -> 'str|None':
762
+ """Deprecated since Robot Framework 7.0. Use :attr:`owner` instead."""
763
+ return self.owner
694
764
 
695
- Cannot be set directly. Set :attr:`libname` and :attr:`kwname`
696
- separately instead.
765
+ @libname.setter
766
+ def libname(self, name: 'str|None'):
767
+ self.owner = name
768
+
769
+ @property
770
+ def sourcename(self) -> str:
771
+ """Deprecated since Robot Framework 7.0. Use :attr:`source_name` instead."""
772
+ return self.source_name
773
+
774
+ @sourcename.setter
775
+ def sourcename(self, name: str):
776
+ self.source_name = name
777
+
778
+ @property
779
+ def setup(self) -> 'Keyword':
780
+ """Keyword setup as a :class:`Keyword` object.
781
+
782
+ See :attr:`teardown` for more information. New in Robot Framework 7.0.
783
+ """
784
+ if self._setup is None:
785
+ self.setup = None
786
+ return self._setup
787
+
788
+ @setup.setter
789
+ def setup(self, setup: 'Keyword|DataDict|None'):
790
+ self._setup = create_fixture(self.__class__, setup, self, self.SETUP)
791
+
792
+ @property
793
+ def has_setup(self) -> bool:
794
+ """Check does a keyword have a setup without creating a setup object.
795
+
796
+ See :attr:`has_teardown` for more information. New in Robot Framework 7.0.
697
797
  """
698
- if not self.libname:
699
- return self.kwname
700
- return f'{self.libname}.{self.kwname}'
701
-
702
- @name.setter
703
- def name(self, name):
704
- if name is not None:
705
- raise AttributeError("Cannot set 'name' attribute directly. "
706
- "Set 'kwname' and 'libname' separately instead.")
707
- self.kwname = None
708
- self.libname = None
709
-
710
- @property # Cannot use @setter because it would create teardowns recursively.
798
+ return bool(self._setup)
799
+
800
+ @property
711
801
  def teardown(self) -> 'Keyword':
712
802
  """Keyword teardown as a :class:`Keyword` object.
713
803
 
@@ -737,7 +827,7 @@ class Keyword(model.Keyword, StatusMixin):
737
827
  Framework 4.1.2.
738
828
  """
739
829
  if self._teardown is None:
740
- self._teardown = create_fixture(self.__class__, None, self, self.TEARDOWN)
830
+ self.teardown = None
741
831
  return self._teardown
742
832
 
743
833
  @teardown.setter
@@ -769,7 +859,7 @@ class TestCase(model.TestCase[Keyword], StatusMixin):
769
859
 
770
860
  See the base class for documentation of attributes not documented here.
771
861
  """
772
- __slots__ = ['status', 'message', 'starttime', 'endtime']
862
+ __slots__ = ['status', 'message', '_start_time', '_end_time', '_elapsed_time']
773
863
  body_class = Body
774
864
  fixture_class = Keyword
775
865
 
@@ -780,29 +870,21 @@ class TestCase(model.TestCase[Keyword], StatusMixin):
780
870
  lineno: 'int|None' = None,
781
871
  status: str = 'FAIL',
782
872
  message: str = '',
783
- starttime: 'str|None' = None,
784
- endtime: 'str|None' = None,
873
+ start_time: 'datetime|str|None' = None,
874
+ end_time: 'datetime|str|None' = None,
875
+ elapsed_time: 'timedelta|int|float|None' = None,
785
876
  parent: 'TestSuite|None' = None):
786
877
  super().__init__(name, doc, tags, timeout, lineno, parent)
787
- #: Status as a string ``PASS`` or ``FAIL``. See also :attr:`passed`.
788
878
  self.status = status
789
- #: Test message. Typically a failure message but can be set also when
790
- #: test passes.
791
879
  self.message = message
792
- #: Test case execution start time in format ``%Y%m%d %H:%M:%S.%f``.
793
- self.starttime = starttime
794
- #: Test case execution end time in format ``%Y%m%d %H:%M:%S.%f``.
795
- self.endtime = endtime
880
+ self.start_time = start_time
881
+ self.end_time = end_time
882
+ self.elapsed_time = elapsed_time
796
883
 
797
884
  @property
798
885
  def not_run(self) -> bool:
799
886
  return False
800
887
 
801
- @property
802
- def critical(self) -> bool:
803
- warnings.warn("'TestCase.critical' is deprecated and always returns 'True'.")
804
- return True
805
-
806
888
  @setter
807
889
  def body(self, body: 'Sequence[BodyItem|DataDict]') -> Body:
808
890
  """Test body as a :class:`~robot.result.Body` object."""
@@ -814,7 +896,7 @@ class TestSuite(model.TestSuite[Keyword, TestCase], StatusMixin):
814
896
 
815
897
  See the base class for documentation of attributes not documented here.
816
898
  """
817
- __slots__ = ['message', 'starttime', 'endtime']
899
+ __slots__ = ['message', '_start_time', '_end_time', '_elapsed_time']
818
900
  test_class = TestCase
819
901
  fixture_class = Keyword
820
902
 
@@ -824,16 +906,26 @@ class TestSuite(model.TestSuite[Keyword, TestCase], StatusMixin):
824
906
  source: 'Path|str|None' = None,
825
907
  rpa: bool = False,
826
908
  message: str = '',
827
- starttime: 'str|None' = None,
828
- endtime: 'str|None' = None,
909
+ start_time: 'datetime|str|None' = None,
910
+ end_time: 'datetime|str|None' = None,
911
+ elapsed_time: 'timedelta|int|float|None' = None,
829
912
  parent: 'TestSuite|None' = None):
830
913
  super().__init__(name, doc, metadata, source, rpa, parent)
831
914
  #: Possible suite setup or teardown error message.
832
915
  self.message = message
833
- #: Suite execution start time in format ``%Y%m%d %H:%M:%S.%f``.
834
- self.starttime = starttime
835
- #: Suite execution end time in format ``%Y%m%d %H:%M:%S.%f``.
836
- self.endtime = endtime
916
+ self.start_time = start_time
917
+ self.end_time = end_time
918
+ self.elapsed_time = elapsed_time
919
+
920
+ def _elapsed_time_from_children(self) -> timedelta:
921
+ elapsed = timedelta()
922
+ if self.has_setup:
923
+ elapsed += self.setup.elapsed_time
924
+ if self.has_teardown:
925
+ elapsed += self.teardown.elapsed_time
926
+ for child in chain(self.suites, self.tests):
927
+ elapsed += child.elapsed_time
928
+ return elapsed
837
929
 
838
930
  @property
839
931
  def passed(self) -> bool:
@@ -855,7 +947,7 @@ class TestSuite(model.TestSuite[Keyword, TestCase], StatusMixin):
855
947
  return False
856
948
 
857
949
  @property
858
- def status(self) -> "Literal['PASS', 'SKIP', 'FAIL']":
950
+ def status(self) -> Literal['PASS', 'SKIP', 'FAIL']:
859
951
  """'PASS', 'FAIL' or 'SKIP' depending on test statuses.
860
952
 
861
953
  - If any test has failed, status is 'FAIL'.
@@ -896,14 +988,6 @@ class TestSuite(model.TestSuite[Keyword, TestCase], StatusMixin):
896
988
  """String representation of the :attr:`statistics`."""
897
989
  return self.statistics.message
898
990
 
899
- @property
900
- def elapsedtime(self) -> int:
901
- """Total execution time in milliseconds."""
902
- if self.starttime and self.endtime:
903
- return get_elapsed_time(self.starttime, self.endtime)
904
- return sum(child.elapsedtime for child in
905
- chain(self.suites, self.tests, (self.setup, self.teardown)))
906
-
907
991
  @setter
908
992
  def suites(self, suites: 'Sequence[TestSuite|DataDict]') -> TestSuites['TestSuite']:
909
993
  return TestSuites['TestSuite'](self.__class__, self, suites)
@@ -911,13 +995,13 @@ class TestSuite(model.TestSuite[Keyword, TestCase], StatusMixin):
911
995
  def remove_keywords(self, how: str):
912
996
  """Remove keywords based on the given condition.
913
997
 
914
- :param how: What approach to use when removing keywords. Either
998
+ :param how: Which approach to use when removing keywords. Either
915
999
  ``ALL``, ``PASSED``, ``FOR``, ``WUKS``, or ``NAME:<pattern>``.
916
1000
 
917
1001
  For more information about the possible values see the documentation
918
1002
  of the ``--removekeywords`` command line option.
919
1003
  """
920
- self.visit(KeywordRemover(how))
1004
+ self.visit(KeywordRemover.from_config(how))
921
1005
 
922
1006
  def filter_messages(self, log_level: str = 'TRACE'):
923
1007
  """Remove log messages below the specified ``log_level``."""