robotframework 6.1rc1__zip → 7.0__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotframework-6.1rc1 → robotframework-7.0}/INSTALL.rst +25 -25
- {robotframework-6.1rc1 → robotframework-7.0}/PKG-INFO +6 -8
- {robotframework-6.1rc1 → robotframework-7.0}/README.rst +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/setup.py +3 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/__init__.py +4 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/deco.py +60 -14
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/exceptions.py +6 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/interfaces.py +403 -68
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/logger.py +27 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/api/parsing.py +4 -2
- robotframework-7.0/src/robot/api/py.typed +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/gatherfailed.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/languages.py +61 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/settings.py +21 -14
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/storage.js +11 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/htmlfilewriter.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.css +10 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/libdoc.html +10 -0
- robotframework-7.0/src/robot/htmldata/rebot/common.css +362 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/doc_formatting.css +13 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.css +51 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.html +14 -23
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/model.js +2 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.css +83 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/report.html +22 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/testdata.js +10 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/view.js +84 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/template.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/builder.py +0 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/datatypes.py +9 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlutils.py +4 -7
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonbuilder.py +38 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/model.py +21 -28
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/robotbuilder.py +50 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/standardtypes.py +9 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlbuilder.py +35 -20
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/xmlwriter.py +18 -38
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/BuiltIn.py +255 -205
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Collections.py +384 -240
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/DateTime.py +73 -60
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/OperatingSystem.py +6 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Process.py +26 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Remote.py +40 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/String.py +66 -76
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/XML.py +66 -59
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/dialogs_py.py +14 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/__init__.py +5 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/body.py +44 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/configurer.py +19 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/control.py +230 -88
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/filter.py +31 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/itemlist.py +9 -8
- robotframework-7.0/src/robot/model/keyword.py +77 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/message.py +19 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modelobject.py +27 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/modifier.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/namepatterns.py +3 -25
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/stats.py +9 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tags.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testcase.py +15 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/testsuite.py +44 -28
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/visitor.py +35 -8
- robotframework-7.0/src/robot/output/console/dotted.py +90 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/quiet.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/verbose.py +61 -61
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/debugfile.py +39 -24
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/filelogger.py +18 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/librarylogger.py +3 -2
- robotframework-7.0/src/robot/output/listeners.py +753 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/logger.py +216 -80
- robotframework-7.0/src/robot/output/loggerapi.py +215 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/loggerhelper.py +23 -56
- robotframework-7.0/src/robot/output/output.py +185 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/stdoutlogsplitter.py +8 -5
- robotframework-7.0/src/robot/output/xmllogger.py +459 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/blocklexers.py +17 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/context.py +12 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/lexer.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/settings.py +6 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/statementlexers.py +39 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokens.py +27 -29
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/blocks.py +19 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/statements.py +193 -94
- robotframework-7.0/src/robot/parsing/model/visitor.py +100 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/rebot.py +2 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/expandkeywordmatcher.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsbuildingcontext.py +8 -6
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsmodelbuilders.py +88 -61
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/logreportwriters.py +16 -10
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/outputwriter.py +18 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/resultwriter.py +4 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/stringcache.py +3 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/xunitwriter.py +15 -21
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/__init__.py +3 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/configurer.py +12 -9
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionresult.py +56 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/flattenkeywordmatcher.py +48 -9
- robotframework-7.0/src/robot/result/keywordremover.py +207 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/merger.py +1 -1
- robotframework-7.0/src/robot/result/model.py +1185 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/modeldeprecation.py +9 -3
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/resultbuilder.py +46 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/xmlelementhandlers.py +83 -43
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/run.py +3 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/__init__.py +14 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/__init__.py +2 -1
- robotframework-7.0/src/robot/running/arguments/argumentconverter.py +100 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentmapper.py +26 -24
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentparser.py +85 -61
- robotframework-7.0/src/robot/running/arguments/argumentresolver.py +158 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentspec.py +83 -116
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/argumentvalidator.py +33 -27
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/customconverters.py +15 -12
- robotframework-7.0/src/robot/running/arguments/embedded.py +145 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/arguments/typeconverters.py +268 -220
- robotframework-7.0/src/robot/running/arguments/typeinfo.py +317 -0
- robotframework-7.0/src/robot/running/arguments/typeinfoparser.py +219 -0
- robotframework-7.0/src/robot/running/arguments/typevalidator.py +60 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/bodyrunner.py +147 -129
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/builders.py +17 -26
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/parsers.py +17 -11
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/settings.py +9 -17
- robotframework-7.0/src/robot/running/builder/transformers.py +535 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/context.py +113 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/dynamicmethods.py +62 -34
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/importer.py +27 -49
- robotframework-7.0/src/robot/running/invalidkeyword.py +67 -0
- robotframework-7.0/src/robot/running/keywordfinder.py +91 -0
- robotframework-7.0/src/robot/running/keywordimplementation.py +164 -0
- robotframework-7.0/src/robot/running/librarykeyword.py +392 -0
- robotframework-7.0/src/robot/running/librarykeywordrunner.py +250 -0
- robotframework-7.0/src/robot/running/libraryscopes.py +115 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/model.py +198 -337
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/namespace.py +124 -137
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/outputcapture.py +20 -12
- robotframework-7.0/src/robot/running/resourcemodel.py +448 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/statusreporter.py +16 -13
- robotframework-7.0/src/robot/running/suiterunner.py +265 -0
- robotframework-7.0/src/robot/running/testlibraries.py +500 -0
- robotframework-7.0/src/robot/running/userkeywordrunner.py +260 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/testdoc.py +18 -13
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/__init__.py +53 -35
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/connectioncache.py +64 -59
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/dotdict.py +3 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encodingsniffer.py +9 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/escaping.py +19 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/importer.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markupwriters.py +23 -15
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/misc.py +1 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/normalizing.py +9 -24
- robotframework-7.0/src/robot/utils/notset.py +33 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/platform.py +15 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotio.py +9 -9
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotpath.py +1 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottime.py +122 -90
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robottypes.py +21 -31
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/setter.py +0 -5
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/text.py +7 -4
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/unic.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/__init__.py +2 -2
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/assigner.py +17 -19
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/evaluation.py +20 -17
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/filesetter.py +80 -80
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/replacer.py +33 -36
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/scopes.py +17 -12
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/search.py +66 -41
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/store.py +14 -16
- robotframework-7.0/src/robot/variables/tablesetter.py +164 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/variables.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/version.py +1 -1
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/PKG-INFO +6 -8
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/SOURCES.txt +10 -8
- {robotframework-6.1rc1 → robotframework-7.0}/tasks.py +6 -6
- robotframework-6.1rc1/src/robot/htmldata/rebot/common.css +0 -239
- robotframework-6.1rc1/src/robot/libraries/Reserved.py +0 -48
- robotframework-6.1rc1/src/robot/model/keyword.py +0 -173
- robotframework-6.1rc1/src/robot/output/console/dotted.py +0 -90
- robotframework-6.1rc1/src/robot/output/listenerarguments.py +0 -165
- robotframework-6.1rc1/src/robot/output/listenermethods.py +0 -113
- robotframework-6.1rc1/src/robot/output/listeners.py +0 -174
- robotframework-6.1rc1/src/robot/output/output.py +0 -95
- robotframework-6.1rc1/src/robot/output/xmllogger.py +0 -354
- robotframework-6.1rc1/src/robot/parsing/model/visitor.py +0 -67
- robotframework-6.1rc1/src/robot/result/keywordremover.py +0 -183
- robotframework-6.1rc1/src/robot/result/model.py +0 -957
- robotframework-6.1rc1/src/robot/running/arguments/argumentconverter.py +0 -79
- robotframework-6.1rc1/src/robot/running/arguments/argumentresolver.py +0 -131
- robotframework-6.1rc1/src/robot/running/arguments/embedded.py +0 -146
- robotframework-6.1rc1/src/robot/running/arguments/typevalidator.py +0 -56
- robotframework-6.1rc1/src/robot/running/builder/transformers.py +0 -642
- robotframework-6.1rc1/src/robot/running/handlers.py +0 -321
- robotframework-6.1rc1/src/robot/running/handlerstore.py +0 -66
- robotframework-6.1rc1/src/robot/running/librarykeywordrunner.py +0 -238
- robotframework-6.1rc1/src/robot/running/libraryscopes.py +0 -97
- robotframework-6.1rc1/src/robot/running/modelcombiner.py +0 -32
- robotframework-6.1rc1/src/robot/running/suiterunner.py +0 -249
- robotframework-6.1rc1/src/robot/running/testlibraries.py +0 -420
- robotframework-6.1rc1/src/robot/running/usererrorhandler.py +0 -75
- robotframework-6.1rc1/src/robot/running/userkeyword.py +0 -111
- robotframework-6.1rc1/src/robot/running/userkeywordrunner.py +0 -274
- robotframework-6.1rc1/src/robot/variables/tablesetter.py +0 -156
- {robotframework-6.1rc1 → robotframework-7.0}/AUTHORS.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/BUILD.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/CONTRIBUTING.rst +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/COPYRIGHT.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/LICENSE.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/MANIFEST.in +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/setup.cfg +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/__main__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/conf/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/errors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/common/js_disabled.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.highlight.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tablesorter.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jquery.tmpl.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/lib/jsxcompressor.min.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/doc_formatting.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/libdoc/pygments.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/fileloading.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/log.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/print.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/rebot/util.js +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.css +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/htmldata/testdoc/testdoc.html +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdoc.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/consoleviewer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/htmlwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/jsonwriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/output.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libdocpkg/writer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Dialogs.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Easter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Screenshot.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/libraries/Telnet.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/fixture.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/metadata.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/statistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/suitestatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/tagstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/model/totalstatistics.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/console/highlighting.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/output/pyloggingconf.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/lexer/tokenizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/model/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/blockparsers.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/fileparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/parser/parser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/parsing/suitestructure.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/pythonpathsetter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jsexecutionresult.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/reporting/jswriter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/executionerrors.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/messagefilter.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/suiteteardownfailed.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/result/visitor.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/builder/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/randomizer.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/runkwregister.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/signalhandler.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/status.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/__init__.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/posix.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/running/timeouts/windows.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/application.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/argumentparser.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/asserts.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/charwidth.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/compress.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/encoding.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/error.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/etreewrapper.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/filereader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/frange.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/htmlformatters.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/markuputils.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/match.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/recommendations.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/restreader.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotenv.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/robotinspect.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/sortable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/utils/typehints.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/finders.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/notfound.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robot/variables/resolvable.py +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/dependency_links.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/entry_points.txt +0 -0
- {robotframework-6.1rc1 → robotframework-7.0}/src/robotframework.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# Copyright 2008-2015 Nokia Networks
|
|
2
|
+
# Copyright 2016- Robot Framework Foundation
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import inspect
|
|
17
|
+
from functools import cached_property, partial
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any, Literal, overload, Sequence, TypeVar
|
|
20
|
+
from types import ModuleType
|
|
21
|
+
|
|
22
|
+
from robot.errors import DataError
|
|
23
|
+
from robot.libraries import STDLIBS
|
|
24
|
+
from robot.output import LOGGER
|
|
25
|
+
from robot.utils import (getdoc, get_error_details, Importer, is_dict_like,
|
|
26
|
+
is_list_like, normalize, NormalizedDict, seq2str2, setter, type_name)
|
|
27
|
+
|
|
28
|
+
from .arguments import CustomArgumentConverters
|
|
29
|
+
from .dynamicmethods import GetKeywordDocumentation, GetKeywordNames, RunKeyword
|
|
30
|
+
from .keywordfinder import KeywordFinder
|
|
31
|
+
from .librarykeyword import DynamicKeyword, LibraryInit, LibraryKeyword, StaticKeyword
|
|
32
|
+
from .libraryscopes import Scope, ScopeManager
|
|
33
|
+
from .outputcapture import OutputCapturer
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Self = TypeVar('Self', bound='TestLibrary')
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestLibrary:
|
|
40
|
+
"""Represents imported test library."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, code: 'type|ModuleType',
|
|
43
|
+
init: LibraryInit,
|
|
44
|
+
name: 'str|None' = None,
|
|
45
|
+
real_name: 'str|None' = None,
|
|
46
|
+
source: 'Path|None' = None,
|
|
47
|
+
logger=LOGGER):
|
|
48
|
+
self.code = code
|
|
49
|
+
self.init = init
|
|
50
|
+
self.init.owner = self
|
|
51
|
+
self.instance = None
|
|
52
|
+
self.name = name or code.__name__
|
|
53
|
+
self.real_name = real_name or self.name
|
|
54
|
+
self.source = source
|
|
55
|
+
self._logger = logger
|
|
56
|
+
self.keywords: list[LibraryKeyword] = []
|
|
57
|
+
self._has_listeners = None
|
|
58
|
+
self.scope_manager = ScopeManager.for_library(self)
|
|
59
|
+
self.keyword_finder = KeywordFinder[LibraryKeyword](self)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def instance(self) -> Any:
|
|
63
|
+
"""Current library instance.
|
|
64
|
+
|
|
65
|
+
With module based libraries this is the module itself.
|
|
66
|
+
|
|
67
|
+
With class based libraries this is an instance of the class. Instances are
|
|
68
|
+
cleared automatically during execution based on their scope. Accessing this
|
|
69
|
+
property creates a new instance if needed.
|
|
70
|
+
|
|
71
|
+
:attr:`code´ contains the original library code. With module based libraries
|
|
72
|
+
it is the same as :attr:`instance`. With class based libraries it is
|
|
73
|
+
the library class.
|
|
74
|
+
"""
|
|
75
|
+
instance = self.code if self._instance is None else self._instance
|
|
76
|
+
if self._has_listeners is None:
|
|
77
|
+
self._has_listeners = self._instance_has_listeners(instance)
|
|
78
|
+
return instance
|
|
79
|
+
|
|
80
|
+
@instance.setter
|
|
81
|
+
def instance(self, instance: Any):
|
|
82
|
+
self._instance = instance
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def listeners(self) -> 'list[Any]':
|
|
86
|
+
if self._has_listeners is None:
|
|
87
|
+
self._has_listeners = self._instance_has_listeners(self.instance)
|
|
88
|
+
if self._has_listeners is False:
|
|
89
|
+
return []
|
|
90
|
+
listener = self.instance.ROBOT_LIBRARY_LISTENER
|
|
91
|
+
return list(listener) if is_list_like(listener) else [listener]
|
|
92
|
+
|
|
93
|
+
def _instance_has_listeners(self, instance) -> bool:
|
|
94
|
+
return getattr(instance, 'ROBOT_LIBRARY_LISTENER', None) is not None
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def converters(self) -> 'CustomArgumentConverters|None':
|
|
98
|
+
converters = getattr(self.code, 'ROBOT_LIBRARY_CONVERTERS', None)
|
|
99
|
+
if not converters:
|
|
100
|
+
return None
|
|
101
|
+
if not is_dict_like(converters):
|
|
102
|
+
self.report_error(f'Argument converters must be given as a dictionary, '
|
|
103
|
+
f'got {type_name(converters)}.')
|
|
104
|
+
return None
|
|
105
|
+
return CustomArgumentConverters.from_dict(converters, self)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def doc(self) -> str:
|
|
109
|
+
return getdoc(self.instance)
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def doc_format(self) -> str:
|
|
113
|
+
return self._attr('ROBOT_LIBRARY_DOC_FORMAT', upper=True)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def scope(self) -> Scope:
|
|
117
|
+
scope = self._attr('ROBOT_LIBRARY_SCOPE', 'TEST', upper=True)
|
|
118
|
+
if scope == 'GLOBAL':
|
|
119
|
+
return Scope.GLOBAL
|
|
120
|
+
if scope in ('SUITE', 'TESTSUITE'):
|
|
121
|
+
return Scope.SUITE
|
|
122
|
+
return Scope.TEST
|
|
123
|
+
|
|
124
|
+
@setter
|
|
125
|
+
def source(self, source: 'Path|str|None') -> 'Path|None':
|
|
126
|
+
return Path(source) if source else None
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def version(self) -> str:
|
|
130
|
+
return self._attr('ROBOT_LIBRARY_VERSION') or self._attr('__version__')
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def lineno(self) -> int:
|
|
134
|
+
return 1
|
|
135
|
+
|
|
136
|
+
def _attr(self, name, default='', upper=False) -> str:
|
|
137
|
+
value = str(getattr(self.code, name, default))
|
|
138
|
+
if upper:
|
|
139
|
+
value = normalize(value, ignore='_').upper()
|
|
140
|
+
return value
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def from_name(cls, name: str,
|
|
144
|
+
real_name: 'str|None' = None,
|
|
145
|
+
args: 'Sequence[str]|None' = None,
|
|
146
|
+
variables=None,
|
|
147
|
+
create_keywords: bool = True,
|
|
148
|
+
logger=LOGGER) -> 'TestLibrary':
|
|
149
|
+
if name in STDLIBS:
|
|
150
|
+
import_name = 'robot.libraries.' + name
|
|
151
|
+
else:
|
|
152
|
+
import_name = name
|
|
153
|
+
if Path(name).exists():
|
|
154
|
+
name = Path(name).stem
|
|
155
|
+
with OutputCapturer(library_import=True):
|
|
156
|
+
importer = Importer('library', logger=logger)
|
|
157
|
+
code, source = importer.import_class_or_module(import_name,
|
|
158
|
+
return_source=True)
|
|
159
|
+
return cls.from_code(code, name, real_name, source, args, variables,
|
|
160
|
+
create_keywords, logger)
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def from_code(cls, code: 'type|ModuleType',
|
|
164
|
+
name: 'str|None' = None,
|
|
165
|
+
real_name: 'str|None' = None,
|
|
166
|
+
source: 'Path|None' = None,
|
|
167
|
+
args: 'Sequence[str]|None' = None,
|
|
168
|
+
variables=None,
|
|
169
|
+
create_keywords: bool = True,
|
|
170
|
+
logger=LOGGER) -> 'TestLibrary':
|
|
171
|
+
if inspect.ismodule(code):
|
|
172
|
+
lib = cls.from_module(code, name, real_name, source, create_keywords, logger)
|
|
173
|
+
if args: # Resolving arguments reports an error.
|
|
174
|
+
lib.init.resolve_arguments(args, variables)
|
|
175
|
+
return lib
|
|
176
|
+
return cls.from_class(code, name, real_name, source, args or (), variables,
|
|
177
|
+
create_keywords, logger)
|
|
178
|
+
|
|
179
|
+
@classmethod
|
|
180
|
+
def from_module(cls, module: ModuleType,
|
|
181
|
+
name: 'str|None' = None,
|
|
182
|
+
real_name: 'str|None' = None,
|
|
183
|
+
source: 'Path|None' = None,
|
|
184
|
+
create_keywords: bool = True,
|
|
185
|
+
logger=LOGGER) -> 'TestLibrary':
|
|
186
|
+
return ModuleLibrary.from_module(module, name, real_name, source,
|
|
187
|
+
create_keywords, logger)
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def from_class(cls, klass: type,
|
|
191
|
+
name: 'str|None' = None,
|
|
192
|
+
real_name: 'str|None' = None,
|
|
193
|
+
source: 'Path|None' = None,
|
|
194
|
+
args: Sequence[str] = (),
|
|
195
|
+
variables=None,
|
|
196
|
+
create_keywords: bool = True,
|
|
197
|
+
logger=LOGGER) -> 'TestLibrary':
|
|
198
|
+
if not GetKeywordNames(klass):
|
|
199
|
+
library = ClassLibrary
|
|
200
|
+
elif not RunKeyword(klass):
|
|
201
|
+
library = HybridLibrary
|
|
202
|
+
else:
|
|
203
|
+
library = DynamicLibrary
|
|
204
|
+
return library.from_class(klass, name, real_name, source, args, variables,
|
|
205
|
+
create_keywords, logger)
|
|
206
|
+
|
|
207
|
+
def create_keywords(self):
|
|
208
|
+
raise NotImplementedError
|
|
209
|
+
|
|
210
|
+
@overload
|
|
211
|
+
def find_keywords(self, name: str, count: Literal[1]) -> 'LibraryKeyword':
|
|
212
|
+
...
|
|
213
|
+
|
|
214
|
+
@overload
|
|
215
|
+
def find_keywords(self, name: str, count: 'int|None' = None) \
|
|
216
|
+
-> 'list[LibraryKeyword]':
|
|
217
|
+
...
|
|
218
|
+
|
|
219
|
+
def find_keywords(self, name: str, count: 'int|None' = None) \
|
|
220
|
+
-> 'list[LibraryKeyword]|LibraryKeyword':
|
|
221
|
+
return self.keyword_finder.find(name, count)
|
|
222
|
+
|
|
223
|
+
def copy(self: Self, name: str) -> Self:
|
|
224
|
+
lib = type(self)(self.code, self.init.copy(), name, self.real_name,
|
|
225
|
+
self.source, self._logger)
|
|
226
|
+
lib.instance = self.instance
|
|
227
|
+
lib.keywords = [kw.copy(owner=lib) for kw in self.keywords]
|
|
228
|
+
return lib
|
|
229
|
+
|
|
230
|
+
def report_error(self, message: str,
|
|
231
|
+
details: 'str|None' = None,
|
|
232
|
+
level: str = 'ERROR',
|
|
233
|
+
details_level: str = 'INFO'):
|
|
234
|
+
prefix = 'Error in' if level in ('ERROR', 'WARN') else 'In'
|
|
235
|
+
self._logger.write(f"{prefix} library '{self.name}': {message}", level)
|
|
236
|
+
if details:
|
|
237
|
+
self._logger.write(f'Details:\n{details}', details_level)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class ModuleLibrary(TestLibrary):
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def scope(self) -> Scope:
|
|
244
|
+
return Scope.GLOBAL
|
|
245
|
+
|
|
246
|
+
@classmethod
|
|
247
|
+
def from_module(cls, module: ModuleType,
|
|
248
|
+
name: 'str|None' = None,
|
|
249
|
+
real_name: 'str|None' = None,
|
|
250
|
+
source: 'Path|None' = None,
|
|
251
|
+
create_keywords: bool = True,
|
|
252
|
+
logger=LOGGER) -> 'ModuleLibrary':
|
|
253
|
+
library = cls(module, LibraryInit.null(), name, real_name, source, logger)
|
|
254
|
+
if create_keywords:
|
|
255
|
+
library.create_keywords()
|
|
256
|
+
return library
|
|
257
|
+
|
|
258
|
+
@classmethod
|
|
259
|
+
def from_class(cls, *args, **kws) -> 'TestLibrary':
|
|
260
|
+
raise TypeError(f"Cannot create '{cls.__name__}' from class.")
|
|
261
|
+
|
|
262
|
+
def create_keywords(self):
|
|
263
|
+
excludes = getattr(self.code, '__all__', None)
|
|
264
|
+
StaticKeywordCreator(self, excluded_names=excludes).create_keywords()
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class ClassLibrary(TestLibrary):
|
|
268
|
+
|
|
269
|
+
@property
|
|
270
|
+
def instance(self) -> Any:
|
|
271
|
+
if self._instance is None:
|
|
272
|
+
positional, named = self.init.positional, self.init.named
|
|
273
|
+
try:
|
|
274
|
+
with OutputCapturer(library_import=True):
|
|
275
|
+
self._instance = self.code(*positional, **named)
|
|
276
|
+
except Exception:
|
|
277
|
+
message, details = get_error_details()
|
|
278
|
+
if positional or named:
|
|
279
|
+
args = seq2str2(positional + [f'{n}={named[n]}' for n in named])
|
|
280
|
+
args_text = f'arguments {args}'
|
|
281
|
+
else:
|
|
282
|
+
args_text = 'no arguments'
|
|
283
|
+
raise DataError(f"Initializing library '{self.name}' with {args_text} "
|
|
284
|
+
f"failed: {message}\n{details}")
|
|
285
|
+
if self._has_listeners is None:
|
|
286
|
+
self._has_listeners = self._instance_has_listeners(self._instance)
|
|
287
|
+
return self._instance
|
|
288
|
+
|
|
289
|
+
@instance.setter
|
|
290
|
+
def instance(self, instance):
|
|
291
|
+
self._instance = instance
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def lineno(self) -> int:
|
|
295
|
+
try:
|
|
296
|
+
lines, start_lineno = inspect.getsourcelines(self.code)
|
|
297
|
+
except (TypeError, OSError, IOError):
|
|
298
|
+
return 1
|
|
299
|
+
for increment, line in enumerate(lines):
|
|
300
|
+
if line.strip().startswith('class '):
|
|
301
|
+
return start_lineno + increment
|
|
302
|
+
return start_lineno
|
|
303
|
+
|
|
304
|
+
@classmethod
|
|
305
|
+
def from_module(cls, *args, **kws) -> 'TestLibrary':
|
|
306
|
+
raise TypeError(f"Cannot create '{cls.__name__}' from module.")
|
|
307
|
+
|
|
308
|
+
@classmethod
|
|
309
|
+
def from_class(cls, klass: type,
|
|
310
|
+
name: 'str|None' = None,
|
|
311
|
+
real_name: 'str|None' = None,
|
|
312
|
+
source: 'Path|None' = None,
|
|
313
|
+
args: Sequence[str] = (),
|
|
314
|
+
variables=None,
|
|
315
|
+
create_keywords: bool = True,
|
|
316
|
+
logger=LOGGER) -> 'ClassLibrary':
|
|
317
|
+
init = LibraryInit.from_class(klass)
|
|
318
|
+
library = cls(klass, init, name, real_name, source, logger)
|
|
319
|
+
positional, named = init.args.resolve(args, variables)
|
|
320
|
+
init.positional, init.named = list(positional), dict(named)
|
|
321
|
+
if create_keywords:
|
|
322
|
+
library.create_keywords()
|
|
323
|
+
return library
|
|
324
|
+
|
|
325
|
+
def create_keywords(self):
|
|
326
|
+
StaticKeywordCreator(self, avoid_properties=True).create_keywords()
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class HybridLibrary(ClassLibrary):
|
|
330
|
+
|
|
331
|
+
def create_keywords(self):
|
|
332
|
+
names = DynamicKeywordCreator(self).get_keyword_names()
|
|
333
|
+
creator = StaticKeywordCreator(self, getting_method_failed_level='ERROR')
|
|
334
|
+
creator.create_keywords(names)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class DynamicLibrary(ClassLibrary):
|
|
338
|
+
_supports_named_args = None
|
|
339
|
+
|
|
340
|
+
@property
|
|
341
|
+
def supports_named_args(self) -> bool:
|
|
342
|
+
if self._supports_named_args is None:
|
|
343
|
+
self._supports_named_args = RunKeyword(self.instance).supports_named_args
|
|
344
|
+
return self._supports_named_args
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def doc(self) -> str:
|
|
348
|
+
return GetKeywordDocumentation(self.instance)('__intro__') or super().doc
|
|
349
|
+
|
|
350
|
+
def create_keywords(self):
|
|
351
|
+
DynamicKeywordCreator(self).create_keywords()
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class KeywordCreator:
|
|
355
|
+
|
|
356
|
+
def __init__(self, library: TestLibrary, getting_method_failed_level='INFO'):
|
|
357
|
+
self.library = library
|
|
358
|
+
self.getting_method_failed_level = getting_method_failed_level
|
|
359
|
+
|
|
360
|
+
def get_keyword_names(self) -> 'list[str]':
|
|
361
|
+
raise NotImplementedError
|
|
362
|
+
|
|
363
|
+
def create_keywords(self, names: 'list[str]|None' = None):
|
|
364
|
+
library = self.library
|
|
365
|
+
library.keyword_finder.invalidate_cache()
|
|
366
|
+
instance = library.instance
|
|
367
|
+
keywords = library.keywords = []
|
|
368
|
+
if names is None:
|
|
369
|
+
names = self.get_keyword_names()
|
|
370
|
+
seen = NormalizedDict(ignore='_')
|
|
371
|
+
for name in names:
|
|
372
|
+
try:
|
|
373
|
+
kw = self._create_keyword(instance, name)
|
|
374
|
+
except DataError as err:
|
|
375
|
+
self._adding_keyword_failed(name, err, self.getting_method_failed_level)
|
|
376
|
+
else:
|
|
377
|
+
if not kw:
|
|
378
|
+
continue
|
|
379
|
+
try:
|
|
380
|
+
if kw.embedded:
|
|
381
|
+
self._validate_embedded(kw)
|
|
382
|
+
else:
|
|
383
|
+
self._handle_duplicates(kw, seen)
|
|
384
|
+
except DataError as err:
|
|
385
|
+
self._adding_keyword_failed(kw.name, err)
|
|
386
|
+
else:
|
|
387
|
+
keywords.append(kw)
|
|
388
|
+
library._logger.debug(f"Created keyword '{kw.name}'.")
|
|
389
|
+
|
|
390
|
+
def _create_keyword(self, instance, name) -> 'LibraryKeyword|None':
|
|
391
|
+
raise NotImplementedError
|
|
392
|
+
|
|
393
|
+
def _handle_duplicates(self, kw, seen: NormalizedDict):
|
|
394
|
+
if kw.name in seen:
|
|
395
|
+
error = 'Keyword with same name defined multiple times.'
|
|
396
|
+
seen[kw.name].error = error
|
|
397
|
+
raise DataError(error)
|
|
398
|
+
seen[kw.name] = kw
|
|
399
|
+
|
|
400
|
+
def _validate_embedded(self, kw):
|
|
401
|
+
if len(kw.embedded.args) > kw.args.maxargs:
|
|
402
|
+
raise DataError(f'Keyword must accept at least as many positional '
|
|
403
|
+
f'arguments as it has embedded arguments.')
|
|
404
|
+
kw.args.embedded = kw.embedded.args
|
|
405
|
+
|
|
406
|
+
def _adding_keyword_failed(self, name, error, level='ERROR'):
|
|
407
|
+
self.library.report_error(
|
|
408
|
+
f"Adding keyword '{name}' failed: {error}",
|
|
409
|
+
error.details,
|
|
410
|
+
level=level,
|
|
411
|
+
details_level='DEBUG'
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class StaticKeywordCreator(KeywordCreator):
|
|
416
|
+
|
|
417
|
+
def __init__(self, library: TestLibrary, getting_method_failed_level='INFO',
|
|
418
|
+
excluded_names=None, avoid_properties=False):
|
|
419
|
+
super().__init__(library, getting_method_failed_level)
|
|
420
|
+
self.excluded_names = excluded_names
|
|
421
|
+
self.avoid_properties = avoid_properties
|
|
422
|
+
|
|
423
|
+
def get_keyword_names(self) -> 'list[str]':
|
|
424
|
+
instance = self.library.instance
|
|
425
|
+
try:
|
|
426
|
+
return self._get_names(instance)
|
|
427
|
+
except Exception:
|
|
428
|
+
message, details = get_error_details()
|
|
429
|
+
raise DataError(f"Getting keyword names from library '{self.library.name}' "
|
|
430
|
+
f"failed: {message}", details)
|
|
431
|
+
|
|
432
|
+
def _get_names(self, instance) -> 'list[str]':
|
|
433
|
+
def explicitly_included(name):
|
|
434
|
+
candidate = inspect.getattr_static(instance, name)
|
|
435
|
+
if isinstance(candidate, (classmethod, staticmethod)):
|
|
436
|
+
candidate = candidate.__func__
|
|
437
|
+
try:
|
|
438
|
+
return hasattr(candidate, 'robot_name')
|
|
439
|
+
except Exception:
|
|
440
|
+
return False
|
|
441
|
+
|
|
442
|
+
names = []
|
|
443
|
+
auto_keywords = getattr(instance, 'ROBOT_AUTO_KEYWORDS', True)
|
|
444
|
+
excluded_names = self.excluded_names
|
|
445
|
+
for name in dir(instance):
|
|
446
|
+
if not auto_keywords:
|
|
447
|
+
if not explicitly_included(name):
|
|
448
|
+
continue
|
|
449
|
+
elif name[:1] == '_':
|
|
450
|
+
if not explicitly_included(name):
|
|
451
|
+
continue
|
|
452
|
+
elif excluded_names is not None:
|
|
453
|
+
if name not in excluded_names:
|
|
454
|
+
continue
|
|
455
|
+
names.append(name)
|
|
456
|
+
return names
|
|
457
|
+
|
|
458
|
+
def _create_keyword(self, instance, name) -> 'StaticKeyword|None':
|
|
459
|
+
if self.avoid_properties:
|
|
460
|
+
candidate = inspect.getattr_static(instance, name)
|
|
461
|
+
self._pre_validate_method(candidate)
|
|
462
|
+
try:
|
|
463
|
+
method = getattr(instance, name)
|
|
464
|
+
except Exception:
|
|
465
|
+
message, details = get_error_details()
|
|
466
|
+
raise DataError(f'Getting handler method failed: {message}', details)
|
|
467
|
+
self._validate_method(method)
|
|
468
|
+
try:
|
|
469
|
+
return StaticKeyword.from_name(name, self.library)
|
|
470
|
+
except DataError as err:
|
|
471
|
+
self._adding_keyword_failed(name, err)
|
|
472
|
+
|
|
473
|
+
def _pre_validate_method(self, candidate):
|
|
474
|
+
if isinstance(candidate, classmethod):
|
|
475
|
+
candidate = candidate.__func__
|
|
476
|
+
if isinstance(candidate, cached_property) or not inspect.isroutine(candidate):
|
|
477
|
+
raise DataError('Not a method or function.')
|
|
478
|
+
|
|
479
|
+
def _validate_method(self, candidate):
|
|
480
|
+
if not (inspect.isroutine(candidate) or isinstance(candidate, partial)):
|
|
481
|
+
raise DataError('Not a method or function.')
|
|
482
|
+
if getattr(candidate, 'robot_not_keyword', False):
|
|
483
|
+
raise DataError('Not exposed as a keyword.')
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
class DynamicKeywordCreator(KeywordCreator):
|
|
487
|
+
library: DynamicLibrary
|
|
488
|
+
|
|
489
|
+
def __init__(self, library: 'DynamicLibrary|HybridLibrary'):
|
|
490
|
+
super().__init__(library, getting_method_failed_level='ERROR')
|
|
491
|
+
|
|
492
|
+
def get_keyword_names(self) -> 'list[str]':
|
|
493
|
+
try:
|
|
494
|
+
return GetKeywordNames(self.library.instance)()
|
|
495
|
+
except DataError as err:
|
|
496
|
+
raise DataError(f"Getting keyword names from library '{self.library.name}' "
|
|
497
|
+
f"failed: {err}")
|
|
498
|
+
|
|
499
|
+
def _create_keyword(self, instance, name) -> DynamicKeyword:
|
|
500
|
+
return DynamicKeyword.from_name(name, self.library)
|