robotframework 7.1rc2__zip → 7.2b1__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 (286) hide show
  1. {robotframework-7.1rc2 → robotframework-7.2b1}/BUILD.rst +7 -7
  2. {robotframework-7.1rc2 → robotframework-7.2b1}/PKG-INFO +2 -2
  3. {robotframework-7.1rc2 → robotframework-7.2b1}/setup.py +1 -1
  4. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/__init__.py +33 -9
  5. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/deco.py +8 -6
  6. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/interfaces.py +66 -15
  7. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/parsing.py +72 -68
  8. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/conf/languages.py +4 -3
  9. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/conf/settings.py +11 -10
  10. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/errors.py +3 -3
  11. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/htmlfilewriter.py +3 -0
  12. robotframework-7.2b1/src/robot/htmldata/libdoc/libdoc.html +408 -0
  13. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/log.html +1 -1
  14. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/report.html +1 -1
  15. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/testdata.js +1 -1
  16. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/template.py +0 -2
  17. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdoc.py +19 -11
  18. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/htmlwriter.py +7 -4
  19. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/model.py +7 -5
  20. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/writer.py +2 -2
  21. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/BuiltIn.py +121 -32
  22. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Collections.py +20 -7
  23. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/__init__.py +3 -3
  24. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/body.py +48 -57
  25. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/control.py +35 -4
  26. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/message.py +13 -8
  27. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/modelobject.py +26 -0
  28. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/statistics.py +13 -9
  29. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/stats.py +12 -14
  30. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/suitestatistics.py +8 -9
  31. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/tags.py +10 -0
  32. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/tagstatistics.py +7 -8
  33. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/testcase.py +1 -0
  34. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/testsuite.py +1 -0
  35. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/totalstatistics.py +14 -21
  36. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/visitor.py +29 -3
  37. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/__init__.py +3 -2
  38. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/console/dotted.py +6 -3
  39. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/console/highlighting.py +18 -10
  40. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/debugfile.py +3 -3
  41. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/filelogger.py +7 -3
  42. robotframework-7.2b1/src/robot/output/jsonlogger.py +338 -0
  43. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/librarylogger.py +12 -11
  44. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/listeners.py +49 -47
  45. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/logger.py +33 -20
  46. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/loggerapi.py +6 -0
  47. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/loggerhelper.py +29 -57
  48. robotframework-7.2b1/src/robot/output/loglevel.py +54 -0
  49. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/output.py +21 -17
  50. robotframework-7.2b1/src/robot/output/outputfile.py +174 -0
  51. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/pyloggingconf.py +2 -0
  52. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/xmllogger.py +40 -169
  53. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/blocklexers.py +25 -12
  54. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/statementlexers.py +16 -7
  55. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/tokens.py +2 -1
  56. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/model/__init__.py +1 -1
  57. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/model/blocks.py +34 -2
  58. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/model/statements.py +32 -2
  59. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/parser/blockparsers.py +7 -2
  60. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/rebot.py +10 -2
  61. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/jsmodelbuilders.py +1 -1
  62. robotframework-7.2b1/src/robot/reporting/outputwriter.py +30 -0
  63. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/__init__.py +1 -1
  64. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/executionerrors.py +9 -9
  65. robotframework-7.2b1/src/robot/result/executionresult.py +331 -0
  66. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/messagefilter.py +14 -10
  67. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/model.py +90 -18
  68. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/resultbuilder.py +2 -5
  69. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/xmlelementhandlers.py +20 -9
  70. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/run.py +18 -6
  71. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/__init__.py +1 -1
  72. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/embedded.py +7 -6
  73. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/typeconverters.py +14 -2
  74. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/typeinfo.py +23 -4
  75. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/bodyrunner.py +41 -0
  76. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/builder/settings.py +2 -1
  77. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/builder/transformers.py +46 -20
  78. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/context.py +22 -11
  79. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/librarykeyword.py +1 -1
  80. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/librarykeywordrunner.py +29 -23
  81. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/model.py +31 -4
  82. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/outputcapture.py +2 -1
  83. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/signalhandler.py +7 -3
  84. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/status.py +49 -38
  85. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/statusreporter.py +1 -1
  86. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/suiterunner.py +22 -15
  87. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/userkeywordrunner.py +4 -0
  88. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/importer.py +39 -23
  89. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/unic.py +7 -8
  90. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/evaluation.py +21 -2
  91. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/replacer.py +20 -24
  92. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/scopes.py +19 -9
  93. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/variables.py +4 -1
  94. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/version.py +1 -1
  95. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robotframework.egg-info/PKG-INFO +2 -2
  96. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robotframework.egg-info/SOURCES.txt +3 -4
  97. robotframework-7.1rc2/src/robot/htmldata/libdoc/doc_formatting.css +0 -74
  98. robotframework-7.1rc2/src/robot/htmldata/libdoc/libdoc.css +0 -747
  99. robotframework-7.1rc2/src/robot/htmldata/libdoc/libdoc.html +0 -702
  100. robotframework-7.1rc2/src/robot/htmldata/libdoc/print.css +0 -11
  101. robotframework-7.1rc2/src/robot/htmldata/libdoc/pygments.css +0 -162
  102. robotframework-7.1rc2/src/robot/reporting/outputwriter.py +0 -48
  103. robotframework-7.1rc2/src/robot/result/executionresult.py +0 -201
  104. {robotframework-7.1rc2 → robotframework-7.2b1}/AUTHORS.rst +0 -0
  105. {robotframework-7.1rc2 → robotframework-7.2b1}/CONTRIBUTING.rst +0 -0
  106. {robotframework-7.1rc2 → robotframework-7.2b1}/COPYRIGHT.txt +0 -0
  107. {robotframework-7.1rc2 → robotframework-7.2b1}/INSTALL.rst +0 -0
  108. {robotframework-7.1rc2 → robotframework-7.2b1}/LICENSE.txt +0 -0
  109. {robotframework-7.1rc2 → robotframework-7.2b1}/MANIFEST.in +0 -0
  110. {robotframework-7.1rc2 → robotframework-7.2b1}/README.rst +0 -0
  111. {robotframework-7.1rc2 → robotframework-7.2b1}/setup.cfg +0 -0
  112. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/__init__.py +0 -0
  113. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/__main__.py +0 -0
  114. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/exceptions.py +0 -0
  115. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/logger.py +0 -0
  116. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/api/py.typed +0 -0
  117. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/conf/__init__.py +0 -0
  118. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/conf/gatherfailed.py +0 -0
  119. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/__init__.py +0 -0
  120. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/common/__init__.py +0 -0
  121. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/common/js_disabled.css +0 -0
  122. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/common/storage.js +0 -0
  123. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/jsonwriter.py +0 -0
  124. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/__init__.py +0 -0
  125. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
  126. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/jquery.min.js +0 -0
  127. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
  128. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
  129. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
  130. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/libdoc/__init__.py +0 -0
  131. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/__init__.py +0 -0
  132. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/common.css +0 -0
  133. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/doc_formatting.css +0 -0
  134. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/fileloading.js +0 -0
  135. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/log.css +0 -0
  136. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/log.js +0 -0
  137. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/model.js +0 -0
  138. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/print.css +0 -0
  139. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/report.css +0 -0
  140. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/util.js +0 -0
  141. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/rebot/view.js +0 -0
  142. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/testdoc/__init__.py +0 -0
  143. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/testdoc/testdoc.css +0 -0
  144. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/htmldata/testdoc/testdoc.html +0 -0
  145. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/__init__.py +0 -0
  146. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/builder.py +0 -0
  147. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/consoleviewer.py +0 -0
  148. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/datatypes.py +0 -0
  149. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/htmlutils.py +0 -0
  150. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/jsonbuilder.py +0 -0
  151. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/jsonwriter.py +0 -0
  152. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/output.py +0 -0
  153. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/robotbuilder.py +0 -0
  154. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/standardtypes.py +0 -0
  155. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/xmlbuilder.py +0 -0
  156. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libdocpkg/xmlwriter.py +0 -0
  157. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/DateTime.py +0 -0
  158. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Dialogs.py +0 -0
  159. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Easter.py +0 -0
  160. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/OperatingSystem.py +0 -0
  161. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Process.py +0 -0
  162. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Remote.py +0 -0
  163. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Screenshot.py +0 -0
  164. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/String.py +0 -0
  165. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/Telnet.py +0 -0
  166. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/XML.py +0 -0
  167. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/__init__.py +0 -0
  168. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/libraries/dialogs_py.py +0 -0
  169. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/configurer.py +0 -0
  170. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/filter.py +0 -0
  171. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/fixture.py +0 -0
  172. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/itemlist.py +0 -0
  173. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/keyword.py +0 -0
  174. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/metadata.py +0 -0
  175. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/modifier.py +0 -0
  176. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/namepatterns.py +0 -0
  177. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/model/tagsetter.py +0 -0
  178. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/console/__init__.py +0 -0
  179. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/console/quiet.py +0 -0
  180. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/console/verbose.py +0 -0
  181. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/output/stdoutlogsplitter.py +0 -0
  182. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/__init__.py +0 -0
  183. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/__init__.py +0 -0
  184. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/context.py +0 -0
  185. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/lexer.py +0 -0
  186. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/settings.py +0 -0
  187. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/lexer/tokenizer.py +0 -0
  188. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/model/visitor.py +0 -0
  189. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/parser/__init__.py +0 -0
  190. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/parser/fileparser.py +0 -0
  191. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/parser/parser.py +0 -0
  192. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/parsing/suitestructure.py +0 -0
  193. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/pythonpathsetter.py +0 -0
  194. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/__init__.py +0 -0
  195. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/expandkeywordmatcher.py +0 -0
  196. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/jsbuildingcontext.py +0 -0
  197. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/jsexecutionresult.py +0 -0
  198. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/jswriter.py +0 -0
  199. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/logreportwriters.py +0 -0
  200. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/resultwriter.py +0 -0
  201. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/stringcache.py +0 -0
  202. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/reporting/xunitwriter.py +0 -0
  203. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/configurer.py +0 -0
  204. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/flattenkeywordmatcher.py +0 -0
  205. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/keywordremover.py +0 -0
  206. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/merger.py +0 -0
  207. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/modeldeprecation.py +0 -0
  208. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/suiteteardownfailed.py +0 -0
  209. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/result/visitor.py +0 -0
  210. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/__init__.py +0 -0
  211. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentconverter.py +0 -0
  212. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentmapper.py +0 -0
  213. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentparser.py +0 -0
  214. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentresolver.py +0 -0
  215. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentspec.py +0 -0
  216. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/argumentvalidator.py +0 -0
  217. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/customconverters.py +0 -0
  218. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/typeinfoparser.py +0 -0
  219. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/arguments/typevalidator.py +0 -0
  220. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/builder/__init__.py +0 -0
  221. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/builder/builders.py +0 -0
  222. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/builder/parsers.py +0 -0
  223. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/dynamicmethods.py +0 -0
  224. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/importer.py +0 -0
  225. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/invalidkeyword.py +0 -0
  226. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/keywordfinder.py +0 -0
  227. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/keywordimplementation.py +0 -0
  228. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/libraryscopes.py +0 -0
  229. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/namespace.py +0 -0
  230. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/randomizer.py +0 -0
  231. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/resourcemodel.py +0 -0
  232. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/runkwregister.py +0 -0
  233. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/testlibraries.py +0 -0
  234. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/timeouts/__init__.py +0 -0
  235. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/timeouts/nosupport.py +0 -0
  236. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/timeouts/posix.py +0 -0
  237. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/running/timeouts/windows.py +0 -0
  238. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/testdoc.py +0 -0
  239. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/__init__.py +0 -0
  240. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/application.py +0 -0
  241. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/argumentparser.py +0 -0
  242. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/asserts.py +0 -0
  243. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/charwidth.py +0 -0
  244. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/compress.py +0 -0
  245. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/connectioncache.py +0 -0
  246. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/dotdict.py +0 -0
  247. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/encoding.py +0 -0
  248. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/encodingsniffer.py +0 -0
  249. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/error.py +0 -0
  250. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/escaping.py +0 -0
  251. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/etreewrapper.py +0 -0
  252. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/filereader.py +0 -0
  253. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/frange.py +0 -0
  254. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/htmlformatters.py +0 -0
  255. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/markuputils.py +0 -0
  256. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/markupwriters.py +0 -0
  257. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/match.py +0 -0
  258. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/misc.py +0 -0
  259. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/normalizing.py +0 -0
  260. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/notset.py +0 -0
  261. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/platform.py +0 -0
  262. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/recommendations.py +0 -0
  263. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/restreader.py +0 -0
  264. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robotenv.py +0 -0
  265. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robotinspect.py +0 -0
  266. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robotio.py +0 -0
  267. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robotpath.py +0 -0
  268. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robottime.py +0 -0
  269. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/robottypes.py +0 -0
  270. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/setter.py +0 -0
  271. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/sortable.py +0 -0
  272. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/text.py +0 -0
  273. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/utils/typehints.py +0 -0
  274. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/__init__.py +0 -0
  275. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/assigner.py +0 -0
  276. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/filesetter.py +0 -0
  277. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/finders.py +0 -0
  278. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/notfound.py +0 -0
  279. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/resolvable.py +0 -0
  280. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/search.py +0 -0
  281. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/store.py +0 -0
  282. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robot/variables/tablesetter.py +0 -0
  283. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robotframework.egg-info/dependency_links.txt +0 -0
  284. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robotframework.egg-info/entry_points.txt +0 -0
  285. {robotframework-7.1rc2 → robotframework-7.2b1}/src/robotframework.egg-info/top_level.txt +0 -0
  286. {robotframework-7.1rc2 → robotframework-7.2b1}/tasks.py +0 -0
