busser-behave 0.1.3
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.
- checksums.yaml +7 -0
- data/.cane +0 -0
- data/.gitignore +17 -0
- data/.tailor +4 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE +15 -0
- data/README.md +41 -0
- data/Rakefile +68 -0
- data/busser-behave.gemspec +30 -0
- data/features/plugin_install_command.feature +11 -0
- data/features/plugin_list_command.feature +8 -0
- data/features/support/env.rb +13 -0
- data/features/test_command.feature +31 -0
- data/lib/busser/behave/version.rb +26 -0
- data/lib/busser/runner_plugin/behave.rb +37 -0
- data/vendor/behave/CHANGES.rst +483 -0
- data/vendor/behave/LICENSE +23 -0
- data/vendor/behave/MANIFEST.in +37 -0
- data/vendor/behave/PROJECT_INFO.rst +21 -0
- data/vendor/behave/README.rst +112 -0
- data/vendor/behave/VERSION.txt +1 -0
- data/vendor/behave/behave.ini +22 -0
- data/vendor/behave/behave/__init__.py +30 -0
- data/vendor/behave/behave/__main__.py +187 -0
- data/vendor/behave/behave/_stepimport.py +185 -0
- data/vendor/behave/behave/_types.py +134 -0
- data/vendor/behave/behave/api/__init__.py +7 -0
- data/vendor/behave/behave/api/async_step.py +283 -0
- data/vendor/behave/behave/capture.py +227 -0
- data/vendor/behave/behave/compat/__init__.py +5 -0
- data/vendor/behave/behave/compat/collections.py +20 -0
- data/vendor/behave/behave/configuration.py +788 -0
- data/vendor/behave/behave/contrib/__init__.py +0 -0
- data/vendor/behave/behave/contrib/scenario_autoretry.py +73 -0
- data/vendor/behave/behave/formatter/__init__.py +12 -0
- data/vendor/behave/behave/formatter/_builtins.py +39 -0
- data/vendor/behave/behave/formatter/_registry.py +135 -0
- data/vendor/behave/behave/formatter/ansi_escapes.py +91 -0
- data/vendor/behave/behave/formatter/base.py +200 -0
- data/vendor/behave/behave/formatter/formatters.py +57 -0
- data/vendor/behave/behave/formatter/json.py +253 -0
- data/vendor/behave/behave/formatter/null.py +12 -0
- data/vendor/behave/behave/formatter/plain.py +158 -0
- data/vendor/behave/behave/formatter/pretty.py +351 -0
- data/vendor/behave/behave/formatter/progress.py +287 -0
- data/vendor/behave/behave/formatter/rerun.py +114 -0
- data/vendor/behave/behave/formatter/sphinx_steps.py +372 -0
- data/vendor/behave/behave/formatter/sphinx_util.py +118 -0
- data/vendor/behave/behave/formatter/steps.py +497 -0
- data/vendor/behave/behave/formatter/tags.py +178 -0
- data/vendor/behave/behave/i18n.py +614 -0
- data/vendor/behave/behave/importer.py +102 -0
- data/vendor/behave/behave/json_parser.py +264 -0
- data/vendor/behave/behave/log_capture.py +233 -0
- data/vendor/behave/behave/matchers.py +402 -0
- data/vendor/behave/behave/model.py +1737 -0
- data/vendor/behave/behave/model_core.py +416 -0
- data/vendor/behave/behave/model_describe.py +105 -0
- data/vendor/behave/behave/parser.py +615 -0
- data/vendor/behave/behave/reporter/__init__.py +0 -0
- data/vendor/behave/behave/reporter/base.py +45 -0
- data/vendor/behave/behave/reporter/junit.py +473 -0
- data/vendor/behave/behave/reporter/summary.py +94 -0
- data/vendor/behave/behave/runner.py +753 -0
- data/vendor/behave/behave/runner_util.py +417 -0
- data/vendor/behave/behave/step_registry.py +112 -0
- data/vendor/behave/behave/tag_expression.py +111 -0
- data/vendor/behave/behave/tag_matcher.py +465 -0
- data/vendor/behave/behave/textutil.py +137 -0
- data/vendor/behave/behave/userdata.py +130 -0
- data/vendor/behave/behave4cmd0/__all_steps__.py +12 -0
- data/vendor/behave/behave4cmd0/__init__.py +5 -0
- data/vendor/behave/behave4cmd0/__setup.py +11 -0
- data/vendor/behave/behave4cmd0/command_shell.py +216 -0
- data/vendor/behave/behave4cmd0/command_shell_proc.py +256 -0
- data/vendor/behave/behave4cmd0/command_steps.py +532 -0
- data/vendor/behave/behave4cmd0/command_util.py +147 -0
- data/vendor/behave/behave4cmd0/failing_steps.py +49 -0
- data/vendor/behave/behave4cmd0/log/__init__.py +1 -0
- data/vendor/behave/behave4cmd0/log/steps.py +395 -0
- data/vendor/behave/behave4cmd0/note_steps.py +29 -0
- data/vendor/behave/behave4cmd0/passing_steps.py +36 -0
- data/vendor/behave/behave4cmd0/pathutil.py +146 -0
- data/vendor/behave/behave4cmd0/setup_command_shell.py +24 -0
- data/vendor/behave/behave4cmd0/textutil.py +304 -0
- data/vendor/behave/bin/behave +44 -0
- data/vendor/behave/bin/behave.cmd +10 -0
- data/vendor/behave/bin/behave.junit_filter.py +85 -0
- data/vendor/behave/bin/behave.step_durations.py +163 -0
- data/vendor/behave/bin/behave2cucumber_json.py +63 -0
- data/vendor/behave/bin/behave_cmd.py +44 -0
- data/vendor/behave/bin/convert_i18n_yaml.py +77 -0
- data/vendor/behave/bin/explore_platform_encoding.py +24 -0
- data/vendor/behave/bin/i18n.yml +621 -0
- data/vendor/behave/bin/invoke +8 -0
- data/vendor/behave/bin/invoke.cmd +9 -0
- data/vendor/behave/bin/json.format.py +167 -0
- data/vendor/behave/bin/jsonschema_validate.py +122 -0
- data/vendor/behave/bin/make_localpi.py +279 -0
- data/vendor/behave/bin/project_bootstrap.sh +30 -0
- data/vendor/behave/bin/toxcmd.py +270 -0
- data/vendor/behave/bin/toxcmd3.py +270 -0
- data/vendor/behave/conftest.py +27 -0
- data/vendor/behave/docs/Makefile +154 -0
- data/vendor/behave/docs/_static/agogo.css +501 -0
- data/vendor/behave/docs/_static/behave_logo.png +0 -0
- data/vendor/behave/docs/_static/behave_logo1.png +0 -0
- data/vendor/behave/docs/_static/behave_logo2.png +0 -0
- data/vendor/behave/docs/_static/behave_logo3.png +0 -0
- data/vendor/behave/docs/_themes/LICENSE +45 -0
- data/vendor/behave/docs/_themes/kr/layout.html +17 -0
- data/vendor/behave/docs/_themes/kr/relations.html +19 -0
- data/vendor/behave/docs/_themes/kr/static/flasky.css_t +480 -0
- data/vendor/behave/docs/_themes/kr/static/small_flask.css +90 -0
- data/vendor/behave/docs/_themes/kr/theme.conf +7 -0
- data/vendor/behave/docs/_themes/kr_small/layout.html +22 -0
- data/vendor/behave/docs/_themes/kr_small/static/flasky.css_t +287 -0
- data/vendor/behave/docs/_themes/kr_small/theme.conf +10 -0
- data/vendor/behave/docs/api.rst +408 -0
- data/vendor/behave/docs/appendix.rst +19 -0
- data/vendor/behave/docs/behave.rst +640 -0
- data/vendor/behave/docs/behave.rst-template +86 -0
- data/vendor/behave/docs/behave_ecosystem.rst +81 -0
- data/vendor/behave/docs/comparison.rst +85 -0
- data/vendor/behave/docs/conf.py +293 -0
- data/vendor/behave/docs/context_attributes.rst +66 -0
- data/vendor/behave/docs/django.rst +192 -0
- data/vendor/behave/docs/formatters.rst +61 -0
- data/vendor/behave/docs/gherkin.rst +673 -0
- data/vendor/behave/docs/index.rst +57 -0
- data/vendor/behave/docs/install.rst +60 -0
- data/vendor/behave/docs/more_info.rst +184 -0
- data/vendor/behave/docs/new_and_noteworthy.rst +18 -0
- data/vendor/behave/docs/new_and_noteworthy_v1.2.4.rst +11 -0
- data/vendor/behave/docs/new_and_noteworthy_v1.2.5.rst +814 -0
- data/vendor/behave/docs/new_and_noteworthy_v1.2.6.rst +255 -0
- data/vendor/behave/docs/parse_builtin_types.rst +59 -0
- data/vendor/behave/docs/philosophy.rst +235 -0
- data/vendor/behave/docs/regular_expressions.rst +71 -0
- data/vendor/behave/docs/related.rst +14 -0
- data/vendor/behave/docs/test_domains.rst +62 -0
- data/vendor/behave/docs/tutorial.rst +636 -0
- data/vendor/behave/docs/update_behave_rst.py +100 -0
- data/vendor/behave/etc/json/behave.json-schema +172 -0
- data/vendor/behave/etc/junit.xml/behave_junit.xsd +103 -0
- data/vendor/behave/etc/junit.xml/junit-4.xsd +92 -0
- data/vendor/behave/examples/async_step/README.txt +8 -0
- data/vendor/behave/examples/async_step/behave.ini +14 -0
- data/vendor/behave/examples/async_step/features/async_dispatch.feature +8 -0
- data/vendor/behave/examples/async_step/features/async_run.feature +6 -0
- data/vendor/behave/examples/async_step/features/environment.py +28 -0
- data/vendor/behave/examples/async_step/features/steps/async_dispatch_steps.py +26 -0
- data/vendor/behave/examples/async_step/features/steps/async_steps34.py +10 -0
- data/vendor/behave/examples/async_step/features/steps/async_steps35.py +10 -0
- data/vendor/behave/examples/async_step/testrun_example.async_dispatch.txt +11 -0
- data/vendor/behave/examples/async_step/testrun_example.async_run.txt +9 -0
- data/vendor/behave/examples/env_vars/README.rst +26 -0
- data/vendor/behave/examples/env_vars/behave.ini +15 -0
- data/vendor/behave/examples/env_vars/behave_run.output_example.txt +12 -0
- data/vendor/behave/examples/env_vars/features/env_var.feature +6 -0
- data/vendor/behave/examples/env_vars/features/steps/env_var_steps.py +38 -0
- data/vendor/behave/features/README.txt +12 -0
- data/vendor/behave/features/background.feature +392 -0
- data/vendor/behave/features/capture_stderr.feature +172 -0
- data/vendor/behave/features/capture_stdout.feature +125 -0
- data/vendor/behave/features/cmdline.lang_list.feature +33 -0
- data/vendor/behave/features/configuration.default_paths.feature +116 -0
- data/vendor/behave/features/context.global_params.feature +35 -0
- data/vendor/behave/features/context.local_params.feature +17 -0
- data/vendor/behave/features/directory_layout.advanced.feature +147 -0
- data/vendor/behave/features/directory_layout.basic.feature +75 -0
- data/vendor/behave/features/directory_layout.basic2.feature +87 -0
- data/vendor/behave/features/environment.py +53 -0
- data/vendor/behave/features/exploratory_testing.with_table.feature +141 -0
- data/vendor/behave/features/feature.description.feature +0 -0
- data/vendor/behave/features/feature.exclude_from_run.feature +96 -0
- data/vendor/behave/features/formatter.help.feature +30 -0
- data/vendor/behave/features/formatter.json.feature +420 -0
- data/vendor/behave/features/formatter.progress3.feature +235 -0
- data/vendor/behave/features/formatter.rerun.feature +296 -0
- data/vendor/behave/features/formatter.steps.feature +181 -0
- data/vendor/behave/features/formatter.steps_catalog.feature +100 -0
- data/vendor/behave/features/formatter.steps_doc.feature +140 -0
- data/vendor/behave/features/formatter.steps_usage.feature +404 -0
- data/vendor/behave/features/formatter.tags.feature +134 -0
- data/vendor/behave/features/formatter.tags_location.feature +183 -0
- data/vendor/behave/features/formatter.user_defined.feature +196 -0
- data/vendor/behave/features/i18n.unicode_problems.feature +445 -0
- data/vendor/behave/features/logcapture.clear_handlers.feature +114 -0
- data/vendor/behave/features/logcapture.feature +188 -0
- data/vendor/behave/features/logcapture.filter.feature +130 -0
- data/vendor/behave/features/logging.no_capture.feature +99 -0
- data/vendor/behave/features/logging.setup_format.feature +157 -0
- data/vendor/behave/features/logging.setup_level.feature +168 -0
- data/vendor/behave/features/logging.setup_with_configfile.feature +137 -0
- data/vendor/behave/features/parser.background.sad_cases.feature +129 -0
- data/vendor/behave/features/parser.feature.sad_cases.feature +144 -0
- data/vendor/behave/features/runner.abort_by_user.feature +305 -0
- data/vendor/behave/features/runner.continue_after_failed_step.feature +136 -0
- data/vendor/behave/features/runner.default_format.feature +175 -0
- data/vendor/behave/features/runner.dry_run.feature +184 -0
- data/vendor/behave/features/runner.feature_listfile.feature +223 -0
- data/vendor/behave/features/runner.hook_errors.feature +382 -0
- data/vendor/behave/features/runner.multiple_formatters.feature +285 -0
- data/vendor/behave/features/runner.scenario_autoretry.feature +131 -0
- data/vendor/behave/features/runner.select_files_by_regexp.example.feature +71 -0
- data/vendor/behave/features/runner.select_files_by_regexp.feature +84 -0
- data/vendor/behave/features/runner.select_scenarios_by_file_location.feature +403 -0
- data/vendor/behave/features/runner.select_scenarios_by_name.feature +289 -0
- data/vendor/behave/features/runner.select_scenarios_by_tag.feature +225 -0
- data/vendor/behave/features/runner.stop_after_failure.feature +122 -0
- data/vendor/behave/features/runner.tag_logic.feature +67 -0
- data/vendor/behave/features/runner.unknown_formatter.feature +23 -0
- data/vendor/behave/features/runner.use_stage_implementations.feature +126 -0
- data/vendor/behave/features/scenario.description.feature +171 -0
- data/vendor/behave/features/scenario.exclude_from_run.feature +217 -0
- data/vendor/behave/features/scenario_outline.basics.feature +100 -0
- data/vendor/behave/features/scenario_outline.improved.feature +177 -0
- data/vendor/behave/features/scenario_outline.name_annotation.feature +157 -0
- data/vendor/behave/features/scenario_outline.parametrized.feature +401 -0
- data/vendor/behave/features/scenario_outline.tagged_examples.feature +118 -0
- data/vendor/behave/features/step.async_steps.feature +225 -0
- data/vendor/behave/features/step.duplicated_step.feature +106 -0
- data/vendor/behave/features/step.execute_steps.feature +59 -0
- data/vendor/behave/features/step.execute_steps.with_table.feature +65 -0
- data/vendor/behave/features/step.import_other_step_module.feature +103 -0
- data/vendor/behave/features/step.pending_steps.feature +128 -0
- data/vendor/behave/features/step.undefined_steps.feature +307 -0
- data/vendor/behave/features/step.use_step_library.feature +44 -0
- data/vendor/behave/features/step_dialect.generic_steps.feature +189 -0
- data/vendor/behave/features/step_dialect.given_when_then.feature +89 -0
- data/vendor/behave/features/step_param.builtin_types.with_float.feature +239 -0
- data/vendor/behave/features/step_param.builtin_types.with_integer.feature +305 -0
- data/vendor/behave/features/step_param.custom_types.feature +134 -0
- data/vendor/behave/features/steps/behave_active_tags_steps.py +86 -0
- data/vendor/behave/features/steps/behave_context_steps.py +67 -0
- data/vendor/behave/features/steps/behave_model_tag_logic_steps.py +105 -0
- data/vendor/behave/features/steps/behave_model_util.py +105 -0
- data/vendor/behave/features/steps/behave_select_files_steps.py +83 -0
- data/vendor/behave/features/steps/behave_tag_expression_steps.py +166 -0
- data/vendor/behave/features/steps/behave_undefined_steps.py +101 -0
- data/vendor/behave/features/steps/use_steplib_behave4cmd.py +12 -0
- data/vendor/behave/features/summary.undefined_steps.feature +114 -0
- data/vendor/behave/features/tags.active_tags.feature +385 -0
- data/vendor/behave/features/tags.default_tags.feature +104 -0
- data/vendor/behave/features/tags.tag_expression.feature +105 -0
- data/vendor/behave/features/userdata.feature +331 -0
- data/vendor/behave/invoke.yaml +21 -0
- data/vendor/behave/issue.features/README.txt +17 -0
- data/vendor/behave/issue.features/environment.py +97 -0
- data/vendor/behave/issue.features/issue0030.feature +21 -0
- data/vendor/behave/issue.features/issue0031.feature +16 -0
- data/vendor/behave/issue.features/issue0032.feature +28 -0
- data/vendor/behave/issue.features/issue0035.feature +74 -0
- data/vendor/behave/issue.features/issue0040.feature +154 -0
- data/vendor/behave/issue.features/issue0041.feature +135 -0
- data/vendor/behave/issue.features/issue0042.feature +230 -0
- data/vendor/behave/issue.features/issue0044.feature +51 -0
- data/vendor/behave/issue.features/issue0046.feature +77 -0
- data/vendor/behave/issue.features/issue0052.feature +66 -0
- data/vendor/behave/issue.features/issue0059.feature +29 -0
- data/vendor/behave/issue.features/issue0063.feature +102 -0
- data/vendor/behave/issue.features/issue0064.feature +97 -0
- data/vendor/behave/issue.features/issue0065.feature +18 -0
- data/vendor/behave/issue.features/issue0066.feature +80 -0
- data/vendor/behave/issue.features/issue0067.feature +90 -0
- data/vendor/behave/issue.features/issue0069.feature +64 -0
- data/vendor/behave/issue.features/issue0072.feature +32 -0
- data/vendor/behave/issue.features/issue0073.feature +228 -0
- data/vendor/behave/issue.features/issue0075.feature +18 -0
- data/vendor/behave/issue.features/issue0077.feature +89 -0
- data/vendor/behave/issue.features/issue0080.feature +49 -0
- data/vendor/behave/issue.features/issue0081.feature +138 -0
- data/vendor/behave/issue.features/issue0083.feature +69 -0
- data/vendor/behave/issue.features/issue0084.feature +69 -0
- data/vendor/behave/issue.features/issue0085.feature +119 -0
- data/vendor/behave/issue.features/issue0092.feature +66 -0
- data/vendor/behave/issue.features/issue0096.feature +173 -0
- data/vendor/behave/issue.features/issue0099.feature +130 -0
- data/vendor/behave/issue.features/issue0109.feature +60 -0
- data/vendor/behave/issue.features/issue0111.feature +53 -0
- data/vendor/behave/issue.features/issue0112.feature +64 -0
- data/vendor/behave/issue.features/issue0114.feature +118 -0
- data/vendor/behave/issue.features/issue0116.feature +71 -0
- data/vendor/behave/issue.features/issue0125.feature +49 -0
- data/vendor/behave/issue.features/issue0127.feature +64 -0
- data/vendor/behave/issue.features/issue0139.feature +67 -0
- data/vendor/behave/issue.features/issue0142.feature +37 -0
- data/vendor/behave/issue.features/issue0143.feature +54 -0
- data/vendor/behave/issue.features/issue0145.feature +63 -0
- data/vendor/behave/issue.features/issue0148.feature +105 -0
- data/vendor/behave/issue.features/issue0152.feature +52 -0
- data/vendor/behave/issue.features/issue0159.feature +74 -0
- data/vendor/behave/issue.features/issue0162.feature +86 -0
- data/vendor/behave/issue.features/issue0171.feature +16 -0
- data/vendor/behave/issue.features/issue0172.feature +51 -0
- data/vendor/behave/issue.features/issue0175.feature +91 -0
- data/vendor/behave/issue.features/issue0177.feature +40 -0
- data/vendor/behave/issue.features/issue0181.feature +36 -0
- data/vendor/behave/issue.features/issue0184.feature +144 -0
- data/vendor/behave/issue.features/issue0186.feature +12 -0
- data/vendor/behave/issue.features/issue0188.feature +60 -0
- data/vendor/behave/issue.features/issue0191.feature +178 -0
- data/vendor/behave/issue.features/issue0194.feature +215 -0
- data/vendor/behave/issue.features/issue0197.feature +11 -0
- data/vendor/behave/issue.features/issue0216.feature +129 -0
- data/vendor/behave/issue.features/issue0226.feature +51 -0
- data/vendor/behave/issue.features/issue0228.feature +41 -0
- data/vendor/behave/issue.features/issue0230.feature +46 -0
- data/vendor/behave/issue.features/issue0231.feature +77 -0
- data/vendor/behave/issue.features/issue0238.feature +52 -0
- data/vendor/behave/issue.features/issue0251.feature +15 -0
- data/vendor/behave/issue.features/issue0280.feature +118 -0
- data/vendor/behave/issue.features/issue0288.feature +95 -0
- data/vendor/behave/issue.features/issue0300.feature +49 -0
- data/vendor/behave/issue.features/issue0302.feature +91 -0
- data/vendor/behave/issue.features/issue0309.feature +52 -0
- data/vendor/behave/issue.features/issue0330.feature +124 -0
- data/vendor/behave/issue.features/issue0349.feature +9 -0
- data/vendor/behave/issue.features/issue0361.feature +79 -0
- data/vendor/behave/issue.features/issue0383.feature +76 -0
- data/vendor/behave/issue.features/issue0384.feature +103 -0
- data/vendor/behave/issue.features/issue0385.feature +109 -0
- data/vendor/behave/issue.features/issue0424.feature +66 -0
- data/vendor/behave/issue.features/issue0446.feature +116 -0
- data/vendor/behave/issue.features/issue0449.feature +42 -0
- data/vendor/behave/issue.features/issue0453.feature +42 -0
- data/vendor/behave/issue.features/issue0457.feature +65 -0
- data/vendor/behave/issue.features/issue0462.feature +38 -0
- data/vendor/behave/issue.features/issue0476.feature +39 -0
- data/vendor/behave/issue.features/issue0487.feature +92 -0
- data/vendor/behave/issue.features/issue0506.feature +77 -0
- data/vendor/behave/issue.features/issue0510.feature +51 -0
- data/vendor/behave/issue.features/requirements.txt +12 -0
- data/vendor/behave/issue.features/steps/ansi_steps.py +20 -0
- data/vendor/behave/issue.features/steps/behave_hooks_steps.py +10 -0
- data/vendor/behave/issue.features/steps/use_steplib_behave4cmd.py +13 -0
- data/vendor/behave/more.features/formatter.json.validate_output.feature +37 -0
- data/vendor/behave/more.features/steps/tutorial_steps.py +16 -0
- data/vendor/behave/more.features/steps/use_steplib_behave4cmd.py +7 -0
- data/vendor/behave/more.features/tutorial.feature +6 -0
- data/vendor/behave/py.requirements/README.txt +5 -0
- data/vendor/behave/py.requirements/all.txt +16 -0
- data/vendor/behave/py.requirements/basic.txt +21 -0
- data/vendor/behave/py.requirements/develop.txt +28 -0
- data/vendor/behave/py.requirements/docs.txt +6 -0
- data/vendor/behave/py.requirements/json.txt +7 -0
- data/vendor/behave/py.requirements/more_py26.txt +8 -0
- data/vendor/behave/py.requirements/testing.txt +10 -0
- data/vendor/behave/pytest.ini +24 -0
- data/vendor/behave/setup.cfg +29 -0
- data/vendor/behave/setup.py +118 -0
- data/vendor/behave/setuptools_behave.py +130 -0
- data/vendor/behave/tasks/__behave.py +45 -0
- data/vendor/behave/tasks/__init__.py +55 -0
- data/vendor/behave/tasks/__main__.py +70 -0
- data/vendor/behave/tasks/_setup.py +135 -0
- data/vendor/behave/tasks/_vendor/README.rst +35 -0
- data/vendor/behave/tasks/_vendor/invoke.zip +0 -0
- data/vendor/behave/tasks/_vendor/path.py +1725 -0
- data/vendor/behave/tasks/_vendor/pathlib.py +1280 -0
- data/vendor/behave/tasks/_vendor/six.py +868 -0
- data/vendor/behave/tasks/clean.py +246 -0
- data/vendor/behave/tasks/docs.py +97 -0
- data/vendor/behave/tasks/requirements.txt +17 -0
- data/vendor/behave/tasks/test.py +192 -0
- data/vendor/behave/test/__init__.py +0 -0
- data/vendor/behave/test/_importer_candidate.py +3 -0
- data/vendor/behave/test/reporters/__init__.py +0 -0
- data/vendor/behave/test/reporters/test_summary.py +240 -0
- data/vendor/behave/test/test_ansi_escapes.py +73 -0
- data/vendor/behave/test/test_configuration.py +172 -0
- data/vendor/behave/test/test_formatter.py +265 -0
- data/vendor/behave/test/test_formatter_progress.py +39 -0
- data/vendor/behave/test/test_formatter_rerun.py +97 -0
- data/vendor/behave/test/test_formatter_tags.py +57 -0
- data/vendor/behave/test/test_importer.py +151 -0
- data/vendor/behave/test/test_log_capture.py +29 -0
- data/vendor/behave/test/test_matchers.py +236 -0
- data/vendor/behave/test/test_model.py +871 -0
- data/vendor/behave/test/test_parser.py +1590 -0
- data/vendor/behave/test/test_runner.py +1074 -0
- data/vendor/behave/test/test_step_registry.py +96 -0
- data/vendor/behave/test/test_tag_expression.py +506 -0
- data/vendor/behave/test/test_tag_expression2.py +462 -0
- data/vendor/behave/test/test_tag_matcher.py +729 -0
- data/vendor/behave/test/test_userdata.py +184 -0
- data/vendor/behave/tests/README.txt +12 -0
- data/vendor/behave/tests/__init__.py +0 -0
- data/vendor/behave/tests/api/__ONLY_PY34_or_newer.txt +0 -0
- data/vendor/behave/tests/api/__init__.py +0 -0
- data/vendor/behave/tests/api/_test_async_step34.py +130 -0
- data/vendor/behave/tests/api/_test_async_step35.py +75 -0
- data/vendor/behave/tests/api/test_async_step.py +18 -0
- data/vendor/behave/tests/api/testing_support.py +94 -0
- data/vendor/behave/tests/api/testing_support_async.py +21 -0
- data/vendor/behave/tests/issues/test_issue0336.py +66 -0
- data/vendor/behave/tests/issues/test_issue0449.py +55 -0
- data/vendor/behave/tests/issues/test_issue0453.py +62 -0
- data/vendor/behave/tests/issues/test_issue0458.py +54 -0
- data/vendor/behave/tests/issues/test_issue0495.py +65 -0
- data/vendor/behave/tests/unit/__init__.py +0 -0
- data/vendor/behave/tests/unit/test_behave4cmd_command_shell_proc.py +135 -0
- data/vendor/behave/tests/unit/test_capture.py +280 -0
- data/vendor/behave/tests/unit/test_model_core.py +56 -0
- data/vendor/behave/tests/unit/test_textutil.py +267 -0
- data/vendor/behave/tools/test-features/background.feature +9 -0
- data/vendor/behave/tools/test-features/environment.py +8 -0
- data/vendor/behave/tools/test-features/french.feature +11 -0
- data/vendor/behave/tools/test-features/outline.feature +39 -0
- data/vendor/behave/tools/test-features/parse.feature +10 -0
- data/vendor/behave/tools/test-features/step-data.feature +60 -0
- data/vendor/behave/tools/test-features/steps/steps.py +120 -0
- data/vendor/behave/tools/test-features/tags.feature +18 -0
- data/vendor/behave/tox.ini +159 -0
- metadata +562 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Importer module for lazy-loading/importing modules and objects.
|
|
4
|
+
|
|
5
|
+
REQUIRES: importlib (provided in Python2.7, Python3.2...)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import absolute_import
|
|
9
|
+
import importlib
|
|
10
|
+
from behave._types import Unknown
|
|
11
|
+
|
|
12
|
+
def parse_scoped_name(scoped_name):
|
|
13
|
+
"""
|
|
14
|
+
SCHEMA: my.module_name:MyClassName
|
|
15
|
+
EXAMPLE:
|
|
16
|
+
behave.formatter.plain:PlainFormatter
|
|
17
|
+
"""
|
|
18
|
+
scoped_name = scoped_name.strip()
|
|
19
|
+
if "::" in scoped_name:
|
|
20
|
+
# -- ALTERNATIVE: my.module_name::MyClassName
|
|
21
|
+
scoped_name = scoped_name.replace("::", ":")
|
|
22
|
+
module_name, object_name = scoped_name.rsplit(":", 1)
|
|
23
|
+
return module_name, object_name
|
|
24
|
+
|
|
25
|
+
def load_module(module_name):
|
|
26
|
+
return importlib.import_module(module_name)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class LazyObject(object):
|
|
30
|
+
"""
|
|
31
|
+
Provides a placeholder for an object that should be loaded lazily.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, module_name, object_name=None):
|
|
35
|
+
if ":" in module_name and not object_name:
|
|
36
|
+
module_name, object_name = parse_scoped_name(module_name)
|
|
37
|
+
assert ":" not in module_name
|
|
38
|
+
self.module_name = module_name
|
|
39
|
+
self.object_name = object_name
|
|
40
|
+
self.resolved_object = None
|
|
41
|
+
|
|
42
|
+
def __get__(self, obj=None, type=None): # pylint: disable=redefined-builtin
|
|
43
|
+
"""
|
|
44
|
+
Implement descriptor protocol,
|
|
45
|
+
useful if this class is used as attribute.
|
|
46
|
+
:return: Real object (lazy-loaded if necessary).
|
|
47
|
+
:raise ImportError: If module or object cannot be imported.
|
|
48
|
+
"""
|
|
49
|
+
__pychecker__ = "unusednames=obj,type"
|
|
50
|
+
resolved_object = None
|
|
51
|
+
if not self.resolved_object:
|
|
52
|
+
# -- SETUP-ONCE: Lazy load the real object.
|
|
53
|
+
module = load_module(self.module_name)
|
|
54
|
+
resolved_object = getattr(module, self.object_name, Unknown)
|
|
55
|
+
if resolved_object is Unknown:
|
|
56
|
+
msg = "%s: %s is Unknown" % (self.module_name, self.object_name)
|
|
57
|
+
raise ImportError(msg)
|
|
58
|
+
self.resolved_object = resolved_object
|
|
59
|
+
return resolved_object
|
|
60
|
+
|
|
61
|
+
def __set__(self, obj, value):
|
|
62
|
+
"""Implement descriptor protocol."""
|
|
63
|
+
__pychecker__ = "unusednames=obj"
|
|
64
|
+
self.resolved_object = value
|
|
65
|
+
|
|
66
|
+
def get(self):
|
|
67
|
+
return self.__get__()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class LazyDict(dict):
|
|
71
|
+
"""
|
|
72
|
+
Provides a dict that supports lazy loading of objects.
|
|
73
|
+
A LazyObject is provided as placeholder for a value that should be
|
|
74
|
+
loaded lazily.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __getitem__(self, key):
|
|
78
|
+
"""
|
|
79
|
+
Provides access to stored dict values.
|
|
80
|
+
Implements lazy loading of item value (if necessary).
|
|
81
|
+
When lazy object is loaded, its value with the dict is replaced
|
|
82
|
+
with the real value.
|
|
83
|
+
|
|
84
|
+
:param key: Key to access the value of an item in the dict.
|
|
85
|
+
:return: value
|
|
86
|
+
:raises: KeyError if item is not found
|
|
87
|
+
:raises: ImportError for a LazyObject that cannot be imported.
|
|
88
|
+
"""
|
|
89
|
+
value = dict.__getitem__(self, key)
|
|
90
|
+
if isinstance(value, LazyObject):
|
|
91
|
+
# -- LAZY-LOADING MECHANISM: Load object and replace with lazy one.
|
|
92
|
+
value = value.__get__()
|
|
93
|
+
self[key] = value
|
|
94
|
+
return value
|
|
95
|
+
|
|
96
|
+
def load_all(self, strict=False):
|
|
97
|
+
for key in self.keys():
|
|
98
|
+
try:
|
|
99
|
+
self.__getitem__(key)
|
|
100
|
+
except ImportError:
|
|
101
|
+
if strict:
|
|
102
|
+
raise
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Read behave's JSON output files and store retrieved information in
|
|
4
|
+
:mod:`behave.model` elements.
|
|
5
|
+
|
|
6
|
+
Utility to retrieve runtime information from behave's JSON output.
|
|
7
|
+
|
|
8
|
+
REQUIRES: Python >= 2.6 (json module is part of Python standard library)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import absolute_import
|
|
12
|
+
import codecs
|
|
13
|
+
from behave import model
|
|
14
|
+
from behave.model_core import Status
|
|
15
|
+
try:
|
|
16
|
+
import json
|
|
17
|
+
except ImportError:
|
|
18
|
+
# -- PYTHON 2.5 backward compatible: Use simplejson module.
|
|
19
|
+
import simplejson as json
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__author__ = "Jens Engel"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ----------------------------------------------------------------------------
|
|
26
|
+
# FUNCTIONS:
|
|
27
|
+
# ----------------------------------------------------------------------------
|
|
28
|
+
def parse(json_filename, encoding="UTF-8"):
|
|
29
|
+
"""
|
|
30
|
+
Reads behave JSON output file back in and stores information in
|
|
31
|
+
behave model elements.
|
|
32
|
+
|
|
33
|
+
:param json_filename: JSON filename to process.
|
|
34
|
+
:return: List of feature objects.
|
|
35
|
+
"""
|
|
36
|
+
with codecs.open(json_filename, "rU", encoding=encoding) as input_file:
|
|
37
|
+
json_data = json.load(input_file, encoding=encoding)
|
|
38
|
+
json_processor = JsonParser()
|
|
39
|
+
features = json_processor.parse_features(json_data)
|
|
40
|
+
return features
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ----------------------------------------------------------------------------
|
|
44
|
+
# CLASSES:
|
|
45
|
+
# ----------------------------------------------------------------------------
|
|
46
|
+
class JsonParser(object):
|
|
47
|
+
|
|
48
|
+
def __init__(self):
|
|
49
|
+
self.current_scenario_outline = None
|
|
50
|
+
|
|
51
|
+
def parse_features(self, json_data):
|
|
52
|
+
assert isinstance(json_data, list)
|
|
53
|
+
features = []
|
|
54
|
+
json_features = json_data
|
|
55
|
+
for json_feature in json_features:
|
|
56
|
+
feature = self.parse_feature(json_feature)
|
|
57
|
+
features.append(feature)
|
|
58
|
+
return features
|
|
59
|
+
|
|
60
|
+
def parse_feature(self, json_feature):
|
|
61
|
+
name = json_feature.get("name", u"")
|
|
62
|
+
keyword = json_feature.get("keyword", None)
|
|
63
|
+
tags = json_feature.get("tags", [])
|
|
64
|
+
description = json_feature.get("description", [])
|
|
65
|
+
location = json_feature.get("location", u"")
|
|
66
|
+
filename, line = location.split(":")
|
|
67
|
+
feature = model.Feature(filename, line, keyword, name, tags, description)
|
|
68
|
+
|
|
69
|
+
json_elements = json_feature.get("elements", [])
|
|
70
|
+
for json_element in json_elements:
|
|
71
|
+
self.add_feature_element(feature, json_element)
|
|
72
|
+
return feature
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def add_feature_element(self, feature, json_element):
|
|
76
|
+
datatype = json_element.get("type", u"")
|
|
77
|
+
category = datatype.lower()
|
|
78
|
+
if category == "background":
|
|
79
|
+
background = self.parse_background(json_element)
|
|
80
|
+
feature.background = background
|
|
81
|
+
elif category == "scenario":
|
|
82
|
+
scenario = self.parse_scenario(json_element)
|
|
83
|
+
feature.add_scenario(scenario)
|
|
84
|
+
elif category == "scenario_outline":
|
|
85
|
+
scenario_outline = self.parse_scenario_outline(json_element)
|
|
86
|
+
feature.add_scenario(scenario_outline)
|
|
87
|
+
self.current_scenario_outline = scenario_outline
|
|
88
|
+
# elif category == "examples":
|
|
89
|
+
# examples = self.parse_examples(json_element)
|
|
90
|
+
# self.current_scenario_outline.examples = examples
|
|
91
|
+
else:
|
|
92
|
+
raise KeyError("Invalid feature-element keyword: %s" % category)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def parse_background(self, json_element):
|
|
96
|
+
"""
|
|
97
|
+
self.add_feature_element({
|
|
98
|
+
'keyword': background.keyword,
|
|
99
|
+
'location': background.location,
|
|
100
|
+
'steps': [],
|
|
101
|
+
})
|
|
102
|
+
"""
|
|
103
|
+
keyword = json_element.get("keyword", u"")
|
|
104
|
+
name = json_element.get("name", u"")
|
|
105
|
+
location = json_element.get("location", u"")
|
|
106
|
+
json_steps = json_element.get("steps", [])
|
|
107
|
+
steps = self.parse_steps(json_steps)
|
|
108
|
+
filename, line = location.split(":")
|
|
109
|
+
background = model.Background(filename, line, keyword, name, steps)
|
|
110
|
+
return background
|
|
111
|
+
|
|
112
|
+
def parse_scenario(self, json_element):
|
|
113
|
+
"""
|
|
114
|
+
self.add_feature_element({
|
|
115
|
+
'keyword': scenario.keyword,
|
|
116
|
+
'name': scenario.name,
|
|
117
|
+
'tags': scenario.tags,
|
|
118
|
+
'location': scenario.location,
|
|
119
|
+
'steps': [],
|
|
120
|
+
})
|
|
121
|
+
"""
|
|
122
|
+
keyword = json_element.get("keyword", u"")
|
|
123
|
+
name = json_element.get("name", u"")
|
|
124
|
+
description = json_element.get("description", [])
|
|
125
|
+
tags = json_element.get("tags", [])
|
|
126
|
+
location = json_element.get("location", u"")
|
|
127
|
+
json_steps = json_element.get("steps", [])
|
|
128
|
+
steps = self.parse_steps(json_steps)
|
|
129
|
+
filename, line = location.split(":")
|
|
130
|
+
scenario = model.Scenario(filename, line, keyword, name, tags, steps)
|
|
131
|
+
scenario.description = description
|
|
132
|
+
return scenario
|
|
133
|
+
|
|
134
|
+
def parse_scenario_outline(self, json_element):
|
|
135
|
+
"""
|
|
136
|
+
self.add_feature_element({
|
|
137
|
+
'keyword': scenario_outline.keyword,
|
|
138
|
+
'name': scenario_outline.name,
|
|
139
|
+
'tags': scenario_outline.tags,
|
|
140
|
+
'location': scenario_outline.location,
|
|
141
|
+
'steps': [],
|
|
142
|
+
'examples': [],
|
|
143
|
+
})
|
|
144
|
+
"""
|
|
145
|
+
keyword = json_element.get("keyword", u"")
|
|
146
|
+
name = json_element.get("name", u"")
|
|
147
|
+
description = json_element.get("description", [])
|
|
148
|
+
tags = json_element.get("tags", [])
|
|
149
|
+
location = json_element.get("location", u"")
|
|
150
|
+
json_steps = json_element.get("steps", [])
|
|
151
|
+
json_examples = json_element.get("examples", [])
|
|
152
|
+
steps = self.parse_steps(json_steps)
|
|
153
|
+
examples = []
|
|
154
|
+
if json_examples:
|
|
155
|
+
# pylint: disable=redefined-variable-type
|
|
156
|
+
examples = self.parse_examples(json_examples)
|
|
157
|
+
filename, line = location.split(":")
|
|
158
|
+
scenario_outline = model.ScenarioOutline(filename, line, keyword, name,
|
|
159
|
+
tags=tags, steps=steps,
|
|
160
|
+
examples=examples)
|
|
161
|
+
scenario_outline.description = description
|
|
162
|
+
return scenario_outline
|
|
163
|
+
|
|
164
|
+
def parse_steps(self, json_steps):
|
|
165
|
+
steps = []
|
|
166
|
+
for json_step in json_steps:
|
|
167
|
+
step = self.parse_step(json_step)
|
|
168
|
+
steps.append(step)
|
|
169
|
+
return steps
|
|
170
|
+
|
|
171
|
+
def parse_step(self, json_element):
|
|
172
|
+
"""
|
|
173
|
+
s = {
|
|
174
|
+
'keyword': step.keyword,
|
|
175
|
+
'step_type': step.step_type,
|
|
176
|
+
'name': step.name,
|
|
177
|
+
'location': step.location,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if step.text:
|
|
181
|
+
s['text'] = step.text
|
|
182
|
+
if step.table:
|
|
183
|
+
s['table'] = self.make_table(step.table)
|
|
184
|
+
element = self.current_feature_element
|
|
185
|
+
element['steps'].append(s)
|
|
186
|
+
"""
|
|
187
|
+
keyword = json_element.get("keyword", u"")
|
|
188
|
+
name = json_element.get("name", u"")
|
|
189
|
+
step_type = json_element.get("step_type", u"")
|
|
190
|
+
location = json_element.get("location", u"")
|
|
191
|
+
text = json_element.get("text", None)
|
|
192
|
+
if isinstance(text, list):
|
|
193
|
+
text = "\n".join(text)
|
|
194
|
+
table = None
|
|
195
|
+
json_table = json_element.get("table", None)
|
|
196
|
+
if json_table:
|
|
197
|
+
table = self.parse_table(json_table)
|
|
198
|
+
filename, line = location.split(":")
|
|
199
|
+
step = model.Step(filename, line, keyword, step_type, name)
|
|
200
|
+
step.text = text
|
|
201
|
+
step.table = table
|
|
202
|
+
json_result = json_element.get("result", None)
|
|
203
|
+
if json_result:
|
|
204
|
+
self.add_step_result(step, json_result)
|
|
205
|
+
return step
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def add_step_result(step, json_result):
|
|
209
|
+
"""
|
|
210
|
+
steps = self.current_feature_element['steps']
|
|
211
|
+
steps[self._step_index]['result'] = {
|
|
212
|
+
'status': result.status.name,
|
|
213
|
+
'duration': result.duration,
|
|
214
|
+
}
|
|
215
|
+
"""
|
|
216
|
+
status_name = json_result.get("status", u"")
|
|
217
|
+
duration = json_result.get("duration", 0)
|
|
218
|
+
error_message = json_result.get("error_message", None)
|
|
219
|
+
if isinstance(error_message, list):
|
|
220
|
+
error_message = "\n".join(error_message)
|
|
221
|
+
step.status = Status.from_name(status_name)
|
|
222
|
+
step.duration = duration
|
|
223
|
+
step.error_message = error_message
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def parse_table(json_table):
|
|
227
|
+
"""
|
|
228
|
+
table_data = {
|
|
229
|
+
'headings': table.headings,
|
|
230
|
+
'rows': [ list(row) for row in table.rows ]
|
|
231
|
+
}
|
|
232
|
+
return table_data
|
|
233
|
+
"""
|
|
234
|
+
headings = json_table.get("headings", [])
|
|
235
|
+
rows = json_table.get("rows", [])
|
|
236
|
+
table = model.Table(headings, rows=rows)
|
|
237
|
+
return table
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def parse_examples(self, json_element):
|
|
241
|
+
"""
|
|
242
|
+
e = {
|
|
243
|
+
'keyword': examples.keyword,
|
|
244
|
+
'name': examples.name,
|
|
245
|
+
'location': examples.location,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if examples.table:
|
|
249
|
+
e['table'] = self.make_table(examples.table)
|
|
250
|
+
|
|
251
|
+
element = self.current_feature_element
|
|
252
|
+
element['examples'].append(e)
|
|
253
|
+
"""
|
|
254
|
+
keyword = json_element.get("keyword", u"")
|
|
255
|
+
name = json_element.get("name", u"")
|
|
256
|
+
location = json_element.get("location", u"")
|
|
257
|
+
|
|
258
|
+
table = None
|
|
259
|
+
json_table = json_element.get("table", None)
|
|
260
|
+
if json_table:
|
|
261
|
+
table = self.parse_table(json_table)
|
|
262
|
+
filename, line = location.split(":")
|
|
263
|
+
examples = model.Examples(filename, line, keyword, name, table)
|
|
264
|
+
return examples
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from __future__ import absolute_import, print_function
|
|
4
|
+
from logging.handlers import BufferingHandler
|
|
5
|
+
import logging
|
|
6
|
+
import functools
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RecordFilter(object):
|
|
11
|
+
"""Implement logging record filtering as per the configuration
|
|
12
|
+
--logging-filter option.
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self, names):
|
|
15
|
+
self.include = set()
|
|
16
|
+
self.exclude = set()
|
|
17
|
+
for name in names.split(','):
|
|
18
|
+
if name[0] == '-':
|
|
19
|
+
self.exclude.add(name[1:])
|
|
20
|
+
else:
|
|
21
|
+
self.include.add(name)
|
|
22
|
+
|
|
23
|
+
def filter(self, record):
|
|
24
|
+
if self.exclude:
|
|
25
|
+
return record.name not in self.exclude
|
|
26
|
+
return record.name in self.include
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# originally from nostetsts logcapture plugin
|
|
30
|
+
class LoggingCapture(BufferingHandler):
|
|
31
|
+
"""Capture logging events in a memory buffer for later display or query.
|
|
32
|
+
|
|
33
|
+
Captured logging events are stored on the attribute
|
|
34
|
+
:attr:`~LoggingCapture.buffer`:
|
|
35
|
+
|
|
36
|
+
.. attribute:: buffer
|
|
37
|
+
|
|
38
|
+
This is a list of captured logging events as `logging.LogRecords`_.
|
|
39
|
+
|
|
40
|
+
.. _`logging.LogRecords`:
|
|
41
|
+
http://docs.python.org/library/logging.html#logrecord-objects
|
|
42
|
+
|
|
43
|
+
By default the format of the messages will be::
|
|
44
|
+
|
|
45
|
+
'%(levelname)s:%(name)s:%(message)s'
|
|
46
|
+
|
|
47
|
+
This may be overridden using standard logging formatter names in the
|
|
48
|
+
configuration variable ``logging_format``.
|
|
49
|
+
|
|
50
|
+
The level of logging captured is set to ``logging.NOTSET`` by default. You
|
|
51
|
+
may override this using the configuration setting ``logging_level`` (which
|
|
52
|
+
is set to a level name.)
|
|
53
|
+
|
|
54
|
+
Finally there may be `filtering of logging events`__ specified by the
|
|
55
|
+
configuration variable ``logging_filter``.
|
|
56
|
+
|
|
57
|
+
.. __: behave.html#command-line-arguments
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, config, level=None):
|
|
61
|
+
BufferingHandler.__init__(self, 1000)
|
|
62
|
+
self.config = config
|
|
63
|
+
self.old_handlers = []
|
|
64
|
+
self.old_level = None
|
|
65
|
+
|
|
66
|
+
# set my formatter
|
|
67
|
+
log_format = datefmt = None
|
|
68
|
+
if config.logging_format:
|
|
69
|
+
log_format = config.logging_format
|
|
70
|
+
else:
|
|
71
|
+
log_format = '%(levelname)s:%(name)s:%(message)s'
|
|
72
|
+
if config.logging_datefmt:
|
|
73
|
+
datefmt = config.logging_datefmt
|
|
74
|
+
formatter = logging.Formatter(log_format, datefmt)
|
|
75
|
+
self.setFormatter(formatter)
|
|
76
|
+
|
|
77
|
+
# figure the level we're logging at
|
|
78
|
+
if level is not None:
|
|
79
|
+
self.level = level
|
|
80
|
+
elif config.logging_level:
|
|
81
|
+
self.level = config.logging_level
|
|
82
|
+
else:
|
|
83
|
+
self.level = logging.NOTSET
|
|
84
|
+
|
|
85
|
+
# construct my filter
|
|
86
|
+
if config.logging_filter:
|
|
87
|
+
self.addFilter(RecordFilter(config.logging_filter))
|
|
88
|
+
|
|
89
|
+
def __bool__(self):
|
|
90
|
+
return bool(self.buffer)
|
|
91
|
+
|
|
92
|
+
def flush(self):
|
|
93
|
+
pass # do nothing
|
|
94
|
+
|
|
95
|
+
def truncate(self):
|
|
96
|
+
self.buffer = []
|
|
97
|
+
|
|
98
|
+
def getvalue(self):
|
|
99
|
+
return '\n'.join(self.formatter.format(r) for r in self.buffer)
|
|
100
|
+
|
|
101
|
+
def find_event(self, pattern):
|
|
102
|
+
"""Search through the buffer for a message that matches the given
|
|
103
|
+
regular expression.
|
|
104
|
+
|
|
105
|
+
Returns boolean indicating whether a match was found.
|
|
106
|
+
"""
|
|
107
|
+
pattern = re.compile(pattern)
|
|
108
|
+
for record in self.buffer:
|
|
109
|
+
if pattern.search(record.getMessage()) is not None:
|
|
110
|
+
return True
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def any_errors(self):
|
|
114
|
+
"""Search through the buffer for any ERROR or CRITICAL events.
|
|
115
|
+
|
|
116
|
+
Returns boolean indicating whether a match was found.
|
|
117
|
+
"""
|
|
118
|
+
return any(record for record in self.buffer
|
|
119
|
+
if record.levelname in ('ERROR', 'CRITICAL'))
|
|
120
|
+
|
|
121
|
+
def inveigle(self):
|
|
122
|
+
"""Turn on logging capture by replacing all existing handlers
|
|
123
|
+
configured in the logging module.
|
|
124
|
+
|
|
125
|
+
If the config var logging_clear_handlers is set then we also remove
|
|
126
|
+
all existing handlers.
|
|
127
|
+
|
|
128
|
+
We also set the level of the root logger.
|
|
129
|
+
|
|
130
|
+
The opposite of this is :meth:`~LoggingCapture.abandon`.
|
|
131
|
+
"""
|
|
132
|
+
root_logger = logging.getLogger()
|
|
133
|
+
if self.config.logging_clear_handlers:
|
|
134
|
+
# kill off all the other log handlers
|
|
135
|
+
for logger in logging.Logger.manager.loggerDict.values():
|
|
136
|
+
if hasattr(logger, "handlers"):
|
|
137
|
+
for handler in logger.handlers:
|
|
138
|
+
self.old_handlers.append((logger, handler))
|
|
139
|
+
logger.removeHandler(handler)
|
|
140
|
+
|
|
141
|
+
# sanity check: remove any existing LoggingCapture
|
|
142
|
+
for handler in root_logger.handlers[:]:
|
|
143
|
+
if isinstance(handler, LoggingCapture):
|
|
144
|
+
root_logger.handlers.remove(handler)
|
|
145
|
+
elif self.config.logging_clear_handlers:
|
|
146
|
+
self.old_handlers.append((root_logger, handler))
|
|
147
|
+
root_logger.removeHandler(handler)
|
|
148
|
+
|
|
149
|
+
# right, we're it now
|
|
150
|
+
root_logger.addHandler(self)
|
|
151
|
+
|
|
152
|
+
# capture the level we're interested in
|
|
153
|
+
self.old_level = root_logger.level
|
|
154
|
+
root_logger.setLevel(self.level)
|
|
155
|
+
|
|
156
|
+
def abandon(self):
|
|
157
|
+
"""Turn off logging capture.
|
|
158
|
+
|
|
159
|
+
If other handlers were removed by :meth:`~LoggingCapture.inveigle` then
|
|
160
|
+
they are reinstated.
|
|
161
|
+
"""
|
|
162
|
+
root_logger = logging.getLogger()
|
|
163
|
+
for handler in root_logger.handlers[:]:
|
|
164
|
+
if handler is self:
|
|
165
|
+
root_logger.handlers.remove(handler)
|
|
166
|
+
|
|
167
|
+
if self.config.logging_clear_handlers:
|
|
168
|
+
for logger, handler in self.old_handlers:
|
|
169
|
+
logger.addHandler(handler)
|
|
170
|
+
|
|
171
|
+
if self.old_level is not None:
|
|
172
|
+
# -- RESTORE: Old log.level before inveigle() was used.
|
|
173
|
+
root_logger.setLevel(self.old_level)
|
|
174
|
+
self.old_level = None
|
|
175
|
+
|
|
176
|
+
# pre-1.2 backwards compatibility
|
|
177
|
+
MemoryHandler = LoggingCapture
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def capture(*args, **kw):
|
|
181
|
+
"""Decorator to wrap an *environment file function* in log file capture.
|
|
182
|
+
|
|
183
|
+
It configures the logging capture using the *behave* context - the first
|
|
184
|
+
argument to the function being decorated (so don't use this to decorate
|
|
185
|
+
something that doesn't have *context* as the first argument.)
|
|
186
|
+
|
|
187
|
+
The basic usage is:
|
|
188
|
+
|
|
189
|
+
.. code-block: python
|
|
190
|
+
|
|
191
|
+
@capture
|
|
192
|
+
def after_scenario(context, scenario):
|
|
193
|
+
...
|
|
194
|
+
|
|
195
|
+
The function prints any captured logging (at the level determined by the
|
|
196
|
+
``log_level`` configuration setting) directly to stdout, regardless of
|
|
197
|
+
error conditions.
|
|
198
|
+
|
|
199
|
+
It is mostly useful for debugging in situations where you are seeing a
|
|
200
|
+
message like::
|
|
201
|
+
|
|
202
|
+
No handlers could be found for logger "name"
|
|
203
|
+
|
|
204
|
+
The decorator takes an optional "level" keyword argument which limits the
|
|
205
|
+
level of logging captured, overriding the level in the run's configuration:
|
|
206
|
+
|
|
207
|
+
.. code-block: python
|
|
208
|
+
|
|
209
|
+
@capture(level=logging.ERROR)
|
|
210
|
+
def after_scenario(context, scenario):
|
|
211
|
+
...
|
|
212
|
+
|
|
213
|
+
This would limit the logging captured to just ERROR and above, and thus
|
|
214
|
+
only display logged events if they are interesting.
|
|
215
|
+
"""
|
|
216
|
+
def create_decorator(func, level=None):
|
|
217
|
+
def f(context, *args):
|
|
218
|
+
h = LoggingCapture(context.config, level=level)
|
|
219
|
+
h.inveigle()
|
|
220
|
+
try:
|
|
221
|
+
func(context, *args)
|
|
222
|
+
finally:
|
|
223
|
+
h.abandon()
|
|
224
|
+
v = h.getvalue()
|
|
225
|
+
if v:
|
|
226
|
+
print("Captured Logging:")
|
|
227
|
+
print(v)
|
|
228
|
+
return f
|
|
229
|
+
|
|
230
|
+
if not args:
|
|
231
|
+
return functools.partial(create_decorator, level=kw.get("level"))
|
|
232
|
+
else:
|
|
233
|
+
return create_decorator(args[0])
|