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
@@ -13,17 +13,19 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import re
17
+
16
18
  from robot.output import LEVELS
19
+ from robot.result import Error, Keyword, Message, Return
17
20
 
18
21
  from .jsbuildingcontext import JsBuildingContext
19
22
  from .jsexecutionresult import JsExecutionResult
20
23
 
21
-
22
24
  STATUSES = {'FAIL': 0, 'PASS': 1, 'SKIP': 2, 'NOT RUN': 3}
23
25
  KEYWORD_TYPES = {'KEYWORD': 0, 'SETUP': 1, 'TEARDOWN': 2,
24
26
  'FOR': 3, 'ITERATION': 4, 'IF': 5, 'ELSE IF': 6, 'ELSE': 7,
25
- 'RETURN': 8, 'TRY': 9, 'EXCEPT': 10, 'FINALLY': 11, 'WHILE': 12,
26
- 'CONTINUE': 13, 'BREAK': 14, 'ERROR': 15}
27
+ 'RETURN': 8, 'VAR': 9, 'TRY': 10, 'EXCEPT': 11, 'FINALLY': 12,
28
+ 'WHILE': 13, 'CONTINUE': 14, 'BREAK': 15, 'ERROR': 16}
27
29
 
28
30
 
29
31
  class JsModelBuilder:
@@ -47,49 +49,61 @@ class JsModelBuilder:
47
49
  )
48
50
 
49
51
 
50
- class _Builder:
52
+ class Builder:
53
+ robot_note = re.compile('<span class="robot-note">(.*)</span>')
51
54
 
52
- def __init__(self, context):
55
+ def __init__(self, context: JsBuildingContext):
53
56
  self._context = context
54
57
  self._string = self._context.string
55
58
  self._html = self._context.html
56
59
  self._timestamp = self._context.timestamp
57
60
 
58
- def _get_status(self, item):
61
+ def _get_status(self, item, note_only=False):
59
62
  model = (STATUSES[item.status],
60
- self._timestamp(item.starttime),
61
- item.elapsedtime)
62
- msg = getattr(item, 'message', '')
63
+ self._timestamp(item.start_time),
64
+ round(item.elapsed_time.total_seconds() * 1000))
65
+ msg = item.message
63
66
  if not msg:
64
67
  return model
65
- elif msg.startswith('*HTML*'):
66
- msg = self._string(msg[6:].lstrip(), escape=False)
68
+ if note_only:
69
+ if msg.startswith('*HTML*'):
70
+ match = self.robot_note.search(msg)
71
+ if match:
72
+ index = self._string(match.group(1))
73
+ return model + (index,)
74
+ return model
75
+ if msg.startswith('*HTML*'):
76
+ index = self._string(msg[6:].lstrip(), escape=False)
67
77
  else:
68
- msg = self._string(msg)
69
- return model + (msg,)
78
+ index = self._string(msg)
79
+ return model + (index,)
70
80
 
71
- def _build_keywords(self, steps, split=False):
81
+ def _build_body(self, body, split=False):
72
82
  splitting = self._context.start_splitting_if_needed(split)
73
- # tuple([<listcomp>>]) is faster than tuple(<genex>) with short lists.
74
- model = tuple([self._build_keyword(step) for step in steps])
83
+ # tuple([<listcomp>]) is faster than tuple(<genex>) with short lists.
84
+ model = tuple([self._build_body_item(item) for item in body])
75
85
  return model if not splitting else self._context.end_splitting(model)
76
86
 
77
- def _build_keyword(self, step):
87
+ def _build_body_item(self, item):
78
88
  raise NotImplementedError
79
89
 
80
90
 
81
- class SuiteBuilder(_Builder):
91
+ class SuiteBuilder(Builder):
82
92
 
83
93
  def __init__(self, context):
84
- _Builder.__init__(self, context)
94
+ super().__init__(context)
85
95
  self._build_suite = self.build
86
96
  self._build_test = TestBuilder(context).build
87
- self._build_keyword = KeywordBuilder(context).build
97
+ self._build_body_item = BodyItemBuilder(context).build
88
98
 
89
99
  def build(self, suite):
90
100
  with self._context.prune_input(suite.tests, suite.suites):
91
101
  stats = self._get_statistics(suite) # Must be done before pruning
