robotframework 6.1rc1__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.1rc1 → robotframework-7.0}/INSTALL.rst +25 -25
  2. {robotframework-6.1rc1 → robotframework-7.0}/PKG-INFO +6 -8
  3. {robotframework-6.1rc1 → robotframework-7.0}/README.rst +3 -2
  4. {robotframework-6.1rc1 → robotframework-7.0}/setup.py +3 -6
  5. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/__init__.py +4 -1
  6. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/deco.py +60 -14
  7. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/exceptions.py +6 -6
  8. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/interfaces.py +403 -68
  9. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/logger.py +27 -20
  10. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/parsing.py +4 -2
  11. robotframework-7.0/src/robot/api/py.typed +0 -0
  12. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/gatherfailed.py +2 -2
  13. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/languages.py +61 -25
  14. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/settings.py +21 -14
  15. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/storage.js +11 -6
  16. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/htmlfilewriter.py +1 -1
  17. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.css +10 -2
  18. {robotframework-6.1rc1 → 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.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/doc_formatting.css +13 -7
  21. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.css +51 -10
  22. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.html +14 -23
  23. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/model.js +2 -4
  24. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.css +83 -19
  25. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.html +22 -7
  26. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/testdata.js +10 -3
  27. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/view.js +84 -0
  28. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/template.py +3 -3
  29. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/builder.py +0 -8
  30. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/datatypes.py +9 -10
  31. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlutils.py +4 -7
  32. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonbuilder.py +38 -20
  33. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/model.py +21 -28
  34. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/robotbuilder.py +50 -31
  35. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/standardtypes.py +9 -1
  36. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlbuilder.py +35 -20
  37. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlwriter.py +18 -38
  38. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/BuiltIn.py +255 -205
  39. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Collections.py +384 -240
  40. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/DateTime.py +73 -60
  41. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/OperatingSystem.py +6 -5
  42. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Process.py +26 -27
  43. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Remote.py +40 -36
  44. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/String.py +66 -76
  45. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/XML.py +66 -59
  46. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/__init__.py +2 -2
  47. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/dialogs_py.py +14 -2
  48. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/__init__.py +5 -5
  49. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/body.py +44 -13
  50. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/configurer.py +19 -15
  51. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/control.py +230 -88
  52. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/filter.py +31 -25
  53. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/itemlist.py +9 -8
  54. robotframework-7.0/src/robot/model/keyword.py +77 -0
  55. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/message.py +19 -10
  56. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modelobject.py +27 -15
  57. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modifier.py +1 -1
  58. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/namepatterns.py +3 -25
  59. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/stats.py +9 -15
  60. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tags.py +1 -1
  61. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testcase.py +15 -27
  62. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testsuite.py +44 -28
  63. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/visitor.py +35 -8
  64. robotframework-7.0/src/robot/output/console/dotted.py +90 -0
  65. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/quiet.py +3 -2
  66. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/verbose.py +61 -61
  67. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/debugfile.py +39 -24
  68. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/filelogger.py +18 -15
  69. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/librarylogger.py +3 -2
  70. robotframework-7.0/src/robot/output/listeners.py +753 -0
  71. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/logger.py +216 -80
  72. robotframework-7.0/src/robot/output/loggerapi.py +215 -0
  73. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/loggerhelper.py +23 -56
  74. robotframework-7.0/src/robot/output/output.py +185 -0
  75. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/stdoutlogsplitter.py +8 -5
  76. robotframework-7.0/src/robot/output/xmllogger.py +459 -0
  77. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/blocklexers.py +17 -13
  78. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/context.py +12 -2
  79. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/lexer.py +1 -1
  80. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/settings.py +6 -3
  81. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/statementlexers.py +39 -10
  82. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokens.py +27 -29
  83. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/blocks.py +19 -6
  84. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/statements.py +193 -94
  85. robotframework-7.0/src/robot/parsing/model/visitor.py +100 -0
  86. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/rebot.py +2 -0
  87. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/expandkeywordmatcher.py +1 -1
  88. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsbuildingcontext.py +8 -6
  89. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsmodelbuilders.py +88 -61
  90. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/logreportwriters.py +16 -10
  91. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/outputwriter.py +18 -2
  92. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/resultwriter.py +4 -4
  93. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/stringcache.py +3 -3
  94. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/xunitwriter.py +15 -21
  95. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/__init__.py +3 -2
  96. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/configurer.py +12 -9
  97. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionresult.py +56 -8
  98. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/flattenkeywordmatcher.py +48 -9
  99. robotframework-7.0/src/robot/result/keywordremover.py +207 -0
  100. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/merger.py +1 -1
  101. robotframework-7.0/src/robot/result/model.py +1185 -0
  102. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/modeldeprecation.py +9 -3
  103. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/resultbuilder.py +46 -36
  104. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/xmlelementhandlers.py +83 -43
  105. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/run.py +3 -1
  106. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/__init__.py +14 -4
  107. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/__init__.py +2 -1
  108. robotframework-7.0/src/robot/running/arguments/argumentconverter.py +100 -0
  109. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentmapper.py +26 -24
  110. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentparser.py +85 -61
  111. robotframework-7.0/src/robot/running/arguments/argumentresolver.py +158 -0
  112. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentspec.py +83 -116
  113. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentvalidator.py +33 -27
  114. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/customconverters.py +15 -12
  115. robotframework-7.0/src/robot/running/arguments/embedded.py +145 -0
  116. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/typeconverters.py +268 -220
  117. robotframework-7.0/src/robot/running/arguments/typeinfo.py +317 -0
  118. robotframework-7.0/src/robot/running/arguments/typeinfoparser.py +219 -0
  119. robotframework-7.0/src/robot/running/arguments/typevalidator.py +60 -0
  120. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/bodyrunner.py +147 -129
  121. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/builders.py +17 -26
  122. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/parsers.py +17 -11
  123. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/settings.py +9 -17
  124. robotframework-7.0/src/robot/running/builder/transformers.py +535 -0
  125. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/context.py +113 -31
  126. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/dynamicmethods.py +62 -34
  127. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/importer.py +27 -49
  128. robotframework-7.0/src/robot/running/invalidkeyword.py +67 -0
  129. robotframework-7.0/src/robot/running/keywordfinder.py +91 -0
  130. robotframework-7.0/src/robot/running/keywordimplementation.py +164 -0
  131. robotframework-7.0/src/robot/running/librarykeyword.py +392 -0
  132. robotframework-7.0/src/robot/running/librarykeywordrunner.py +250 -0
  133. robotframework-7.0/src/robot/running/libraryscopes.py +115 -0
  134. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/model.py +198 -337
  135. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/namespace.py +124 -137
  136. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/outputcapture.py +20 -12
  137. robotframework-7.0/src/robot/running/resourcemodel.py +448 -0
  138. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/statusreporter.py +16 -13
  139. robotframework-7.0/src/robot/running/suiterunner.py +265 -0
  140. robotframework-7.0/src/robot/running/testlibraries.py +500 -0
  141. robotframework-7.0/src/robot/running/userkeywordrunner.py +260 -0
  142. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/testdoc.py +18 -13
  143. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/__init__.py +53 -35
  144. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/connectioncache.py +64 -59
  145. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/dotdict.py +3 -0
  146. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encodingsniffer.py +9 -4
  147. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/escaping.py +19 -19
  148. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/importer.py +2 -2
  149. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markupwriters.py +23 -15
  150. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/misc.py +1 -2
  151. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/normalizing.py +9 -24
  152. robotframework-7.0/src/robot/utils/notset.py +33 -0
  153. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/platform.py +15 -5
  154. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotio.py +9 -9
  155. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotpath.py +1 -0
  156. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottime.py +122 -90
  157. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottypes.py +21 -31
  158. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/setter.py +0 -5
  159. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/text.py +7 -4
  160. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/unic.py +2 -2
  161. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/__init__.py +2 -2
  162. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/assigner.py +17 -19
  163. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/evaluation.py +20 -17
  164. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/filesetter.py +80 -80
  165. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/replacer.py +33 -36
  166. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/scopes.py +17 -12
  167. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/search.py +66 -41
  168. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/store.py +14 -16
  169. robotframework-7.0/src/robot/variables/tablesetter.py +164 -0
  170. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/variables.py +1 -1
  171. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/version.py +1 -1
  172. {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/PKG-INFO +6 -8
  173. {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/SOURCES.txt +10 -8
  174. {robotframework-6.1rc1 → robotframework-7.0}/tasks.py +6 -6
  175. robotframework-6.1rc1/src/robot/htmldata/rebot/common.css +0 -239
  176. robotframework-6.1rc1/src/robot/libraries/Reserved.py +0 -48
  177. robotframework-6.1rc1/src/robot/model/keyword.py +0 -173
  178. robotframework-6.1rc1/src/robot/output/console/dotted.py +0 -90
  179. robotframework-6.1rc1/src/robot/output/listenerarguments.py +0 -165
  180. robotframework-6.1rc1/src/robot/output/listenermethods.py +0 -113
  181. robotframework-6.1rc1/src/robot/output/listeners.py +0 -174
  182. robotframework-6.1rc1/src/robot/output/output.py +0 -95
  183. robotframework-6.1rc1/src/robot/output/xmllogger.py +0 -354
  184. robotframework-6.1rc1/src/robot/parsing/model/visitor.py +0 -67
  185. robotframework-6.1rc1/src/robot/result/keywordremover.py +0 -183
  186. robotframework-6.1rc1/src/robot/result/model.py +0 -957
  187. robotframework-6.1rc1/src/robot/running/arguments/argumentconverter.py +0 -79
  188. robotframework-6.1rc1/src/robot/running/arguments/argumentresolver.py +0 -131
  189. robotframework-6.1rc1/src/robot/running/arguments/embedded.py +0 -146
  190. robotframework-6.1rc1/src/robot/running/arguments/typevalidator.py +0 -56
  191. robotframework-6.1rc1/src/robot/running/builder/transformers.py +0 -642
  192. robotframework-6.1rc1/src/robot/running/handlers.py +0 -321
  193. robotframework-6.1rc1/src/robot/running/handlerstore.py +0 -66
  194. robotframework-6.1rc1/src/robot/running/librarykeywordrunner.py +0 -238
  195. robotframework-6.1rc1/src/robot/running/libraryscopes.py +0 -97
  196. robotframework-6.1rc1/src/robot/running/modelcombiner.py +0 -32
  197. robotframework-6.1rc1/src/robot/running/suiterunner.py +0 -249
  198. robotframework-6.1rc1/src/robot/running/testlibraries.py +0 -420
  199. robotframework-6.1rc1/src/robot/running/usererrorhandler.py +0 -75
  200. robotframework-6.1rc1/src/robot/running/userkeyword.py +0 -111
  201. robotframework-6.1rc1/src/robot/running/userkeywordrunner.py +0 -274
  202. robotframework-6.1rc1/src/robot/variables/tablesetter.py +0 -156
  203. {robotframework-6.1rc1 → robotframework-7.0}/AUTHORS.rst +0 -0
  204. {robotframework-6.1rc1 → robotframework-7.0}/BUILD.rst +0 -0
  205. {robotframework-6.1rc1 → robotframework-7.0}/CONTRIBUTING.rst +0 -0
  206. {robotframework-6.1rc1 → robotframework-7.0}/COPYRIGHT.txt +0 -0
  207. {robotframework-6.1rc1 → robotframework-7.0}/LICENSE.txt +0 -0
  208. {robotframework-6.1rc1 → robotframework-7.0}/MANIFEST.in +0 -0
  209. {robotframework-6.1rc1 → robotframework-7.0}/setup.cfg +0 -0
  210. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__init__.py +0 -0
  211. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__main__.py +0 -0
  212. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/__init__.py +0 -0
  213. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/errors.py +0 -0
  214. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/__init__.py +0 -0
  215. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/__init__.py +0 -0
  216. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/js_disabled.css +0 -0
  217. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/jsonwriter.py +0 -0
  218. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/__init__.py +0 -0
  219. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
  220. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.min.js +0 -0
  221. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
  222. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
  223. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
  224. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/__init__.py +0 -0
  225. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
  226. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/print.css +0 -0
  227. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/pygments.css +0 -0
  228. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/__init__.py +0 -0
  229. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/fileloading.js +0 -0
  230. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.js +0 -0
  231. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/print.css +0 -0
  232. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/util.js +0 -0
  233. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/__init__.py +0 -0
  234. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.css +0 -0
  235. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.html +0 -0
  236. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdoc.py +0 -0
  237. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/__init__.py +0 -0
  238. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/consoleviewer.py +0 -0
  239. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlwriter.py +0 -0
  240. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonwriter.py +0 -0
  241. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/output.py +0 -0
  242. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/writer.py +0 -0
  243. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Dialogs.py +0 -0
  244. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Easter.py +0 -0
  245. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Screenshot.py +0 -0
  246. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Telnet.py +0 -0
  247. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/fixture.py +0 -0
  248. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/metadata.py +0 -0
  249. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/statistics.py +0 -0
  250. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/suitestatistics.py +0 -0
  251. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagsetter.py +0 -0
  252. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagstatistics.py +0 -0
  253. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/totalstatistics.py +0 -0
  254. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/__init__.py +0 -0
  255. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/__init__.py +0 -0
  256. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/highlighting.py +0 -0
  257. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/pyloggingconf.py +0 -0
  258. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/__init__.py +0 -0
  259. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/__init__.py +0 -0
  260. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokenizer.py +0 -0
  261. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/__init__.py +0 -0
  262. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/__init__.py +0 -0
  263. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/blockparsers.py +0 -0
  264. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/fileparser.py +0 -0
  265. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/parser.py +0 -0
  266. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/suitestructure.py +0 -0
  267. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/pythonpathsetter.py +0 -0
  268. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/__init__.py +0 -0
  269. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsexecutionresult.py +0 -0
  270. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jswriter.py +0 -0
  271. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionerrors.py +0 -0
  272. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/messagefilter.py +0 -0
  273. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/suiteteardownfailed.py +0 -0
  274. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/visitor.py +0 -0
  275. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/__init__.py +0 -0
  276. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/randomizer.py +0 -0
  277. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/runkwregister.py +0 -0
  278. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/signalhandler.py +0 -0
  279. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/status.py +0 -0
  280. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/__init__.py +0 -0
  281. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/posix.py +0 -0
  282. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/windows.py +0 -0
  283. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/application.py +0 -0
  284. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/argumentparser.py +0 -0
  285. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/asserts.py +0 -0
  286. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/charwidth.py +0 -0
  287. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/compress.py +0 -0
  288. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encoding.py +0 -0
  289. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/error.py +0 -0
  290. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/etreewrapper.py +0 -0
  291. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/filereader.py +0 -0
  292. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/frange.py +0 -0
  293. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/htmlformatters.py +0 -0
  294. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markuputils.py +0 -0
  295. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/match.py +0 -0
  296. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/recommendations.py +0 -0
  297. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/restreader.py +0 -0
  298. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotenv.py +0 -0
  299. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotinspect.py +0 -0
  300. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/sortable.py +0 -0
  301. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/typehints.py +0 -0
  302. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/finders.py +0 -0
  303. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/notfound.py +0 -0
  304. {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/resolvable.py +0 -0
  305. {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/dependency_links.txt +0 -0
  306. {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/entry_points.txt +0 -0
  307. {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/top_level.txt +0 -0
@@ -17,6 +17,7 @@ import difflib
17
17
  import re
18
18
  import time
19
19
  from collections import OrderedDict
20
+ from collections.abc import Sequence
20
21
 
21
22
  from robot.api import logger, SkipExecution
22
23
  from robot.api.deco import keyword
@@ -25,7 +26,6 @@ from robot.errors import (BreakLoop, ContinueLoop, DataError, ExecutionFailed,
25
26
  ReturnFromKeyword, VariableError)
26
27
  from robot.running import Keyword, RUN_KW_REGISTER
27
28
  from robot.running.context import EXECUTION_CONTEXTS
28
- from robot.running.usererrorhandler import UserErrorHandler
29
29
  from robot.utils import (DotDict, escape, format_assign_message, get_error_message,
30
30
  get_time, html_escape, is_falsy, is_integer, is_list_like,
31
31
  is_string, is_truthy, Matcher, normalize,
@@ -36,7 +36,7 @@ from robot.utils import (DotDict, escape, format_assign_message, get_error_messa
36
36
  from robot.utils.asserts import assert_equal, assert_not_equal
37
37
  from robot.variables import (evaluate_expression, is_dict_variable,
38
38
  is_list_variable, search_variable,
39
- DictVariableTableValue, VariableTableValue)
39
+ DictVariableResolver, VariableResolver)
40
40
  from robot.version import get_version
41
41
 
42
42
 
@@ -153,8 +153,8 @@ class _Converter(_BuiltInBase):
153
153
  return int(item, self._convert_to_integer(base))
154
154
  return int(item)
155
155
  except:
156
- raise RuntimeError("'%s' cannot be converted to an integer: %s"
157
- % (orig, get_error_message()))
156
+ raise RuntimeError(f"'{orig}' cannot be converted to an integer: "
157
+ f"{get_error_message()}")
158
158
 
159
159
  def _get_base(self, item, base):
160
160
  if not is_string(item):
@@ -300,8 +300,8 @@ class _Converter(_BuiltInBase):
300
300
  try:
301
301
  return float(self._convert_to_integer(item))
302
302
  except RuntimeError:
303
- raise RuntimeError("'%s' cannot be converted to a floating "
304
- "point number: %s" % (item, error))
303
+ raise RuntimeError(f"'{item}' cannot be converted to a floating "
304
+ f"point number: {error}")
305
305
 
306
306
  def convert_to_string(self, item):
307
307
  """Converts the given item to a Unicode string.
@@ -380,12 +380,12 @@ class _Converter(_BuiltInBase):
380
380
  """
381
381
  try:
382
382
  try:
383
- ordinals = getattr(self, '_get_ordinals_from_%s' % input_type)
383
+ ordinals = getattr(self, f'_get_ordinals_from_{input_type}')
384
384
  except AttributeError:
385
- raise RuntimeError("Invalid input type '%s'." % input_type)
385
+ raise RuntimeError(f"Invalid input type '{input_type}'.")
386
386
  return bytes(bytearray(o for o in ordinals(input)))
387
387
  except:
388
- raise RuntimeError("Creating bytes failed: %s" % get_error_message())
388
+ raise RuntimeError("Creating bytes failed: " + get_error_message())
389
389
 
390
390
  def _get_ordinals_from_text(self, input):
391
391
  for char in input:
@@ -395,8 +395,7 @@ class _Converter(_BuiltInBase):
395
395
  def _test_ordinal(self, ordinal, original, type):
396
396
  if 0 <= ordinal <= 255:
397
397
  return ordinal
398
- raise RuntimeError("%s '%s' cannot be represented as a byte."
399
- % (type, original))
398
+ raise RuntimeError(f"{type} '{original}' cannot be represented as a byte.")
400
399
 
401
400
  def _get_ordinals_from_int(self, input):
402
401
  if is_string(input):
@@ -422,7 +421,7 @@ class _Converter(_BuiltInBase):
422
421
  return input
423
422
  input = ''.join(input.split())
424
423
  if len(input) % length != 0:
425
- raise RuntimeError('Expected input to be multiple of %d.' % length)
424
+ raise RuntimeError(f'Expected input to be multiple of {length}.')
426
425
  return (input[i:i+length] for i in range(0, len(input), length))
427
426
 
428
427
  def create_list(self, *items):
@@ -472,7 +471,7 @@ class _Converter(_BuiltInBase):
472
471
  """
473
472
  separate, combined = self._split_dict_items(items)
474
473
  result = DotDict(self._format_separate_dict_items(separate))
475
- combined = DictVariableTableValue(combined).resolve(self._variables)
474
+ combined = DictVariableResolver(combined).resolve(self._variables)
476
475
  result.update(combined)
477
476
  return result
478
477
 
@@ -488,8 +487,8 @@ class _Converter(_BuiltInBase):
488
487
  def _format_separate_dict_items(self, separate):
489
488
  separate = self._variables.replace_list(separate)
490
489
  if len(separate) % 2 != 0:
491
- raise DataError('Expected even number of keys and values, got %d.'
492
- % len(separate))
490
+ raise DataError(f'Expected even number of keys and values, '
491
+ f'got {len(separate)}.')
493
492
  return [separate[i:i+2] for i in range(0, len(separate), 2)]
494
493
 
495
494
 
@@ -527,7 +526,7 @@ class _Verify(_BuiltInBase):
527
526
  See `Fatal Error` if you need to stop the whole test execution.
528
527
  """
529
528
  self._set_and_remove_tags(tags)
530
- raise AssertionError(msg) if msg else AssertionError()
529
+ raise AssertionError(msg) if msg is not None else AssertionError()
531
530
 
532
531
  def fatal_error(self, msg=None):
533
532
  """Stops the whole test execution.
@@ -549,7 +548,7 @@ class _Verify(_BuiltInBase):
549
548
  and how ``msg`` can be used to override the default error message.
550
549
  """
551
550
  if self._is_true(condition):
552
- raise AssertionError(msg or "'%s' should not be true." % condition)
551
+ raise AssertionError(msg or f"'{condition}' should not be true.")
553
552
 
554
553
  def should_be_true(self, condition, msg=None):
555
554
  """Fails if the given condition is not true.
@@ -580,7 +579,7 @@ class _Verify(_BuiltInBase):
580
579
  | Should Be True | $status == 'PASS' | # Expected string must be quoted |
581
580
  """
582
581
  if not self._is_true(condition):
583
- raise AssertionError(msg or "'%s' should be true." % condition)
582
+ raise AssertionError(msg or f"'{condition}' should be true.")
584
583
 
585
584
  def should_be_equal(self, first, second, msg=None, values=True,
586
585
  ignore_case=False, formatter='str', strip_spaces=False,
@@ -627,8 +626,8 @@ class _Verify(_BuiltInBase):
627
626
  self._log_types_at_info_if_different(first, second)
628
627
  if is_string(first) and is_string(second):
629
628
  if ignore_case:
630
- first = first.lower()
631
- second = second.lower()
629
+ first = first.casefold()
630
+ second = second.casefold()
632
631
  if strip_spaces:
633
632
  first = self._strip_spaces(first, strip_spaces)
634
633
  second = self._strip_spaces(second, strip_spaces)
@@ -655,14 +654,14 @@ class _Verify(_BuiltInBase):
655
654
  second_lines = second.splitlines(True)
656
655
  if len(first_lines) < 3 or len(second_lines) < 3:
657
656
  return
658
- self.log("%s\n\n!=\n\n%s" % (first.rstrip(), second.rstrip()))
657
+ self.log(f"{first.rstrip()}\n\n!=\n\n{second.rstrip()}")
659
658
  diffs = list(difflib.unified_diff(first_lines, second_lines,
660
659
  fromfile='first', tofile='second',
661
660
  lineterm=''))
662
661
  diffs[3:] = [item[0] + formatter(item[1:]).rstrip() for item in diffs[3:]]
663
662
  prefix = 'Multiline strings are different:'
664
663
  if msg:
665
- prefix = '%s: %s' % (msg, prefix)
664
+ prefix = f'{msg}: {prefix}'
666
665
  raise AssertionError('\n'.join([prefix] + diffs))
667
666
 
668
667
  def _include_values(self, values):
@@ -709,8 +708,8 @@ class _Verify(_BuiltInBase):
709
708
  self._log_types_at_info_if_different(first, second)
710
709
  if is_string(first) and is_string(second):
711
710
  if ignore_case:
712
- first = first.lower()
713
- second = second.lower()
711
+ first = first.casefold()
712
+ second = second.casefold()
714
713
  if strip_spaces:
715
714
  first = self._strip_spaces(first, strip_spaces)
716
715
  second = self._strip_spaces(second, strip_spaces)
@@ -845,8 +844,8 @@ class _Verify(_BuiltInBase):
845
844
  first = safe_str(first)
846
845
  second = safe_str(second)
847
846
  if ignore_case:
848
- first = first.lower()
849
- second = second.lower()
847
+ first = first.casefold()
848
+ second = second.casefold()
850
849
  if strip_spaces:
851
850
  first = self._strip_spaces(first, strip_spaces)
852
851
  second = self._strip_spaces(second, strip_spaces)
@@ -886,8 +885,8 @@ class _Verify(_BuiltInBase):
886
885
  first = safe_str(first)
887
886
  second = safe_str(second)
888
887
  if ignore_case:
889
- first = first.lower()
890
- second = second.lower()
888
+ first = first.casefold()
889
+ second = second.casefold()
891
890
  if strip_spaces:
892
891
  first = self._strip_spaces(first, strip_spaces)
893
892
  second = self._strip_spaces(second, strip_spaces)
@@ -906,8 +905,8 @@ class _Verify(_BuiltInBase):
906
905
  of the ``ignore_case``, ``strip_spaces``, and ``collapse_spaces`` options.
907
906
  """
908
907
  if ignore_case:
909
- str1 = str1.lower()
910
- str2 = str2.lower()
908
+ str1 = str1.casefold()
909
+ str2 = str2.casefold()
911
910
  if strip_spaces:
912
911
  str1 = self._strip_spaces(str1, strip_spaces)
913
912
  str2 = self._strip_spaces(str2, strip_spaces)
@@ -927,8 +926,8 @@ class _Verify(_BuiltInBase):
927
926
  of the ``ignore_case``, ``strip_spaces``, and ``collapse_spaces`` options.
928
927
  """
929
928
  if ignore_case:
930
- str1 = str1.lower()
931
- str2 = str2.lower()
929
+ str1 = str1.casefold()
930
+ str2 = str2.casefold()
932
931
  if strip_spaces:
933
932
  str1 = self._strip_spaces(str1, strip_spaces)
934
933
  str2 = self._strip_spaces(str2, strip_spaces)
@@ -949,8 +948,8 @@ class _Verify(_BuiltInBase):
949
948
  of the ``ignore_case``, ``strip_spaces``, and ``collapse_spaces`` options.
950
949
  """
951
950
  if ignore_case:
952
- str1 = str1.lower()
953
- str2 = str2.lower()
951
+ str1 = str1.casefold()
952
+ str2 = str2.casefold()
954
953
  if strip_spaces:
955
954
  str1 = self._strip_spaces(str1, strip_spaces)
956
955
  str2 = self._strip_spaces(str2, strip_spaces)
@@ -970,8 +969,8 @@ class _Verify(_BuiltInBase):
970
969
  of the ``ignore_case``, ``strip_spaces``, and ``collapse_spaces`` options.
971
970
  """
972
971
  if ignore_case:
973
- str1 = str1.lower()
974
- str2 = str2.lower()
972
+ str1 = str1.casefold()
973
+ str2 = str2.casefold()
975
974
  if strip_spaces:
976
975
  str1 = self._strip_spaces(str1, strip_spaces)
977
976
  str2 = self._strip_spaces(str2, strip_spaces)
@@ -1018,11 +1017,11 @@ class _Verify(_BuiltInBase):
1018
1017
  # case-insensitive comparisons.
1019
1018
  orig_container = container
1020
1019
  if ignore_case and is_string(item):
1021
- item = item.lower()
1020
+ item = item.casefold()
1022
1021
  if is_string(container):
1023
- container = container.lower()
1022
+ container = container.casefold()
1024
1023
  elif is_list_like(container):
1025
- container = set(x.lower() if is_string(x) else x for x in container)
1024
+ container = set(x.casefold() if is_string(x) else x for x in container)
1026
1025
  if strip_spaces and is_string(item):
1027
1026
  item = self._strip_spaces(item, strip_spaces)
1028
1027
  if is_string(container):
@@ -1074,11 +1073,11 @@ class _Verify(_BuiltInBase):
1074
1073
  """
1075
1074
  orig_container = container
1076
1075
  if ignore_case and is_string(item):
1077
- item = item.lower()
1076
+ item = item.casefold()
1078
1077
  if is_string(container):
1079
- container = container.lower()
1078
+ container = container.casefold()
1080
1079
  elif is_list_like(container):
1081
- container = set(x.lower() if is_string(x) else x for x in container)
1080
+ container = set(x.casefold() if is_string(x) else x for x in container)
1082
1081
  if strip_spaces and is_string(item):
1083
1082
  item = self._strip_spaces(item, strip_spaces)
1084
1083
  if is_string(container):
@@ -1123,17 +1122,17 @@ class _Verify(_BuiltInBase):
1123
1122
  strip_spaces = configuration.pop('strip_spaces', False)
1124
1123
  collapse_spaces = is_truthy(configuration.pop('collapse_spaces', False))
1125
1124
  if configuration:
1126
- raise RuntimeError("Unsupported configuration parameter%s: %s."
1127
- % (s(configuration), seq2str(sorted(configuration))))
1125
+ raise RuntimeError(f"Unsupported configuration parameter{s(configuration)}: "
1126
+ f"{seq2str(sorted(configuration))}.")
1128
1127
  if not items:
1129
1128
  raise RuntimeError('One or more items required.')
1130
1129
  orig_container = container
1131
1130
  if ignore_case:
1132
- items = [x.lower() if is_string(x) else x for x in items]
1131
+ items = [x.casefold() if is_string(x) else x for x in items]
1133
1132
  if is_string(container):
1134
- container = container.lower()
1133
+ container = container.casefold()
1135
1134
  elif is_list_like(container):
1136
- container = set(x.lower() if is_string(x) else x for x in container)
1135
+ container = set(x.casefold() if is_string(x) else x for x in container)
1137
1136
  if strip_spaces:
1138
1137
  items = [self._strip_spaces(x, strip_spaces) for x in items]
1139
1138
  if is_string(container):
@@ -1181,17 +1180,17 @@ class _Verify(_BuiltInBase):
1181
1180
  strip_spaces = configuration.pop('strip_spaces', False)
1182
1181
  collapse_spaces = is_truthy(configuration.pop('collapse_spaces', False))
1183
1182
  if configuration:
1184
- raise RuntimeError("Unsupported configuration parameter%s: %s."
1185
- % (s(configuration), seq2str(sorted(configuration))))
1183
+ raise RuntimeError(f"Unsupported configuration parameter{s(configuration)}: "
1184
+ f"{seq2str(sorted(configuration))}.")
1186
1185
  if not items:
1187
1186
  raise RuntimeError('One or more items required.')
1188
1187
  orig_container = container
1189
1188
  if ignore_case:
1190
- items = [x.lower() if is_string(x) else x for x in items]
1189
+ items = [x.casefold() if is_string(x) else x for x in items]
1191
1190
  if is_string(container):
1192
- container = container.lower()
1191
+ container = container.casefold()
1193
1192
  elif is_list_like(container):
1194
- container = set(x.lower() if is_string(x) else x for x in container)
1193
+ container = set(x.casefold() if is_string(x) else x for x in container)
1195
1194
  if strip_spaces:
1196
1195
  items = [self._strip_spaces(x, strip_spaces) for x in items]
1197
1196
  if is_string(container):
@@ -1247,11 +1246,11 @@ class _Verify(_BuiltInBase):
1247
1246
  orig_container = container
1248
1247
  if is_string(item):
1249
1248
  if ignore_case:
1250
- item = item.lower()
1249
+ item = item.casefold()
1251
1250
  if is_string(container):
1252
- container = container.lower()
1251
+ container = container.casefold()
1253
1252
  elif is_list_like(container):
1254
- container = [x.lower() if is_string(x) else x for x in container]
1253
+ container = [x.casefold() if is_string(x) else x for x in container]
1255
1254
  if strip_spaces:
1256
1255
  item = self._strip_spaces(item, strip_spaces)
1257
1256
  if is_string(container):
@@ -1266,8 +1265,8 @@ class _Verify(_BuiltInBase):
1266
1265
  container = [self._collapse_spaces(x) for x in container]
1267
1266
  x = self.get_count(container, item)
1268
1267
  if not msg:
1269
- msg = "%r contains '%s' %d time%s, not %d time%s." \
1270
- % (orig_container, item, x, s(x), count, s(count))
1268
+ msg = (f"{orig_container!r} contains '{item}' {x} time{s(x)}, "
1269
+ f"not {count} time{s(count)}.")
1271
1270
  self.should_be_equal_as_integers(x, count, msg, values=False)
1272
1271
 
1273
1272
  def get_count(self, container, item):
@@ -1284,10 +1283,10 @@ class _Verify(_BuiltInBase):
1284
1283
  try:
1285
1284
  container = list(container)
1286
1285
  except:
1287
- raise RuntimeError("Converting '%s' to list failed: %s"
1288
- % (container, get_error_message()))
1286
+ raise RuntimeError(f"Converting '{container}' to list failed: "
1287
+ f"{get_error_message()}")
1289
1288
  count = container.count(item)
1290
- self.log('Item found from container %d time%s.' % (count, s(count)))
1289
+ self.log(f'Item found from container {count} time{s(count)}.')
1291
1290
  return count
1292
1291
 
1293
1292
  def should_not_match(self, string, pattern, msg=None, values=True,
@@ -1407,7 +1406,7 @@ class _Verify(_BuiltInBase):
1407
1406
  Empty`.
1408
1407
  """
1409
1408
  length = self._get_length(item)
1410
- self.log('Length is %d' % length)
1409
+ self.log(f'Length is {length}.')
1411
1410
  return length
1412
1411
 
1413
1412
  def _get_length(self, item):
@@ -1431,7 +1430,7 @@ class _Verify(_BuiltInBase):
1431
1430
  except RERAISED_EXCEPTIONS:
1432
1431
  raise
1433
1432
  except:
1434
- raise RuntimeError("Could not get length of '%s'." % item)
1433
+ raise RuntimeError(f"Could not get length of '{item}'.")
1435
1434
 
1436
1435
  def length_should_be(self, item, length, msg=None):
1437
1436
  """Verifies that the length of the given item is correct.
@@ -1442,8 +1441,8 @@ class _Verify(_BuiltInBase):
1442
1441
  length = self._convert_to_integer(length)
1443
1442
  actual = self.get_length(item)
1444
1443
  if actual != length:
1445
- raise AssertionError(msg or "Length of '%s' should be %d but is %d."
1446
- % (item, length, actual))
1444
+ raise AssertionError(msg or f"Length of '{item}' should be {length} "
1445
+ f"but is {actual}.")
1447
1446
 
1448
1447
  def should_be_empty(self, item, msg=None):
1449
1448
  """Verifies that the given item is empty.
@@ -1452,7 +1451,7 @@ class _Verify(_BuiltInBase):
1452
1451
  default error message can be overridden with the ``msg`` argument.
1453
1452
  """
1454
1453
  if self.get_length(item) > 0:
1455
- raise AssertionError(msg or "'%s' should be empty." % (item,))
1454
+ raise AssertionError(msg or f"'{item}' should be empty.")
1456
1455
 
1457
1456
  def should_not_be_empty(self, item, msg=None):
1458
1457
  """Verifies that the given item is not empty.
@@ -1461,18 +1460,18 @@ class _Verify(_BuiltInBase):
1461
1460
  default error message can be overridden with the ``msg`` argument.
1462
1461
  """
1463
1462
  if self.get_length(item) == 0:
1464
- raise AssertionError(msg or "'%s' should not be empty." % (item,))
1463
+ raise AssertionError(msg or f"'{item}' should not be empty.")
1465
1464
 
1466
1465
  def _get_string_msg(self, item1, item2, custom_message, include_values,
1467
1466
  delimiter, quote_item1=True, quote_item2=True):
1468
1467
  if custom_message and not self._include_values(include_values):
1469
1468
  return custom_message
1470
- item1 = "'%s'" % safe_str(item1) if quote_item1 else safe_str(item1)
1471
- item2 = "'%s'" % safe_str(item2) if quote_item2 else safe_str(item2)
1472
- default_message = '%s %s %s' % (item1, delimiter, item2)
1469
+ item1 = f"'{safe_str(item1)}'" if quote_item1 else safe_str(item1)
1470
+ item2 = f"'{safe_str(item2)}'" if quote_item2 else safe_str(item2)
1471
+ default_message = f'{item1} {delimiter} {item2}'
1473
1472
  if not custom_message:
1474
1473
  return default_message
1475
- return '%s: %s' % (custom_message, default_message)
1474
+ return f'{custom_message}: {default_message}'
1476
1475
 
1477
1476
 
1478
1477
  class _Variables(_BuiltInBase):
@@ -1533,7 +1532,7 @@ class _Variables(_BuiltInBase):
1533
1532
  def log_variables(self, level='INFO'):
1534
1533
  """Logs all variables in the current scope with given log level."""
1535
1534
  variables = self.get_variables()
1536
- for name in sorted(variables, key=lambda s: s[2:-1].lower()):
1535
+ for name in sorted(variables, key=lambda s: s[2:-1].casefold()):
1537
1536
  name, value = self._get_logged_variable(name, variables)
1538
1537
  msg = format_assign_message(name, value, cut_long=False)
1539
1538
  self.log(msg, level)
@@ -1542,12 +1541,15 @@ class _Variables(_BuiltInBase):
1542
1541
  value = variables[name]
1543
1542
  try:
1544
1543
  if name[0] == '@':
1545
- value = list(value)
1544
+ if isinstance(value, Sequence):
1545
+ value = list(value)
1546
+ else: # Don't consume iterables.
1547
+ name = '$' + name[1:]
1546
1548
  if name[0] == '&':
1547
1549
  value = OrderedDict(value)
1548
1550
  except RERAISED_EXCEPTIONS:
1549
1551
  raise
1550
- except:
1552
+ except Exception:
1551
1553
  name = '$' + name[1:]
1552
1554
  return name, value
1553
1555
 
@@ -1569,7 +1571,7 @@ class _Variables(_BuiltInBase):
1569
1571
  self._variables.replace_scalar(name)
1570
1572
  except VariableError:
1571
1573
  raise AssertionError(self._variables.replace_string(msg)
1572
- if msg else "Variable '%s' does not exist." % name)
1574
+ if msg else f"Variable '{name}' does not exist.")
1573
1575
 
1574
1576
  @run_keyword_variant(resolve=0)
1575
1577
  def variable_should_not_exist(self, name, msg=None):
@@ -1591,14 +1593,14 @@ class _Variables(_BuiltInBase):
1591
1593
  pass
1592
1594
  else:
1593
1595
  raise AssertionError(self._variables.replace_string(msg)
1594
- if msg else "Variable '%s' exists." % name)
1596
+ if msg else f"Variable '{name}' exists.")
1595
1597
 
1596
1598
  def replace_variables(self, text):
1597
1599
  """Replaces variables in the given text with their current values.
1598
1600
 
1599
1601
  If the text contains undefined variables, this keyword fails.
1600
1602
  If the given ``text`` contains only a single variable, its value is
1601
- returned as-is and it can be any object. Otherwise this keyword
1603
+ returned as-is and it can be any object. Otherwise, this keyword
1602
1604
  always returns a string.
1603
1605
 
1604
1606
  Example:
@@ -1621,16 +1623,23 @@ class _Variables(_BuiltInBase):
1621
1623
  It is recommended to use `Create List` when creating new lists.
1622
1624
 
1623
1625
  Examples:
1624
- | ${hi} = | Set Variable | Hello, world! |
1625
- | ${hi2} = | Set Variable | I said: ${hi} |
1626
- | ${var1} | ${var2} = | Set Variable | Hello | world |
1627
- | @{list} = | Set Variable | ${list with some items} |
1628
- | ${item1} | ${item2} = | Set Variable | ${list with 2 items} |
1626
+ | ${hi} = Set Variable Hello, world!
1627
+ | ${hi2} = Set Variable I said: ${hi}
1628
+ | ${var1} ${var2} = Set Variable Hello world
1629
+ | @{list} = Set Variable ${list with some items}
1630
+ | ${item1} ${item2} = Set Variable ${list with 2 items}
1629
1631
 
1630
1632
  Variables created with this keyword are available only in the
1631
1633
  scope where they are created. See `Set Global Variable`,
1632
1634
  `Set Test Variable` and `Set Suite Variable` for information on how to
1633
1635
  set variables so that they are available also in a larger scope.
1636
+
1637
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is generally
1638
+ recommended over this keyword. The basic usage is shown below and the Robot
1639
+ Framework User Guide explains the syntax in detail.
1640
+
1641
+ | VAR ${hi} Hello, world!
1642
+ | VAR ${hi2} I said: ${hi}
1634
1643
  """
1635
1644
  if len(values) == 0:
1636
1645
  return ''
@@ -1670,10 +1679,13 @@ class _Variables(_BuiltInBase):
1670
1679
  ``${name}``.
1671
1680
 
1672
1681
  See also `Set Global Variable` and `Set Test Variable`.
1682
+
1683
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is recommended
1684
+ over this keyword.
1673
1685
  """
1674
1686
  name = self._get_var_name(name)
1675
1687
  value = self._get_var_value(name, values)
1676
- self._variables.set_local_variable(name, value)
1688
+ self._variables.set_local(name, value)
1677
1689
  self._log_set_variable(name, value)
1678
1690
 
1679
1691
  @run_keyword_variant(resolve=0)
@@ -1696,6 +1708,9 @@ class _Variables(_BuiltInBase):
1696
1708
 
1697
1709
  When creating automated tasks, not tests, it is possible to use `Set
1698
1710
  Task Variable`. See also `Set Global Variable` and `Set Local Variable`.
1711
+
1712
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is recommended
1713
+ over this keyword.
1699
1714
  """
1700
1715
  name = self._get_var_name(name)
1701
1716
  value = self._get_var_value(name, values)
@@ -1708,6 +1723,9 @@ class _Variables(_BuiltInBase):
1708
1723
 
1709
1724
  This is an alias for `Set Test Variable` that is more applicable when
1710
1725
  creating tasks, not tests.
1726
+
1727
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is recommended
1728
+ over this keyword.
1711
1729
  """
1712
1730
  self.set_test_variable(name, *values)
1713
1731
 
@@ -1760,6 +1778,14 @@ class _Variables(_BuiltInBase):
1760
1778
  | Set Suite Variable &DICT &{EMPTY}
1761
1779
 
1762
1780
  See also `Set Global Variable`, `Set Test Variable` and `Set Local Variable`.
1781
+
1782
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is recommended
1783
+ over this keyword. The basic usage is shown below and the Robot Framework
1784
+ User Guide explains the syntax in detail.
1785
+
1786
+ | VAR ${SCALAR} Hello, world! scope=SUITE
1787
+ | VAR @{LIST} First item Second item scope=SUITE
1788
+ | VAR &{DICT} key=value foo=bar scope=SUITE
1763
1789
  """
1764
1790
  name = self._get_var_name(name)
1765
1791
  if values and is_string(values[-1]) and values[-1].startswith('children='):
@@ -1793,6 +1819,9 @@ class _Variables(_BuiltInBase):
1793
1819
  section for information why it is recommended to give the variable name
1794
1820
  in escaped format like ``$name`` or ``\${name}`` instead of the normal
1795
1821
  ``${name}``.
1822
+
1823
+ *NOTE:* The ``VAR`` syntax introduced in Robot Framework 7.0 is recommended
1824
+ over this keyword.
1796
1825
  """
1797
1826
  name = self._get_var_name(name)
1798
1827
  value = self._get_var_value(name, values)
@@ -1814,7 +1843,7 @@ class _Variables(_BuiltInBase):
1814
1843
  match.resolve_base(self._variables)
1815
1844
  valid = match.is_assign() if require_assign else match.is_variable()
1816
1845
  if not valid:
1817
- raise DataError("Invalid variable name '%s'." % name)
1846
+ raise DataError(f"Invalid variable name '{name}'.")
1818
1847
  return str(match)
1819
1848
 
1820
1849
  def _resolve_var_name(self, name):
@@ -1823,7 +1852,7 @@ class _Variables(_BuiltInBase):
1823
1852
  if len(name) < 2 or name[0] not in '$@&':
1824
1853
  raise ValueError
1825
1854
  if name[1] != '{':
1826
- name = '%s{%s}' % (name[0], name[1:])
1855
+ name = f'{name[0]}{{{name[1:]}}}'
1827
1856
  match = search_variable(name, identifiers='$@&', ignore_errors=True)
1828
1857
  match.resolve_base(self._variables)
1829
1858
  if not match.is_assign():
@@ -1839,11 +1868,12 @@ class _Variables(_BuiltInBase):
1839
1868
  # handling non-string values somehow. For details see
1840
1869
  # https://github.com/robotframework/robotframework/issues/1919
1841
1870
  if len(values) != 1 or is_list_variable(values[0]):
1842
- raise DataError("Setting list value to scalar variable '%s' "
1843
- "is not supported anymore. Create list "
1844
- "variable '@%s' instead." % (name, name[1:]))
1871
+ raise DataError(f"Setting list value to scalar variable '{name}' "
1872
+ f"is not supported anymore. Create list variable "
1873
+ f"'@{name[1:]}' instead.")
1845
1874
  return self._variables.replace_scalar(values[0])
1846
- return VariableTableValue(values, name).resolve(self._variables)
1875
+ resolver = VariableResolver.from_name_and_value(name, values)
1876
+ return resolver.resolve(self._variables)
1847
1877
 
1848
1878
  def _log_set_variable(self, name, value):
1849
1879
  self.log(format_assign_message(name, value))
@@ -1870,14 +1900,19 @@ class _RunKeyword(_BuiltInBase):
1870
1900
  ctx = self._context
1871
1901
  if not (ctx.dry_run or self._accepts_embedded_arguments(name, ctx)):
1872
1902
  name, args = self._replace_variables_in_name([name] + list(args))
1873
- parent = ctx.steps[-1] if ctx.steps else (ctx.test or ctx.suite)
1874
- kw = Keyword(name, args=args, parent=parent,
1875
- lineno=getattr(parent, 'lineno', None))
1876
- return kw.run(ctx)
1903
+ if ctx.steps:
1904
+ data, result = ctx.steps[-1]
1905
+ lineno = data.lineno
1906
+ else: # Called, typically by a listener, when no keyword started.
1907
+ data = lineno = None
1908
+ result = ctx.test or (ctx.suite.setup if not ctx.suite.has_tests
1909
+ else ctx.suite.teardown)
1910
+ kw = Keyword(name, args=args, parent=data, lineno=lineno)
1911
+ return kw.run(result, ctx)
1877
1912
 
1878
1913
  def _accepts_embedded_arguments(self, name, ctx):
1879
1914
  if '{' in name:
1880
- runner = ctx.get_runner(name)
1915
+ runner = ctx.get_runner(name, recommend_on_failure=False)
1881
1916
  return runner and hasattr(runner, 'embedded_args')
1882
1917
  return False
1883
1918
 
@@ -2048,7 +2083,7 @@ class _RunKeyword(_BuiltInBase):
2048
2083
  index = list(args).index(control_word)
2049
2084
  branch = self._variables.replace_list(args[index+1:], required)
2050
2085
  if len(branch) < required:
2051
- raise DataError('%s requires %s.' % (control_word, required_error))
2086
+ raise DataError(f'{control_word} requires {required_error}.')
2052
2087
  return args[:index], branch
2053
2088
 
2054
2089
  @run_keyword_variant(resolve=1, dry_run=True)
@@ -2105,7 +2140,7 @@ class _RunKeyword(_BuiltInBase):
2105
2140
  """
2106
2141
  status, message = self.run_keyword_and_ignore_error(name, *args)
2107
2142
  if status == 'FAIL':
2108
- logger.warn("Executing keyword '%s' failed:\n%s" % (name, message))
2143
+ logger.warn(f"Executing keyword '{name}' failed:\n{message}")
2109
2144
  return status, message
2110
2145
 
2111
2146
  @run_keyword_variant(resolve=0, dry_run=True)
@@ -2206,11 +2241,9 @@ class _RunKeyword(_BuiltInBase):
2206
2241
  raise
2207
2242
  error = err.message
2208
2243
  else:
2209
- raise AssertionError("Expected error '%s' did not occur."
2210
- % expected_error)
2244
+ raise AssertionError(f"Expected error '{expected_error}' did not occur.")
2211
2245
  if not self._error_is_expected(error, expected_error):
2212
- raise AssertionError("Expected error '%s' but got '%s'."
2213
- % (expected_error, error))
2246
+ raise AssertionError(f"Expected error '{expected_error}' but got '{error}'.")
2214
2247
  return error
2215
2248
 
2216
2249
  def _error_is_expected(self, error, expected_error):
@@ -2218,7 +2251,7 @@ class _RunKeyword(_BuiltInBase):
2218
2251
  matchers = {'GLOB': glob,
2219
2252
  'EQUALS': lambda s, p: s == p,
2220
2253
  'STARTS': lambda s, p: s.startswith(p),
2221
- 'REGEXP': lambda s, p: re.match(p + r'\Z', s) is not None}
2254
+ 'REGEXP': lambda s, p: re.fullmatch(p, s) is not None}
2222
2255
  prefixes = tuple(prefix + ':' for prefix in matchers)
2223
2256
  if not expected_error.startswith(prefixes):
2224
2257
  return glob(error, expected_error)
@@ -2287,21 +2320,20 @@ class _RunKeyword(_BuiltInBase):
2287
2320
 
2288
2321
  def _keywords_repeated_by_count(self, count, name, args):
2289
2322
  if count <= 0:
2290
- self.log("Keyword '%s' repeated zero times." % name)
2323
+ self.log(f"Keyword '{name}' repeated zero times.")
2291
2324
  for i in range(count):
2292
- self.log("Repeating keyword, round %d/%d." % (i + 1, count))
2325
+ self.log(f"Repeating keyword, round {i+1}/{count}.")
2293
2326
  yield name, args
2294
2327
 
2295
2328
  def _keywords_repeated_by_timeout(self, timeout, name, args):
2296
2329
  if timeout <= 0:
2297
- self.log("Keyword '%s' repeated zero times." % name)
2298
- repeat_round = 0
2330
+ self.log(f"Keyword '{name}' repeated zero times.")
2331
+ round = 0
2299
2332
  maxtime = time.time() + timeout
2300
2333
  while time.time() < maxtime:
2301
- repeat_round += 1
2302
- self.log("Repeating keyword, round %d, %s remaining."
2303
- % (repeat_round,
2304
- secs_to_timestr(maxtime - time.time(), compact=True)))
2334
+ round += 1
2335
+ remaining = secs_to_timestr(maxtime - time.time(), compact=True)
2336
+ self.log(f"Repeating keyword, round {round}, {remaining} remaining.")
2305
2337
  yield name, args
2306
2338
 
2307
2339
  @run_keyword_variant(resolve=2, dry_run=True)
@@ -2320,7 +2352,7 @@ class _RunKeyword(_BuiltInBase):
2320
2352
  ``5 times``, ``10 x``). ``retry_interval`` must always be given in
2321
2353
  Robot Framework's time format.
2322
2354
 
2323
- By default ``retry_interval`` is the time to wait _after_ a keyword has
2355
+ By default, ``retry_interval`` is the time to wait _after_ a keyword has
2324
2356
  failed. For example, if the first run takes 2 seconds and the retry
2325
2357
  interval is 3 seconds, the second run starts 5 seconds after the first
2326
2358
  run started. If ``retry_interval`` start with prefix ``strict:``, the
@@ -2344,7 +2376,7 @@ class _RunKeyword(_BuiltInBase):
2344
2376
  Running the same keyword multiple times inside this keyword can create
2345
2377
  lots of output and considerably increase the size of the generated
2346
2378
  output files. It is possible to remove unnecessary keywords from
2347
- the outputs using ``--RemoveKeywords WUKS`` command line option.
2379
+ the outputs using the ``--remove-keywords WUKS`` command line option.
2348
2380
 
2349
2381
  Support for "strict" retry interval is new in Robot Framework 4.1.
2350
2382
  """
@@ -2354,11 +2386,11 @@ class _RunKeyword(_BuiltInBase):
2354
2386
  except ValueError:
2355
2387
  timeout = timestr_to_secs(retry)
2356
2388
  maxtime = time.time() + timeout
2357
- message = 'for %s' % secs_to_timestr(timeout)
2389
+ message = f'for {secs_to_timestr(timeout)}'
2358
2390
  else:
2359
2391
  if count <= 0:
2360
- raise ValueError('Retry count %d is not positive.' % count)
2361
- message = '%d time%s' % (count, s(count))
2392
+ raise ValueError(f'Retry count {count} is not positive.')
2393
+ message = f'{count} time{s(count)}'
2362
2394
  if is_string(retry_interval) and normalize(retry_interval).startswith('strict:'):
2363
2395
  retry_interval = retry_interval.split(':', 1)[1].strip()
2364
2396
  strict_interval = True
@@ -2374,16 +2406,19 @@ class _RunKeyword(_BuiltInBase):
2374
2406
  raise
2375
2407
  count -= 1
2376
2408
  if time.time() > maxtime > 0 or count == 0:
2377
- raise AssertionError("Keyword '%s' failed after retrying %s. "
2378
- "The last error was: %s" % (name, message, err))
2409
+ name = self._variables.replace_scalar(name)
2410
+ raise AssertionError(f"Keyword '{name}' failed after retrying "
2411
+ f"{message}. The last error was: {err}")
2379
2412
  finally:
2380
2413
  if strict_interval:
2381
- keyword_runtime = time.time() - start_time
2382
- sleep_time = retry_interval - keyword_runtime
2414
+ execution_time = time.time() - start_time
2415
+ sleep_time = retry_interval - execution_time
2383
2416
  if sleep_time < 0:
2384
- logger.warn("Keyword execution time %s is longer than retry "
2385
- "interval %s." % (secs_to_timestr(keyword_runtime),
2386
- secs_to_timestr(retry_interval)))
2417
+ logger.warn(
2418
+ f"Keyword execution time {secs_to_timestr(execution_time)} "
2419
+ f"is longer than retry interval "
2420
+ f"{secs_to_timestr(retry_interval)}."
2421
+ )
2387
2422
  self._sleep_in_parts(sleep_time)
2388
2423
 
2389
2424
  @run_keyword_variant(resolve=1)
@@ -2426,19 +2461,21 @@ class _RunKeyword(_BuiltInBase):
2426
2461
  Use `Get Variable Value` if you need to set variables
2427
2462
  dynamically based on whether a variable exist or not.
2428
2463
  """
2429
- values = self._verify_values_for_set_variable_if(list(values))
2430
- if self._is_true(condition):
2431
- return self._variables.replace_scalar(values[0])
2432
- values = self._verify_values_for_set_variable_if(values[1:], True)
2433
- if len(values) == 1:
2434
- return self._variables.replace_scalar(values[0])
2435
- return self.run_keyword('BuiltIn.Set Variable If', *values[0:])
2436
-
2437
- def _verify_values_for_set_variable_if(self, values, default=False):
2464
+ values = list(values)
2465
+ while True:
2466
+ values = self._verify_values_for_set_variable_if(values)
2467
+ if self._is_true(condition):
2468
+ return self._variables.replace_scalar(values[0])
2469
+ if len(values) == 1:
2470
+ return None
2471
+ if len(values) == 2:
2472
+ return self._variables.replace_scalar(values[1])
2473
+ condition, *values = values[1:]
2474
+ condition = self._variables.replace_scalar(condition)
2475
+
2476
+ def _verify_values_for_set_variable_if(self, values):
2438
2477
  if not values:
2439
- if default:
2440
- return [None]
2441
- raise RuntimeError('At least one value is required')
2478
+ raise RuntimeError('At least one value is required.')
2442
2479
  if is_list_variable(values[0]):
2443
2480
  values[:1] = [escape(item) for item in self._variables[values[0]]]
2444
2481
  return self._verify_values_for_set_variable_if(values)
@@ -2520,10 +2557,9 @@ class _RunKeyword(_BuiltInBase):
2520
2557
  if suite.statistics.failed > 0:
2521
2558
  return self.run_keyword(name, *args)
2522
2559
 
2523
- def _get_suite_in_teardown(self, kwname):
2560
+ def _get_suite_in_teardown(self, kw):
2524
2561
  if not self._context.in_suite_teardown:
2525
- raise RuntimeError("Keyword '%s' can only be used in suite teardown."
2526
- % kwname)
2562
+ raise RuntimeError(f"Keyword '{kw}' can only be used in suite teardown.")
2527
2563
  return self._context.suite
2528
2564
 
2529
2565
 
@@ -2872,7 +2908,7 @@ class _Control(_BuiltInBase):
2872
2908
  Passing execution in the middle of a test, setup or teardown should be
2873
2909
  used with care. In the worst case it leads to tests that skip all the
2874
2910
  parts that could actually uncover problems in the tested application.
2875
- In cases where execution cannot continue do to external factors,
2911
+ In cases where execution cannot continue due to external factors,
2876
2912
  it is often safer to fail the test case and make it non-critical.
2877
2913
  """
2878
2914
  message = message.strip()
@@ -2880,7 +2916,7 @@ class _Control(_BuiltInBase):
2880
2916
  raise RuntimeError('Message cannot be empty.')
2881
2917
  self._set_and_remove_tags(tags)
2882
2918
  log_message, level = self._get_logged_test_message_and_level(message)
2883
- self.log('Execution passed with message:\n%s' % log_message, level)
2919
+ self.log(f'Execution passed with message:\n{log_message}', level)
2884
2920
  raise PassExecution(message)
2885
2921
 
2886
2922
  @run_keyword_variant(resolve=1)
@@ -2931,7 +2967,7 @@ class _Misc(_BuiltInBase):
2931
2967
  if seconds < 0:
2932
2968
  seconds = 0
2933
2969
  self._sleep_in_parts(seconds)
2934
- self.log('Slept %s' % secs_to_timestr(seconds))
2970
+ self.log(f'Slept {secs_to_timestr(seconds)}.')
2935
2971
  if reason:
2936
2972
  self.log(reason)
2937
2973
 
@@ -3050,8 +3086,8 @@ class _Misc(_BuiltInBase):
3050
3086
  'len': len,
3051
3087
  'type': lambda x: type(x).__name__}[formatter.lower()]
3052
3088
  except KeyError:
3053
- raise ValueError("Invalid formatter '%s'. Available "
3054
- "'str', 'repr', 'ascii', 'len', and 'type'." % formatter)
3089
+ raise ValueError(f"Invalid formatter '{formatter}'. Available "
3090
+ f"'str', 'repr', 'ascii', 'len', and 'type'.")
3055
3091
 
3056
3092
  @run_keyword_variant(resolve=0)
3057
3093
  def log_many(self, *messages):
@@ -3078,7 +3114,7 @@ class _Misc(_BuiltInBase):
3078
3114
  yield item
3079
3115
  elif match.is_dict_variable():
3080
3116
  for name, value in value.items():
3081
- yield '%s=%s' % (name, value)
3117
+ yield f'{name}={value}'
3082
3118
  else:
3083
3119
  yield value
3084
3120
 
@@ -3128,23 +3164,34 @@ class _Misc(_BuiltInBase):
3128
3164
  pass
3129
3165
 
3130
3166
  def set_log_level(self, level):
3131
- """Sets the log threshold to the specified level and returns the old level.
3167
+ """Sets the log threshold to the specified level.
3132
3168
 
3133
3169
  Messages below the level will not logged. The default logging level is
3134
- INFO, but it can be overridden with the command line option
3135
- ``--loglevel``.
3170
+ INFO, but it can be overridden with the ``--loglevel`` command line option.
3171
+ The available levels are TRACE, DEBUG, INFO (default), WARN, ERROR and NONE
3172
+ (no logging).
3136
3173
 
3137
- The available levels: TRACE, DEBUG, INFO (default), WARN, ERROR and NONE (no
3138
- logging).
3174
+ The old level is returned and can be used for setting the level back
3175
+ later. An alternative way to reset the level is using the dedicated
3176
+ `Reset Log Level` keyword.
3139
3177
  """
3140
- try:
3141
- old = self._context.output.set_log_level(level)
3142
- except DataError as err:
3143
- raise RuntimeError(str(err))
3178
+ old = self._context.output.set_log_level(level)
3144
3179
  self._namespace.variables.set_global('${LOG_LEVEL}', level.upper())
3145
- self.log('Log level changed from %s to %s.' % (old, level.upper()))
3180
+ self.log(f'Log level changed from {old} to {level.upper()}.', level='DEBUG')
3146
3181
  return old
3147
3182
 
3183
+ def reset_log_level(self):
3184
+ """Resets the log level to the original value.
3185
+
3186
+ The original log level is set from the command line with the ``--loglevel``
3187
+ option and is INFO by default. The active log level can be changed using
3188
+ the `Set Log Level` keyword.
3189
+
3190
+ New in Robot Framework 7.0.
3191
+ """
3192
+ level = self._context.output.initial_log_level
3193
+ return self.set_log_level(level)
3194
+
3148
3195
  def reload_library(self, name_or_instance):
3149
3196
  """Rechecks what keywords the specified library provides.
3150
3197
 
@@ -3155,9 +3202,8 @@ class _Misc(_BuiltInBase):
3155
3202
  the library. The latter is especially useful if the library itself
3156
3203
  calls this keyword as a method.
3157
3204
  """
3158
- library = self._namespace.reload_library(name_or_instance)
3159
- self.log('Reloaded library %s with %s keywords.' % (library.name,
3160
- len(library)))
3205
+ lib = self._namespace.reload_library(name_or_instance)
3206
+ self.log(f'Reloaded library {lib.name} with {len(lib.keywords)} keywords.')
3161
3207
 
3162
3208
  @run_keyword_variant(resolve=0)
3163
3209
  def import_library(self, name, *args):
@@ -3297,11 +3343,11 @@ class _Misc(_BuiltInBase):
3297
3343
  See also `Variable Should Exist`.
3298
3344
  """
3299
3345
  try:
3300
- runner = self._namespace.get_runner(name, recommend_on_failure=False)
3301
- except DataError as error:
3302
- raise AssertionError(msg or error.message)
3303
- if isinstance(runner, UserErrorHandler):
3304
- raise AssertionError(msg or runner.error.message)
3346
+ kw = self._namespace.get_runner(name, recommend_on_failure=False).keyword
3347
+ if kw.error:
3348
+ raise DataError(kw.error)
3349
+ except DataError as err:
3350
+ raise AssertionError(msg or err.message)
3305
3351
 
3306
3352
  def get_time(self, format='timestamp', time_='NOW'):
3307
3353
  """Returns the given time in the requested format.
@@ -3523,7 +3569,7 @@ class _Misc(_BuiltInBase):
3523
3569
  if self._context.in_test_teardown:
3524
3570
  self._variables.set_test("${TEST_MESSAGE}", test.message)
3525
3571
  message, level = self._get_logged_test_message_and_level(test.message)
3526
- self.log('Set test message to:\n%s' % message, level)
3572
+ self.log(f'Set test message to:\n{message}', level)
3527
3573
 
3528
3574
  def _get_new_text(self, old, new, append, handle_html=False):
3529
3575
  if not is_string(new):
@@ -3534,10 +3580,10 @@ class _Misc(_BuiltInBase):
3534
3580
  if new.startswith('*HTML*'):
3535
3581
  new = new[6:].lstrip()
3536
3582
  if not old.startswith('*HTML*'):
3537
- old = '*HTML* %s' % html_escape(old)
3583
+ old = f'*HTML* {html_escape(old)}'
3538
3584
  elif old.startswith('*HTML*'):
3539
3585
  new = html_escape(new)
3540
- return '%s %s' % (old, new)
3586
+ return f'{old} {new}'
3541
3587
 
3542
3588
  def _get_logged_test_message_and_level(self, message):
3543
3589
  if message.startswith('*HTML*'):
@@ -3561,12 +3607,12 @@ class _Misc(_BuiltInBase):
3561
3607
  "used in suite setup or teardown.")
3562
3608
  test.doc = self._get_new_text(test.doc, doc, append)
3563
3609
  self._variables.set_test('${TEST_DOCUMENTATION}', test.doc)
3564
- self.log('Set test documentation to:\n%s' % test.doc)
3610
+ self.log(f'Set test documentation to:\n{test.doc}')
3565
3611
 
3566
3612
  def set_suite_documentation(self, doc, append=False, top=False):
3567
3613
  """Sets documentation for the current test suite.
3568
3614
 
3569
- By default the possible existing documentation is overwritten, but
3615
+ By default, the possible existing documentation is overwritten, but
3570
3616
  this can be changed using the optional ``append`` argument similarly
3571
3617
  as with `Set Test Message` keyword.
3572
3618
 
@@ -3581,12 +3627,12 @@ class _Misc(_BuiltInBase):
3581
3627
  suite = self._get_context(top).suite
3582
3628
  suite.doc = self._get_new_text(suite.doc, doc, append)
3583
3629
  self._variables.set_suite('${SUITE_DOCUMENTATION}', suite.doc, top)
3584
- self.log('Set suite documentation to:\n%s' % suite.doc)
3630
+ self.log(f'Set suite documentation to:\n{suite.doc}')
3585
3631
 
3586
3632
  def set_suite_metadata(self, name, value, append=False, top=False):
3587
3633
  """Sets metadata for the current test suite.
3588
3634
 
3589
- By default possible existing metadata values are overwritten, but
3635
+ By default, possible existing metadata values are overwritten, but
3590
3636
  this can be changed using the optional ``append`` argument similarly
3591
3637
  as with `Set Test Message` keyword.
3592
3638
 
@@ -3604,7 +3650,7 @@ class _Misc(_BuiltInBase):
3604
3650
  original = metadata.get(name, '')
3605
3651
  metadata[name] = self._get_new_text(original, value, append)
3606
3652
  self._variables.set_suite('${SUITE_METADATA}', metadata.copy(), top)
3607
- self.log("Set suite metadata '%s' to value '%s'." % (name, metadata[name]))
3653
+ self.log(f"Set suite metadata '{name}' to value '{metadata[name]}'.")
3608
3654
 
3609
3655
  def set_tags(self, *tags):
3610
3656
  """Adds given ``tags`` for the current test or all tests in a suite.
@@ -3629,7 +3675,7 @@ class _Misc(_BuiltInBase):
3629
3675
  ctx.suite.set_tags(tags, persist=True)
3630
3676
  else:
3631
3677
  raise RuntimeError("'Set Tags' cannot be used in suite teardown.")
3632
- self.log('Set tag%s %s.' % (s(tags), seq2str(tags)))
3678
+ self.log(f'Set tag{s(tags)} {seq2str((tags))}.')
3633
3679
 
3634
3680
  def remove_tags(self, *tags):
3635
3681
  """Removes given ``tags`` from the current test or all tests in a suite.
@@ -3657,7 +3703,7 @@ class _Misc(_BuiltInBase):
3657
3703
  ctx.suite.set_tags(remove=tags, persist=True)
3658
3704
  else:
3659
3705
  raise RuntimeError("'Remove Tags' cannot be used in suite teardown.")
3660
- self.log('Removed tag%s %s.' % (s(tags), seq2str(tags)))
3706
+ self.log(f'Removed tag{s(tags)} {seq2str((tags))}.')
3661
3707
 
3662
3708
  def get_library_instance(self, name=None, all=False):
3663
3709
  """Returns the currently active instance of the specified library.
@@ -3672,8 +3718,7 @@ class _Misc(_BuiltInBase):
3672
3718
  | seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
3673
3719
  | title = seleniumlib.get_title()
3674
3720
  | if not title.startswith(expected):
3675
- | raise AssertionError("Title '%s' did not start with '%s'"
3676
- | % (title, expected))
3721
+ | raise AssertionError(f"Title '{title}' did not start with '{expected}'.")
3677
3722
 
3678
3723
  It is also possible to use this keyword in the test data and
3679
3724
  pass the returned library instance to another keyword. If a
@@ -3716,40 +3761,6 @@ class BuiltIn(_Verify, _Converter, _Variables, _RunKeyword, _Control, _Misc):
3716
3761
  HTML in messages is not limited to BuiltIn library but works with any
3717
3762
  error message.
3718
3763
 
3719
- = Using variables with keywords creating or accessing variables =
3720
-
3721
- This library has special keywords `Set Global Variable`, `Set Suite Variable`,
3722
- `Set Test Variable` and `Set Local Variable` for creating variables in
3723
- different scopes. These keywords take the variable name and its value as
3724
- arguments. The name can be given using the normal ``${variable}`` syntax or
3725
- in escaped format either like ``$variable`` or ``\${variable}``. For example,
3726
- these are typically equivalent and create new suite level variable
3727
- ``${name}`` with value ``value``:
3728
-
3729
- | Set Suite Variable ${name} value
3730
- | Set Suite Variable $name value
3731
- | Set Suite Variable \${name} value
3732
-
3733
- A problem with using the normal ``${variable}`` syntax is that these
3734
- keywords cannot easily know is the idea to create a variable with exactly
3735
- that name or does that variable actually contain the name of the variable
3736
- to create. If the variable does not initially exist, it will always be
3737
- created. If it exists and its value is a variable name either in the normal
3738
- or in the escaped syntax, variable with _that_ name is created instead.
3739
- For example, if ``${name}`` variable would exist and contain value
3740
- ``$example``, these examples would create different variables:
3741
-
3742
- | Set Suite Variable ${name} value # Creates ${example}.
3743
- | Set Suite Variable $name value # Creates ${name}.
3744
- | Set Suite Variable \${name} value # Creates ${name}.
3745
-
3746
- Because the behavior when using the normal ``${variable}`` syntax depends
3747
- on the possible existing value of the variable, it is *highly recommended
3748
- to use the escaped ``$variable`` or ``\${variable}`` format instead*.
3749
-
3750
- This same problem occurs also with special keywords for accessing variables
3751
- `Get Variable Value`, `Variable Should Exist` and `Variable Should Not Exist`.
3752
-
3753
3764
  = Evaluating expressions =
3754
3765
 
3755
3766
  Many keywords, such as `Evaluate`, `Run Keyword If` and `Should Be True`,
@@ -3814,6 +3825,45 @@ class BuiltIn(_Verify, _Converter, _Variables, _RunKeyword, _Control, _Misc):
3814
3825
  to move the logic into a library. That eases maintenance and can also
3815
3826
  enhance execution speed.
3816
3827
 
3828
+ = Using variables with keywords creating or accessing variables =
3829
+
3830
+ This library has special keywords `Set Global Variable`, `Set Suite Variable`,
3831
+ `Set Test Variable` and `Set Local Variable` for creating variables in
3832
+ different scopes. These keywords take the variable name and its value as
3833
+ arguments. The name can be given using the normal ``${variable}`` syntax or
3834
+ in escaped format either like ``$variable`` or ``\${variable}``. For example,
3835
+ these are typically equivalent and create new suite level variable
3836
+ ``${name}`` with value ``value``:
3837
+
3838
+ | Set Suite Variable ${name} value
3839
+ | Set Suite Variable $name value
3840
+ | Set Suite Variable \${name} value
3841
+
3842
+ A problem with using the normal ``${variable}`` syntax is that these
3843
+ keywords cannot easily know is the idea to create a variable with exactly
3844
+ that name or does that variable actually contain the name of the variable
3845
+ to create. If the variable does not initially exist, it will always be
3846
+ created. If it exists and its value is a variable name either in the normal
3847
+ or in the escaped syntax, variable with _that_ name is created instead.
3848
+ For example, if ``${name}`` variable would exist and contain value
3849
+ ``$example``, these examples would create different variables:
3850
+
3851
+ | Set Suite Variable ${name} value # Creates ${example}.
3852
+ | Set Suite Variable $name value # Creates ${name}.
3853
+ | Set Suite Variable \${name} value # Creates ${name}.
3854
+
3855
+ Because the behavior when using the normal ``${variable}`` syntax depends
3856
+ on the possible existing value of the variable, it is *highly recommended
3857
+ to use the escaped ``$variable`` or ``\${variable}`` format instead*.
3858
+
3859
+ This same problem occurs also with special keywords for accessing variables
3860
+ `Get Variable Value`, `Variable Should Exist` and `Variable Should Not Exist`.
3861
+
3862
+ *NOTE:* It is recommended to use the ``VAR`` syntax introduced in Robot
3863
+ Framework 7.0 for creating variables in different scopes instead of the
3864
+ `Set Global/Suite/Test/Local Variable` keywords. It makes creating variables
3865
+ uniform and avoids all the problems discussed above.
3866
+
3817
3867
  = Boolean arguments =
3818
3868
 
3819
3869
  Some keywords accept arguments that are handled as Boolean values true or