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
@@ -105,9 +105,9 @@ removed altogether if they get in the way.
105
105
  from typing import TYPE_CHECKING
106
106
 
107
107
  if TYPE_CHECKING:
108
- from robot.model import (Break, BodyItem, Continue, Error, For, If, IfBranch,
109
- Keyword, Message, Return, TestCase, TestSuite, Try,
110
- TryBranch, Var, While)
108
+ from robot.model import (Break, BodyItem, Continue, Error, For, Group, If,
109
+ IfBranch, Keyword, Message, Return, TestCase, TestSuite,
110
+ Try, TryBranch, Var, While)
111
111
  from robot.result import ForIteration, WhileIteration
112
112
 
113
113
 
@@ -427,6 +427,32 @@ class SuiteVisitor:
427
427
  """
428
428
  self.end_body_item(iteration)
429
429
 
430
+ def visit_group(self, group: 'Group'):
431
+ """Visits GROUP elements.
432
+
433
+ Can be overridden to allow modifying the passed in ``group`` without
434
+ calling :meth:`start_group` or :meth:`end_group` nor visiting body.
435
+ """
436
+ if self.start_group(group) is not False:
437
+ group.body.visit(self)
438
+ self.end_group(group)
439
+
440
+ def start_group(self, group: 'Group') -> 'bool|None':
441
+ """Called when a GROUP element starts.
442
+
443
+ By default, calls :meth:`start_body_item` which, by default, does nothing.
444
+
445
+ Can return explicit ``False`` to stop visiting.
446
+ """
447
+ return self.start_body_item(group)
448
+
449
+ def end_group(self, group: 'Group'):
450
+ """Called when a GROUP element ends.
451
+
452
+ By default, calls :meth:`end_body_item` which, by default, does nothing.
453
+ """
454
+ self.end_body_item(group)
455
+
430
456
  def visit_var(self, var: 'Var'):
431
457
  """Visits a VAR elements."""
432
458
  if self.start_var(var) is not False:
@@ -19,7 +19,8 @@ Not part of the public API, and also subject to change in the future when
19
19
  test execution is refactored.
20
20
  """
21
21
 
22
- from .output import Output
23
22
  from .logger import LOGGER
24
- from .xmllogger import XmlLogger
25
23
  from .loggerhelper import LEVELS, Message
24
+ from .loglevel import LogLevel
25
+ from .output import Output
26
+ from .xmllogger import XmlLogger
@@ -14,14 +14,17 @@
14
14
  # limitations under the License.
15
15
 
16
16
  import sys
17
+ from typing import TYPE_CHECKING
17
18
 
18
19
  from robot.model import SuiteVisitor
19
- from robot.result import TestCase, TestSuite
20
20
  from robot.utils import plural_or_not as s, secs_to_timestr
21
21
 
22
22
  from .highlighting import HighlightingStream
23
23
  from ..loggerapi import LoggerApi
24
24
 
25
+ if TYPE_CHECKING:
26
+ from robot.result import TestCase, TestSuite
27
+
25
28
 
26
29
  class DottedOutput(LoggerApi):
27
30
 
@@ -72,7 +75,7 @@ class StatusReporter(SuiteVisitor):
72
75
  self.stream = stream
73
76
  self.width = width
74
77
 
75
- def report(self, suite: TestSuite):
78
+ def report(self, suite: 'TestSuite'):
76
79
  suite.visit(self)
77
80
  stats = suite.statistics
78
81
  ts = ('test' if not suite.rpa else 'task') + s(stats.total)
@@ -83,7 +86,7 @@ class StatusReporter(SuiteVisitor):
83
86
  self.stream.highlight(suite.status + ed, suite.status)
84
87
  self.stream.write(f'\n{stats.message}\n')
85
88
 
86
- def visit_test(self, test: TestCase):
89
+ def visit_test(self, test: 'TestCase'):
87
90
  if test.failed and not test.tags.robot('exit'):
88
91
  self.stream.write('-' * self.width + '\n')
89
92
  self.stream.highlight('FAIL')
@@ -19,7 +19,6 @@
19
19
 
20
20
  import errno
21
21
  import os
22
- import socket
23
22
  import sys
24
23
  from contextlib import contextmanager
25
24
  try:
@@ -44,10 +43,12 @@ from robot.utils import console_encode, isatty, WINDOWS
44
43
  class HighlightingStream:
45
44
 
46
45
  def __init__(self, stream, colors='AUTO', links='AUTO'):
47
- self.stream = stream
46
+ self.stream = stream or NullStream()
48
47
  self._highlighter = self._get_highlighter(stream, colors, links)
49
48
 
50
49
  def _get_highlighter(self, stream, colors, links):
50
+ if not stream:
51
+ return NoHighlighting()
51
52
  options = {'AUTO': Highlighter if isatty(stream) else NoHighlighting,
52
53
  'ON': Highlighter,
53
54
  'OFF': NoHighlighting,
@@ -103,7 +104,7 @@ class HighlightingStream:
103
104
  def error(self, message, level):
104
105
  self.write('[ ', flush=False)
105
106
  self.highlight(level, flush=False)
106
- self.write(' ] %s\n' % message)
107
+ self.write(f' ] {message}\n')
107
108
 
108
109
  @contextmanager
109
110
  def _highlighting(self, status):
@@ -120,10 +121,19 @@ class HighlightingStream:
120
121
  highlighter.reset()
121
122
 
122
123
  def result_file(self, kind, path):
123
- path = self._highlighter.link(path)
124
+ path = self._highlighter.link(path) if path else 'NONE'
124
125
  self.write(f"{kind + ':':8} {path}\n")
125
126
 
126
127
 
128
+ class NullStream:
129
+
130
+ def write(self, text):
131
+ pass
132
+
133
+ def flush(self):
134
+ pass
135
+
136
+
127
137
  def Highlighter(stream, links=True):
128
138
  if os.sep == '/':
129
139
  return AnsiHighlighter(stream, links)
@@ -163,12 +173,7 @@ class AnsiHighlighter:
163
173
  uri = path.as_uri()
164
174
  except ValueError:
165
175
  return path
166
- # Add the host name to the URI to support opening links remotely.
167
- # Windows Terminal doesn't yet support the host component, though:
168
- # https://github.com/microsoft/terminal/issues/14116
169
- if uri[:8] == 'file:///' and not WINDOWS:
170
- uri = f'file://{socket.getfqdn()}/{uri[8:]}'
171
- # The hyperlink format is documented here:
176
+ # Terminal hyperlink syntax is documented here:
172
177
  # https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
173
178
  return f'\033]8;;{uri}\033\\{path}\033]8;;\033\\'
174
179
 
@@ -178,6 +183,9 @@ class AnsiHighlighter:
178
183
 
179
184
  class NoHighlighting(AnsiHighlighter):
180
185
 
186
+ def __init__(self, stream=None, links=True):
187
+ super().__init__(stream, links)
188
+
181
189
  def link(self, path):
182
190
  return path
183
191
 
@@ -20,7 +20,7 @@ from robot.utils import file_writer, seq2str2
20
20
 
21
21
  from .logger import LOGGER
22
22
  from .loggerapi import LoggerApi
23
- from .loggerhelper import IsLogged
23
+ from .loglevel import LogLevel
24
24
 
25
25
 
26
26
  def DebugFile(path):
@@ -45,7 +45,7 @@ class _DebugFileWriter(LoggerApi):
45
45
  self._kw_level = 0
46
46
  self._separator_written_last = False
47
47
  self._outfile = outfile
48
- self._is_logged = IsLogged('DEBUG')
48
+ self._is_logged = LogLevel('DEBUG').is_logged
49
49
 
50
50
  def start_suite(self, data, result):
51
51
  self._separator('SUITE')
@@ -91,7 +91,7 @@ class _DebugFileWriter(LoggerApi):
91
91
  self._kw_level -= 1
92
92
 
93
93
  def log_message(self, msg):
94
- if self._is_logged(msg.level):
94
+ if self._is_logged(msg):
95
95
  self._write(f'{msg.timestamp} - {msg.level} - {msg.message}')
96
96
 
97
97
  def close(self):
@@ -15,21 +15,25 @@
15
15
 
16
16
  from robot.utils import file_writer
17
17
 
18
- from .loggerhelper import AbstractLogger
19
18
  from .loggerapi import LoggerApi
19
+ from .loggerhelper import AbstractLogger
20
+ from .loglevel import LogLevel
20
21
 
21
22
 
22
23
  class FileLogger(AbstractLogger, LoggerApi):
23
24
 
24
25
  def __init__(self, path, level):
25
- super().__init__(level)
26
+ self._log_level = LogLevel(level)
26
27
  self._writer = self._get_writer(path) # unit test hook
27
28
 
28
29
  def _get_writer(self, path):
29
30
  return file_writer(path, usage='syslog')
30
31
 
32
+ def set_level(self, level):
33
+ self._log_level.set(level)
34
+
31
35
  def message(self, msg):
32
- if self._is_logged(msg.level) and not self._writer.closed:
36
+ if self._log_level.is_logged(msg) and not self._writer.closed:
33
37
  entry = '%s | %s | %s\n' % (msg.timestamp, msg.level.ljust(5),
34
38
  msg.message)
35
39
  self._writer.write(entry)
@@ -0,0 +1,338 @@
1
+ # Copyright 2008-2015 Nokia Networks
2
+ # Copyright 2016- Robot Framework Foundation
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import json
17
+ from collections.abc import Mapping, Sequence
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+ from typing import TextIO
21
+
22
+ from robot.version import get_full_version
23
+
24
+
25
+ class JsonLogger:
26
+
27
+ def __init__(self, file: TextIO, rpa: bool = False):
28
+ self.writer = JsonWriter(file)
29
+ self.writer.start_dict(generator=get_full_version('Robot'),
30
+ generated=datetime.now().isoformat(),
31
+ rpa=Raw(self.writer.encode(rpa)))
32
+ self.containers = []
33
+
34
+ def start_suite(self, suite):
35
+ if not self.containers:
36
+ name = 'suite'
37
+ container = None
38
+ else:
39
+ name = None
40
+ container = 'suites'
41
+ self._start(container, name, id=suite.id)
42
+
43
+ def end_suite(self, suite):
44
+ self._end(name=suite.name,
45
+ doc=suite.doc,
46
+ metadata=suite.metadata,
47
+ source=suite.source,
48
+ rpa=suite.rpa,
49
+ **self._status(suite))
50
+
51
+ def start_test(self, test):
52
+ self._start('tests', id=test.id)
53
+
54
+ def end_test(self, test):
55
+ self._end(name=test.name,
56
+ doc=test.doc,
57
+ tags=test.tags,
58
+ lineno=test.lineno,
59
+ timeout=str(test.timeout) if test.timeout else None,
60
+ **self._status(test))
61
+
62
+ def start_keyword(self, kw):
63
+ if kw.type in ('SETUP', 'TEARDOWN'):
64
+ self._end_container()
65
+ name = kw.type.lower()
66
+ container = None
67
+ else:
68
+ name = None
69
+ container = 'body'
70
+ self._start(container, name)
71
+
72
+ def end_keyword(self, kw):
73
+ self._end(name=kw.name,
74
+ owner=kw.owner,
75
+ source_name=kw.source_name,
76
+ args=[str(a) for a in kw.args],
77
+ assign=kw.assign,
78
+ tags=kw.tags,
79
+ doc=kw.doc,
80
+ timeout=str(kw.timeout) if kw.timeout else None,
81
+ **self._status(kw))
82
+
83
+ def start_for(self, item):
84
+ self._start(type=item.type)
85
+
86
+ def end_for(self, item):
87
+ self._end(flavor=item.flavor,
88
+ start=item.start,
89
+ mode=item.mode,
90
+ fill=UnlessNone(item.fill),
91
+ assign=item.assign,
92
+ values=item.values,
93
+ **self._status(item))
94
+
95
+ def start_for_iteration(self, item):
96
+ self._start(type=item.type)
97
+
98
+ def end_for_iteration(self, item):
99
+ self._end(assign=item.assign, **self._status(item))
100
+
101
+ def start_while(self, item):
102
+ self._start(type=item.type)
103
+
104
+ def end_while(self, item):
105
+ self._end(condition=item.condition,
106
+ limit=item.limit,
107
+ on_limit=item.on_limit,
108
+ on_limit_message=item.on_limit_message,
109
+ **self._status(item))
110
+
111
+ def start_while_iteration(self, item):
112
+ self._start(type=item.type)
113
+
114
+ def end_while_iteration(self, item):
115
+ self._end(**self._status(item))
116
+
117
+ def start_if(self, item):
118
+ self._start(type=item.type)
119
+
120
+ def end_if(self, item):
121
+ self._end(**self._status(item))
122
+
123
+ def start_if_branch(self, item):
124
+ self._start(type=item.type)
125
+
126
+ def end_if_branch(self, item):
127
+ self._end(condition=item.condition, **self._status(item))
128
+
129
+ def start_try(self, item):
130
+ self._start(type=item.type)
131
+
132
+ def end_try(self, item):
133
+ self._end(**self._status(item))
134
+
135
+ def start_try_branch(self, item):
136
+ self._start(type=item.type)
137
+
138
+ def end_try_branch(self, item):
139
+ self._end(patterns=item.patterns,
140
+ pattern_type=item.pattern_type,
141
+ assign=item.assign,
142
+ **self._status(item))
143
+
144
+ def start_group(self, item):
145
+ self._start(type=item.type)
146
+
147
+ def end_group(self, item):
148
+ self._end(name=item.name,
149
+ **self._status(item))
150
+
151
+ def start_var(self, item):
152
+ self._start(type=item.type)
153
+
154
+ def end_var(self, item):
155
+ self._end(name=item.name,
156
+ scope=item.scope,
157
+ separator=UnlessNone(item.separator),
158
+ value=item.value,
159
+ **self._status(item))
160
+
161
+ def start_return(self, item):
162
+ self._start(type=item.type)
163
+
164
+ def end_return(self, item):
165
+ self._end(values=item.values, **self._status(item))
166
+
167
+ def start_continue(self, item):
168
+ self._start(type=item.type)
169
+
170
+ def end_continue(self, item):
171
+ self._end(**self._status(item))
172
+
173
+ def start_break(self, item):
174
+ self._start(type=item.type)
175
+
176
+ def end_break(self, item):
177
+ self._end(**self._status(item))
178
+
179
+ def start_error(self, item):
180
+ self._start(type=item.type)
181
+
182
+ def end_error(self, item):
183
+ self._end(values=item.values, **self._status(item))
184
+
185
+ def message(self, msg):
186
+ self._dict(**msg.to_dict())
187
+
188
+ def errors(self, messages):
189
+ self._list('errors', [m.to_dict(include_type=False) for m in messages])
190
+
191
+ def statistics(self, stats):
192
+ data = stats.to_dict()
193
+ self._start(None, 'statistics')
194
+ self._dict(None, 'total', **data['total'])
195
+ self._list('suites', data['suites'])
196
+ self._list('tags', data['tags'])
197
+ self._end()
198
+
199
+ def close(self):
200
+ self.writer.end_dict()
201
+ self.writer.close()
202
+
203
+ def _status(self, item):
204
+ return {'status': item.status,
205
+ 'message': item.message,
206
+ 'start_time': item.start_time.isoformat() if item.start_time else None,
207
+ 'elapsed_time': Raw(format(item.elapsed_time.total_seconds(), 'f'))}
208
+
209
+ def _dict(self, container: 'str|None' = 'body', name: 'str|None' = None, /,
210
+ **items):
211
+ self._start(container, name, **items)
212
+ self._end()
213
+
214
+ def _list(self, name: 'str|None', items: list):
215
+ self.writer.start_list(name)
216
+ for item in items:
217
+ self._dict(None, None, **item)
218
+ self.writer.end_list()
219
+
220
+ def _start(self, container: 'str|None' = 'body', name: 'str|None' = None, /,
221
+ **items):
222
+ if container:
223
+ self._start_container(container)
224
+ self.writer.start_dict(name, **items)
225
+ self.containers.append(None)
226
+
227
+ def _start_container(self, container):
228
+ if self.containers[-1] != container:
229
+ if self.containers[-1]:
230
+ self.writer.end_list()
231
+ self.writer.start_list(container)
232
+ self.containers[-1] = container
233
+
234
+ def _end(self, **items):
235
+ self._end_container()
236
+ self.containers.pop()
237
+ self.writer.end_dict(**items)
238
+
239
+ def _end_container(self):
240
+ if self.containers[-1]:
241
+ self.writer.end_list()
242
+ self.containers[-1] = None
243
+
244
+
245
+ class JsonWriter:
246
+
247
+ def __init__(self, file):
248
+ self.encode = json.JSONEncoder(check_circular=False,
249
+ separators=(',', ':'),
250
+ default=self._handle_custom).encode
251
+ self.file = file
252
+ self.comma = False
253
+ self.newline = False
254
+
255
+ def _handle_custom(self, value):
256
+ if isinstance(value, Path):
257
+ return str(value)
258
+ if isinstance(value, Mapping):
259
+ return dict(value)
260
+ if isinstance(value, Sequence):
261
+ return list(value)
262
+ raise TypeError(type(value).__name__)
263
+
264
+ def start_dict(self, name=None, /, **items):
265
+ self._start(name, '{')
266
+ self.items(**items)
267
+
268
+ def _start(self, name, char):
269
+ self._newline(newline=name is not None)
270
+ self._name(name)
271
+ self._write(char)
272
+ self.comma = False
273
+
274
+ def _newline(self, comma: 'bool|None' = None, newline: 'bool|None' = None):
275
+ if (self.comma if comma is None else comma):
276
+ self._write(',')
277
+ if (self.newline if newline is None else newline):
278
+ self._write('\n')
279
+ self.newline = True
280
+
281
+ def _name(self, name):
282
+ if name:
283
+ self._write(f'"{name}":')
284
+
285
+ def _write(self, text):
286
+ self.file.write(text)
287
+
288
+ def end_dict(self, **items):
289
+ self.items(**items)
290
+ self._end('}')
291
+
292
+ def _end(self, char, newline=True):
293
+ self._newline(comma=False, newline=newline)
294
+ self._write(char)
295
+ self.comma = True
296
+
297
+ def start_list(self, name=None, /):
298
+ self._start(name, '[')
299
+
300
+ def end_list(self):
301
+ self._end(']', newline=False)
302
+
303
+ def items(self, **items):
304
+ for name, value in items.items():
305
+ self._item(value, name)
306
+
307
+ def _item(self, value, name=None):
308
+ if isinstance(value, UnlessNone) and value:
309
+ value = value.value
310
+ elif not (value or value == 0 and not isinstance(value, bool)):
311
+ return
312
+ if isinstance(value, Raw):
313
+ value = value.value
314
+ else:
315
+ value = self.encode(value)
316
+ self._newline()
317
+ self._name(name)
318
+ self._write(value)
319
+ self.comma = True
320
+
321
+ def close(self):
322
+ self._write('\n')
323
+ self.file.close()
324
+
325
+
326
+ class Raw:
327
+
328
+ def __init__(self, value):
329
+ self.value = value
330
+
331
+
332
+ class UnlessNone:
333
+
334
+ def __init__(self, value):
335
+ self.value = value
336
+
337
+ def __bool__(self):
338
+ return self.value is not None
@@ -19,29 +19,30 @@ This is exposed via :py:mod:`robot.api.logger`. Implementation must reside
19
19
  here to avoid cyclic imports.
20
20
  """
21
21
 
22
- import threading
23
- from typing import Callable
22
+ from threading import current_thread
23
+ from typing import Any
24
+
25
+ from robot.utils import safe_str
24
26
 
25
27
  from .logger import LOGGER
26
28
  from .loggerhelper import Message, write_to_console
27
29
 
28
30
 
29
- LOGGING_THREADS = ('MainThread', 'RobotFrameworkTimeoutThread')
31
+ # This constant is used by BackgroundLogger.
32
+ # https://github.com/robotframework/robotbackgroundlogger
33
+ LOGGING_THREADS = ['MainThread', 'RobotFrameworkTimeoutThread']
30
34
 
31
35
 
32
- def write(msg: 'str | Callable[[], str]', level: str, html: bool = False):
33
- # Callable messages allow lazy logging internally, but we don't want to
34
- # expose this functionality publicly. See the following issue for details:
35
- # https://github.com/robotframework/robotframework/issues/1505
36
- if callable(msg):
37
- msg = str(msg)
36
+ def write(msg: Any, level: str, html: bool = False):
37
+ if not isinstance(msg, str):
38
+ msg = safe_str(msg)
38
39
  if level.upper() not in ('TRACE', 'DEBUG', 'INFO', 'HTML', 'WARN', 'ERROR'):
39
40
  if level.upper() == 'CONSOLE':
40
41
  level = 'INFO'
41
42
  console(msg)
42
43
  else:
43
- raise RuntimeError("Invalid log level '%s'." % level)
44
- if threading.current_thread().name in LOGGING_THREADS:
44
+ raise RuntimeError(f"Invalid log level '{level}'.")
45
+ if current_thread().name in LOGGING_THREADS:
45
46
  LOGGER.log_message(Message(msg, level, html))
46
47
 
47
48