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
@@ -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,22 +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
821
+ # TODO: Change Return to mean ReturnStatement in RF 8.0.
822
+ # - Rename ReturnStatement to Return
825
823
  # - Add backwards compatible ReturnStatement alias
824
+ # - Consider keeping ReturnSetting for backwards compatibility. It could just be `None`.
826
825
  # - Change Token.RETURN to mean Token.RETURN_STATEMENT
827
826
  # - Update also ModelVisitor
828
827
  @Statement.register
829
828
  class Return(MultiValue):
830
829
  """Represents the deprecated ``[Return]`` setting.
831
830
 
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.
831
+ The ``[Return]`` setting is deprecated and will be removed in Robot Framework 8.0.
832
+ At the same time the :class:`ReturnStatement` class will be renamed to ``Return``.
838
833
  """
839
834
  type = Token.RETURN
840
835
 
@@ -908,15 +903,23 @@ class TemplateArguments(Statement):
908
903
  @Statement.register
909
904
  class ForHeader(Statement):
910
905
  type = Token.FOR
906
+ options = {
907
+ 'start': None,
908
+ 'mode': ('STRICT', 'SHORTEST', 'LONGEST'),
909
+ 'fill': None
910
+ }
911
911
 
912
912
  @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':
913
+ def from_params(cls, assign: 'Sequence[str]',
914
+ values: 'Sequence[str]',
915
+ flavor: Literal['IN', 'IN RANGE', 'IN ENUMERATE', 'IN ZIP'] = 'IN',
916
+ indent: str = FOUR_SPACES,
917
+ separator: str = FOUR_SPACES,
918
+ eol: str = EOL) -> 'ForHeader':
916
919
  tokens = [Token(Token.SEPARATOR, indent),
917
920
  Token(Token.FOR),
918
921
  Token(Token.SEPARATOR, separator)]
919
- for variable in variables:
922
+ for variable in assign:
920
923
  tokens.extend([Token(Token.VARIABLE, variable),
921
924
  Token(Token.SEPARATOR, separator)])
922
925
  tokens.append(Token(Token.FOR_SEPARATOR, flavor))
@@ -927,9 +930,15 @@ class ForHeader(Statement):
927
930
  return cls(tokens)
928
931
 
929
932
  @property
930
- def variables(self) -> 'tuple[str, ...]':
933
+ def assign(self) -> 'tuple[str, ...]':
931
934
  return self.get_values(Token.VARIABLE)
932
935
 
936
+ @property
937
+ def variables(self) -> 'tuple[str, ...]': # TODO: Remove in RF 8.0.
938
+ warnings.warn("'ForHeader.variables' is deprecated and will be removed in "
939
+ "Robot Framework 8.0. Use 'ForHeader.assign' instead.")
940
+ return self.assign
941
+
933
942
  @property
934
943
  def values(self) -> 'tuple[str, ...]':
935
944
  return self.get_values(Token.ARGUMENT)
@@ -952,17 +961,17 @@ class ForHeader(Statement):
952
961
  return self.get_option('fill') if self.flavor == 'IN ZIP' else None
953
962
 
954
963
  def validate(self, ctx: 'ValidationContext'):
955
- self._validate_options()
956
- if not self.variables:
964
+ if not self.assign:
957
965
  self._add_error('no loop variables')
958
966
  if not self.flavor:
959
967
  self._add_error("no 'IN' or other valid separator")
960
968
  else:
961
- for var in self.variables:
969
+ for var in self.assign:
962
970
  if not is_scalar_assign(var):
963
971
  self._add_error(f"invalid loop variable '{var}'")
964
972
  if not self.values:
965
973
  self._add_error('no loop values')
974
+ self._validate_options()
966
975
 
967
976
  def _add_error(self, error: str):
968
977
  self.errors += (f'FOR loop has {error}.',)
@@ -1084,10 +1093,13 @@ class TryHeader(NoArgumentHeader):
1084
1093
  @Statement.register
1085
1094
  class ExceptHeader(Statement):
1086
1095
  type = Token.EXCEPT
1096
+ options = {
1097
+ 'type': ('GLOB', 'REGEXP', 'START', 'LITERAL')
1098
+ }
1087
1099
 
