busser-behave 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,1280 @@
|
|
1
|
+
import fnmatch
|
2
|
+
import functools
|
3
|
+
import io
|
4
|
+
import ntpath
|
5
|
+
import os
|
6
|
+
import posixpath
|
7
|
+
import re
|
8
|
+
import sys
|
9
|
+
import time
|
10
|
+
from collections import Sequence
|
11
|
+
from contextlib import contextmanager
|
12
|
+
from errno import EINVAL, ENOENT
|
13
|
+
from operator import attrgetter
|
14
|
+
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
|
15
|
+
try:
|
16
|
+
from urllib import quote as urlquote, quote as urlquote_from_bytes
|
17
|
+
except ImportError:
|
18
|
+
from urllib.parse import quote as urlquote, quote_from_bytes as urlquote_from_bytes
|
19
|
+
|
20
|
+
|
21
|
+
try:
|
22
|
+
intern = intern
|
23
|
+
except NameError:
|
24
|
+
intern = sys.intern
|
25
|
+
try:
|
26
|
+
basestring = basestring
|
27
|
+
except NameError:
|
28
|
+
basestring = str
|
29
|
+
|
30
|
+
supports_symlinks = True
|
31
|
+
try:
|
32
|
+
import nt
|
33
|
+
except ImportError:
|
34
|
+
nt = None
|
35
|
+
else:
|
36
|
+
if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2):
|
37
|
+
from nt import _getfinalpathname
|
38
|
+
else:
|
39
|
+
supports_symlinks = False
|
40
|
+
_getfinalpathname = None
|
41
|
+
|
42
|
+
|
43
|
+
__all__ = [
|
44
|
+
"PurePath", "PurePosixPath", "PureWindowsPath",
|
45
|
+
"Path", "PosixPath", "WindowsPath",
|
46
|
+
]
|
47
|
+
|
48
|
+
#
|
49
|
+
# Internals
|
50
|
+
#
|
51
|
+
|
52
|
+
_py2 = sys.version_info < (3,)
|
53
|
+
_py2_fs_encoding = 'ascii'
|
54
|
+
|
55
|
+
def _py2_fsencode(parts):
|
56
|
+
# py2 => minimal unicode support
|
57
|
+
return [part.encode(_py2_fs_encoding) if isinstance(part, unicode)
|
58
|
+
else part for part in parts]
|
59
|
+
|
60
|
+
def _is_wildcard_pattern(pat):
|
61
|
+
# Whether this pattern needs actual matching using fnmatch, or can
|
62
|
+
# be looked up directly as a file.
|
63
|
+
return "*" in pat or "?" in pat or "[" in pat
|
64
|
+
|
65
|
+
|
66
|
+
class _Flavour(object):
|
67
|
+
"""A flavour implements a particular (platform-specific) set of path
|
68
|
+
semantics."""
|
69
|
+
|
70
|
+
def __init__(self):
|
71
|
+
self.join = self.sep.join
|
72
|
+
|
73
|
+
def parse_parts(self, parts):
|
74
|
+
if _py2:
|
75
|
+
parts = _py2_fsencode(parts)
|
76
|
+
parsed = []
|
77
|
+
sep = self.sep
|
78
|
+
altsep = self.altsep
|
79
|
+
drv = root = ''
|
80
|
+
it = reversed(parts)
|
81
|
+
for part in it:
|
82
|
+
if not part:
|
83
|
+
continue
|
84
|
+
if altsep:
|
85
|
+
part = part.replace(altsep, sep)
|
86
|
+
drv, root, rel = self.splitroot(part)
|
87
|
+
if sep in rel:
|
88
|
+
for x in reversed(rel.split(sep)):
|
89
|
+
if x and x != '.':
|
90
|
+
parsed.append(intern(x))
|
91
|
+
else:
|
92
|
+
if rel and rel != '.':
|
93
|
+
parsed.append(intern(rel))
|
94
|
+
if drv or root:
|
95
|
+
if not drv:
|
96
|
+
# If no drive is present, try to find one in the previous
|
97
|
+
# parts. This makes the result of parsing e.g.
|
98
|
+
# ("C:", "/", "a") reasonably intuitive.
|
99
|
+
for part in it:
|
100
|
+
drv = self.splitroot(part)[0]
|
101
|
+
if drv:
|
102
|
+
break
|
103
|
+
break
|
104
|
+
if drv or root:
|
105
|
+
parsed.append(drv + root)
|
106
|
+
parsed.reverse()
|
107
|
+
return drv, root, parsed
|
108
|
+
|
109
|
+
def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
|
110
|
+
"""
|
111
|
+
Join the two paths represented by the respective
|
112
|
+
(drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
|
113
|
+
"""
|
114
|
+
if root2:
|
115
|
+
if not drv2 and drv:
|
116
|
+
return drv, root2, [drv + root2] + parts2[1:]
|
117
|
+
elif drv2:
|
118
|
+
if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
|
119
|
+
# Same drive => second path is relative to the first
|
120
|
+
return drv, root, parts + parts2[1:]
|
121
|
+
else:
|
122
|
+
# Second path is non-anchored (common case)
|
123
|
+
return drv, root, parts + parts2
|
124
|
+
return drv2, root2, parts2
|
125
|
+
|
126
|
+
|
127
|
+
class _WindowsFlavour(_Flavour):
|
128
|
+
# Reference for Windows paths can be found at
|
129
|
+
# http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
|
130
|
+
|
131
|
+
sep = '\\'
|
132
|
+
altsep = '/'
|
133
|
+
has_drv = True
|
134
|
+
pathmod = ntpath
|
135
|
+
|
136
|
+
is_supported = (nt is not None)
|
137
|
+
|
138
|
+
drive_letters = (
|
139
|
+
set(chr(x) for x in range(ord('a'), ord('z') + 1)) |
|
140
|
+
set(chr(x) for x in range(ord('A'), ord('Z') + 1))
|
141
|
+
)
|
142
|
+
ext_namespace_prefix = '\\\\?\\'
|
143
|
+
|
144
|
+
reserved_names = (
|
145
|
+
set(['CON', 'PRN', 'AUX', 'NUL']) |
|
146
|
+
set(['COM%d' % i for i in range(1, 10)]) |
|
147
|
+
set(['LPT%d' % i for i in range(1, 10)])
|
148
|
+
)
|
149
|
+
|
150
|
+
# Interesting findings about extended paths:
|
151
|
+
# - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
|
152
|
+
# but '\\?\c:/a' is not
|
153
|
+
# - extended paths are always absolute; "relative" extended paths will
|
154
|
+
# fail.
|
155
|
+
|
156
|
+
def splitroot(self, part, sep=sep):
|
157
|
+
first = part[0:1]
|
158
|
+
second = part[1:2]
|
159
|
+
if (second == sep and first == sep):
|
160
|
+
# XXX extended paths should also disable the collapsing of "."
|
161
|
+
# components (according to MSDN docs).
|
162
|
+
prefix, part = self._split_extended_path(part)
|
163
|
+
first = part[0:1]
|
164
|
+
second = part[1:2]
|
165
|
+
else:
|
166
|
+
prefix = ''
|
167
|
+
third = part[2:3]
|
168
|
+
if (second == sep and first == sep and third != sep):
|
169
|
+
# is a UNC path:
|
170
|
+
# vvvvvvvvvvvvvvvvvvvvv root
|
171
|
+
# \\machine\mountpoint\directory\etc\...
|
172
|
+
# directory ^^^^^^^^^^^^^^
|
173
|
+
index = part.find(sep, 2)
|
174
|
+
if index != -1:
|
175
|
+
index2 = part.find(sep, index + 1)
|
176
|
+
# a UNC path can't have two slashes in a row
|
177
|
+
# (after the initial two)
|
178
|
+
if index2 != index + 1:
|
179
|
+
if index2 == -1:
|
180
|
+
index2 = len(part)
|
181
|
+
if prefix:
|
182
|
+
return prefix + part[1:index2], sep, part[index2+1:]
|
183
|
+
else:
|
184
|
+
return part[:index2], sep, part[index2+1:]
|
185
|
+
drv = root = ''
|
186
|
+
if second == ':' and first in self.drive_letters:
|
187
|
+
drv = part[:2]
|
188
|
+
part = part[2:]
|
189
|
+
first = third
|
190
|
+
if first == sep:
|
191
|
+
root = first
|
192
|
+
part = part.lstrip(sep)
|
193
|
+
return prefix + drv, root, part
|
194
|
+
|
195
|
+
def casefold(self, s):
|
196
|
+
return s.lower()
|
197
|
+
|
198
|
+
def casefold_parts(self, parts):
|
199
|
+
return [p.lower() for p in parts]
|
200
|
+
|
201
|
+
def resolve(self, path):
|
202
|
+
s = str(path)
|
203
|
+
if not s:
|
204
|
+
return os.getcwd()
|
205
|
+
if _getfinalpathname is not None:
|
206
|
+
return self._ext_to_normal(_getfinalpathname(s))
|
207
|
+
# Means fallback on absolute
|
208
|
+
return None
|
209
|
+
|
210
|
+
def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
|
211
|
+
prefix = ''
|
212
|
+
if s.startswith(ext_prefix):
|
213
|
+
prefix = s[:4]
|
214
|
+
s = s[4:]
|
215
|
+
if s.startswith('UNC\\'):
|
216
|
+
prefix += s[:3]
|
217
|
+
s = '\\' + s[3:]
|
218
|
+
return prefix, s
|
219
|
+
|
220
|
+
def _ext_to_normal(self, s):
|
221
|
+
# Turn back an extended path into a normal DOS-like path
|
222
|
+
return self._split_extended_path(s)[1]
|
223
|
+
|
224
|
+
def is_reserved(self, parts):
|
225
|
+
# NOTE: the rules for reserved names seem somewhat complicated
|
226
|
+
# (e.g. r"..\NUL" is reserved but not r"foo\NUL").
|
227
|
+
# We err on the side of caution and return True for paths which are
|
228
|
+
# not considered reserved by Windows.
|
229
|
+
if not parts:
|
230
|
+
return False
|
231
|
+
if parts[0].startswith('\\\\'):
|
232
|
+
# UNC paths are never reserved
|
233
|
+
return False
|
234
|
+
return parts[-1].partition('.')[0].upper() in self.reserved_names
|
235
|
+
|
236
|
+
def make_uri(self, path):
|
237
|
+
# Under Windows, file URIs use the UTF-8 encoding.
|
238
|
+
drive = path.drive
|
239
|
+
if len(drive) == 2 and drive[1] == ':':
|
240
|
+
# It's a path on a local drive => 'file:///c:/a/b'
|
241
|
+
rest = path.as_posix()[2:].lstrip('/')
|
242
|
+
return 'file:///%s/%s' % (
|
243
|
+
drive, urlquote_from_bytes(rest.encode('utf-8')))
|
244
|
+
else:
|
245
|
+
# It's a path on a network drive => 'file://host/share/a/b'
|
246
|
+
return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
|
247
|
+
|
248
|
+
|
249
|
+
class _PosixFlavour(_Flavour):
|
250
|
+
sep = '/'
|
251
|
+
altsep = ''
|
252
|
+
has_drv = False
|
253
|
+
pathmod = posixpath
|
254
|
+
|
255
|
+
is_supported = (os.name != 'nt')
|
256
|
+
|
257
|
+
def splitroot(self, part, sep=sep):
|
258
|
+
if part and part[0] == sep:
|
259
|
+
stripped_part = part.lstrip(sep)
|
260
|
+
# According to POSIX path resolution:
|
261
|
+
# http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
|
262
|
+
# "A pathname that begins with two successive slashes may be
|
263
|
+
# interpreted in an implementation-defined manner, although more
|
264
|
+
# than two leading slashes shall be treated as a single slash".
|
265
|
+
if len(part) - len(stripped_part) == 2:
|
266
|
+
return '', sep * 2, stripped_part
|
267
|
+
else:
|
268
|
+
return '', sep, stripped_part
|
269
|
+
else:
|
270
|
+
return '', '', part
|
271
|
+
|
272
|
+
def casefold(self, s):
|
273
|
+
return s
|
274
|
+
|
275
|
+
def casefold_parts(self, parts):
|
276
|
+
return parts
|
277
|
+
|
278
|
+
def resolve(self, path):
|
279
|
+
sep = self.sep
|
280
|
+
accessor = path._accessor
|
281
|
+
seen = {}
|
282
|
+
def _resolve(path, rest):
|
283
|
+
if rest.startswith(sep):
|
284
|
+
path = ''
|
285
|
+
|
286
|
+
for name in rest.split(sep):
|
287
|
+
if not name or name == '.':
|
288
|
+
# current dir
|
289
|
+
continue
|
290
|
+
if name == '..':
|
291
|
+
# parent dir
|
292
|
+
path, _, _ = path.rpartition(sep)
|
293
|
+
continue
|
294
|
+
newpath = path + sep + name
|
295
|
+
if newpath in seen:
|
296
|
+
# Already seen this path
|
297
|
+
path = seen[newpath]
|
298
|
+
if path is not None:
|
299
|
+
# use cached value
|
300
|
+
continue
|
301
|
+
# The symlink is not resolved, so we must have a symlink loop.
|
302
|
+
raise RuntimeError("Symlink loop from %r" % newpath)
|
303
|
+
# Resolve the symbolic link
|
304
|
+
try:
|
305
|
+
target = accessor.readlink(newpath)
|
306
|
+
except OSError as e:
|
307
|
+
if e.errno != EINVAL:
|
308
|
+
raise
|
309
|
+
# Not a symlink
|
310
|
+
path = newpath
|
311
|
+
else:
|
312
|
+
seen[newpath] = None # not resolved symlink
|
313
|
+
path = _resolve(path, target)
|
314
|
+
seen[newpath] = path # resolved symlink
|
315
|
+
|
316
|
+
return path
|
317
|
+
# NOTE: according to POSIX, getcwd() cannot contain path components
|
318
|
+
# which are symlinks.
|
319
|
+
base = '' if path.is_absolute() else os.getcwd()
|
320
|
+
return _resolve(base, str(path)) or sep
|
321
|
+
|
322
|
+
def is_reserved(self, parts):
|
323
|
+
return False
|
324
|
+
|
325
|
+
def make_uri(self, path):
|
326
|
+
# We represent the path using the local filesystem encoding,
|
327
|
+
# for portability to other applications.
|
328
|
+
bpath = bytes(path)
|
329
|
+
return 'file://' + urlquote_from_bytes(bpath)
|
330
|
+
|
331
|
+
|
332
|
+
_windows_flavour = _WindowsFlavour()
|
333
|
+
_posix_flavour = _PosixFlavour()
|
334
|
+
|
335
|
+
|
336
|
+
class _Accessor:
|
337
|
+
"""An accessor implements a particular (system-specific or not) way of
|
338
|
+
accessing paths on the filesystem."""
|
339
|
+
|
340
|
+
|
341
|
+
class _NormalAccessor(_Accessor):
|
342
|
+
|
343
|
+
def _wrap_strfunc(strfunc):
|
344
|
+
@functools.wraps(strfunc)
|
345
|
+
def wrapped(pathobj, *args):
|
346
|
+
return strfunc(str(pathobj), *args)
|
347
|
+
return staticmethod(wrapped)
|
348
|
+
|
349
|
+
def _wrap_binary_strfunc(strfunc):
|
350
|
+
@functools.wraps(strfunc)
|
351
|
+
def wrapped(pathobjA, pathobjB, *args):
|
352
|
+
return strfunc(str(pathobjA), str(pathobjB), *args)
|
353
|
+
return staticmethod(wrapped)
|
354
|
+
|
355
|
+
stat = _wrap_strfunc(os.stat)
|
356
|
+
|
357
|
+
lstat = _wrap_strfunc(os.lstat)
|
358
|
+
|
359
|
+
open = _wrap_strfunc(os.open)
|
360
|
+
|
361
|
+
listdir = _wrap_strfunc(os.listdir)
|
362
|
+
|
363
|
+
chmod = _wrap_strfunc(os.chmod)
|
364
|
+
|
365
|
+
if hasattr(os, "lchmod"):
|
366
|
+
lchmod = _wrap_strfunc(os.lchmod)
|
367
|
+
else:
|
368
|
+
def lchmod(self, pathobj, mode):
|
369
|
+
raise NotImplementedError("lchmod() not available on this system")
|
370
|
+
|
371
|
+
mkdir = _wrap_strfunc(os.mkdir)
|
372
|
+
|
373
|
+
unlink = _wrap_strfunc(os.unlink)
|
374
|
+
|
375
|
+
rmdir = _wrap_strfunc(os.rmdir)
|
376
|
+
|
377
|
+
rename = _wrap_binary_strfunc(os.rename)
|
378
|
+
|
379
|
+
if sys.version_info >= (3, 3):
|
380
|
+
replace = _wrap_binary_strfunc(os.replace)
|
381
|
+
|
382
|
+
if nt:
|
383
|
+
if supports_symlinks:
|
384
|
+
symlink = _wrap_binary_strfunc(os.symlink)
|
385
|
+
else:
|
386
|
+
def symlink(a, b, target_is_directory):
|
387
|
+
raise NotImplementedError("symlink() not available on this system")
|
388
|
+
else:
|
389
|
+
# Under POSIX, os.symlink() takes two args
|
390
|
+
@staticmethod
|
391
|
+
def symlink(a, b, target_is_directory):
|
392
|
+
return os.symlink(str(a), str(b))
|
393
|
+
|
394
|
+
utime = _wrap_strfunc(os.utime)
|
395
|
+
|
396
|
+
# Helper for resolve()
|
397
|
+
def readlink(self, path):
|
398
|
+
return os.readlink(path)
|
399
|
+
|
400
|
+
|
401
|
+
_normal_accessor = _NormalAccessor()
|
402
|
+
|
403
|
+
|
404
|
+
#
|
405
|
+
# Globbing helpers
|
406
|
+
#
|
407
|
+
|
408
|
+
@contextmanager
|
409
|
+
def _cached(func):
|
410
|
+
try:
|
411
|
+
func.__cached__
|
412
|
+
yield func
|
413
|
+
except AttributeError:
|
414
|
+
cache = {}
|
415
|
+
def wrapper(*args):
|
416
|
+
try:
|
417
|
+
return cache[args]
|
418
|
+
except KeyError:
|
419
|
+
value = cache[args] = func(*args)
|
420
|
+
return value
|
421
|
+
wrapper.__cached__ = True
|
422
|
+
try:
|
423
|
+
yield wrapper
|
424
|
+
finally:
|
425
|
+
cache.clear()
|
426
|
+
|
427
|
+
def _make_selector(pattern_parts):
|
428
|
+
pat = pattern_parts[0]
|
429
|
+
child_parts = pattern_parts[1:]
|
430
|
+
if pat == '**':
|
431
|
+
cls = _RecursiveWildcardSelector
|
432
|
+
elif '**' in pat:
|
433
|
+
raise ValueError("Invalid pattern: '**' can only be an entire path component")
|
434
|
+
elif _is_wildcard_pattern(pat):
|
435
|
+
cls = _WildcardSelector
|
436
|
+
else:
|
437
|
+
cls = _PreciseSelector
|
438
|
+
return cls(pat, child_parts)
|
439
|
+
|
440
|
+
if hasattr(functools, "lru_cache"):
|
441
|
+
_make_selector = functools.lru_cache()(_make_selector)
|
442
|
+
|
443
|
+
|
444
|
+
class _Selector:
|
445
|
+
"""A selector matches a specific glob pattern part against the children
|
446
|
+
of a given path."""
|
447
|
+
|
448
|
+
def __init__(self, child_parts):
|
449
|
+
self.child_parts = child_parts
|
450
|
+
if child_parts:
|
451
|
+
self.successor = _make_selector(child_parts)
|
452
|
+
else:
|
453
|
+
self.successor = _TerminatingSelector()
|
454
|
+
|
455
|
+
def select_from(self, parent_path):
|
456
|
+
"""Iterate over all child paths of `parent_path` matched by this
|
457
|
+
selector. This can contain parent_path itself."""
|
458
|
+
path_cls = type(parent_path)
|
459
|
+
is_dir = path_cls.is_dir
|
460
|
+
exists = path_cls.exists
|
461
|
+
listdir = parent_path._accessor.listdir
|
462
|
+
return self._select_from(parent_path, is_dir, exists, listdir)
|
463
|
+
|
464
|
+
|
465
|
+
class _TerminatingSelector:
|
466
|
+
|
467
|
+
def _select_from(self, parent_path, is_dir, exists, listdir):
|
468
|
+
yield parent_path
|
469
|
+
|
470
|
+
|
471
|
+
class _PreciseSelector(_Selector):
|
472
|
+
|
473
|
+
def __init__(self, name, child_parts):
|
474
|
+
self.name = name
|
475
|
+
_Selector.__init__(self, child_parts)
|
476
|
+
|
477
|
+
def _select_from(self, parent_path, is_dir, exists, listdir):
|
478
|
+
if not is_dir(parent_path):
|
479
|
+
return
|
480
|
+
path = parent_path._make_child_relpath(self.name)
|
481
|
+
if exists(path):
|
482
|
+
for p in self.successor._select_from(path, is_dir, exists, listdir):
|
483
|
+
yield p
|
484
|
+
|
485
|
+
|
486
|
+
class _WildcardSelector(_Selector):
|
487
|
+
|
488
|
+
def __init__(self, pat, child_parts):
|
489
|
+
self.pat = re.compile(fnmatch.translate(pat))
|
490
|
+
_Selector.__init__(self, child_parts)
|
491
|
+
|
492
|
+
def _select_from(self, parent_path, is_dir, exists, listdir):
|
493
|
+
if not is_dir(parent_path):
|
494
|
+
return
|
495
|
+
cf = parent_path._flavour.casefold
|
496
|
+
for name in listdir(parent_path):
|
497
|
+
casefolded = cf(name)
|
498
|
+
if self.pat.match(casefolded):
|
499
|
+
path = parent_path._make_child_relpath(name)
|
500
|
+
for p in self.successor._select_from(path, is_dir, exists, listdir):
|
501
|
+
yield p
|
502
|
+
|
503
|
+
|
504
|
+
class _RecursiveWildcardSelector(_Selector):
|
505
|
+
|
506
|
+
def __init__(self, pat, child_parts):
|
507
|
+
_Selector.__init__(self, child_parts)
|
508
|
+
|
509
|
+
def _iterate_directories(self, parent_path, is_dir, listdir):
|
510
|
+
yield parent_path
|
511
|
+
for name in listdir(parent_path):
|
512
|
+
path = parent_path._make_child_relpath(name)
|
513
|
+
if is_dir(path):
|
514
|
+
for p in self._iterate_directories(path, is_dir, listdir):
|
515
|
+
yield p
|
516
|
+
|
517
|
+
def _select_from(self, parent_path, is_dir, exists, listdir):
|
518
|
+
if not is_dir(parent_path):
|
519
|
+
return
|
520
|
+
with _cached(listdir) as listdir:
|
521
|
+
yielded = set()
|
522
|
+
try:
|
523
|
+
successor_select = self.successor._select_from
|
524
|
+
for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
|
525
|
+
for p in successor_select(starting_point, is_dir, exists, listdir):
|
526
|
+
if p not in yielded:
|
527
|
+
yield p
|
528
|
+
yielded.add(p)
|
529
|
+
finally:
|
530
|
+
yielded.clear()
|
531
|
+
|
532
|
+
|
533
|
+
#
|
534
|
+
# Public API
|
535
|
+
#
|
536
|
+
|
537
|
+
class _PathParents(Sequence):
|
538
|
+
"""This object provides sequence-like access to the logical ancestors
|
539
|
+
of a path. Don't try to construct it yourself."""
|
540
|
+
__slots__ = ('_pathcls', '_drv', '_root', '_parts')
|
541
|
+
|
542
|
+
def __init__(self, path):
|
543
|
+
# We don't store the instance to avoid reference cycles
|
544
|
+
self._pathcls = type(path)
|
545
|
+
self._drv = path._drv
|
546
|
+
self._root = path._root
|
547
|
+
self._parts = path._parts
|
548
|
+
|
549
|
+
def __len__(self):
|
550
|
+
if self._drv or self._root:
|
551
|
+
return len(self._parts) - 1
|
552
|
+
else:
|
553
|
+
return len(self._parts)
|
554
|
+
|
555
|
+
def __getitem__(self, idx):
|
556
|
+
if idx < 0 or idx >= len(self):
|
557
|
+
raise IndexError(idx)
|
558
|
+
return self._pathcls._from_parsed_parts(self._drv, self._root,
|
559
|
+
self._parts[:-idx - 1])
|
560
|
+
|
561
|
+
def __repr__(self):
|
562
|
+
return "<{0}.parents>".format(self._pathcls.__name__)
|
563
|
+
|
564
|
+
|
565
|
+
class PurePath(object):
|
566
|
+
"""PurePath represents a filesystem path and offers operations which
|
567
|
+
don't imply any actual filesystem I/O. Depending on your system,
|
568
|
+
instantiating a PurePath will return either a PurePosixPath or a
|
569
|
+
PureWindowsPath object. You can also instantiate either of these classes
|
570
|
+
directly, regardless of your system.
|
571
|
+
"""
|
572
|
+
__slots__ = (
|
573
|
+
'_drv', '_root', '_parts',
|
574
|
+
'_str', '_hash', '_pparts', '_cached_cparts',
|
575
|
+
)
|
576
|
+
|
577
|
+
def __new__(cls, *args):
|
578
|
+
"""Construct a PurePath from one or several strings and or existing
|
579
|
+
PurePath objects. The strings and path objects are combined so as
|
580
|
+
to yield a canonicalized path, which is incorporated into the
|
581
|
+
new PurePath object.
|
582
|
+
"""
|
583
|
+
if cls is PurePath:
|
584
|
+
cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
|
585
|
+
return cls._from_parts(args)
|
586
|
+
|
587
|
+
def __reduce__(self):
|
588
|
+
# Using the parts tuple helps share interned path parts
|
589
|
+
# when pickling related paths.
|
590
|
+
return (self.__class__, tuple(self._parts))
|
591
|
+
|
592
|
+
@classmethod
|
593
|
+
def _parse_args(cls, args):
|
594
|
+
# This is useful when you don't want to create an instance, just
|
595
|
+
# canonicalize some constructor arguments.
|
596
|
+
parts = []
|
597
|
+
for a in args:
|
598
|
+
if isinstance(a, PurePath):
|
599
|
+
parts += a._parts
|
600
|
+
elif isinstance(a, basestring):
|
601
|
+
parts.append(a)
|
602
|
+
else:
|
603
|
+
raise TypeError(
|
604
|
+
"argument should be a path or str object, not %r"
|
605
|
+
% type(a))
|
606
|
+
return cls._flavour.parse_parts(parts)
|
607
|
+
|
608
|
+
@classmethod
|
609
|
+
def _from_parts(cls, args, init=True):
|
610
|
+
# We need to call _parse_args on the instance, so as to get the
|
611
|
+
# right flavour.
|
612
|
+
self = object.__new__(cls)
|
613
|
+
drv, root, parts = self._parse_args(args)
|
614
|
+
self._drv = drv
|
615
|
+
self._root = root
|
616
|
+
self._parts = parts
|
617
|
+
if init:
|
618
|
+
self._init()
|
619
|
+
return self
|
620
|
+
|
621
|
+
@classmethod
|
622
|
+
def _from_parsed_parts(cls, drv, root, parts, init=True):
|
623
|
+
self = object.__new__(cls)
|
624
|
+
self._drv = drv
|
625
|
+
self._root = root
|
626
|
+
self._parts = parts
|
627
|
+
if init:
|
628
|
+
self._init()
|
629
|
+
return self
|
630
|
+
|
631
|
+
@classmethod
|
632
|
+
def _format_parsed_parts(cls, drv, root, parts):
|
633
|
+
if drv or root:
|
634
|
+
return drv + root + cls._flavour.join(parts[1:])
|
635
|
+
else:
|
636
|
+
return cls._flavour.join(parts)
|
637
|
+
|
638
|
+
def _init(self):
|
639
|
+
# Overriden in concrete Path
|
640
|
+
pass
|
641
|
+
|
642
|
+
def _make_child(self, args):
|
643
|
+
drv, root, parts = self._parse_args(args)
|
644
|
+
drv, root, parts = self._flavour.join_parsed_parts(
|
645
|
+
self._drv, self._root, self._parts, drv, root, parts)
|
646
|
+
return self._from_parsed_parts(drv, root, parts)
|
647
|
+
|
648
|
+
def __str__(self):
|
649
|
+
"""Return the string representation of the path, suitable for
|
650
|
+
passing to system calls."""
|
651
|
+
try:
|
652
|
+
return self._str
|
653
|
+
except AttributeError:
|
654
|
+
self._str = self._format_parsed_parts(self._drv, self._root,
|
655
|
+
self._parts) or '.'
|
656
|
+
return self._str
|
657
|
+
|
658
|
+
def as_posix(self):
|
659
|
+
"""Return the string representation of the path with forward (/)
|
660
|
+
slashes."""
|
661
|
+
f = self._flavour
|
662
|
+
return str(self).replace(f.sep, '/')
|
663
|
+
|
664
|
+
def __bytes__(self):
|
665
|
+
"""Return the bytes representation of the path. This is only
|
666
|
+
recommended to use under Unix."""
|
667
|
+
if sys.version_info < (3, 2):
|
668
|
+
raise NotImplementedError("needs Python 3.2 or later")
|
669
|
+
return os.fsencode(str(self))
|
670
|
+
|
671
|
+
def __repr__(self):
|
672
|
+
return "{0}({1!r})".format(self.__class__.__name__, self.as_posix())
|
673
|
+
|
674
|
+
def as_uri(self):
|
675
|
+
"""Return the path as a 'file' URI."""
|
676
|
+
if not self.is_absolute():
|
677
|
+
raise ValueError("relative path can't be expressed as a file URI")
|
678
|
+
return self._flavour.make_uri(self)
|
679
|
+
|
680
|
+
@property
|
681
|
+
def _cparts(self):
|
682
|
+
# Cached casefolded parts, for hashing and comparison
|
683
|
+
try:
|
684
|
+
return self._cached_cparts
|
685
|
+
except AttributeError:
|
686
|
+
self._cached_cparts = self._flavour.casefold_parts(self._parts)
|
687
|
+
return self._cached_cparts
|
688
|
+
|
689
|
+
def __eq__(self, other):
|
690
|
+
if not isinstance(other, PurePath):
|
691
|
+
return NotImplemented
|
692
|
+
return self._cparts == other._cparts and self._flavour is other._flavour
|
693
|
+
|
694
|
+
def __ne__(self, other):
|
695
|
+
return not self == other
|
696
|
+
|
697
|
+
def __hash__(self):
|
698
|
+
try:
|
699
|
+
return self._hash
|
700
|
+
except AttributeError:
|
701
|
+
self._hash = hash(tuple(self._cparts))
|
702
|
+
return self._hash
|
703
|
+
|
704
|
+
def __lt__(self, other):
|
705
|
+
if not isinstance(other, PurePath) or self._flavour is not other._flavour:
|
706
|
+
return NotImplemented
|
707
|
+
return self._cparts < other._cparts
|
708
|
+
|
709
|
+
def __le__(self, other):
|
710
|
+
if not isinstance(other, PurePath) or self._flavour is not other._flavour:
|
711
|
+
return NotImplemented
|
712
|
+
return self._cparts <= other._cparts
|
713
|
+
|
714
|
+
def __gt__(self, other):
|
715
|
+
if not isinstance(other, PurePath) or self._flavour is not other._flavour:
|
716
|
+
return NotImplemented
|
717
|
+
return self._cparts > other._cparts
|
718
|
+
|
719
|
+
def __ge__(self, other):
|
720
|
+
if not isinstance(other, PurePath) or self._flavour is not other._flavour:
|
721
|
+
return NotImplemented
|
722
|
+
return self._cparts >= other._cparts
|
723
|
+
|
724
|
+
drive = property(attrgetter('_drv'),
|
725
|
+
doc="""The drive prefix (letter or UNC path), if any.""")
|
726
|
+
|
727
|
+
root = property(attrgetter('_root'),
|
728
|
+
doc="""The root of the path, if any.""")
|
729
|
+
|
730
|
+
@property
|
731
|
+
def anchor(self):
|
732
|
+
"""The concatenation of the drive and root, or ''."""
|
733
|
+
anchor = self._drv + self._root
|
734
|
+
return anchor
|
735
|
+
|
736
|
+
@property
|
737
|
+
def name(self):
|
738
|
+
"""The final path component, if any."""
|
739
|
+
parts = self._parts
|
740
|
+
if len(parts) == (1 if (self._drv or self._root) else 0):
|
741
|
+
return ''
|
742
|
+
return parts[-1]
|
743
|
+
|
744
|
+
@property
|
745
|
+
def suffix(self):
|
746
|
+
"""The final component's last suffix, if any."""
|
747
|
+
name = self.name
|
748
|
+
i = name.rfind('.')
|
749
|
+
if 0 < i < len(name) - 1:
|
750
|
+
return name[i:]
|
751
|
+
else:
|
752
|
+
return ''
|
753
|
+
|
754
|
+
@property
|
755
|
+
def suffixes(self):
|
756
|
+
"""A list of the final component's suffixes, if any."""
|
757
|
+
name = self.name
|
758
|
+
if name.endswith('.'):
|
759
|
+
return []
|
760
|
+
name = name.lstrip('.')
|
761
|
+
return ['.' + suffix for suffix in name.split('.')[1:]]
|
762
|
+
|
763
|
+
@property
|
764
|
+
def stem(self):
|
765
|
+
"""The final path component, minus its last suffix."""
|
766
|
+
name = self.name
|
767
|
+
i = name.rfind('.')
|
768
|
+
if 0 < i < len(name) - 1:
|
769
|
+
return name[:i]
|
770
|
+
else:
|
771
|
+
return name
|
772
|
+
|
773
|
+
def with_name(self, name):
|
774
|
+
"""Return a new path with the file name changed."""
|
775
|
+
if not self.name:
|
776
|
+
raise ValueError("%r has an empty name" % (self,))
|
777
|
+
return self._from_parsed_parts(self._drv, self._root,
|
778
|
+
self._parts[:-1] + [name])
|
779
|
+
|
780
|
+
def with_suffix(self, suffix):
|
781
|
+
"""Return a new path with the file suffix changed (or added, if none)."""
|
782
|
+
# XXX if suffix is None, should the current suffix be removed?
|
783
|
+
drv, root, parts = self._flavour.parse_parts((suffix,))
|
784
|
+
if drv or root or len(parts) != 1:
|
785
|
+
raise ValueError("Invalid suffix %r" % (suffix))
|
786
|
+
suffix = parts[0]
|
787
|
+
if not suffix.startswith('.'):
|
788
|
+
raise ValueError("Invalid suffix %r" % (suffix))
|
789
|
+
name = self.name
|
790
|
+
if not name:
|
791
|
+
raise ValueError("%r has an empty name" % (self,))
|
792
|
+
old_suffix = self.suffix
|
793
|
+
if not old_suffix:
|
794
|
+
name = name + suffix
|
795
|
+
else:
|
796
|
+
name = name[:-len(old_suffix)] + suffix
|
797
|
+
return self._from_parsed_parts(self._drv, self._root,
|
798
|
+
self._parts[:-1] + [name])
|
799
|
+
|
800
|
+
def relative_to(self, *other):
|
801
|
+
"""Return the relative path to another path identified by the passed
|
802
|
+
arguments. If the operation is not possible (because this is not
|
803
|
+
a subpath of the other path), raise ValueError.
|
804
|
+
"""
|
805
|
+
# For the purpose of this method, drive and root are considered
|
806
|
+
# separate parts, i.e.:
|
807
|
+
# Path('c:/').relative_to('c:') gives Path('/')
|
808
|
+
# Path('c:/').relative_to('/') raise ValueError
|
809
|
+
if not other:
|
810
|
+
raise TypeError("need at least one argument")
|
811
|
+
parts = self._parts
|
812
|
+
drv = self._drv
|
813
|
+
root = self._root
|
814
|
+
if root:
|
815
|
+
abs_parts = [drv, root] + parts[1:]
|
816
|
+
else:
|
817
|
+
abs_parts = parts
|
818
|
+
to_drv, to_root, to_parts = self._parse_args(other)
|
819
|
+
if to_root:
|
820
|
+
to_abs_parts = [to_drv, to_root] + to_parts[1:]
|
821
|
+
else:
|
822
|
+
to_abs_parts = to_parts
|
823
|
+
n = len(to_abs_parts)
|
824
|
+
cf = self._flavour.casefold_parts
|
825
|
+
if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
|
826
|
+
formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
|
827
|
+
raise ValueError("{!r} does not start with {!r}"
|
828
|
+
.format(str(self), str(formatted)))
|
829
|
+
return self._from_parsed_parts('', root if n == 1 else '',
|
830
|
+
abs_parts[n:])
|
831
|
+
|
832
|
+
@property
|
833
|
+
def parts(self):
|
834
|
+
"""An object providing sequence-like access to the
|
835
|
+
components in the filesystem path."""
|
836
|
+
# We cache the tuple to avoid building a new one each time .parts
|
837
|
+
# is accessed. XXX is this necessary?
|
838
|
+
try:
|
839
|
+
return self._pparts
|
840
|
+
except AttributeError:
|
841
|
+
self._pparts = tuple(self._parts)
|
842
|
+
return self._pparts
|
843
|
+
|
844
|
+
def joinpath(self, *args):
|
845
|
+
"""Combine this path with one or several arguments, and return a
|
846
|
+
new path representing either a subpath (if all arguments are relative
|
847
|
+
paths) or a totally different path (if one of the arguments is
|
848
|
+
anchored).
|
849
|
+
"""
|
850
|
+
return self._make_child(args)
|
851
|
+
|
852
|
+
def __truediv__(self, key):
|
853
|
+
return self._make_child((key,))
|
854
|
+
|
855
|
+
def __rtruediv__(self, key):
|
856
|
+
return self._from_parts([key] + self._parts)
|
857
|
+
|
858
|
+
if sys.version_info < (3,):
|
859
|
+
__div__ = __truediv__
|
860
|
+
__rdiv__ = __rtruediv__
|
861
|
+
|
862
|
+
@property
|
863
|
+
def parent(self):
|
864
|
+
"""The logical parent of the path."""
|
865
|
+
drv = self._drv
|
866
|
+
root = self._root
|
867
|
+
parts = self._parts
|
868
|
+
if len(parts) == 1 and (drv or root):
|
869
|
+
return self
|
870
|
+
return self._from_parsed_parts(drv, root, parts[:-1])
|
871
|
+
|
872
|
+
@property
|
873
|
+
def parents(self):
|
874
|
+
"""A sequence of this path's logical parents."""
|
875
|
+
return _PathParents(self)
|
876
|
+
|
877
|
+
def is_absolute(self):
|
878
|
+
"""True if the path is absolute (has both a root and, if applicable,
|
879
|
+
a drive)."""
|
880
|
+
if not self._root:
|
881
|
+
return False
|
882
|
+
return not self._flavour.has_drv or bool(self._drv)
|
883
|
+
|
884
|
+
def is_reserved(self):
|
885
|
+
"""Return True if the path contains one of the special names reserved
|
886
|
+
by the system, if any."""
|
887
|
+
return self._flavour.is_reserved(self._parts)
|
888
|
+
|
889
|
+
def match(self, path_pattern):
|
890
|
+
"""
|
891
|
+
Return True if this path matches the given pattern.
|
892
|
+
"""
|
893
|
+
cf = self._flavour.casefold
|
894
|
+
path_pattern = cf(path_pattern)
|
895
|
+
drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
|
896
|
+
if not pat_parts:
|
897
|
+
raise ValueError("empty pattern")
|
898
|
+
if drv and drv != cf(self._drv):
|
899
|
+
return False
|
900
|
+
if root and root != cf(self._root):
|
901
|
+
return False
|
902
|
+
parts = self._cparts
|
903
|
+
if drv or root:
|
904
|
+
if len(pat_parts) != len(parts):
|
905
|
+
return False
|
906
|
+
pat_parts = pat_parts[1:]
|
907
|
+
elif len(pat_parts) > len(parts):
|
908
|
+
return False
|
909
|
+
for part, pat in zip(reversed(parts), reversed(pat_parts)):
|
910
|
+
if not fnmatch.fnmatchcase(part, pat):
|
911
|
+
return False
|
912
|
+
return True
|
913
|
+
|
914
|
+
|
915
|
+
class PurePosixPath(PurePath):
|
916
|
+
_flavour = _posix_flavour
|
917
|
+
__slots__ = ()
|
918
|
+
|
919
|
+
|
920
|
+
class PureWindowsPath(PurePath):
|
921
|
+
_flavour = _windows_flavour
|
922
|
+
__slots__ = ()
|
923
|
+
|
924
|
+
|
925
|
+
# Filesystem-accessing classes
|
926
|
+
|
927
|
+
|
928
|
+
class Path(PurePath):
|
929
|
+
__slots__ = (
|
930
|
+
'_accessor',
|
931
|
+
)
|
932
|
+
|
933
|
+
def __new__(cls, *args, **kwargs):
|
934
|
+
if cls is Path:
|
935
|
+
cls = WindowsPath if os.name == 'nt' else PosixPath
|
936
|
+
self = cls._from_parts(args, init=False)
|
937
|
+
if not self._flavour.is_supported:
|
938
|
+
raise NotImplementedError("cannot instantiate %r on your system"
|
939
|
+
% (cls.__name__,))
|
940
|
+
self._init()
|
941
|
+
return self
|
942
|
+
|
943
|
+
def _init(self,
|
944
|
+
# Private non-constructor arguments
|
945
|
+
template=None,
|
946
|
+
):
|
947
|
+
if template is not None:
|
948
|
+
self._accessor = template._accessor
|
949
|
+
else:
|
950
|
+
self._accessor = _normal_accessor
|
951
|
+
|
952
|
+
def _make_child_relpath(self, part):
|
953
|
+
# This is an optimization used for dir walking. `part` must be
|
954
|
+
# a single part relative to this path.
|
955
|
+
parts = self._parts + [part]
|
956
|
+
return self._from_parsed_parts(self._drv, self._root, parts)
|
957
|
+
|
958
|
+
def _opener(self, name, flags, mode=0o666):
|
959
|
+
# A stub for the opener argument to built-in open()
|
960
|
+
return self._accessor.open(self, flags, mode)
|
961
|
+
|
962
|
+
def _raw_open(self, flags, mode=0o777):
|
963
|
+
"""
|
964
|
+
Open the file pointed by this path and return a file descriptor,
|
965
|
+
as os.open() does.
|
966
|
+
"""
|
967
|
+
return self._accessor.open(self, flags, mode)
|
968
|
+
|
969
|
+
# Public API
|
970
|
+
|
971
|
+
@classmethod
|
972
|
+
def cwd(cls):
|
973
|
+
"""Return a new path pointing to the current working directory
|
974
|
+
(as returned by os.getcwd()).
|
975
|
+
"""
|
976
|
+
return cls(os.getcwd())
|
977
|
+
|
978
|
+
def iterdir(self):
|
979
|
+
"""Iterate over the files in this directory. Does not yield any
|
980
|
+
result for the special paths '.' and '..'.
|
981
|
+
"""
|
982
|
+
for name in self._accessor.listdir(self):
|
983
|
+
if name in ('.', '..'):
|
984
|
+
# Yielding a path object for these makes little sense
|
985
|
+
continue
|
986
|
+
yield self._make_child_relpath(name)
|
987
|
+
|
988
|
+
def glob(self, pattern):
|
989
|
+
"""Iterate over this subtree and yield all existing files (of any
|
990
|
+
kind, including directories) matching the given pattern.
|
991
|
+
"""
|
992
|
+
pattern = self._flavour.casefold(pattern)
|
993
|
+
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
|
994
|
+
if drv or root:
|
995
|
+
raise NotImplementedError("Non-relative patterns are unsupported")
|
996
|
+
selector = _make_selector(tuple(pattern_parts))
|
997
|
+
for p in selector.select_from(self):
|
998
|
+
yield p
|
999
|
+
|
1000
|
+
def rglob(self, pattern):
|
1001
|
+
"""Recursively yield all existing files (of any kind, including
|
1002
|
+
directories) matching the given pattern, anywhere in this subtree.
|
1003
|
+
"""
|
1004
|
+
pattern = self._flavour.casefold(pattern)
|
1005
|
+
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
|
1006
|
+
if drv or root:
|
1007
|
+
raise NotImplementedError("Non-relative patterns are unsupported")
|
1008
|
+
selector = _make_selector(("**",) + tuple(pattern_parts))
|
1009
|
+
for p in selector.select_from(self):
|
1010
|
+
yield p
|
1011
|
+
|
1012
|
+
def absolute(self):
|
1013
|
+
"""Return an absolute version of this path. This function works
|
1014
|
+
even if the path doesn't point to anything.
|
1015
|
+
|
1016
|
+
No normalization is done, i.e. all '.' and '..' will be kept along.
|
1017
|
+
Use resolve() to get the canonical path to a file.
|
1018
|
+
"""
|
1019
|
+
# XXX untested yet!
|
1020
|
+
if self.is_absolute():
|
1021
|
+
return self
|
1022
|
+
# FIXME this must defer to the specific flavour (and, under Windows,
|
1023
|
+
# use nt._getfullpathname())
|
1024
|
+
obj = self._from_parts([os.getcwd()] + self._parts, init=False)
|
1025
|
+
obj._init(template=self)
|
1026
|
+
return obj
|
1027
|
+
|
1028
|
+
def resolve(self):
|
1029
|
+
"""
|
1030
|
+
Make the path absolute, resolving all symlinks on the way and also
|
1031
|
+
normalizing it (for example turning slashes into backslashes under
|
1032
|
+
Windows).
|
1033
|
+
"""
|
1034
|
+
s = self._flavour.resolve(self)
|
1035
|
+
if s is None:
|
1036
|
+
# No symlink resolution => for consistency, raise an error if
|
1037
|
+
# the path doesn't exist or is forbidden
|
1038
|
+
self.stat()
|
1039
|
+
s = str(self.absolute())
|
1040
|
+
# Now we have no symlinks in the path, it's safe to normalize it.
|
1041
|
+
normed = self._flavour.pathmod.normpath(s)
|
1042
|
+
obj = self._from_parts((normed,), init=False)
|
1043
|
+
obj._init(template=self)
|
1044
|
+
return obj
|
1045
|
+
|
1046
|
+
def stat(self):
|
1047
|
+
"""
|
1048
|
+
Return the result of the stat() system call on this path, like
|
1049
|
+
os.stat() does.
|
1050
|
+
"""
|
1051
|
+
return self._accessor.stat(self)
|
1052
|
+
|
1053
|
+
def owner(self):
|
1054
|
+
"""
|
1055
|
+
Return the login name of the file owner.
|
1056
|
+
"""
|
1057
|
+
import pwd
|
1058
|
+
return pwd.getpwuid(self.stat().st_uid).pw_name
|
1059
|
+
|
1060
|
+
def group(self):
|
1061
|
+
"""
|
1062
|
+
Return the group name of the file gid.
|
1063
|
+
"""
|
1064
|
+
import grp
|
1065
|
+
return grp.getgrgid(self.stat().st_gid).gr_name
|
1066
|
+
|
1067
|
+
def open(self, mode='r', buffering=-1, encoding=None,
|
1068
|
+
errors=None, newline=None):
|
1069
|
+
"""
|
1070
|
+
Open the file pointed by this path and return a file object, as
|
1071
|
+
the built-in open() function does.
|
1072
|
+
"""
|
1073
|
+
if sys.version_info >= (3, 3):
|
1074
|
+
return io.open(str(self), mode, buffering, encoding, errors, newline,
|
1075
|
+
opener=self._opener)
|
1076
|
+
else:
|
1077
|
+
return io.open(str(self), mode, buffering, encoding, errors, newline)
|
1078
|
+
|
1079
|
+
def touch(self, mode=0o666, exist_ok=True):
|
1080
|
+
"""
|
1081
|
+
Create this file with the given access mode, if it doesn't exist.
|
1082
|
+
"""
|
1083
|
+
if exist_ok:
|
1084
|
+
# First try to bump modification time
|
1085
|
+
# Implementation note: GNU touch uses the UTIME_NOW option of
|
1086
|
+
# the utimensat() / futimens() functions.
|
1087
|
+
t = time.time()
|
1088
|
+
try:
|
1089
|
+
self._accessor.utime(self, (t, t))
|
1090
|
+
except OSError:
|
1091
|
+
# Avoid exception chaining
|
1092
|
+
pass
|
1093
|
+
else:
|
1094
|
+
return
|
1095
|
+
flags = os.O_CREAT | os.O_WRONLY
|
1096
|
+
if not exist_ok:
|
1097
|
+
flags |= os.O_EXCL
|
1098
|
+
fd = self._raw_open(flags, mode)
|
1099
|
+
os.close(fd)
|
1100
|
+
|
1101
|
+
def mkdir(self, mode=0o777, parents=False):
|
1102
|
+
if not parents:
|
1103
|
+
self._accessor.mkdir(self, mode)
|
1104
|
+
else:
|
1105
|
+
try:
|
1106
|
+
self._accessor.mkdir(self, mode)
|
1107
|
+
except OSError as e:
|
1108
|
+
if e.errno != ENOENT:
|
1109
|
+
raise
|
1110
|
+
self.parent.mkdir(parents=True)
|
1111
|
+
self._accessor.mkdir(self, mode)
|
1112
|
+
|
1113
|
+
def chmod(self, mode):
|
1114
|
+
"""
|
1115
|
+
Change the permissions of the path, like os.chmod().
|
1116
|
+
"""
|
1117
|
+
self._accessor.chmod(self, mode)
|
1118
|
+
|
1119
|
+
def lchmod(self, mode):
|
1120
|
+
"""
|
1121
|
+
Like chmod(), except if the path points to a symlink, the symlink's
|
1122
|
+
permissions are changed, rather than its target's.
|
1123
|
+
"""
|
1124
|
+
self._accessor.lchmod(self, mode)
|
1125
|
+
|
1126
|
+
def unlink(self):
|
1127
|
+
"""
|
1128
|
+
Remove this file or link.
|
1129
|
+
If the path is a directory, use rmdir() instead.
|
1130
|
+
"""
|
1131
|
+
self._accessor.unlink(self)
|
1132
|
+
|
1133
|
+
def rmdir(self):
|
1134
|
+
"""
|
1135
|
+
Remove this directory. The directory must be empty.
|
1136
|
+
"""
|
1137
|
+
self._accessor.rmdir(self)
|
1138
|
+
|
1139
|
+
def lstat(self):
|
1140
|
+
"""
|
1141
|
+
Like stat(), except if the path points to a symlink, the symlink's
|
1142
|
+
status information is returned, rather than its target's.
|
1143
|
+
"""
|
1144
|
+
return self._accessor.lstat(self)
|
1145
|
+
|
1146
|
+
def rename(self, target):
|
1147
|
+
"""
|
1148
|
+
Rename this path to the given path.
|
1149
|
+
"""
|
1150
|
+
self._accessor.rename(self, target)
|
1151
|
+
|
1152
|
+
def replace(self, target):
|
1153
|
+
"""
|
1154
|
+
Rename this path to the given path, clobbering the existing
|
1155
|
+
destination if it exists.
|
1156
|
+
"""
|
1157
|
+
if sys.version_info < (3, 3):
|
1158
|
+
raise NotImplementedError("replace() is only available "
|
1159
|
+
"with Python 3.3 and later")
|
1160
|
+
self._accessor.replace(self, target)
|
1161
|
+
|
1162
|
+
def symlink_to(self, target, target_is_directory=False):
|
1163
|
+
"""
|
1164
|
+
Make this path a symlink pointing to the given path.
|
1165
|
+
Note the order of arguments (self, target) is the reverse of os.symlink's.
|
1166
|
+
"""
|
1167
|
+
self._accessor.symlink(target, self, target_is_directory)
|
1168
|
+
|
1169
|
+
# Convenience functions for querying the stat results
|
1170
|
+
|
1171
|
+
def exists(self):
|
1172
|
+
"""
|
1173
|
+
Whether this path exists.
|
1174
|
+
"""
|
1175
|
+
try:
|
1176
|
+
self.stat()
|
1177
|
+
except OSError as e:
|
1178
|
+
if e.errno != ENOENT:
|
1179
|
+
raise
|
1180
|
+
return False
|
1181
|
+
return True
|
1182
|
+
|
1183
|
+
def is_dir(self):
|
1184
|
+
"""
|
1185
|
+
Whether this path is a directory.
|
1186
|
+
"""
|
1187
|
+
try:
|
1188
|
+
return S_ISDIR(self.stat().st_mode)
|
1189
|
+
except OSError as e:
|
1190
|
+
if e.errno != ENOENT:
|
1191
|
+
raise
|
1192
|
+
# Path doesn't exist or is a broken symlink
|
1193
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1194
|
+
return False
|
1195
|
+
|
1196
|
+
def is_file(self):
|
1197
|
+
"""
|
1198
|
+
Whether this path is a regular file (also True for symlinks pointing
|
1199
|
+
to regular files).
|
1200
|
+
"""
|
1201
|
+
try:
|
1202
|
+
return S_ISREG(self.stat().st_mode)
|
1203
|
+
except OSError as e:
|
1204
|
+
if e.errno != ENOENT:
|
1205
|
+
raise
|
1206
|
+
# Path doesn't exist or is a broken symlink
|
1207
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1208
|
+
return False
|
1209
|
+
|
1210
|
+
def is_symlink(self):
|
1211
|
+
"""
|
1212
|
+
Whether this path is a symbolic link.
|
1213
|
+
"""
|
1214
|
+
try:
|
1215
|
+
return S_ISLNK(self.lstat().st_mode)
|
1216
|
+
except OSError as e:
|
1217
|
+
if e.errno != ENOENT:
|
1218
|
+
raise
|
1219
|
+
# Path doesn't exist
|
1220
|
+
return False
|
1221
|
+
|
1222
|
+
def is_block_device(self):
|
1223
|
+
"""
|
1224
|
+
Whether this path is a block device.
|
1225
|
+
"""
|
1226
|
+
try:
|
1227
|
+
return S_ISBLK(self.stat().st_mode)
|
1228
|
+
except OSError as e:
|
1229
|
+
if e.errno != ENOENT:
|
1230
|
+
raise
|
1231
|
+
# Path doesn't exist or is a broken symlink
|
1232
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1233
|
+
return False
|
1234
|
+
|
1235
|
+
def is_char_device(self):
|
1236
|
+
"""
|
1237
|
+
Whether this path is a character device.
|
1238
|
+
"""
|
1239
|
+
try:
|
1240
|
+
return S_ISCHR(self.stat().st_mode)
|
1241
|
+
except OSError as e:
|
1242
|
+
if e.errno != ENOENT:
|
1243
|
+
raise
|
1244
|
+
# Path doesn't exist or is a broken symlink
|
1245
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1246
|
+
return False
|
1247
|
+
|
1248
|
+
def is_fifo(self):
|
1249
|
+
"""
|
1250
|
+
Whether this path is a FIFO.
|
1251
|
+
"""
|
1252
|
+
try:
|
1253
|
+
return S_ISFIFO(self.stat().st_mode)
|
1254
|
+
except OSError as e:
|
1255
|
+
if e.errno != ENOENT:
|
1256
|
+
raise
|
1257
|
+
# Path doesn't exist or is a broken symlink
|
1258
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1259
|
+
return False
|
1260
|
+
|
1261
|
+
def is_socket(self):
|
1262
|
+
"""
|
1263
|
+
Whether this path is a socket.
|
1264
|
+
"""
|
1265
|
+
try:
|
1266
|
+
return S_ISSOCK(self.stat().st_mode)
|
1267
|
+
except OSError as e:
|
1268
|
+
if e.errno != ENOENT:
|
1269
|
+
raise
|
1270
|
+
# Path doesn't exist or is a broken symlink
|
1271
|
+
# (see https://bitbucket.org/pitrou/pathlib/issue/12/)
|
1272
|
+
return False
|
1273
|
+
|
1274
|
+
|
1275
|
+
class PosixPath(Path, PurePosixPath):
|
1276
|
+
__slots__ = ()
|
1277
|
+
|
1278
|
+
class WindowsPath(Path, PureWindowsPath):
|
1279
|
+
__slots__ = ()
|
1280
|
+
|