robotframework 7.3.1__tar.gz → 7.3.2__tar.gz

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 (285) hide show
  1. {robotframework-7.3.1 → robotframework-7.3.2}/BUILD.rst +1 -1
  2. {robotframework-7.3.1 → robotframework-7.3.2}/PKG-INFO +2 -2
  3. {robotframework-7.3.1 → robotframework-7.3.2}/setup.py +1 -1
  4. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/BuiltIn.py +5 -2
  5. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/executionresult.py +51 -13
  6. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/flattenkeywordmatcher.py +37 -1
  7. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/resultbuilder.py +59 -53
  8. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/suiteteardownfailed.py +6 -6
  9. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/bodyrunner.py +3 -1
  10. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/namespace.py +25 -7
  11. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/json.py +51 -7
  12. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/version.py +1 -1
  13. {robotframework-7.3.1 → robotframework-7.3.2}/src/robotframework.egg-info/PKG-INFO +2 -2
  14. {robotframework-7.3.1 → robotframework-7.3.2}/AUTHORS.rst +0 -0
  15. {robotframework-7.3.1 → robotframework-7.3.2}/CONTRIBUTING.rst +0 -0
  16. {robotframework-7.3.1 → robotframework-7.3.2}/COPYRIGHT.txt +0 -0
  17. {robotframework-7.3.1 → robotframework-7.3.2}/INSTALL.rst +0 -0
  18. {robotframework-7.3.1 → robotframework-7.3.2}/LICENSE.txt +0 -0
  19. {robotframework-7.3.1 → robotframework-7.3.2}/MANIFEST.in +0 -0
  20. {robotframework-7.3.1 → robotframework-7.3.2}/README.rst +0 -0
  21. {robotframework-7.3.1 → robotframework-7.3.2}/pyproject.toml +0 -0
  22. {robotframework-7.3.1 → robotframework-7.3.2}/setup.cfg +0 -0
  23. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/__init__.py +0 -0
  24. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/__main__.py +0 -0
  25. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/__init__.py +0 -0
  26. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/deco.py +0 -0
  27. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/exceptions.py +0 -0
  28. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/interfaces.py +0 -0
  29. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/logger.py +0 -0
  30. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/parsing.py +0 -0
  31. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/api/py.typed +0 -0
  32. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/conf/__init__.py +0 -0
  33. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/conf/gatherfailed.py +0 -0
  34. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/conf/languages.py +0 -0
  35. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/conf/settings.py +0 -0
  36. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/errors.py +0 -0
  37. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/__init__.py +0 -0
  38. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/common/__init__.py +0 -0
  39. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/common/js_disabled.css +0 -0
  40. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/common/storage.js +0 -0
  41. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/htmlfilewriter.py +0 -0
  42. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/jsonwriter.py +0 -0
  43. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/__init__.py +0 -0
  44. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
  45. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/jquery.min.js +0 -0
  46. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
  47. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
  48. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
  49. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/libdoc/__init__.py +0 -0
  50. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/libdoc/libdoc.html +0 -0
  51. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/__init__.py +0 -0
  52. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/common.css +0 -0
  53. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/doc_formatting.css +0 -0
  54. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/fileloading.js +0 -0
  55. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/log.css +0 -0
  56. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/log.html +0 -0
  57. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/log.js +0 -0
  58. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/model.js +0 -0
  59. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/print.css +0 -0
  60. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/report.css +0 -0
  61. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/report.html +0 -0
  62. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/testdata.js +0 -0
  63. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/util.js +0 -0
  64. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/rebot/view.js +0 -0
  65. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/template.py +0 -0
  66. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/testdoc/__init__.py +0 -0
  67. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/testdoc/testdoc.css +0 -0
  68. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/htmldata/testdoc/testdoc.html +0 -0
  69. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdoc.py +0 -0
  70. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/__init__.py +0 -0
  71. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/builder.py +0 -0
  72. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/consoleviewer.py +0 -0
  73. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/datatypes.py +0 -0
  74. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/htmlutils.py +0 -0
  75. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/htmlwriter.py +0 -0
  76. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/jsonbuilder.py +0 -0
  77. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/jsonwriter.py +0 -0
  78. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/languages.py +0 -0
  79. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/model.py +0 -0
  80. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/output.py +0 -0
  81. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/robotbuilder.py +0 -0
  82. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/standardtypes.py +0 -0
  83. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/writer.py +0 -0
  84. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/xmlbuilder.py +0 -0
  85. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libdocpkg/xmlwriter.py +0 -0
  86. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Collections.py +0 -0
  87. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/DateTime.py +0 -0
  88. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Dialogs.py +0 -0
  89. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Easter.py +0 -0
  90. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/OperatingSystem.py +0 -0
  91. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Process.py +0 -0
  92. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Remote.py +0 -0
  93. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Screenshot.py +0 -0
  94. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/String.py +0 -0
  95. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/Telnet.py +0 -0
  96. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/XML.py +0 -0
  97. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/__init__.py +0 -0
  98. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/libraries/dialogs_py.py +0 -0
  99. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/logo.png +0 -0
  100. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/__init__.py +0 -0
  101. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/body.py +0 -0
  102. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/configurer.py +0 -0
  103. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/control.py +0 -0
  104. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/filter.py +0 -0
  105. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/fixture.py +0 -0
  106. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/itemlist.py +0 -0
  107. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/keyword.py +0 -0
  108. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/message.py +0 -0
  109. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/metadata.py +0 -0
  110. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/modelobject.py +0 -0
  111. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/modifier.py +0 -0
  112. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/namepatterns.py +0 -0
  113. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/statistics.py +0 -0
  114. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/stats.py +0 -0
  115. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/suitestatistics.py +0 -0
  116. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/tags.py +0 -0
  117. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/tagsetter.py +0 -0
  118. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/tagstatistics.py +0 -0
  119. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/testcase.py +0 -0
  120. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/testsuite.py +0 -0
  121. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/totalstatistics.py +0 -0
  122. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/model/visitor.py +0 -0
  123. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/__init__.py +0 -0
  124. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/console/__init__.py +0 -0
  125. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/console/dotted.py +0 -0
  126. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/console/highlighting.py +0 -0
  127. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/console/quiet.py +0 -0
  128. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/console/verbose.py +0 -0
  129. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/debugfile.py +0 -0
  130. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/filelogger.py +0 -0
  131. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/jsonlogger.py +0 -0
  132. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/librarylogger.py +0 -0
  133. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/listeners.py +0 -0
  134. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/logger.py +0 -0
  135. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/loggerapi.py +0 -0
  136. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/loggerhelper.py +0 -0
  137. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/loglevel.py +0 -0
  138. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/output.py +0 -0
  139. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/outputfile.py +0 -0
  140. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/pyloggingconf.py +0 -0
  141. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/stdoutlogsplitter.py +0 -0
  142. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/output/xmllogger.py +0 -0
  143. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/__init__.py +0 -0
  144. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/__init__.py +0 -0
  145. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/blocklexers.py +0 -0
  146. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/context.py +0 -0
  147. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/lexer.py +0 -0
  148. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/settings.py +0 -0
  149. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/statementlexers.py +0 -0
  150. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/tokenizer.py +0 -0
  151. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/lexer/tokens.py +0 -0
  152. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/model/__init__.py +0 -0
  153. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/model/blocks.py +0 -0
  154. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/model/statements.py +0 -0
  155. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/model/visitor.py +0 -0
  156. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/parser/__init__.py +0 -0
  157. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/parser/blockparsers.py +0 -0
  158. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/parser/fileparser.py +0 -0
  159. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/parser/parser.py +0 -0
  160. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/parsing/suitestructure.py +0 -0
  161. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/pythonpathsetter.py +0 -0
  162. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/rebot.py +0 -0
  163. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/__init__.py +0 -0
  164. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/expandkeywordmatcher.py +0 -0
  165. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/jsbuildingcontext.py +0 -0
  166. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/jsexecutionresult.py +0 -0
  167. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/jsmodelbuilders.py +0 -0
  168. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/jswriter.py +0 -0
  169. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/logreportwriters.py +0 -0
  170. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/outputwriter.py +0 -0
  171. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/resultwriter.py +0 -0
  172. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/stringcache.py +0 -0
  173. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/reporting/xunitwriter.py +0 -0
  174. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/__init__.py +0 -0
  175. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/configurer.py +0 -0
  176. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/executionerrors.py +0 -0
  177. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/keywordremover.py +0 -0
  178. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/merger.py +0 -0
  179. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/messagefilter.py +0 -0
  180. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/model.py +0 -0
  181. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/modeldeprecation.py +0 -0
  182. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/visitor.py +0 -0
  183. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/result/xmlelementhandlers.py +0 -0
  184. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/run.py +0 -0
  185. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/__init__.py +0 -0
  186. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/__init__.py +0 -0
  187. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentconverter.py +0 -0
  188. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentmapper.py +0 -0
  189. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentparser.py +0 -0
  190. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentresolver.py +0 -0
  191. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentspec.py +0 -0
  192. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/argumentvalidator.py +0 -0
  193. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/customconverters.py +0 -0
  194. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/embedded.py +0 -0
  195. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/typeconverters.py +0 -0
  196. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/typeinfo.py +0 -0
  197. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/typeinfoparser.py +0 -0
  198. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/arguments/typevalidator.py +0 -0
  199. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/builder/__init__.py +0 -0
  200. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/builder/builders.py +0 -0
  201. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/builder/parsers.py +0 -0
  202. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/builder/settings.py +0 -0
  203. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/builder/transformers.py +0 -0
  204. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/context.py +0 -0
  205. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/dynamicmethods.py +0 -0
  206. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/importer.py +0 -0
  207. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/invalidkeyword.py +0 -0
  208. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/keywordfinder.py +0 -0
  209. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/keywordimplementation.py +0 -0
  210. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/librarykeyword.py +0 -0
  211. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/librarykeywordrunner.py +0 -0
  212. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/libraryscopes.py +0 -0
  213. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/model.py +0 -0
  214. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/outputcapture.py +0 -0
  215. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/randomizer.py +0 -0
  216. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/resourcemodel.py +0 -0
  217. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/runkwregister.py +0 -0
  218. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/signalhandler.py +0 -0
  219. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/status.py +0 -0
  220. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/statusreporter.py +0 -0
  221. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/suiterunner.py +0 -0
  222. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/testlibraries.py +0 -0
  223. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/__init__.py +0 -0
  224. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/nosupport.py +0 -0
  225. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/posix.py +0 -0
  226. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/runner.py +0 -0
  227. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/timeout.py +0 -0
  228. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/timeouts/windows.py +0 -0
  229. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/running/userkeywordrunner.py +0 -0
  230. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/testdoc.py +0 -0
  231. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/__init__.py +0 -0
  232. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/application.py +0 -0
  233. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/argumentparser.py +0 -0
  234. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/asserts.py +0 -0
  235. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/charwidth.py +0 -0
  236. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/compress.py +0 -0
  237. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/connectioncache.py +0 -0
  238. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/dotdict.py +0 -0
  239. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/encoding.py +0 -0
  240. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/encodingsniffer.py +0 -0
  241. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/error.py +0 -0
  242. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/escaping.py +0 -0
  243. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/etreewrapper.py +0 -0
  244. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/filereader.py +0 -0
  245. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/frange.py +0 -0
  246. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/htmlformatters.py +0 -0
  247. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/importer.py +0 -0
  248. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/markuputils.py +0 -0
  249. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/markupwriters.py +0 -0
  250. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/match.py +0 -0
  251. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/misc.py +0 -0
  252. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/normalizing.py +0 -0
  253. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/notset.py +0 -0
  254. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/platform.py +0 -0
  255. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/recommendations.py +0 -0
  256. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/restreader.py +0 -0
  257. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robotenv.py +0 -0
  258. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robotinspect.py +0 -0
  259. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robotio.py +0 -0
  260. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robotpath.py +0 -0
  261. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robottime.py +0 -0
  262. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/robottypes.py +0 -0
  263. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/setter.py +0 -0
  264. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/sortable.py +0 -0
  265. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/text.py +0 -0
  266. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/typehints.py +0 -0
  267. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/utils/unic.py +0 -0
  268. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/__init__.py +0 -0
  269. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/assigner.py +0 -0
  270. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/evaluation.py +0 -0
  271. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/filesetter.py +0 -0
  272. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/finders.py +0 -0
  273. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/notfound.py +0 -0
  274. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/replacer.py +0 -0
  275. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/resolvable.py +0 -0
  276. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/scopes.py +0 -0
  277. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/search.py +0 -0
  278. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/store.py +0 -0
  279. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/tablesetter.py +0 -0
  280. {robotframework-7.3.1 → robotframework-7.3.2}/src/robot/variables/variables.py +0 -0
  281. {robotframework-7.3.1 → robotframework-7.3.2}/src/robotframework.egg-info/SOURCES.txt +0 -0
  282. {robotframework-7.3.1 → robotframework-7.3.2}/src/robotframework.egg-info/dependency_links.txt +0 -0
  283. {robotframework-7.3.1 → robotframework-7.3.2}/src/robotframework.egg-info/entry_points.txt +0 -0
  284. {robotframework-7.3.1 → robotframework-7.3.2}/src/robotframework.egg-info/top_level.txt +0 -0
  285. {robotframework-7.3.1 → robotframework-7.3.2}/tasks.py +0 -0