1088
1100
  @classmethod
1089
1101
  def from_params(cls, patterns: 'Sequence[str]' = (), type: 'str|None' = None,
1090
- variable: 'str|None' = None, indent: str = FOUR_SPACES,
1102
+ assign: 'str|None' = None, indent: str = FOUR_SPACES,
1091
1103
  separator: str = FOUR_SPACES, eol: str = EOL) -> 'ExceptHeader':
1092
1104
  tokens = [Token(Token.SEPARATOR, indent),
1093
1105
  Token(Token.EXCEPT)]
@@ -1097,11 +1109,11 @@ class ExceptHeader(Statement):
1097
1109
  if type:
1098
1110
  tokens.extend([Token(Token.SEPARATOR, separator),
1099
1111
  Token(Token.OPTION, f'type={type}')])
1100
- if variable:
1112
+ if assign:
1101
1113
  tokens.extend([Token(Token.SEPARATOR, separator),
1102
1114
  Token(Token.AS),
1103
1115
  Token(Token.SEPARATOR, separator),
1104
- Token(Token.VARIABLE, variable)])
1116
+ Token(Token.VARIABLE, assign)])
1105
1117
  tokens.append(Token(Token.EOL, eol))
1106
1118
  return cls(tokens)
1107
1119
 
@@ -1114,20 +1126,26 @@ class ExceptHeader(Statement):
1114
1126
  return self.get_option('type')
1115
1127
 
1116
1128
  @property
1117
- def variable(self) -> 'str|None':
1129
+ def assign(self) -> 'str|None':
1118
1130
  return self.get_value(Token.VARIABLE)
1119
1131
 
1132
+ @property
1133
+ def variable(self) -> 'str|None': # TODO: Remove in RF 8.0.
1134
+ warnings.warn("'ExceptHeader.variable' is deprecated and will be removed in "
1135
+ "Robot Framework 8.0. Use 'ExceptHeader.assigns' instead.")
1136
+ return self.assign
1137
+
1120
1138
  def validate(self, ctx: 'ValidationContext'):
1121
- self._validate_options()
1122
1139
  as_token = self.get_token(Token.AS)
1123
1140
  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.",)
1141
+ assign = self.get_tokens(Token.VARIABLE)
1142
+ if not assign:
1143
+ self.errors += ("EXCEPT AS requires a value.",)
1144
+ elif len(assign) > 1:
1145
+ self.errors += ("EXCEPT AS accepts only one value.",)
1146
+ elif not is_scalar_assign(assign[0].value):
1147
+ self.errors += (f"EXCEPT AS variable '{assign[0].value}' is invalid.",)
1148
+ self._validate_options()
1131
1149
 
1132
1150
 
1133
1151
  @Statement.register
@@ -1143,6 +1161,11 @@ class End(NoArgumentHeader):
1143
1161
  @Statement.register
1144
1162
  class WhileHeader(Statement):
1145
1163
  type = Token.WHILE
1164
+ options = {
1165
+ 'limit': None,
1166
+ 'on_limit': ('PASS', 'FAIL'),
1167
+ 'on_limit_message': None
1168
+ }
1146
1169
 
1147
1170
  @classmethod
1148
1171
  def from_params(cls, condition: str, limit: 'str|None' = None,
@@ -1154,13 +1177,13 @@ class WhileHeader(Statement):
1154
1177
  Token(Token.SEPARATOR, separator),
1155
1178
  Token(Token.ARGUMENT, condition)]
1156
1179
  if limit:
1157
- tokens.extend([Token(Token.SEPARATOR, indent),
1180
+ tokens.extend([Token(Token.SEPARATOR, separator),
1158
1181
  Token(Token.OPTION, f'limit={limit}')])
1159
1182
  if on_limit:
1160
- tokens.extend([Token(Token.SEPARATOR, indent),
1183
+ tokens.extend([Token(Token.SEPARATOR, separator),
1161
1184
  Token(Token.OPTION, f'on_limit={on_limit}')])
1162
1185
  if on_limit_message:
1163
- tokens.extend([Token(Token.SEPARATOR, indent),
1186
+ tokens.extend([Token(Token.SEPARATOR, separator),
1164
1187
  Token(Token.OPTION, f'on_limit_message={on_limit_message}')])
1165
1188
  tokens.append(Token(Token.EOL, eol))
1166
1189
  return cls(tokens)
@@ -1182,26 +1205,76 @@ class WhileHeader(Statement):
1182
1205
  return self.get_option('on_limit_message')
1183
1206
 
1184
1207
  def validate(self, ctx: 'ValidationContext'):
1185
- conditions = self.get_tokens(Token.ARGUMENT)
1208
+ conditions = self.get_values(Token.ARGUMENT)
1186
1209
  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)}')
1210
+ self.errors += (f"WHILE accepts only one condition, got {len(conditions)} "
1211
+ f"conditions {seq2str(conditions)}.",)
1189
1212
  if self.on_limit and not self.limit:
1190
- self._add_error("'on_limit' option cannot be used without 'limit'")
1213
+ self.errors += ("WHILE option 'on_limit' cannot be used without 'limit'.",)
1191
1214
  self._validate_options()
1192
1215
 
1193
- def _add_error(self, error: str):
1194
- self.errors += (f'WHILE loop {error}.',)
1195
-
1196
1216
 
1197
1217
  @Statement.register
1198
- class ReturnStatement(Statement):
1199
- type = Token.RETURN_STATEMENT
1218
+ class Var(Statement):
1219
+ type = Token.VAR
1220
+ options = {
1221
+ 'scope': ('GLOBAL', 'SUITE', 'TEST', 'TASK', 'LOCAL'),
1222
+ 'separator': None
1223
+ }
1224
+
1225
+ @classmethod
1226
+ def from_params(cls, name: str,
1227
+ value: 'str|Sequence[str]',
1228
+ scope: 'str|None' = None,
1229
+ value_separator: 'str|None' = None,
1230
+ indent: str = FOUR_SPACES,
1231
+ separator: str = FOUR_SPACES,
1232
+ eol: str = EOL) -> 'Var':
1233
+ tokens = [Token(Token.SEPARATOR, indent),
1234
+ Token(Token.VAR),
1235
+ Token(Token.SEPARATOR, separator),
1236
+ Token(Token.VARIABLE, name)]
1237
+ values = [value] if isinstance(value, str) else value
1238
+ for value in values:
1239
+ tokens.extend([Token(Token.SEPARATOR, separator),
1240
+ Token(Token.ARGUMENT, value)])
1241
+ if scope:
1242
+ tokens.extend([Token(Token.SEPARATOR, separator),
1243
+ Token(Token.OPTION, f'scope={scope}')])
1244
+ if value_separator:
1245
+ tokens.extend([Token(Token.SEPARATOR, separator),
1246
+ Token(Token.OPTION, f'separator={value_separator}')])
1247
+ tokens.append(Token(Token.EOL, eol))
1248
+ return cls(tokens)
1200
1249
 
1201
1250
  @property
1202
- def values(self):
1251
+ def name(self) -> str:
1252
+ name = self.get_value(Token.VARIABLE, '')
1253
+ if name.endswith('='):
1254
+ return name[:-1].rstrip()
1255
+ return name
1256
+
1257
+ @property
1258
+ def value(self) -> 'tuple[str, ...]':
1203
1259
  return self.get_values(Token.ARGUMENT)
1204
1260
 
1261
+ @property
1262
+ def scope(self) -> 'str|None':
1263
+ return self.get_option('scope')
1264
+
1265
+ @property
1266
+ def separator(self) -> 'str|None':
1267
+ return self.get_option('separator')
1268
+
1269
+ def validate(self, ctx: 'ValidationContext'):
1270
+ VariableValidator().validate(self)
1271
+ self._validate_options()
1272
+
1273
+
1274
+ @Statement.register
1275
+ class ReturnStatement(Statement):
1276
+ type = Token.RETURN_STATEMENT
1277
+
1205
1278
  @classmethod
1206
1279
  def from_params(cls, values: 'Sequence[str]' = (), indent: str = FOUR_SPACES,
1207
1280
  separator: str = FOUR_SPACES, eol: str = EOL) -> 'ReturnStatement':
@@ -1213,6 +1286,10 @@ class ReturnStatement(Statement):
1213
1286
  tokens.append(Token(Token.EOL, eol))
1214
1287
  return cls(tokens)
1215
1288
 
1289
+ @property
1290
+ def values(self) -> 'tuple[str, ...]':
1291
+ return self.get_values(Token.ARGUMENT)
1292
+
1216
1293
  def validate(self, ctx: 'ValidationContext'):
1217
1294
  if not ctx.in_keyword:
1218
1295
  self.errors += ('RETURN can only be used inside a user keyword.',)
@@ -1310,3 +1387,26 @@ class EmptyLine(Statement):
1310
1387
  @classmethod
1311
1388
  def from_params(cls, eol: str = EOL):
1312
1389
  return cls([Token(Token.EOL, eol)])
1390
+
1391
+
1392
+ class VariableValidator:
1393
+
1394
+ def validate(self, statement: Statement):
1395
+ name = statement.get_value(Token.VARIABLE, '')
1396
+ match = search_variable(name, ignore_errors=True)
1397
+ if not match.is_assign(allow_assign_mark=True, allow_nested=True):
1398
+ statement.errors += (f"Invalid variable name '{name}'.",)
1399
+ if match.identifier == '&':
1400
+ self._validate_dict_items(statement)
1401
+
1402
+ def _validate_dict_items(self, statement: Statement):
1403
+ for item in statement.get_values(Token.ARGUMENT):
1404
+ if not self._is_valid_dict_item(item):
1405
+ statement.errors += (
1406
+ f"Invalid dictionary variable item '{item}'. Items must use "
1407
+ f"'name=value' syntax or be dictionary variables themselves.",
1408
+ )
1409
+
1410
+ def _is_valid_dict_item(self, item: str) -> bool:
1411
+ name, value = split_from_equals(item)
1412
+ return value is not None or is_dict_variable(item)
@@ -0,0 +1,102 @@
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._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 _compatibility(cls, method_name):
59
+ # visit_ForceTags is supported for backwards compatibility.
60
+ # visit_ReturnSetting is supported for forward compatibility.
61
+ name = {'visit_TestTags': 'visit_ForceTags',
62
+ 'visit_Return': 'visit_ReturnSetting'}[method_name]
63
+ return getattr(cls, name, None)
64
+
65
+ def generic_visit(self, node: Node) -> 'None|Node|list[Node]':
66
+ raise NotImplementedError
67
+
68
+
69
+ class ModelVisitor(NodeVisitor, VisitorFinder):
70
+ """NodeVisitor that supports matching nodes based on their base classes.
71
+
72
+ The biggest difference compared to the standard `ast.NodeVisitor
73
+ <https://docs.python.org/library/ast.html#ast.NodeVisitor>`__,
74
+ is that this class allows creating ``visit_ClassName`` methods so that
75
+ the ``ClassName`` is one of the base classes of the node. For example,
76
+ the following visitor method matches all node classes that extend
77
+ ``Statement``::
78
+
79
+ def visit_Statement(self, node):
80
+ ...
81
+
82
+ Another difference is that visitor methods are cached for performance
83
+ reasons. This means that dynamically adding ``visit_Something`` methods
84
+ does not work.
85
+ """
86
+
87
+ def visit(self, node: Node) -> None:
88
+ visitor_method = self._find_visitor(type(node))
89
+ visitor_method(self, node)
90
+
91
+
92
+ class ModelTransformer(NodeTransformer, VisitorFinder):
93
+ """NodeTransformer that supports matching nodes based on their base classes.
94
+
95
+ See :class:`ModelVisitor` for explanation how this is different compared
96
+ to the standard `ast.NodeTransformer
97
+ <https://docs.python.org/library/ast.html#ast.NodeTransformer>`__.
98
+ """
99
+
100
+ def visit(self, node: Node) -> 'None|Node|list[Node]':
101
+ visitor_method = self._find_visitor(type(node))
102
+ return visitor_method(self, node)
@@ -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