robotframework 6.1.1__zip → 7.0__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 (307) hide show
  1. {robotframework-6.1.1 → robotframework-7.0}/INSTALL.rst +25 -25
  2. {robotframework-6.1.1 → robotframework-7.0}/PKG-INFO +6 -8
  3. {robotframework-6.1.1 → robotframework-7.0}/README.rst +3 -2
  4. {robotframework-6.1.1 → robotframework-7.0}/setup.py +3 -6
  5. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/__init__.py +4 -1
  6. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/deco.py +60 -14
  7. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/exceptions.py +6 -6
  8. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/interfaces.py +402 -67
  9. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/logger.py +27 -20
  10. {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/parsing.py +4 -2
  11. robotframework-7.0/src/robot/api/py.typed +0 -0
  12. {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/gatherfailed.py +2 -2
  13. {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/languages.py +0 -9
  14. {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/settings.py +21 -14
  15. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/storage.js +11 -6
  16. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/htmlfilewriter.py +1 -1
  17. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.css +10 -2
  18. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.html +10 -0
  19. robotframework-7.0/src/robot/htmldata/rebot/common.css +362 -0
  20. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/doc_formatting.css +13 -7
  21. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.css +51 -10
  22. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.html +14 -23
  23. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/model.js +2 -4
  24. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/report.css +83 -19
  25. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/report.html +22 -7
  26. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/testdata.js +10 -3
  27. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/view.js +84 -0
  28. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/template.py +3 -3
  29. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/builder.py +0 -8
  30. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/datatypes.py +9 -10
  31. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/htmlutils.py +4 -7
  32. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/jsonbuilder.py +38 -20
  33. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/model.py +21 -28
  34. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/robotbuilder.py +50 -31
  35. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/standardtypes.py +9 -1
  36. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/xmlbuilder.py +35 -20
  37. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/xmlwriter.py +18 -38
  38. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/BuiltIn.py +255 -205
  39. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Collections.py +384 -240
  40. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/DateTime.py +73 -60
  41. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/OperatingSystem.py +6 -5
  42. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Process.py +26 -27
  43. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Remote.py +40 -36
  44. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/String.py +66 -76
  45. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/XML.py +66 -59
  46. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/__init__.py +2 -2
  47. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/__init__.py +5 -5
  48. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/body.py +44 -13
  49. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/configurer.py +15 -11
  50. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/control.py +226 -84
  51. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/filter.py +31 -25
  52. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/itemlist.py +9 -8
  53. robotframework-7.0/src/robot/model/keyword.py +77 -0
  54. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/message.py +19 -10
  55. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/modelobject.py +25 -7
  56. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/namepatterns.py +3 -25
  57. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/stats.py +9 -15
  58. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tags.py +1 -1
  59. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/testcase.py +15 -27
  60. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/testsuite.py +17 -26
  61. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/visitor.py +35 -8
  62. robotframework-7.0/src/robot/output/console/dotted.py +90 -0
  63. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/quiet.py +3 -2
  64. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/verbose.py +61 -61
  65. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/debugfile.py +39 -24
  66. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/filelogger.py +18 -15
  67. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/librarylogger.py +3 -2
  68. robotframework-7.0/src/robot/output/listeners.py +753 -0
  69. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/logger.py +216 -80
  70. robotframework-7.0/src/robot/output/loggerapi.py +215 -0
  71. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/loggerhelper.py +23 -56
  72. robotframework-7.0/src/robot/output/output.py +185 -0
  73. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/stdoutlogsplitter.py +8 -5
  74. robotframework-7.0/src/robot/output/xmllogger.py +459 -0
  75. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/blocklexers.py +17 -13
  76. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/context.py +12 -2
  77. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/lexer.py +1 -1
  78. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/settings.py +6 -3
  79. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/statementlexers.py +39 -10
  80. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/tokens.py +27 -29
  81. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/blocks.py +19 -6
  82. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/statements.py +193 -94
  83. robotframework-7.0/src/robot/parsing/model/visitor.py +100 -0
  84. {robotframework-6.1.1 → robotframework-7.0}/src/robot/rebot.py +2 -0
  85. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/expandkeywordmatcher.py +1 -1
  86. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsbuildingcontext.py +8 -6
  87. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsmodelbuilders.py +88 -61
  88. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/logreportwriters.py +16 -10
  89. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/outputwriter.py +18 -2
  90. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/resultwriter.py +4 -4
  91. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/stringcache.py +3 -3
  92. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/xunitwriter.py +15 -21
  93. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/__init__.py +3 -2
  94. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/configurer.py +12 -9
  95. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/executionresult.py +56 -8
  96. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/flattenkeywordmatcher.py +48 -9
  97. robotframework-7.0/src/robot/result/keywordremover.py +207 -0
  98. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/merger.py +1 -1
  99. robotframework-7.0/src/robot/result/model.py +1185 -0
  100. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/modeldeprecation.py +9 -3
  101. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/resultbuilder.py +46 -36
  102. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/xmlelementhandlers.py +83 -43
  103. {robotframework-6.1.1 → robotframework-7.0}/src/robot/run.py +2 -0
  104. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/__init__.py +14 -4
  105. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/__init__.py +2 -1
  106. robotframework-7.0/src/robot/running/arguments/argumentconverter.py +100 -0
  107. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentmapper.py +26 -24
  108. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentparser.py +82 -60
  109. robotframework-7.0/src/robot/running/arguments/argumentresolver.py +158 -0
  110. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentspec.py +83 -116
  111. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentvalidator.py +33 -27
  112. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/customconverters.py +15 -12
  113. robotframework-7.0/src/robot/running/arguments/embedded.py +145 -0
  114. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/typeconverters.py +233 -213
  115. robotframework-7.0/src/robot/running/arguments/typeinfo.py +317 -0
  116. robotframework-7.0/src/robot/running/arguments/typeinfoparser.py +219 -0
  117. robotframework-7.0/src/robot/running/arguments/typevalidator.py +60 -0
  118. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/bodyrunner.py +147 -129
  119. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/builders.py +2 -1
  120. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/parsers.py +10 -11
  121. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/settings.py +9 -17
  122. robotframework-7.0/src/robot/running/builder/transformers.py +535 -0
  123. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/context.py +113 -31
  124. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/dynamicmethods.py +62 -34
  125. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/importer.py +27 -49
  126. robotframework-7.0/src/robot/running/invalidkeyword.py +67 -0
  127. robotframework-7.0/src/robot/running/keywordfinder.py +91 -0
  128. robotframework-7.0/src/robot/running/keywordimplementation.py +164 -0
  129. robotframework-7.0/src/robot/running/librarykeyword.py +392 -0
  130. robotframework-7.0/src/robot/running/librarykeywordrunner.py +250 -0
  131. robotframework-7.0/src/robot/running/libraryscopes.py +115 -0
  132. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/model.py +195 -377
  133. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/namespace.py +124 -137
  134. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/outputcapture.py +20 -12
  135. robotframework-7.0/src/robot/running/resourcemodel.py +448 -0
  136. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/statusreporter.py +16 -13
  137. robotframework-7.0/src/robot/running/suiterunner.py +265 -0
  138. robotframework-7.0/src/robot/running/testlibraries.py +500 -0
  139. robotframework-7.0/src/robot/running/userkeywordrunner.py +260 -0
  140. {robotframework-6.1.1 → robotframework-7.0}/src/robot/testdoc.py +18 -13
  141. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/__init__.py +53 -35
  142. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/connectioncache.py +64 -59
  143. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/dotdict.py +3 -0
  144. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/encodingsniffer.py +1 -1
  145. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/escaping.py +19 -19
  146. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/importer.py +2 -2
  147. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/markupwriters.py +23 -15
  148. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/misc.py +1 -2
  149. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/normalizing.py +9 -24
  150. robotframework-7.0/src/robot/utils/notset.py +33 -0
  151. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/platform.py +15 -5
  152. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotio.py +9 -9
  153. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotpath.py +1 -0
  154. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robottime.py +122 -90
  155. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robottypes.py +21 -31
  156. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/setter.py +0 -5
  157. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/text.py +7 -4
  158. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/unic.py +2 -2
  159. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/__init__.py +2 -2
  160. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/assigner.py +17 -19
  161. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/evaluation.py +20 -17
  162. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/filesetter.py +80 -80
  163. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/replacer.py +33 -36
  164. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/scopes.py +17 -12
  165. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/search.py +66 -41
  166. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/store.py +14 -16
  167. robotframework-7.0/src/robot/variables/tablesetter.py +164 -0
  168. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/variables.py +1 -1
  169. {robotframework-6.1.1 → robotframework-7.0}/src/robot/version.py +1 -1
  170. {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/PKG-INFO +6 -8
  171. {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/SOURCES.txt +10 -8
  172. {robotframework-6.1.1 → robotframework-7.0}/tasks.py +6 -6
  173. robotframework-6.1.1/src/robot/htmldata/rebot/common.css +0 -239
  174. robotframework-6.1.1/src/robot/libraries/Reserved.py +0 -48
  175. robotframework-6.1.1/src/robot/model/keyword.py +0 -173
  176. robotframework-6.1.1/src/robot/output/console/dotted.py +0 -90
  177. robotframework-6.1.1/src/robot/output/listenerarguments.py +0 -165
  178. robotframework-6.1.1/src/robot/output/listenermethods.py +0 -113
  179. robotframework-6.1.1/src/robot/output/listeners.py +0 -174
  180. robotframework-6.1.1/src/robot/output/output.py +0 -95
  181. robotframework-6.1.1/src/robot/output/xmllogger.py +0 -354
  182. robotframework-6.1.1/src/robot/parsing/model/visitor.py +0 -67
  183. robotframework-6.1.1/src/robot/result/keywordremover.py +0 -183
  184. robotframework-6.1.1/src/robot/result/model.py +0 -957
  185. robotframework-6.1.1/src/robot/running/arguments/argumentconverter.py +0 -79
  186. robotframework-6.1.1/src/robot/running/arguments/argumentresolver.py +0 -131
  187. robotframework-6.1.1/src/robot/running/arguments/embedded.py +0 -146
  188. robotframework-6.1.1/src/robot/running/arguments/typevalidator.py +0 -56
  189. robotframework-6.1.1/src/robot/running/builder/transformers.py +0 -642
  190. robotframework-6.1.1/src/robot/running/handlers.py +0 -321
  191. robotframework-6.1.1/src/robot/running/handlerstore.py +0 -66
  192. robotframework-6.1.1/src/robot/running/librarykeywordrunner.py +0 -238
  193. robotframework-6.1.1/src/robot/running/libraryscopes.py +0 -97
  194. robotframework-6.1.1/src/robot/running/modelcombiner.py +0 -32
  195. robotframework-6.1.1/src/robot/running/suiterunner.py +0 -248
  196. robotframework-6.1.1/src/robot/running/testlibraries.py +0 -423
  197. robotframework-6.1.1/src/robot/running/usererrorhandler.py +0 -75
  198. robotframework-6.1.1/src/robot/running/userkeyword.py +0 -111
  199. robotframework-6.1.1/src/robot/running/userkeywordrunner.py +0 -274
  200. robotframework-6.1.1/src/robot/variables/tablesetter.py +0 -156
  201. {robotframework-6.1.1 → robotframework-7.0}/AUTHORS.rst +0 -0
  202. {robotframework-6.1.1 → robotframework-7.0}/BUILD.rst +0 -0
  203. {robotframework-6.1.1 → robotframework-7.0}/CONTRIBUTING.rst +0 -0
  204. {robotframework-6.1.1 → robotframework-7.0}/COPYRIGHT.txt +0 -0
  205. {robotframework-6.1.1 → robotframework-7.0}/LICENSE.txt +0 -0
  206. {robotframework-6.1.1 → robotframework-7.0}/MANIFEST.in +0 -0
  207. {robotframework-6.1.1 → robotframework-7.0}/setup.cfg +0 -0
  208. {robotframework-6.1.1 → robotframework-7.0}/src/robot/__init__.py +0 -0
  209. {robotframework-6.1.1 → robotframework-7.0}/src/robot/__main__.py +0 -0
  210. {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/__init__.py +0 -0
  211. {robotframework-6.1.1 → robotframework-7.0}/src/robot/errors.py +0 -0
  212. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/__init__.py +0 -0
  213. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/__init__.py +0 -0
  214. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/js_disabled.css +0 -0
  215. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/jsonwriter.py +0 -0
  216. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/__init__.py +0 -0
  217. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
  218. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.min.js +0 -0
  219. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
  220. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
  221. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
  222. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/__init__.py +0 -0
  223. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
  224. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/print.css +0 -0
  225. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/pygments.css +0 -0
  226. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/__init__.py +0 -0
  227. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/fileloading.js +0 -0
  228. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.js +0 -0
  229. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/print.css +0 -0
  230. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/util.js +0 -0
  231. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/__init__.py +0 -0
  232. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.css +0 -0
  233. {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.html +0 -0
  234. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdoc.py +0 -0
  235. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/__init__.py +0 -0
  236. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/consoleviewer.py +0 -0
  237. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/htmlwriter.py +0 -0
  238. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/jsonwriter.py +0 -0
  239. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/output.py +0 -0
  240. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/writer.py +0 -0
  241. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Dialogs.py +0 -0
  242. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Easter.py +0 -0
  243. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Screenshot.py +0 -0
  244. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Telnet.py +0 -0
  245. {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/dialogs_py.py +0 -0
  246. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/fixture.py +0 -0
  247. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/metadata.py +0 -0
  248. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/modifier.py +0 -0
  249. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/statistics.py +0 -0
  250. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/suitestatistics.py +0 -0
  251. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tagsetter.py +0 -0
  252. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tagstatistics.py +0 -0
  253. {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/totalstatistics.py +0 -0
  254. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/__init__.py +0 -0
  255. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/__init__.py +0 -0
  256. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/highlighting.py +0 -0
  257. {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/pyloggingconf.py +0 -0
  258. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/__init__.py +0 -0
  259. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/__init__.py +0 -0
  260. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/tokenizer.py +0 -0
  261. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/__init__.py +0 -0
  262. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/__init__.py +0 -0
  263. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/blockparsers.py +0 -0
  264. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/fileparser.py +0 -0
  265. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/parser.py +0 -0
  266. {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/suitestructure.py +0 -0
  267. {robotframework-6.1.1 → robotframework-7.0}/src/robot/pythonpathsetter.py +0 -0
  268. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/__init__.py +0 -0
  269. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsexecutionresult.py +0 -0
  270. {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jswriter.py +0 -0
  271. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/executionerrors.py +0 -0
  272. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/messagefilter.py +0 -0
  273. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/suiteteardownfailed.py +0 -0
  274. {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/visitor.py +0 -0
  275. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/__init__.py +0 -0
  276. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/randomizer.py +0 -0
  277. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/runkwregister.py +0 -0
  278. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/signalhandler.py +0 -0
  279. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/status.py +0 -0
  280. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/__init__.py +0 -0
  281. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/posix.py +0 -0
  282. {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/windows.py +0 -0
  283. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/application.py +0 -0
  284. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/argumentparser.py +0 -0
  285. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/asserts.py +0 -0
  286. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/charwidth.py +0 -0
  287. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/compress.py +0 -0
  288. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/encoding.py +0 -0
  289. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/error.py +0 -0
  290. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/etreewrapper.py +0 -0
  291. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/filereader.py +0 -0
  292. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/frange.py +0 -0
  293. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/htmlformatters.py +0 -0
  294. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/markuputils.py +0 -0
  295. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/match.py +0 -0
  296. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/recommendations.py +0 -0
  297. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/restreader.py +0 -0
  298. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotenv.py +0 -0
  299. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotinspect.py +0 -0
  300. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/sortable.py +0 -0
  301. {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/typehints.py +0 -0
  302. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/finders.py +0 -0
  303. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/notfound.py +0 -0
  304. {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/resolvable.py +0 -0
  305. {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/dependency_links.txt +0 -0
  306. {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/entry_points.txt +0 -0
  307. {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/top_level.txt +0 -0
@@ -15,14 +15,16 @@
15
15
 
16
16
  import ast
17
17
  import re
18
+ import warnings
18
19
  from abc import ABC, abstractmethod
19
20
  from collections.abc import Iterator, Sequence
20
- from typing import cast, ClassVar, overload, TYPE_CHECKING, Type, TypeVar
21
+ from typing import cast, ClassVar, Literal, overload, TYPE_CHECKING, Type, TypeVar
21
22
 
22
23
  from robot.conf import Language
23
24
  from robot.running.arguments import UserKeywordArgumentParser
24
25
  from robot.utils import normalize_whitespace, seq2str, split_from_equals, test_or_task
25
- from robot.variables import is_scalar_assign, is_dict_variable, search_variable
26
+ from robot.variables import (contains_variable, is_scalar_assign, is_dict_variable,
27
+ search_variable)
26
28
 
27
29
  from ..lexer import Token
28
30
 
@@ -45,10 +47,13 @@ class Node(ast.AST, ABC):
45
47
 
46
48
 
47
49
  class Statement(Node, ABC):
48
- _fields = ('type', 'tokens')
50
+ _attributes = ('type', 'tokens') + Node._attributes
49
51
  type: str
50
52
  handles_types: 'ClassVar[tuple[str, ...]]' = ()
51
53
  statement_handlers: 'ClassVar[dict[str, Type[Statement]]]' = {}
54
+ # Accepted configuration options. If the value is a tuple, it lists accepted
55
+ # values. If the used value contains a variable, it cannot be validated.
56
+ options: 'dict[str, tuple|None]' = {}
52
57
 
53
58
  def __init__(self, tokens: 'Sequence[Token]', errors: 'Sequence[str]' = ()):
54
59
  self.tokens = tuple(tokens)
@@ -164,15 +169,10 @@ class Statement(Node, ABC):
164
169
 
165
170
  New in Robot Framework 6.1.
166
171
  """
167
- options = self._get_options()
168
- return ', '.join(options[name]) if name in options else default
172
+ return self._get_options().get(name, default)
169
173
 
170
- def _get_options(self) -> 'dict[str, list[str]]':
171
- options: 'dict[str, list[str]]' = {}
172
- for option in self.get_values(Token.OPTION):
173
- name, value = option.split('=', 1)
174
- options.setdefault(name, []).append(value)
175
- return options
174
+ def _get_options(self) -> 'dict[str, str]':
175
+ return dict(opt.split('=', 1) for opt in self.get_values(Token.OPTION))
176
176
 
177
177
  @property
178
178
  def lines(self) -> 'Iterator[list[Token]]':
@@ -189,10 +189,13 @@ class Statement(Node, ABC):
189
189
  pass
190
190
 
191
191
  def _validate_options(self):
192
- for name, values in self._get_options().items():
193
- if len(values) > 1:
194
- self.errors += (f"Option '{name}' allowed only once, got values "
195
- f"{seq2str(values)}.",)
192
+ for name, value in self._get_options().items():
193
+ if self.options[name] is not None:
194
+ expected = self.options[name]
195
+ if value.upper() not in expected and not contains_variable(value):
196
+ self.errors += (f"{self.type} option '{name}' does not accept "
197
+ f"value '{value}'. Valid values are "
198
+ f"{seq2str(expected)}.",)
196
199
 
197
200
  def __iter__(self) -> 'Iterator[Token]':
198
201
  return iter(self.tokens)
@@ -344,7 +347,7 @@ class LibraryImport(Statement):
344
347
  Token(Token.ARGUMENT, arg)])
345
348
  if alias is not None:
346
349
  tokens.extend([Token(Token.SEPARATOR, separator),
347
- Token(Token.WITH_NAME),
350
+ Token(Token.AS),
348
351
  Token(Token.SEPARATOR, separator),
349
352
  Token(Token.NAME, alias)])
350
353
  tokens.append(Token(Token.EOL, eol))
@@ -360,7 +363,7 @@ class LibraryImport(Statement):
360
363
 
361
364
  @property
362
365
  def alias(self) -> 'str|None':
363
- separator = self.get_token(Token.WITH_NAME)
366
+ separator = self.get_token(Token.AS)
364
367
  return self.get_tokens(Token.NAME)[-1].value if separator else None
365
368
 
366
369
 
@@ -467,13 +470,13 @@ class Metadata(DocumentationOrMetadata):
467
470
 
468
471
 
469
472
  @Statement.register
470
- class ForceTags(MultiValue):
471
- type = Token.FORCE_TAGS
473
+ class TestTags(MultiValue):
474
+ type = Token.TEST_TAGS
472
475
 
473
476
  @classmethod
474
477
  def from_params(cls, values: 'Sequence[str]', separator: str = FOUR_SPACES,
475
- eol: str = EOL) -> 'ForceTags':
476
- tokens = [Token(Token.FORCE_TAGS, 'Force Tags')]
478
+ eol: str = EOL) -> 'TestTags':
479
+ tokens = [Token(Token.TEST_TAGS, 'Test Tags')]
477
480
  for tag in values:
478
481
  tokens.extend([Token(Token.SEPARATOR, separator),
479
482
  Token(Token.ARGUMENT, tag)])
@@ -627,15 +630,24 @@ class TestTimeout(SingleValue):
627
630
  @Statement.register
628
631
  class Variable(Statement):
629
632
  type = Token.VARIABLE
633
+ options = {
634
+ 'separator': None
635
+ }
630
636
 
631
637
  @classmethod
632
- def from_params(cls, name: str, value: 'str|Sequence[str]',
633
- separator: str = FOUR_SPACES, eol: str = EOL) -> 'Variable':
638
+ def from_params(cls, name: str,
639
+ value: 'str|Sequence[str]',
640
+ value_separator: 'str|None' = None,
641
+ separator: str = FOUR_SPACES,
642
+ eol: str = EOL) -> 'Variable':
634
643
  values = [value] if isinstance(value, str) else value
635
644
  tokens = [Token(Token.VARIABLE, name)]
636
645
  for value in values:
637
646
  tokens.extend([Token(Token.SEPARATOR, separator),
638
647
  Token(Token.ARGUMENT, value)])
648
+ if value_separator is not None:
649
+ tokens.extend([Token(Token.SEPARATOR, separator),
650
+ Token(Token.OPTION, f'separator={value_separator}')])
639
651
  tokens.append(Token(Token.EOL, eol))
640
652
  return cls(tokens)
641
653
 
@@ -650,26 +662,13 @@ class Variable(Statement):
650
662
  def value(self) -> 'tuple[str, ...]':
651
663
  return self.get_values(Token.ARGUMENT)
652
664
 
653
- def validate(self, ctx: 'ValidationContext'):
654
- name = self.get_value(Token.VARIABLE)
655
- match = search_variable(name, ignore_errors=True)
656
- if not match.is_assign(allow_assign_mark=True, allow_nested=True):
657
- self.errors += (f"Invalid variable name '{name}'.",)
658
- if match.is_dict_assign(allow_assign_mark=True):
659
- self._validate_dict_items()
660
-
661
- def _validate_dict_items(self):
662
- for item in self.get_values(Token.ARGUMENT):
663
- if not self._is_valid_dict_item(item):
664
- self.errors += (
665
- f"Invalid dictionary variable item '{item}'. "
666
- f"Items must use 'name=value' syntax or be dictionary "
667
- f"variables themselves.",
668
- )
665
+ @property
666
+ def separator(self) -> 'str|None':
667
+ return self.get_option('separator')
669
668
 
670
- def _is_valid_dict_item(self, item: str) -> bool:
671
- name, value = split_from_equals(item)
672
- return value is not None or is_dict_variable(item)
669
+ def validate(self, ctx: 'ValidationContext'):
670
+ VariableValidator().validate(self)
671
+ self._validate_options()
673
672
 
674
673
 
675
674
  @Statement.register
@@ -819,28 +818,18 @@ class Arguments(MultiValue):
819
818
  self.errors = tuple(errors)
820
819
 
821
820
 
822
- # TODO: Change Return to mean ReturnStatement in RF 7.0
823
- # - Rename current Return to ReturnSetting
824
- # - Rename current ReturnStatement to Return
825
- # - Add backwards compatible ReturnStatement alias
826
- # - Change Token.RETURN to mean Token.RETURN_STATEMENT
827
- # - Update also ModelVisitor
828
821
  @Statement.register
829
- class Return(MultiValue):
822
+ class ReturnSetting(MultiValue):
830
823
  """Represents the deprecated ``[Return]`` setting.
831
824
 
832
- In addition to the ``[Return]`` setting itself, also the ``Return`` node
833
- in the parsing model is deprecated and :class:`ReturnSetting` (new in
834
- Robot Framework 6.1) should be used instead. :class:`ReturnStatement` will
835
- be renamed to ``Return`` in Robot Framework 7.0.
836
-
837
- Eventually ``[Return]`` and ``ReturnSetting`` will be removed altogether.
825
+ This class was named ``Return`` prior to Robot Framework 7.0. A forward
826
+ compatible ``ReturnSetting`` alias existed already in Robot Framework 6.1.
838
827
  """
839
828
  type = Token.RETURN
840
829
 
841
830
  @classmethod
842
831
  def from_params(cls, args: 'Sequence[str]', indent: str = FOUR_SPACES,
843
- separator: str = FOUR_SPACES, eol: str = EOL) -> 'Return':
832
+ separator: str = FOUR_SPACES, eol: str = EOL) -> 'ReturnSetting':
844
833
  tokens = [Token(Token.SEPARATOR, indent),
845
834
  Token(Token.RETURN, '[Return]')]
846
835
  for arg in args:
@@ -850,10 +839,6 @@ class Return(MultiValue):
850
839
  return cls(tokens)
851
840
 
852
841
 
853
- # Forward compatible alias for Return.
854
- ReturnSetting = Return
855
-
856
-
857
842
  @Statement.register
858
843
  class KeywordCall(Statement):
859
844
  type = Token.KEYWORD
@@ -908,15 +893,23 @@ class TemplateArguments(Statement):
908
893
  @Statement.register
909
894
  class ForHeader(Statement):
910
895
  type = Token.FOR
896
+ options = {
897
+ 'start': None,
898
+ 'mode': ('STRICT', 'SHORTEST', 'LONGEST'),
899
+ 'fill': None
900
+ }
911
901
 
912
902
  @classmethod
913
- def from_params(cls, variables: 'Sequence[str]', values: 'Sequence[str]',
914
- flavor: str = 'IN', indent: str = FOUR_SPACES,
915
- separator: str = FOUR_SPACES, eol: str = EOL) -> 'ForHeader':
903
+ def from_params(cls, assign: 'Sequence[str]',
904
+ values: 'Sequence[str]',
905
+ flavor: Literal['IN', 'IN RANGE', 'IN ENUMERATE', 'IN ZIP'] = 'IN',
906
+ indent: str = FOUR_SPACES,
907
+ separator: str = FOUR_SPACES,
908
+ eol: str = EOL) -> 'ForHeader':
916
909
  tokens = [Token(Token.SEPARATOR, indent),
917
910
  Token(Token.FOR),
918
911
  Token(Token.SEPARATOR, separator)]
919
- for variable in variables:
912
+ for variable in assign:
920
913
  tokens.extend([Token(Token.VARIABLE, variable),
921
914
  Token(Token.SEPARATOR, separator)])
922
915
  tokens.append(Token(Token.FOR_SEPARATOR, flavor))
@@ -927,9 +920,15 @@ class ForHeader(Statement):
927
920
  return cls(tokens)
928
921
 
929
922
  @property
930
- def variables(self) -> 'tuple[str, ...]':
923
+ def assign(self) -> 'tuple[str, ...]':
931
924
  return self.get_values(Token.VARIABLE)
932
925
 
926
+ @property
927
+ def variables(self) -> 'tuple[str, ...]': # TODO: Remove in RF 8.0.
928
+ warnings.warn("'ForHeader.variables' is deprecated and will be removed in "
929
+ "Robot Framework 8.0. Use 'ForHeader.assign' instead.")
930
+ return self.assign
931
+
933
932
  @property
934
933
  def values(self) -> 'tuple[str, ...]':
935
934
  return self.get_values(Token.ARGUMENT)
@@ -952,17 +951,17 @@ class ForHeader(Statement):
952
951
  return self.get_option('fill') if self.flavor == 'IN ZIP' else None
953
952
 
954
953
  def validate(self, ctx: 'ValidationContext'):
955
- self._validate_options()
956
- if not self.variables:
954
+ if not self.assign:
957
955
  self._add_error('no loop variables')
958
956
  if not self.flavor:
959
957
  self._add_error("no 'IN' or other valid separator")
960
958
  else:
961
- for var in self.variables:
959
+ for var in self.assign:
962
960
  if not is_scalar_assign(var):
963
961
  self._add_error(f"invalid loop variable '{var}'")
964
962
  if not self.values:
965
963
  self._add_error('no loop values')
964
+ self._validate_options()
966
965
 
967
966
  def _add_error(self, error: str):
968
967
  self.errors += (f'FOR loop has {error}.',)
@@ -1084,10 +1083,13 @@ class TryHeader(NoArgumentHeader):
1084
1083
  @Statement.register
1085
1084
  class ExceptHeader(Statement):
1086
1085
  type = Token.EXCEPT
1086
+ options = {
1087
+ 'type': ('GLOB', 'REGEXP', 'START', 'LITERAL')
1088
+ }
1087
1089
 
1088
1090
  @classmethod
1089
1091
  def from_params(cls, patterns: 'Sequence[str]' = (), type: 'str|None' = None,
1090
- variable: 'str|None' = None, indent: str = FOUR_SPACES,
1092
+ assign: 'str|None' = None, indent: str = FOUR_SPACES,
1091
1093
  separator: str = FOUR_SPACES, eol: str = EOL) -> 'ExceptHeader':
1092
1094
  tokens = [Token(Token.SEPARATOR, indent),
1093
1095
  Token(Token.EXCEPT)]
@@ -1097,11 +1099,11 @@ class ExceptHeader(Statement):
1097
1099
  if type:
1098
1100
  tokens.extend([Token(Token.SEPARATOR, separator),
1099
1101
  Token(Token.OPTION, f'type={type}')])
1100
- if variable:
1102
+ if assign:
1101
1103
  tokens.extend([Token(Token.SEPARATOR, separator),
1102
1104
  Token(Token.AS),
1103
1105
  Token(Token.SEPARATOR, separator),
1104
- Token(Token.VARIABLE, variable)])
1106
+ Token(Token.VARIABLE, assign)])
1105
1107
  tokens.append(Token(Token.EOL, eol))
1106
1108
  return cls(tokens)
1107
1109
 
@@ -1114,20 +1116,26 @@ class ExceptHeader(Statement):
1114
1116
  return self.get_option('type')
1115
1117
 
1116
1118
  @property
1117
- def variable(self) -> 'str|None':
1119
+ def assign(self) -> 'str|None':
1118
1120
  return self.get_value(Token.VARIABLE)
1119
1121
 
1122
+ @property
1123
+ def variable(self) -> 'str|None': # TODO: Remove in RF 8.0.
1124
+ warnings.warn("'ExceptHeader.variable' is deprecated and will be removed in "
1125
+ "Robot Framework 8.0. Use 'ExceptHeader.assigns' instead.")
1126
+ return self.assign
1127
+
1120
1128
  def validate(self, ctx: 'ValidationContext'):
1121
- self._validate_options()
1122
1129
  as_token = self.get_token(Token.AS)
1123
1130
  if as_token:
1124
- variables = self.get_tokens(Token.VARIABLE)
1125
- if not variables:
1126
- self.errors += ("EXCEPT's AS requires variable.",)
1127
- elif len(variables) > 1:
1128
- self.errors += ("EXCEPT's AS accepts only one variable.",)
1129
- elif not is_scalar_assign(variables[0].value):
1130
- self.errors += (f"EXCEPT's AS variable '{variables[0].value}' is invalid.",)
1131
+ assign = self.get_tokens(Token.VARIABLE)
1132
+ if not assign:
1133
+ self.errors += ("EXCEPT AS requires a value.",)
1134
+ elif len(assign) > 1:
1135
+ self.errors += ("EXCEPT AS accepts only one value.",)
1136
+ elif not is_scalar_assign(assign[0].value):
1137
+ self.errors += (f"EXCEPT AS variable '{assign[0].value}' is invalid.",)
1138
+ self._validate_options()
1131
1139
 
1132
1140
 
1133
1141
  @Statement.register
@@ -1143,6 +1151,11 @@ class End(NoArgumentHeader):
1143
1151
  @Statement.register
1144
1152
  class WhileHeader(Statement):
1145
1153
  type = Token.WHILE
1154
+ options = {
1155
+ 'limit': None,
1156
+ 'on_limit': ('PASS', 'FAIL'),
1157
+ 'on_limit_message': None
1158
+ }
1146
1159
 
1147
1160
  @classmethod
1148
1161
  def from_params(cls, condition: str, limit: 'str|None' = None,
@@ -1154,13 +1167,13 @@ class WhileHeader(Statement):
1154
1167
  Token(Token.SEPARATOR, separator),
1155
1168
  Token(Token.ARGUMENT, condition)]
1156
1169
  if limit:
1157
- tokens.extend([Token(Token.SEPARATOR, indent),
1170
+ tokens.extend([Token(Token.SEPARATOR, separator),
1158
1171
  Token(Token.OPTION, f'limit={limit}')])
1159
1172
  if on_limit:
1160
- tokens.extend([Token(Token.SEPARATOR, indent),
1173
+ tokens.extend([Token(Token.SEPARATOR, separator),
1161
1174
  Token(Token.OPTION, f'on_limit={on_limit}')])
1162
1175
  if on_limit_message:
1163
- tokens.extend([Token(Token.SEPARATOR, indent),
1176
+ tokens.extend([Token(Token.SEPARATOR, separator),
1164
1177
  Token(Token.OPTION, f'on_limit_message={on_limit_message}')])
1165
1178
  tokens.append(Token(Token.EOL, eol))
1166
1179
  return cls(tokens)
@@ -1182,29 +1195,84 @@ class WhileHeader(Statement):
1182
1195
  return self.get_option('on_limit_message')
1183
1196
 
1184
1197
  def validate(self, ctx: 'ValidationContext'):
1185
- conditions = self.get_tokens(Token.ARGUMENT)
1198
+ conditions = self.get_values(Token.ARGUMENT)
1186
1199
  if len(conditions) > 1:
1187
- self._add_error(f'cannot have more than one condition, got '
1188
- f'{seq2str(c.value for c in conditions)}')
1200
+ self.errors += (f"WHILE accepts only one condition, got {len(conditions)} "
1201
+ f"conditions {seq2str(conditions)}.",)
1189
1202
  if self.on_limit and not self.limit:
1190
- self._add_error("'on_limit' option cannot be used without 'limit'")
1203
+ self.errors += ("WHILE option 'on_limit' cannot be used without 'limit'.",)
1191
1204
  self._validate_options()
1192
1205
 
1193
- def _add_error(self, error: str):
1194
- self.errors += (f'WHILE loop {error}.',)
1195
-
1196
1206
 
1197
1207
  @Statement.register
1198
- class ReturnStatement(Statement):
1199
- type = Token.RETURN_STATEMENT
1208
+ class Var(Statement):
1209
+ type = Token.VAR
1210
+ options = {
1211
+ 'scope': ('GLOBAL', 'SUITE', 'TEST', 'TASK', 'LOCAL'),
1212
+ 'separator': None
1213
+ }
1214
+
1215
+ @classmethod
1216
+ def from_params(cls, name: str,
1217
+ value: 'str|Sequence[str]',
1218
+ scope: 'str|None' = None,
1219
+ value_separator: 'str|None' = None,
1220
+ indent: str = FOUR_SPACES,
1221
+ separator: str = FOUR_SPACES,
1222
+ eol: str = EOL) -> 'Var':
1223
+ tokens = [Token(Token.SEPARATOR, indent),
1224
+ Token(Token.VAR),
1225
+ Token(Token.SEPARATOR, separator),
1226
+ Token(Token.VARIABLE, name)]
1227
+ values = [value] if isinstance(value, str) else value
1228
+ for value in values:
1229
+ tokens.extend([Token(Token.SEPARATOR, separator),
1230
+ Token(Token.ARGUMENT, value)])
1231
+ if scope:
1232
+ tokens.extend([Token(Token.SEPARATOR, separator),
1233
+ Token(Token.OPTION, f'scope={scope}')])
1234
+ if value_separator:
1235
+ tokens.extend([Token(Token.SEPARATOR, separator),
1236
+ Token(Token.OPTION, f'separator={value_separator}')])
1237
+ tokens.append(Token(Token.EOL, eol))
1238
+ return cls(tokens)
1239
+
1240
+ @property
1241
+ def name(self) -> str:
1242
+ name = self.get_value(Token.VARIABLE, '')
1243
+ if name.endswith('='):
1244
+ return name[:-1].rstrip()
1245
+ return name
1200
1246
 
1201
1247
  @property
1202
- def values(self):
1248
+ def value(self) -> 'tuple[str, ...]':
1203
1249
  return self.get_values(Token.ARGUMENT)
1204
1250
 
1251
+ @property
1252
+ def scope(self) -> 'str|None':
1253
+ return self.get_option('scope')
1254
+
1255
+ @property
1256
+ def separator(self) -> 'str|None':
1257
+ return self.get_option('separator')
1258
+
1259
+ def validate(self, ctx: 'ValidationContext'):
1260
+ VariableValidator().validate(self)
1261
+ self._validate_options()
1262
+
1263
+
1264
+ @Statement.register
1265
+ class Return(Statement):
1266
+ """Represents the RETURN statement.
1267
+
1268
+ This class named ``ReturnStatement`` prior to Robot Framework 7.0.
1269
+ The old name still exists as a backwards compatible alias.
1270
+ """
1271
+ type = Token.RETURN_STATEMENT
1272
+
1205
1273
  @classmethod
1206
1274
  def from_params(cls, values: 'Sequence[str]' = (), indent: str = FOUR_SPACES,
1207
- separator: str = FOUR_SPACES, eol: str = EOL) -> 'ReturnStatement':
1275
+ separator: str = FOUR_SPACES, eol: str = EOL) -> 'Return':
1208
1276
  tokens = [Token(Token.SEPARATOR, indent),
1209
1277
  Token(Token.RETURN_STATEMENT)]
1210
1278
  for value in values:
@@ -1213,6 +1281,10 @@ class ReturnStatement(Statement):
1213
1281
  tokens.append(Token(Token.EOL, eol))
1214
1282
  return cls(tokens)
1215
1283
 
1284
+ @property
1285
+ def values(self) -> 'tuple[str, ...]':
1286
+ return self.get_values(Token.ARGUMENT)
1287
+
1216
1288
  def validate(self, ctx: 'ValidationContext'):
1217
1289
  if not ctx.in_keyword:
1218
1290
  self.errors += ('RETURN can only be used inside a user keyword.',)
@@ -1220,6 +1292,10 @@ class ReturnStatement(Statement):
1220
1292
  self.errors += ('RETURN cannot be used in FINALLY branch.',)
1221
1293
 
1222
1294
 
1295
+ # Backwards compatibility with RF < 7.
1296
+ ReturnStatement = Return
1297
+
1298
+
1223
1299
  class LoopControl(NoArgumentHeader, ABC):
1224
1300
 
1225
1301
  def validate(self, ctx: 'ValidationContext'):
@@ -1310,3 +1386,26 @@ class EmptyLine(Statement):
1310
1386
  @classmethod
1311
1387
  def from_params(cls, eol: str = EOL):
1312
1388
  return cls([Token(Token.EOL, eol)])
1389
+
1390
+
1391
+ class VariableValidator:
1392
+
1393
+ def validate(self, statement: Statement):
1394
+ name = statement.get_value(Token.VARIABLE, '')
1395
+ match = search_variable(name, ignore_errors=True)
1396
+ if not match.is_assign(allow_assign_mark=True, allow_nested=True):
1397
+ statement.errors += (f"Invalid variable name '{name}'.",)
1398
+ if match.identifier == '&':
1399
+ self._validate_dict_items(statement)
1400
+
1401
+ def _validate_dict_items(self, statement: Statement):
1402
+ for item in statement.get_values(Token.ARGUMENT):
1403
+ if not self._is_valid_dict_item(item):
1404
+ statement.errors += (
1405
+ f"Invalid dictionary variable item '{item}'. Items must use "
1406
+ f"'name=value' syntax or be dictionary variables themselves.",
1407
+ )
1408
+
1409
+ def _is_valid_dict_item(self, item: str) -> bool:
1410
+ name, value = split_from_equals(item)
1411
+ return value is not None or is_dict_variable(item)
@@ -0,0 +1,100 @@
1
+ # Copyright 2008-2015 Nokia Networks
2
+ # Copyright 2016- Robot Framework Foundation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from ast import NodeTransformer, NodeVisitor
17
+ from typing import Callable
18
+
19
+ from .statements import Node
20
+
21
+
22
+ # Unbound method and thus needs `NodeVisitor` as `self`.
23
+ VisitorMethod = Callable[[NodeVisitor, Node], 'None|Node|list[Node]']
24
+
25
+
26
+ class VisitorFinder:
27
+ __visitor_cache: 'dict[type[Node], VisitorMethod]'
28
+
29
+ def __init_subclass__(cls, **kwargs):
30
+ super().__init_subclass__(**kwargs)
31
+ cls.__visitor_cache = {}
32
+
33
+ @classmethod
34
+ def _find_visitor(cls, node_cls: 'type[Node]') -> VisitorMethod:
35
+ if node_cls not in cls.__visitor_cache:
36
+ visitor = cls._find_visitor_from_class(node_cls)
37
+ cls.__visitor_cache[node_cls] = visitor or cls.generic_visit
38
+ return cls.__visitor_cache[node_cls]
39
+
40
+ @classmethod
41
+ def _find_visitor_from_class(cls, node_cls: 'type[Node]') -> 'VisitorMethod|None':
42
+ method_name = 'visit_' + node_cls.__name__
43
+ method = getattr(cls, method_name, None)
44
+ if callable(method):
45
+ return method
46
+ if method_name in ('visit_TestTags', 'visit_Return'):
47
+ method = cls._backwards_compatibility(method_name)
48
+ if callable(method):
49
+ return method
50
+ for base in node_cls.__bases__:
51
+ if issubclass(base, Node):
52
+ method = cls._find_visitor_from_class(base)
53
+ if method:
54
+ return method
55
+ return None
56
+
57
+ @classmethod
58
+ def _backwards_compatibility(cls, method_name):
59
+ name = {'visit_TestTags': 'visit_ForceTags',
60
+ 'visit_Return': 'visit_ReturnStatement'}[method_name]
61
+ return getattr(cls, name, None)
62
+
63
+ def generic_visit(self, node: Node) -> 'None|Node|list[Node]':
64
+ raise NotImplementedError
65
+
66
+
67
+ class ModelVisitor(NodeVisitor, VisitorFinder):
68
+ """NodeVisitor that supports matching nodes based on their base classes.
69
+
70
+ The biggest difference compared to the standard `ast.NodeVisitor
71
+ <https://docs.python.org/library/ast.html#ast.NodeVisitor>`__,
72
+ is that this class allows creating ``visit_ClassName`` methods so that
73
+ the ``ClassName`` is one of the base classes of the node. For example,
74
+ the following visitor method matches all node classes that extend
75
+ ``Statement``::
76
+
77
+ def visit_Statement(self, node):
78
+ ...
79
+
80
+ Another difference is that visitor methods are cached for performance
81
+ reasons. This means that dynamically adding ``visit_Something`` methods
82
+ does not work.
83
+ """
84
+
85
+ def visit(self, node: Node) -> None:
86
+ visitor_method = self._find_visitor(type(node))
87
+ visitor_method(self, node)
88
+
89
+
90
+ class ModelTransformer(NodeTransformer, VisitorFinder):
91
+ """NodeTransformer that supports matching nodes based on their base classes.
92
+
93
+ See :class:`ModelVisitor` for explanation how this is different compared
94
+ to the standard `ast.NodeTransformer
95
+ <https://docs.python.org/library/ast.html#ast.NodeTransformer>`__.
96
+ """
97
+
98
+ def visit(self, node: Node) -> 'None|Node|list[Node]':
99
+ visitor_method = self._find_visitor(type(node))
100
+ return visitor_method(self, node)
@@ -130,6 +130,8 @@ Options
130
130
  specified. Given path, similarly as paths given to
131
131
  --log, --report and --xunit, is relative to
132
132
  --outputdir unless given as an absolute path.
133
+ --legacyoutput Create XML output file in format compatible with
134
+ Robot Framework 6.x and earlier.
133
135
  -l --log file HTML log file. Can be disabled by giving a special
134
136
  name `NONE`. Default: log.html
135
137
  Examples: `--log mylog.html`, `-l none`
@@ -33,6 +33,6 @@ class ExpandKeywordMatcher:
33
33
  self._match_tags = MultiMatcher(tags).match_any
34
34
 
35
35
  def match(self, kw: Keyword):
36
- if (self._match_name(kw.name or '')
36
+ if (self._match_name(kw.full_name or '')
37
37
  or self._match_tags(kw.tags)) and not kw.not_run:
38
38
  self.matched_ids.append(kw.id)
@@ -13,12 +13,12 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from datetime import datetime
16
17
  from contextlib import contextmanager
17
18
  from pathlib import Path
18
19
 
19
20
  from robot.output.loggerhelper import LEVELS
20
- from robot.utils import (attribute_escape, get_link_path, html_escape, safe_str,
21
- timestamp_to_secs)
21
+ from robot.utils import attribute_escape, get_link_path, html_escape, safe_str
22
22
 
23
23
  from .expandkeywordmatcher import ExpandKeywordMatcher
24
24
  from .stringcache import StringCache
@@ -48,7 +48,9 @@ class JsBuildingContext:
48
48
  return None
49
49
 
50
50
  def string(self, string, escape=True, attr=False):
51
- if escape and string:
51
+ if not string:
52
+ return self._strings.empty
53
+ if escape:
52
54
  if not isinstance(string, str):
53
55
  string = safe_str(string)
54
56
  string = (html_escape if not attr else attribute_escape)(string)
@@ -64,10 +66,10 @@ class JsBuildingContext:
64
66
  if self._log_dir and source and source.exists() else ''
65
67
  return self.string(rel_source)
66
68
 
67
- def timestamp(self, time):
68
- if not time:
69
+ def timestamp(self, ts: datetime) -> 'int|None':
70
+ if not ts:
69
71
  return None
70
- millis = int(timestamp_to_secs(time) * 1000)
72
+ millis = round(ts.timestamp() * 1000)
71
73
  if self.basemillis is None:
72
74
  self.basemillis = millis
73
75
  return millis - self.basemillis