@@ -282,6 +282,6 @@ Announcements
282
282
  2. `Forum <https://forum.robotframework.org/>`_.
283
283
 
284
284
  3. `LinkedIn group <https://www.linkedin.com/groups/3710899/>`_. A personal
285
- LinkedIn post is a good idea at least with bigger releases.
285
+ LinkedIn post is a good idea at least with bigger releases.
286
286
 
287
287
  4. `robotframework-users <https://groups.google.com/group/robotframework-users>`_
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: robotframework
3
- Version: 7.3.1
3
+ Version: 7.3.2
4
4
  Summary: Generic automation framework for acceptance testing and robotic process automation (RPA)
5
5
  Home-page: https://robotframework.org
6
6
  Download-URL: https://pypi.org/project/robotframework
@@ -10,7 +10,7 @@ License: Apache License 2.0
10
10
  Project-URL: Source, https://github.com/robotframework/robotframework
11
11
  Project-URL: Issue Tracker, https://github.com/robotframework/robotframework/issues
12
12
  Project-URL: Documentation, https://robotframework.org/robotframework
13
- Project-URL: Release Notes, https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.3.1.rst
13
+ Project-URL: Release Notes, https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.3.2.rst
14
14
  Project-URL: Slack, http://slack.robotframework.org
15
15
  Keywords: robotframework automation testautomation rpa testing acceptancetesting atdd bdd
