robotframework 6.1rc1__zip → 7.0__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotframework-6.1rc1 → robotframework-7.0}/INSTALL.rst +25 -25
- {robotframework-6.1rc1 → robotframework-7.0}/PKG-INFO +6 -8
- {robotframework-6.1rc1 → robotframework-7.0}/README.rst +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/setup.py +3 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/__init__.py +4 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/deco.py +60 -14
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/exceptions.py +6 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/interfaces.py +403 -68
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/logger.py +27 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/parsing.py +4 -2
- robotframework-7.0/src/robot/api/py.typed +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/gatherfailed.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/languages.py +61 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/settings.py +21 -14
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/storage.js +11 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/htmlfilewriter.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.css +10 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.html +10 -0
- robotframework-7.0/src/robot/htmldata/rebot/common.css +362 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/doc_formatting.css +13 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.css +51 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.html +14 -23
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/model.js +2 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.css +83 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.html +22 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/testdata.js +10 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/view.js +84 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/template.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/builder.py +0 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/datatypes.py +9 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlutils.py +4 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonbuilder.py +38 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/model.py +21 -28
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/robotbuilder.py +50 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/standardtypes.py +9 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlbuilder.py +35 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlwriter.py +18 -38
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/BuiltIn.py +255 -205
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Collections.py +384 -240
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/DateTime.py +73 -60
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/OperatingSystem.py +6 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Process.py +26 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Remote.py +40 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/String.py +66 -76
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/XML.py +66 -59
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/dialogs_py.py +14 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/__init__.py +5 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/body.py +44 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/configurer.py +19 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/control.py +230 -88
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/filter.py +31 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/itemlist.py +9 -8
- robotframework-7.0/src/robot/model/keyword.py +77 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/message.py +19 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modelobject.py +27 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modifier.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/namepatterns.py +3 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/stats.py +9 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tags.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testcase.py +15 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testsuite.py +44 -28
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/visitor.py +35 -8
- robotframework-7.0/src/robot/output/console/dotted.py +90 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/quiet.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/verbose.py +61 -61
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/debugfile.py +39 -24
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/filelogger.py +18 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/librarylogger.py +3 -2
- robotframework-7.0/src/robot/output/listeners.py +753 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/logger.py +216 -80
- robotframework-7.0/src/robot/output/loggerapi.py +215 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/loggerhelper.py +23 -56
- robotframework-7.0/src/robot/output/output.py +185 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/stdoutlogsplitter.py +8 -5
- robotframework-7.0/src/robot/output/xmllogger.py +459 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/blocklexers.py +17 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/context.py +12 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/lexer.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/settings.py +6 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/statementlexers.py +39 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokens.py +27 -29
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/blocks.py +19 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/statements.py +193 -94
- robotframework-7.0/src/robot/parsing/model/visitor.py +100 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/rebot.py +2 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/expandkeywordmatcher.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsbuildingcontext.py +8 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsmodelbuilders.py +88 -61
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/logreportwriters.py +16 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/outputwriter.py +18 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/resultwriter.py +4 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/stringcache.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/xunitwriter.py +15 -21
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/__init__.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/configurer.py +12 -9
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionresult.py +56 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/flattenkeywordmatcher.py +48 -9
- robotframework-7.0/src/robot/result/keywordremover.py +207 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/merger.py +1 -1
- robotframework-7.0/src/robot/result/model.py +1185 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/modeldeprecation.py +9 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/resultbuilder.py +46 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/xmlelementhandlers.py +83 -43
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/run.py +3 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/__init__.py +14 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/__init__.py +2 -1
- robotframework-7.0/src/robot/running/arguments/argumentconverter.py +100 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentmapper.py +26 -24
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentparser.py +85 -61
- robotframework-7.0/src/robot/running/arguments/argumentresolver.py +158 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentspec.py +83 -116
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentvalidator.py +33 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/customconverters.py +15 -12
- robotframework-7.0/src/robot/running/arguments/embedded.py +145 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/typeconverters.py +268 -220
- robotframework-7.0/src/robot/running/arguments/typeinfo.py +317 -0
- robotframework-7.0/src/robot/running/arguments/typeinfoparser.py +219 -0
- robotframework-7.0/src/robot/running/arguments/typevalidator.py +60 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/bodyrunner.py +147 -129
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/builders.py +17 -26
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/parsers.py +17 -11
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/settings.py +9 -17
- robotframework-7.0/src/robot/running/builder/transformers.py +535 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/context.py +113 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/dynamicmethods.py +62 -34
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/importer.py +27 -49
- robotframework-7.0/src/robot/running/invalidkeyword.py +67 -0
- robotframework-7.0/src/robot/running/keywordfinder.py +91 -0
- robotframework-7.0/src/robot/running/keywordimplementation.py +164 -0
- robotframework-7.0/src/robot/running/librarykeyword.py +392 -0
- robotframework-7.0/src/robot/running/librarykeywordrunner.py +250 -0
- robotframework-7.0/src/robot/running/libraryscopes.py +115 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/model.py +198 -337
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/namespace.py +124 -137
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/outputcapture.py +20 -12
- robotframework-7.0/src/robot/running/resourcemodel.py +448 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/statusreporter.py +16 -13
- robotframework-7.0/src/robot/running/suiterunner.py +265 -0
- robotframework-7.0/src/robot/running/testlibraries.py +500 -0
- robotframework-7.0/src/robot/running/userkeywordrunner.py +260 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/testdoc.py +18 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/__init__.py +53 -35
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/connectioncache.py +64 -59
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/dotdict.py +3 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encodingsniffer.py +9 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/escaping.py +19 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/importer.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markupwriters.py +23 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/misc.py +1 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/normalizing.py +9 -24
- robotframework-7.0/src/robot/utils/notset.py +33 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/platform.py +15 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotio.py +9 -9
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotpath.py +1 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottime.py +122 -90
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottypes.py +21 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/setter.py +0 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/text.py +7 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/unic.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/assigner.py +17 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/evaluation.py +20 -17
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/filesetter.py +80 -80
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/replacer.py +33 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/scopes.py +17 -12
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/search.py +66 -41
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/store.py +14 -16
- robotframework-7.0/src/robot/variables/tablesetter.py +164 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/variables.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/version.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/PKG-INFO +6 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/SOURCES.txt +10 -8
- {robotframework-6.1rc1 → robotframework-7.0}/tasks.py +6 -6
- robotframework-6.1rc1/src/robot/htmldata/rebot/common.css +0 -239
- robotframework-6.1rc1/src/robot/libraries/Reserved.py +0 -48
- robotframework-6.1rc1/src/robot/model/keyword.py +0 -173
- robotframework-6.1rc1/src/robot/output/console/dotted.py +0 -90
- robotframework-6.1rc1/src/robot/output/listenerarguments.py +0 -165
- robotframework-6.1rc1/src/robot/output/listenermethods.py +0 -113
- robotframework-6.1rc1/src/robot/output/listeners.py +0 -174
- robotframework-6.1rc1/src/robot/output/output.py +0 -95
- robotframework-6.1rc1/src/robot/output/xmllogger.py +0 -354
- robotframework-6.1rc1/src/robot/parsing/model/visitor.py +0 -67
- robotframework-6.1rc1/src/robot/result/keywordremover.py +0 -183
- robotframework-6.1rc1/src/robot/result/model.py +0 -957
- robotframework-6.1rc1/src/robot/running/arguments/argumentconverter.py +0 -79
- robotframework-6.1rc1/src/robot/running/arguments/argumentresolver.py +0 -131
- robotframework-6.1rc1/src/robot/running/arguments/embedded.py +0 -146
- robotframework-6.1rc1/src/robot/running/arguments/typevalidator.py +0 -56
- robotframework-6.1rc1/src/robot/running/builder/transformers.py +0 -642
- robotframework-6.1rc1/src/robot/running/handlers.py +0 -321
- robotframework-6.1rc1/src/robot/running/handlerstore.py +0 -66
- robotframework-6.1rc1/src/robot/running/librarykeywordrunner.py +0 -238
- robotframework-6.1rc1/src/robot/running/libraryscopes.py +0 -97
- robotframework-6.1rc1/src/robot/running/modelcombiner.py +0 -32
- robotframework-6.1rc1/src/robot/running/suiterunner.py +0 -249
- robotframework-6.1rc1/src/robot/running/testlibraries.py +0 -420
- robotframework-6.1rc1/src/robot/running/usererrorhandler.py +0 -75
- robotframework-6.1rc1/src/robot/running/userkeyword.py +0 -111
- robotframework-6.1rc1/src/robot/running/userkeywordrunner.py +0 -274
- robotframework-6.1rc1/src/robot/variables/tablesetter.py +0 -156
- {robotframework-6.1rc1 → robotframework-7.0}/AUTHORS.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/BUILD.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/CONTRIBUTING.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/COPYRIGHT.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/LICENSE.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/MANIFEST.in +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/setup.cfg +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__main__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/errors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/js_disabled.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/pygments.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/fileloading.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/util.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.html +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdoc.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/consoleviewer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/output.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/writer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Dialogs.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Easter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Screenshot.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Telnet.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/fixture.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/metadata.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/statistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/suitestatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/totalstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/highlighting.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/pyloggingconf.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokenizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/blockparsers.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/fileparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/parser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/suitestructure.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/pythonpathsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsexecutionresult.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jswriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionerrors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/messagefilter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/suiteteardownfailed.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/visitor.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/randomizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/runkwregister.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/signalhandler.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/status.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/posix.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/windows.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/application.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/argumentparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/asserts.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/charwidth.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/compress.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encoding.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/error.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/etreewrapper.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/filereader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/frange.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/htmlformatters.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markuputils.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/match.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/recommendations.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/restreader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotenv.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotinspect.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/sortable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/typehints.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/finders.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/notfound.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/resolvable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/dependency_links.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/entry_points.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/top_level.txt +0 -0
|
@@ -15,14 +15,16 @@
|
|
|
15
15
|
|
|
16
16
|
import ast
|
|
17
17
|
import re
|
|
18
|
+
import warnings
|
|
18
19
|
from abc import ABC, abstractmethod
|
|
19
20
|
from collections.abc import Iterator, Sequence
|
|
20
|
-
from typing import cast, ClassVar, overload, TYPE_CHECKING, Type, TypeVar
|
|
21
|
+
from typing import cast, ClassVar, Literal, overload, TYPE_CHECKING, Type, TypeVar
|
|
21
22
|
|
|
22
23
|
from robot.conf import Language
|
|
23
24
|
from robot.running.arguments import UserKeywordArgumentParser
|
|
24
25
|
from robot.utils import normalize_whitespace, seq2str, split_from_equals, test_or_task
|
|
25
|
-
from robot.variables import is_scalar_assign, is_dict_variable,
|
|
26
|
+
from robot.variables import (contains_variable, is_scalar_assign, is_dict_variable,
|
|
27
|
+
search_variable)
|
|
26
28
|
|
|
27
29
|
from ..lexer import Token
|
|
28
30
|
|
|
@@ -45,10 +47,13 @@ class Node(ast.AST, ABC):
|
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
class Statement(Node, ABC):
|
|
48
|
-
|
|
50
|
+
_attributes = ('type', 'tokens') + Node._attributes
|
|
49
51
|
type: str
|
|
50
52
|
handles_types: 'ClassVar[tuple[str, ...]]' = ()
|
|
51
53
|
statement_handlers: 'ClassVar[dict[str, Type[Statement]]]' = {}
|
|
54
|
+
# Accepted configuration options. If the value is a tuple, it lists accepted
|
|
55
|
+
# values. If the used value contains a variable, it cannot be validated.
|
|
56
|
+
options: 'dict[str, tuple|None]' = {}
|
|
52
57
|
|
|
53
58
|
def __init__(self, tokens: 'Sequence[Token]', errors: 'Sequence[str]' = ()):
|
|
54
59
|
self.tokens = tuple(tokens)
|
|
@@ -164,15 +169,10 @@ class Statement(Node, ABC):
|
|
|
164
169
|
|
|
165
170
|
New in Robot Framework 6.1.
|
|
166
171
|
"""
|
|
167
|
-
|
|
168
|
-
return ', '.join(options[name]) if name in options else default
|
|
172
|
+
return self._get_options().get(name, default)
|
|
169
173
|
|
|
170
|
-
def _get_options(self) -> 'dict[str,
|
|
171
|
-
|
|
172
|
-
for option in self.get_values(Token.OPTION):
|
|
173
|
-
name, value = option.split('=', 1)
|
|
174
|
-
options.setdefault(name, []).append(value)
|
|
175
|
-
return options
|
|
174
|
+
def _get_options(self) -> 'dict[str, str]':
|
|
175
|
+
return dict(opt.split('=', 1) for opt in self.get_values(Token.OPTION))
|
|
176
176
|
|
|
177
177
|
@property
|
|
178
178
|
def lines(self) -> 'Iterator[list[Token]]':
|
|
@@ -189,10 +189,13 @@ class Statement(Node, ABC):
|
|
|
189
189
|
pass
|
|
190
190
|
|
|
191
191
|
def _validate_options(self):
|
|
192
|
-
for name,
|
|
193
|
-
if
|
|
194
|
-
self.
|
|
195
|
-
|
|
192
|
+
for name, value in self._get_options().items():
|
|
193
|
+
if self.options[name] is not None:
|
|
194
|
+
expected = self.options[name]
|
|
195
|
+
if value.upper() not in expected and not contains_variable(value):
|
|
196
|
+
self.errors += (f"{self.type} option '{name}' does not accept "
|
|
197
|
+
f"value '{value}'. Valid values are "
|
|
198
|
+
f"{seq2str(expected)}.",)
|
|
196
199
|
|
|
197
200
|
def __iter__(self) -> 'Iterator[Token]':
|
|
198
201
|
return iter(self.tokens)
|
|
@@ -344,7 +347,7 @@ class LibraryImport(Statement):
|
|
|
344
347
|
Token(Token.ARGUMENT, arg)])
|
|
345
348
|
if alias is not None:
|
|
346
349
|
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
347
|
-
Token(Token.
|
|
350
|
+
Token(Token.AS),
|
|
348
351
|
Token(Token.SEPARATOR, separator),
|
|
349
352
|
Token(Token.NAME, alias)])
|
|
350
353
|
tokens.append(Token(Token.EOL, eol))
|
|
@@ -360,7 +363,7 @@ class LibraryImport(Statement):
|
|
|
360
363
|
|
|
361
364
|
@property
|
|
362
365
|
def alias(self) -> 'str|None':
|
|
363
|
-
separator = self.get_token(Token.
|
|
366
|
+
separator = self.get_token(Token.AS)
|
|
364
367
|
return self.get_tokens(Token.NAME)[-1].value if separator else None
|
|
365
368
|
|
|
366
369
|
|
|
@@ -467,13 +470,13 @@ class Metadata(DocumentationOrMetadata):
|
|
|
467
470
|
|
|
468
471
|
|
|
469
472
|
@Statement.register
|
|
470
|
-
class
|
|
471
|
-
type = Token.
|
|
473
|
+
class TestTags(MultiValue):
|
|
474
|
+
type = Token.TEST_TAGS
|
|
472
475
|
|
|
473
476
|
@classmethod
|
|
474
477
|
def from_params(cls, values: 'Sequence[str]', separator: str = FOUR_SPACES,
|
|
475
|
-
eol: str = EOL) -> '
|
|
476
|
-
tokens = [Token(Token.
|
|
478
|
+
eol: str = EOL) -> 'TestTags':
|
|
479
|
+
tokens = [Token(Token.TEST_TAGS, 'Test Tags')]
|
|
477
480
|
for tag in values:
|
|
478
481
|
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
479
482
|
Token(Token.ARGUMENT, tag)])
|
|
@@ -627,15 +630,24 @@ class TestTimeout(SingleValue):
|
|
|
627
630
|
@Statement.register
|
|
628
631
|
class Variable(Statement):
|
|
629
632
|
type = Token.VARIABLE
|
|
633
|
+
options = {
|
|
634
|
+
'separator': None
|
|
635
|
+
}
|
|
630
636
|
|
|
631
637
|
@classmethod
|
|
632
|
-
def from_params(cls, name: str,
|
|
633
|
-
|
|
638
|
+
def from_params(cls, name: str,
|
|
639
|
+
value: 'str|Sequence[str]',
|
|
640
|
+
value_separator: 'str|None' = None,
|
|
641
|
+
separator: str = FOUR_SPACES,
|
|
642
|
+
eol: str = EOL) -> 'Variable':
|
|
634
643
|
values = [value] if isinstance(value, str) else value
|
|
635
644
|
tokens = [Token(Token.VARIABLE, name)]
|
|
636
645
|
for value in values:
|
|
637
646
|
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
638
647
|
Token(Token.ARGUMENT, value)])
|
|
648
|
+
if value_separator is not None:
|
|
649
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
650
|
+
Token(Token.OPTION, f'separator={value_separator}')])
|
|
639
651
|
tokens.append(Token(Token.EOL, eol))
|
|
640
652
|
return cls(tokens)
|
|
641
653
|
|
|
@@ -650,26 +662,13 @@ class Variable(Statement):
|
|
|
650
662
|
def value(self) -> 'tuple[str, ...]':
|
|
651
663
|
return self.get_values(Token.ARGUMENT)
|
|
652
664
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
if not match.is_assign(allow_assign_mark=True, allow_nested=True):
|
|
657
|
-
self.errors += (f"Invalid variable name '{name}'.",)
|
|
658
|
-
if match.is_dict_assign(allow_assign_mark=True):
|
|
659
|
-
self._validate_dict_items()
|
|
660
|
-
|
|
661
|
-
def _validate_dict_items(self):
|
|
662
|
-
for item in self.get_values(Token.ARGUMENT):
|
|
663
|
-
if not self._is_valid_dict_item(item):
|
|
664
|
-
self.errors += (
|
|
665
|
-
f"Invalid dictionary variable item '{item}'. "
|
|
666
|
-
f"Items must use 'name=value' syntax or be dictionary "
|
|
667
|
-
f"variables themselves.",
|
|
668
|
-
)
|
|
665
|
+
@property
|
|
666
|
+
def separator(self) -> 'str|None':
|
|
667
|
+
return self.get_option('separator')
|
|
669
668
|
|
|
670
|
-
def
|
|
671
|
-
|
|
672
|
-
|
|
669
|
+
def validate(self, ctx: 'ValidationContext'):
|
|
670
|
+
VariableValidator().validate(self)
|
|
671
|
+
self._validate_options()
|
|
673
672
|
|
|
674
673
|
|
|
675
674
|
@Statement.register
|
|
@@ -819,28 +818,18 @@ class Arguments(MultiValue):
|
|
|
819
818
|
self.errors = tuple(errors)
|
|
820
819
|
|
|
821
820
|
|
|
822
|
-
# TODO: Change Return to mean ReturnStatement in RF 7.0
|
|
823
|
-
# - Rename current Return to ReturnSetting
|
|
824
|
-
# - Rename current ReturnStatement to Return
|
|
825
|
-
# - Add backwards compatible ReturnStatement alias
|
|
826
|
-
# - Change Token.RETURN to mean Token.RETURN_STATEMENT
|
|
827
|
-
# - Update also ModelVisitor
|
|
828
821
|
@Statement.register
|
|
829
|
-
class
|
|
822
|
+
class ReturnSetting(MultiValue):
|
|
830
823
|
"""Represents the deprecated ``[Return]`` setting.
|
|
831
824
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
Robot Framework 6.1) should be used instead. :class:`ReturnStatement` will
|
|
835
|
-
be renamed to ``Return`` in Robot Framework 7.0.
|
|
836
|
-
|
|
837
|
-
Eventually ``[Return]`` and ``ReturnSetting`` will be removed altogether.
|
|
825
|
+
This class was named ``Return`` prior to Robot Framework 7.0. A forward
|
|
826
|
+
compatible ``ReturnSetting`` alias existed already in Robot Framework 6.1.
|
|
838
827
|
"""
|
|
839
828
|
type = Token.RETURN
|
|
840
829
|
|
|
841
830
|
@classmethod
|
|
842
831
|
def from_params(cls, args: 'Sequence[str]', indent: str = FOUR_SPACES,
|
|
843
|
-
separator: str = FOUR_SPACES, eol: str = EOL) -> '
|
|
832
|
+
separator: str = FOUR_SPACES, eol: str = EOL) -> 'ReturnSetting':
|
|
844
833
|
tokens = [Token(Token.SEPARATOR, indent),
|
|
845
834
|
Token(Token.RETURN, '[Return]')]
|
|
846
835
|
for arg in args:
|
|
@@ -850,10 +839,6 @@ class Return(MultiValue):
|
|
|
850
839
|
return cls(tokens)
|
|
851
840
|
|
|
852
841
|
|
|
853
|
-
# Forward compatible alias for Return.
|
|
854
|
-
ReturnSetting = Return
|
|
855
|
-
|
|
856
|
-
|
|
857
842
|
@Statement.register
|
|
858
843
|
class KeywordCall(Statement):
|
|
859
844
|
type = Token.KEYWORD
|
|
@@ -908,15 +893,23 @@ class TemplateArguments(Statement):
|
|
|
908
893
|
@Statement.register
|
|
909
894
|
class ForHeader(Statement):
|
|
910
895
|
type = Token.FOR
|
|
896
|
+
options = {
|
|
897
|
+
'start': None,
|
|
898
|
+
'mode': ('STRICT', 'SHORTEST', 'LONGEST'),
|
|
899
|
+
'fill': None
|
|
900
|
+
}
|
|
911
901
|
|
|
912
902
|
@classmethod
|
|
913
|
-
def from_params(cls,
|
|
914
|
-
|
|
915
|
-
|
|
903
|
+
def from_params(cls, assign: 'Sequence[str]',
|
|
904
|
+
values: 'Sequence[str]',
|
|
905
|
+
flavor: Literal['IN', 'IN RANGE', 'IN ENUMERATE', 'IN ZIP'] = 'IN',
|
|
906
|
+
indent: str = FOUR_SPACES,
|
|
907
|
+
separator: str = FOUR_SPACES,
|
|
908
|
+
eol: str = EOL) -> 'ForHeader':
|
|
916
909
|
tokens = [Token(Token.SEPARATOR, indent),
|
|
917
910
|
Token(Token.FOR),
|
|
918
911
|
Token(Token.SEPARATOR, separator)]
|
|
919
|
-
for variable in
|
|
912
|
+
for variable in assign:
|
|
920
913
|
tokens.extend([Token(Token.VARIABLE, variable),
|
|
921
914
|
Token(Token.SEPARATOR, separator)])
|
|
922
915
|
tokens.append(Token(Token.FOR_SEPARATOR, flavor))
|
|
@@ -927,9 +920,15 @@ class ForHeader(Statement):
|
|
|
927
920
|
return cls(tokens)
|
|
928
921
|
|
|
929
922
|
@property
|
|
930
|
-
def
|
|
923
|
+
def assign(self) -> 'tuple[str, ...]':
|
|
931
924
|
return self.get_values(Token.VARIABLE)
|
|
932
925
|
|
|
926
|
+
@property
|
|
927
|
+
def variables(self) -> 'tuple[str, ...]': # TODO: Remove in RF 8.0.
|
|
928
|
+
warnings.warn("'ForHeader.variables' is deprecated and will be removed in "
|
|
929
|
+
"Robot Framework 8.0. Use 'ForHeader.assign' instead.")
|
|
930
|
+
return self.assign
|
|
931
|
+
|
|
933
932
|
@property
|
|
934
933
|
def values(self) -> 'tuple[str, ...]':
|
|
935
934
|
return self.get_values(Token.ARGUMENT)
|
|
@@ -952,17 +951,17 @@ class ForHeader(Statement):
|
|
|
952
951
|
return self.get_option('fill') if self.flavor == 'IN ZIP' else None
|
|
953
952
|
|
|
954
953
|
def validate(self, ctx: 'ValidationContext'):
|
|
955
|
-
self.
|
|
956
|
-
if not self.variables:
|
|
954
|
+
if not self.assign:
|
|
957
955
|
self._add_error('no loop variables')
|
|
958
956
|
if not self.flavor:
|
|
959
957
|
self._add_error("no 'IN' or other valid separator")
|
|
960
958
|
else:
|
|
961
|
-
for var in self.
|
|
959
|
+
for var in self.assign:
|
|
962
960
|
if not is_scalar_assign(var):
|
|
963
961
|
self._add_error(f"invalid loop variable '{var}'")
|
|
964
962
|
if not self.values:
|
|
965
963
|
self._add_error('no loop values')
|
|
964
|
+
self._validate_options()
|
|
966
965
|
|
|
967
966
|
def _add_error(self, error: str):
|
|
968
967
|
self.errors += (f'FOR loop has {error}.',)
|
|
@@ -1084,10 +1083,13 @@ class TryHeader(NoArgumentHeader):
|
|
|
1084
1083
|
@Statement.register
|
|
1085
1084
|
class ExceptHeader(Statement):
|
|
1086
1085
|
type = Token.EXCEPT
|
|
1086
|
+
options = {
|
|
1087
|
+
'type': ('GLOB', 'REGEXP', 'START', 'LITERAL')
|
|
1088
|
+
}
|
|
1087
1089
|
|
|
1088
1090
|
@classmethod
|
|
1089
1091
|
def from_params(cls, patterns: 'Sequence[str]' = (), type: 'str|None' = None,
|
|
1090
|
-
|
|
1092
|
+
assign: 'str|None' = None, indent: str = FOUR_SPACES,
|
|
1091
1093
|
separator: str = FOUR_SPACES, eol: str = EOL) -> 'ExceptHeader':
|
|
1092
1094
|
tokens = [Token(Token.SEPARATOR, indent),
|
|
1093
1095
|
Token(Token.EXCEPT)]
|
|
@@ -1097,11 +1099,11 @@ class ExceptHeader(Statement):
|
|
|
1097
1099
|
if type:
|
|
1098
1100
|
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1099
1101
|
Token(Token.OPTION, f'type={type}')])
|
|
1100
|
-
if
|
|
1102
|
+
if assign:
|
|
1101
1103
|
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1102
1104
|
Token(Token.AS),
|
|
1103
1105
|
Token(Token.SEPARATOR, separator),
|
|
1104
|
-
Token(Token.VARIABLE,
|
|
1106
|
+
Token(Token.VARIABLE, assign)])
|
|
1105
1107
|
tokens.append(Token(Token.EOL, eol))
|
|
1106
1108
|
return cls(tokens)
|
|
1107
1109
|
|
|
@@ -1114,20 +1116,26 @@ class ExceptHeader(Statement):
|
|
|
1114
1116
|
return self.get_option('type')
|
|
1115
1117
|
|
|
1116
1118
|
@property
|
|
1117
|
-
def
|
|
1119
|
+
def assign(self) -> 'str|None':
|
|
1118
1120
|
return self.get_value(Token.VARIABLE)
|
|
1119
1121
|
|
|
1122
|
+
@property
|
|
1123
|
+
def variable(self) -> 'str|None': # TODO: Remove in RF 8.0.
|
|
1124
|
+
warnings.warn("'ExceptHeader.variable' is deprecated and will be removed in "
|
|
1125
|
+
"Robot Framework 8.0. Use 'ExceptHeader.assigns' instead.")
|
|
1126
|
+
return self.assign
|
|
1127
|
+
|
|
1120
1128
|
def validate(self, ctx: 'ValidationContext'):
|
|
1121
|
-
self._validate_options()
|
|
1122
1129
|
as_token = self.get_token(Token.AS)
|
|
1123
1130
|
if as_token:
|
|
1124
|
-
|
|
1125
|
-
if not
|
|
1126
|
-
self.errors += ("EXCEPT
|
|
1127
|
-
elif len(
|
|
1128
|
-
self.errors += ("EXCEPT
|
|
1129
|
-
elif not is_scalar_assign(
|
|
1130
|
-
self.errors += (f"EXCEPT
|
|
1131
|
+
assign = self.get_tokens(Token.VARIABLE)
|
|
1132
|
+
if not assign:
|
|
1133
|
+
self.errors += ("EXCEPT AS requires a value.",)
|
|
1134
|
+
elif len(assign) > 1:
|
|
1135
|
+
self.errors += ("EXCEPT AS accepts only one value.",)
|
|
1136
|
+
elif not is_scalar_assign(assign[0].value):
|
|
1137
|
+
self.errors += (f"EXCEPT AS variable '{assign[0].value}' is invalid.",)
|
|
1138
|
+
self._validate_options()
|
|
1131
1139
|
|
|
1132
1140
|
|
|
1133
1141
|
@Statement.register
|
|
@@ -1143,6 +1151,11 @@ class End(NoArgumentHeader):
|
|
|
1143
1151
|
@Statement.register
|
|
1144
1152
|
class WhileHeader(Statement):
|
|
1145
1153
|
type = Token.WHILE
|
|
1154
|
+
options = {
|
|
1155
|
+
'limit': None,
|
|
1156
|
+
'on_limit': ('PASS', 'FAIL'),
|
|
1157
|
+
'on_limit_message': None
|
|
1158
|
+
}
|
|
1146
1159
|
|
|
1147
1160
|
@classmethod
|
|
1148
1161
|
def from_params(cls, condition: str, limit: 'str|None' = None,
|
|
@@ -1154,13 +1167,13 @@ class WhileHeader(Statement):
|
|
|
1154
1167
|
Token(Token.SEPARATOR, separator),
|
|
1155
1168
|
Token(Token.ARGUMENT, condition)]
|
|
1156
1169
|
if limit:
|
|
1157
|
-
tokens.extend([Token(Token.SEPARATOR,
|
|
1170
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1158
1171
|
Token(Token.OPTION, f'limit={limit}')])
|
|
1159
1172
|
if on_limit:
|
|
1160
|
-
tokens.extend([Token(Token.SEPARATOR,
|
|
1173
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1161
1174
|
Token(Token.OPTION, f'on_limit={on_limit}')])
|
|
1162
1175
|
if on_limit_message:
|
|
1163
|
-
tokens.extend([Token(Token.SEPARATOR,
|
|
1176
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1164
1177
|
Token(Token.OPTION, f'on_limit_message={on_limit_message}')])
|
|
1165
1178
|
tokens.append(Token(Token.EOL, eol))
|
|
1166
1179
|
return cls(tokens)
|
|
@@ -1182,29 +1195,84 @@ class WhileHeader(Statement):
|
|
|
1182
1195
|
return self.get_option('on_limit_message')
|
|
1183
1196
|
|
|
1184
1197
|
def validate(self, ctx: 'ValidationContext'):
|
|
1185
|
-
conditions = self.
|
|
1198
|
+
conditions = self.get_values(Token.ARGUMENT)
|
|
1186
1199
|
if len(conditions) > 1:
|
|
1187
|
-
self.
|
|
1188
|
-
f
|
|
1200
|
+
self.errors += (f"WHILE accepts only one condition, got {len(conditions)} "
|
|
1201
|
+
f"conditions {seq2str(conditions)}.",)
|
|
1189
1202
|
if self.on_limit and not self.limit:
|
|
1190
|
-
self.
|
|
1203
|
+
self.errors += ("WHILE option 'on_limit' cannot be used without 'limit'.",)
|
|
1191
1204
|
self._validate_options()
|
|
1192
1205
|
|
|
1193
|
-
def _add_error(self, error: str):
|
|
1194
|
-
self.errors += (f'WHILE loop {error}.',)
|
|
1195
|
-
|
|
1196
1206
|
|
|
1197
1207
|
@Statement.register
|
|
1198
|
-
class
|
|
1199
|
-
type = Token.
|
|
1208
|
+
class Var(Statement):
|
|
1209
|
+
type = Token.VAR
|
|
1210
|
+
options = {
|
|
1211
|
+
'scope': ('GLOBAL', 'SUITE', 'TEST', 'TASK', 'LOCAL'),
|
|
1212
|
+
'separator': None
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
@classmethod
|
|
1216
|
+
def from_params(cls, name: str,
|
|
1217
|
+
value: 'str|Sequence[str]',
|
|
1218
|
+
scope: 'str|None' = None,
|
|
1219
|
+
value_separator: 'str|None' = None,
|
|
1220
|
+
indent: str = FOUR_SPACES,
|
|
1221
|
+
separator: str = FOUR_SPACES,
|
|
1222
|
+
eol: str = EOL) -> 'Var':
|
|
1223
|
+
tokens = [Token(Token.SEPARATOR, indent),
|
|
1224
|
+
Token(Token.VAR),
|
|
1225
|
+
Token(Token.SEPARATOR, separator),
|
|
1226
|
+
Token(Token.VARIABLE, name)]
|
|
1227
|
+
values = [value] if isinstance(value, str) else value
|
|
1228
|
+
for value in values:
|
|
1229
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1230
|
+
Token(Token.ARGUMENT, value)])
|
|
1231
|
+
if scope:
|
|
1232
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1233
|
+
Token(Token.OPTION, f'scope={scope}')])
|
|
1234
|
+
if value_separator:
|
|
1235
|
+
tokens.extend([Token(Token.SEPARATOR, separator),
|
|
1236
|
+
Token(Token.OPTION, f'separator={value_separator}')])
|
|
1237
|
+
tokens.append(Token(Token.EOL, eol))
|
|
1238
|
+
return cls(tokens)
|
|
1239
|
+
|
|
1240
|
+
@property
|
|
1241
|
+
def name(self) -> str:
|
|
1242
|
+
name = self.get_value(Token.VARIABLE, '')
|
|
1243
|
+
if name.endswith('='):
|
|
1244
|
+
return name[:-1].rstrip()
|
|
1245
|
+
return name
|
|
1200
1246
|
|
|
1201
1247
|
@property
|
|
1202
|
-
def
|
|
1248
|
+
def value(self) -> 'tuple[str, ...]':
|
|
1203
1249
|
return self.get_values(Token.ARGUMENT)
|
|
1204
1250
|
|
|
1251
|
+
@property
|
|
1252
|
+
def scope(self) -> 'str|None':
|
|
1253
|
+
return self.get_option('scope')
|
|
1254
|
+
|
|
1255
|
+
@property
|
|
1256
|
+
def separator(self) -> 'str|None':
|
|
1257
|
+
return self.get_option('separator')
|
|
1258
|
+
|
|
1259
|
+
def validate(self, ctx: 'ValidationContext'):
|
|
1260
|
+
VariableValidator().validate(self)
|
|
1261
|
+
self._validate_options()
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
@Statement.register
|
|
1265
|
+
class Return(Statement):
|
|
1266
|
+
"""Represents the RETURN statement.
|
|
1267
|
+
|
|
1268
|
+
This class named ``ReturnStatement`` prior to Robot Framework 7.0.
|
|
1269
|
+
The old name still exists as a backwards compatible alias.
|
|
1270
|
+
"""
|
|
1271
|
+
type = Token.RETURN_STATEMENT
|
|
1272
|
+
|
|
1205
1273
|
@classmethod
|
|
1206
1274
|
def from_params(cls, values: 'Sequence[str]' = (), indent: str = FOUR_SPACES,
|
|
1207
|
-
separator: str = FOUR_SPACES, eol: str = EOL) -> '
|
|
1275
|
+
separator: str = FOUR_SPACES, eol: str = EOL) -> 'Return':
|
|
1208
1276
|
tokens = [Token(Token.SEPARATOR, indent),
|
|
1209
1277
|
Token(Token.RETURN_STATEMENT)]
|
|
1210
1278
|
for value in values:
|
|
@@ -1213,6 +1281,10 @@ class ReturnStatement(Statement):
|
|
|
1213
1281
|
tokens.append(Token(Token.EOL, eol))
|
|
1214
1282
|
return cls(tokens)
|
|
1215
1283
|
|
|
1284
|
+
@property
|
|
1285
|
+
def values(self) -> 'tuple[str, ...]':
|
|
1286
|
+
return self.get_values(Token.ARGUMENT)
|
|
1287
|
+
|
|
1216
1288
|
def validate(self, ctx: 'ValidationContext'):
|
|
1217
1289
|
if not ctx.in_keyword:
|
|
1218
1290
|
self.errors += ('RETURN can only be used inside a user keyword.',)
|
|
@@ -1220,6 +1292,10 @@ class ReturnStatement(Statement):
|
|
|
1220
1292
|
self.errors += ('RETURN cannot be used in FINALLY branch.',)
|
|
1221
1293
|
|
|
1222
1294
|
|
|
1295
|
+
# Backwards compatibility with RF < 7.
|
|
1296
|
+
ReturnStatement = Return
|
|
1297
|
+
|
|
1298
|
+
|
|
1223
1299
|
class LoopControl(NoArgumentHeader, ABC):
|
|
1224
1300
|
|
|
1225
1301
|
def validate(self, ctx: 'ValidationContext'):
|
|
@@ -1310,3 +1386,26 @@ class EmptyLine(Statement):
|
|
|
1310
1386
|
@classmethod
|
|
1311
1387
|
def from_params(cls, eol: str = EOL):
|
|
1312
1388
|
return cls([Token(Token.EOL, eol)])
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
class VariableValidator:
|
|
1392
|
+
|
|
1393
|
+
def validate(self, statement: Statement):
|
|
1394
|
+
name = statement.get_value(Token.VARIABLE, '')
|
|
1395
|
+
match = search_variable(name, ignore_errors=True)
|
|
1396
|
+
if not match.is_assign(allow_assign_mark=True, allow_nested=True):
|
|
1397
|
+
statement.errors += (f"Invalid variable name '{name}'.",)
|
|
1398
|
+
if match.identifier == '&':
|
|
1399
|
+
self._validate_dict_items(statement)
|
|
1400
|
+
|
|
1401
|
+
def _validate_dict_items(self, statement: Statement):
|
|
1402
|
+
for item in statement.get_values(Token.ARGUMENT):
|
|
1403
|
+
if not self._is_valid_dict_item(item):
|
|
1404
|
+
statement.errors += (
|
|
1405
|
+
f"Invalid dictionary variable item '{item}'. Items must use "
|
|
1406
|
+
f"'name=value' syntax or be dictionary variables themselves.",
|
|
1407
|
+
)
|
|
1408
|
+
|
|
1409
|
+
def _is_valid_dict_item(self, item: str) -> bool:
|
|
1410
|
+
name, value = split_from_equals(item)
|
|
1411
|
+
return value is not None or is_dict_variable(item)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright 2008-2015 Nokia Networks
|
|
2
|
+
# Copyright 2016- Robot Framework Foundation
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from ast import NodeTransformer, NodeVisitor
|
|
17
|
+
from typing import Callable
|
|
18
|
+
|
|
19
|
+
from .statements import Node
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Unbound method and thus needs `NodeVisitor` as `self`.
|
|
23
|
+
VisitorMethod = Callable[[NodeVisitor, Node], 'None|Node|list[Node]']
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class VisitorFinder:
|
|
27
|
+
__visitor_cache: 'dict[type[Node], VisitorMethod]'
|
|
28
|
+
|
|
29
|
+
def __init_subclass__(cls, **kwargs):
|
|
30
|
+
super().__init_subclass__(**kwargs)
|
|
31
|
+
cls.__visitor_cache = {}
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def _find_visitor(cls, node_cls: 'type[Node]') -> VisitorMethod:
|
|
35
|
+
if node_cls not in cls.__visitor_cache:
|
|
36
|
+
visitor = cls._find_visitor_from_class(node_cls)
|
|
37
|
+
cls.__visitor_cache[node_cls] = visitor or cls.generic_visit
|
|
38
|
+
return cls.__visitor_cache[node_cls]
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def _find_visitor_from_class(cls, node_cls: 'type[Node]') -> 'VisitorMethod|None':
|
|
42
|
+
method_name = 'visit_' + node_cls.__name__
|
|
43
|
+
method = getattr(cls, method_name, None)
|
|
44
|
+
if callable(method):
|
|
45
|
+
return method
|
|
46
|
+
if method_name in ('visit_TestTags', 'visit_Return'):
|
|
47
|
+
method = cls._backwards_compatibility(method_name)
|
|
48
|
+
if callable(method):
|
|
49
|
+
return method
|
|
50
|
+
for base in node_cls.__bases__:
|
|
51
|
+
if issubclass(base, Node):
|
|
52
|
+
method = cls._find_visitor_from_class(base)
|
|
53
|
+
if method:
|
|
54
|
+
return method
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def _backwards_compatibility(cls, method_name):
|
|
59
|
+
name = {'visit_TestTags': 'visit_ForceTags',
|
|
60
|
+
'visit_Return': 'visit_ReturnStatement'}[method_name]
|
|
61
|
+
return getattr(cls, name, None)
|
|
62
|
+
|
|
63
|
+
def generic_visit(self, node: Node) -> 'None|Node|list[Node]':
|
|
64
|
+
raise NotImplementedError
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ModelVisitor(NodeVisitor, VisitorFinder):
|
|
68
|
+
"""NodeVisitor that supports matching nodes based on their base classes.
|
|
69
|
+
|
|
70
|
+
The biggest difference compared to the standard `ast.NodeVisitor
|
|
71
|
+
<https://docs.python.org/library/ast.html#ast.NodeVisitor>`__,
|
|
72
|
+
is that this class allows creating ``visit_ClassName`` methods so that
|
|
73
|
+
the ``ClassName`` is one of the base classes of the node. For example,
|
|
74
|
+
the following visitor method matches all node classes that extend
|
|
75
|
+
``Statement``::
|
|
76
|
+
|
|
77
|
+
def visit_Statement(self, node):
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
Another difference is that visitor methods are cached for performance
|
|
81
|
+
reasons. This means that dynamically adding ``visit_Something`` methods
|
|
82
|
+
does not work.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def visit(self, node: Node) -> None:
|
|
86
|
+
visitor_method = self._find_visitor(type(node))
|
|
87
|
+
visitor_method(self, node)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ModelTransformer(NodeTransformer, VisitorFinder):
|
|
91
|
+
"""NodeTransformer that supports matching nodes based on their base classes.
|
|
92
|
+
|
|
93
|
+
See :class:`ModelVisitor` for explanation how this is different compared
|
|
94
|
+
to the standard `ast.NodeTransformer
|
|
95
|
+
<https://docs.python.org/library/ast.html#ast.NodeTransformer>`__.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def visit(self, node: Node) -> 'None|Node|list[Node]':
|
|
99
|
+
visitor_method = self._find_visitor(type(node))
|
|
100
|
+
return visitor_method(self, node)
|
|
@@ -130,6 +130,8 @@ Options
|
|
|
130
130
|
specified. Given path, similarly as paths given to
|
|
131
131
|
--log, --report and --xunit, is relative to
|
|
132
132
|
--outputdir unless given as an absolute path.
|
|
133
|
+
--legacyoutput Create XML output file in format compatible with
|
|
134
|
+
Robot Framework 6.x and earlier.
|
|
133
135
|
-l --log file HTML log file. Can be disabled by giving a special
|
|
134
136
|
name `NONE`. Default: log.html
|
|
135
137
|
Examples: `--log mylog.html`, `-l none`
|
|
@@ -33,6 +33,6 @@ class ExpandKeywordMatcher:
|
|
|
33
33
|
self._match_tags = MultiMatcher(tags).match_any
|
|
34
34
|
|
|
35
35
|
def match(self, kw: Keyword):
|
|
36
|
-
if (self._match_name(kw.
|
|
36
|
+
if (self._match_name(kw.full_name or '')
|
|
37
37
|
or self._match_tags(kw.tags)) and not kw.not_run:
|
|
38
38
|
self.matched_ids.append(kw.id)
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
+
from datetime import datetime
|
|
16
17
|
from contextlib import contextmanager
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
|
|
19
20
|
from robot.output.loggerhelper import LEVELS
|
|
20
|
-
from robot.utils import
|
|
21
|
-
timestamp_to_secs)
|
|
21
|
+
from robot.utils import attribute_escape, get_link_path, html_escape, safe_str
|
|
22
22
|
|
|
23
23
|
from .expandkeywordmatcher import ExpandKeywordMatcher
|
|
24
24
|
from .stringcache import StringCache
|
|
@@ -48,7 +48,9 @@ class JsBuildingContext:
|
|
|
48
48
|
return None
|
|
49
49
|
|
|
50
50
|
def string(self, string, escape=True, attr=False):
|
|
51
|
-
if
|
|
51
|
+
if not string:
|
|
52
|
+
return self._strings.empty
|
|
53
|
+
if escape:
|
|
52
54
|
if not isinstance(string, str):
|
|
53
55
|
string = safe_str(string)
|
|
54
56
|
string = (html_escape if not attr else attribute_escape)(string)
|
|
@@ -64,10 +66,10 @@ class JsBuildingContext:
|
|
|
64
66
|
if self._log_dir and source and source.exists() else ''
|
|
65
67
|
return self.string(rel_source)
|
|
66
68
|
|
|
67
|
-
def timestamp(self,
|
|
68
|
-
if not
|
|
69
|
+
def timestamp(self, ts: datetime) -> 'int|None':
|
|
70
|
+
if not ts:
|
|
69
71
|
return None
|
|
70
|
-
millis =
|
|
72
|
+
millis = round(ts.timestamp() * 1000)
|
|
71
73
|
if self.basemillis is None:
|
|
72
74
|
self.basemillis = millis
|
|
73
75
|
return millis - self.basemillis
|