@@ -17,6 +17,7 @@ import re
17
17
  from typing import (Any, Callable, cast, Generic, Iterable, Type, TYPE_CHECKING,
18
18
  TypeVar, Union)
19
19
 
20
+ from robot.errors import DataError
20
21
  from robot.utils import copy_signature, KnownAtRuntime
21
22
 
22
23
  from .itemlist import ItemList
@@ -24,8 +25,8 @@ from .modelobject import DataDict, full_name, ModelObject
24
25
 
25
26
  if TYPE_CHECKING:
26
27
  from robot.running.model import ResourceFile, UserKeyword
27
- from .control import (Break, Continue, Error, For, ForIteration, If, IfBranch,
28
- Return, Try, TryBranch, Var, While, WhileIteration)
28
+ from .control import (Break, Continue, Error, For, ForIteration, Group, If,
29
+ IfBranch, Return, Try, TryBranch, Var, While, WhileIteration)
29
30
  from .keyword import Keyword
30
31
  from .message import Message
31
32
  from .testcase import TestCase
@@ -33,12 +34,14 @@ if TYPE_CHECKING:
33
34
 
34
35
 
35
36
  BodyItemParent = Union['TestSuite', 'TestCase', 'UserKeyword', 'For', 'ForIteration',
36
- 'If', 'IfBranch', 'Try', 'TryBranch', 'While', 'WhileIteration',
37
- 'Keyword', 'Var', 'Return', 'Continue', 'Break', 'Error', None]
37
+ 'If', 'IfBranch', 'Try', 'TryBranch', 'While', 'Group',
38
+ 'WhileIteration', 'Keyword', 'Var', 'Return', 'Continue',
39
+ 'Break', 'Error', None]
38
40
  BI = TypeVar('BI', bound='BodyItem')