16
16
  Platform: any
@@ -6,7 +6,7 @@ from setuptools import find_packages, setup
6
6
 
7
7
  # Version number typically updated by running `invoke set-version <version>`.
8
8
  # Run `invoke --help set-version` or see tasks.py for details.
9
- VERSION = "7.3.1"
9
+ VERSION = "7.3.2"
10
10
  with open(join(dirname(abspath(__file__)), "README.rst")) as f:
11
11
  LONG_DESCRIPTION = f.read()
12
12
  base_url = "https://github.com/robotframework/robotframework/blob/master"
@@ -2184,11 +2184,14 @@ class _RunKeyword(_BuiltInBase):
2184
2184
  # to 'Keyword.run', but then it would be better if 'Run Keyword' would support
2185
2185
  # 'NONE' as a special value to not run anything similarly as setup/teardown.
2186
2186
  replaced = ctx.variables.replace_scalar(name, ignore_errors=ctx.in_teardown)
2187
- runner = ctx.get_runner(replaced, recommend_on_failure=False)
2188
- if hasattr(runner, "embedded_args"):
2187
+ if self._accepts_embedded(replaced, ctx) and self._accepts_embedded(name, ctx):
2189
2188
  return name, args
2190
2189
  return replaced, args
2191
2190
 
2191
+ def _accepts_embedded(self, name, ctx):
2192
+ runner = ctx.get_runner(name, recommend_on_failure=False)
2193
+ return hasattr(runner, "embedded_args")
2194
+
2192
2195
  def _replace_variables_in_name_with_list_variable(self, name, args, ctx):