92
- kws = [kw for kw in (suite.setup, suite.teardown) if kw]
102
+ fixture = []
103
+ if suite.has_setup:
104
+ fixture.append(suite.setup)
105
+ if suite.has_teardown:
106
+ fixture.append(suite.teardown)
93
107
  return (self._string(suite.name, attr=True),
94
108
  self._string(suite.source),
95
109
  self._context.relative_source(suite.source),
@@ -98,7 +112,7 @@ class SuiteBuilder(_Builder):
98
112
  self._get_status(suite),
99
113
  tuple(self._build_suite(s) for s in suite.suites),
100
114
  tuple(self._build_test(t) for t in suite.tests),
101
- tuple(self._build_keyword(k, split=True) for k in kws),
115
+ tuple(self._build_body_item(kw, split=True) for kw in fixture),
102
116
  stats)
103
117
 
104
118
  def _yield_metadata(self, suite):
@@ -111,63 +125,76 @@ class SuiteBuilder(_Builder):
111
125
  return (stats.total, stats.passed, stats.failed, stats.skipped)
112
126
 
113
127
 
114
- class TestBuilder(_Builder):
128
+ class TestBuilder(Builder):
115
129
 
116
130
  def __init__(self, context):
117
- _Builder.__init__(self, context)
118
- self._build_keyword = KeywordBuilder(context).build
131
+ super().__init__(context)
132
+ self._build_body_item = BodyItemBuilder(context).build
119
133
 
120
134
  def build(self, test):
121
- kws = self._get_keywords(test)
135
+ body = self._get_body_items(test)
122
136
  with self._context.prune_input(test.body):
123
137
  return (self._string(test.name, attr=True),
124
138
  self._string(test.timeout),
125
139
  self._html(test.doc),
126
140
  tuple(self._string(t) for t in test.tags),
127
141
  self._get_status(test),
128
- self._build_keywords(kws, split=True))
142
+ self._build_body(body, split=True))
129
143
 
130
- def _get_keywords(self, test):
131
- kws = []
132
- if test.setup:
133
- kws.append(test.setup)
134
- kws.extend(test.body.flatten())
135
- if test.teardown:
136
- kws.append(test.teardown)
137
- return kws
144
+ def _get_body_items(self, test):
145
+ body = test.body.flatten()
146
+ if test.has_setup:
147
+ body.insert(0, test.setup)
148
+ if test.has_teardown:
149
+ body.append(test.teardown)
150
+ return body
138
151
 
139
152
 
140
- class KeywordBuilder(_Builder):
153
+ class BodyItemBuilder(Builder):
141
154
 
142
155
  def __init__(self, context):
143
- _Builder.__init__(self, context)
144
- self._build_keyword = self.build
156
+ super().__init__(context)
157
+ self._build_body_item = self.build
145
158
  self._build_message = MessageBuilder(context).build
146
159
 
147
160
  def build(self, item, split=False):
148
- if item.type == item.MESSAGE:
161
+ if isinstance(item, Message):
149
162
  return self._build_message(item)
150
- return self.build_keyword(item, split)
151
-
152
- def build_keyword(self, kw, split=False):
163
+ with self._context.prune_input(item.body):
164
+ if isinstance (item, Keyword):
165
+ return self._build_keyword(item, split)
166
+ if isinstance(item, (Return, Error)):
167
+ return self._build(item, args=' '.join(item.values), split=split)
168
+ return self._build(item, item._log_name, split=split)
169
+
170
+ def _build_keyword(self, kw: Keyword, split):
153
171
  self._context.check_expansion(kw)
154
- items = kw.body.flatten()
155
- if getattr(kw, 'has_teardown', False):
156
- items.append(kw.teardown)
157
- with self._context.prune_input(kw.body):
158
- return (KEYWORD_TYPES[kw.type],
159
- self._string(kw.kwname, attr=True),
160
- self._string(kw.libname, attr=True),
161
- self._string(kw.timeout),
162
- self._html(kw.doc),
163
- self._string(', '.join(kw.args)),
164
- self._string(', '.join(kw.assign)),
165
- self._string(', '.join(kw.tags)),
166
- self._get_status(kw),
167
- self._build_keywords(items, split))
168
-
169
-
170
- class MessageBuilder(_Builder):
172
+ body = kw.body.flatten()
173
+ if kw.has_setup:
174
+ body.insert(0, kw.setup)
175
+ if kw.has_teardown:
176
+ body.append(kw.teardown)
177
+ return self._build(kw, kw.name, kw.owner, kw.timeout, kw.doc,
178
+ ' '.join(kw.args), ' '.join(kw.assign),
179
+ ', '.join(kw.tags), body, split=split)
180
+
181
+ def _build(self, item, name='', owner='', timeout='', doc='', args='', assign='',
182
+ tags='', body=None, split=False):
183
+ if body is None:
184
+ body = item.body.flatten()
185
+ return (KEYWORD_TYPES[item.type],
186
+ self._string(name, attr=True),
187
+ self._string(owner, attr=True),
188
+ self._string(timeout),
189
+ self._html(doc),
190
+ self._string(args),
191
+ self._string(assign),
192
+ self._string(tags),
193
+ self._get_status(item, note_only=True),
194
+ self._build_body(body, split))
195
+
196
+
197
+ class MessageBuilder(Builder):
171
198
 