39
41
  KW = TypeVar('KW', bound='Keyword')
40
42
  F = TypeVar('F', bound='For')
41
43
  W = TypeVar('W', bound='While')
44
+ G = TypeVar('G', bound='Group')
42
45
  I = TypeVar('I', bound='If')
43
46
  T = TypeVar('T', bound='Try')
44
47
  V = TypeVar('V', bound='Var')
@@ -52,28 +55,7 @@ FW = TypeVar('FW', bound='ForIteration|WhileIteration')
52
55
 
53
56
 
54
57
  class BodyItem(ModelObject):
55
- KEYWORD = 'KEYWORD'
56
- SETUP = 'SETUP'
57
- TEARDOWN = 'TEARDOWN'
58
- FOR = 'FOR'
59
- ITERATION = 'ITERATION'
60
- IF_ELSE_ROOT = 'IF/ELSE ROOT'
61
- IF = 'IF'
62
- ELSE_IF = 'ELSE IF'
63
- ELSE = 'ELSE'
64
- TRY_EXCEPT_ROOT = 'TRY/EXCEPT ROOT'
65
- TRY = 'TRY'
66
- EXCEPT = 'EXCEPT'
67
- FINALLY = 'FINALLY'
68
- WHILE = 'WHILE'
69
- VAR = 'VAR'
70
- RETURN = 'RETURN'
71
- CONTINUE = 'CONTINUE'
72
- BREAK = 'BREAK'
73
- ERROR = 'ERROR'
74
- MESSAGE = 'MESSAGE'
75
- KEYWORD_TYPES = (KEYWORD, SETUP, TEARDOWN)
76
- type = None
58
+ body: 'BaseBody'
77
59
  __slots__ = ['parent']
