robotframework 6.1.1__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.1.1 → robotframework-7.0}/INSTALL.rst +25 -25
- {robotframework-6.1.1 → robotframework-7.0}/PKG-INFO +6 -8
- {robotframework-6.1.1 → robotframework-7.0}/README.rst +3 -2
- {robotframework-6.1.1 → robotframework-7.0}/setup.py +3 -6
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/__init__.py +4 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/deco.py +60 -14
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/exceptions.py +6 -6
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/interfaces.py +402 -67
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/logger.py +27 -20
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/api/parsing.py +4 -2
- robotframework-7.0/src/robot/api/py.typed +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/gatherfailed.py +2 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/languages.py +0 -9
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/settings.py +21 -14
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/storage.js +11 -6
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/htmlfilewriter.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.css +10 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.html +10 -0
- robotframework-7.0/src/robot/htmldata/rebot/common.css +362 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/doc_formatting.css +13 -7
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.css +51 -10
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.html +14 -23
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/model.js +2 -4
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/report.css +83 -19
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/report.html +22 -7
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/testdata.js +10 -3
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/view.js +84 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/template.py +3 -3
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/builder.py +0 -8
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/datatypes.py +9 -10
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/htmlutils.py +4 -7
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/jsonbuilder.py +38 -20
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/model.py +21 -28
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/robotbuilder.py +50 -31
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/standardtypes.py +9 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/xmlbuilder.py +35 -20
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/xmlwriter.py +18 -38
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/BuiltIn.py +255 -205
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Collections.py +384 -240
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/DateTime.py +73 -60
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/OperatingSystem.py +6 -5
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Process.py +26 -27
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Remote.py +40 -36
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/String.py +66 -76
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/XML.py +66 -59
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/__init__.py +2 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/__init__.py +5 -5
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/body.py +44 -13
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/configurer.py +15 -11
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/control.py +226 -84
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/filter.py +31 -25
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/itemlist.py +9 -8
- robotframework-7.0/src/robot/model/keyword.py +77 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/message.py +19 -10
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/modelobject.py +25 -7
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/namepatterns.py +3 -25
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/stats.py +9 -15
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tags.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/testcase.py +15 -27
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/testsuite.py +17 -26
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/visitor.py +35 -8
- robotframework-7.0/src/robot/output/console/dotted.py +90 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/quiet.py +3 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/verbose.py +61 -61
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/debugfile.py +39 -24
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/filelogger.py +18 -15
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/librarylogger.py +3 -2
- robotframework-7.0/src/robot/output/listeners.py +753 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/logger.py +216 -80
- robotframework-7.0/src/robot/output/loggerapi.py +215 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/loggerhelper.py +23 -56
- robotframework-7.0/src/robot/output/output.py +185 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/stdoutlogsplitter.py +8 -5
- robotframework-7.0/src/robot/output/xmllogger.py +459 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/blocklexers.py +17 -13
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/context.py +12 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/lexer.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/settings.py +6 -3
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/statementlexers.py +39 -10
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/tokens.py +27 -29
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/blocks.py +19 -6
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/statements.py +193 -94
- robotframework-7.0/src/robot/parsing/model/visitor.py +100 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/rebot.py +2 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/expandkeywordmatcher.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsbuildingcontext.py +8 -6
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsmodelbuilders.py +88 -61
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/logreportwriters.py +16 -10
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/outputwriter.py +18 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/resultwriter.py +4 -4
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/stringcache.py +3 -3
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/xunitwriter.py +15 -21
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/__init__.py +3 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/configurer.py +12 -9
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/executionresult.py +56 -8
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/flattenkeywordmatcher.py +48 -9
- robotframework-7.0/src/robot/result/keywordremover.py +207 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/merger.py +1 -1
- robotframework-7.0/src/robot/result/model.py +1185 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/modeldeprecation.py +9 -3
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/resultbuilder.py +46 -36
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/xmlelementhandlers.py +83 -43
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/run.py +2 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/__init__.py +14 -4
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/__init__.py +2 -1
- robotframework-7.0/src/robot/running/arguments/argumentconverter.py +100 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentmapper.py +26 -24
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentparser.py +82 -60
- robotframework-7.0/src/robot/running/arguments/argumentresolver.py +158 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentspec.py +83 -116
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/argumentvalidator.py +33 -27
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/customconverters.py +15 -12
- robotframework-7.0/src/robot/running/arguments/embedded.py +145 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/arguments/typeconverters.py +233 -213
- 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.1.1 → robotframework-7.0}/src/robot/running/bodyrunner.py +147 -129
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/builders.py +2 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/parsers.py +10 -11
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/settings.py +9 -17
- robotframework-7.0/src/robot/running/builder/transformers.py +535 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/context.py +113 -31
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/dynamicmethods.py +62 -34
- {robotframework-6.1.1 → 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.1.1 → robotframework-7.0}/src/robot/running/model.py +195 -377
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/namespace.py +124 -137
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/outputcapture.py +20 -12
- robotframework-7.0/src/robot/running/resourcemodel.py +448 -0
- {robotframework-6.1.1 → 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.1.1 → robotframework-7.0}/src/robot/testdoc.py +18 -13
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/__init__.py +53 -35
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/connectioncache.py +64 -59
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/dotdict.py +3 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/encodingsniffer.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/escaping.py +19 -19
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/importer.py +2 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/markupwriters.py +23 -15
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/misc.py +1 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/normalizing.py +9 -24
- robotframework-7.0/src/robot/utils/notset.py +33 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/platform.py +15 -5
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotio.py +9 -9
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotpath.py +1 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robottime.py +122 -90
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robottypes.py +21 -31
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/setter.py +0 -5
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/text.py +7 -4
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/unic.py +2 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/__init__.py +2 -2
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/assigner.py +17 -19
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/evaluation.py +20 -17
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/filesetter.py +80 -80
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/replacer.py +33 -36
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/scopes.py +17 -12
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/search.py +66 -41
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/store.py +14 -16
- robotframework-7.0/src/robot/variables/tablesetter.py +164 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/variables.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/version.py +1 -1
- {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/PKG-INFO +6 -8
- {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/SOURCES.txt +10 -8
- {robotframework-6.1.1 → robotframework-7.0}/tasks.py +6 -6
- robotframework-6.1.1/src/robot/htmldata/rebot/common.css +0 -239
- robotframework-6.1.1/src/robot/libraries/Reserved.py +0 -48
- robotframework-6.1.1/src/robot/model/keyword.py +0 -173
- robotframework-6.1.1/src/robot/output/console/dotted.py +0 -90
- robotframework-6.1.1/src/robot/output/listenerarguments.py +0 -165
- robotframework-6.1.1/src/robot/output/listenermethods.py +0 -113
- robotframework-6.1.1/src/robot/output/listeners.py +0 -174
- robotframework-6.1.1/src/robot/output/output.py +0 -95
- robotframework-6.1.1/src/robot/output/xmllogger.py +0 -354
- robotframework-6.1.1/src/robot/parsing/model/visitor.py +0 -67
- robotframework-6.1.1/src/robot/result/keywordremover.py +0 -183
- robotframework-6.1.1/src/robot/result/model.py +0 -957
- robotframework-6.1.1/src/robot/running/arguments/argumentconverter.py +0 -79
- robotframework-6.1.1/src/robot/running/arguments/argumentresolver.py +0 -131
- robotframework-6.1.1/src/robot/running/arguments/embedded.py +0 -146
- robotframework-6.1.1/src/robot/running/arguments/typevalidator.py +0 -56
- robotframework-6.1.1/src/robot/running/builder/transformers.py +0 -642
- robotframework-6.1.1/src/robot/running/handlers.py +0 -321
- robotframework-6.1.1/src/robot/running/handlerstore.py +0 -66
- robotframework-6.1.1/src/robot/running/librarykeywordrunner.py +0 -238
- robotframework-6.1.1/src/robot/running/libraryscopes.py +0 -97
- robotframework-6.1.1/src/robot/running/modelcombiner.py +0 -32
- robotframework-6.1.1/src/robot/running/suiterunner.py +0 -248
- robotframework-6.1.1/src/robot/running/testlibraries.py +0 -423
- robotframework-6.1.1/src/robot/running/usererrorhandler.py +0 -75
- robotframework-6.1.1/src/robot/running/userkeyword.py +0 -111
- robotframework-6.1.1/src/robot/running/userkeywordrunner.py +0 -274
- robotframework-6.1.1/src/robot/variables/tablesetter.py +0 -156
- {robotframework-6.1.1 → robotframework-7.0}/AUTHORS.rst +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/BUILD.rst +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/CONTRIBUTING.rst +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/COPYRIGHT.txt +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/LICENSE.txt +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/MANIFEST.in +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/setup.cfg +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/__main__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/conf/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/errors.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/common/js_disabled.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/jsonwriter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.min.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/print.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/libdoc/pygments.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/fileloading.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/log.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/print.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/rebot/util.js +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.css +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.html +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdoc.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/consoleviewer.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/htmlwriter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/jsonwriter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/output.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libdocpkg/writer.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Dialogs.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Easter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Screenshot.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/Telnet.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/libraries/dialogs_py.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/fixture.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/metadata.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/modifier.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/statistics.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/suitestatistics.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tagsetter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/tagstatistics.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/model/totalstatistics.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/console/highlighting.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/output/pyloggingconf.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/lexer/tokenizer.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/model/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/blockparsers.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/fileparser.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/parser/parser.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/parsing/suitestructure.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/pythonpathsetter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jsexecutionresult.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/reporting/jswriter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/executionerrors.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/messagefilter.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/suiteteardownfailed.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/result/visitor.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/builder/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/randomizer.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/runkwregister.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/signalhandler.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/status.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/__init__.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/posix.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/running/timeouts/windows.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/application.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/argumentparser.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/asserts.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/charwidth.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/compress.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/encoding.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/error.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/etreewrapper.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/filereader.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/frange.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/htmlformatters.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/markuputils.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/match.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/recommendations.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/restreader.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotenv.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/robotinspect.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/sortable.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/utils/typehints.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/finders.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/notfound.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robot/variables/resolvable.py +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/dependency_links.txt +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/entry_points.txt +0 -0
- {robotframework-6.1.1 → robotframework-7.0}/src/robotframework.egg-info/top_level.txt +0 -0
|
@@ -15,22 +15,15 @@
|
|
|
15
15
|
|
|
16
16
|
import copy
|
|
17
17
|
from ast import literal_eval
|
|
18
|
+
from itertools import chain
|
|
18
19
|
|
|
19
20
|
from robot.api import logger
|
|
20
|
-
from robot.utils import (get_error_message, is_dict_like, is_list_like,
|
|
21
|
-
|
|
21
|
+
from robot.utils import (get_error_message, is_dict_like, is_list_like, Matcher,
|
|
22
|
+
NOT_SET, plural_or_not as s, seq2str, seq2str2, type_name)
|
|
22
23
|
from robot.utils.asserts import assert_equal
|
|
23
24
|
from robot.version import get_version
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
class NotSet:
|
|
27
|
-
def __repr__(self):
|
|
28
|
-
return ""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
NOT_SET = NotSet()
|
|
32
|
-
|
|
33
|
-
|
|
34
27
|
class _List:
|
|
35
28
|
|
|
36
29
|
def convert_to_list(self, item):
|
|
@@ -93,10 +86,7 @@ class _List:
|
|
|
93
86
|
| ${L1} and ${L2} are not changed.
|
|
94
87
|
"""
|
|
95
88
|
self._validate_lists(*lists)
|
|
96
|
-
|
|
97
|
-
for item in lists:
|
|
98
|
-
ret.extend(item)
|
|
99
|
-
return ret
|
|
89
|
+
return list(chain.from_iterable(lists))
|
|
100
90
|
|
|
101
91
|
def set_list_value(self, list_, index, value):
|
|
102
92
|
"""Sets the value of ``list`` specified by ``index`` to the given ``value``.
|
|
@@ -263,19 +253,19 @@ class _List:
|
|
|
263
253
|
| ${L5} is not changed
|
|
264
254
|
"""
|
|
265
255
|
self._validate_list(list_)
|
|
266
|
-
|
|
267
|
-
start = 0
|
|
256
|
+
start = self._index_to_int(start, empty_to_zero=True)
|
|
268
257
|
list_ = self.get_slice_from_list(list_, start, end)
|
|
269
258
|
try:
|
|
270
|
-
return
|
|
259
|
+
return start + list_.index(value)
|
|
271
260
|
except ValueError:
|
|
272
261
|
return -1
|
|
273
262
|
|
|
274
263
|
def copy_list(self, list_, deepcopy=False):
|
|
275
264
|
"""Returns a copy of the given list.
|
|
276
265
|
|
|
277
|
-
|
|
278
|
-
|
|
266
|
+
By default, returns a new list with same items as in the original.
|
|
267
|
+
Set the ``deepcopy`` argument to a true value if also items should
|
|
268
|
+
be copied.
|
|
279
269
|
|
|
280
270
|
The given list is never altered by this keyword.
|
|
281
271
|
"""
|
|
@@ -301,36 +291,44 @@ class _List:
|
|
|
301
291
|
"""Sorts the given list in place.
|
|
302
292
|
|
|
303
293
|
Sorting fails if items in the list are not comparable with each others.
|
|
304
|
-
|
|
305
|
-
for example, strings with numbers is not possible.
|
|
294
|
+
For example, sorting a list containing strings and numbers is not possible.
|
|
306
295
|
|
|
307
296
|
Note that the given list is changed and nothing is returned. Use
|
|
308
|
-
`Copy List` first, if you need to
|
|
297
|
+
`Copy List` first, if you need to preserve the list also in the original
|
|
298
|
+
order.
|
|
309
299
|
"""
|
|
310
300
|
self._validate_list(list_)
|
|
311
301
|
list_.sort()
|
|
312
302
|
|
|
313
|
-
def list_should_contain_value(self, list_, value, msg=None):
|
|
303
|
+
def list_should_contain_value(self, list_, value, msg=None, ignore_case=False):
|
|
314
304
|
"""Fails if the ``value`` is not found from ``list``.
|
|
315
305
|
|
|
316
306
|
Use the ``msg`` argument to override the default error message.
|
|
307
|
+
|
|
308
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
309
|
+
See the `Ignore case` section for more details. This option is new in
|
|
310
|
+
Robot Framework 7.0.
|
|
317
311
|
"""
|
|
318
312
|
self._validate_list(list_)
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
msg)
|
|
313
|
+
normalize = Normalizer(ignore_case).normalize
|
|
314
|
+
_verify_condition(normalize(value) in normalize(list_),
|
|
315
|
+
f"{seq2str2(list_)} does not contain value '{value}'.", msg)
|
|
322
316
|
|
|
323
|
-
def list_should_not_contain_value(self, list_, value, msg=None):
|
|
317
|
+
def list_should_not_contain_value(self, list_, value, msg=None, ignore_case=False):
|
|
324
318
|
"""Fails if the ``value`` is found from ``list``.
|
|
325
319
|
|
|
326
320
|
Use the ``msg`` argument to override the default error message.
|
|
321
|
+
|
|
322
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
323
|
+
See the `Ignore case` section for more details. This option is new in
|
|
324
|
+
Robot Framework 7.0.
|
|
327
325
|
"""
|
|
328
326
|
self._validate_list(list_)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
msg)
|
|
327
|
+
normalize = Normalizer(ignore_case).normalize
|
|
328
|
+
_verify_condition(normalize(value) not in normalize(list_),
|
|
329
|
+
f"{seq2str2(list_)} contains value '{value}'.", msg)
|
|
332
330
|
|
|
333
|
-
def list_should_not_contain_duplicates(self, list_, msg=None):
|
|
331
|
+
def list_should_not_contain_duplicates(self, list_, msg=None, ignore_case=False):
|
|
334
332
|
"""Fails if any element in the ``list`` is found from it more than once.
|
|
335
333
|
|
|
336
334
|
The default error message lists all the elements that were found
|
|
@@ -340,11 +338,14 @@ class _List:
|
|
|
340
338
|
|
|
341
339
|
This keyword works with all iterables that can be converted to a list.
|
|
342
340
|
The original iterable is never altered.
|
|
341
|
+
|
|
342
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
343
|
+
See the `Ignore case` section for more details. This option is new in
|
|
344
|
+
Robot Framework 7.0.
|
|
343
345
|
"""
|
|
344
346
|
self._validate_list(list_)
|
|
345
|
-
if not isinstance(list_, list):
|
|
346
|
-
list_ = list(list_)
|
|
347
347
|
dupes = []
|
|
348
|
+
list_ = Normalizer(ignore_case).normalize(list_)
|
|
348
349
|
for item in list_:
|
|
349
350
|
if item not in dupes:
|
|
350
351
|
count = list_.count(item)
|
|
@@ -355,7 +356,7 @@ class _List:
|
|
|
355
356
|
raise AssertionError(msg or f'{seq2str(dupes)} found multiple times.')
|
|
356
357
|
|
|
357
358
|
def lists_should_be_equal(self, list1, list2, msg=None, values=True,
|
|
358
|
-
names=None, ignore_order=False):
|
|
359
|
+
names=None, ignore_order=False, ignore_case=False):
|
|
359
360
|
"""Fails if given lists are unequal.
|
|
360
361
|
|
|
361
362
|
The keyword first verifies that the lists have equal lengths, and then
|
|
@@ -392,12 +393,17 @@ class _List:
|
|
|
392
393
|
|
|
393
394
|
The optional ``ignore_order`` argument can be used to ignore the order
|
|
394
395
|
of the elements in the lists. Using it requires items to be sortable.
|
|
395
|
-
This
|
|
396
|
+
This option works recursively with nested lists starting from Robot
|
|
397
|
+
Framework 7.0.
|
|
396
398
|
|
|
397
399
|
Example:
|
|
398
400
|
| ${list1} = | Create List | apple | cherry | banana |
|
|
399
401
|
| ${list2} = | Create List | cherry | banana | apple |
|
|
400
402
|
| Lists Should Be Equal | ${list1} | ${list2} | ignore_order=True |
|
|
403
|
+
|
|
404
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
405
|
+
See the `Ignore case` section for more details. This option is new in
|
|
406
|
+
Robot Framework 7.0.
|
|
401
407
|
"""
|
|
402
408
|
self._validate_lists(list1, list2)
|
|
403
409
|
len1 = len(list1)
|
|
@@ -406,10 +412,9 @@ class _List:
|
|
|
406
412
|
f'Lengths are different: {len1} != {len2}',
|
|
407
413
|
msg, values)
|
|
408
414
|
names = self._get_list_index_name_mapping(names, len1)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
diffs = '\n'.join(self._yield_list_diffs(list1, list2, names))
|
|
415
|
+
normalize = Normalizer(ignore_case, ignore_order).normalize
|
|
416
|
+
diffs = '\n'.join(self._yield_list_diffs(normalize(list1), normalize(list2),
|
|
417
|
+
names))
|
|
413
418
|
_verify_condition(not diffs,
|
|
414
419
|
f'Lists are different:\n{diffs}',
|
|
415
420
|
msg, values)
|
|
@@ -418,7 +423,7 @@ class _List:
|
|
|
418
423
|
if not names:
|
|
419
424
|
return {}
|
|
420
425
|
if is_dict_like(names):
|
|
421
|
-
return
|
|
426
|
+
return {int(index): names[index] for index in names}
|
|
422
427
|
return dict(zip(range(list_length), names))
|
|
423
428
|
|
|
424
429
|
def _yield_list_diffs(self, list1, list2, names):
|
|
@@ -429,7 +434,8 @@ class _List:
|
|
|
429
434
|
except AssertionError as err:
|
|
430
435
|
yield str(err)
|
|
431
436
|
|
|
432
|
-
def list_should_contain_sub_list(self, list1, list2, msg=None, values=True
|
|
437
|
+
def list_should_contain_sub_list(self, list1, list2, msg=None, values=True,
|
|
438
|
+
ignore_case=False):
|
|
433
439
|
"""Fails if not all elements in ``list2`` are found in ``list1``.
|
|
434
440
|
|
|
435
441
|
The order of values and the number of values are not taken into
|
|
@@ -437,8 +443,15 @@ class _List:
|
|
|
437
443
|
|
|
438
444
|
See `Lists Should Be Equal` for more information about configuring
|
|
439
445
|
the error message with ``msg`` and ``values`` arguments.
|
|
446
|
+
|
|
447
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
448
|
+
See the `Ignore case` section for more details. This option is new in
|
|
449
|
+
Robot Framework 7.0.
|
|
440
450
|
"""
|
|
441
451
|
self._validate_lists(list1, list2)
|
|
452
|
+
normalize = Normalizer(ignore_case).normalize
|
|
453
|
+
list1 = normalize(list1)
|
|
454
|
+
list2 = normalize(list2)
|
|
442
455
|
diffs = ', '.join(str(item) for item in list2 if item not in list1)
|
|
443
456
|
_verify_condition(not diffs,
|
|
444
457
|
f'Following values were not found from first list: {diffs}',
|
|
@@ -586,12 +599,9 @@ class _Dictionary:
|
|
|
586
599
|
def copy_dictionary(self, dictionary, deepcopy=False):
|
|
587
600
|
"""Returns a copy of the given dictionary.
|
|
588
601
|
|
|
589
|
-
|
|
590
|
-
a
|
|
591
|
-
|
|
592
|
-
``deepcopy`` a true value (see `Boolean arguments`). This is a new
|
|
593
|
-
option in Robot Framework 3.1.2. Earlier versions always returned
|
|
594
|
-
shallow copies.
|
|
602
|
+
By default, returns a new dictionary with same items as in the original.
|
|
603
|
+
Set the ``deepcopy`` argument to a true value if also items should
|
|
604
|
+
be copied.
|
|
595
605
|
|
|
596
606
|
The given dictionary is never altered by this keyword.
|
|
597
607
|
"""
|
|
@@ -603,53 +613,36 @@ class _Dictionary:
|
|
|
603
613
|
def get_dictionary_keys(self, dictionary, sort_keys=True):
|
|
604
614
|
"""Returns keys of the given ``dictionary`` as a list.
|
|
605
615
|
|
|
606
|
-
By default keys are returned in sorted order (assuming they are
|
|
616
|
+
By default, keys are returned in sorted order (assuming they are
|
|
607
617
|
sortable), but they can be returned in the original order by giving
|
|
608
|
-
``sort_keys``
|
|
609
|
-
with Python 3.5 and earlier dictionary order is undefined unless using
|
|
610
|
-
ordered dictionaries.
|
|
618
|
+
``sort_keys`` a false value.
|
|
611
619
|
|
|
612
620
|
The given ``dictionary`` is never altered by this keyword.
|
|
613
621
|
|
|
614
622
|
Example:
|
|
615
623
|
| ${sorted} = | Get Dictionary Keys | ${D3} |
|
|
616
624
|
| ${unsorted} = | Get Dictionary Keys | ${D3} | sort_keys=False |
|
|
617
|
-
=>
|
|
618
|
-
| ${sorted} = ['a', 'b', 'c']
|
|
619
|
-
| ${unsorted} = ['b', 'a', 'c'] # Order depends on Python version.
|
|
620
|
-
|
|
621
|
-
``sort_keys`` is a new option in Robot Framework 3.1.2. Earlier keys
|
|
622
|
-
were always sorted.
|
|
623
625
|
"""
|
|
624
626
|
self._validate_dictionary(dictionary)
|
|
625
|
-
keys = dictionary.keys()
|
|
626
627
|
if sort_keys:
|
|
627
628
|
try:
|
|
628
|
-
return sorted(
|
|
629
|
+
return sorted(dictionary)
|
|
629
630
|
except TypeError:
|
|
630
631
|
pass
|
|
631
|
-
return list(
|
|
632
|
+
return list(dictionary)
|
|
632
633
|
|
|
633
634
|
def get_dictionary_values(self, dictionary, sort_keys=True):
|
|
634
635
|
"""Returns values of the given ``dictionary`` as a list.
|
|
635
636
|
|
|
636
637
|
Uses `Get Dictionary Keys` to get keys and then returns corresponding
|
|
637
|
-
values. By default keys are sorted and values returned in that order,
|
|
638
|
-
but this can be changed by giving ``sort_keys`` a false value
|
|
639
|
-
`Boolean arguments`). Notice that with Python 3.5 and earlier
|
|
640
|
-
dictionary order is undefined unless using ordered dictionaries.
|
|
638
|
+
values. By default, keys are sorted and values returned in that order,
|
|
639
|
+
but this can be changed by giving ``sort_keys`` a false value.
|
|
641
640
|
|
|
642
641
|
The given ``dictionary`` is never altered by this keyword.
|
|
643
642
|
|
|
644
643
|
Example:
|
|
645
644
|
| ${sorted} = | Get Dictionary Values | ${D3} |
|
|
646
645
|
| ${unsorted} = | Get Dictionary Values | ${D3} | sort_keys=False |
|
|
647
|
-
=>
|
|
648
|
-
| ${sorted} = [1, 2, 3]
|
|
649
|
-
| ${unsorted} = [2, 1, 3] # Order depends on Python version.
|
|
650
|
-
|
|
651
|
-
``sort_keys`` is a new option in Robot Framework 3.1.2. Earlier values
|
|
652
|
-
were always sorted based on keys.
|
|
653
646
|
"""
|
|
654
647
|
self._validate_dictionary(dictionary)
|
|
655
648
|
keys = self.get_dictionary_keys(dictionary, sort_keys=sort_keys)
|
|
@@ -659,10 +652,8 @@ class _Dictionary:
|
|
|
659
652
|
"""Returns items of the given ``dictionary`` as a list.
|
|
660
653
|
|
|
661
654
|
Uses `Get Dictionary Keys` to get keys and then returns corresponding
|
|
662
|
-
items. By default keys are sorted and items returned in that order,
|
|
663
|
-
but this can be changed by giving ``sort_keys`` a false value
|
|
664
|
-
`Boolean arguments`). Notice that with Python 3.5 and earlier
|
|
665
|
-
dictionary order is undefined unless using ordered dictionaries.
|
|
655
|
+
items. By default, keys are sorted and items returned in that order,
|
|
656
|
+
but this can be changed by giving ``sort_keys`` a false value.
|
|
666
657
|
|
|
667
658
|
Items are returned as a flat list so that first item is a key,
|
|
668
659
|
second item is a corresponding value, third item is the second key,
|
|
@@ -673,12 +664,6 @@ class _Dictionary:
|
|
|
673
664
|
Example:
|
|
674
665
|
| ${sorted} = | Get Dictionary Items | ${D3} |
|
|
675
666
|
| ${unsorted} = | Get Dictionary Items | ${D3} | sort_keys=False |
|
|
676
|
-
=>
|
|
677
|
-
| ${sorted} = ['a', 1, 'b', 2, 'c', 3]
|
|
678
|
-
| ${unsorted} = ['b', 2, 'a', 1, 'c', 3] # Order depends on Python version.
|
|
679
|
-
|
|
680
|
-
``sort_keys`` is a new option in Robot Framework 3.1.2. Earlier items
|
|
681
|
-
were always sorted based on keys.
|
|
682
667
|
"""
|
|
683
668
|
self._validate_dictionary(dictionary)
|
|
684
669
|
keys = self.get_dictionary_keys(dictionary, sort_keys=sort_keys)
|
|
@@ -708,61 +693,95 @@ class _Dictionary:
|
|
|
708
693
|
return default
|
|
709
694
|
raise RuntimeError(f"Dictionary does not contain key '{key}'.")
|
|
710
695
|
|
|
711
|
-
def dictionary_should_contain_key(self, dictionary, key, msg=None
|
|
696
|
+
def dictionary_should_contain_key(self, dictionary, key, msg=None,
|
|
697
|
+
ignore_case=False):
|
|
712
698
|
"""Fails if ``key`` is not found from ``dictionary``.
|
|
713
699
|
|
|
714
700
|
Use the ``msg`` argument to override the default error message.
|
|
701
|
+
|
|
702
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
703
|
+
See the `Ignore case` section for more details. This option is new in
|
|
704
|
+
Robot Framework 7.0.
|
|
715
705
|
"""
|
|
716
706
|
self._validate_dictionary(dictionary)
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
707
|
+
norm = Normalizer(ignore_case)
|
|
708
|
+
_verify_condition(
|
|
709
|
+
norm.normalize_key(key) in norm.normalize(dictionary),
|
|
710
|
+
f"Dictionary does not contain key '{key}'.", msg
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
def dictionary_should_not_contain_key(self, dictionary, key, msg=None,
|
|
714
|
+
ignore_case=False):
|
|
722
715
|
"""Fails if ``key`` is found from ``dictionary``.
|
|
723
716
|
|
|
724
717
|
Use the ``msg`` argument to override the default error message.
|
|
718
|
+
|
|
719
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
720
|
+
See the `Ignore case` section for more details. This option is new in
|
|
721
|
+
Robot Framework 7.0.
|
|
725
722
|
"""
|
|
726
723
|
self._validate_dictionary(dictionary)
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
724
|
+
norm = Normalizer(ignore_case)
|
|
725
|
+
_verify_condition(
|
|
726
|
+
norm.normalize_key(key) not in norm.normalize(dictionary),
|
|
727
|
+
f"Dictionary contains key '{key}'.", msg
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
def dictionary_should_contain_item(self, dictionary, key, value, msg=None,
|
|
731
|
+
ignore_case=False):
|
|
732
732
|
"""An item of ``key`` / ``value`` must be found in a ``dictionary``.
|
|
733
733
|
|
|
734
|
-
Value is converted to unicode for comparison.
|
|
735
|
-
|
|
736
734
|
Use the ``msg`` argument to override the default error message.
|
|
735
|
+
|
|
736
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
737
|
+
See the `Ignore case` section for more details. This option is new in
|
|
738
|
+
Robot Framework 7.0.
|
|
737
739
|
"""
|
|
738
740
|
self._validate_dictionary(dictionary)
|
|
739
|
-
self.dictionary_should_contain_key(dictionary, key, msg)
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
741
|
+
self.dictionary_should_contain_key(dictionary, key, msg, ignore_case)
|
|
742
|
+
norm = Normalizer(ignore_case)
|
|
743
|
+
assert_equal(
|
|
744
|
+
norm.normalize(dictionary)[norm.normalize_key(key)],
|
|
745
|
+
norm.normalize_value(value),
|
|
746
|
+
msg or f"Value of dictionary key '{key}' does not match", values=not msg
|
|
747
|
+
)
|
|
748
|
+
|
|
749
|
+
def dictionary_should_contain_value(self, dictionary, value, msg=None,
|
|
750
|
+
ignore_case=False):
|
|
745
751
|
"""Fails if ``value`` is not found from ``dictionary``.
|
|
746
752
|
|
|
747
753
|
Use the ``msg`` argument to override the default error message.
|
|
754
|
+
|
|
755
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
756
|
+
See the `Ignore case` section for more details. This option is new in
|
|
757
|
+
Robot Framework 7.0.
|
|
748
758
|
"""
|
|
749
759
|
self._validate_dictionary(dictionary)
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
760
|
+
norm = Normalizer(ignore_case)
|
|
761
|
+
_verify_condition(
|
|
762
|
+
norm.normalize_value(value) in norm.normalize(dictionary).values(),
|
|
763
|
+
f"Dictionary does not contain value '{value}'.", msg
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
def dictionary_should_not_contain_value(self, dictionary, value, msg=None,
|
|
767
|
+
ignore_case=False):
|
|
755
768
|
"""Fails if ``value`` is found from ``dictionary``.
|
|
756
769
|
|
|
757
770
|
Use the ``msg`` argument to override the default error message.
|
|
771
|
+
|
|
772
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
773
|
+
See the `Ignore case` section for more details. This option is new in
|
|
774
|
+
Robot Framework 7.0.
|
|
758
775
|
"""
|
|
759
776
|
self._validate_dictionary(dictionary)
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
777
|
+
norm = Normalizer(ignore_case)
|
|
778
|
+
_verify_condition(
|
|
779
|
+
norm.normalize_value(value) not in norm.normalize(dictionary).values(),
|
|
780
|
+
f"Dictionary contains value '{value}'.", msg
|
|
781
|
+
)
|
|
763
782
|
|
|
764
783
|
def dictionaries_should_be_equal(self, dict1, dict2, msg=None, values=True,
|
|
765
|
-
ignore_keys=None):
|
|
784
|
+
ignore_keys=None, ignore_case=False):
|
|
766
785
|
"""Fails if the given dictionaries are not equal.
|
|
767
786
|
|
|
768
787
|
First the equality of dictionaries' keys is checked and after that all
|
|
@@ -772,7 +791,8 @@ class _Dictionary:
|
|
|
772
791
|
|
|
773
792
|
``ignore_keys`` can be used to provide a list of keys to ignore in the
|
|
774
793
|
comparison. It can be an actual list or a Python list literal. This
|
|
775
|
-
option is new in Robot Framework 6.1.
|
|
794
|
+
option is new in Robot Framework 6.1. It works recursively with nested
|
|
795
|
+
dictionaries starting from Robot Framework 7.0.
|
|
776
796
|
|
|
777
797
|
Examples:
|
|
778
798
|
| Dictionaries Should Be Equal | ${dict} | ${expected} |
|
|
@@ -781,39 +801,58 @@ class _Dictionary:
|
|
|
781
801
|
|
|
782
802
|
See `Lists Should Be Equal` for more information about configuring
|
|
783
803
|
the error message with ``msg`` and ``values`` arguments.
|
|
804
|
+
|
|
805
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
806
|
+
See the `Ignore case` section for more details. This option is new in
|
|
807
|
+
Robot Framework 7.0.
|
|
784
808
|
"""
|
|
785
|
-
self._validate_dictionary(dict1)
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
809
|
+
self._validate_dictionary(dict1, dict2)
|
|
810
|
+
normalizer = Normalizer(ignore_case, ignore_keys=ignore_keys)
|
|
811
|
+
dict1 = normalizer.normalize(dict1)
|
|
812
|
+
dict2 = normalizer.normalize(dict2)
|
|
813
|
+
self._should_have_same_keys(dict1, dict2, msg, values)
|
|
814
|
+
self._should_have_same_values(dict1, dict2, msg, values)
|
|
815
|
+
|
|
816
|
+
def _should_have_same_keys(self, dict1, dict2, message, values, validate_both=True):
|
|
817
|
+
missing = seq2str([k for k in dict2 if k not in dict1])
|
|
818
|
+
error = ''
|
|
819
|
+
if missing:
|
|
820
|
+
error = f"Following keys missing from first dictionary: {missing}"
|
|
821
|
+
if validate_both:
|
|
822
|
+
missing = seq2str([k for k in dict1 if k not in dict2])
|
|
823
|
+
if missing:
|
|
824
|
+
error += f"\nFollowing keys missing from second dictionary: {missing}"
|
|
825
|
+
if error:
|
|
826
|
+
_report_error(error.strip(), message, values)
|
|
827
|
+
|
|
828
|
+
def _should_have_same_values(self, dict1, dict2, message, values):
|
|
829
|
+
errors = []
|
|
830
|
+
for key in dict2:
|
|
831
|
+
try:
|
|
832
|
+
assert_equal(dict1[key], dict2[key], msg=f'Key {key}')
|
|
833
|
+
except AssertionError as err:
|
|
834
|
+
errors.append(str(err))
|
|
835
|
+
if errors:
|
|
836
|
+
error = '\n'.join([f'Following keys have different values:', *errors])
|
|
837
|
+
_report_error(error, message, values)
|
|
801
838
|
|
|
802
839
|
def dictionary_should_contain_sub_dictionary(self, dict1, dict2, msg=None,
|
|
803
|
-
values=True):
|
|
840
|
+
values=True, ignore_case=False):
|
|
804
841
|
"""Fails unless all items in ``dict2`` are found from ``dict1``.
|
|
805
842
|
|
|
806
843
|
See `Lists Should Be Equal` for more information about configuring
|
|
807
844
|
the error message with ``msg`` and ``values`` arguments.
|
|
845
|
+
|
|
846
|
+
The ``ignore_case`` argument can be used to make comparison case-insensitive.
|
|
847
|
+
See the `Ignore case` section for more details. This option is new in
|
|
848
|
+
Robot Framework 7.0.
|
|
808
849
|
"""
|
|
809
|
-
self._validate_dictionary(dict1)
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
msg, values)
|
|
816
|
-
self._key_values_should_be_equal(keys, dict1, dict2, msg, values)
|
|
850
|
+
self._validate_dictionary(dict1, dict2)
|
|
851
|
+
normalizer = Normalizer(ignore_case)
|
|
852
|
+
dict1 = normalizer.normalize(dict1)
|
|
853
|
+
dict2 = normalizer.normalize(dict2)
|
|
854
|
+
self._should_have_same_keys(dict1, dict2, msg, values, validate_both=False)
|
|
855
|
+
self._should_have_same_values(dict1, dict2, msg, values)
|
|
817
856
|
|
|
818
857
|
def log_dictionary(self, dictionary, level='INFO'):
|
|
819
858
|
"""Logs the size and contents of the ``dictionary`` using given ``level``.
|
|
@@ -836,36 +875,11 @@ class _Dictionary:
|
|
|
836
875
|
for key in self.get_dictionary_keys(dictionary):
|
|
837
876
|
yield f'{key}: {dictionary[key]}'
|
|
838
877
|
|
|
839
|
-
def
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
error = []
|
|
845
|
-
if miss1:
|
|
846
|
-
error += [f'Following keys missing from first dictionary: {miss1}']
|
|
847
|
-
if miss2:
|
|
848
|
-
error += [f'Following keys missing from second dictionary: {miss2}']
|
|
849
|
-
_verify_condition(not error, '\n'.join(error), msg, values)
|
|
850
|
-
return keys1
|
|
851
|
-
|
|
852
|
-
def _key_values_should_be_equal(self, keys, dict1, dict2, msg, values):
|
|
853
|
-
diffs = '\n'.join(self._yield_dict_diffs(keys, dict1, dict2))
|
|
854
|
-
_verify_condition(not diffs,
|
|
855
|
-
f'Following keys have different values:\n{diffs}',
|
|
856
|
-
msg, values)
|
|
857
|
-
|
|
858
|
-
def _yield_dict_diffs(self, keys, dict1, dict2):
|
|
859
|
-
for key in keys:
|
|
860
|
-
try:
|
|
861
|
-
assert_equal(dict1[key], dict2[key], msg=f'Key {key}')
|
|
862
|
-
except AssertionError as err:
|
|
863
|
-
yield str(err)
|
|
864
|
-
|
|
865
|
-
def _validate_dictionary(self, dictionary, position=1):
|
|
866
|
-
if not is_dict_like(dictionary):
|
|
867
|
-
raise TypeError(f"Expected argument {position} to be a dictionary or "
|
|
868
|
-
f"dictionary-like, got {type_name(dictionary)} instead.")
|
|
878
|
+
def _validate_dictionary(self, *dictionaries):
|
|
879
|
+
for index, dictionary in enumerate(dictionaries, start=1):
|
|
880
|
+
if not is_dict_like(dictionary):
|
|
881
|
+
raise TypeError(f"Expected argument {index} to be a dictionary, "
|
|
882
|
+
f"got {type_name(dictionary)} instead.")
|
|
869
883
|
|
|
870
884
|
|
|
871
885
|
class Collections(_List, _Dictionary):
|
|
@@ -903,14 +917,36 @@ class Collections(_List, _Dictionary):
|
|
|
903
917
|
= Using with list-like and dictionary-like objects =
|
|
904
918
|
|
|
905
919
|
List keywords that do not alter the given list can also be used
|
|
906
|
-
with tuples, and to some
|
|
920
|
+
with tuples, and to some extent also with other iterables.
|
|
907
921
|
`Convert To List` can be used to convert tuples and other iterables
|
|
908
922
|
to Python ``list`` objects.
|
|
909
923
|
|
|
910
|
-
Similarly dictionary keywords can, for most parts, be used with other
|
|
924
|
+
Similarly, dictionary keywords can, for most parts, be used with other
|
|
911
925
|
mappings. `Convert To Dictionary` can be used if real Python ``dict``
|
|
912
926
|
objects are needed.
|
|
913
927
|
|
|
928
|
+
= Ignore case =
|
|
929
|
+
|
|
930
|
+
Various keywords support ignoring case in comparisons by using the optional
|
|
931
|
+
``ignore_case`` argument. Case-insensitivity can be enabled by using
|
|
932
|
+
``ignore_case=True`` (see `Boolean arguments`) and it works recursively.
|
|
933
|
+
With dictionaries, it is also possible to use special values ``keys`` and
|
|
934
|
+
``values`` to normalize only keys or values, respectively. These options
|
|
935
|
+
themselves are case-insensitive and also singular forms ``key`` and
|
|
936
|
+
``value`` are supported.
|
|
937
|
+
|
|
938
|
+
If a dictionary contains keys that normalize to the same value, e.g.
|
|
939
|
+
``{'a': 1, 'A': 2}``, normalizing keys causes an error.
|
|
940
|
+
|
|
941
|
+
Examples:
|
|
942
|
+
| `Lists Should Be Equal` | ${list1} | ${list2} | ignore_case=True |
|
|
943
|
+
| `Dictionaries Should Be Equal` | ${dict1} | ${dict2} | ignore_case=values |
|
|
944
|
+
|
|
945
|
+
Notice that some keywords accept also an older ``case_insensitive`` argument
|
|
946
|
+
in addition to ``ignore_case``. The latter is new in Robot Framework 7.0 and
|
|
947
|
+
should be used unless there is a need to support older versions. The old
|
|
948
|
+
argument is considered deprecated and will eventually be removed.
|
|
949
|
+
|
|
914
950
|
= Boolean arguments =
|
|
915
951
|
|
|
916
952
|
Some keywords accept arguments that are handled as Boolean values true or
|
|
@@ -922,20 +958,9 @@ class Collections(_List, _Dictionary):
|
|
|
922
958
|
regardless their value, and other argument types are tested using the same
|
|
923
959
|
[http://docs.python.org/library/stdtypes.html#truth|rules as in Python].
|
|
924
960
|
|
|
925
|
-
True
|
|
926
|
-
| `Should Contain Match` | ${list} | ${pattern} |
|
|
927
|
-
| `Should
|
|
928
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=${TRUE} | # Python ``True`` is true. |
|
|
929
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=${42} | # Numbers other than 0 are true. |
|
|
930
|
-
|
|
931
|
-
False examples:
|
|
932
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=False | # String ``false`` is false. |
|
|
933
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=no | # Also string ``no`` is false. |
|
|
934
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=${EMPTY} | # Empty string is false. |
|
|
935
|
-
| `Should Contain Match` | ${list} | ${pattern} | case_insensitive=${FALSE} | # Python ``False`` is false. |
|
|
936
|
-
| `Lists Should Be Equal` | ${x} | ${y} | Custom error | values=no values | # ``no values`` works with ``values`` argument |
|
|
937
|
-
|
|
938
|
-
Considering ``OFF`` and ``0`` false is new in Robot Framework 3.1.
|
|
961
|
+
| `Should Contain Match` | ${list} | ${pattern} | ignore_case=True |
|
|
962
|
+
| `Should Contain Match` | ${list} | ${pattern} | ignore_case=False |
|
|
963
|
+
| `Lists Should Be Equal` | ${list1} | ${list2} | Custom error | no values |
|
|
939
964
|
|
|
940
965
|
= Data in examples =
|
|
941
966
|
|
|
@@ -947,12 +972,15 @@ class Collections(_List, _Dictionary):
|
|
|
947
972
|
Dictionary keywords use similar ``${Dx}`` variables. For example, ``${D1}``
|
|
948
973
|
means ``{'a': 1}`` and ``${D3}`` means ``{'a': 1, 'b': 2, 'c': 3}``.
|
|
949
974
|
"""
|
|
975
|
+
|
|
950
976
|
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
|
|
951
977
|
ROBOT_LIBRARY_VERSION = get_version()
|
|
952
978
|
|
|
953
979
|
def should_contain_match(self, list, pattern, msg=None,
|
|
954
|
-
case_insensitive=
|
|
955
|
-
whitespace_insensitive=
|
|
980
|
+
case_insensitive: 'bool|None' = None,
|
|
981
|
+
whitespace_insensitive: 'bool|None' = None,
|
|
982
|
+
ignore_case: bool = False,
|
|
983
|
+
ignore_whitespace: bool = False):
|
|
956
984
|
"""Fails if ``pattern`` is not found in ``list``.
|
|
957
985
|
|
|
958
986
|
By default, pattern matching is similar to matching files in a shell
|
|
@@ -964,72 +992,88 @@ class Collections(_List, _Dictionary):
|
|
|
964
992
|
If you prepend ``regexp=`` to your pattern, your pattern will be used
|
|
965
993
|
according to the Python
|
|
966
994
|
[http://docs.python.org/library/re.html|re module] regular expression
|
|
967
|
-
syntax.
|
|
968
|
-
|
|
969
|
-
|
|
995
|
+
syntax. Notice that the backslash character often used with regular
|
|
996
|
+
expressions is an escape character in Robot Framework data and needs
|
|
997
|
+
to be escaped with another backslash like ``regexp=\\\\d{6}``. See
|
|
998
|
+
`BuiltIn.Should Match Regexp` for more details.
|
|
970
999
|
|
|
971
|
-
|
|
972
|
-
the
|
|
1000
|
+
Matching is case-sensitive by default, but that can be changed by giving
|
|
1001
|
+
the ``ignore_case`` argument a true value (see `Boolean arguments`).
|
|
1002
|
+
This argument is new in Robot Framework 7.0, but with earlier versions
|
|
1003
|
+
it is possible to use ``case_insensitive`` for the same purpose.
|
|
973
1004
|
|
|
974
|
-
|
|
975
|
-
|
|
1005
|
+
It is possible to ignore all whitespace by giving the ``ignore_whitespace``
|
|
1006
|
+
argument a true value. This argument is new in Robot Framework 7.0 as well,
|
|
1007
|
+
and with earlier versions it is possible to use ``whitespace_insensitive``.
|
|
1008
|
+
|
|
1009
|
+
Notice that both ``case_insensitive`` and ``whitespace_insensitive``
|
|
1010
|
+
are considered deprecated. They will eventually be removed.
|
|
976
1011
|
|
|
977
1012
|
Non-string values in lists are ignored when matching patterns.
|
|
978
1013
|
|
|
979
1014
|
Use the ``msg`` argument to override the default error message.
|
|
980
1015
|
|
|
981
|
-
See also ``Should Not Contain Match``.
|
|
982
|
-
|
|
983
1016
|
Examples:
|
|
984
1017
|
| Should Contain Match | ${list} | a* | | | # Match strings beginning with 'a'. |
|
|
985
1018
|
| Should Contain Match | ${list} | regexp=a.* | | | # Same as the above but with regexp. |
|
|
986
1019
|
| Should Contain Match | ${list} | regexp=\\\\d{6} | | | # Match strings containing six digits. |
|
|
987
|
-
| Should Contain Match | ${list} | a* |
|
|
988
|
-
| Should Contain Match | ${list} | ab* |
|
|
989
|
-
| Should Contain Match | ${list} | ab* |
|
|
1020
|
+
| Should Contain Match | ${list} | a* | ignore_case=True | | # Match strings beginning with 'a' or 'A'. |
|
|
1021
|
+
| Should Contain Match | ${list} | ab* | ignore_whitespace=yes | | # Match strings beginning with 'ab' with possible whitespace ignored. |
|
|
1022
|
+
| Should Contain Match | ${list} | ab* | ignore_whitespace=true | ignore_case=true | # Same as the above but also ignore case. |
|
|
990
1023
|
"""
|
|
991
1024
|
_List._validate_list(self, list)
|
|
992
|
-
matches =
|
|
993
|
-
|
|
1025
|
+
matches = self._get_matches(list, pattern, case_insensitive,
|
|
1026
|
+
whitespace_insensitive, ignore_case,
|
|
1027
|
+
ignore_whitespace)
|
|
994
1028
|
default = f"{seq2str2(list)} does not contain match for pattern '{pattern}'."
|
|
995
1029
|
_verify_condition(matches, default, msg)
|
|
996
1030
|
|
|
997
1031
|
def should_not_contain_match(self, list, pattern, msg=None,
|
|
998
|
-
case_insensitive=
|
|
999
|
-
whitespace_insensitive=
|
|
1032
|
+
case_insensitive: 'bool|None' = None,
|
|
1033
|
+
whitespace_insensitive: 'bool|None' = None,
|
|
1034
|
+
ignore_case: bool = False,
|
|
1035
|
+
ignore_whitespace: bool = False):
|
|
1000
1036
|
"""Fails if ``pattern`` is found in ``list``.
|
|
1001
1037
|
|
|
1002
1038
|
Exact opposite of `Should Contain Match` keyword. See that keyword
|
|
1003
1039
|
for information about arguments and usage in general.
|
|
1004
1040
|
"""
|
|
1005
1041
|
_List._validate_list(self, list)
|
|
1006
|
-
matches =
|
|
1007
|
-
|
|
1042
|
+
matches = self._get_matches(list, pattern, case_insensitive,
|
|
1043
|
+
whitespace_insensitive, ignore_case,
|
|
1044
|
+
ignore_whitespace)
|
|
1008
1045
|
default = f"{seq2str2(list)} contains match for pattern '{pattern}'."
|
|
1009
1046
|
_verify_condition(not matches, default, msg)
|
|
1010
1047
|
|
|
1011
|
-
def get_matches(self, list, pattern,
|
|
1012
|
-
|
|
1048
|
+
def get_matches(self, list, pattern,
|
|
1049
|
+
case_insensitive: 'bool|None' = None,
|
|
1050
|
+
whitespace_insensitive: 'bool|None' = None,
|
|
1051
|
+
ignore_case: bool = False,
|
|
1052
|
+
ignore_whitespace: bool = False):
|
|
1013
1053
|
"""Returns a list of matches to ``pattern`` in ``list``.
|
|
1014
1054
|
|
|
1015
|
-
For more information on ``pattern``, ``case_insensitive``, and
|
|
1016
|
-
``whitespace_insensitive``, see `Should Contain Match`.
|
|
1055
|
+
For more information on ``pattern``, ``case_insensitive/ignore_case``, and
|
|
1056
|
+
``whitespace_insensitive/ignore_whitespace``, see `Should Contain Match`.
|
|
1017
1057
|
|
|
1018
1058
|
Examples:
|
|
1019
1059
|
| ${matches}= | Get Matches | ${list} | a* | # ${matches} will contain any string beginning with 'a' |
|
|
1020
1060
|
| ${matches}= | Get Matches | ${list} | regexp=a.* | # ${matches} will contain any string beginning with 'a' (regexp version) |
|
|
1021
|
-
| ${matches}= | Get Matches | ${list} | a* |
|
|
1061
|
+
| ${matches}= | Get Matches | ${list} | a* | ignore_case=True | # ${matches} will contain any string beginning with 'a' or 'A' |
|
|
1022
1062
|
"""
|
|
1023
1063
|
_List._validate_list(self, list)
|
|
1024
|
-
return
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1064
|
+
return self._get_matches(list, pattern, case_insensitive,
|
|
1065
|
+
whitespace_insensitive, ignore_case,
|
|
1066
|
+
ignore_whitespace)
|
|
1067
|
+
|
|
1068
|
+
def get_match_count(self, list, pattern,
|
|
1069
|
+
case_insensitive: 'bool|None' = None,
|
|
1070
|
+
whitespace_insensitive: 'bool|None' = None,
|
|
1071
|
+
ignore_case: bool = False,
|
|
1072
|
+
ignore_whitespace: bool = False):
|
|
1029
1073
|
"""Returns the count of matches to ``pattern`` in ``list``.
|
|
1030
1074
|
|
|
1031
|
-
For more information on ``pattern``, ``case_insensitive``, and
|
|
1032
|
-
``whitespace_insensitive``, see `Should Contain Match`.
|
|
1075
|
+
For more information on ``pattern``, ``case_insensitive/ignore_case``, and
|
|
1076
|
+
``whitespace_insensitive/ignore_whitespace``, see `Should Contain Match`.
|
|
1033
1077
|
|
|
1034
1078
|
Examples:
|
|
1035
1079
|
| ${count}= | Get Match Count | ${list} | a* | # ${count} will be the count of strings beginning with 'a' |
|
|
@@ -1038,31 +1082,131 @@ class Collections(_List, _Dictionary):
|
|
|
1038
1082
|
"""
|
|
1039
1083
|
_List._validate_list(self, list)
|
|
1040
1084
|
return len(self.get_matches(list, pattern, case_insensitive,
|
|
1041
|
-
whitespace_insensitive
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
def
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
pattern
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1085
|
+
whitespace_insensitive, ignore_case,
|
|
1086
|
+
ignore_whitespace))
|
|
1087
|
+
|
|
1088
|
+
def _get_matches(self, iterable, pattern, case_insensitive=None,
|
|
1089
|
+
whitespace_insensitive=None, ignore_case=True,
|
|
1090
|
+
ignore_whitespace=False):
|
|
1091
|
+
# `ignore_xxx` were added in RF 7.0 for consistency reasons.
|
|
1092
|
+
# The idea is that they eventually replace `xxx_insensitive`.
|
|
1093
|
+
# TODO: Emit deprecation warnings in RF 8.0.
|
|
1094
|
+
if case_insensitive is not None:
|
|
1095
|
+
ignore_case = case_insensitive
|
|
1096
|
+
if whitespace_insensitive is not None:
|
|
1097
|
+
ignore_whitespace = whitespace_insensitive
|
|
1098
|
+
if not isinstance(pattern, str):
|
|
1099
|
+
raise TypeError(f"Pattern must be string, got '{type_name(pattern)}'.")
|
|
1100
|
+
regexp = False
|
|
1101
|
+
if pattern.startswith('regexp='):
|
|
1102
|
+
pattern = pattern[7:]
|
|
1103
|
+
regexp = True
|
|
1104
|
+
elif pattern.startswith('glob='):
|
|
1105
|
+
pattern = pattern[5:]
|
|
1106
|
+
matcher = Matcher(pattern, caseless=ignore_case, spaceless=ignore_whitespace,
|
|
1107
|
+
regexp=regexp)
|
|
1108
|
+
return [item for item in iterable if isinstance(item, str) and matcher.match(item)]
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
def _verify_condition(condition, default_message, message, values=False):
|
|
1112
|
+
if not condition:
|
|
1113
|
+
_report_error(default_message, message, values)
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
def _report_error(default_message, message, values=False):
|
|
1117
|
+
if not message:
|
|
1118
|
+
message = default_message
|
|
1119
|
+
elif values and not (isinstance(values, str) and values.upper() == 'NO VALUES'):
|
|
1120
|
+
message += '\n' + default_message
|
|
1121
|
+
raise AssertionError(message)
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
class Normalizer:
|
|
1125
|
+
|
|
1126
|
+
def __init__(self, ignore_case=False, ignore_order=False, ignore_keys=None):
|
|
1127
|
+
print(ignore_case)
|
|
1128
|
+
self.ignore_case = ignore_case
|
|
1129
|
+
if isinstance(ignore_case, str):
|
|
1130
|
+
self.ignore_key_case = ignore_case.upper() not in ('VALUE', 'VALUES')
|
|
1131
|
+
self.ignore_value_case = ignore_case.upper() not in ('KEY', 'KEYS')
|
|
1132
|
+
else:
|
|
1133
|
+
self.ignore_key_case = self.ignore_value_case = self.ignore_case
|
|
1134
|
+
self.ignore_order = ignore_order
|
|
1135
|
+
self.ignore_keys = self._parse_ignored_keys(ignore_keys)
|
|
1136
|
+
|
|
1137
|
+
def _parse_ignored_keys(self, ignore_keys):
|
|
1138
|
+
if not ignore_keys:
|
|
1139
|
+
return set()
|
|
1140
|
+
try:
|
|
1141
|
+
if isinstance(ignore_keys, str):
|
|
1142
|
+
ignore_keys = literal_eval(ignore_keys)
|
|
1143
|
+
if not is_list_like(ignore_keys):
|
|
1144
|
+
raise ValueError
|
|
1145
|
+
except Exception:
|
|
1146
|
+
raise ValueError(f"'ignore_keys' value '{ignore_keys}' cannot be "
|
|
1147
|
+
f"converted to a list.")
|
|
1148
|
+
return {self.normalize_key(k) for k in ignore_keys}
|
|
1149
|
+
|
|
1150
|
+
def normalize(self, value):
|
|
1151
|
+
if not self:
|
|
1152
|
+
return value
|
|
1153
|
+
if isinstance(value, str):
|
|
1154
|
+
return self.normalize_string(value)
|
|
1155
|
+
if is_dict_like(value):
|
|
1156
|
+
return self.normalize_dict(value)
|
|
1157
|
+
if is_list_like(value):
|
|
1158
|
+
return self.normalize_list(value)
|
|
1159
|
+
return value
|
|
1160
|
+
|
|
1161
|
+
def normalize_string(self, value):
|
|
1162
|
+
return value.casefold() if self.ignore_case else value
|
|
1163
|
+
|
|
1164
|
+
def normalize_list(self, value):
|
|
1165
|
+
cls = type(value)
|
|
1166
|
+
if self.ignore_order:
|
|
1167
|
+
value = sorted(value)
|
|
1168
|
+
value = [self.normalize(v) for v in value]
|
|
1169
|
+
return self._try_to_preserve_type(value, cls)
|
|
1170
|
+
|
|
1171
|
+
def _try_to_preserve_type(self, value, cls):
|
|
1172
|
+
# Try to preserve original type. Most importantly, preserve tuples to
|
|
1173
|
+
# allow using them as dictionary keys.
|
|
1174
|
+
try:
|
|
1175
|
+
return cls(value)
|
|
1176
|
+
except TypeError:
|
|
1177
|
+
return value
|
|
1178
|
+
|
|
1179
|
+
def normalize_dict(self, value):
|
|
1180
|
+
cls = type(value)
|
|
1181
|
+
result = {}
|
|
1182
|
+
for key in value:
|
|
1183
|
+
normalized = self.normalize_key(key)
|
|
1184
|
+
if normalized in self.ignore_keys:
|
|
1185
|
+
continue
|
|
1186
|
+
if normalized in result:
|
|
1187
|
+
raise AssertionError(
|
|
1188
|
+
f"Dictionary {value} contains multiple keys that are normalized "
|
|
1189
|
+
f"to '{normalized}'. Try normalizing only dictionary values like "
|
|
1190
|
+
f"'ignore_case=values'."
|
|
1191
|
+
)
|
|
1192
|
+
result[normalized] = self.normalize_value(value[key])
|
|
1193
|
+
return self._try_to_preserve_type(result, cls)
|
|
1194
|
+
|
|
1195
|
+
def normalize_key(self, key):
|
|
1196
|
+
ignore_case, self.ignore_case = self.ignore_case, self.ignore_key_case
|
|
1197
|
+
try:
|
|
1198
|
+
return self.normalize(key)
|
|
1199
|
+
finally:
|
|
1200
|
+
self.ignore_case = ignore_case
|
|
1201
|
+
|
|
1202
|
+
def normalize_value(self, value):
|
|
1203
|
+
ignore_case, self.ignore_case = self.ignore_case, self.ignore_value_case
|
|
1204
|
+
try:
|
|
1205
|
+
return self.normalize(value)
|
|
1206
|
+
finally:
|
|
1207
|
+
self.ignore_case = ignore_case
|
|
1208
|
+
|
|
1209
|
+
def __bool__(self):
|
|
1210
|
+
return bool(self.ignore_case
|
|
1211
|
+
or self.ignore_order
|
|
1212
|
+
or getattr(self, 'ignore_keys', False))
|