172
199
  def build(self, msg):
173
200
  if msg.level in ('WARN', 'ERROR'):
@@ -196,10 +223,10 @@ class StatisticsBuilder:
196
223
  for stat in stats)
197
224
 
198
225
 
199
- class ErrorsBuilder(_Builder):
226
+ class ErrorsBuilder(Builder):
200
227
 
201
228
  def __init__(self, context):
202
- _Builder.__init__(self, context)
229
+ super().__init__(context)
203
230
  self._build_message = ErrorMessageBuilder(context).build
204
231
 
205
232
  def build(self, errors):
@@ -13,10 +13,11 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from pathlib import Path
16
17
  from os.path import basename, splitext
17
18
 
18
19
  from robot.htmldata import HtmlFileWriter, ModelWriter, LOG, REPORT
19
- from robot.utils import file_writer, is_string
20
+ from robot.utils import file_writer
20
21
 
21
22
  from .jswriter import JsResultWriter, SplitLogWriter
22
23
 
@@ -27,9 +28,9 @@ class _LogReportWriter:
27
28
  def __init__(self, js_model):
28
29
  self._js_model = js_model
29
30
 
30
- def _write_file(self, path, config, template):
31
+ def _write_file(self, path: Path, config, template):
31
32
  outfile = file_writer(path, usage=self.usage) \
32
- if is_string(path) else path # unit test hook
33
+ if isinstance(path, Path) else path # unit test hook
33
34
  with outfile:
34
35
  model_writer = RobotModelWriter(outfile, self._js_model, config)
35
36
  writer = HtmlFileWriter(outfile, model_writer)
@@ -39,26 +40,31 @@ class _LogReportWriter:
39
40
  class LogWriter(_LogReportWriter):
40
41
  usage = 'log'
41
42
 
42
- def write(self, path, config):
43
+ def write(self, path: 'Path|str', config):
44
+ if isinstance(path, str):
45
+ path = Path(path)
43
46
  self._write_file(path, config, LOG)
44
47
  if self._js_model.split_results:
45
- self._write_split_logs(splitext(path)[0])
48
+ self._write_split_logs(path)
46
49
 
47
- def _write_split_logs(self, base):
50
+ def _write_split_logs(self, path: Path):
48
51
  for index, (keywords, strings) in enumerate(self._js_model.split_results,
49
52
  start=1):
50
- self._write_split_log(index, keywords, strings, '%s-%d.js' % (base, index))
53
+ name = f'{path.stem}-{index}.js'
54
+ self._write_split_log(index, keywords, strings, path.with_name(name))
51
55
 
52
- def _write_split_log(self, index, keywords, strings, path):
56
+ def _write_split_log(self, index, keywords, strings, path: Path):
53
57
  with file_writer(path, usage=self.usage) as outfile:
54
58
  writer = SplitLogWriter(outfile)
55
- writer.write(keywords, strings, index, basename(path))
59
+ writer.write(keywords, strings, index, path.name)
56
60
 
57
61
 
58
62
  class ReportWriter(_LogReportWriter):
59
63
  usage = 'report'
60
64
 
61
- def write(self, path, config):
65
+ def write(self, path: 'Path|str', config):
66
+ if isinstance(path, str):
67
+ path = Path(path)
62
68
  self._write_file(path, config, REPORT)
63
69
 
64
70
 
@@ -13,13 +13,29 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- from robot.output.xmllogger import XmlLogger
16
+ from robot.output.xmllogger import XmlLogger, LegacyXmlLogger
17
17
 
