behavex 4.2.2__tar.gz → 4.2.4__tar.gz
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.
- {behavex-4.2.2/behavex.egg-info → behavex-4.2.4}/PKG-INFO +2 -2
- behavex-4.2.4/behavex/__pycache__/__init__.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/__main__.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/arguments.cpython-310.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/arguments.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/conf_mgr.cpython-310.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/conf_mgr.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/environment.cpython-310.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/environment.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/execution_singleton.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/global_vars.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/progress_bar.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/runner.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/runner.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/utils.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/__pycache__/utils.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/arguments.py +0 -1
- {behavex-4.2.2 → behavex-4.2.4}/behavex/conf_logging.cfg +2 -2
- {behavex-4.2.2 → behavex-4.2.4}/behavex/environment.py +9 -9
- behavex-4.2.4/behavex/outputs/__pycache__/__init__.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/formatter_manager.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/formatter_manager.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/jinja_mgr.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/output_strings.cpython-310.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/output_strings.cpython-39.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/report_html.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/report_json.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/report_utils.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/__pycache__/report_xml.cpython-310.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/formatter_manager.py +25 -22
- behavex-4.2.4/behavex/outputs/formatters/__pycache__/allure_behavex_formatter.cpython-310.pyc +0 -0
- behavex-4.2.4/behavex/outputs/formatters/__pycache__/allure_behavex_formatter.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/formatters/allure_behavex_formatter.py +22 -13
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/output_strings.py +8 -5
- {behavex-4.2.2 → behavex-4.2.4}/behavex/runner.py +84 -28
- {behavex-4.2.2 → behavex-4.2.4}/behavex/utils.py +2 -8
- {behavex-4.2.2 → behavex-4.2.4/behavex.egg-info}/PKG-INFO +2 -2
- behavex-4.2.4/behavex.egg-info/SOURCES.txt +239 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex.egg-info/requires.txt +1 -1
- behavex-4.2.4/output/focused_test_run/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/full_test_run/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/image_test_verification/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_001349/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_003713/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_004697/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_006245/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_008581/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_014810/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_034257/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_049842/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_057264/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_065267/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_071651/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_080858/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_107483/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_116700/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_120092/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_140259/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_143213/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_146320/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_146403/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_154070/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_159339/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_164111/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_188075/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_189804/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_195102/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_206620/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_238600/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_251312/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_260546/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_288178/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_304378/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_323270/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_328507/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_344685/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_344776/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_344852/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_348748/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_372668/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_376424/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_382185/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_405504/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_422012/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_423021/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_426722/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_434999/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_435402/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_440809/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_449330/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_450637/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_450881/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_465338/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_475651/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_479506/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_489113/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_495088/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_496889/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_497394/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_540969/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_574360/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_577418/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_579891/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_588144/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_590886/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_596667/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_601328/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_602191/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_631745/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_634385/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_646388/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_654650/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_656366/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_678770/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_680470/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_683436/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_685176/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_689341/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_691007/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_695521/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_703468/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_704571/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_710568/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_711677/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_719414/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_723957/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_724106/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_725084/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_732485/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_732517/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_742134/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_756176/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_767286/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_773557/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_787703/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_798702/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_803377/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_818000/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_821244/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_841973/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_843772/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_851821/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_852322/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_857146/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_858906/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_867706/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_868972/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_886897/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_891058/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_892919/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_907134/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_909239/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_932996/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_936717/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_940684/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_945860/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_947760/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_952517/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_955858/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_959703/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_969405/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/output_972545/outputs/logs/image_attachments_utils/__init__.py +4 -0
- behavex-4.2.4/output/outputs/logs/image_attachments_utils/__init__.py +4 -0
- {behavex-4.2.2 → behavex-4.2.4}/pyproject.toml +2 -2
- {behavex-4.2.2 → behavex-4.2.4}/setup.py +2 -2
- behavex-4.2.4/tests/features/environment.py +13 -0
- behavex-4.2.4/tests/features/secondary_features/environment.py +16 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/secondary_features/steps/generic_secondary_steps.py +39 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/steps/execution_steps.py +114 -0
- behavex-4.2.2/behavex/__pycache__/runner.cpython-39.pyc +0 -0
- behavex-4.2.2/behavex/__pycache__/utils.cpython-39.pyc +0 -0
- behavex-4.2.2/behavex/outputs/__pycache__/formatter_manager.cpython-39.pyc +0 -0
- behavex-4.2.2/behavex/outputs/formatters/__pycache__/allure_behavex_formatter.cpython-39.pyc +0 -0
- behavex-4.2.2/behavex.egg-info/SOURCES.txt +0 -96
- behavex-4.2.2/tests/features/environment.py +0 -3
- behavex-4.2.2/tests/features/secondary_features/environment.py +0 -6
- {behavex-4.2.2 → behavex-4.2.4}/LICENSE +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/MANIFEST.in +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/README.md +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/.DS_Store +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__main__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/__init__.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/__main__.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/execution_singleton.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/global_vars.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/__pycache__/progress_bar.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/conf_behavex.cfg +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/conf_mgr.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/execution_singleton.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/global_vars.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/__init__.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/jinja_mgr.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/report_html.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/report_json.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/report_utils.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/__pycache__/report_xml.cpython-39.pyc +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/behavex.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap-theme.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap-theme.min.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap-theme.min.css.map +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap.min.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/bootstrap.min.css.map +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/css/pace-theme-loading-bar.min.css +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/fonts/glyphicons-halflings-regular.svg +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/bootstrap.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/bootstrap.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/chart.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/jquery-1.11.0.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/jquery-ui.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/jquery.tablesorter.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/jquery.tooltipster.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/bootstrap/js/pace.min.js +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja/base.jinja2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja/main.jinja2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja/manifest.jinja2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja/xml.jinja2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja/xml_json.jinja2 +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/jinja_mgr.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/report_html.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/report_json.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/report_utils.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/outputs/report_xml.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/progress_bar.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex/steps/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex.egg-info/dependency_links.txt +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex.egg-info/entry_points.txt +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/behavex.egg-info/top_level.txt +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/docs/conf.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/setup.cfg +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/crashing_features/environment.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/crashing_features/steps/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/crashing_features/steps/crashing_steps.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/secondary_features/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/secondary_features/steps/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/secondary_features/steps/allure_formatter_secondary_steps.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/steps/__init__.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/steps/allure_formatter_steps.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/steps/allure_formatter_unit_steps.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/tests/features/steps/install_steps.py +0 -0
- {behavex-4.2.2 → behavex-4.2.4}/venv/bin/activate_this.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: behavex
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.4
|
|
4
4
|
Summary: Agile testing framework on top of Behave (BDD).
|
|
5
5
|
Home-page: https://github.com/hrcorval/behavex
|
|
6
6
|
Author: Hernan Rey
|
|
@@ -29,7 +29,7 @@ Requires-Python: >=3.5
|
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
31
|
Requires-Dist: behave==1.2.6
|
|
32
|
-
Requires-Dist: behavex-images>=3.
|
|
32
|
+
Requires-Dist: behavex-images>=3.2.1
|
|
33
33
|
Requires-Dist: allure-python-commons
|
|
34
34
|
Requires-Dist: jinja2
|
|
35
35
|
Requires-Dist: configobj
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -11,12 +11,12 @@ keys=simpleFormatter
|
|
|
11
11
|
encoding=utf-8-sig
|
|
12
12
|
|
|
13
13
|
[logger_root]
|
|
14
|
-
level=
|
|
14
|
+
level=INFO
|
|
15
15
|
handlers=consoleHandler
|
|
16
16
|
|
|
17
17
|
[handler_consoleHandler]
|
|
18
18
|
class=StreamHandler
|
|
19
|
-
level=
|
|
19
|
+
level=INFO
|
|
20
20
|
encoding=utf-8-sig
|
|
21
21
|
formatter=simpleFormatter
|
|
22
22
|
args=(sys.stdout, )
|
|
@@ -11,18 +11,18 @@ from datetime import datetime
|
|
|
11
11
|
|
|
12
12
|
from behave.contrib.scenario_autoretry import patch_scenario_with_autoretry
|
|
13
13
|
from behave.log_capture import capture
|
|
14
|
-
from behave.model import ScenarioOutline
|
|
14
|
+
from behave.model import ScenarioOutline # pyright: ignore[reportUnusedImport]
|
|
15
15
|
from behave.runner import Context, ModelRunner
|
|
16
16
|
|
|
17
17
|
from behavex import conf_mgr
|
|
18
18
|
from behavex.conf_mgr import get_env, get_param
|
|
19
19
|
from behavex.global_vars import global_vars
|
|
20
20
|
from behavex.outputs import report_json, report_xml
|
|
21
|
-
from behavex.outputs.report_utils import create_log_path,
|
|
21
|
+
from behavex.outputs.report_utils import (create_log_path, get_string_hash,
|
|
22
|
+
strip_ansi_codes)
|
|
22
23
|
from behavex.utils import (LOGGING_CFG, create_custom_log_when_called,
|
|
23
24
|
get_autoretry_attempts, get_logging_level,
|
|
24
|
-
get_scenario_tags, get_scenarios_instances
|
|
25
|
-
get_string_hash)
|
|
25
|
+
get_scenario_tags, get_scenarios_instances)
|
|
26
26
|
|
|
27
27
|
Context.__getattribute__ = create_custom_log_when_called
|
|
28
28
|
|
|
@@ -186,19 +186,19 @@ def before_scenario(context, scenario):
|
|
|
186
186
|
scenario.start = _get_current_timestamp_ms()
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
def before_step(context, step):
|
|
189
|
+
def before_step(context, step): # pyright: ignore[reportUnusedParameter]
|
|
190
190
|
step.start = _get_current_timestamp_ms()
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
def before_tag(context, tag):
|
|
193
|
+
def before_tag(context, tag): # pyright: ignore[reportUnusedParameter]
|
|
194
194
|
pass
|
|
195
195
|
|
|
196
196
|
|
|
197
|
-
def after_tag(context, tag):
|
|
197
|
+
def after_tag(context, tag): # pyright: ignore[reportUnusedParameter]
|
|
198
198
|
pass
|
|
199
199
|
|
|
200
200
|
|
|
201
|
-
def after_step(context, step):
|
|
201
|
+
def after_step(context, step): # pyright: ignore[reportUnusedParameter]
|
|
202
202
|
step.stop = _get_current_timestamp_ms()
|
|
203
203
|
try:
|
|
204
204
|
if step.exception:
|
|
@@ -230,7 +230,7 @@ def after_scenario(context, scenario):
|
|
|
230
230
|
|
|
231
231
|
|
|
232
232
|
# noinspection PyUnusedLocal
|
|
233
|
-
def after_feature(context, feature):
|
|
233
|
+
def after_feature(context, feature): # pyright: ignore[reportUnusedParameter]
|
|
234
234
|
try:
|
|
235
235
|
if get_env('multiprocessing') and get_param('parallel_scheme') == 'scenario':
|
|
236
236
|
return
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -9,16 +9,20 @@ Formatter manager module to handle custom formatters.
|
|
|
9
9
|
import importlib
|
|
10
10
|
import os
|
|
11
11
|
import sys
|
|
12
|
-
from typing import Optional,
|
|
12
|
+
from typing import (Any, Dict, Optional, # pyright: ignore[reportDeprecated]
|
|
13
|
+
Type)
|
|
13
14
|
|
|
14
15
|
from behavex.conf_mgr import get_env, get_param
|
|
15
16
|
|
|
17
|
+
# Formatter Constants
|
|
18
|
+
DEFAULT_FORMATTER_DIR = 'report-artifacts'
|
|
19
|
+
|
|
16
20
|
|
|
17
21
|
class FormatterManager:
|
|
18
22
|
"""Manager class for handling custom formatters in BehaveX."""
|
|
19
23
|
|
|
20
24
|
@staticmethod
|
|
21
|
-
def load_formatter(formatter_spec: str) -> Optional[Type]:
|
|
25
|
+
def load_formatter(formatter_spec: str) -> Optional[Type[Any]]: #pyright: ignore[reportDeprecated]
|
|
22
26
|
"""
|
|
23
27
|
Load a formatter class from a module path specification.
|
|
24
28
|
|
|
@@ -64,25 +68,27 @@ class FormatterManager:
|
|
|
64
68
|
return None
|
|
65
69
|
|
|
66
70
|
@staticmethod
|
|
67
|
-
def get_formatter_output_dir() -> str:
|
|
71
|
+
def get_formatter_output_dir(formatter_spec: str) -> Optional[str]: #pyright: ignore[reportDeprecated]
|
|
68
72
|
"""
|
|
69
|
-
Get the output directory
|
|
73
|
+
Get the preferred output directory from a formatter class.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
formatter_spec: String in format "module_path:FormatterClass"
|
|
70
77
|
|
|
71
78
|
Returns:
|
|
72
|
-
|
|
79
|
+
The formatter's preferred output directory, or None if not found
|
|
73
80
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return None
|
|
81
|
+
try:
|
|
82
|
+
formatter_class = FormatterManager.load_formatter(formatter_spec)
|
|
83
|
+
if formatter_class and hasattr(formatter_class, 'DEFAULT_OUTPUT_DIR'):
|
|
84
|
+
return formatter_class.DEFAULT_OUTPUT_DIR
|
|
85
|
+
except Exception as e:
|
|
86
|
+
print(f"Warning: Could not load formatter {formatter_spec} to get output directory: {str(e)}")
|
|
81
87
|
|
|
82
|
-
return
|
|
88
|
+
return None
|
|
83
89
|
|
|
84
90
|
@staticmethod
|
|
85
|
-
def format_results(json_output:
|
|
91
|
+
def format_results(json_output: Dict[str, Any]) -> None: #pyright: ignore[reportDeprecated]
|
|
86
92
|
"""
|
|
87
93
|
Format test results using the specified custom formatter.
|
|
88
94
|
|
|
@@ -97,20 +103,17 @@ class FormatterManager:
|
|
|
97
103
|
if not formatter_class:
|
|
98
104
|
return
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# Create the output directory only if a custom one is specified
|
|
103
|
-
if output_dir:
|
|
104
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
106
|
+
# The formatter will handle its own output directory setup
|
|
107
|
+
# No need to create directories here since formatters manage their own paths
|
|
105
108
|
|
|
106
109
|
try:
|
|
107
110
|
formatter = formatter_class()
|
|
108
111
|
# Check if the formatter has the expected method
|
|
109
|
-
if not hasattr(formatter, '
|
|
110
|
-
print(f"Formatter {formatter_class.__name__} does not implement required method '
|
|
112
|
+
if not hasattr(formatter, 'launch_json_formatter'):
|
|
113
|
+
print(f"Formatter {formatter_class.__name__} does not implement required method 'launch_json_formatter'")
|
|
111
114
|
return
|
|
112
115
|
|
|
113
|
-
formatter.
|
|
116
|
+
formatter.launch_json_formatter(json_output)
|
|
114
117
|
except Exception as e:
|
|
115
118
|
print(f"Error running formatter {formatter_spec}: {str(e)}")
|
|
116
119
|
import traceback
|
|
Binary file
|
|
Binary file
|
|
@@ -31,7 +31,6 @@ import os
|
|
|
31
31
|
import re
|
|
32
32
|
import sys
|
|
33
33
|
import uuid
|
|
34
|
-
from datetime import datetime
|
|
35
34
|
from pathlib import Path
|
|
36
35
|
|
|
37
36
|
from allure_commons.model2 import (Attachment, Parameter, TestResult,
|
|
@@ -40,13 +39,15 @@ from allure_commons.types import AttachmentType
|
|
|
40
39
|
from allure_commons.utils import now
|
|
41
40
|
|
|
42
41
|
from behavex.conf_mgr import get_env, get_param
|
|
43
|
-
from behavex.outputs.formatter_manager import FormatterManager
|
|
44
42
|
from behavex.outputs.report_utils import get_string_hash
|
|
45
43
|
|
|
46
44
|
|
|
47
45
|
class AllureBehaveXFormatter:
|
|
48
46
|
"""Allure formatter for BehaveX test results."""
|
|
49
47
|
|
|
48
|
+
# Default output directory for this formatter
|
|
49
|
+
DEFAULT_OUTPUT_DIR = 'allure-results'
|
|
50
|
+
|
|
50
51
|
def _get_step_line_from_image(self, filename):
|
|
51
52
|
"""Extract step line number from image filename.
|
|
52
53
|
|
|
@@ -243,7 +244,11 @@ class AllureBehaveXFormatter:
|
|
|
243
244
|
TestResult: The updated test case with evidence attachments
|
|
244
245
|
"""
|
|
245
246
|
|
|
246
|
-
|
|
247
|
+
logs_dir = get_env('logs')
|
|
248
|
+
if logs_dir is None:
|
|
249
|
+
# Handle standalone script execution case
|
|
250
|
+
logs_dir = os.path.join(os.path.dirname(output_dir), 'outputs', 'logs')
|
|
251
|
+
evidence_dir = os.path.join(logs_dir, str(scenario_hash), 'evidence')
|
|
247
252
|
|
|
248
253
|
if not os.path.exists(evidence_dir):
|
|
249
254
|
return test_case
|
|
@@ -297,19 +302,20 @@ class AllureBehaveXFormatter:
|
|
|
297
302
|
|
|
298
303
|
return test_case
|
|
299
304
|
|
|
300
|
-
def
|
|
305
|
+
def launch_json_formatter(self, json_data):
|
|
301
306
|
"""
|
|
302
|
-
|
|
307
|
+
Generic method to launch the formatter and process JSON test results.
|
|
303
308
|
|
|
304
309
|
Args:
|
|
305
310
|
json_data (dict): Dictionary containing the test results data.
|
|
306
311
|
"""
|
|
307
|
-
#
|
|
308
|
-
|
|
312
|
+
# Use the LOGS environment variable which is set consistently by the runner
|
|
313
|
+
# This ensures evidence, logs, and allure results are all in the same location
|
|
314
|
+
output_dir = get_env('logs')
|
|
309
315
|
|
|
310
|
-
#
|
|
311
|
-
|
|
312
|
-
|
|
316
|
+
# Fallback if LOGS is not set (for standalone script execution)
|
|
317
|
+
if not output_dir:
|
|
318
|
+
output_dir = os.path.join(get_env('OUTPUT') or 'output', self.DEFAULT_OUTPUT_DIR)
|
|
313
319
|
|
|
314
320
|
os.makedirs(output_dir, exist_ok=True)
|
|
315
321
|
|
|
@@ -487,7 +493,11 @@ class AllureBehaveXFormatter:
|
|
|
487
493
|
# Process scenario logs as attachment
|
|
488
494
|
if get_param('formatter_attach_logs'):
|
|
489
495
|
scenario_hash = scenario.get('identifier_hash', get_string_hash(f"{str(feature['filename'])}-{str(scenario['line'])}"))
|
|
490
|
-
|
|
496
|
+
logs_dir_for_log = get_env('logs')
|
|
497
|
+
if logs_dir_for_log is None:
|
|
498
|
+
# Handle standalone script execution case
|
|
499
|
+
logs_dir_for_log = os.path.join(os.path.dirname(output_dir), 'outputs', 'logs')
|
|
500
|
+
log_path = os.path.join(logs_dir_for_log, str(scenario_hash), 'scenario.log')
|
|
491
501
|
if os.path.exists(log_path):
|
|
492
502
|
# Use relative path for the source if possible to avoid duplication
|
|
493
503
|
rel_path = os.path.relpath(log_path, output_dir) if output_dir in log_path else log_path
|
|
@@ -637,7 +647,6 @@ class AllureBehaveXFormatter:
|
|
|
637
647
|
with open(os.path.join(output_dir, "environment-categories.json"), "w") as f:
|
|
638
648
|
json.dump(env_categories, f, indent=2)
|
|
639
649
|
|
|
640
|
-
|
|
641
650
|
def main():
|
|
642
651
|
parser = argparse.ArgumentParser(description='Parse BehaveX report.json into Allure format')
|
|
643
652
|
parser.add_argument('--report-path',
|
|
@@ -651,7 +660,7 @@ def main():
|
|
|
651
660
|
|
|
652
661
|
try:
|
|
653
662
|
with open(args.report_path) as f:
|
|
654
|
-
formatter.
|
|
663
|
+
formatter.launch_json_formatter(json.load(f))
|
|
655
664
|
except FileNotFoundError:
|
|
656
665
|
print(f"Error: Could not find report file at {args.report_path}")
|
|
657
666
|
sys.exit(1)
|
|
@@ -45,8 +45,8 @@ TEXTS = {
|
|
|
45
45
|
'description': '',
|
|
46
46
|
'modal': {
|
|
47
47
|
'title': '',
|
|
48
|
-
'body': '<b>Test Automation Rate:</b> % of automated scenarios.<br>'
|
|
49
|
-
|
|
48
|
+
'body': ('<b>Test Automation Rate:</b> % of automated scenarios.<br>'
|
|
49
|
+
'<b>Pass Rate:</b>: % of passed scenarios.<br>'),
|
|
50
50
|
},
|
|
51
51
|
},
|
|
52
52
|
'joined': {'title': '', 'description': '', 'modal': {'title': '', 'modal': 'the'}},
|
|
@@ -61,9 +61,9 @@ TEXTS = {
|
|
|
61
61
|
'serial_execution': u'\n{0}\nRunning serial scenarios (tagged as @SERIAL).\n{0}\n'.format('*' * 60),
|
|
62
62
|
'running_parallels': u'\n{0}\nRunning parallel scenarios\n{0}\n'.format('*' * 60),
|
|
63
63
|
'run_behave': u"Running feature '{}' with scenario '{}'.",
|
|
64
|
-
'duplicated_scenarios': '{0}\nThere are duplicate scenario names to run.\n'
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
'duplicated_scenarios': ('{0}\nThere are duplicate scenario names to run.\n'
|
|
65
|
+
'Parallel test execution by scenario cannot be performed.\n'
|
|
66
|
+
'Duplicated scenario names: \n{1}.\n{0}\n').format('*' * 60, {}),
|
|
67
67
|
'execution_crashed': 'Execution crashed or was interrupted when executing the scenario. No outputs could be generated.'
|
|
68
68
|
},
|
|
69
69
|
'folder': {'run_behave': u"Running folder: '{}' and feature '{}'."},
|
|
@@ -77,6 +77,9 @@ TEXTS = {
|
|
|
77
77
|
'execution': {
|
|
78
78
|
'callback': {
|
|
79
79
|
'error': u'\nError occurred during execution callback: {}'
|
|
80
|
+
},
|
|
81
|
+
'dry_run': {
|
|
82
|
+
'completed': u'\nDry run completed. Please, see the report in {0} folder.\n\n'
|
|
80
83
|
}
|
|
81
84
|
},
|
|
82
85
|
'parallel': {
|
|
@@ -12,37 +12,39 @@ including setup, execution, and reporting.
|
|
|
12
12
|
from __future__ import absolute_import, print_function
|
|
13
13
|
|
|
14
14
|
import codecs
|
|
15
|
-
import concurrent
|
|
15
|
+
import concurrent # pyright: ignore[reportUnusedImport]
|
|
16
16
|
import copy
|
|
17
17
|
import io
|
|
18
18
|
import json
|
|
19
|
-
import logging.config
|
|
19
|
+
import logging.config # pyright: ignore[reportUnusedImport]
|
|
20
20
|
import multiprocessing
|
|
21
21
|
import os
|
|
22
22
|
import os.path
|
|
23
23
|
import platform
|
|
24
|
-
import re
|
|
25
24
|
import signal
|
|
26
25
|
import sys
|
|
27
26
|
import time
|
|
28
27
|
import traceback
|
|
29
28
|
from concurrent.futures import ProcessPoolExecutor
|
|
29
|
+
from concurrent.futures.process import BrokenProcessPool
|
|
30
30
|
from multiprocessing import active_children
|
|
31
31
|
from multiprocessing.managers import DictProxy
|
|
32
32
|
from tempfile import gettempdir
|
|
33
|
+
from typing import Any, Dict
|
|
33
34
|
|
|
34
35
|
from behave import __main__ as behave_script
|
|
35
36
|
from behave.model import Feature, Scenario, ScenarioOutline
|
|
36
37
|
|
|
37
38
|
# noinspection PyUnresolvedReferences
|
|
38
|
-
import behavex.outputs.report_json
|
|
39
39
|
from behavex import conf_mgr
|
|
40
40
|
from behavex.arguments import BEHAVE_ARGS, BEHAVEX_ARGS, parse_arguments
|
|
41
|
-
from behavex.conf_mgr import ConfigRun, get_env, get_param
|
|
41
|
+
from behavex.conf_mgr import ConfigRun, get_env, get_param
|
|
42
42
|
from behavex.environment import extend_behave_hooks
|
|
43
43
|
from behavex.execution_singleton import ExecutionSingleton
|
|
44
44
|
from behavex.global_vars import global_vars
|
|
45
45
|
from behavex.outputs import report_xml
|
|
46
|
+
from behavex.outputs.formatter_manager import (DEFAULT_FORMATTER_DIR,
|
|
47
|
+
FormatterManager)
|
|
46
48
|
from behavex.outputs.report_json import generate_execution_info
|
|
47
49
|
from behavex.outputs.report_utils import (get_overall_status,
|
|
48
50
|
match_for_execution,
|
|
@@ -53,13 +55,12 @@ from behavex.utils import (IncludeNameMatch, IncludePathsMatch, MatchInclude,
|
|
|
53
55
|
cleanup_folders, configure_logging,
|
|
54
56
|
copy_bootstrap_html_generator,
|
|
55
57
|
create_execution_complete_callback_function,
|
|
56
|
-
expand_paths, explore_features,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
print_env_variables, print_parallel,
|
|
58
|
+
expand_paths, explore_features, generate_reports,
|
|
59
|
+
get_feature_and_scenario_line, get_json_results,
|
|
60
|
+
get_logging_level, get_scenario_tags,
|
|
61
|
+
get_scenarios_instances, get_text,
|
|
62
|
+
join_feature_reports, join_scenario_reports,
|
|
63
|
+
len_scenarios, print_env_variables, print_parallel,
|
|
63
64
|
set_behave_tags, set_env_variable,
|
|
64
65
|
set_environ_config, set_system_paths)
|
|
65
66
|
|
|
@@ -136,8 +137,8 @@ def run(args):
|
|
|
136
137
|
# Handle include_paths parameter
|
|
137
138
|
if len(get_param('include_paths')) > 0:
|
|
138
139
|
include_paths = ",".join(expand_paths(get_param('include_paths'))).replace('\n', '')
|
|
139
|
-
features_path = os.environ.get('FEATURES_PATH')
|
|
140
|
-
if features_path == '' or
|
|
140
|
+
features_path = os.environ.get('FEATURES_PATH', '')
|
|
141
|
+
if features_path == '' or not os.path.exists(features_path):
|
|
141
142
|
os.environ['FEATURES_PATH'] = include_paths
|
|
142
143
|
else:
|
|
143
144
|
os.environ['FEATURES_PATH'] = features_path + ',' + include_paths
|
|
@@ -210,7 +211,7 @@ def launch_behavex():
|
|
|
210
211
|
execution_codes = []
|
|
211
212
|
results = None
|
|
212
213
|
config = conf_mgr.get_config()
|
|
213
|
-
features_path = os.environ.get('FEATURES_PATH')
|
|
214
|
+
features_path = os.environ.get('FEATURES_PATH', '')
|
|
214
215
|
parallel_scheme = get_param('parallel_scheme')
|
|
215
216
|
if get_param('dry_run'):
|
|
216
217
|
parallel_processes = 1
|
|
@@ -221,7 +222,7 @@ def launch_behavex():
|
|
|
221
222
|
show_progress_bar = get_param('show_progress_bar')
|
|
222
223
|
multiprocess = (
|
|
223
224
|
True
|
|
224
|
-
if
|
|
225
|
+
if parallel_processes > 1 and not get_param('dry_run')
|
|
225
226
|
else False
|
|
226
227
|
)
|
|
227
228
|
set_behave_tags()
|
|
@@ -283,11 +284,9 @@ def launch_behavex():
|
|
|
283
284
|
lock,
|
|
284
285
|
show_progress_bar)
|
|
285
286
|
wrap_up_process_pools(process_pool, json_reports, scenario)
|
|
286
|
-
time_end = global_vars.execution_end_time
|
|
287
287
|
|
|
288
288
|
if get_param('dry_run'):
|
|
289
|
-
|
|
290
|
-
print(msg.format(get_env('OUTPUT')))
|
|
289
|
+
print_parallel('execution.dry_run.completed', get_env('OUTPUT'))
|
|
291
290
|
|
|
292
291
|
remove_temporary_files(parallel_processes, json_reports)
|
|
293
292
|
|
|
@@ -397,7 +396,6 @@ def create_scenario_line_references(features):
|
|
|
397
396
|
updated_features = {}
|
|
398
397
|
for feature_path, scenarios in features.items():
|
|
399
398
|
for scenario in scenarios:
|
|
400
|
-
scenario_filename = text(scenario.filename)
|
|
401
399
|
if global_vars.rerun_failures or ".feature:" in feature_path:
|
|
402
400
|
if feature_path not in updated_features:
|
|
403
401
|
updated_features[feature_path] = []
|
|
@@ -502,8 +500,10 @@ def launch_by_feature(features,
|
|
|
502
500
|
for parallel_process in parallel_processes:
|
|
503
501
|
try:
|
|
504
502
|
parallel_process.result()
|
|
503
|
+
except (KeyboardInterrupt, SystemExit):
|
|
504
|
+
# Allow KeyboardInterrupt (Ctrl+C) and SystemExit to propagate to top level
|
|
505
|
+
raise
|
|
505
506
|
except:
|
|
506
|
-
from concurrent.futures.process import BrokenProcessPool
|
|
507
507
|
e = sys.exc_info()[1]
|
|
508
508
|
if isinstance(e, BrokenProcessPool):
|
|
509
509
|
print_parallel('process.pool.broken.main', str(e))
|
|
@@ -625,8 +625,10 @@ def launch_by_scenario(features,
|
|
|
625
625
|
for parallel_process in parallel_processes:
|
|
626
626
|
try:
|
|
627
627
|
parallel_process.result()
|
|
628
|
+
except (KeyboardInterrupt, SystemExit):
|
|
629
|
+
# Allow KeyboardInterrupt (Ctrl+C) and SystemExit to propagate to top level
|
|
630
|
+
raise
|
|
628
631
|
except:
|
|
629
|
-
from concurrent.futures.process import BrokenProcessPool
|
|
630
632
|
e = sys.exc_info()[1]
|
|
631
633
|
if isinstance(e, BrokenProcessPool):
|
|
632
634
|
print_parallel('process.pool.broken.main', str(e))
|
|
@@ -772,21 +774,57 @@ def _launch_behave(behave_args):
|
|
|
772
774
|
|
|
773
775
|
# Use a custom output capture class that mirrors to console and captures
|
|
774
776
|
class TeePrint:
|
|
777
|
+
"""A complete wrapper for stdout that captures output while maintaining all stdout functionality."""
|
|
778
|
+
|
|
775
779
|
def __init__(self, original_stdout):
|
|
776
|
-
|
|
777
|
-
self
|
|
780
|
+
# Use object.__setattr__ to avoid recursion with __setattr__
|
|
781
|
+
object.__setattr__(self, 'original_stdout', original_stdout)
|
|
782
|
+
object.__setattr__(self, 'captured', io.StringIO())
|
|
778
783
|
|
|
779
784
|
def write(self, data):
|
|
785
|
+
"""Override write to capture output while maintaining original behavior."""
|
|
780
786
|
self.original_stdout.write(data)
|
|
781
787
|
self.captured.write(data)
|
|
788
|
+
return len(data) if hasattr(data, '__len__') else None
|
|
782
789
|
|
|
783
790
|
def flush(self):
|
|
791
|
+
"""Override flush to flush both original and captured streams."""
|
|
784
792
|
self.original_stdout.flush()
|
|
785
793
|
self.captured.flush()
|
|
786
794
|
|
|
787
795
|
def getvalue(self):
|
|
796
|
+
"""Custom method to get captured output."""
|
|
788
797
|
return self.captured.getvalue()
|
|
789
798
|
|
|
799
|
+
def __getattr__(self, name):
|
|
800
|
+
"""Delegate all other attributes/methods to the original stdout."""
|
|
801
|
+
try:
|
|
802
|
+
return getattr(self.original_stdout, name)
|
|
803
|
+
except AttributeError:
|
|
804
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|
|
805
|
+
|
|
806
|
+
def __setattr__(self, name, value):
|
|
807
|
+
"""Delegate attribute setting to original stdout (except for our internal attributes)."""
|
|
808
|
+
if name in ('original_stdout', 'captured'):
|
|
809
|
+
object.__setattr__(self, name, value)
|
|
810
|
+
else:
|
|
811
|
+
setattr(self.original_stdout, name, value)
|
|
812
|
+
|
|
813
|
+
def __getattribute__(self, name):
|
|
814
|
+
"""Handle attribute access with proper delegation."""
|
|
815
|
+
# Handle our own methods and attributes first
|
|
816
|
+
if name in ('original_stdout', 'captured', 'write', 'flush', 'getvalue',
|
|
817
|
+
'__class__', '__dict__', '__getattr__', '__setattr__'):
|
|
818
|
+
return object.__getattribute__(self, name)
|
|
819
|
+
|
|
820
|
+
# For common stdout properties, delegate to original_stdout
|
|
821
|
+
try:
|
|
822
|
+
original_stdout = object.__getattribute__(self, 'original_stdout')
|
|
823
|
+
return getattr(original_stdout, name)
|
|
824
|
+
except (AttributeError, KeyError):
|
|
825
|
+
# Fallback to our own implementation
|
|
826
|
+
return object.__getattribute__(self, name)
|
|
827
|
+
|
|
790
828
|
# Create the tee capture object
|
|
791
829
|
tee = TeePrint(sys.__stdout__)
|
|
792
830
|
|
|
@@ -867,7 +905,7 @@ def wrap_up_process_pools(process_pool,
|
|
|
867
905
|
output = os.path.join(get_env('OUTPUT'))
|
|
868
906
|
try:
|
|
869
907
|
process_pool.shutdown(wait=True)
|
|
870
|
-
except Exception
|
|
908
|
+
except Exception:
|
|
871
909
|
process_pool.shutdown(wait=False, cancel_futures=True)
|
|
872
910
|
if type(json_reports) is list:
|
|
873
911
|
if scenario:
|
|
@@ -1049,8 +1087,25 @@ def _set_env_variables(args):
|
|
|
1049
1087
|
if get_param('name'):
|
|
1050
1088
|
set_env_variable('NAME', args.name)
|
|
1051
1089
|
if get_param('formatter'):
|
|
1052
|
-
formatter_outdir = get_param('formatter_outdir')
|
|
1053
|
-
|
|
1090
|
+
formatter_outdir = get_param('formatter_outdir', '')
|
|
1091
|
+
formatter_spec = get_param('formatter')
|
|
1092
|
+
|
|
1093
|
+
# If no formatter output directory is specified, use the default
|
|
1094
|
+
if not formatter_outdir:
|
|
1095
|
+
formatter_outdir = DEFAULT_FORMATTER_DIR
|
|
1096
|
+
|
|
1097
|
+
# Special handling for custom formatters with default settings
|
|
1098
|
+
if formatter_outdir == DEFAULT_FORMATTER_DIR and formatter_spec:
|
|
1099
|
+
# Try to dynamically get the formatter's preferred output directory
|
|
1100
|
+
custom_formatter_dir = FormatterManager.get_formatter_output_dir(formatter_spec)
|
|
1101
|
+
if custom_formatter_dir:
|
|
1102
|
+
# Use the formatter's preferred directory to maintain consistency
|
|
1103
|
+
set_env_variable('LOGS', os.path.join(get_env('output'), custom_formatter_dir))
|
|
1104
|
+
else:
|
|
1105
|
+
# Fallback to default formatter directory
|
|
1106
|
+
set_env_variable('LOGS', os.path.join(get_env('output'), formatter_outdir))
|
|
1107
|
+
else:
|
|
1108
|
+
set_env_variable('LOGS', os.path.join(get_env('output'), formatter_outdir))
|
|
1054
1109
|
else:
|
|
1055
1110
|
set_env_variable('LOGS', os.path.join(get_env('output'), 'outputs', 'logs'))
|
|
1056
1111
|
for arg in BEHAVEX_ARGS[4:]:
|
|
@@ -1267,8 +1322,9 @@ def dump_json_results():
|
|
|
1267
1322
|
process_name = multiprocessing.current_process().name.split('-')[-1]
|
|
1268
1323
|
path_info = os.path.join(gettempdir(), 'result{}.tmp'.format(process_name))
|
|
1269
1324
|
|
|
1270
|
-
def _load_json():
|
|
1325
|
+
def _load_json() -> Dict[str, Any]:
|
|
1271
1326
|
"""this function load from file"""
|
|
1327
|
+
json_output_converted = {}
|
|
1272
1328
|
with open(path_info, 'r') as info_file:
|
|
1273
1329
|
json_output_file = info_file.read()
|
|
1274
1330
|
json_output_converted = json.loads(json_output_file)
|