78
60
 
79
61
  @property
@@ -99,28 +81,27 @@ class BodyItem(ModelObject):
99
81
  # or linking to warnings and errors won't work.
100
82
  steps = []
101
83
  if getattr(parent, 'has_setup', False):
102
- steps.append(parent.setup) # type: ignore - Use Protocol with RF 7.
84
+ steps.append(parent.setup)
103
85
  if hasattr(parent, 'body'):
104
- steps.extend(step for step in
105
- parent.body.flatten() # type: ignore - Use Protocol with RF 7.
106
- if step.type != self.MESSAGE)
86
+ steps.extend(parent.body.flatten(messages=False))
107
87
  if getattr(parent, 'has_teardown', False):
108
- steps.append(parent.teardown) # type: ignore - Use Protocol with RF 7.
88
+ steps.append(parent.teardown)
109
89
  index = steps.index(self) if self in steps else len(steps)
110
- parent_id = getattr(parent, 'id', None)
111
- return f'{parent_id}-k{index + 1}' if parent_id else f'k{index + 1}'
90
+ pid = parent.id # IF/TRY root id is None. Avoid calling property twice.
91
+ return f'{pid}-k{index + 1}' if pid else f'k{index + 1}'
112
92
 
113
93
  def to_dict(self) -> DataDict:
114
94
  raise NotImplementedError
115
95
 
116
96
 
117
- class BaseBody(ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]):
97
+ class BaseBody(ItemList[BodyItem], Generic[KW, F, W, G, I, T, V, R, C, B, M, E]):
118
98
  """Base class for Body and Branches objects."""
119
- __slots__ = []
99
+ __slots__ = ()
120
100
  # Set using 'BaseBody.register' when these classes are created.
121
101
  keyword_class: Type[KW] = KnownAtRuntime
122
102
  for_class: Type[F] = KnownAtRuntime
123
103
  while_class: Type[W] = KnownAtRuntime
104
+ group_class: Type[G] = KnownAtRuntime
124
105
  if_class: Type[I] = KnownAtRuntime
125
106
  try_class: Type[T] = KnownAtRuntime
126
107
  var_class: Type[V] = KnownAtRuntime
@@ -189,6 +170,10 @@ class BaseBody(ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]):
189
170
  def create_while(self, *args, **kwargs) -> while_class:
190
171
  return self._create(self.while_class, 'create_while', args, kwargs)
191
172
 
173
+ @copy_signature(group_class)
174
+ def create_group(self, *args, **kwargs) -> group_class:
175
+ return self._create(self.group_class, 'create_group', args, kwargs)
176
+
192
177
  @copy_signature(var_class)
193
178
  def create_var(self, *args, **kwargs) -> var_class:
194
179
  return self._create(self.var_class, 'create_var', args, kwargs)
@@ -214,7 +199,7 @@ class BaseBody(ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]):
214
199
  return self._create(self.error_class, 'create_error', args, kwargs)
215
200
 
216
201
  def filter(self, keywords: 'bool|None' = None, messages: 'bool|None' = None,
217
- predicate: 'Callable[[T], bool]|None' = None):
202
+ predicate: 'Callable[[T], bool]|None' = None) -> 'list[BodyItem]':
218
203
  """Filter body items based on type and/or custom predicate.
219
204
 
220
205
  To include or exclude items based on types, give matching arguments
@@ -238,9 +223,6 @@ class BaseBody(ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]):
238
223
  use ``body.filter(keywords=False``, messages=False)``. For more detailed
239
224
  filtering it is possible to use ``predicate``.
240
225
  """
241
- if messages is not None and self.message_class is KnownAtRuntime:
242
- raise TypeError(f"'{full_name(self)}' object does not support "
243
- f"filtering by 'messages'.")
244
226
  return self._filter([(self.keyword_class, keywords),
245
227
  (self.message_class, messages)], predicate)
246
228
 
@@ -258,38 +240,41 @@ class BaseBody(ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]):
258
240
  items = [item for item in items if predicate(item)]
259
241
  return items
260
242
 
261
- def flatten(self) -> 'list[BodyItem]':
243
+ def flatten(self, **filter_config) -> 'list[BodyItem]':
262
244
  """Return steps so that IF and TRY structures are flattened.
263
245
 
264
246
  Basically the IF/ELSE and TRY/EXCEPT root elements are replaced
265
- with their branches. This is how they are shown in log files.
247
+ with their branches. This is how they are shown in the log file.
248
+
249
+ ``filter_config`` can be used to filter steps using the :meth:`filter`
250
+ method before flattening. New in Robot Framework 7.2.
266
251
  """
267
252
  roots = BodyItem.IF_ELSE_ROOT, BodyItem.TRY_EXCEPT_ROOT
268
- steps = []
269
- for item in self:
253
+ steps = self if not filter_config else self.filter(**filter_config)
254
+ flat = []
255
+ for item in steps:
270
256
  if item.type in roots:
271
- item = cast('Try|If', item)
272
- steps.extend(item.body)
257
+ flat.extend(item.body)
273
258
  else:
274
- steps.append(item)
275
- return steps
259
+ flat.append(item)
260
+ return flat
276
261
 
277
262
 
278
- class Body(BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
279
- 'Continue', 'Break', 'Message', 'Error']):
263
+ class Body(BaseBody['Keyword', 'For', 'While', 'Group', 'If', 'Try', 'Var',
264
+ 'Return', 'Continue', 'Break', 'Message', 'Error']):
280
265
  """A list-like object representing a body of a test, keyword, etc.
281
266
 
282
267
  Body contains the keywords and other structures such as FOR loops.
283
268
  """
284
- pass
269
+ __slots__ = ()
285
270
 
286
271
 
287
272
  # BaseBranches cannot extend Generic[IT] directly with BaseBody[...].
288
273
  class BranchType(Generic[IT]):
289
- pass
274
+ __slots__ = ()
290
275
 
291
276
 
292
- class BaseBranches(BaseBody[KW, F, W, I, T, V, R, C, B, M, E], BranchType[IT]):
277
+ class BaseBranches(BaseBody[KW, F, W, G, I, T, V, R, C, B, M, E], BranchType[IT]):
293
278
  """A list-like object representing IF and TRY branches."""
294
279
  __slots__ = ['branch_class']
295
280
  branch_type: Type[IT] = KnownAtRuntime
@@ -300,8 +285,11 @@ class BaseBranches(BaseBody[KW, F, W, I, T, V, R, C, B, M, E], BranchType[IT]):
300
285
  self.branch_class = branch_class
301
286
  super().__init__(parent, items)
302
287
 
303
- def _item_from_dict(self, data: DataDict) -> IT:
304
- return self.branch_class.from_dict(data)
288
+ def _item_from_dict(self, data: DataDict) -> BodyItem:
289
+ try:
290
+ return self.branch_class.from_dict(data)
291
+ except DataError:
292
+ return super()._item_from_dict(data)
305
293
 
306
294
  @copy_signature(branch_type)
307
295
  def create_branch(self, *args, **kwargs) -> IT:
@@ -310,10 +298,10 @@ class BaseBranches(BaseBody[KW, F, W, I, T, V, R, C, B, M, E], BranchType[IT]):
310
298
 
311
299
  # BaseIterations cannot extend Generic[IT] directly with BaseBody[...].
312
300
  class IterationType(Generic[FW]):
313
- pass
301
+ __slots__ = ()
314
302
 
315
303
 
316
- class BaseIterations(BaseBody[KW, F, W, I, T, V, R, C, B, M, E], IterationType[FW]):
304
+ class BaseIterations(BaseBody[KW, F, W, G, I, T, V, R, C, B, M, E], IterationType[FW]):
317
305
  __slots__ = ['iteration_class']
318
306
  iteration_type: Type[FW] = KnownAtRuntime
319
307
 