18
18
 
19
19
  class OutputWriter(XmlLogger):
20
20
 
21
+ def __init__(self, output, rpa=False, suite_only=False):
22
+ super().__init__(output, rpa=rpa, generator='Rebot', suite_only=suite_only)
23
+
24
+ def start_message(self, msg):
25
+ self._write_message(msg)
26
+
27
+ def close(self):
28
+ self._writer.end('robot')
29
+ self._writer.close()
30
+
31
+ def end_result(self, result):
32
+ self.close()
33
+
34
+
35
+ class LegacyOutputWriter(LegacyXmlLogger):
36
+
21
37
  def __init__(self, output, rpa=False):
22
- XmlLogger.__init__(self, output, rpa=rpa, generator='Rebot')
38
+ super().__init__(output, rpa=rpa, generator='Rebot')
23
39
 
24
40
  def start_message(self, msg):
25
41
  self._write_message(msg)
@@ -54,7 +54,7 @@ class ResultWriter:
54
54
  settings = settings or RebotSettings(options)
55
55
  results = Results(settings, *self._sources)
56
56
  if settings.output:
57
- self._write_output(results.result, settings.output)
57
+ self._write_output(results.result, settings.output, settings.legacy_output)
58
58
  if settings.xunit:
59
59
  self._write_xunit(results.result, settings.xunit)
60
60
  if settings.log:
@@ -67,8 +67,8 @@ class ResultWriter:
67
67
  settings.report_config)
68
68
  return results.return_code
69
69
 
70
- def _write_output(self, result, path):
71
- self._write('Output', result.save, path)
70
+ def _write_output(self, result, path, legacy_output=False):
71
+ self._write('Output', result.save, path, legacy_output)
72
72
 
73
73
  def _write_xunit(self, result, path):
74
74
  self._write('XUnit', XUnitWriter(result).write, path)
@@ -85,7 +85,7 @@ class ResultWriter:
85
85
  except DataError as err:
86
86
  LOGGER.error(err.message)
87
87
  else:
88
- LOGGER.output_file(name, path)
88
+ LOGGER.result_file(name, path)
89
89
 
90
90
 
91
91
  class Results:
@@ -21,16 +21,16 @@ class StringIndex(int):
21
21
 
22
22
 
23
23
  class StringCache:
24
+ empty = StringIndex(0)
24
25
  _compress_threshold = 80
25
26
  _use_compressed_threshold = 1.1
26
- _zero_index = StringIndex(0)
27
27
 
28
28
  def __init__(self):
29
- self._cache = {('', False): self._zero_index}
29
+ self._cache = {('', False): self.empty}
30
30
 
31
31
  def add(self, text, html=False):
32
32
  if not text:
33
- return self._zero_index
33
+ return self.empty
34
34
  key = (text, html)
35
35
  if key not in self._cache:
36
36
  self._cache[key] = StringIndex(len(self._cache))
@@ -13,7 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- from robot.result import ResultVisitor
16
+ from robot.result import ResultVisitor, TestCase, TestSuite
17
17
  from robot.utils import XmlWriter
18
18
 
19
19
 
@@ -38,32 +38,34 @@ class XUnitFileWriter(ResultVisitor):
38
38
  def __init__(self, xml_writer):
39
39
  self._writer = xml_writer
40
40
 
41
- def start_suite(self, suite):
41
+ def start_suite(self, suite: TestSuite):
42
42
  stats = suite.statistics # Accessing property only once.
43
43
  attrs = {'name': suite.name,
44
- 'tests': f'{stats.total}',
44
+ 'tests': str(stats.total),
45
45
  'errors': '0',
46
- 'failures': f'{stats.failed}',
47
- 'skipped': f'{stats.skipped}',
48
- 'time': self._time_as_seconds(suite.elapsedtime),
49
- 'timestamp' : self._starttime_to_isoformat(suite.starttime)}
46
+ 'failures': str(stats.failed),
47
+ 'skipped': str(stats.skipped),
48
+ 'time': format(suite.elapsed_time.total_seconds(), '.3f'),
49
+ 'timestamp': suite.start_time.isoformat() if suite.start_time else None}
50
50
  self._writer.start('testsuite', attrs)
51
51
 
52
- def end_suite(self, suite):
52
+ def end_suite(self, suite: TestSuite):
53
53
  if suite.metadata or suite.doc:
54
54
  self._writer.start('properties')
55
55
  if suite.doc:
56
- self._writer.element('property', attrs={'name': 'Documentation', 'value': suite.doc})
56
+ self._writer.element('property', attrs={'name': 'Documentation',
57
+ 'value': suite.doc})
57
58
  for meta_name, meta_value in suite.metadata.items():
58
- self._writer.element('property', attrs={'name': meta_name, 'value': meta_value})
59
+ self._writer.element('property', attrs={'name': meta_name,
60
+ 'value': meta_value})
59
61
  self._writer.end('properties')
60
62
  self._writer.end('testsuite')
61
63
 
62
- def visit_test(self, test):
64
+ def visit_test(self, test: TestCase):
63
65
  self._writer.start('testcase',
64
- {'classname': test.parent.longname,
66
+ {'classname': test.parent.full_name,
65
67
  'name': test.name,
66
- 'time': self._time_as_seconds(test.elapsedtime)})
68
+ 'time': format(test.elapsed_time.total_seconds(), '.3f')})
67
69
  if test.failed:
68
70
  self._writer.element('failure', attrs={'message': test.message,
69
71
  'type': 'AssertionError'})
@@ -72,9 +74,6 @@ class XUnitFileWriter(ResultVisitor):
72
74
  'type': 'SkipExecution'})
73
75
  self._writer.end('testcase')
74
76
 
75
- def _time_as_seconds(self, millis):
76
- return format(millis / 1000, '.3f')
77
-
78
77
  def visit_keyword(self, kw):
79
78
  pass
80
79
 
@@ -86,8 +85,3 @@ class XUnitFileWriter(ResultVisitor):
86
85
 
87
86
  def end_result(self, result):
88
87
  self._writer.close()
89
-
90
- def _starttime_to_isoformat(self, stime):
91
- if not stime:
92
- return None
93
- return f'{stime[:4]}-{stime[4:6]}-{stime[6:8]}T{stime[9:22]}000'
@@ -38,7 +38,8 @@ __ http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#
38
38
  """
39
39
 
40
40
  from .executionresult import Result
41
- from .model import (Break, Continue, Error, For, ForIteration, If, IfBranch, Keyword, Message,
42
- Return, TestCase, TestSuite, Try, TryBranch, While, WhileIteration)
41
+ from .model import (Break, Continue, Error, For, ForIteration, If, IfBranch, Keyword,
42
+ Message, Return, TestCase, TestSuite, Try, TryBranch, Var, While,
43
+ WhileIteration)
43
44
  from .resultbuilder import ExecutionResult, ExecutionResultBuilder
44
45
  from .visitor import ResultVisitor
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
 
16
16
  from robot import model
17
- from robot.utils import is_string, secs_to_timestamp, timestamp_to_secs
17
+ from robot.utils import is_string, parse_timestamp
18
18
 
19
19
 
20
20
  class SuiteConfigurer(model.SuiteConfigurer):
@@ -32,11 +32,11 @@ class SuiteConfigurer(model.SuiteConfigurer):
32
32
 
33
33
  def __init__(self, remove_keywords=None, log_level=None, start_time=None,
34
34
  end_time=None, **base_config):
35
- model.SuiteConfigurer.__init__(self, **base_config)
35
+ super().__init__(**base_config)
36
36
  self.remove_keywords = self._get_remove_keywords(remove_keywords)
37
37
  self.log_level = log_level
38
- self.start_time = self._get_time(start_time)
39
- self.end_time = self._get_time(end_time)
38
+ self.start_time = self._to_datetime(start_time)
39
+ self.end_time = self._to_datetime(end_time)
40
40
 
41
41
  def _get_remove_keywords(self, value):
42
42
  if value is None:
@@ -45,14 +45,13 @@ class SuiteConfigurer(model.SuiteConfigurer):
45
45
  return [value]
46
46
  return value
47
47
 
48
- def _get_time(self, timestamp):
48
+ def _to_datetime(self, timestamp):
49
49
  if not timestamp:
50
50
  return None
51
51
  try:
52
- secs = timestamp_to_secs(timestamp, seps=' :.-_')
52
+ return parse_timestamp(timestamp)
53
53
  except ValueError:
54
54
  return None
55
- return secs_to_timestamp(secs, millis=True)
56
55
 
57
56
  def visit_suite(self, suite):
58
57
  model.SuiteConfigurer.visit_suite(self, suite)
@@ -66,6 +65,10 @@ class SuiteConfigurer(model.SuiteConfigurer):
66
65
 
67
66
  def _set_times(self, suite):
68
67
  if self.start_time:
69
- suite.starttime = self.start_time
68
+ suite.end_time = suite.end_time # Preserve original value.
69
+ suite.elapsed_time = None # Force re-calculation.
70
+ suite.start_time = self.start_time
70
71
  if self.end_time:
71
- suite.endtime = self.end_time
72
+ suite.start_time = suite.start_time
73
+ suite.elapsed_time = None
74
+ suite.end_time = self.end_time
@@ -13,6 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from pathlib import Path
17
+
16
18
  from robot.errors import DataError
17
19
  from robot.model import Statistics
18
20
 
@@ -20,6 +22,28 @@ from .executionerrors import ExecutionErrors
20
22
  from .model import TestSuite
21
23
 
22
24
 
25
+ def is_json_source(source):
26
+ if isinstance(source, bytes):
27
+ # Latin-1 is most likely not the right encoding, but decoding bytes with it
28
+ # always succeeds and characters we care about will be correct as well.
29
+ source = source.decode('Latin-1')
30
+ if isinstance(source, str):
31
+ source = source.strip()
32
+ first, last = (source[0], source[-1]) if source else ('', '')
33
+ if (first, last) == ('{', '}'):
34
+ return True
35
+ if (first, last) == ('<', '>'):
36
+ return False
37
+ path = Path(source)
38
+ elif isinstance(source, Path):
39
+ path = source
40
+ elif hasattr(source, 'name') and isinstance(source.name, str):
41
+ path = Path(source.name)
42
+ else:
43
+ return False
44
+ return bool(path and path.suffix.lower() == '.json')
45
+
46
+
23
47
  class Result:
24
48
  """Test execution results.
