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
@@ -22,9 +22,10 @@ from robot.errors import DataError
22
22
  from robot.parsing import File, get_init_model, get_model, get_resource_model
23
23
  from robot.utils import FileReader, get_error_message, read_rest_data, type_name
24
24
 
25
+ from ..model import TestSuite
26
+ from ..resourcemodel import ResourceFile
25
27
  from .settings import FileSettings, InitFileSettings, TestDefaults
26
28
  from .transformers import ResourceBuilder, SuiteBuilder
27
- from ..model import ResourceFile, TestSuite
28
29
 
29
30
 
30
31
  class Parser(ABC):
@@ -53,22 +54,21 @@ class RobotParser(Parser):
53
54
  def parse_suite_file(self, source: Path, defaults: TestDefaults) -> TestSuite:
54
55
  model = get_model(self._get_source(source), data_only=True,
55
56
  curdir=self._get_curdir(source), lang=self.lang)
56
- suite = TestSuite(name=TestSuite.name_from_source(source, self.extensions),
57
- source=source)
58
- SuiteBuilder(suite, FileSettings(defaults)).build(model)
59
- return suite
57
+ model.source = source
58
+ return self.parse_model(model, defaults)
60
59
 
61
60
  def parse_init_file(self, source: Path, defaults: TestDefaults) -> TestSuite:
62
61
  model = get_init_model(self._get_source(source), data_only=True,
63
62
  curdir=self._get_curdir(source), lang=self.lang)
64
- directory = source.parent
65
- suite = TestSuite(name=TestSuite.name_from_source(directory), source=directory)
63
+ model.source = source
64
+ suite = TestSuite(name=TestSuite.name_from_source(source.parent),
65
+ source=source.parent, rpa=None)
66
66
  SuiteBuilder(suite, InitFileSettings(defaults)).build(model)
67
67
  return suite
68
68
 
69
69
  def parse_model(self, model: File, defaults: 'TestDefaults|None' = None) -> TestSuite:
70
- source = model.source
71
- suite = TestSuite(name=TestSuite.name_from_source(source), source=source)
70
+ name = TestSuite.name_from_source(model.source, self.extensions)
71
+ suite = TestSuite(name=name, source=model.source)
72
72
  SuiteBuilder(suite, FileSettings(defaults)).build(model)
73
73
  return suite
74
74
 
@@ -81,7 +81,12 @@ class RobotParser(Parser):
81
81
  def parse_resource_file(self, source: Path) -> ResourceFile:
82
82
  model = get_resource_model(self._get_source(source), data_only=True,
83
83
  curdir=self._get_curdir(source), lang=self.lang)
84
- resource = ResourceFile(source=source)
84
+ model.source = source
85
+ resource = self.parse_resource_model(model)
86
+ return resource
87
+
88
+ def parse_resource_model(self, model: File) -> ResourceFile:
89
+ resource = ResourceFile(source=model.source)
85
90
  ResourceBuilder(resource).build(model)
86
91
  return resource
87
92
 
@@ -112,7 +117,8 @@ class JsonParser(Parser):
112
117
  class NoInitFileDirectoryParser(Parser):
113
118
 
114
119
  def parse_init_file(self, source: Path, defaults: TestDefaults) -> TestSuite:
115
- return TestSuite(name=TestSuite.name_from_source(source), source=source)
120
+ return TestSuite(name=TestSuite.name_from_source(source),
121
+ source=source, rpa=None)
116
122
 
117
123
 
118
124
  class CustomParser(Parser):
@@ -13,31 +13,23 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- import sys
17
16
  from collections.abc import Sequence
17
+ from typing import TypedDict
18
18
 
19
19
  from ..model import TestCase
20
20
 
21
21
 
22
- if sys.version_info >= (3, 8):
23
- from typing import TypedDict
22
+ class OptionalItems(TypedDict, total=False):
23
+ args: 'Sequence[str]'
24
+ lineno: int
24
25
 
25
26
 