@@ -323,7 +311,10 @@ class BaseIterations(BaseBody[KW, F, W, I, T, V, R, C, B, M, E], IterationType[F
323
311
  self.iteration_class = iteration_class
324
312
  super().__init__(parent, items)
325
313
 
326
- def _item_from_dict(self, data: DataDict) -> FW:
314
+ def _item_from_dict(self, data: DataDict) -> BodyItem:
315
+ # Non-iteration data is typically caused by listeners.
316
+ if data.get('type') != 'ITERATION':
317
+ return super()._item_from_dict(data)
327
318
  return self.iteration_class.from_dict(data)
328
319
 
329
320
  @copy_signature(iteration_type)
@@ -31,13 +31,13 @@ IT = TypeVar('IT', bound='IfBranch|TryBranch')
31
31
  FW = TypeVar('FW', bound='ForIteration|WhileIteration')
32
32
 
33
33
 
34
- class Branches(BaseBranches['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
35
- 'Continue', 'Break', 'Message', 'Error', IT]):
34
+ class Branches(BaseBranches['Keyword', 'For', 'While', 'Group', 'If', 'Try', 'Var',
35
+ 'Return', 'Continue', 'Break', 'Message', 'Error', IT]):
36
36
  __slots__ = ()
37
37
 
38
38
 
39
- class Iterations(BaseIterations['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return',
40
- 'Continue', 'Break', 'Message', 'Error', FW]):
39
+ class Iterations(BaseIterations['Keyword', 'For', 'While', 'Group', 'If', 'Try', 'Var',
40
+ 'Return', 'Continue', 'Break', 'Message', 'Error', FW]):
41
41
  __slots__ = ()
42
42
 
43
43
 
@@ -229,6 +229,37 @@ class While(BodyItem):
229
229
  return ' '.join(parts)
230
230
 
231
231
 
232
+ @Body.register
233
+ class Group(BodyItem):
234
+ """Represents ``GROUP``."""
235
+ type = BodyItem.GROUP
236
+ body_class = Body
237
+ repr_args = ('name',)
238
+ __slots__ = ['name']
239
+
240
+ def __init__(self, name: str = '',
241
+ parent: BodyItemParent = None):
242
+ self.name = name
243
+ self.parent = parent
244
+ self.body = ()
245
+
246
+ @setter
247
+ def body(self, body: 'Sequence[BodyItem|DataDict]') -> Body:
248
+ return self.body_class(self, body)
249
+
250
+ def visit(self, visitor: SuiteVisitor):
251
+ visitor.visit_group(self)
252
+
253
+ def to_dict(self) -> DataDict:
254
+ return {'type': self.type, 'name': self.name, 'body': self.body.to_dicts()}
255
+
256
+ def __str__(self) -> str:
257
+ parts = ['GROUP']
258
+ if self.name:
259
+ parts.append(self.name)
260
+ return ' '.join(parts)
261
+
262
+
232
263
  class IfBranch(BodyItem):
233
264
  """Represents individual ``IF``, ``ELSE IF`` or ``ELSE`` branch."""
234
265
  body_class = Body
@@ -61,7 +61,10 @@ class Message(BodyItem):
61
61
  def id(self):
62
62
  if not self.parent:
63
63
  return 'm1'
64
- messages = self.parent.messages
64
+ if hasattr(self.parent, 'messages'):
65
+ messages = self.parent.messages
66
+ else:
67
+ messages = self.parent.body.filter(messages=True)
65
68
  index = messages.index(self) if self in messages else len(messages)
66
69
  return f'{self.parent.id}-m{index + 1}'
67
70
 
@@ -69,12 +72,14 @@ class Message(BodyItem):
69
72
  """:mod:`Visitor interface <robot.model.visitor>` entry-point."""
70
73
  visitor.visit_message(self)
71
74
 
75
+ def to_dict(self):
76
+ data = {'message': self.message,
77
+ 'level': self.level}
78
+ if self.html:
79
+ data['html'] = True
80
+ if self.timestamp:
81
+ data['timestamp'] = self.timestamp.isoformat()
82
+ return data
83
+
72
84
  def __str__(self):
73
85
  return self.message
74
-
75
-
76
- class Messages(ItemList):
77
- __slots__ = []
78
-
79
- def __init__(self, message_class=Message, parent=None, messages=None):
80
- ItemList.__init__(self, message_class, {'parent': parent}, messages)
@@ -27,6 +27,32 @@ DataDict = Dict[str, Any]
27
27
 
28
28
 
29
29
  class ModelObject(metaclass=SetterAwareType):
30
+ SUITE = 'SUITE'
31
+ TEST = 'TEST'
32
+ TASK = TEST
33
+ KEYWORD = 'KEYWORD'
34
+ SETUP = 'SETUP'
35
+ TEARDOWN = 'TEARDOWN'
36
+ FOR = 'FOR'
37
+ ITERATION = 'ITERATION'
38
+ IF_ELSE_ROOT = 'IF/ELSE ROOT'
39
+ IF = 'IF'
40
+ ELSE_IF = 'ELSE IF'
41
+ ELSE = 'ELSE'
42
+ TRY_EXCEPT_ROOT = 'TRY/EXCEPT ROOT'
43
+ TRY = 'TRY'
44
+ EXCEPT = 'EXCEPT'
45
+ FINALLY = 'FINALLY'
46
+ WHILE = 'WHILE'
47
+ GROUP = 'GROUP'
48
+ VAR = 'VAR'
49
+ RETURN = 'RETURN'
50
+ CONTINUE = 'CONTINUE'
51
+ BREAK = 'BREAK'
52
+ ERROR = 'ERROR'
53
+ MESSAGE = 'MESSAGE'
54
+ KEYWORD_TYPES = (KEYWORD, SETUP, TEARDOWN)
55
+ type: str
30
56
  repr_args = ()
31
57
  __slots__ = []
32
58
 
@@ -13,9 +13,9 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- from .totalstatistics import TotalStatisticsBuilder
17
- from .suitestatistics import SuiteStatisticsBuilder
18
- from .tagstatistics import TagStatisticsBuilder
16
+ from .totalstatistics import TotalStatistics, TotalStatisticsBuilder
17
+ from .suitestatistics import SuiteStatistics, SuiteStatisticsBuilder
18
+ from .tagstatistics import TagStatistics, TagStatisticsBuilder
19
19
  from .visitor import SuiteVisitor
20
20
 
21
21
 
@@ -34,12 +34,16 @@ class Statistics:
34
34
  tag_stat_exclude, tag_stat_combine,
35
35
  tag_doc, tag_stat_link)
36
36
  suite.visit(StatisticsBuilder(total_builder, suite_builder, tag_builder))
37
- #: Instance of :class:`~robot.model.totalstatistics.TotalStatistics`.
38
- self.total = total_builder.stats
39
- #: Instance of :class:`~robot.model.suitestatistics.SuiteStatistics`.
40
- self.suite = suite_builder.stats
41
- #: Instance of :class:`~robot.model.tagstatistics.TagStatistics`.
42
- self.tags = tag_builder.stats
37
+ self.total: TotalStatistics = total_builder.stats
38
+ self.suite: SuiteStatistics = suite_builder.stats
39
+ self.tags: TagStatistics = tag_builder.stats
40
+
41
+ def to_dict(self):
42
+ return {
43
+ 'total': self.total.stat.get_attributes(include_label=True),
44
+ 'suites': [s.get_attributes(include_label=True) for s in self.suite],
45
+ 'tags': [t.get_attributes(include_label=True) for t in self.tags],
46
+ }
43
47
 
44
48
  def visit(self, visitor):
45
49
  visitor.visit_statistics(self)
@@ -15,8 +15,7 @@
15
15
 
16
16
  from datetime import timedelta
17
17
 
18
- from robot.utils import (Sortable, elapsed_time_to_string, html_escape,
19
- is_string, normalize)
18
+ from robot.utils import elapsed_time_to_string, html_escape, normalize, Sortable
20
19
 
21
20
  from .tags import TagPattern
22
21
 
@@ -40,28 +39,27 @@ class Stat(Sortable):
40
39
  self._norm_name = normalize(name, ignore='_')
41
40
 
42
41
  def get_attributes(self, include_label=False, include_elapsed=False,
43
- exclude_empty=True, values_as_strings=False,
44
- html_escape=False):
45
- attrs = {'pass': self.passed, 'fail': self.failed, 'skip': self.skipped}
46
- attrs.update(self._get_custom_attrs())
47
- if include_label:
48
- attrs['label'] = self.name
42
+ exclude_empty=True, values_as_strings=False, html_escape=False):
43
+ attrs = {
44
+ **({'label': self.name} if include_label else {}),
45
+ **self._get_custom_attrs(),
46
+ **{'pass': self.passed, 'fail': self.failed, 'skip': self.skipped},
47
+ }
49
48
  if include_elapsed:
50
49
  attrs['elapsed'] = elapsed_time_to_string(self.elapsed, include_millis=False)
51
50
  if exclude_empty:
52
- attrs = dict((k, v) for k, v in attrs.items() if v not in ('', None))
51
+ attrs = {k: v for k, v in attrs.items() if v not in ('', None)}
53
52
  if values_as_strings:
54
- attrs = dict((k, str(v) if v is not None else '')
55
- for k, v in attrs.items())
53
+ attrs = {k: str(v if v is not None else '') for k, v in attrs.items()}
56
54
  if html_escape:
57
- attrs = dict((k, self._html_escape(v)) for k, v in attrs.items())
55
+ attrs = {k: self._html_escape(v) for k, v in attrs.items()}
58
56
  return attrs
59
57
 
60
58
  def _get_custom_attrs(self):
61
59
  return {}
62
60
 
63
61
  def _html_escape(self, item):
64
- return html_escape(item) if is_string(item) else item
62
+ return html_escape(item) if isinstance(item, str) else item
65
63
 
66
64
  @property
67
65
  def total(self):
@@ -109,7 +107,7 @@ class SuiteStat(Stat):
109
107
  self._name = suite.name
110
108
 
111
109
  def _get_custom_attrs(self):
112
- return {'id': self.id, 'name': self._name}
110
+ return {'name': self._name, 'id': self.id}
113
111
 
114
112
  def _update_elapsed(self, test):
115
113
  pass
@@ -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 typing import Iterator
17
+
16
18
  from .stats import SuiteStat
17
19
 
18
20
 
@@ -20,30 +22,27 @@ class SuiteStatistics:
20
22
  """Container for suite statistics."""
21
23
 
22
24
  def __init__(self, suite):
23
- #: Instance of :class:`~robot.model.stats.SuiteStat`.
24
25
  self.stat = SuiteStat(suite)
25
- #: List of :class:`~robot.model.testsuite.TestSuite` objects.
26
- self.suites = []
26
+ self.suites: list[SuiteStatistics] = []
27
27
 
28
28
  def visit(self, visitor):
29
29
  visitor.visit_suite_statistics(self)
30
30
 
31
- def __iter__(self):
31
+ def __iter__(self) -> Iterator[SuiteStat]:
32
32
  yield self.stat
33
33
  for child in self.suites:
34
- for stat in child:
35
- yield stat
34
+ yield from child
36
35
 
37
36
 
38
37
  class SuiteStatisticsBuilder:
39
38
 
40
39
  def __init__(self, suite_stat_level):
41
40
  self._suite_stat_level = suite_stat_level
42
- self._stats_stack = []
43
- self.stats = None
41
+ self._stats_stack: list[SuiteStatistics] = []
42
+ self.stats: SuiteStatistics | None = None
44
43
 
45
44
  @property
46
- def current(self):
45
+ def current(self) -> 'SuiteStatistics|None':
47
46
  return self._stats_stack[-1] if self._stats_stack else None
48
47
 
49
48
  def start_suite(self, suite):
@@ -108,6 +108,10 @@ class TagPatterns(Sequence['TagPattern']):
108
108
  def __init__(self, patterns: Iterable[str] = ()):
109
109
  self._patterns = tuple(TagPattern.from_string(p) for p in Tags(patterns))
110
110
 
111
+ @property
112
+ def is_constant(self):
113
+ return all(p.is_constant for p in self._patterns)
114
+
111
115
  def match(self, tags: Iterable[str]) -> bool:
112
116
  if not self._patterns:
113
117
  return False
@@ -132,6 +136,7 @@ class TagPatterns(Sequence['TagPattern']):
132
136
 
133
137
 
134
138
  class TagPattern(ABC):
139
+ is_constant = False
135
140
 
136
141
  @classmethod
137
142
  def from_string(cls, pattern: str) -> 'TagPattern':
@@ -166,6 +171,11 @@ class SingleTagPattern(TagPattern):
166
171
  self._matcher = Matcher(normalize(pattern, ignore='_'),
167
172
  caseless=False, spaceless=False)
168
173
 
174
+ @property
175
+ def is_constant(self):
176
+ pattern = self._matcher.pattern
177
+ return not ('*' in pattern or '?' in pattern or '[' in pattern)
178
+
169
179
  def match(self, tags: Iterable[str]) -> bool:
170
180
  tags = normalize_tags(tags)
171
181
  return self._matcher.match_any(tags)
@@ -13,8 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- from itertools import chain
17
16
  import re
17
+ from itertools import chain
18
18
 
19
19
  from robot.utils import NormalizedDict
20
20
 
@@ -26,10 +26,7 @@ class TagStatistics:
26
26
  """Container for tag statistics."""
27
27
 
28
28
  def __init__(self, combined_stats):