25
49
 
@@ -96,14 +120,38 @@ class Result:
96
120
  self._status_rc = status_rc
97
121
  self._stat_config = stat_config or {}
98
122
 
99
- def save(self, path=None):
100
- """Save results as a new output XML file.
101
-
102
- :param path: Path to save results to. If omitted, overwrites the
103
- original file.
123
+ def save(self, target=None, legacy_output=False):
124
+ """Save results as XML or JSON file.
125
+
126
+ :param target: Target where to save results to. Can be a path
127
+ (``pathlib.Path`` or ``str``) or an open file object. If omitted,
128
+ uses the :attr:`source` which overwrites the original file.
129
+ :param legacy_output: Save result in Robot Framework 6.x compatible
130
+ format. New in Robot Framework 7.0.
131
+
132
+ File type is got based on the ``target``. The type is JSON if the ``target``
133
+ is a path that has a ``.json`` suffix or if it is an open file that has
134
+ a ``name`` attribute with a ``.json`` suffix. Otherwise, the type is XML.
135
+
136
+ Notice that saved JSON files only contain suite information, no statics
137
+ or errors like XML files. This is likely to change in the future so
138
+ that JSON files get a new root object with the current suite as a child
139
+ and statics and errors as additional children. Robot Framework's own
140
+ functions and methods accepting JSON results will continue to work
141
+ also with JSON files containing only a suite.
104
142
  """
105
- from robot.reporting.outputwriter import OutputWriter
106
- self.visit(OutputWriter(path or self.source, rpa=self.rpa))
143
+ from robot.reporting.outputwriter import LegacyOutputWriter, OutputWriter
144
+
145
+ target = target or self.source
146
+ if not target:
147
+ raise ValueError('Path required.')
148
+ if is_json_source(target):
149
+ # This writes only suite information, not stats or errors. This
150
+ # should be changed when we add JSON support to execution.
151
+ self.suite.to_json(target)
152
+ else:
153
+ writer = OutputWriter if not legacy_output else LegacyOutputWriter
154
+ self.visit(writer(target, rpa=self.rpa))
107
155
 
108
156
  def visit(self, visitor):
109
157
  """An entry point to visit the whole result object.
@@ -142,7 +190,7 @@ class CombinedResult(Result):
142
190
  """Combined results of multiple test executions."""
143
191
 
144
192
  def __init__(self, results=None):
145
- Result.__init__(self)
193
+ super().__init__()
146
194
  for result in results or ():
147
195
  self.add_result(result)
148
196