26
- class OptionalItems(TypedDict, total=False):
27
- args: 'Sequence[str]'
28
- lineno: int
27
+ class FixtureDict(OptionalItems):
28
+ """Dictionary containing setup or teardown info.
29
29
 
30
-
31
- class FixtureDict(OptionalItems):
32
- """Dictionary containing setup or teardown info.
33
-
34
- :attr:`args` and :attr:`lineno` are optional.
35
- """
36
- name: str
37
-
38
- else:
39
- class FixtureDict(dict):
40
- pass
30
+ :attr:`args` and :attr:`lineno` are optional.
31
+ """
32
+ name: str
41
33
 
42
34
 
43
35
  class TestDefaults:
@@ -0,0 +1,535 @@
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 robot.errors import DataError
17
+ from robot.output import LOGGER
18
+ from robot.parsing import File, ModelVisitor, Token
19
+ from robot.utils import NormalizedDict
20
+ from robot.variables import VariableMatches
21
+
22
+ from ..model import For, If, IfBranch, TestSuite, TestCase, Try, TryBranch, While
23
+ from ..resourcemodel import ResourceFile, UserKeyword
24
+ from .settings import FileSettings
25
+
26
+
27
+ class SettingsBuilder(ModelVisitor):
28
+
29
+ def __init__(self, suite: TestSuite, settings: FileSettings):
30
+ self.suite = suite
31
+ self.settings = settings
32
+
33
+ def visit_Documentation(self, node):
34
+ self.suite.doc = node.value
35
+
36
+ def visit_Metadata(self, node):
37
+ self.suite.metadata[node.name] = node.value
38
+
39
+ def visit_SuiteName(self, node):
40
+ self.suite.name = node.value
41
+
42
+ def visit_SuiteSetup(self, node):
43
+ self.suite.setup.config(name=node.name, args=node.args,
44
+ lineno=node.lineno)
45
+
46
+ def visit_SuiteTeardown(self, node):
47
+ self.suite.teardown.config(name=node.name, args=node.args,
48
+ lineno=node.lineno)
49
+
50
+ def visit_TestSetup(self, node):
51
+ self.settings.test_setup = {'name': node.name, 'args': node.args,
52
+ 'lineno': node.lineno}
53
+
54
+ def visit_TestTeardown(self, node):
55
+ self.settings.test_teardown = {'name': node.name, 'args': node.args,
56
+ 'lineno': node.lineno}
57
+
58
+ def visit_TestTimeout(self, node):
59
+ self.settings.test_timeout = node.value
60
+
61
+ def visit_DefaultTags(self, node):
62
+ self.settings.default_tags = node.values
63
+
64
+ def visit_TestTags(self, node):
65
+ self.settings.test_tags = node.values
66
+
67
+ def visit_KeywordTags(self, node):
68
+ self.settings.keyword_tags = node.values
69
+
70
+ def visit_TestTemplate(self, node):
71
+ self.settings.test_template = node.value
72
+
73
+ def visit_LibraryImport(self, node):
74
+ self.suite.resource.imports.library(node.name, node.args, node.alias, node.lineno)
75
+
76
+ def visit_ResourceImport(self, node):
77
+ self.suite.resource.imports.resource(node.name, node.lineno)
78
+
79
+ def visit_VariablesImport(self, node):
80
+ self.suite.resource.imports.variables(node.name, node.args, node.lineno)
81
+
82
+ def visit_VariableSection(self, node):
83
+ pass
84
+
85
+ def visit_TestCaseSection(self, node):
86
+ pass
87
+
88
+ def visit_KeywordSection(self, node):
89
+ pass
90
+
91
+
92
+ class SuiteBuilder(ModelVisitor):
93
+
94
+ def __init__(self, suite: TestSuite, settings: FileSettings):
95
+ self.suite = suite
96
+ self.settings = settings
97
+ self.seen_keywords = NormalizedDict(ignore='_')
98
+ self.rpa = None
99
+
100
+ def build(self, model: File):
101
+ ErrorReporter(model.source).visit(model)
102
+ SettingsBuilder(self.suite, self.settings).visit(model)
103
+ self.visit(model)
104
+ if self.rpa is not None:
105
+ self.suite.rpa = self.rpa
106
+
107
+ def visit_SettingSection(self, node):
108
+ pass
109
+
110
+ def visit_Variable(self, node):
111
+ self.suite.resource.variables.create(name=node.name,
112
+ value=node.value,
113
+ separator=node.separator,
114
+ lineno=node.lineno,
115
+ error=format_error(node.errors))
116
+
117
+ def visit_TestCaseSection(self, node):
118
+ if self.rpa is None:
119
+ self.rpa = node.tasks
120
+ elif self.rpa != node.tasks:
121
+ raise DataError('One file cannot have both tests and tasks.')
122
+ self.generic_visit(node)
123
+
124
+ def visit_TestCase(self, node):
125
+ TestCaseBuilder(self.suite, self.settings).build(node)
126
+
127
+ def visit_Keyword(self, node):
128
+ KeywordBuilder(self.suite.resource, self.settings, self.seen_keywords).build(node)
129
+
130
+
131
+ class ResourceBuilder(ModelVisitor):
132
+
133
+ def __init__(self, resource: ResourceFile):
134
+ self.resource = resource
135
+ self.settings = FileSettings()
136
+ self.seen_keywords = NormalizedDict(ignore='_')
137
+
138
+ def build(self, model: File):
139
+ ErrorReporter(model.source, raise_on_invalid_header=True).visit(model)
140
+ self.visit(model)
141
+
142
+ def visit_Documentation(self, node):
143
+ self.resource.doc = node.value
144
+
145
+ def visit_KeywordTags(self, node):
146
+ self.settings.keyword_tags = node.values
147
+
148
+ def visit_LibraryImport(self, node):
149
+ self.resource.imports.library(node.name, node.args, node.alias, node.lineno)
150
+
151
+ def visit_ResourceImport(self, node):
152
+ self.resource.imports.resource(node.name, node.lineno)
153
+
154
+ def visit_VariablesImport(self, node):
155
+ self.resource.imports.variables(node.name, node.args, node.lineno)
156
+
157
+ def visit_Variable(self, node):
158
+ self.resource.variables.create(name=node.name,
159
+ value=node.value,
160
+ separator=node.separator,
161
+ lineno=node.lineno,
162
+ error=format_error(node.errors))
163
+
164
+ def visit_Keyword(self, node):
165
+ KeywordBuilder(self.resource, self.settings, self.seen_keywords).build(node)
166
+
167
+
168
+ class BodyBuilder(ModelVisitor):
169
+
170
+ def __init__(self, model: 'TestCase|UserKeyword|For|If|Try|While|None' = None):
171
+ self.model = model
172
+
173
+ def visit_For(self, node):
174
+ ForBuilder(self.model).build(node)
175
+
176
+ def visit_While(self, node):
177
+ WhileBuilder(self.model).build(node)
178
+
179
+ def visit_If(self, node):
180
+ IfBuilder(self.model).build(node)
181
+
182
+ def visit_Try(self, node):
183
+ TryBuilder(self.model).build(node)
184
+
185
+ def visit_KeywordCall(self, node):
186
+ self.model.body.create_keyword(name=node.keyword, args=node.args,
187
+ assign=node.assign, lineno=node.lineno)
188
+
189
+ def visit_TemplateArguments(self, node):
190
+ self.model.body.create_keyword(args=node.args, lineno=node.lineno)
191
+
192
+ def visit_Var(self, node):
193
+ self.model.body.create_var(node.name, node.value, node.scope, node.separator,
194
+ lineno=node.lineno, error=format_error(node.errors))
195
+
196
+ def visit_Return(self, node):
197
+ self.model.body.create_return(node.values, lineno=node.lineno,
198
+ error=format_error(node.errors))
199
+
200
+ def visit_Continue(self, node):
201
+ self.model.body.create_continue(lineno=node.lineno,
202
+ error=format_error(node.errors))
203
+
204
+ def visit_Break(self, node):
205
+ self.model.body.create_break(lineno=node.lineno,
206
+ error=format_error(node.errors))
207
+
208
+ def visit_Error(self, node):
209
+ self.model.body.create_error(node.values, lineno=node.lineno,
210
+ error=format_error(node.errors))
211
+
212
+
213
+ class TestCaseBuilder(BodyBuilder):
214
+ model: TestCase
215
+
216
+ def __init__(self, suite: TestSuite, settings: FileSettings):
217
+ super().__init__(suite.tests.create())
218
+ self.settings = settings
219
+ self._test_has_tags = False
220
+
221
+ def build(self, node):
222
+ settings = self.settings
223
+ # Possible parsing errors aren't reported further with tests because:
224
+ # - We only validate that test body or name isn't empty.
225
+ # - That is validated again during execution.
226
+ # - This way e.g. model modifiers can add content to body.
227
+ self.model.config(name=node.name, tags=settings.test_tags,
228
+ timeout=settings.test_timeout,
229
+ template=settings.test_template,
230
+ lineno=node.lineno)
231
+ if settings.test_setup:
232
+ self.model.setup.config(**settings.test_setup)
233
+ if settings.test_teardown:
234
+ self.model.teardown.config(**settings.test_teardown)
235
+ self.generic_visit(node)
236
+ if not self._test_has_tags:
237
+ self.model.tags.add(settings.default_tags)
238
+ if self.model.template:
239
+ self._set_template(self.model, self.model.template)
240
+
241
+ def _set_template(self, parent, template):
242
+ for item in parent.body:
243
+ if item.type == item.FOR:
244
+ self._set_template(item, template)
245
+ elif item.type == item.IF_ELSE_ROOT:
246
+ for branch in item.body:
247
+ self._set_template(branch, template)
248
+ elif item.type == item.KEYWORD:
249
+ name, args = self._format_template(template, item.args)
250
+ item.name = name
251
+ item.args = args
252
+
253
+ def _format_template(self, template, arguments):
254
+ matches = VariableMatches(template, identifiers='$')
255
+ count = len(matches)
256
+ if count == 0 or count != len(arguments):
257
+ return template, arguments
258
+ temp = []
259
+ for match, arg in zip(matches, arguments):
260
+ temp[-1:] = [match.before, arg, match.after]
261
+ return ''.join(temp), ()
262
+
263
+ def visit_Documentation(self, node):
264
+ self.model.doc = node.value
265
+
266
+ def visit_Setup(self, node):
267
+ self.model.setup.config(name=node.name, args=node.args, lineno=node.lineno)
268
+
269
+ def visit_Teardown(self, node):
270
+ self.model.teardown.config(name=node.name, args=node.args, lineno=node.lineno)
271
+
272
+ def visit_Timeout(self, node):
273
+ self.model.timeout = node.value
274
+
275
+ def visit_Tags(self, node):
276
+ for tag in node.values:
277
+ if tag.startswith('-'):
278
+ self.model.tags.remove(tag[1:])
279
+ else:
280
+ self.model.tags.add(tag)
281
+ self._test_has_tags = True
282
+
283
+ def visit_Template(self, node):
284
+ self.model.template = node.value
285
+
286
+
287
+ class KeywordBuilder(BodyBuilder):
288
+ model: UserKeyword
289
+
290
+ def __init__(self, resource: ResourceFile, settings: FileSettings,
291
+ seen_keywords: NormalizedDict):
292
+ super().__init__(resource.keywords.create(tags=settings.keyword_tags))
293
+ self.resource = resource
294
+ self.seen_keywords = seen_keywords
295
+ self.return_setting = None
296
+
297
+ def build(self, node):
298
+ kw = self.model
299
+ try:
300
+ # Validate only name here. Reporting all parsing errors would report also
301
+ # body being empty, but we want to validate it only at parsing time.
302
+ if not node.name:
303
+ raise DataError('User keyword name cannot be empty.')
304
+ kw.config(name=node.name, lineno=node.lineno)
305
+ except DataError as err:
306
+ # Errors other than name being empty mean that name contains invalid
307
+ # embedded arguments. Need to set `_name` to bypass `@property`.
308
+ kw.config(_name=node.name, lineno=node.lineno, error=str(err))
309
+ self._report_error(node, err)
310
+ self.generic_visit(node)
311
+ if self.return_setting:
312
+ kw.body.create_return(self.return_setting)
313
+ if not kw.embedded:
314
+ self._handle_duplicates(kw, self.seen_keywords, node)
315
+
316
+ def _report_error(self, node, error):
317
+ error = f"Creating keyword '{self.model.name}' failed: {error}"
318
+ ErrorReporter(self.model.source).report_error(node, error)
319
+
320
+ def _handle_duplicates(self, kw, seen, node):
321
+ if kw.name in seen:
322
+ error = 'Keyword with same name defined multiple times.'
323
+ seen[kw.name].error = error
324
+ self.resource.keywords.pop()
325
+ self._report_error(node, error)
326
+ else:
327
+ seen[kw.name] = kw
328
+
329
+ def visit_Documentation(self, node):
330
+ self.model.doc = node.value
331
+
332
+ def visit_Arguments(self, node):
333
+ if node.errors:
334
+ error = 'Invalid argument specification: ' + format_error(node.errors)
335
+ self.model.error = error
336
+ self._report_error(node, error)
337
+ else:
338
+ self.model.args = node.values
339
+
340
+ def visit_Tags(self, node):
341
+ for tag in node.values:
342
+ if tag.startswith('-'):
343
+ self.model.tags.remove(tag[1:])
344
+ else:
345
+ self.model.tags.add(tag)
346
+
347
+ def visit_ReturnSetting(self, node):
348
+ ErrorReporter(self.model.source).visit(node)
349
+ self.return_setting = node.values
350
+
351
+ def visit_Timeout(self, node):
352
+ self.model.timeout = node.value
353
+
354
+ def visit_Setup(self, node):
355
+ self.model.setup.config(name=node.name, args=node.args, lineno=node.lineno)
356
+
357
+ def visit_Teardown(self, node):
358
+ self.model.teardown.config(name=node.name, args=node.args, lineno=node.lineno)
359
+
360
+ def visit_KeywordCall(self, node):
361
+ self.model.body.create_keyword(name=node.keyword, args=node.args,
362
+ assign=node.assign, lineno=node.lineno)
363
+
364
+
365
+ class ForBuilder(BodyBuilder):
366
+ model: For
367
+
368
+ def __init__(self, parent: 'TestCase|UserKeyword|For|If|Try|While'):
369
+ super().__init__(parent.body.create_for())
370
+
371
+ def build(self, node):
372
+ error = format_error(self._get_errors(node))
373
+ self.model.config(assign=node.assign, flavor=node.flavor, values=node.values,
374
+ start=node.start, mode=node.mode, fill=node.fill,
375
+ lineno=node.lineno, error=error)
376
+ for step in node.body:
377
+ self.visit(step)
378
+ return self.model
379
+
380
+ def _get_errors(self, node):
381
+ errors = node.header.errors + node.errors
382
+ if node.end:
383
+ errors += node.end.errors
384
+ return errors
385
+
386
+
387
+ class IfBuilder(BodyBuilder):
388
+ model: 'IfBranch|None'
389
+
390
+ def __init__(self, parent: 'TestCase|UserKeyword|For|If|Try|While'):
391
+ super().__init__()
392
+ self.root = parent.body.create_if()
393
+
394
+ def build(self, node):
395
+ self.root.config(lineno=node.lineno, error=format_error(self._get_errors(node)))
396
+ assign = node.assign
397
+ node_type = None
398
+ while node:
399
+ node_type = node.type if node.type != 'INLINE IF' else 'IF'
400
+ self.model = self.root.body.create_branch(node_type, node.condition,
401
+ lineno=node.lineno)
402
+ for step in node.body:
403
+ self.visit(step)
404
+ if assign:
405
+ for item in self.model.body:
406
+ # Having assign when model item doesn't support assign is an error,
407
+ # but it has been handled already when model was validated.
408
+ if hasattr(item, 'assign'):
409
+ item.assign = assign
410
+ node = node.orelse
411
+ # Smallish hack to make sure assignment is always run.
412
+ if assign and node_type != 'ELSE':
413
+ self.root.body.create_branch('ELSE').body.create_keyword(
414
+ assign=assign, name='BuiltIn.Set Variable', args=['${NONE}']
415
+ )
416
+ return self.root
417
+
418
+ def _get_errors(self, node):
419
+ errors = node.header.errors + node.errors
420
+ if node.orelse:
421
+ errors += self._get_errors(node.orelse)
422
+ if node.end:
423
+ errors += node.end.errors
424
+ return errors
425
+
426
+
427
+ class TryBuilder(BodyBuilder):
428
+ model: 'TryBranch|None'
429
+
430
+ def __init__(self, parent: 'TestCase|UserKeyword|For|If|Try|While'):
431
+ super().__init__()
432
+ self.root = parent.body.create_try()
433
+ self.template_error = None
434
+
435
+ def build(self, node):
436
+ self.root.config(lineno=node.lineno)
437
+ errors = self._get_errors(node)
438
+ while node:
439
+ self.model = self.root.body.create_branch(node.type, node.patterns,
440
+ node.pattern_type, node.assign,
441
+ lineno=node.lineno)
442
+ for step in node.body:
443
+ self.visit(step)
444
+ node = node.next
445
+ if self.template_error:
446
+ errors += (self.template_error,)
447
+ if errors:
448
+ self.root.error = format_error(errors)
449
+ return self.root
450
+
451
+ def _get_errors(self, node):
452
+ errors = node.header.errors + node.errors
453
+ if node.next:
454
+ errors += self._get_errors(node.next)
455
+ if node.end:
456
+ errors += node.end.errors
457
+ return errors
458
+
459
+ def visit_TemplateArguments(self, node):
460
+ self.template_error = 'Templates cannot be used with TRY.'
461
+
462
+
463
+ class WhileBuilder(BodyBuilder):
464
+ model: While
465
+
466
+ def __init__(self, parent: 'TestCase|UserKeyword|For|If|Try|While'):
467
+ super().__init__(parent.body.create_while())
468
+
469
+ def build(self, node):
470
+ error = format_error(self._get_errors(node))
471
+ self.model.config(condition=node.condition, limit=node.limit,
472
+ on_limit=node.on_limit, on_limit_message=node.on_limit_message,
473
+ lineno=node.lineno, error=error)
474
+ for step in node.body:
475
+ self.visit(step)
476
+ return self.model
477
+
478
+ def _get_errors(self, node):
479
+ errors = node.header.errors + node.errors
480
+ if node.end:
481
+ errors += node.end.errors
482
+ return errors
483
+
484
+
485
+ def format_error(errors):
486
+ if not errors:
487
+ return None
488
+ if len(errors) == 1:
489
+ return errors[0]
490
+ return '\n- '.join(('Multiple errors:',) + errors)
491
+
492
+
493
+ class ErrorReporter(ModelVisitor):
494
+
495
+ def __init__(self, source, raise_on_invalid_header=False):
496
+ self.source = source
497
+ self.raise_on_invalid_header = raise_on_invalid_header
498
+
499
+ def visit_TestCase(self, node):
500
+ pass
501
+
502
+ def visit_Keyword(self, node):
503
+ pass
504
+
505
+ def visit_ReturnSetting(self, node):
506
+ # Empty 'visit_Keyword' above prevents calling this when visiting the whole
507
+ # model, but 'KeywordBuilder.visit_ReturnSetting' visits the node it gets.
508
+ self.report_error(node.get_token(Token.RETURN_SETTING), warn=True)
509
+
510
+ def visit_SectionHeader(self, node):
511
+ token = node.get_token(*Token.HEADER_TOKENS)
512
+ if not token.error:
513
+ return
514
+ if token.type == Token.INVALID_HEADER:
515
+ self.report_error(token, throw=self.raise_on_invalid_header)
516
+ else:
517
+ # Errors, other than totally invalid headers, can occur only with
518
+ # deprecated singular headers, and we want to report them as warnings.
519
+ # A more generic solution for separating errors and warnings would be good.
520
+ self.report_error(token, warn=True)
521
+
522
+ def visit_Error(self, node):
523
+ for token in node.get_tokens(Token.ERROR):
524
+ self.report_error(token)
525
+
526
+ def report_error(self, source, error=None, warn=False, throw=False):
527
+ if not error:
528
+ if isinstance(source, Token):
529
+ error = source.error
530
+ else:
531
+ error = format_error(source.errors)
532
+ message = f"Error in file '{self.source}' on line {source.lineno}: {error}"
533
+ if throw:
534
+ raise DataError(message)
535
+ LOGGER.write(message, level='WARN' if warn else 'ERROR')