2193
2196
  # TODO: This seems to be the only place where `replace_until` is used.
2194
2197
  # That functionality should be removed from `replace_list` and implemented
@@ -15,14 +15,15 @@
15
15
 
16
16
  from datetime import datetime
17
17
  from pathlib import Path
18
- from typing import overload, TextIO
18
+ from typing import overload, Sequence, TextIO
19
19
 
20
20
  from robot.errors import DataError
21
- from robot.model import Statistics
21
+ from robot.model import Statistics, SuiteVisitor
22
22
  from robot.utils import JsonDumper, JsonLoader, setter
23
23
  from robot.version import get_full_version
24
24
 
25
25
  from .executionerrors import ExecutionErrors
26
+ from .flattenkeywordmatcher import Flattener
26
27
  from .model import TestSuite
27
28
 
28
29
 
@@ -154,17 +155,27 @@ class Result:
154
155
  def from_json(
155
156
  cls,
156
157
  source: "str|bytes|TextIO|Path",
158
+ include_keywords: bool = True,
159
+ flattened_keywords: Sequence[str] = (),
157
160
  rpa: "bool|None" = None,
158
161
  ) -> "Result":
159
162
  """Construct a result object from JSON data.
160
163
 
161
- The data is given as the ``source`` parameter. It can be:
162
-
163
- - a string (or bytes) containing the data directly,
164
- - an open file object where to read the data from, or
165
- - a path (``pathlib.Path`` or string) to a UTF-8 encoded file to read.
166
-
167
- Data can contain either:
164
+ :param source: JSON data as a string or bytes containing the data
165
+ directly, an open file object where to read the data from, or a path
166
+ (``pathlib.Path`` or string) to a UTF-8 encoded file to read.
167
+ :param include_keywords: When ``False``, keyword and control structure
168
+ information is not parsed. This can save considerable amount of time
169
+ and memory. New in RF 7.3.2.
170
+ :param flattened_keywords: List of patterns controlling what keywords
171
+ and control structures to flatten. See the documentation of
172
+ the ``--flattenkeywords`` option for more details. New in RF 7.3.2.
173
+ :param rpa: Setting ``rpa`` either to ``True`` (RPA mode) or ``False``
174
+ (test automation) sets the execution mode explicitly. By default,
175
+ the mode is got from the parsed data.
176
+ :returns: :class:`Result` instance.
177
+
178
+ The data can contain either:
168
179
 
169
180
  - full result data (contains suite information, execution errors, etc.)
170
181
  got, for example, from the :meth:`to_json` method, or
@@ -174,13 +185,11 @@ class Result:
174
185
  :attr:`statistics` are populated automatically based on suite information
175
186
  and thus ignored if they are present in the data.
176
187
 
177
- The ``rpa`` argument can be used to override the RPA mode. The mode is
178
- got from the data by default.
179
-
180
188
  New in Robot Framework 7.2.
181
189
  """
190
+ loader = cls._get_json_loader(include_keywords)
182
191
  try:
183
- data = JsonLoader().load(source)
192
+ data = loader.load(source)
184
193
  except (TypeError, ValueError) as err:
185
194
  raise DataError(f"Loading JSON data failed: {err}")
186
195
  if "suite" in data:
@@ -192,8 +201,27 @@ class Result:
192
201
  result.source = source
193
202
  elif isinstance(source, str) and source[0] != "{" and Path(source).exists():
194
203
  result.source = Path(source)
204
+ result.handle_suite_teardown_failures()
205
+ if not include_keywords:
206
+ result.suite.visit(KeywordRemover())
207
+ if flattened_keywords:
208
+ result.suite.visit(Flattener(flattened_keywords))
195
209
  return result
196
210
 
211
+ @classmethod
212
+ def _get_json_loader(cls, include_keywords: bool) -> JsonLoader:
213
+ if include_keywords:
214
+ return JsonLoader()
215
+
216
+ def remove_keywords(obj):
217
+ obj.pop("body", None)
218
+ obj.pop("setup", None)
219
+ # Teardowns cannot be removed yet, because we need to check suite
220
+ # teardown status. They are removed later using KeywordRemover.
221
+ return obj
222
+
223
+ return JsonLoader(object_hook=remove_keywords)
224
+
197
225
  @classmethod
198
226
  def _from_full_json(cls, data) -> "Result":