29
- #: Dictionary, where key is the name of the tag as a string and value
30
- #: is an instance of :class:`~robot.model.stats.TagStat`.
31
29
  self.tags = NormalizedDict(ignore='_')
32
- #: List of :class:`~robot.model.stats.CombinedTagStat` objects.
33
30
  self.combined = combined_stats
34
31
 
35
32
  def visit(self, visitor):
@@ -127,21 +124,23 @@ class TagStatLink:
127
124
  return link, title
128
125
 
129
126
  def _replace_groups(self, link, title, match):
130
- for index, group in enumerate(match.groups()):
131
- placefolder = '%%%d' % (index+1)
127
+ for index, group in enumerate(match.groups(), start=1):
128
+ placefolder = f'%{index}'
132
129
  link = link.replace(placefolder, group)
133
130
  title = title.replace(placefolder, group)
134
131
  return link, title
135
132
 
136
133
  def _get_match_regexp(self, pattern):
137
- pattern = '^%s$' % ''.join(self._yield_match_pattern(pattern))
134
+ pattern = ''.join(self._yield_match_pattern(pattern))
138
135
  return re.compile(pattern, re.IGNORECASE)
139
136
 
140
137
  def _yield_match_pattern(self, pattern):
138
+ yield '^'
141
139
  for token in self._match_pattern_tokenizer.split(pattern):
142
140
  if token.startswith('?'):
143
- yield '(%s)' % ('.'*len(token))
141
+ yield f'({"."*len(token)})'
144
142
  elif token == '*':
145
143
  yield '(.*)'
146
144
  else:
147
145
  yield re.escape(token)
146
+ yield '$'
@@ -40,6 +40,7 @@ class TestCase(ModelObject, Generic[KW]):
40
40
  Extended by :class:`robot.running.model.TestCase` and
41
41
  :class:`robot.result.model.TestCase`.
42
42
  """
43
+ type = 'TEST'
43
44
  body_class = Body
44
45
  # See model.TestSuite on removing the type ignore directive
45
46
  fixture_class: Type[KW] = Keyword # type: ignore
@@ -42,6 +42,7 @@ class TestSuite(ModelObject, Generic[KW, TC]):
42
42
  Extended by :class:`robot.running.model.TestSuite` and
43
43
  :class:`robot.result.model.TestSuite`.
44
44
  """
45
+ type = 'SUITE'
45
46
  # FIXME: Type Ignore declarations: Typevars only accept subclasses of the bound class
46
47
  # assigning `Type[KW]` to `Keyword` results in an error. In RF 7 the class should be
47
48
  # made impossible to instantiate directly, and the assignments can be replaced with
@@ -15,7 +15,7 @@
15
15
 
16
16
  from collections.abc import Iterator
17
17
 
18
- from robot.utils import test_or_task
18
+ from robot.utils import plural_or_not, test_or_task
19
19
 
20
20
  from .stats import TotalStat
21
21
  from .visitor import SuiteVisitor
@@ -26,33 +26,33 @@ class TotalStatistics:
26
26
 
27
27
  def __init__(self, rpa: bool = False):
28
28
  #: Instance of :class:`~robot.model.stats.TotalStat` for all the tests.
29
- self._stat = TotalStat(test_or_task('All {Test}s', rpa))
29
+ self.stat = TotalStat(test_or_task('All {Test}s', rpa))
30
30
  self._rpa = rpa
31
31
 
32
32
  def visit(self, visitor):
33
- visitor.visit_total_statistics(self._stat)
33
+ visitor.visit_total_statistics(self.stat)
34
34
 
35
35
  def __iter__(self) -> 'Iterator[TotalStat]':
36
- yield self._stat
36
+ yield self.stat
37
37
 
38
38
  @property
39
39
  def total(self) -> int:
40
- return self._stat.total
40
+ return self.stat.total
41
41
 
42
42
  @property
43
43
  def passed(self) -> int:
44
- return self._stat.passed
44
+ return self.stat.passed
45
45
 
46
46
  @property
47
47
  def skipped(self) -> int:
48
- return self._stat.skipped
48
+ return self.stat.skipped
49
49
 
50
50
  @property
51
51
  def failed(self) -> int:
52
- return self._stat.failed
52
+ return self.stat.failed
53
53
 
54
54
  def add_test(self, test):
55
- self._stat.add_test(test)
55
+ self.stat.add_test(test)
56
56
 
57
57
  @property
58
58
  def message(self) -> str:
@@ -61,18 +61,11 @@ class TotalStatistics:
61
61
  For example::
62
62
  2 tests, 1 passed, 1 failed
63
63
  """
64
- # TODO: should this message be highlighted in console
65
- test_or_task = 'test' if not self._rpa else 'task'
66
- total, end, passed, failed, skipped = self._get_counts()
67
- template = '%d %s%s, %d passed, %d failed'
68
- if skipped:
69
- return ((template + ', %d skipped')
70
- % (total, test_or_task, end, passed, failed, skipped))
71
- return template % (total, test_or_task, end, passed, failed)
72
-
73
- def _get_counts(self):
74
- ending = 's' if self.total != 1 else ''
75
- return self.total, ending, self.passed, self.failed, self.skipped
64
+ kind = test_or_task('test', self._rpa) + plural_or_not(self.total)
65
+ msg = f'{self.total} {kind}, {self.passed} passed, {self.failed} failed'
66
+ if self.skipped:
67
+ msg += f', {self.skipped} skipped'
68
+ return msg
76
69
 
77
70
 
78
71
  class TotalStatisticsBuilder(SuiteVisitor):