robotframework 6.1rc1__zip → 7.0a1__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/src/robotframework.egg-info → robotframework-7.0a1}/PKG-INFO +3 -6
- {robotframework-6.1rc1 → robotframework-7.0a1}/setup.py +2 -5
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/interfaces.py +36 -49
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/parsing.py +4 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/gatherfailed.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/languages.py +61 -25
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/settings.py +8 -5
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.css +4 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.html +9 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/model.js +2 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/testdata.js +10 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/template.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/builder.py +0 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/datatypes.py +9 -10
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/htmlutils.py +4 -7
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/jsonbuilder.py +14 -10
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/model.py +13 -25
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/robotbuilder.py +14 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/xmlbuilder.py +8 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/xmlwriter.py +12 -38
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/BuiltIn.py +215 -189
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Collections.py +2 -9
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/DateTime.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/OperatingSystem.py +4 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Process.py +26 -27
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Remote.py +40 -36
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/String.py +4 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/XML.py +7 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/dialogs_py.py +14 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/__init__.py +4 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/body.py +14 -6
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/configurer.py +19 -15
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/control.py +155 -85
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/filter.py +31 -25
- robotframework-7.0a1/src/robot/model/keyword.py +70 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/message.py +19 -10
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/modelobject.py +2 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/modifier.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/namepatterns.py +3 -25
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/stats.py +9 -15
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tags.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/testcase.py +12 -21
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/testsuite.py +43 -24
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/visitor.py +35 -8
- robotframework-7.0a1/src/robot/output/console/dotted.py +90 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/quiet.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/verbose.py +60 -60
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/debugfile.py +36 -23
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/filelogger.py +16 -13
- robotframework-7.0a1/src/robot/output/listeners.py +586 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/logger.py +164 -77
- robotframework-7.0a1/src/robot/output/loggerapi.py +152 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/loggerhelper.py +23 -56
- robotframework-7.0a1/src/robot/output/output.py +158 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/stdoutlogsplitter.py +8 -5
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/xmllogger.py +163 -109
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/blocklexers.py +17 -13
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/context.py +12 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/lexer.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/settings.py +6 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/statementlexers.py +39 -10
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/tokens.py +27 -29
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/blocks.py +19 -6
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/statements.py +184 -84
- robotframework-7.0a1/src/robot/parsing/model/visitor.py +102 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/expandkeywordmatcher.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsbuildingcontext.py +8 -6
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsmodelbuilders.py +88 -61
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/stringcache.py +4 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/xunitwriter.py +15 -21
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/__init__.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/configurer.py +12 -9
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/flattenkeywordmatcher.py +8 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/keywordremover.py +71 -54
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/merger.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/model.py +400 -316
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/modeldeprecation.py +9 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/resultbuilder.py +21 -23
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/xmlelementhandlers.py +76 -40
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/run.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/__init__.py +1 -1
- robotframework-7.0a1/src/robot/running/arguments/argumentconverter.py +101 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentmapper.py +16 -14
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentparser.py +3 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentresolver.py +41 -33
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentspec.py +24 -90
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/argumentvalidator.py +34 -27
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/customconverters.py +14 -11
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/embedded.py +23 -26
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/typeconverters.py +210 -220
- robotframework-7.0a1/src/robot/running/arguments/typeinfo.py +367 -0
- robotframework-7.0a1/src/robot/running/arguments/typevalidator.py +62 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/bodyrunner.py +83 -68
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/builders.py +15 -25
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/parsers.py +15 -10
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/settings.py +9 -17
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/transformers.py +166 -308
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/context.py +80 -25
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/handlers.py +11 -16
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/handlerstore.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/librarykeywordrunner.py +9 -17
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/model.py +156 -36
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/namespace.py +18 -19
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/statusreporter.py +13 -12
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/suiterunner.py +18 -21
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/testlibraries.py +35 -39
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/usererrorhandler.py +8 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/userkeyword.py +13 -8
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/userkeywordrunner.py +18 -21
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/testdoc.py +18 -13
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/__init__.py +50 -35
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/connectioncache.py +64 -59
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/encodingsniffer.py +9 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/escaping.py +11 -9
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/markupwriters.py +20 -13
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/normalizing.py +9 -24
- robotframework-7.0a1/src/robot/utils/notset.py +33 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/platform.py +15 -5
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotpath.py +1 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robottime.py +120 -88
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robottypes.py +16 -31
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/setter.py +0 -5
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/text.py +7 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/unic.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/assigner.py +17 -19
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/evaluation.py +20 -17
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/filesetter.py +80 -80
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/replacer.py +33 -36
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/scopes.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/search.py +66 -41
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/store.py +14 -16
- robotframework-7.0a1/src/robot/variables/tablesetter.py +164 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/variables.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/version.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0a1/src/robotframework.egg-info}/PKG-INFO +3 -6
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/SOURCES.txt +3 -4
- {robotframework-6.1rc1 → robotframework-7.0a1}/tasks.py +6 -6
- 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/parsing/model/visitor.py +0 -67
- robotframework-6.1rc1/src/robot/running/arguments/argumentconverter.py +0 -79
- robotframework-6.1rc1/src/robot/running/arguments/typevalidator.py +0 -56
- robotframework-6.1rc1/src/robot/running/modelcombiner.py +0 -32
- robotframework-6.1rc1/src/robot/variables/tablesetter.py +0 -156
- {robotframework-6.1rc1 → robotframework-7.0a1}/AUTHORS.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/BUILD.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/CONTRIBUTING.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/COPYRIGHT.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/INSTALL.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/LICENSE.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/MANIFEST.in +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/README.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/setup.cfg +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/__main__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/deco.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/exceptions.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/api/logger.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/conf/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/errors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/js_disabled.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/common/storage.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/htmlfilewriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/libdoc.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/libdoc.html +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/libdoc/pygments.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/common.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/doc_formatting.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/fileloading.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/log.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/report.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/report.html +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/util.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/rebot/view.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/testdoc.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/htmldata/testdoc/testdoc.html +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdoc.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/consoleviewer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/htmlwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/output.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/standardtypes.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libdocpkg/writer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Dialogs.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Easter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Screenshot.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/libraries/Telnet.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/fixture.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/itemlist.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/metadata.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/statistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/suitestatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tagsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/tagstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/model/totalstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/console/highlighting.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/librarylogger.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/output/pyloggingconf.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/lexer/tokenizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/model/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/blockparsers.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/fileparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/parser/parser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/parsing/suitestructure.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/pythonpathsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/rebot.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jsexecutionresult.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/jswriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/logreportwriters.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/outputwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/reporting/resultwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/executionerrors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/executionresult.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/messagefilter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/suiteteardownfailed.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/result/visitor.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/arguments/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/builder/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/dynamicmethods.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/importer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/libraryscopes.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/outputcapture.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/randomizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/runkwregister.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/signalhandler.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/status.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/posix.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/running/timeouts/windows.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/application.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/argumentparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/asserts.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/charwidth.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/compress.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/dotdict.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/encoding.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/error.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/etreewrapper.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/filereader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/frange.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/htmlformatters.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/importer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/markuputils.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/match.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/misc.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/recommendations.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/restreader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotenv.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotinspect.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/robotio.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/sortable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/utils/typehints.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/finders.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/notfound.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robot/variables/resolvable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/dependency_links.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/entry_points.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0a1}/src/robotframework.egg-info/top_level.txt +0 -0
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
import builtins
|
|
17
|
+
import re
|
|
17
18
|
import token
|
|
18
19
|
from collections.abc import MutableMapping
|
|
19
20
|
from io import StringIO
|
|
@@ -22,7 +23,7 @@ from tokenize import generate_tokens, untokenize
|
|
|
22
23
|
from robot.errors import DataError
|
|
23
24
|
from robot.utils import get_error_message, type_name
|
|
24
25
|
|
|
25
|
-
from .search import
|
|
26
|
+
from .search import VariableMatches
|
|
26
27
|
from .notfound import variable_not_found
|
|
27
28
|
|
|
28
29
|
|
|
@@ -44,12 +45,18 @@ def evaluate_expression(expression, variables, modules=None, namespace=None,
|
|
|
44
45
|
return _evaluate(expression, variables.store, modules, namespace)
|
|
45
46
|
except DataError as err:
|
|
46
47
|
error = str(err)
|
|
47
|
-
|
|
48
|
-
except Exception:
|
|
48
|
+
variable_recommendation = ''
|
|
49
|
+
except Exception as err:
|
|
49
50
|
error = get_error_message()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
variable_recommendation = ''
|
|
52
|
+
if isinstance(err, NameError) and 'RF_VAR_' in error:
|
|
53
|
+
name = re.search(r'RF_VAR_([\w_]*)', error).group(1)
|
|
54
|
+
error = (f"Robot Framework variable '${name}' is used in a scope "
|
|
55
|
+
f"where it cannot be seen.")
|
|
56
|
+
else:
|
|
57
|
+
variable_recommendation = _recommend_special_variables(original)
|
|
58
|
+
raise DataError(f'Evaluating expression {expression!r} failed: {error}\n\n'
|
|
59
|
+
f'{variable_recommendation}'.strip())
|
|
53
60
|
|
|
54
61
|
|
|
55
62
|
def _evaluate(expression, variable_store, modules=None, namespace=None):
|
|
@@ -106,19 +113,15 @@ def _import_modules(module_names):
|
|
|
106
113
|
|
|
107
114
|
|
|
108
115
|
def _recommend_special_variables(expression):
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
while True:
|
|
112
|
-
match = search_variable(remaining)
|
|
113
|
-
if not match:
|
|
114
|
-
break
|
|
115
|
-
example[-1:] = [match.before, match.identifier, match.base, match.after]
|
|
116
|
-
remaining = example[-1]
|
|
117
|
-
if not example:
|
|
116
|
+
matches = VariableMatches(expression)
|
|
117
|
+
if not matches:
|
|
118
118
|
return ''
|
|
119
|
+
example = []
|
|
120
|
+
for match in matches:
|
|
121
|
+
example[-1:] += [match.before, match.identifier, match.base, match.after]
|
|
119
122
|
example = ''.join(example)
|
|
120
|
-
return (f"Variables in the original expression
|
|
121
|
-
f"before the expression was evaluated. Try using
|
|
123
|
+
return (f"Variables in the original expression {expression!r} were resolved "
|
|
124
|
+
f"before the expression was evaluated. Try using {example!r} "
|
|
122
125
|
f"syntax to avoid that. See Evaluating Expressions appendix in "
|
|
123
126
|
f"Robot Framework User Guide for more details.")
|
|
124
127
|
|
|
@@ -23,14 +23,16 @@ except ImportError:
|
|
|
23
23
|
|
|
24
24
|
from robot.errors import DataError
|
|
25
25
|
from robot.output import LOGGER
|
|
26
|
-
from robot.utils import (get_error_message,
|
|
27
|
-
|
|
26
|
+
from robot.utils import (DotDict, get_error_message, Importer, is_dict_like,
|
|
27
|
+
is_list_like, type_name)
|
|
28
|
+
|
|
29
|
+
from .store import VariableStore
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class VariableFileSetter:
|
|
31
33
|
|
|
32
|
-
def __init__(self, store):
|
|
33
|
-
self.
|
|
34
|
+
def __init__(self, store: VariableStore):
|
|
35
|
+
self.store = store
|
|
34
36
|
|
|
35
37
|
def set(self, path_or_variables, args=None, overwrite=False):
|
|
36
38
|
variables = self._import_if_needed(path_or_variables, args)
|
|
@@ -38,10 +40,9 @@ class VariableFileSetter:
|
|
|
38
40
|
return variables
|
|
39
41
|
|
|
40
42
|
def _import_if_needed(self, path_or_variables, args=None):
|
|
41
|
-
if not
|
|
43
|
+
if not isinstance(path_or_variables, str):
|
|
42
44
|
return path_or_variables
|
|
43
|
-
LOGGER.info("Importing variable file '
|
|
44
|
-
% (path_or_variables, args))
|
|
45
|
+
LOGGER.info(f"Importing variable file '{path_or_variables}' with args {args}.")
|
|
45
46
|
if path_or_variables.lower().endswith(('.yaml', '.yml')):
|
|
46
47
|
importer = YamlImporter()
|
|
47
48
|
elif path_or_variables.lower().endswith('.json'):
|
|
@@ -50,48 +51,14 @@ class VariableFileSetter:
|
|
|
50
51
|
importer = PythonImporter()
|
|
51
52
|
try:
|
|
52
53
|
return importer.import_variables(path_or_variables, args)
|
|
53
|
-
except:
|
|
54
|
-
args = 'with arguments
|
|
55
|
-
raise DataError("Processing variable file '
|
|
56
|
-
|
|
54
|
+
except Exception:
|
|
55
|
+
args = f'with arguments {args} ' if args else ''
|
|
56
|
+
raise DataError(f"Processing variable file '{path_or_variables}' "
|
|
57
|
+
f"{args}failed: {get_error_message()}")
|
|
57
58
|
|
|
58
59
|
def _set(self, variables, overwrite=False):
|
|
59
60
|
for name, value in variables:
|
|
60
|
-
self.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class YamlImporter:
|
|
64
|
-
|
|
65
|
-
def import_variables(self, path, args=None):
|
|
66
|
-
if args:
|
|
67
|
-
raise DataError('YAML variable files do not accept arguments.')
|
|
68
|
-
variables = self._import(path)
|
|
69
|
-
return [('${%s}' % name, self._dot_dict(value))
|
|
70
|
-
for name, value in variables]
|
|
71
|
-
|
|
72
|
-
def _import(self, path):
|
|
73
|
-
with io.open(path, encoding='UTF-8') as stream:
|
|
74
|
-
variables = self._load_yaml(stream)
|
|
75
|
-
if not is_dict_like(variables):
|
|
76
|
-
raise DataError('YAML variable file must be a mapping, got %s.'
|
|
77
|
-
% type_name(variables))
|
|
78
|
-
return variables.items()
|
|
79
|
-
|
|
80
|
-
def _load_yaml(self, stream):
|
|
81
|
-
if not yaml:
|
|
82
|
-
raise DataError('Using YAML variable files requires PyYAML module '
|
|
83
|
-
'to be installed. Typically you can install it '
|
|
84
|
-
'by running `pip install pyyaml`.')
|
|
85
|
-
if yaml.__version__.split('.')[0] == '3':
|
|
86
|
-
return yaml.load(stream)
|
|
87
|
-
return yaml.full_load(stream)
|
|
88
|
-
|
|
89
|
-
def _dot_dict(self, value):
|
|
90
|
-
if is_dict_like(value):
|
|
91
|
-
return DotDict((k, self._dot_dict(v)) for k, v in value.items())
|
|
92
|
-
if is_list_like(value):
|
|
93
|
-
return [self._dot_dict(v) for v in value]
|
|
94
|
-
return value
|
|
61
|
+
self.store.add(name, value, overwrite, decorated=False)
|
|
95
62
|
|
|
96
63
|
|
|
97
64
|
class PythonImporter:
|
|
@@ -102,24 +69,29 @@ class PythonImporter:
|
|
|
102
69
|
return self._get_variables(var_file, args)
|
|
103
70
|
|
|
104
71
|
def _get_variables(self, var_file, args):
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
72
|
+
get_variables = (getattr(var_file, 'get_variables', None) or
|
|
73
|
+
getattr(var_file, 'getVariables', None))
|
|
74
|
+
if get_variables:
|
|
75
|
+
variables = self._get_dynamic(get_variables, args)
|
|
76
|
+
elif not args:
|
|
108
77
|
variables = self._get_static(var_file)
|
|
78
|
+
else:
|
|
79
|
+
raise DataError('Static variable files do not accept arguments.')
|
|
109
80
|
return list(self._decorate_and_validate(variables))
|
|
110
81
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _get_dynamic(self, var_file, args):
|
|
116
|
-
get_variables = (getattr(var_file, 'get_variables', None) or
|
|
117
|
-
getattr(var_file, 'getVariables'))
|
|
118
|
-
variables = get_variables(*args)
|
|
82
|
+
def _get_dynamic(self, get_variables, args):
|
|
83
|
+
positional, named = self._resolve_arguments(get_variables, args)
|
|
84
|
+
variables = get_variables(*positional, **dict(named))
|
|
119
85
|
if is_dict_like(variables):
|
|
120
86
|
return variables.items()
|
|
121
|
-
raise DataError("Expected '
|
|
122
|
-
|
|
87
|
+
raise DataError(f"Expected '{get_variables.__name__}' to return "
|
|
88
|
+
f"a dictionary-like value, got {type_name(variables)}.")
|
|
89
|
+
|
|
90
|
+
def _resolve_arguments(self, get_variables, args):
|
|
91
|
+
# Avoid cyclic import. Yuck.
|
|
92
|
+
from robot.running.arguments import PythonArgumentParser
|
|
93
|
+
spec = PythonArgumentParser('variable file').parse(get_variables)
|
|
94
|
+
return spec.resolve(args)
|
|
123
95
|
|
|
124
96
|
def _get_static(self, var_file):
|
|
125
97
|
names = [attr for attr in dir(var_file) if not attr.startswith('_')]
|
|
@@ -132,40 +104,35 @@ class PythonImporter:
|
|
|
132
104
|
|
|
133
105
|
def _decorate_and_validate(self, variables):
|
|
134
106
|
for name, value in variables:
|
|
135
|
-
name
|
|
136
|
-
|
|
107
|
+
if name.startswith('LIST__'):
|
|
108
|
+
if not is_list_like(value):
|
|
109
|
+
raise DataError(f"Invalid variable '{name}': Expected a "
|
|
110
|
+
f"list-like value, got {type_name(value)}.")
|
|
111
|
+
name = name[6:]
|
|
112
|
+
value = list(value)
|
|
113
|
+
elif name.startswith('DICT__'):
|
|
114
|
+
if not is_dict_like(value):
|
|
115
|
+
raise DataError(f"Invalid variable '{name}': Expected a "
|
|
116
|
+
f"dictionary-like value, got {type_name(value)}.")
|
|
117
|
+
name = name[6:]
|
|
118
|
+
value = DotDict(value)
|
|
137
119
|
yield name, value
|
|
138
120
|
|
|
139
|
-
def _decorate(self, name):
|
|
140
|
-
if name.startswith('LIST__'):
|
|
141
|
-
return '@{%s}' % name[6:]
|
|
142
|
-
if name.startswith('DICT__'):
|
|
143
|
-
return '&{%s}' % name[6:]
|
|
144
|
-
return '${%s}' % name
|
|
145
|
-
|
|
146
|
-
def _validate(self, name, value):
|
|
147
|
-
if name[0] == '@' and not is_list_like(value):
|
|
148
|
-
raise DataError("Invalid variable '%s': Expected list-like value, "
|
|
149
|
-
"got %s." % (name, type_name(value)))
|
|
150
|
-
if name[0] == '&' and not is_dict_like(value):
|
|
151
|
-
raise DataError("Invalid variable '%s': Expected dict-like value, "
|
|
152
|
-
"got %s." % (name, type_name(value)))
|
|
153
|
-
|
|
154
121
|
|
|
155
122
|
class JsonImporter:
|
|
123
|
+
|
|
156
124
|
def import_variables(self, path, args=None):
|
|
157
125
|
if args:
|
|
158
126
|
raise DataError('JSON variable files do not accept arguments.')
|
|
159
127
|
variables = self._import(path)
|
|
160
|
-
return [(
|
|
161
|
-
for name, value in variables]
|
|
128
|
+
return [(name, self._dot_dict(value)) for name, value in variables]
|
|
162
129
|
|
|
163
130
|
def _import(self, path):
|
|
164
131
|
with io.open(path, encoding='UTF-8') as stream:
|
|
165
132
|
variables = json.load(stream)
|
|
166
133
|
if not is_dict_like(variables):
|
|
167
|
-
raise DataError('JSON variable file must be a mapping,
|
|
168
|
-
|
|
134
|
+
raise DataError(f'JSON variable file must be a mapping, '
|
|
135
|
+
f'got {type_name(variables)}.')
|
|
169
136
|
return variables.items()
|
|
170
137
|
|
|
171
138
|
def _dot_dict(self, value):
|
|
@@ -174,3 +141,36 @@ class JsonImporter:
|
|
|
174
141
|
if is_list_like(value):
|
|
175
142
|
return [self._dot_dict(v) for v in value]
|
|
176
143
|
return value
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class YamlImporter:
|
|
147
|
+
|
|
148
|
+
def import_variables(self, path, args=None):
|
|
149
|
+
if args:
|
|
150
|
+
raise DataError('YAML variable files do not accept arguments.')
|
|
151
|
+
variables = self._import(path)
|
|
152
|
+
return [(name, self._dot_dict(value)) for name, value in variables]
|
|
153
|
+
|
|
154
|
+
def _import(self, path):
|
|
155
|
+
with io.open(path, encoding='UTF-8') as stream:
|
|
156
|
+
variables = self._load_yaml(stream)
|
|
157
|
+
if not is_dict_like(variables):
|
|
158
|
+
raise DataError(f'YAML variable file must be a mapping, '
|
|
159
|
+
f'got {type_name(variables)}.')
|
|
160
|
+
return variables.items()
|
|
161
|
+
|
|
162
|
+
def _load_yaml(self, stream):
|
|
163
|
+
if not yaml:
|
|
164
|
+
raise DataError('Using YAML variable files requires PyYAML module '
|
|
165
|
+
'to be installed. Typically you can install it '
|
|
166
|
+
'by running `pip install pyyaml`.')
|
|
167
|
+
if yaml.__version__.split('.')[0] == '3':
|
|
168
|
+
return yaml.load(stream)
|
|
169
|
+
return yaml.full_load(stream)
|
|
170
|
+
|
|
171
|
+
def _dot_dict(self, value):
|
|
172
|
+
if is_dict_like(value):
|
|
173
|
+
return DotDict((k, self._dot_dict(v)) for k, v in value.items())
|
|
174
|
+
if is_list_like(value):
|
|
175
|
+
return [self._dot_dict(v) for v in value]
|
|
176
|
+
return value
|
|
@@ -42,33 +42,32 @@ class VariableReplacer:
|
|
|
42
42
|
items = list(items or [])
|
|
43
43
|
if replace_until is not None:
|
|
44
44
|
return self._replace_list_until(items, replace_until, ignore_errors)
|
|
45
|
-
return
|
|
45
|
+
return self._replace_list(items, ignore_errors)
|
|
46
46
|
|
|
47
|
-
def _replace_list_until(self, items,
|
|
47
|
+
def _replace_list_until(self, items, limit, ignore_errors):
|
|
48
48
|
# @{list} variables can contain more or less arguments than needed.
|
|
49
49
|
# Therefore, we need to go through items one by one, and escape
|
|
50
50
|
# possible extra items we got.
|
|
51
51
|
replaced = []
|
|
52
|
-
while len(replaced) <
|
|
52
|
+
while len(replaced) < limit and items:
|
|
53
53
|
replaced.extend(self._replace_list([items.pop(0)], ignore_errors))
|
|
54
|
-
if len(replaced) >
|
|
55
|
-
replaced[
|
|
56
|
-
for item in replaced[replace_until:]]
|
|
54
|
+
if len(replaced) > limit:
|
|
55
|
+
replaced[limit:] = [escape(item) for item in replaced[limit:]]
|
|
57
56
|
return replaced + items
|
|
58
57
|
|
|
59
58
|
def _replace_list(self, items, ignore_errors):
|
|
59
|
+
result = []
|
|
60
60
|
for item in items:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return [value]
|
|
61
|
+
match = search_variable(item, ignore_errors=ignore_errors)
|
|
62
|
+
if not match:
|
|
63
|
+
result.append(unescape(item))
|
|
64
|
+
else:
|
|
65
|
+
value = self._replace_scalar(match, ignore_errors)
|
|
66
|
+
if match.is_list_variable() and is_list_like(value):
|
|
67
|
+
result.extend(value)
|
|
68
|
+
else:
|
|
69
|
+
result.append(value)
|
|
70
|
+
return result
|
|
72
71
|
|
|
73
72
|
def replace_scalar(self, item, ignore_errors=False):
|
|
74
73
|
"""Replaces variables from a scalar item.
|
|
@@ -77,20 +76,18 @@ class VariableReplacer:
|
|
|
77
76
|
its value is returned. Otherwise, possible variables are replaced with
|
|
78
77
|
'replace_string'. Result may be any object.
|
|
79
78
|
"""
|
|
80
|
-
|
|
79
|
+
if isinstance(item, VariableMatch):
|
|
80
|
+
match = item
|
|
81
|
+
else:
|
|
82
|
+
match = search_variable(item, ignore_errors=ignore_errors)
|
|
81
83
|
if not match:
|
|
82
84
|
return unescape(match.string)
|
|
83
85
|
return self._replace_scalar(match, ignore_errors)
|
|
84
86
|
|
|
85
|
-
def _search_variable(self, item, ignore_errors):
|
|
86
|
-
if isinstance(item, VariableMatch):
|
|
87
|
-
return item
|
|
88
|
-
return search_variable(item, ignore_errors=ignore_errors)
|
|
89
|
-
|
|
90
87
|
def _replace_scalar(self, match, ignore_errors=False):
|
|
91
|
-
if
|
|
92
|
-
return self.
|
|
93
|
-
return self.
|
|
88
|
+
if match.is_variable():
|
|
89
|
+
return self._get_variable_value(match, ignore_errors)
|
|
90
|
+
return self._replace_string(match, unescape, ignore_errors)
|
|
94
91
|
|
|
95
92
|
def replace_string(self, item, custom_unescaper=None, ignore_errors=False):
|
|
96
93
|
"""Replaces variables from a string. Result is always a string.
|
|
@@ -98,7 +95,10 @@ class VariableReplacer:
|
|
|
98
95
|
Input can also be an already found VariableMatch.
|
|
99
96
|
"""
|
|
100
97
|
unescaper = custom_unescaper or unescape
|
|
101
|
-
|
|
98
|
+
if isinstance(item, VariableMatch):
|
|
99
|
+
match = item
|
|
100
|
+
else:
|
|
101
|
+
match = search_variable(item, ignore_errors=ignore_errors)
|
|
102
102
|
if not match:
|
|
103
103
|
return safe_str(unescaper(match.string))
|
|
104
104
|
return self._replace_string(match, unescaper, ignore_errors)
|
|
@@ -106,10 +106,8 @@ class VariableReplacer:
|
|
|
106
106
|
def _replace_string(self, match, unescaper, ignore_errors):
|
|
107
107
|
parts = []
|
|
108
108
|
while match:
|
|
109
|
-
parts.
|
|
110
|
-
|
|
111
|
-
safe_str(self._get_variable_value(match, ignore_errors))
|
|
112
|
-
])
|
|
109
|
+
parts.append(unescaper(match.before))
|
|
110
|
+
parts.append(safe_str(self._get_variable_value(match, ignore_errors)))
|
|
113
111
|
match = search_variable(match.after, ignore_errors=ignore_errors)
|
|
114
112
|
parts.append(unescaper(match.string))
|
|
115
113
|
return ''.join(parts)
|
|
@@ -126,17 +124,16 @@ class VariableReplacer:
|
|
|
126
124
|
if match.items:
|
|
127
125
|
value = self._get_variable_item(match, value)
|
|
128
126
|
try:
|
|
129
|
-
|
|
127
|
+
return self._validate_value(match, value)
|
|
130
128
|
except VariableError:
|
|
131
129
|
raise
|
|
132
130
|
except Exception:
|
|
133
131
|
error = get_error_message()
|
|
134
132
|
raise VariableError(f"Resolving variable '{match}' failed: {error}")
|
|
135
133
|
except DataError:
|
|
136
|
-
if
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return value
|
|
134
|
+
if ignore_errors:
|
|
135
|
+
return unescape(match.match)
|
|
136
|
+
raise
|
|
140
137
|
|
|
141
138
|
def _get_variable_item(self, match, value):
|
|
142
139
|
name = match.name
|
|
@@ -113,9 +113,9 @@ class VariableScopes:
|
|
|
113
113
|
else:
|
|
114
114
|
scope.set_from_file(variables, overwrite=overwrite)
|
|
115
115
|
|
|
116
|
-
def
|
|
116
|
+
def set_from_variable_section(self, variables, overwrite=False):
|
|
117
117
|
for scope in self._scopes_until_suite:
|
|
118
|
-
scope.
|
|
118
|
+
scope.set_from_variable_section(variables, overwrite)
|
|
119
119
|
|
|
120
120
|
def resolve_delayed(self):
|
|
121
121
|
for scope in self._scopes_until_suite:
|
|
@@ -154,7 +154,7 @@ class VariableScopes:
|
|
|
154
154
|
self.current[name] = value
|
|
155
155
|
self._variables_set.set_keyword(name, value)
|
|
156
156
|
|
|
157
|
-
def
|
|
157
|
+
def set_local(self, name, value):
|
|
158
158
|
self.current[name] = value
|
|
159
159
|
|
|
160
160
|
def as_dict(self, decoration=True):
|
|
@@ -14,59 +14,79 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
import re
|
|
17
|
+
from typing import Iterator, Sequence
|
|
17
18
|
|
|
18
19
|
from robot.errors import VariableError
|
|
19
20
|
from robot.utils import is_string
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
def search_variable(string, identifiers='$@&%*',
|
|
23
|
+
def search_variable(string: str, identifiers: Sequence[str] = '$@&%*',
|
|
24
|
+
ignore_errors: bool = False) -> 'VariableMatch':
|
|
23
25
|
if not (is_string(string) and '{' in string):
|
|
24
26
|
return VariableMatch(string)
|
|
25
27
|
return _search_variable(string, identifiers, ignore_errors)
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
def contains_variable(string, identifiers='$@&'):
|
|
30
|
+
def contains_variable(string: str, identifiers: Sequence[str] = '$@&') -> bool:
|
|
29
31
|
match = search_variable(string, identifiers, ignore_errors=True)
|
|
30
32
|
return bool(match)
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
def is_variable(string, identifiers='$@&'):
|
|
35
|
+
def is_variable(string: str, identifiers: Sequence[str] = '$@&') -> bool:
|
|
34
36
|
match = search_variable(string, identifiers, ignore_errors=True)
|
|
35
37
|
return match.is_variable()
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
def is_scalar_variable(string):
|
|
40
|
+
def is_scalar_variable(string: str) -> bool:
|
|
39
41
|
return is_variable(string, '$')
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
def is_list_variable(string):
|
|
44
|
+
def is_list_variable(string: str) -> bool:
|
|
43
45
|
return is_variable(string, '@')
|
|
44
46
|
|
|
45
47
|
|
|
46
|
-
def is_dict_variable(string):
|
|
48
|
+
def is_dict_variable(string: str) -> bool:
|
|
47
49
|
return is_variable(string, '&')
|
|
48
50
|
|
|
49
51
|
|
|
50
|
-
def is_assign(string
|
|
52
|
+
def is_assign(string: str,
|
|
53
|
+
identifiers: Sequence[str] = '$@&',
|
|
54
|
+
allow_assign_mark: bool = False,
|
|
55
|
+
allow_nested: bool = False,
|
|
56
|
+
allow_items: bool = False) -> bool:
|
|
51
57
|
match = search_variable(string, identifiers, ignore_errors=True)
|
|
52
|
-
return match.is_assign(allow_assign_mark, allow_items
|
|
58
|
+
return match.is_assign(allow_assign_mark, allow_nested, allow_items)
|
|
53
59
|
|
|
54
60
|
|
|
55
|
-
def is_scalar_assign(string
|
|
56
|
-
|
|
61
|
+
def is_scalar_assign(string: str,
|
|
62
|
+
allow_assign_mark: bool = False,
|
|
63
|
+
allow_nested: bool = False,
|
|
64
|
+
allow_items: bool = False) -> bool:
|
|
65
|
+
return is_assign(string, '$', allow_assign_mark, allow_nested, allow_items)
|
|
57
66
|
|
|
58
67
|
|
|
59
|
-
def is_list_assign(string
|
|
60
|
-
|
|
68
|
+
def is_list_assign(string: str,
|
|
69
|
+
allow_assign_mark: bool = False,
|
|
70
|
+
allow_nested: bool = False,
|
|
71
|
+
allow_items: bool = False) -> bool:
|
|
72
|
+
return is_assign(string, '@', allow_assign_mark, allow_nested, allow_items)
|
|
61
73
|
|
|
62
74
|
|
|
63
|
-
def is_dict_assign(string
|
|
64
|
-
|
|
75
|
+
def is_dict_assign(string: str,
|
|
76
|
+
allow_assign_mark: bool = False,
|
|
77
|
+
allow_nested: bool = False,
|
|
78
|
+
allow_items: bool = False) -> bool:
|
|
79
|
+
return is_assign(string, '&', allow_assign_mark, allow_nested, allow_items)
|
|
65
80
|
|
|
66
81
|
|
|
67
82
|
class VariableMatch:
|
|
68
83
|
|
|
69
|
-
def __init__(self, string
|
|
84
|
+
def __init__(self, string: str,
|
|
85
|
+
identifier: 'str|None' = None,
|
|
86
|
+
base: 'str|None' = None,
|
|
87
|
+
items: 'tuple[str, ...]' = (),
|
|
88
|
+
start: int = -1,
|
|
89
|
+
end: int = -1):
|
|
70
90
|
self.string = string
|
|
71
91
|
self.identifier = identifier
|
|
72
92
|
self.base = base
|
|
@@ -84,66 +104,70 @@ class VariableMatch:
|
|
|
84
104
|
)
|
|
85
105
|
|
|
86
106
|
@property
|
|
87
|
-
def name(self):
|
|
88
|
-
return '
|
|
107
|
+
def name(self) -> 'str|None':
|
|
108
|
+
return f'{self.identifier}{{{self.base}}}' if self.identifier else None
|
|
89
109
|
|
|
90
110
|
@property
|
|
91
|
-
def before(self):
|
|
111
|
+
def before(self) -> str:
|
|
92
112
|
return self.string[:self.start] if self.identifier else self.string
|
|
93
113
|
|
|
94
114
|
@property
|
|
95
|
-
def match(self):
|
|
115
|
+
def match(self) -> 'str|None':
|
|
96
116
|
return self.string[self.start:self.end] if self.identifier else None
|
|
97
117
|
|
|
98
118
|
@property
|
|
99
|
-
def after(self):
|
|
100
|
-
return self.string[self.end:] if self.identifier else
|
|
119
|
+
def after(self) -> str:
|
|
120
|
+
return self.string[self.end:] if self.identifier else ''
|
|
101
121
|
|
|
102
|
-
def is_variable(self):
|
|
122
|
+
def is_variable(self) -> bool:
|
|
103
123
|
return bool(self.identifier
|
|
104
124
|
and self.base
|
|
105
125
|
and self.start == 0
|
|
106
126
|
and self.end == len(self.string))
|
|
107
127
|
|
|
108
|
-
def is_scalar_variable(self):
|
|
128
|
+
def is_scalar_variable(self) -> bool:
|
|
109
129
|
return self.identifier == '$' and self.is_variable()
|
|
110
130
|
|
|
111
|
-
def is_list_variable(self):
|
|
131
|
+
def is_list_variable(self) -> bool:
|
|
112
132
|
return self.identifier == '@' and self.is_variable()
|
|
113
133
|
|
|
114
|
-
def is_dict_variable(self):
|
|
134
|
+
def is_dict_variable(self) -> bool:
|
|
115
135
|
return self.identifier == '&' and self.is_variable()
|
|
116
136
|
|
|
117
|
-
def is_assign(self,
|
|
118
|
-
|
|
137
|
+
def is_assign(self, allow_assign_mark: bool = False, allow_nested: bool = False,
|
|
138
|
+
allow_items: bool = False) -> bool:
|
|
119
139
|
if allow_assign_mark and self.string.endswith('='):
|
|
120
140
|
match = search_variable(self.string[:-1].rstrip(), ignore_errors=True)
|
|
121
|
-
return match.is_assign(allow_items=allow_items)
|
|
141
|
+
return match.is_assign(allow_nested=allow_nested, allow_items=allow_items)
|
|
122
142
|
return (self.is_variable()
|
|
123
143
|
and self.identifier in '$@&'
|
|
124
144
|
and (allow_items or not self.items)
|
|
125
145
|
and (allow_nested or not search_variable(self.base)))
|
|
126
146
|
|
|
127
|
-
def is_scalar_assign(self, allow_assign_mark=False,
|
|
147
|
+
def is_scalar_assign(self, allow_assign_mark: bool = False,
|
|
148
|
+
allow_nested: bool = False) -> bool:
|
|
128
149
|
return self.identifier == '$' and self.is_assign(allow_assign_mark, allow_nested)
|
|
129
150
|
|
|
130
|
-
def is_list_assign(self, allow_assign_mark=False,
|
|
151
|
+
def is_list_assign(self, allow_assign_mark: bool = False,
|
|
152
|
+
allow_nested: bool = False) -> bool:
|
|
131
153
|
return self.identifier == '@' and self.is_assign(allow_assign_mark, allow_nested)
|
|
132
154
|
|
|
133
|
-
def is_dict_assign(self, allow_assign_mark=False,
|
|
155
|
+
def is_dict_assign(self, allow_assign_mark: bool = False,
|
|
156
|
+
allow_nested: bool = False) -> bool:
|
|
134
157
|
return self.identifier == '&' and self.is_assign(allow_assign_mark, allow_nested)
|
|
135
158
|
|
|
136
|
-
def __bool__(self):
|
|
159
|
+
def __bool__(self) -> bool:
|
|
137
160
|
return self.identifier is not None
|
|
138
161
|
|
|
139
|
-
def __str__(self):
|
|
162
|
+
def __str__(self) -> str:
|
|
140
163
|
if not self:
|
|
141
164
|
return '<no match>'
|
|
142
165
|
items = ''.join('[%s]' % i for i in self.items) if self.items else ''
|
|
143
166
|
return '%s{%s}%s' % (self.identifier, self.base, items)
|
|
144
167
|
|
|
145
168
|
|
|
146
|
-
def _search_variable(string, identifiers,
|
|
169
|
+
def _search_variable(string: str, identifiers: Sequence[str],
|
|
170
|
+
ignore_errors: bool = False) -> VariableMatch:
|
|
147
171
|
start = _find_variable_start(string, identifiers)
|
|
148
172
|
if start < 0:
|
|
149
173
|
return VariableMatch(string)
|
|
@@ -194,7 +218,7 @@ def _search_variable(string, identifiers, ignore_errors=False):
|
|
|
194
218
|
raise VariableError(f"Variable '{incomplete}' was not closed properly.")
|
|
195
219
|
raise VariableError(f"Variable item '{incomplete}' was not closed properly.")
|
|
196
220
|
|
|
197
|
-
return match
|
|
221
|
+
return match
|
|
198
222
|
|
|
199
223
|
|
|
200
224
|
def _find_variable_start(string, identifiers):
|
|
@@ -233,26 +257,27 @@ def unescape_variable_syntax(item):
|
|
|
233
257
|
return re.sub(r'(\\+)(?=(.+))', handle_escapes, item)
|
|
234
258
|
|
|
235
259
|
|
|
236
|
-
class
|
|
260
|
+
class VariableMatches:
|
|
237
261
|
|
|
238
|
-
def __init__(self, string, identifiers='$@&%',
|
|
262
|
+
def __init__(self, string: str, identifiers: Sequence[str] = '$@&%',
|
|
263
|
+
ignore_errors: bool = False):
|
|
239
264
|
self.string = string
|
|
240
265
|
self.identifiers = identifiers
|
|
241
266
|
self.ignore_errors = ignore_errors
|
|
242
267
|
|
|
243
|
-
def __iter__(self):
|
|
268
|
+
def __iter__(self) -> Iterator[VariableMatch]:
|
|
244
269
|
remaining = self.string
|
|
245
270
|
while True:
|
|
246
271
|
match = search_variable(remaining, self.identifiers, self.ignore_errors)
|
|
247
272
|
if not match:
|
|
248
273
|
break
|
|
249
274
|
remaining = match.after
|
|
250
|
-
yield match
|
|
275
|
+
yield match
|
|
251
276
|
|
|
252
|
-
def __len__(self):
|
|
277
|
+
def __len__(self) -> int:
|
|
253
278
|
return sum(1 for _ in self)
|
|
254
279
|
|
|
255
|
-
def __bool__(self):
|
|
280
|
+
def __bool__(self) -> bool:
|
|
256
281
|
try:
|
|
257
282
|
next(iter(self))
|
|
258
283
|
except StopIteration:
|