199
227
  return Result(
@@ -355,3 +383,13 @@ class CombinedResult(Result):
355
383
  self.set_execution_mode(other)
356
384
  self.suite.suites.append(other.suite)
357
385
  self.errors.add(other.errors)
386
+
387
+
388
+ class KeywordRemover(SuiteVisitor):
389
+
390
+ def start_suite(self, suite):
391
+ suite.setup = suite.teardown = None
392
+
393
+ def visit_test(self, test):
394
+ test.setup = test.teardown = None
395
+ test.body = []
@@ -57,7 +57,8 @@ class FlattenByTypeMatcher:
57
57
  if "while" in flatten:
58
58
  self.types.add("while")
59
59
  if "iteration" in flatten or "foritem" in flatten:
60
- self.types.add("iter")
60
+ self.types.add("iter") # Matches output.xml tag.
61
+ self.types.add("iteration") # Matches model object type.
61
62
 
62
63
  def match(self, tag):
63
64
  return tag in self.types
@@ -97,6 +98,34 @@ class FlattenByTagMatcher:
97
98
  return bool(self._matcher)
98
99
 
99
100
 
101
+ class Flattener(SuiteVisitor):
102
+
103
+ def __init__(self, flatten):
104
+ self.name_matcher = FlattenByNameMatcher(flatten)
105
+ self.tag_matcher = FlattenByTagMatcher(flatten)
106
+ self.type_matcher = FlattenByTypeMatcher(flatten)
107
+
108
+ def start_suite(self, suite):
109
+ return bool(self)
110
+
111
+ def start_keyword(self, kw):
112
+ if self.name_matcher and self.name_matcher.match(kw.name, kw.owner):
113
+ self._flatten(kw)
114
+ if self.tag_matcher and self.tag_matcher.match(kw.tags):
115
+ self._flatten(kw)
116
+
117
+ def start_body_item(self, item):
118
+ if self.type_matcher and self.type_matcher.match(item.type.lower()):
119
+ self._flatten(item)
120
+
121
+ def _flatten(self, item):
122
+ item.message = create_flatten_message(item.message)
123
+ item.body = MessageFinder(item).messages
124
+
125
+ def __bool__(self):
126
+ return bool(self.name_matcher or self.tag_matcher or self.type_matcher)
127
+
128
+
100
129
  class FlattenByTags(SuiteVisitor):
101
130
 
102
131
  def __init__(self, flatten):
@@ -122,3 +151,10 @@ class MessageFinder(SuiteVisitor):
122
151
 
123
152
  def visit_message(self, message):
124
153
  self.messages.append(message)
154
+
155
+
156
+ # TODO: Refactor this module in RF 7.4.
157
+ # - Currently code working with XML tags and model objects is somewhat messy.
158
+ # Either separate it better or make it more generic.
159
+ # - MessageFinder API is now that nice.
160
+ # - The module doesn't anymore contain only matchers so it should be renamed.
@@ -13,13 +13,13 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ from typing import Sequence
16
17
  from xml.etree import ElementTree as ET
17
18
 
18
19
  from robot.errors import DataError
19
- from robot.model import SuiteVisitor
20
20
  from robot.utils import ETSource, get_error_message
21
21
 
22
- from .executionresult import CombinedResult, is_json_source, Result
22
+ from .executionresult import CombinedResult, is_json_source, KeywordRemover, Result
23
23
  from .flattenkeywordmatcher import (
24
24
  create_flatten_message, FlattenByNameMatcher, FlattenByTags, FlattenByTypeMatcher
25
25
  )
@@ -27,20 +27,28 @@ from .merger import Merger
27
27
  from .xmlelementhandlers import XmlElementHandler
28
28
 
29
29
 
30
- def ExecutionResult(*sources, **options):
30
+ def ExecutionResult(
31
+ *sources,
32
+ merge: bool = False,
33
+ include_keywords: bool = True,
34
+ flattened_keywords: Sequence[str] = (),
35
+ rpa: "bool|None" = None,
36
+ ):
31
37
  """Factory method to constructs :class:`~.executionresult.Result` objects.
32
38
 
33
39
  :param sources: XML or JSON source(s) containing execution results.
34
40
  Can be specified as paths (``pathlib.Path`` or ``str``), opened file
35
41
  objects, or strings/bytes containing XML/JSON directly.
36
- :param options: Configuration options.
37
- Using ``merge=True`` causes multiple results to be combined so that
38
- tests in the latter results replace the ones in the original.
39
- Setting ``rpa`` either to ``True`` (RPA mode) or ``False`` (test
40
- automation) sets execution mode explicitly. By default, it is got
42
+ :param merge: When ``True`` and multiple sources are given, results are merged
43
+ instead of combined.
44
+ :param include_keywords: When ``False``, keyword and control structure information
45
+ is not parsed. This can save considerable amount of time and memory.
46
+ :param flattened_keywords: List of patterns controlling what keywords
47
+ and control structures to flatten. See the documentation of
48
+ the ``--flattenkeywords`` option for more details.
49
+ :param rpa: Setting ``rpa`` either to ``True`` (RPA mode) or ``False`` (test
50
+ automation) sets the execution mode explicitly. By default, the mode is got
41
51
  from processed output files and conflicting modes cause an error.
42
- Other options are passed directly to the
43
- :class:`ExecutionResultBuilder` object used internally.
44
52
  :returns: :class:`~.executionresult.Result` instance.
45
53
 
46
54
  A source is considered to be JSON in these cases:
@@ -53,7 +61,12 @@ def ExecutionResult(*sources, **options):
53
61
  """
54
62
  if not sources:
55
63
  raise DataError("One or more data source needed.")
56
- if options.pop("merge", False):
64
+ options = {
65
+ "include_keywords": include_keywords,
66
+ "flattened_keywords": flattened_keywords,
67
+ "rpa": rpa,
68
+ }
69
+ if merge:
57
70
  return _merge_results(sources[0], sources[1:], options)
58
71
  if len(sources) > 1:
59
72
  return _combine_results(sources, options)
@@ -63,8 +76,8 @@ def ExecutionResult(*sources, **options):
63
76
  def _merge_results(original, merged, options):
64
77
  result = ExecutionResult(original, **options)
65
78
  merger = Merger(result, rpa=result.rpa)
66
- for path in merged:
67
- merged = ExecutionResult(path, **options)
79
+ for source in merged:
80
+ merged = ExecutionResult(source, **options)
68
81
  merger.merge(merged)
69
82
  return result
70
83
 
@@ -75,13 +88,13 @@ def _combine_results(sources, options):
75
88
 
76
89
  def _single_result(source, options):
77
90
  if is_json_source(source):
78
- return _json_result(source, options)
79
- return _xml_result(source, options)
91
+ return _json_result(source, **options)
92
+ return _xml_result(source, **options)
80
93
 
81
94
 
82
- def _json_result(source, options):
95
+ def _json_result(source, include_keywords, flattened_keywords, rpa):
83
96
  try:
84
- return Result.from_json(source, rpa=options.get("rpa"))
97
+ return Result.from_json(source, include_keywords, flattened_keywords, rpa)
85
98
  except IOError as err:
86
99
  error = err.strerror
87
100
  except Exception:
@@ -89,11 +102,12 @@ def _json_result(source, options):
89
102
  raise DataError(f"Reading JSON source '{source}' failed: {error}")
90
103
 
91
104
 
92
- def _xml_result(source, options):
105
+ def _xml_result(source, include_keywords, flattened_keywords, rpa):
93
106
  ets = ETSource(source)
94
- result = Result(source, rpa=options.pop("rpa", None))
107
+ builder = ExecutionResultBuilder(ets, include_keywords, flattened_keywords)
108
+ result = Result(source, rpa=rpa)
95
109
  try:
96
- return ExecutionResultBuilder(ets, **options).build(result)
110
+ return builder.build(result)
97
111
  except IOError as err:
98
112
  error = err.strerror
99
113
  except Exception:
@@ -101,6 +115,9 @@ def _xml_result(source, options):
101
115
  raise DataError(f"Reading XML source '{ets}' failed: {error}")
102
116
 
103
117
 
118
+ # TODO:
119
+ # - Rename e.g. to XmlExecutionResultBuilder. Probably best done in a major release.
120
+ # - Add Result.from_xml as a more convenient API. Could be done in RF 7.4.
104
121
  class ExecutionResultBuilder:
105
122
  """Builds :class:`~.executionresult.Result` objects based on XML output files.
106
123
 
@@ -108,7 +125,7 @@ class ExecutionResultBuilder:
108
125
  :func:`ExecutionResult` factory method.
109
126
  """
110
127
 
111
- def __init__(self, source, include_keywords=True, flattened_keywords=None):
128
+ def __init__(self, source, include_keywords=True, flattened_keywords=()):
112
129
  """
113
130
  :param source: Path to the XML output file to build
114
131
  :class:`~.executionresult.Result` objects from.
@@ -134,7 +151,7 @@ class ExecutionResultBuilder:
134
151
  # flatten based on them when parsing output.xml.
135
152
  result.suite.visit(FlattenByTags(self._flattened_keywords))
136
153
  if not self._include_keywords:
137
- result.suite.visit(RemoveKeywords())
154
+ result.suite.visit(KeywordRemover())
138
155
  return result
139
156
 
140
157
  def _parse(self, source, start, end):
@@ -151,11 +168,11 @@ class ExecutionResultBuilder:
151
168
  elem.clear()
152
169
 
153
170
  def _omit_keywords(self, context):
154
- omitted_elements = {"kw", "for", "while", "if", "try"}
171
+ omitted_elements = {"kw", "for", "while", "if", "try", "group", "variable"}
155
172
  omitted = 0
156
173
  for event, elem in context:
157
- # Teardowns aren't omitted yet to allow checking suite teardown status.
158
- # They'll be removed later when not needed in `build()`.
174
+ # Teardowns cannot be removed yet, because we need to check suite
175
+ # teardown status. They are removed later using KeywordRemover.
159
176
  omit = elem.tag in omitted_elements and elem.get("type") != "TEARDOWN"
160
177
  start = event == "start"
161
178
  if omit and start:
@@ -172,44 +189,33 @@ class ExecutionResultBuilder:
172
189
  name_match, by_name = self._get_matcher(FlattenByNameMatcher, flattened)
173
190
  type_match, by_type = self._get_matcher(FlattenByTypeMatcher, flattened)
174
191
  started = -1 # If 0 or more, we are flattening.
175
- containers = {"kw", "for", "while", "iter", "if", "try"}
176
- inside = 0 # To make sure we don't read tags from a test.
192
+ include_on_top = {"doc", "tag", "timeout", "status"}
177
193
  for event, elem in context:
178
194
  tag = elem.tag
179
195
  if event == "start":
180
- if tag in containers:
181
- inside += 1
182
- if started >= 0:
183
- started += 1
184
- elif by_name and name_match(
196
+ if started >= 0:
197
+ started += 1
198
+ elif (
199
+ by_name
200
+ and tag == "kw"
201
+ and name_match(
185
202
  elem.get("name", ""),
186
203
  elem.get("owner") or elem.get("library"),
187
- ):
188
- started = 0
189
- elif by_type and type_match(tag):
190
- started = 0
191
- else:
192
- if tag in containers:
193
- inside -= 1
194
- elif started == 0 and tag == "status":
195
- elem.text = create_flatten_message(elem.text)
196
- if started <= 0 or tag == "msg":
204
+ # 'library' is for RF < 7 compatibility
205
+ )
206
+ ):
207
+ started = 0
208
+ elif by_type and type_match(tag):
209
+ started = 0
210
+ elif started == 1 and tag == "status":
211
+ elem.text = create_flatten_message(elem.text)
212
+ if started <= 0 or (started == 1 and tag in include_on_top) or tag == "msg":
197
213
  yield event, elem
198
214
  else:
199
215
  elem.clear()
200
- if started >= 0 and event == "end" and tag in containers:
216
+ if started >= 0 and event == "end":
201
217
  started -= 1
202
218
 
203
219
  def _get_matcher(self, matcher_class, flattened):
204
220
  matcher = matcher_class(flattened)
205
221
  return matcher.match, bool(matcher)
206
-
207
-
208
- class RemoveKeywords(SuiteVisitor):
209
-
210
- def start_suite(self, suite):
211
- suite.setup = None
212
- suite.teardown = None
213
-
214
- def visit_test(self, test):
215
- test.body = []
@@ -19,12 +19,12 @@ from robot.model import SuiteVisitor
19
19
  class SuiteTeardownFailureHandler(SuiteVisitor):
20
20
 
21
21
  def end_suite(self, suite):
22
- teardown = suite.teardown
23
- # Both 'PASS' and 'NOT RUN' statuses are OK.
24
- if teardown and teardown.status == teardown.FAIL:
25
- suite.suite_teardown_failed(teardown.message)
26
- if teardown and teardown.status == teardown.SKIP:
27
- suite.suite_teardown_skipped(teardown.message)
22
+ if suite.has_teardown:
23
+ teardown = suite.teardown
24
+ if teardown.status == teardown.FAIL:
25
+ suite.suite_teardown_failed(teardown.message)
26
+ if teardown.status == teardown.SKIP:
27
+ suite.suite_teardown_skipped(teardown.message)
28
28
 
29
29
  def visit_test(self, test):
30
30
  pass
@@ -108,7 +108,9 @@ class KeywordRunner:
108
108
  # BuiltIn.run_keyword has the same logic.
109
109
  runner = context.get_runner(name, recommend_on_failure=self._run)
110
110
  if hasattr(runner, "embedded_args") and name != data.name:
111
- runner = context.get_runner(data.name)
111
+ candidate = context.get_runner(data.name)
112
+ if hasattr(candidate, "embedded_args"):
113
+ runner = candidate
112
114
  return runner
113
115
 
114
116
 
@@ -17,6 +17,7 @@ import copy
17
17
  import os
18
18
  from collections import OrderedDict
19
19
 
20
+ from robot.conf import Languages
20
21
  from robot.errors import DataError, KeywordError
21
22
  from robot.libraries import STDLIBS
22
23
  from robot.output import LOGGER, Message
@@ -231,7 +232,7 @@ class Namespace:
231
232
 
232
233
  class KeywordStore:
233
234
 
234
- def __init__(self, suite_file, languages):
235
+ def __init__(self, suite_file, languages: Languages):
235
236
  self.suite_file = suite_file
236
237
  self.libraries = OrderedDict()
237
238
  self.resources = ImportCache()
@@ -300,6 +301,9 @@ class KeywordStore:
300
301
  runner = None
301
302
  if strip_bdd_prefix:
302
303
  runner = self._get_bdd_style_runner(name)
304
+ if runner:
305
+ runner = copy.copy(runner)
306
+ runner.name = name
303
307
  if not runner:
304
308
  runner = self._get_runner_from_suite_file(name)
305
309
  if not runner and "." in name:
@@ -309,13 +313,27 @@ class KeywordStore:
309
313
  return runner
310
314
 
311
315
  def _get_bdd_style_runner(self, name):
316
+ # TODO: Consider using 'startswith' instead of regexps for checking does any
317
+ # prefix match. That ought to make that check a bit faster (especially if the
318
+ # tuple of prefixes is pre-built in 'Languages'), but finding the keyword if
319
+ # there's a match can be a bit slower. It also makes it explicit that prefixes
320
+ # are constants, not patterns, and allows deprecating 'bdd_prefix_regexp'.
312
321
  match = self.languages.bdd_prefix_regexp.match(name)
313
- if match:
314
- runner = self._get_runner(name[match.end() :], strip_bdd_prefix=False)
315
- if runner:
316
- runner = copy.copy(runner)
317
- runner.name = name
318
- return runner
322
+ if not match:
323
+ return None
324
+ runner = self._get_runner(name[match.end() :], strip_bdd_prefix=False)
325
+ if runner:
326
+ return runner
327
+ # Some prefix matched, but there was no matching keyword. Go through all
328
+ # prefixes individually to see were there possibly multiple matching ones.
329
+ # https://github.com/robotframework/robotframework/issues/5456
330
+ name = " ".join(name.split()).title() # Normalize spaces and case.
331
+ for prefix in sorted(self.languages.bdd_prefixes, key=len, reverse=True):
332
+ prefix += " "
333
+ if name.startswith(prefix):
334
+ runner = self._get_runner(name[len(prefix) :], strip_bdd_prefix=False)
335
+ if runner:
336
+ return runner
319
337
  return None
320
338
 
321
339
  def _get_implicit_runner(self, name):
@@ -15,15 +15,48 @@
15
15
 
16
16
  import json
17
17
  from pathlib import Path
18
- from typing import Any, Dict, overload, TextIO
18
+ from typing import Dict, overload, TextIO
19
19
 
20
20
  from .error import get_error_message
21
21
  from .robottypes import type_name
22
22
 
23
- DataDict = Dict[str, Any]
23
+ DataDict = Dict[str, object]
24
24
 
25
25
 
26
26
  class JsonLoader:
27
+ """Generic JSON object loader.
28
+
29
+ JSON source can be a string or bytes, a path or an open file object.
30
+ The top level JSON item must always be a dictionary.
31
+
32
+ Supports the same configuration parameters as the underlying `json.load`__
33
+ except for ``object_pairs_hook``. As a special feature, handles duplicate
34
+ items so that lists are merged.
35
+
36
+ __ https://docs.python.org/3/library/json.html#json.load
37
+ """
38
+
39
+ def __init__(self, **config):
40
+ self.config = self._add_hook_to_merge_duplicate_lists(config)
41
+
42
+ def _add_hook_to_merge_duplicate_lists(self, config):
43
+ object_hook = config.get("object_hook")
44
+ object_pairs_hook = config.get("object_pairs_hook")
45
+ if object_pairs_hook:
46
+ raise ValueError("'object_pairs_hook' is not supported.")
47
+
48
+ def merge_duplicate_lists(items: "list[tuple[str, object]]") -> DataDict:
49
+ data = {}
50
+ for name, value in items:
51
+ if name in data and isinstance(value, list):
52
+ data[name].extend(value)
53
+ else:
54
+ data[name] = value
55
+ return object_hook(data) if object_hook else data
56
+
57
+ config["object_pairs_hook"] = merge_duplicate_lists
58
+ return config
59
+
27
60
  def load(self, source: "str|bytes|TextIO|Path") -> DataDict:
28
61
  try:
29
62
  data = self._load(source)
@@ -33,21 +66,30 @@ class JsonLoader:
33
66
  raise TypeError(f"Expected dictionary, got {type_name(data)}.")
34
67
  return data
35
68
 
36
- def _load(self, source):
69
+ def _load(self, source: "str|bytes|TextIO|Path") -> object:
37
70
  if self._is_path(source):
38
71
  with open(source, encoding="UTF-8") as file:
39
- return json.load(file)
72
+ return json.load(file, **self.config)
40
73
  if hasattr(source, "read"):
41
- return json.load(source)
42
- return json.loads(source)
74
+ return json.load(source, **self.config)
75
+ return json.loads(source, **self.config)
43
76
 
44
- def _is_path(self, source):
77
+ def _is_path(self, source: "str|bytes|TextIO|Path") -> bool:
45
78
  if isinstance(source, Path):
46
79
  return True
47
80
  return isinstance(source, str) and "{" not in source
48
81
 
49
82
 
50
83
  class JsonDumper:
84
+ """Generic JSON dumper.
85
+
86
+ JSON can be written to a file given as a path or as an open file object.
87
+ If no output is given, JSON is returned as a string.
88
+
89
+ Supports the same configuration as the underlying `json.dump`__.
90
+
91
+ __ https://docs.python.org/3/library/json.html#json.load
92
+ """
51
93
 
52
94
  def __init__(self, **config):
53
95
  self.config = config
@@ -64,8 +106,10 @@ class JsonDumper:
64
106
  elif isinstance(output, (str, Path)):
65
107
  with open(output, "w", encoding="UTF-8") as file:
66
108
  json.dump(data, file, **self.config)
109
+ return None
67
110
  elif hasattr(output, "write"):
68
111
  json.dump(data, output, **self.config)
112
+ return None
69
113
  else:
70
114
  raise TypeError(
71
115
  f"Output should be None, path or open file, got {type_name(output)}."
@@ -18,7 +18,7 @@ import sys
18
18
 
19
19
  # Version number typically updated by running `invoke set-version <version>`.
20
20
  # Run `invoke --help set-version` or see tasks.py for details.
21
- VERSION = "7.3.1"
21
+ VERSION = "7.3.2"
22
22
 
23
23
 
24
24
  def get_version(naked=False):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: robotframework
3
- Version: 7.3.1
3
+ Version: 7.3.2
4
4
  Summary: Generic automation framework for acceptance testing and robotic process automation (RPA)
5
5
  Home-page: https://robotframework.org
6
6
  Download-URL: https://pypi.org/project/robotframework
@@ -10,7 +10,7 @@ License: Apache License 2.0
10
10
  Project-URL: Source, https://github.com/robotframework/robotframework
11
11
  Project-URL: Issue Tracker, https://github.com/robotframework/robotframework/issues
12
12
  Project-URL: Documentation, https://robotframework.org/robotframework
13
- Project-URL: Release Notes, https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.3.1.rst
13
+ Project-URL: Release Notes, https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.3.2.rst
14
14
  Project-URL: Slack, http://slack.robotframework.org
15
15
  Keywords: robotframework automation testautomation rpa testing acceptancetesting atdd bdd
16
16
  Platform: any