From 6d154c1ed3397fd131dd555e5679059ab05f7186 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Wed, 16 Jun 2021 15:53:16 +0000 Subject: [PATCH] Bug 1713377: Change vendoring to use wheels where possible r=ahal,glandium Vendoring wheels has three benefits: * There's far less files, so Firefox checkouts will be smaller. * It works around `zipp` not allowing `pip install` from extracted source `tar.gz` files. Now, we should be able to use the pip resolver against vendored packages, which will be needed for future mach virtualenv work. * `./mach vendor python` takes far less time to execute. Since we need the raw Python to be available to add to the `sys.path`, we extract the wheels before putting them in tree. Due to the structure of some wheels being less nested than of a source `tar.gz`, `common_virtualenv_packages` needed to be adjusted accordingly. `install_pip_package()` had to be tweaked as well since you can't `pip install` an extracted wheel. So, we "re-bundle" the wheel before installing from a vendored package. Replace python packages with wheels where possible This contains the vendoring changes caused by the last patch. For reviewing, there's a couple things to note: * A bunch of files are deleted, since there's generally less files in a wheel than in a source archive. * There's a new `.dist-info` directory for each extracted wheel, so expect roughly 5 or 6 new files for each wheel'd package. * There should be no source code changes other than moves from package names changing from having `-` to having `_`. Differential Revision: https://phabricator.services.mozilla.com/D116512 --- build/common_virtualenv_packages.txt | 20 +- .../mozbuild/mozbuild/vendor/vendor_python.py | 72 +- python/mozbuild/mozbuild/virtualenv.py | 23 +- third_party/python/Click/CHANGES.rst | 635 --- third_party/python/Click/CONTRIBUTING.rst | 61 - .../LICENSE.txt} | 0 .../METADATA} | 34 +- .../python/Click/Click-7.0.dist-info/RECORD | 22 + .../python/Click/Click-7.0.dist-info/WHEEL | 6 + .../Click/Click-7.0.dist-info/top_level.txt | 1 + third_party/python/Click/MANIFEST.in | 11 - third_party/python/Click/PKG-INFO | 119 - third_party/python/Click/artwork/logo.svg | 75 - third_party/python/Click/examples/README | 12 - .../python/Click/examples/aliases/README | 17 - .../python/Click/examples/aliases/aliases.ini | 2 - .../python/Click/examples/aliases/aliases.py | 111 - .../python/Click/examples/aliases/setup.py | 15 - .../Click/examples/bashcompletion/README | 12 - .../examples/bashcompletion/bashcompletion.py | 45 - .../Click/examples/bashcompletion/setup.py | 15 - .../python/Click/examples/colors/README | 11 - .../python/Click/examples/colors/colors.py | 28 - .../python/Click/examples/colors/setup.py | 17 - .../python/Click/examples/complex/README | 16 - .../Click/examples/complex/complex/cli.py | 65 - .../complex/complex/commands/cmd_init.py | 13 - .../complex/complex/commands/cmd_status.py | 10 - .../python/Click/examples/complex/setup.py | 15 - .../Click/examples/imagepipe/.gitignore | 1 - .../python/Click/examples/imagepipe/README | 13 - .../Click/examples/imagepipe/example01.jpg | Bin 51677 -> 0 bytes .../Click/examples/imagepipe/example02.jpg | Bin 39106 -> 0 bytes .../Click/examples/imagepipe/imagepipe.py | 266 - .../python/Click/examples/imagepipe/setup.py | 16 - .../python/Click/examples/inout/README | 10 - .../python/Click/examples/inout/inout.py | 30 - .../python/Click/examples/inout/setup.py | 15 - .../python/Click/examples/naval/README | 14 - .../python/Click/examples/naval/naval.py | 70 - .../python/Click/examples/naval/setup.py | 15 - third_party/python/Click/examples/repo/README | 9 - .../python/Click/examples/repo/repo.py | 151 - .../python/Click/examples/repo/setup.py | 15 - .../python/Click/examples/termui/README | 9 - .../python/Click/examples/termui/setup.py | 17 - .../python/Click/examples/termui/termui.py | 156 - .../python/Click/examples/validation/README | 12 - .../python/Click/examples/validation/setup.py | 15 - .../Click/examples/validation/validation.py | 44 - third_party/python/Click/setup.cfg | 25 - third_party/python/Click/setup.py | 44 - third_party/python/Click/tox.ini | 39 - third_party/python/Jinja2/CHANGES.rst | 784 --- .../{ => Jinja2-2.11.3.dist-info}/LICENSE.rst | 0 .../METADATA} | 40 + .../Jinja2/Jinja2-2.11.3.dist-info/RECORD | 33 + .../Jinja2/Jinja2-2.11.3.dist-info/WHEEL | 6 + .../Jinja2-2.11.3.dist-info/entry_points.txt | 3 + .../Jinja2-2.11.3.dist-info/top_level.txt | 1 + third_party/python/Jinja2/MANIFEST.in | 9 - third_party/python/Jinja2/PKG-INFO | 102 - .../python/Jinja2/artwork/jinjalogo.svg | 132 - .../python/Jinja2/examples/basic/cycle.py | 18 - .../python/Jinja2/examples/basic/debugger.py | 8 - .../Jinja2/examples/basic/inheritance.py | 15 - .../examples/basic/templates/broken.html | 6 - .../examples/basic/templates/subbroken.html | 3 - .../python/Jinja2/examples/basic/test.py | 31 - .../basic/test_filter_and_linestatements.py | 29 - .../Jinja2/examples/basic/test_loop_filter.py | 15 - .../python/Jinja2/examples/basic/translate.py | 20 - third_party/python/Jinja2/ext/Vim/jinja.vim | 138 - .../Jinja2/{src => }/jinja2/__init__.py | 0 .../python/Jinja2/{src => }/jinja2/_compat.py | 0 .../Jinja2/{src => }/jinja2/_identifier.py | 0 .../Jinja2/{src => }/jinja2/asyncfilters.py | 0 .../Jinja2/{src => }/jinja2/asyncsupport.py | 0 .../python/Jinja2/{src => }/jinja2/bccache.py | 0 .../Jinja2/{src => }/jinja2/compiler.py | 0 .../Jinja2/{src => }/jinja2/constants.py | 0 .../python/Jinja2/{src => }/jinja2/debug.py | 0 .../Jinja2/{src => }/jinja2/defaults.py | 0 .../Jinja2/{src => }/jinja2/environment.py | 0 .../Jinja2/{src => }/jinja2/exceptions.py | 0 .../python/Jinja2/{src => }/jinja2/ext.py | 0 .../python/Jinja2/{src => }/jinja2/filters.py | 0 .../Jinja2/{src => }/jinja2/idtracking.py | 0 .../python/Jinja2/{src => }/jinja2/lexer.py | 0 .../python/Jinja2/{src => }/jinja2/loaders.py | 0 .../python/Jinja2/{src => }/jinja2/meta.py | 0 .../Jinja2/{src => }/jinja2/nativetypes.py | 0 .../python/Jinja2/{src => }/jinja2/nodes.py | 0 .../Jinja2/{src => }/jinja2/optimizer.py | 0 .../python/Jinja2/{src => }/jinja2/parser.py | 0 .../python/Jinja2/{src => }/jinja2/runtime.py | 0 .../python/Jinja2/{src => }/jinja2/sandbox.py | 0 .../python/Jinja2/{src => }/jinja2/tests.py | 0 .../python/Jinja2/{src => }/jinja2/utils.py | 0 .../python/Jinja2/{src => }/jinja2/visitor.py | 0 third_party/python/Jinja2/setup.cfg | 39 - third_party/python/Jinja2/setup.py | 56 - third_party/python/Jinja2/tox.ini | 20 - third_party/python/appdirs/.gitignore | 8 - third_party/python/appdirs/.travis.yml | 10 - third_party/python/appdirs/CHANGES.rst | 93 - third_party/python/appdirs/Dockerfile | 13 - third_party/python/appdirs/HACKING.md | 16 - third_party/python/appdirs/MANIFEST.in | 5 - third_party/python/appdirs/PKG-INFO | 262 - third_party/python/appdirs/README.rst | 138 - third_party/python/appdirs/TODO.md | 1 - .../{ => appdirs-1.4.4.dist-info}/LICENSE.txt | 0 .../appdirs/appdirs-1.4.4.dist-info/METADATA | 264 + .../appdirs/appdirs-1.4.4.dist-info/RECORD | 6 + .../appdirs/appdirs-1.4.4.dist-info/WHEEL | 6 + .../appdirs-1.4.4.dist-info/top_level.txt | 1 + third_party/python/appdirs/setup.cfg | 7 - third_party/python/appdirs/setup.py | 64 - third_party/python/appdirs/tox.ini | 5 - third_party/python/atomicwrites/LICENSE | 19 - third_party/python/atomicwrites/MANIFEST.in | 6 - third_party/python/atomicwrites/PKG-INFO | 112 - .../DESCRIPTION.rst} | 2 + .../atomicwrites-1.1.5.dist-info/METADATA | 114 + .../atomicwrites-1.1.5.dist-info/RECORD | 7 + .../atomicwrites-1.1.5.dist-info/WHEEL | 6 + .../metadata.json | 1 + .../top_level.txt | 1 + third_party/python/atomicwrites/setup.cfg | 8 - third_party/python/atomicwrites/setup.py | 27 - third_party/python/attrs/.coveragerc | 13 - .../python/attrs/.github/CODE_OF_CONDUCT.rst | 55 - .../python/attrs/.github/CONTRIBUTING.rst | 250 - .../attrs/.github/PULL_REQUEST_TEMPLATE.md | 18 - .../python/attrs/.pre-commit-config.yaml | 33 - third_party/python/attrs/.readthedocs.yml | 10 - third_party/python/attrs/.travis.yml | 77 - third_party/python/attrs/AUTHORS.rst | 11 - third_party/python/attrs/CHANGELOG.rst | 559 -- third_party/python/attrs/MANIFEST.in | 23 - third_party/python/attrs/PKG-INFO | 231 - .../python/attrs/{src => }/attr/__init__.py | 0 .../python/attrs/{src => }/attr/__init__.pyi | 0 .../python/attrs/{src => }/attr/_compat.py | 0 .../python/attrs/{src => }/attr/_config.py | 0 .../python/attrs/{src => }/attr/_funcs.py | 0 .../python/attrs/{src => }/attr/_make.py | 0 .../python/attrs/{src => }/attr/converters.py | 0 .../attrs/{src => }/attr/converters.pyi | 0 .../python/attrs/{src => }/attr/exceptions.py | 0 .../attrs/{src => }/attr/exceptions.pyi | 0 .../python/attrs/{src => }/attr/filters.py | 0 .../python/attrs/{src => }/attr/filters.pyi | 0 .../python/attrs/{src => }/attr/py.typed | 0 .../python/attrs/{src => }/attr/validators.py | 0 .../attrs/{src => }/attr/validators.pyi | 0 .../{ => attrs-19.1.0.dist-info}/LICENSE | 0 .../METADATA} | 111 + .../attrs/attrs-19.1.0.dist-info/RECORD | 20 + .../python/attrs/attrs-19.1.0.dist-info/WHEEL | 6 + .../attrs-19.1.0.dist-info/top_level.txt | 1 + .../attrs/changelog.d/towncrier_template.rst | 35 - third_party/python/attrs/codecov.yml | 10 - third_party/python/attrs/conftest.py | 41 - third_party/python/attrs/pyproject.toml | 36 - third_party/python/attrs/setup.cfg | 31 - third_party/python/attrs/setup.py | 122 - third_party/python/attrs/tox.ini | 85 - third_party/python/blessings/LICENSE | 19 - third_party/python/blessings/MANIFEST.in | 3 - third_party/python/blessings/PKG-INFO | 560 -- .../METADATA} | 33 + .../blessings/blessings-1.7.dist-info/RECORD | 6 + .../blessings/blessings-1.7.dist-info/WHEEL | 5 + .../blessings-1.7.dist-info/top_level.txt | 1 + third_party/python/blessings/setup.cfg | 5 - third_party/python/blessings/setup.py | 49 - third_party/python/blessings/tox.ini | 8 - third_party/python/certifi/MANIFEST.in | 1 - third_party/python/certifi/PKG-INFO | 69 - .../DESCRIPTION.rst} | 2 + .../LICENSE.txt} | 0 .../certifi-2018.4.16.dist-info/METADATA | 71 + .../certifi-2018.4.16.dist-info/RECORD | 11 + .../certifi/certifi-2018.4.16.dist-info/WHEEL | 6 + .../certifi-2018.4.16.dist-info/metadata.json | 1 + .../certifi-2018.4.16.dist-info/top_level.txt | 1 + third_party/python/certifi/setup.cfg | 11 - third_party/python/certifi/setup.py | 67 - third_party/python/chardet/MANIFEST.in | 8 - third_party/python/chardet/NOTES.rst | 140 - third_party/python/chardet/PKG-INFO | 99 - .../{ => chardet-4.0.0.dist-info}/LICENSE | 0 .../METADATA} | 33 + .../chardet/chardet-4.0.0.dist-info/RECORD | 49 + .../chardet/chardet-4.0.0.dist-info/WHEEL | 6 + .../chardet-4.0.0.dist-info/entry_points.txt | 3 + .../chardet-4.0.0.dist-info/top_level.txt | 1 + third_party/python/chardet/setup.cfg | 12 - third_party/python/chardet/setup.py | 53 - third_party/python/chardet/test.py | 146 - third_party/python/compare-locales/PKG-INFO | 82 - .../compare_locales/tests/__init__.py | 82 - .../tests/android/test_checks.py | 344 -- .../tests/android/test_merge.py | 82 - .../tests/android/test_parser.py | 128 - .../tests/data/bug121341.properties | 68 - .../tests/data/test.properties | 14 - .../tests/data/triple-license.dtd | 38 - .../compare_locales/tests/dtd/test_checks.py | 335 -- .../compare_locales/tests/dtd/test_merge.py | 133 - .../compare_locales/tests/dtd/test_parser.py | 271 - .../compare_locales/tests/fluent/__init__.py | 0 .../tests/fluent/test_checks.py | 581 -- .../tests/fluent/test_merge.py | 283 - .../tests/fluent/test_parser.py | 310 -- .../compare_locales/tests/lint/__init__.py | 0 .../compare_locales/tests/lint/test_linter.py | 97 - .../compare_locales/tests/lint/test_util.py | 91 - .../compare_locales/tests/merge/__init__.py | 0 .../tests/merge/test_comments.py | 188 - .../tests/merge/test_messages.py | 93 - .../tests/merge/test_unknown.py | 22 - .../tests/merge/test_whitespace.py | 76 - .../compare_locales/tests/paths/__init__.py | 132 - .../tests/paths/test_configparser.py | 126 - .../compare_locales/tests/paths/test_files.py | 572 -- .../compare_locales/tests/paths/test_ini.py | 90 - .../tests/paths/test_matcher.py | 500 -- .../compare_locales/tests/paths/test_paths.py | 28 - .../tests/paths/test_project.py | 229 - .../compare_locales/tests/po/__init__.py | 0 .../compare_locales/tests/po/test_parser.py | 139 - .../tests/properties/__init__.py | 0 .../tests/properties/test_checks.py | 109 - .../tests/properties/test_merge.py | 68 - .../tests/properties/test_parser.py | 243 - .../tests/serializer/__init__.py | 34 - .../tests/serializer/test_android.py | 218 - .../tests/serializer/test_fluent.py | 79 - .../tests/serializer/test_properties.py | 106 - .../compare_locales/tests/test_apps.py | 168 - .../compare_locales/tests/test_checks.py | 89 - .../compare_locales/tests/test_compare.py | 229 - .../compare_locales/tests/test_defines.py | 251 - .../compare_locales/tests/test_ini.py | 223 - .../compare_locales/tests/test_keyedtuple.py | 54 - .../compare_locales/tests/test_merge.py | 1408 ----- .../compare_locales/tests/test_mozpath.py | 139 - .../compare_locales/tests/test_parser.py | 118 - .../compare_locales/tests/test_util.py | 30 - third_party/python/compare-locales/setup.cfg | 7 - third_party/python/compare-locales/setup.py | 62 - .../DESCRIPTION.rst} | 2 + .../compare_locales-8.1.0.dist-info/METADATA | 87 + .../compare_locales-8.1.0.dist-info/RECORD | 97 + .../compare_locales-8.1.0.dist-info/WHEEL | 6 + .../entry_points.txt | 4 + .../metadata.json | 1 + .../top_level.txt | 1 + .../compare_locales/__init__.py | 0 .../compare_locales/checks/__init__.py | 0 .../compare_locales/checks/android.py | 0 .../compare_locales/checks/base.py | 0 .../compare_locales/checks/dtd.py | 0 .../compare_locales/checks/fluent.py | 0 .../compare_locales/checks/properties.py | 0 .../compare_locales/commands.py | 0 .../compare_locales/compare/__init__.py | 0 .../compare_locales/compare/content.py | 0 .../compare_locales/compare/observer.py | 0 .../compare_locales/compare/utils.py | 0 .../integration_tests/__init__.py | 0 .../integration_tests/test_plurals.py | 0 .../compare_locales/keyedtuple.py | 0 .../compare_locales/lint}/__init__.py | 0 .../compare_locales/lint/cli.py | 0 .../compare_locales/lint/linter.py | 0 .../compare_locales/lint/util.py | 0 .../compare_locales/merge.py | 0 .../compare_locales/mozpath.py | 0 .../compare_locales/parser/__init__.py | 0 .../compare_locales/parser/android.py | 0 .../compare_locales/parser/base.py | 0 .../compare_locales/parser/defines.py | 0 .../compare_locales/parser/dtd.py | 0 .../compare_locales/parser/fluent.py | 0 .../compare_locales/parser/ini.py | 0 .../compare_locales/parser/po.py | 0 .../compare_locales/parser/properties.py | 0 .../compare_locales/paths/__init__.py | 0 .../compare_locales/paths/configparser.py | 0 .../compare_locales/paths/files.py | 0 .../compare_locales/paths/ini.py | 0 .../compare_locales/paths/matcher.py | 0 .../compare_locales/paths/project.py | 0 .../compare_locales/plurals.py | 0 .../compare_locales/serializer.py | 0 .../compare_locales/util.py | 0 third_party/python/cookies/PKG-INFO | 109 - .../DESCRIPTION.rst} | 2 + .../cookies/cookies-2.2.1.dist-info/METADATA | 111 + .../cookies/cookies-2.2.1.dist-info/RECORD | 8 + .../cookies/cookies-2.2.1.dist-info/WHEEL | 6 + .../cookies-2.2.1.dist-info/metadata.json | 1 + .../cookies-2.2.1.dist-info/top_level.txt | 2 + third_party/python/cookies/setup.cfg | 8 - third_party/python/cookies/setup.py | 45 - third_party/python/diskcache/MANIFEST.in | 1 - third_party/python/diskcache/PKG-INFO | 428 -- .../{ => diskcache-4.1.0.dist-info}/LICENSE | 0 .../METADATA} | 26 + .../diskcache-4.1.0.dist-info/RECORD | 12 + .../diskcache/diskcache-4.1.0.dist-info/WHEEL | 6 + .../diskcache-4.1.0.dist-info/top_level.txt | 1 + third_party/python/diskcache/setup.cfg | 4 - third_party/python/diskcache/setup.py | 51 - third_party/python/distro/CHANGELOG.md | 147 - third_party/python/distro/CONTRIBUTING.md | 54 - third_party/python/distro/CONTRIBUTORS.md | 13 - third_party/python/distro/MANIFEST.in | 12 - third_party/python/distro/Makefile | 145 - third_party/python/distro/PKG-INFO | 168 - .../python/distro/dev-requirements.txt | 3 - .../{ => distro-1.4.0.dist-info}/LICENSE | 0 .../METADATA} | 30 + .../distro/distro-1.4.0.dist-info/RECORD | 7 + .../distro/distro-1.4.0.dist-info/WHEEL | 6 + .../distro-1.4.0.dist-info/entry_points.txt | 3 + .../distro-1.4.0.dist-info/top_level.txt | 1 + third_party/python/distro/distro.py | 0 .../python/distro/query_local_distro.py | 45 - third_party/python/distro/setup.cfg | 10 - third_party/python/distro/setup.py | 67 - third_party/python/ecdsa/MANIFEST.in | 3 - third_party/python/ecdsa/NEWS | 213 - third_party/python/ecdsa/PKG-INFO | 620 --- .../ecdsa/{ => ecdsa-0.15.dist-info}/LICENSE | 0 .../METADATA} | 30 + .../python/ecdsa/ecdsa-0.15.dist-info/RECORD | 28 + .../python/ecdsa/ecdsa-0.15.dist-info/WHEEL | 6 + .../ecdsa/ecdsa-0.15.dist-info/top_level.txt | 1 + .../python/ecdsa/{src => }/ecdsa/__init__.py | 0 .../python/ecdsa/{src => }/ecdsa/_compat.py | 0 .../python/ecdsa/{src => }/ecdsa/_rwlock.py | 0 .../python/ecdsa/{src => }/ecdsa/_version.py | 0 .../python/ecdsa/{src => }/ecdsa/curves.py | 0 .../python/ecdsa/{src => }/ecdsa/der.py | 0 .../python/ecdsa/{src => }/ecdsa/ecdh.py | 0 .../python/ecdsa/{src => }/ecdsa/ecdsa.py | 0 .../ecdsa/{src => }/ecdsa/ellipticcurve.py | 0 .../python/ecdsa/{src => }/ecdsa/keys.py | 0 .../ecdsa/{src => }/ecdsa/numbertheory.py | 0 .../python/ecdsa/{src => }/ecdsa/rfc6979.py | 0 .../python/ecdsa/{src => }/ecdsa/test_der.py | 0 .../python/ecdsa/{src => }/ecdsa/test_ecdh.py | 0 .../ecdsa/{src => }/ecdsa/test_ecdsa.py | 0 .../{src => }/ecdsa/test_ellipticcurve.py | 0 .../ecdsa/{src => }/ecdsa/test_jacobi.py | 0 .../python/ecdsa/{src => }/ecdsa/test_keys.py | 0 .../{src => }/ecdsa/test_malformed_sigs.py | 0 .../{src => }/ecdsa/test_numbertheory.py | 0 .../ecdsa/{src => }/ecdsa/test_pyecdsa.py | 0 .../ecdsa/{src => }/ecdsa/test_rw_lock.py | 0 .../python/ecdsa/{src => }/ecdsa/util.py | 0 third_party/python/ecdsa/setup.cfg | 15 - third_party/python/ecdsa/setup.py | 48 - third_party/python/ecdsa/versioneer.py | 1817 ------ third_party/python/fluent.syntax/PKG-INFO | 39 - .../DESCRIPTION.rst} | 2 + .../fluent.syntax-0.18.1.dist-info/METADATA | 41 + .../fluent.syntax-0.18.1.dist-info/RECORD | 14 + .../fluent.syntax-0.18.1.dist-info/WHEEL | 6 + .../metadata.json | 1 + .../top_level.txt | 1 + third_party/python/fluent.syntax/setup.cfg | 19 - third_party/python/fluent.syntax/setup.py | 29 - .../python/glean_parser/.circleci/config.yml | 212 - third_party/python/glean_parser/.editorconfig | 21 - third_party/python/glean_parser/.flake8 | 2 - .../glean_parser/.github/ISSUE_TEMPLATE.md | 15 - .../glean_parser/.github/dependabot.yml | 6 - .../.github/pull_request_template.md | 8 - third_party/python/glean_parser/.gitignore | 110 - .../python/glean_parser/.swiftlint.yml | 6 - .../python/glean_parser/CODE_OF_CONDUCT.md | 15 - .../python/glean_parser/CONTRIBUTING.md | 182 - third_party/python/glean_parser/MANIFEST.in | 14 - third_party/python/glean_parser/Makefile | 74 - third_party/python/glean_parser/PKG-INFO | 565 -- third_party/python/glean_parser/README.md | 52 - .../AUTHORS.md | 0 .../LICENSE | 0 .../METADATA} | 84 + .../glean_parser-3.6.0.dist-info/RECORD | 35 + .../glean_parser-3.6.0.dist-info/WHEEL | 5 + .../entry_points.txt | 3 + .../top_level.txt | 1 + .../python/glean_parser/requirements_dev.txt | 15 - third_party/python/glean_parser/setup.cfg | 13 - third_party/python/glean_parser/setup.py | 75 - .../tools/extract_data_categories.py | 176 - third_party/python/idna/HISTORY.rst | 162 - third_party/python/idna/MANIFEST.in | 6 - third_party/python/idna/PKG-INFO | 241 - .../{ => idna-2.10.dist-info}/LICENSE.rst | 0 .../METADATA} | 32 + .../python/idna/idna-2.10.dist-info/RECORD | 13 + .../python/idna/idna-2.10.dist-info/WHEEL | 6 + .../idna/idna-2.10.dist-info/top_level.txt | 1 + third_party/python/idna/setup.cfg | 7 - third_party/python/idna/setup.py | 59 - third_party/python/idna/tools/idna-data | 670 --- third_party/python/idna/tools/intranges.py | 53 - .../python/importlib_metadata/.coveragerc | 10 - .../python/importlib_metadata/.editorconfig | 15 - third_party/python/importlib_metadata/.flake8 | 10 - .../.github/workflows/automerge.yml | 27 - .../.github/workflows/main.yml | 76 - .../python/importlib_metadata/.gitignore | 13 - .../.pre-commit-config.yaml | 10 - .../importlib_metadata/.readthedocs.yml | 6 - .../python/importlib_metadata/CHANGES.rst | 512 -- .../python/importlib_metadata/PKG-INFO | 75 - .../python/importlib_metadata/conftest.py | 4 - .../LICENSE | 0 .../METADATA} | 37 + .../RECORD | 11 + .../importlib_metadata-3.10.1.dist-info/WHEEL | 5 + .../top_level.txt | 0 .../importlib_metadata.egg-info/PKG-INFO | 75 - .../importlib_metadata.egg-info/SOURCES.txt | 47 - .../dependency_links.txt | 1 - .../importlib_metadata.egg-info/requires.txt | 27 - .../python/importlib_metadata/mypy.ini | 2 - .../prepare/example/example/__init__.py | 2 - .../prepare/example/setup.py | 11 - .../python/importlib_metadata/pyproject.toml | 20 - .../python/importlib_metadata/pytest.ini | 7 - .../python/importlib_metadata/setup.cfg | 59 - .../python/importlib_metadata/setup.py | 6 - .../python/importlib_metadata/skeleton.md | 166 - third_party/python/importlib_metadata/tox.ini | 91 - third_party/python/iso8601/MANIFEST.in | 2 - third_party/python/iso8601/PKG-INFO | 221 - .../python/iso8601/dev-requirements.txt | 8 - .../{ => iso8601-0.1.14.dist-info}/LICENSE | 0 .../METADATA} | 18 + .../iso8601/iso8601-0.1.14.dist-info/RECORD | 8 + .../iso8601/iso8601-0.1.14.dist-info/WHEEL | 6 + .../iso8601-0.1.14.dist-info/top_level.txt | 1 + third_party/python/iso8601/setup.cfg | 4 - third_party/python/iso8601/setup.py | 34 - third_party/python/iso8601/tox.ini | 18 - third_party/python/jsonschema/.appveyor.yml | 33 - third_party/python/jsonschema/.coveragerc | 5 - .../python/jsonschema/.github/FUNDING.yml | 5 - .../python/jsonschema/.github/SECURITY.md | 21 - third_party/python/jsonschema/.gitignore | 5 - third_party/python/jsonschema/.travis.yml | 30 - third_party/python/jsonschema/CHANGELOG.rst | 196 - third_party/python/jsonschema/DEMO.ipynb | 167 - third_party/python/jsonschema/MANIFEST.in | 4 - third_party/python/jsonschema/PKG-INFO | 206 - third_party/python/jsonschema/codecov.yml | 11 - third_party/python/jsonschema/demo.yml | 2 - third_party/python/jsonschema/json/.gitignore | 1 - .../python/jsonschema/json/.travis.yml | 8 - third_party/python/jsonschema/json/LICENSE | 19 - third_party/python/jsonschema/json/README.md | 181 - .../jsonschema/json/bin/jsonschema_suite | 298 - third_party/python/jsonschema/json/index.js | 45 - .../python/jsonschema/json/package.json | 28 - .../json/remotes/folder/folderInteger.json | 3 - .../jsonschema/json/remotes/integer.json | 3 - .../jsonschema/json/remotes/name-defs.json | 15 - .../python/jsonschema/json/remotes/name.json | 15 - .../jsonschema/json/remotes/subSchemas.json | 8 - .../python/jsonschema/json/test-schema.json | 59 - .../tests/draft2019-09/additionalItems.json | 87 - .../draft2019-09/additionalProperties.json | 133 - .../json/tests/draft2019-09/allOf.json | 218 - .../json/tests/draft2019-09/anchor.json | 87 - .../json/tests/draft2019-09/anyOf.json | 189 - .../tests/draft2019-09/boolean_schema.json | 104 - .../json/tests/draft2019-09/const.json | 170 - .../json/tests/draft2019-09/contains.json | 95 - .../json/tests/draft2019-09/default.json | 49 - .../json/tests/draft2019-09/defs.json | 24 - .../json/tests/draft2019-09/dependencies.json | 268 - .../json/tests/draft2019-09/enum.json | 179 - .../tests/draft2019-09/exclusiveMaximum.json | 30 - .../tests/draft2019-09/exclusiveMinimum.json | 30 - .../json/tests/draft2019-09/format.json | 614 --- .../json/tests/draft2019-09/if-then-else.json | 188 - .../json/tests/draft2019-09/items.json | 250 - .../json/tests/draft2019-09/maxItems.json | 28 - .../json/tests/draft2019-09/maxLength.json | 33 - .../tests/draft2019-09/maxProperties.json | 38 - .../json/tests/draft2019-09/maximum.json | 28 - .../json/tests/draft2019-09/minItems.json | 28 - .../json/tests/draft2019-09/minLength.json | 33 - .../tests/draft2019-09/minProperties.json | 38 - .../json/tests/draft2019-09/minimum.json | 59 - .../json/tests/draft2019-09/multipleOf.json | 60 - .../json/tests/draft2019-09/not.json | 117 - .../json/tests/draft2019-09/oneOf.json | 206 - .../tests/draft2019-09/optional/bignum.json | 105 - .../tests/draft2019-09/optional/content.json | 77 - .../optional/ecmascript-regex.json | 213 - .../optional/format/date-time.json | 53 - .../draft2019-09/optional/format/date.json | 23 - .../draft2019-09/optional/format/email.json | 18 - .../optional/format/hostname.json | 33 - .../optional/format/idn-email.json | 18 - .../optional/format/idn-hostname.json | 28 - .../draft2019-09/optional/format/ipv4.json | 33 - .../draft2019-09/optional/format/ipv6.json | 28 - .../optional/format/iri-reference.json | 43 - .../draft2019-09/optional/format/iri.json | 53 - .../optional/format/json-pointer.json | 168 - .../draft2019-09/optional/format/regex.json | 18 - .../format/relative-json-pointer.json | 33 - .../draft2019-09/optional/format/time.json | 23 - .../optional/format/uri-reference.json | 43 - .../optional/format/uri-template.json | 28 - .../draft2019-09/optional/format/uri.json | 103 - .../optional/zeroTerminatedFloats.json | 15 - .../json/tests/draft2019-09/pattern.json | 34 - .../tests/draft2019-09/patternProperties.json | 151 - .../json/tests/draft2019-09/properties.json | 167 - .../tests/draft2019-09/propertyNames.json | 78 - .../json/tests/draft2019-09/ref.json | 359 -- .../json/tests/draft2019-09/refRemote.json | 167 - .../json/tests/draft2019-09/required.json | 105 - .../json/tests/draft2019-09/type.json | 464 -- .../json/tests/draft2019-09/uniqueItems.json | 173 - .../json/tests/draft3/additionalItems.json | 82 - .../tests/draft3/additionalProperties.json | 133 - .../jsonschema/json/tests/draft3/default.json | 49 - .../json/tests/draft3/dependencies.json | 118 - .../json/tests/draft3/disallow.json | 80 - .../json/tests/draft3/divisibleBy.json | 60 - .../jsonschema/json/tests/draft3/enum.json | 71 - .../jsonschema/json/tests/draft3/extends.json | 94 - .../jsonschema/json/tests/draft3/format.json | 362 -- .../jsonschema/json/tests/draft3/items.json | 46 - .../json/tests/draft3/maxItems.json | 28 - .../json/tests/draft3/maxLength.json | 33 - .../jsonschema/json/tests/draft3/maximum.json | 42 - .../json/tests/draft3/minItems.json | 28 - .../json/tests/draft3/minLength.json | 33 - .../jsonschema/json/tests/draft3/minimum.json | 73 - .../json/tests/draft3/optional/bignum.json | 107 - .../draft3/optional/ecmascript-regex.json | 18 - .../json/tests/draft3/optional/format.json | 227 - .../draft3/optional/zeroTerminatedFloats.json | 15 - .../jsonschema/json/tests/draft3/pattern.json | 34 - .../json/tests/draft3/patternProperties.json | 115 - .../json/tests/draft3/properties.json | 97 - .../jsonschema/json/tests/draft3/ref.json | 192 - .../json/tests/draft3/refRemote.json | 74 - .../json/tests/draft3/required.json | 53 - .../jsonschema/json/tests/draft3/type.json | 489 -- .../json/tests/draft3/uniqueItems.json | 163 - .../json/tests/draft4/additionalItems.json | 87 - .../tests/draft4/additionalProperties.json | 133 - .../jsonschema/json/tests/draft4/allOf.json | 185 - .../jsonschema/json/tests/draft4/anyOf.json | 156 - .../jsonschema/json/tests/draft4/default.json | 49 - .../json/tests/draft4/definitions.json | 32 - .../json/tests/draft4/dependencies.json | 194 - .../jsonschema/json/tests/draft4/enum.json | 179 - .../jsonschema/json/tests/draft4/format.json | 218 - .../jsonschema/json/tests/draft4/items.json | 195 - .../json/tests/draft4/maxItems.json | 28 - .../json/tests/draft4/maxLength.json | 33 - .../json/tests/draft4/maxProperties.json | 38 - .../jsonschema/json/tests/draft4/maximum.json | 73 - .../json/tests/draft4/minItems.json | 28 - .../json/tests/draft4/minLength.json | 33 - .../json/tests/draft4/minProperties.json | 38 - .../jsonschema/json/tests/draft4/minimum.json | 104 - .../json/tests/draft4/multipleOf.json | 60 - .../jsonschema/json/tests/draft4/not.json | 96 - .../jsonschema/json/tests/draft4/oneOf.json | 162 - .../json/tests/draft4/optional/bignum.json | 107 - .../draft4/optional/ecmascript-regex.json | 213 - .../json/tests/draft4/optional/format.json | 253 - .../draft4/optional/zeroTerminatedFloats.json | 15 - .../jsonschema/json/tests/draft4/pattern.json | 34 - .../json/tests/draft4/patternProperties.json | 120 - .../json/tests/draft4/properties.json | 136 - .../jsonschema/json/tests/draft4/ref.json | 411 -- .../json/tests/draft4/refRemote.json | 171 - .../json/tests/draft4/required.json | 89 - .../jsonschema/json/tests/draft4/type.json | 464 -- .../json/tests/draft4/uniqueItems.json | 173 - .../json/tests/draft6/additionalItems.json | 87 - .../tests/draft6/additionalProperties.json | 133 - .../jsonschema/json/tests/draft6/allOf.json | 218 - .../jsonschema/json/tests/draft6/anyOf.json | 189 - .../json/tests/draft6/boolean_schema.json | 104 - .../jsonschema/json/tests/draft6/const.json | 170 - .../json/tests/draft6/contains.json | 100 - .../jsonschema/json/tests/draft6/default.json | 49 - .../json/tests/draft6/definitions.json | 32 - .../json/tests/draft6/dependencies.json | 268 - .../jsonschema/json/tests/draft6/enum.json | 179 - .../json/tests/draft6/exclusiveMaximum.json | 30 - .../json/tests/draft6/exclusiveMinimum.json | 30 - .../jsonschema/json/tests/draft6/format.json | 326 -- .../jsonschema/json/tests/draft6/items.json | 250 - .../json/tests/draft6/maxItems.json | 28 - .../json/tests/draft6/maxLength.json | 33 - .../json/tests/draft6/maxProperties.json | 38 - .../jsonschema/json/tests/draft6/maximum.json | 28 - .../json/tests/draft6/minItems.json | 28 - .../json/tests/draft6/minLength.json | 33 - .../json/tests/draft6/minProperties.json | 38 - .../jsonschema/json/tests/draft6/minimum.json | 59 - .../json/tests/draft6/multipleOf.json | 60 - .../jsonschema/json/tests/draft6/not.json | 117 - .../jsonschema/json/tests/draft6/oneOf.json | 206 - .../json/tests/draft6/optional/bignum.json | 105 - .../draft6/optional/ecmascript-regex.json | 213 - .../json/tests/draft6/optional/format.json | 491 -- .../draft6/optional/zeroTerminatedFloats.json | 15 - .../jsonschema/json/tests/draft6/pattern.json | 34 - .../json/tests/draft6/patternProperties.json | 151 - .../json/tests/draft6/properties.json | 167 - .../json/tests/draft6/propertyNames.json | 78 - .../jsonschema/json/tests/draft6/ref.json | 443 -- .../json/tests/draft6/refRemote.json | 171 - .../json/tests/draft6/required.json | 105 - .../jsonschema/json/tests/draft6/type.json | 464 -- .../json/tests/draft6/uniqueItems.json | 173 - .../json/tests/draft7/additionalItems.json | 87 - .../tests/draft7/additionalProperties.json | 133 - .../jsonschema/json/tests/draft7/allOf.json | 218 - .../jsonschema/json/tests/draft7/anyOf.json | 189 - .../json/tests/draft7/boolean_schema.json | 104 - .../jsonschema/json/tests/draft7/const.json | 170 - .../json/tests/draft7/contains.json | 100 - .../jsonschema/json/tests/draft7/default.json | 49 - .../json/tests/draft7/definitions.json | 32 - .../json/tests/draft7/dependencies.json | 268 - .../jsonschema/json/tests/draft7/enum.json | 179 - .../json/tests/draft7/exclusiveMaximum.json | 30 - .../json/tests/draft7/exclusiveMinimum.json | 30 - .../jsonschema/json/tests/draft7/format.json | 614 --- .../json/tests/draft7/if-then-else.json | 188 - .../jsonschema/json/tests/draft7/items.json | 250 - .../json/tests/draft7/maxItems.json | 28 - .../json/tests/draft7/maxLength.json | 33 - .../json/tests/draft7/maxProperties.json | 38 - .../jsonschema/json/tests/draft7/maximum.json | 28 - .../json/tests/draft7/minItems.json | 28 - .../json/tests/draft7/minLength.json | 33 - .../json/tests/draft7/minProperties.json | 38 - .../jsonschema/json/tests/draft7/minimum.json | 59 - .../json/tests/draft7/multipleOf.json | 60 - .../jsonschema/json/tests/draft7/not.json | 117 - .../jsonschema/json/tests/draft7/oneOf.json | 206 - .../json/tests/draft7/optional/bignum.json | 105 - .../json/tests/draft7/optional/content.json | 77 - .../draft7/optional/ecmascript-regex.json | 213 - .../draft7/optional/format/date-time.json | 53 - .../tests/draft7/optional/format/date.json | 23 - .../tests/draft7/optional/format/email.json | 18 - .../draft7/optional/format/hostname.json | 33 - .../draft7/optional/format/idn-email.json | 18 - .../draft7/optional/format/idn-hostname.json | 28 - .../tests/draft7/optional/format/ipv4.json | 33 - .../tests/draft7/optional/format/ipv6.json | 28 - .../draft7/optional/format/iri-reference.json | 43 - .../tests/draft7/optional/format/iri.json | 53 - .../draft7/optional/format/json-pointer.json | 168 - .../tests/draft7/optional/format/regex.json | 18 - .../format/relative-json-pointer.json | 33 - .../tests/draft7/optional/format/time.json | 23 - .../draft7/optional/format/uri-reference.json | 43 - .../draft7/optional/format/uri-template.json | 28 - .../tests/draft7/optional/format/uri.json | 103 - .../draft7/optional/zeroTerminatedFloats.json | 15 - .../jsonschema/json/tests/draft7/pattern.json | 34 - .../json/tests/draft7/patternProperties.json | 151 - .../json/tests/draft7/properties.json | 167 - .../json/tests/draft7/propertyNames.json | 78 - .../jsonschema/json/tests/draft7/ref.json | 443 -- .../json/tests/draft7/refRemote.json | 171 - .../json/tests/draft7/required.json | 105 - .../jsonschema/json/tests/draft7/type.json | 464 -- .../json/tests/draft7/uniqueItems.json | 173 - .../json/tests/latest/additionalItems.json | 87 - .../tests/latest/additionalProperties.json | 133 - .../jsonschema/json/tests/latest/allOf.json | 218 - .../jsonschema/json/tests/latest/anchor.json | 87 - .../jsonschema/json/tests/latest/anyOf.json | 189 - .../json/tests/latest/boolean_schema.json | 104 - .../jsonschema/json/tests/latest/const.json | 170 - .../json/tests/latest/contains.json | 95 - .../jsonschema/json/tests/latest/default.json | 49 - .../jsonschema/json/tests/latest/defs.json | 24 - .../json/tests/latest/dependencies.json | 268 - .../jsonschema/json/tests/latest/enum.json | 179 - .../json/tests/latest/exclusiveMaximum.json | 30 - .../json/tests/latest/exclusiveMinimum.json | 30 - .../jsonschema/json/tests/latest/format.json | 614 --- .../json/tests/latest/if-then-else.json | 188 - .../jsonschema/json/tests/latest/items.json | 250 - .../json/tests/latest/maxItems.json | 28 - .../json/tests/latest/maxLength.json | 33 - .../json/tests/latest/maxProperties.json | 38 - .../jsonschema/json/tests/latest/maximum.json | 28 - .../json/tests/latest/minItems.json | 28 - .../json/tests/latest/minLength.json | 33 - .../json/tests/latest/minProperties.json | 38 - .../jsonschema/json/tests/latest/minimum.json | 59 - .../json/tests/latest/multipleOf.json | 60 - .../jsonschema/json/tests/latest/not.json | 117 - .../jsonschema/json/tests/latest/oneOf.json | 206 - .../json/tests/latest/optional/bignum.json | 105 - .../json/tests/latest/optional/content.json | 77 - .../latest/optional/ecmascript-regex.json | 213 - .../latest/optional/format/date-time.json | 53 - .../tests/latest/optional/format/date.json | 23 - .../tests/latest/optional/format/email.json | 18 - .../latest/optional/format/hostname.json | 33 - .../latest/optional/format/idn-email.json | 18 - .../latest/optional/format/idn-hostname.json | 28 - .../tests/latest/optional/format/ipv4.json | 33 - .../tests/latest/optional/format/ipv6.json | 28 - .../latest/optional/format/iri-reference.json | 43 - .../tests/latest/optional/format/iri.json | 53 - .../latest/optional/format/json-pointer.json | 168 - .../tests/latest/optional/format/regex.json | 18 - .../format/relative-json-pointer.json | 33 - .../tests/latest/optional/format/time.json | 23 - .../latest/optional/format/uri-reference.json | 43 - .../latest/optional/format/uri-template.json | 28 - .../tests/latest/optional/format/uri.json | 103 - .../latest/optional/zeroTerminatedFloats.json | 15 - .../jsonschema/json/tests/latest/pattern.json | 34 - .../json/tests/latest/patternProperties.json | 151 - .../json/tests/latest/properties.json | 167 - .../json/tests/latest/propertyNames.json | 78 - .../jsonschema/json/tests/latest/ref.json | 359 -- .../json/tests/latest/refRemote.json | 167 - .../json/tests/latest/required.json | 105 - .../jsonschema/json/tests/latest/type.json | 464 -- .../json/tests/latest/uniqueItems.json | 173 - third_party/python/jsonschema/json/tox.ini | 9 - .../{ => jsonschema-3.2.0.dist-info}/COPYING | 0 .../METADATA} | 45 + .../jsonschema-3.2.0.dist-info/RECORD | 34 + .../jsonschema-3.2.0.dist-info/WHEEL | 6 + .../entry_points.txt | 0 .../top_level.txt | 0 .../jsonschema/jsonschema.egg-info/PKG-INFO | 206 - .../jsonschema.egg-info/SOURCES.txt | 354 -- .../jsonschema.egg-info/dependency_links.txt | 1 - .../jsonschema.egg-info/requires.txt | 24 - .../jsonschema/benchmarks/issue232/issue.json | 2653 --------- .../jsonschema/jsonschema/tests/__init__.py | 0 .../jsonschema/jsonschema/tests/_helpers.py | 5 - .../jsonschema/jsonschema/tests/_suite.py | 239 - .../jsonschema/jsonschema/tests/test_cli.py | 151 - .../jsonschema/tests/test_exceptions.py | 462 -- .../jsonschema/tests/test_format.py | 89 - .../tests/test_jsonschema_test_suite.py | 277 - .../jsonschema/jsonschema/tests/test_types.py | 190 - .../jsonschema/tests/test_validators.py | 1762 ------ third_party/python/jsonschema/pyproject.toml | 8 - third_party/python/jsonschema/setup.cfg | 81 - third_party/python/jsonschema/setup.py | 2 - .../python/jsonschema/test-requirements.txt | 1 - third_party/python/jsonschema/tox.ini | 153 - third_party/python/more-itertools/LICENSE | 19 - third_party/python/more-itertools/MANIFEST.in | 9 - third_party/python/more-itertools/PKG-INFO | 430 -- .../more_itertools/tests/__init__.py | 0 .../more_itertools/tests/test_more.py | 2074 ------- .../more_itertools/tests/test_recipes.py | 616 --- third_party/python/more-itertools/setup.cfg | 8 - third_party/python/more-itertools/setup.py | 59 - third_party/python/more-itertools/tox.ini | 5 - .../more_itertools-4.3.0.dist-info/METADATA} | 279 + .../more_itertools-4.3.0.dist-info/RECORD | 10 + .../more_itertools-4.3.0.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../more_itertools/__init__.py | 0 .../more_itertools/more.py | 0 .../more_itertools/recipes.py | 0 .../python/mozilla-version/MANIFEST.in | 8 - third_party/python/mozilla-version/README.md | 28 - .../mozilla_version/test/__init__.py | 5 - .../mozilla_version/test/test_balrog.py | 172 - .../mozilla_version/test/test_gecko.py | 411 -- .../mozilla_version/test/test_maven.py | 87 - .../mozilla_version/test/test_version.py | 171 - .../requirements-coveralls.txt | 140 - .../mozilla-version/requirements-docs.txt | 122 - .../mozilla-version/requirements-test.txt | 140 - .../python/mozilla-version/requirements.txt | 14 - .../mozilla-version/requirements.txt.in | 3 - third_party/python/mozilla-version/setup.cfg | 4 - third_party/python/mozilla-version/setup.py | 38 - .../python/mozilla-version/version.txt | 1 - .../mozilla_version-0.3.4.dist-info}/LICENSE | 0 .../mozilla_version-0.3.4.dist-info/METADATA} | 12 +- .../mozilla_version-0.3.4.dist-info/RECORD | 17 + .../mozilla_version-0.3.4.dist-info/WHEEL | 6 + .../top_level.txt | 1 + .../mozilla_version/__init__.py | 0 .../mozilla_version/balrog.py | 0 .../mozilla_version/errors.py | 0 .../mozilla_version/gecko.py | 0 .../mozilla_version/maven.py | 0 .../mozilla_version/parser.py | 0 .../mozilla_version/version.py | 0 .../pathlib2-2.3.2.dist-info/DESCRIPTION.rst | 47 + .../pathlib2-2.3.2.dist-info/METADATA | 76 + .../pathlib2/pathlib2-2.3.2.dist-info/RECORD | 7 + .../pathlib2/pathlib2-2.3.2.dist-info/WHEEL | 6 + .../pathlib2-2.3.2.dist-info/metadata.json | 1 + .../pathlib2-2.3.2.dist-info/top_level.txt | 1 + third_party/python/pathspec/CHANGES.rst | 202 - third_party/python/pathspec/MANIFEST.in | 2 - third_party/python/pathspec/PKG-INFO | 380 -- third_party/python/pathspec/README.rst | 153 - .../{ => pathspec-0.8.0.dist-info}/LICENSE | 0 .../pathspec-0.8.0.dist-info/METADATA | 382 ++ .../pathspec/pathspec-0.8.0.dist-info/RECORD | 16 + .../pathspec/pathspec-0.8.0.dist-info/WHEEL | 6 + .../pathspec-0.8.0.dist-info/top_level.txt | 1 + .../pathspec/pathspec/tests/__init__.py | 0 .../pathspec/tests/test_gitwildmatch.py | 474 -- .../pathspec/pathspec/tests/test_pathspec.py | 129 - .../pathspec/pathspec/tests/test_util.py | 380 -- third_party/python/pathspec/setup.cfg | 7 - third_party/python/pathspec/setup.py | 44 - third_party/python/pip-tools/.bandit | 2 - third_party/python/pip-tools/.coveragerc | 8 - third_party/python/pip-tools/.fussyfox.yml | 3 - .../.github/ISSUE_TEMPLATE/bug-report.md | 28 - .../.github/ISSUE_TEMPLATE/feature-request.md | 19 - .../.github/PULL_REQUEST_TEMPLATE.md | 9 - .../python/pip-tools/.github/workflows/ci.yml | 67 - .../pip-tools/.github/workflows/cron.yml | 76 - .../python/pip-tools/.github/workflows/qa.yml | 44 - .../pip-tools/.github/workflows/release.yml | 43 - third_party/python/pip-tools/.gitignore | 31 - .../python/pip-tools/.pre-commit-config.yaml | 24 - .../python/pip-tools/.pre-commit-hooks.yaml | 7 - third_party/python/pip-tools/CHANGELOG.md | 646 --- third_party/python/pip-tools/CONTRIBUTING.md | 49 - third_party/python/pip-tools/PKG-INFO | 527 -- .../python/pip-tools/examples/django.in | 3 - .../python/pip-tools/examples/flask.in | 2 - .../python/pip-tools/examples/hypothesis.in | 1 - .../python/pip-tools/examples/protection.in | 3 - .../python/pip-tools/examples/sentry.in | 2 - .../pip-tools/img/pip-tools-overview.png | Bin 23961 -> 0 bytes .../pip-tools/piptools/scripts/__init__.py | 0 third_party/python/pip-tools/setup.cfg | 77 - third_party/python/pip-tools/setup.py | 3 - third_party/python/pip-tools/tox.ini | 39 - .../pip_tools-5.5.0.dist-info}/LICENSE | 0 .../pip_tools-5.5.0.dist-info/METADATA} | 38 + .../pip_tools-5.5.0.dist-info/RECORD | 28 + .../pip_tools/pip_tools-5.5.0.dist-info/WHEEL | 6 + .../entry_points.txt | 4 + .../pip_tools-5.5.0.dist-info/top_level.txt | 1 + .../piptools/__init__.py | 0 .../piptools/__main__.py | 0 .../piptools/_compat/__init__.py | 0 .../piptools/_compat/contextlib.py | 0 .../piptools/_compat/pip_compat.py | 0 .../piptools/_compat/tempfile.py | 0 .../piptools/cache.py | 0 .../piptools/click.py | 0 .../piptools/exceptions.py | 0 .../piptools/locations.py | 0 .../piptools/logging.py | 0 .../piptools/repositories/__init__.py | 0 .../piptools/repositories/base.py | 0 .../piptools/repositories/local.py | 0 .../piptools/repositories/pypi.py | 0 .../piptools/resolver.py | 0 .../piptools/scripts}/__init__.py | 0 .../piptools/scripts/compile.py | 0 .../piptools/scripts/sync.py | 0 .../{pip-tools => pip_tools}/piptools/sync.py | 0 .../piptools/utils.py | 0 .../piptools/writer.py | 0 third_party/python/pluggy/MANIFEST.in | 7 - third_party/python/pluggy/PKG-INFO | 112 - .../DESCRIPTION.rst} | 2 + .../LICENSE.txt} | 0 .../pluggy/pluggy-0.6.0.dist-info/METADATA | 114 + .../pluggy/pluggy-0.6.0.dist-info/RECORD | 9 + .../pluggy/pluggy-0.6.0.dist-info/WHEEL | 5 + .../pluggy-0.6.0.dist-info/metadata.json | 1 + .../pluggy-0.6.0.dist-info/top_level.txt | 1 + third_party/python/pluggy/setup.cfg | 13 - third_party/python/pluggy/setup.py | 51 - .../python/pluggy/testing/benchmark.py | 59 - third_party/python/pluggy/testing/conftest.py | 30 - .../python/pluggy/testing/test_details.py | 103 - .../python/pluggy/testing/test_helpers.py | 68 - .../python/pluggy/testing/test_hookrelay.py | 210 - .../pluggy/testing/test_method_ordering.py | 322 -- .../python/pluggy/testing/test_multicall.py | 194 - .../pluggy/testing/test_pluginmanager.py | 374 -- .../python/pluggy/testing/test_tracer.py | 89 - third_party/python/pluggy/tox.ini | 44 - third_party/python/py/.flake8 | 4 - third_party/python/py/.gitattributes | 1 - .../python/py/.github/workflows/main.yml | 68 - third_party/python/py/.gitignore | 15 - third_party/python/py/AUTHORS | 25 - third_party/python/py/CHANGELOG.rst | 1229 ----- third_party/python/py/MANIFEST.in | 11 - third_party/python/py/PKG-INFO | 64 - third_party/python/py/README.rst | 31 - third_party/python/py/RELEASING.rst | 17 - third_party/python/py/bench/localpath.py | 73 - third_party/python/py/codecov.yml | 7 - third_party/python/py/conftest.py | 60 - .../py/{ => py-1.10.0.dist-info}/LICENSE | 0 .../python/py/py-1.10.0.dist-info/METADATA | 66 + .../python/py/py-1.10.0.dist-info/RECORD | 63 + .../python/py/py-1.10.0.dist-info/WHEEL | 6 + .../py/py-1.10.0.dist-info/top_level.txt | 1 + third_party/python/py/setup.cfg | 13 - third_party/python/py/setup.py | 45 - third_party/python/py/tasks/__init__.py | 0 third_party/python/py/tasks/vendoring.py | 41 - .../python/py/testing/code/test_assertion.py | 305 - .../python/py/testing/code/test_code.py | 159 - .../python/py/testing/code/test_excinfo.py | 956 ---- .../python/py/testing/code/test_source.py | 656 --- third_party/python/py/testing/conftest.py | 3 - third_party/python/py/testing/io_/__init__.py | 1 - .../python/py/testing/io_/test_capture.py | 501 -- .../python/py/testing/io_/test_saferepr.py | 75 - .../py/testing/io_/test_terminalwriter.py | 305 - .../io_/test_terminalwriter_linewidth.py | 56 - third_party/python/py/testing/log/__init__.py | 0 third_party/python/py/testing/log/test_log.py | 191 - .../python/py/testing/log/test_warning.py | 86 - third_party/python/py/testing/path/common.py | 492 -- .../python/py/testing/path/conftest.py | 80 - .../python/py/testing/path/repotest.dump | 228 - .../python/py/testing/path/svntestbase.py | 31 - .../python/py/testing/path/test_cacheutil.py | 89 - .../python/py/testing/path/test_local.py | 1078 ---- .../python/py/testing/path/test_svnauth.py | 460 -- .../python/py/testing/path/test_svnurl.py | 95 - .../python/py/testing/path/test_svnwc.py | 557 -- .../python/py/testing/process/__init__.py | 1 - .../python/py/testing/process/test_cmdexec.py | 41 - .../py/testing/process/test_forkedfunc.py | 173 - .../py/testing/process/test_killproc.py | 18 - .../python/py/testing/root/__init__.py | 1 - .../python/py/testing/root/test_builtin.py | 156 - .../python/py/testing/root/test_error.py | 76 - .../python/py/testing/root/test_py_imports.py | 71 - .../python/py/testing/root/test_std.py | 13 - .../python/py/testing/root/test_xmlgen.py | 146 - third_party/python/py/tox.ini | 44 - third_party/python/pyasn1/CHANGES.rst | 716 --- third_party/python/pyasn1/MANIFEST.in | 5 - third_party/python/pyasn1/PKG-INFO | 35 - third_party/python/pyasn1/README.md | 184 - third_party/python/pyasn1/TODO.rst | 92 - .../{ => pyasn1-0.4.8.dist-info}/LICENSE.rst | 0 .../METADATA} | 7 +- .../pyasn1/pyasn1-0.4.8.dist-info/RECORD | 42 + .../pyasn1/pyasn1-0.4.8.dist-info/WHEEL | 6 + .../top_level.txt | 0 .../zip-safe | 0 .../python/pyasn1/pyasn1.egg-info/SOURCES.txt | 161 - .../pyasn1.egg-info/dependency_links.txt | 1 - third_party/python/pyasn1/setup.cfg | 10 - third_party/python/pyasn1/setup.py | 121 - third_party/python/pytest/.coveragerc | 4 - third_party/python/pytest/.gitattributes | 1 - .../python/pytest/.github/ISSUE_TEMPLATE.md | 8 - .../pytest/.github/PULL_REQUEST_TEMPLATE.md | 14 - third_party/python/pytest/.gitignore | 40 - .../python/pytest/.pre-commit-config.yaml | 36 - third_party/python/pytest/.travis.yml | 83 - third_party/python/pytest/AUTHORS | 213 - third_party/python/pytest/CHANGELOG.rst | 4883 ----------------- third_party/python/pytest/CONTRIBUTING.rst | 294 - third_party/python/pytest/HOWTORELEASE.rst | 49 - third_party/python/pytest/PKG-INFO | 149 - .../pytest/{src => }/_pytest/__init__.py | 0 .../pytest/{src => }/_pytest/_argcomplete.py | 0 .../{src => }/_pytest/_code/__init__.py | 0 .../{src => }/_pytest/_code/_py2traceback.py | 0 .../pytest/{src => }/_pytest/_code/code.py | 0 .../pytest/{src => }/_pytest/_code/source.py | 0 .../pytest/{src => }/_pytest/_version.py | 0 .../{src => }/_pytest/assertion/__init__.py | 0 .../{src => }/_pytest/assertion/rewrite.py | 0 .../{src => }/_pytest/assertion/truncate.py | 0 .../{src => }/_pytest/assertion/util.py | 0 .../pytest/{src => }/_pytest/cacheprovider.py | 0 .../pytest/{src => }/_pytest/capture.py | 0 .../python/pytest/{src => }/_pytest/compat.py | 0 .../{src => }/_pytest/config/__init__.py | 0 .../{src => }/_pytest/config/argparsing.py | 0 .../{src => }/_pytest/config/exceptions.py | 0 .../{src => }/_pytest/config/findpaths.py | 0 .../pytest/{src => }/_pytest/debugging.py | 0 .../pytest/{src => }/_pytest/deprecated.py | 0 .../pytest/{src => }/_pytest/doctest.py | 0 .../pytest/{src => }/_pytest/fixtures.py | 0 .../{src => }/_pytest/freeze_support.py | 0 .../pytest/{src => }/_pytest/helpconfig.py | 0 .../pytest/{src => }/_pytest/hookspec.py | 0 .../pytest/{src => }/_pytest/junitxml.py | 0 .../pytest/{src => }/_pytest/logging.py | 0 .../python/pytest/{src => }/_pytest/main.py | 0 .../pytest/{src => }/_pytest/mark/__init__.py | 0 .../pytest/{src => }/_pytest/mark/evaluate.py | 0 .../pytest/{src => }/_pytest/mark/legacy.py | 0 .../{src => }/_pytest/mark/structures.py | 0 .../pytest/{src => }/_pytest/monkeypatch.py | 0 .../python/pytest/{src => }/_pytest/nodes.py | 0 .../python/pytest/{src => }/_pytest/nose.py | 0 .../pytest/{src => }/_pytest/outcomes.py | 0 .../pytest/{src => }/_pytest/pastebin.py | 0 .../pytest/{src => }/_pytest/pytester.py | 0 .../python/pytest/{src => }/_pytest/python.py | 0 .../pytest/{src => }/_pytest/python_api.py | 0 .../pytest/{src => }/_pytest/recwarn.py | 0 .../pytest/{src => }/_pytest/resultlog.py | 0 .../python/pytest/{src => }/_pytest/runner.py | 0 .../pytest/{src => }/_pytest/setuponly.py | 0 .../pytest/{src => }/_pytest/setupplan.py | 0 .../pytest/{src => }/_pytest/skipping.py | 0 .../pytest/{src => }/_pytest/terminal.py | 0 .../python/pytest/{src => }/_pytest/tmpdir.py | 0 .../pytest/{src => }/_pytest/unittest.py | 0 .../pytest/{src => }/_pytest/warnings.py | 0 third_party/python/pytest/appveyor.yml | 48 - third_party/python/pytest/bench/bench.py | 13 - .../python/pytest/bench/bench_argcomplete.py | 22 - third_party/python/pytest/bench/empty.py | 4 - third_party/python/pytest/bench/manyparam.py | 15 - third_party/python/pytest/bench/skip.py | 11 - .../python/pytest/changelog/README.rst | 32 - .../python/pytest/changelog/_template.rst | 40 - third_party/python/pytest/extra/get_issues.py | 84 - .../pytest/extra/setup-py.test/setup.py | 11 - third_party/python/pytest/pyproject.toml | 43 - .../LICENSE.txt} | 0 .../METADATA} | 44 + .../pytest/pytest-3.6.2.dist-info/RECORD | 57 + .../pytest/pytest-3.6.2.dist-info/WHEEL | 6 + .../pytest-3.6.2.dist-info/entry_points.txt | 4 + .../pytest-3.6.2.dist-info/top_level.txt | 2 + third_party/python/pytest/{src => }/pytest.py | 0 .../python/pytest/scripts/call-tox.bat | 8 - .../python/pytest/scripts/install-pypy.bat | 6 - third_party/python/pytest/setup.cfg | 25 - third_party/python/pytest/setup.py | 124 - third_party/python/pytest/tasks/__init__.py | 10 - third_party/python/pytest/tasks/generate.py | 118 - .../python/pytest/tasks/release.minor.rst | 27 - .../python/pytest/tasks/release.patch.rst | 17 - .../python/pytest/tasks/requirements.txt | 6 - .../python/pytest/testing/acceptance_test.py | 1066 ---- .../python/pytest/testing/code/test_code.py | 210 - .../pytest/testing/code/test_excinfo.py | 1357 ----- .../python/pytest/testing/code/test_source.py | 758 --- .../code/test_source_multiline_block.py | 29 - .../python/pytest/testing/deprecated_test.py | 265 - .../python/pytest/testing/freeze/.gitignore | 3 - .../testing/freeze/create_executable.py | 12 - .../pytest/testing/freeze/runtests_script.py | 10 - .../testing/freeze/tests/test_doctest.txt | 6 - .../testing/freeze/tests/test_trivial.py | 6 - .../python/pytest/testing/freeze/tox_run.py | 12 - .../pytest/testing/logging/test_fixture.py | 119 - .../pytest/testing/logging/test_formatter.py | 37 - .../pytest/testing/logging/test_reporting.py | 874 --- .../python/pytest/testing/python/approx.py | 406 -- .../python/pytest/testing/python/collect.py | 1555 ------ .../python/pytest/testing/python/fixture.py | 4011 -------------- .../pytest/testing/python/integration.py | 453 -- .../python/pytest/testing/python/metafunc.py | 1768 ------ .../python/pytest/testing/python/raises.py | 177 - .../pytest/testing/python/setup_only.py | 269 - .../pytest/testing/python/setup_plan.py | 19 - .../testing/python/show_fixtures_per_test.py | 183 - .../testing/python/test_deprecations.py | 22 - .../python/pytest/testing/test_argcomplete.py | 109 - .../python/pytest/testing/test_assertion.py | 1172 ---- .../pytest/testing/test_assertrewrite.py | 1144 ---- .../pytest/testing/test_cacheprovider.py | 820 --- .../python/pytest/testing/test_capture.py | 1394 ----- .../python/pytest/testing/test_collection.py | 944 ---- .../python/pytest/testing/test_compat.py | 110 - .../python/pytest/testing/test_config.py | 1068 ---- .../python/pytest/testing/test_conftest.py | 543 -- .../python/pytest/testing/test_doctest.py | 1206 ---- .../pytest/testing/test_entry_points.py | 14 - .../python/pytest/testing/test_helpconfig.py | 72 - .../python/pytest/testing/test_junitxml.py | 1231 ----- .../python/pytest/testing/test_mark.py | 1134 ---- .../python/pytest/testing/test_modimport.py | 29 - .../python/pytest/testing/test_monkeypatch.py | 368 -- .../python/pytest/testing/test_nodes.py | 21 - .../python/pytest/testing/test_nose.py | 433 -- .../python/pytest/testing/test_parseopt.py | 336 -- .../python/pytest/testing/test_pastebin.py | 132 - third_party/python/pytest/testing/test_pdb.py | 702 --- .../pytest/testing/test_pluginmanager.py | 386 -- .../python/pytest/testing/test_pytester.py | 401 -- .../python/pytest/testing/test_recwarn.py | 347 -- .../python/pytest/testing/test_resultlog.py | 243 - .../python/pytest/testing/test_runner.py | 951 ---- .../pytest/testing/test_runner_xunit.py | 352 -- .../python/pytest/testing/test_session.py | 343 -- .../python/pytest/testing/test_skipping.py | 1194 ---- .../python/pytest/testing/test_terminal.py | 1267 ----- .../python/pytest/testing/test_tmpdir.py | 212 - .../python/pytest/testing/test_unittest.py | 992 ---- .../python/pytest/testing/test_warnings.py | 290 - third_party/python/pytest/tox.ini | 212 - third_party/python/redo/README.md | 147 - .../python/redo/redo-2.0.3.dist-info/AUTHORS | 7 + .../METADATA} | 7 +- .../python/redo/redo-2.0.3.dist-info/RECORD | 8 + .../python/redo/redo-2.0.3.dist-info/WHEEL | 6 + .../entry_points.txt | 0 .../top_level.txt | 0 .../python/redo/redo.egg-info/PKG-INFO | 10 - .../python/redo/redo.egg-info/SOURCES.txt | 10 - .../redo/redo.egg-info/dependency_links.txt | 1 - third_party/python/redo/setup.cfg | 7 - third_party/python/redo/setup.py | 16 - third_party/python/requests/HISTORY.md | 1710 ------ third_party/python/requests/MANIFEST.in | 2 - third_party/python/requests/NOTICE | 2 - third_party/python/requests/PKG-INFO | 93 - third_party/python/requests/pytest.ini | 3 - .../{ => requests-2.25.1.dist-info}/LICENSE | 0 .../METADATA} | 41 + .../requests/requests-2.25.1.dist-info/RECORD | 23 + .../requests/requests-2.25.1.dist-info/WHEEL | 6 + .../top_level.txt | 0 .../requests/requests.egg-info/PKG-INFO | 93 - .../requests/requests.egg-info/SOURCES.txt | 47 - .../requests.egg-info/dependency_links.txt | 1 - .../requests/requests.egg-info/not-zip-safe | 1 - .../requests/requests.egg-info/requires.txt | 14 - .../python/requests/requirements-dev.txt | 6 - third_party/python/requests/setup.cfg | 10 - third_party/python/requests/setup.py | 112 - third_party/python/responses/CHANGES | 119 - third_party/python/responses/MANIFEST.in | 3 - third_party/python/responses/PKG-INFO | 443 -- .../{ => responses-0.10.6.dist-info}/LICENSE | 0 .../METADATA} | 34 + .../responses-0.10.6.dist-info/RECORD | 6 + .../responses-0.10.6.dist-info/WHEEL | 6 + .../responses-0.10.6.dist-info/top_level.txt | 1 + third_party/python/responses/setup.cfg | 16 - third_party/python/responses/setup.py | 85 - .../python/responses/test_responses.py | 924 ---- third_party/python/responses/tox.ini | 7 - third_party/python/sentry-sdk/MANIFEST.in | 2 - third_party/python/sentry-sdk/README.md | 42 - .../sentry-sdk/sentry_sdk.egg-info/PKG-INFO | 43 - .../sentry_sdk.egg-info/SOURCES.txt | 64 - .../sentry_sdk.egg-info/dependency_links.txt | 1 - .../sentry_sdk.egg-info/not-zip-safe | 1 - .../sentry_sdk.egg-info/requires.txt | 39 - third_party/python/sentry-sdk/setup.cfg | 7 - third_party/python/sentry-sdk/setup.py | 58 - .../sentry_sdk-0.14.3.dist-info}/LICENSE | 0 .../sentry_sdk-0.14.3.dist-info/METADATA} | 51 +- .../sentry_sdk-0.14.3.dist-info/RECORD | 58 + .../sentry_sdk-0.14.3.dist-info/WHEEL | 6 + .../top_level.txt | 0 .../sentry_sdk/__init__.py | 0 .../sentry_sdk/_compat.py | 0 .../sentry_sdk/_types.py | 0 .../sentry_sdk/api.py | 0 .../sentry_sdk/client.py | 0 .../sentry_sdk/consts.py | 0 .../sentry_sdk/debug.py | 0 .../sentry_sdk/envelope.py | 0 .../sentry_sdk/hub.py | 0 .../sentry_sdk/integrations/__init__.py | 0 .../sentry_sdk/integrations/_wsgi_common.py | 0 .../sentry_sdk/integrations/aiohttp.py | 0 .../sentry_sdk/integrations/argv.py | 0 .../sentry_sdk/integrations/asgi.py | 0 .../sentry_sdk/integrations/atexit.py | 0 .../sentry_sdk/integrations/aws_lambda.py | 0 .../sentry_sdk/integrations/beam.py | 0 .../sentry_sdk/integrations/bottle.py | 0 .../sentry_sdk/integrations/celery.py | 0 .../sentry_sdk/integrations/dedupe.py | 0 .../integrations/django/__init__.py | 0 .../sentry_sdk/integrations/django/asgi.py | 0 .../integrations/django/middleware.py | 0 .../integrations/django/templates.py | 0 .../integrations/django/transactions.py | 0 .../sentry_sdk/integrations/excepthook.py | 0 .../sentry_sdk/integrations/falcon.py | 0 .../sentry_sdk/integrations/flask.py | 0 .../sentry_sdk/integrations/gnu_backtrace.py | 0 .../sentry_sdk/integrations/logging.py | 0 .../sentry_sdk/integrations/modules.py | 0 .../sentry_sdk/integrations/pyramid.py | 0 .../sentry_sdk/integrations/redis.py | 0 .../sentry_sdk/integrations/rq.py | 0 .../sentry_sdk/integrations/sanic.py | 0 .../sentry_sdk/integrations/serverless.py | 0 .../sentry_sdk/integrations/spark/__init__.py | 0 .../integrations/spark/spark_driver.py | 0 .../integrations/spark/spark_worker.py | 0 .../sentry_sdk/integrations/sqlalchemy.py | 0 .../sentry_sdk/integrations/stdlib.py | 0 .../sentry_sdk/integrations/threading.py | 0 .../sentry_sdk/integrations/tornado.py | 0 .../sentry_sdk/integrations/trytond.py | 0 .../sentry_sdk/integrations/wsgi.py | 0 .../sentry_sdk/py.typed | 0 .../sentry_sdk/scope.py | 0 .../sentry_sdk/serializer.py | 0 .../sentry_sdk/sessions.py | 0 .../sentry_sdk/tracing.py | 0 .../sentry_sdk/transport.py | 0 .../sentry_sdk/utils.py | 0 .../sentry_sdk/worker.py | 0 third_party/python/six/CHANGES | 315 -- third_party/python/six/MANIFEST.in | 6 - third_party/python/six/PKG-INFO | 50 - third_party/python/six/documentation/Makefile | 130 - third_party/python/six/documentation/conf.py | 217 - .../python/six/documentation/index.rst | 875 --- third_party/python/six/setup.cfg | 24 - third_party/python/six/setup.py | 58 - .../six/{ => six-1.13.0.dist-info}/LICENSE | 0 .../METADATA} | 20 + .../python/six/six-1.13.0.dist-info/RECORD | 6 + .../python/six/six-1.13.0.dist-info/WHEEL | 6 + .../six/six-1.13.0.dist-info/top_level.txt | 1 + third_party/python/six/test_six.py | 1060 ---- .../python/typing_extensions/MANIFEST.in | 5 - .../python/typing_extensions/README.rst | 90 - .../python/typing_extensions/setup.cfg | 7 - third_party/python/typing_extensions/setup.py | 69 - .../src_py2/test_typing_extensions.py | 456 -- .../src_py2/typing_extensions.py | 283 - .../src_py3/test_typing_extensions.py | 1940 ------- .../LICENSE | 0 .../METADATA} | 41 +- .../RECORD | 6 + .../typing_extensions-3.7.4.3.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../{src_py3 => }/typing_extensions.py | 0 third_party/python/urllib3/CONTRIBUTORS.txt | 304 - third_party/python/urllib3/MANIFEST.in | 5 - third_party/python/urllib3/PKG-INFO | 1253 ----- third_party/python/urllib3/README.rst | 104 - .../python/urllib3/dev-requirements.txt | 16 - .../python/urllib3/dummyserver/__init__.py | 0 .../urllib3/dummyserver/certs/README.rst | 17 - .../urllib3/dummyserver/certs/cacert.key | 27 - .../urllib3/dummyserver/certs/cacert.pem | 21 - .../urllib3/dummyserver/certs/server.crt | 21 - .../urllib3/dummyserver/certs/server.key | 27 - .../python/urllib3/dummyserver/handlers.py | 328 -- .../python/urllib3/dummyserver/proxy.py | 139 - .../python/urllib3/dummyserver/server.py | 188 - .../python/urllib3/dummyserver/testcase.py | 210 - third_party/python/urllib3/setup.cfg | 31 - third_party/python/urllib3/setup.py | 83 - .../urllib3/src/urllib3.egg-info/PKG-INFO | 1253 ----- .../urllib3/src/urllib3.egg-info/SOURCES.txt | 115 - .../src/urllib3.egg-info/dependency_links.txt | 1 - .../urllib3/src/urllib3.egg-info/requires.txt | 15 - .../urllib3/src/urllib3/contrib/__init__.py | 0 .../contrib/_securetransport/__init__.py | 0 .../urllib3/packages/backports/__init__.py | 0 .../LICENSE.txt | 0 .../METADATA} | 150 + .../urllib3/urllib3-1.25.9.dist-info/RECORD | 41 + .../urllib3/urllib3-1.25.9.dist-info/WHEEL | 6 + .../top_level.txt | 0 .../urllib3/{src => }/urllib3/__init__.py | 0 .../urllib3/{src => }/urllib3/_collections.py | 0 .../urllib3/{src => }/urllib3/connection.py | 0 .../{src => }/urllib3/connectionpool.py | 0 .../urllib3/contrib}/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 0 .../contrib/_securetransport}/__init__.py | 0 .../contrib/_securetransport/bindings.py | 0 .../contrib/_securetransport/low_level.py | 0 .../{src => }/urllib3/contrib/appengine.py | 0 .../{src => }/urllib3/contrib/ntlmpool.py | 0 .../{src => }/urllib3/contrib/pyopenssl.py | 0 .../urllib3/contrib/securetransport.py | 0 .../{src => }/urllib3/contrib/socks.py | 0 .../urllib3/{src => }/urllib3/exceptions.py | 0 .../urllib3/{src => }/urllib3/fields.py | 0 .../urllib3/{src => }/urllib3/filepost.py | 0 .../{src => }/urllib3/packages/__init__.py | 0 .../urllib3/packages/backports}/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 0 .../urllib3/{src => }/urllib3/packages/six.py | 0 .../packages/ssl_match_hostname/__init__.py | 0 .../ssl_match_hostname/_implementation.py | 0 .../urllib3/{src => }/urllib3/poolmanager.py | 0 .../urllib3/{src => }/urllib3/request.py | 0 .../urllib3/{src => }/urllib3/response.py | 0 .../{src => }/urllib3/util/__init__.py | 0 .../{src => }/urllib3/util/connection.py | 0 .../urllib3/{src => }/urllib3/util/queue.py | 0 .../urllib3/{src => }/urllib3/util/request.py | 0 .../{src => }/urllib3/util/response.py | 0 .../urllib3/{src => }/urllib3/util/retry.py | 0 .../urllib3/{src => }/urllib3/util/ssl_.py | 0 .../urllib3/{src => }/urllib3/util/timeout.py | 0 .../urllib3/{src => }/urllib3/util/url.py | 0 .../urllib3/{src => }/urllib3/util/wait.py | 0 third_party/python/voluptuous/CHANGELOG.md | 104 - third_party/python/voluptuous/COPYING | 25 - third_party/python/voluptuous/MANIFEST.in | 4 - third_party/python/voluptuous/PKG-INFO | 744 --- third_party/python/voluptuous/setup.cfg | 9 - third_party/python/voluptuous/setup.py | 40 - .../METADATA} | 23 + .../voluptuous-0.11.5.dist-info/RECORD | 10 + .../voluptuous-0.11.5.dist-info/WHEEL | 6 + .../voluptuous-0.11.5.dist-info/top_level.txt | 1 + .../voluptuous/voluptuous/tests/__init__.py | 1 - .../voluptuous/voluptuous/tests/tests.md | 273 - .../voluptuous/voluptuous/tests/tests.py | 1265 ----- third_party/python/yamllint/MANIFEST.in | 4 - third_party/python/yamllint/README.rst | 144 - third_party/python/yamllint/setup.cfg | 17 - third_party/python/yamllint/setup.py | 56 - .../{ => yamllint-1.23.0.dist-info}/LICENSE | 0 .../METADATA} | 16 +- .../yamllint/yamllint-1.23.0.dist-info/RECORD | 37 + .../yamllint/yamllint-1.23.0.dist-info/WHEEL | 6 + .../entry_points.txt | 3 + .../yamllint-1.23.0.dist-info/top_level.txt | 1 + third_party/python/zipp/.coveragerc | 5 - third_party/python/zipp/.editorconfig | 15 - third_party/python/zipp/.flake8 | 9 - .../zipp/.github/workflows/automerge.yml | 27 - .../python/zipp/.github/workflows/main.yml | 42 - .../python/zipp/.pre-commit-config.yaml | 10 - third_party/python/zipp/.readthedocs.yml | 6 - third_party/python/zipp/CHANGES.rst | 179 - third_party/python/zipp/PKG-INFO | 40 - third_party/python/zipp/README.rst | 22 - third_party/python/zipp/conftest.py | 0 third_party/python/zipp/mypy.ini | 2 - third_party/python/zipp/pyproject.toml | 20 - third_party/python/zipp/pytest.ini | 7 - third_party/python/zipp/setup.cfg | 54 - third_party/python/zipp/setup.py | 6 - third_party/python/zipp/skeleton.md | 166 - third_party/python/zipp/test_zipp.py | 360 -- third_party/python/zipp/tox.ini | 42 - .../zipp/{ => zipp-3.4.1.dist-info}/LICENSE | 0 .../python/zipp/zipp-3.4.1.dist-info/METADATA | 54 + .../python/zipp/zipp-3.4.1.dist-info/RECORD | 6 + .../python/zipp/zipp-3.4.1.dist-info/WHEEL | 5 + .../zipp/zipp-3.4.1.dist-info/top_level.txt | 1 + 1384 files changed, 3952 insertions(+), 141824 deletions(-) delete mode 100644 third_party/python/Click/CHANGES.rst delete mode 100644 third_party/python/Click/CONTRIBUTING.rst rename third_party/python/Click/{LICENSE.rst => Click-7.0.dist-info/LICENSE.txt} (100%) rename third_party/python/Click/{README.rst => Click-7.0.dist-info/METADATA} (67%) create mode 100644 third_party/python/Click/Click-7.0.dist-info/RECORD create mode 100644 third_party/python/Click/Click-7.0.dist-info/WHEEL create mode 100644 third_party/python/Click/Click-7.0.dist-info/top_level.txt delete mode 100644 third_party/python/Click/MANIFEST.in delete mode 100644 third_party/python/Click/PKG-INFO delete mode 100644 third_party/python/Click/artwork/logo.svg delete mode 100644 third_party/python/Click/examples/README delete mode 100644 third_party/python/Click/examples/aliases/README delete mode 100644 third_party/python/Click/examples/aliases/aliases.ini delete mode 100644 third_party/python/Click/examples/aliases/aliases.py delete mode 100644 third_party/python/Click/examples/aliases/setup.py delete mode 100644 third_party/python/Click/examples/bashcompletion/README delete mode 100644 third_party/python/Click/examples/bashcompletion/bashcompletion.py delete mode 100644 third_party/python/Click/examples/bashcompletion/setup.py delete mode 100644 third_party/python/Click/examples/colors/README delete mode 100644 third_party/python/Click/examples/colors/colors.py delete mode 100644 third_party/python/Click/examples/colors/setup.py delete mode 100644 third_party/python/Click/examples/complex/README delete mode 100644 third_party/python/Click/examples/complex/complex/cli.py delete mode 100644 third_party/python/Click/examples/complex/complex/commands/cmd_init.py delete mode 100644 third_party/python/Click/examples/complex/complex/commands/cmd_status.py delete mode 100644 third_party/python/Click/examples/complex/setup.py delete mode 100644 third_party/python/Click/examples/imagepipe/.gitignore delete mode 100644 third_party/python/Click/examples/imagepipe/README delete mode 100644 third_party/python/Click/examples/imagepipe/example01.jpg delete mode 100644 third_party/python/Click/examples/imagepipe/example02.jpg delete mode 100644 third_party/python/Click/examples/imagepipe/imagepipe.py delete mode 100644 third_party/python/Click/examples/imagepipe/setup.py delete mode 100644 third_party/python/Click/examples/inout/README delete mode 100644 third_party/python/Click/examples/inout/inout.py delete mode 100644 third_party/python/Click/examples/inout/setup.py delete mode 100644 third_party/python/Click/examples/naval/README delete mode 100644 third_party/python/Click/examples/naval/naval.py delete mode 100644 third_party/python/Click/examples/naval/setup.py delete mode 100644 third_party/python/Click/examples/repo/README delete mode 100644 third_party/python/Click/examples/repo/repo.py delete mode 100644 third_party/python/Click/examples/repo/setup.py delete mode 100644 third_party/python/Click/examples/termui/README delete mode 100644 third_party/python/Click/examples/termui/setup.py delete mode 100644 third_party/python/Click/examples/termui/termui.py delete mode 100644 third_party/python/Click/examples/validation/README delete mode 100644 third_party/python/Click/examples/validation/setup.py delete mode 100644 third_party/python/Click/examples/validation/validation.py delete mode 100644 third_party/python/Click/setup.cfg delete mode 100644 third_party/python/Click/setup.py delete mode 100644 third_party/python/Click/tox.ini delete mode 100644 third_party/python/Jinja2/CHANGES.rst rename third_party/python/Jinja2/{ => Jinja2-2.11.3.dist-info}/LICENSE.rst (100%) rename third_party/python/Jinja2/{README.rst => Jinja2-2.11.3.dist-info/METADATA} (52%) create mode 100644 third_party/python/Jinja2/Jinja2-2.11.3.dist-info/RECORD create mode 100644 third_party/python/Jinja2/Jinja2-2.11.3.dist-info/WHEEL create mode 100644 third_party/python/Jinja2/Jinja2-2.11.3.dist-info/entry_points.txt create mode 100644 third_party/python/Jinja2/Jinja2-2.11.3.dist-info/top_level.txt delete mode 100644 third_party/python/Jinja2/MANIFEST.in delete mode 100644 third_party/python/Jinja2/PKG-INFO delete mode 100644 third_party/python/Jinja2/artwork/jinjalogo.svg delete mode 100644 third_party/python/Jinja2/examples/basic/cycle.py delete mode 100644 third_party/python/Jinja2/examples/basic/debugger.py delete mode 100644 third_party/python/Jinja2/examples/basic/inheritance.py delete mode 100644 third_party/python/Jinja2/examples/basic/templates/broken.html delete mode 100644 third_party/python/Jinja2/examples/basic/templates/subbroken.html delete mode 100644 third_party/python/Jinja2/examples/basic/test.py delete mode 100644 third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py delete mode 100644 third_party/python/Jinja2/examples/basic/test_loop_filter.py delete mode 100644 third_party/python/Jinja2/examples/basic/translate.py delete mode 100644 third_party/python/Jinja2/ext/Vim/jinja.vim rename third_party/python/Jinja2/{src => }/jinja2/__init__.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/_compat.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/_identifier.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/asyncfilters.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/asyncsupport.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/bccache.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/compiler.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/constants.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/debug.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/defaults.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/environment.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/exceptions.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/ext.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/filters.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/idtracking.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/lexer.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/loaders.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/meta.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/nativetypes.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/nodes.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/optimizer.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/parser.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/runtime.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/sandbox.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/tests.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/utils.py (100%) rename third_party/python/Jinja2/{src => }/jinja2/visitor.py (100%) delete mode 100644 third_party/python/Jinja2/setup.cfg delete mode 100644 third_party/python/Jinja2/setup.py delete mode 100644 third_party/python/Jinja2/tox.ini delete mode 100644 third_party/python/appdirs/.gitignore delete mode 100644 third_party/python/appdirs/.travis.yml delete mode 100644 third_party/python/appdirs/CHANGES.rst delete mode 100644 third_party/python/appdirs/Dockerfile delete mode 100644 third_party/python/appdirs/HACKING.md delete mode 100644 third_party/python/appdirs/MANIFEST.in delete mode 100644 third_party/python/appdirs/PKG-INFO delete mode 100644 third_party/python/appdirs/README.rst delete mode 100644 third_party/python/appdirs/TODO.md rename third_party/python/appdirs/{ => appdirs-1.4.4.dist-info}/LICENSE.txt (100%) create mode 100644 third_party/python/appdirs/appdirs-1.4.4.dist-info/METADATA create mode 100644 third_party/python/appdirs/appdirs-1.4.4.dist-info/RECORD create mode 100644 third_party/python/appdirs/appdirs-1.4.4.dist-info/WHEEL create mode 100644 third_party/python/appdirs/appdirs-1.4.4.dist-info/top_level.txt delete mode 100644 third_party/python/appdirs/setup.cfg delete mode 100644 third_party/python/appdirs/setup.py delete mode 100644 third_party/python/appdirs/tox.ini delete mode 100644 third_party/python/atomicwrites/LICENSE delete mode 100644 third_party/python/atomicwrites/MANIFEST.in delete mode 100644 third_party/python/atomicwrites/PKG-INFO rename third_party/python/atomicwrites/{README.rst => atomicwrites-1.1.5.dist-info/DESCRIPTION.rst} (99%) create mode 100644 third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/METADATA create mode 100644 third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/RECORD create mode 100644 third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/WHEEL create mode 100644 third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/metadata.json create mode 100644 third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/top_level.txt delete mode 100644 third_party/python/atomicwrites/setup.cfg delete mode 100644 third_party/python/atomicwrites/setup.py delete mode 100644 third_party/python/attrs/.coveragerc delete mode 100644 third_party/python/attrs/.github/CODE_OF_CONDUCT.rst delete mode 100644 third_party/python/attrs/.github/CONTRIBUTING.rst delete mode 100644 third_party/python/attrs/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 third_party/python/attrs/.pre-commit-config.yaml delete mode 100644 third_party/python/attrs/.readthedocs.yml delete mode 100644 third_party/python/attrs/.travis.yml delete mode 100644 third_party/python/attrs/AUTHORS.rst delete mode 100644 third_party/python/attrs/CHANGELOG.rst delete mode 100644 third_party/python/attrs/MANIFEST.in delete mode 100644 third_party/python/attrs/PKG-INFO rename third_party/python/attrs/{src => }/attr/__init__.py (100%) rename third_party/python/attrs/{src => }/attr/__init__.pyi (100%) rename third_party/python/attrs/{src => }/attr/_compat.py (100%) rename third_party/python/attrs/{src => }/attr/_config.py (100%) rename third_party/python/attrs/{src => }/attr/_funcs.py (100%) rename third_party/python/attrs/{src => }/attr/_make.py (100%) rename third_party/python/attrs/{src => }/attr/converters.py (100%) rename third_party/python/attrs/{src => }/attr/converters.pyi (100%) rename third_party/python/attrs/{src => }/attr/exceptions.py (100%) rename third_party/python/attrs/{src => }/attr/exceptions.pyi (100%) rename third_party/python/attrs/{src => }/attr/filters.py (100%) rename third_party/python/attrs/{src => }/attr/filters.pyi (100%) rename third_party/python/attrs/{src => }/attr/py.typed (100%) rename third_party/python/attrs/{src => }/attr/validators.py (100%) rename third_party/python/attrs/{src => }/attr/validators.pyi (100%) rename third_party/python/attrs/{ => attrs-19.1.0.dist-info}/LICENSE (100%) rename third_party/python/attrs/{README.rst => attrs-19.1.0.dist-info/METADATA} (50%) create mode 100644 third_party/python/attrs/attrs-19.1.0.dist-info/RECORD create mode 100644 third_party/python/attrs/attrs-19.1.0.dist-info/WHEEL create mode 100644 third_party/python/attrs/attrs-19.1.0.dist-info/top_level.txt delete mode 100644 third_party/python/attrs/changelog.d/towncrier_template.rst delete mode 100644 third_party/python/attrs/codecov.yml delete mode 100644 third_party/python/attrs/conftest.py delete mode 100644 third_party/python/attrs/pyproject.toml delete mode 100644 third_party/python/attrs/setup.cfg delete mode 100644 third_party/python/attrs/setup.py delete mode 100644 third_party/python/attrs/tox.ini delete mode 100644 third_party/python/blessings/LICENSE delete mode 100644 third_party/python/blessings/MANIFEST.in delete mode 100644 third_party/python/blessings/PKG-INFO rename third_party/python/blessings/{README.rst => blessings-1.7.dist-info/METADATA} (93%) create mode 100644 third_party/python/blessings/blessings-1.7.dist-info/RECORD create mode 100644 third_party/python/blessings/blessings-1.7.dist-info/WHEEL create mode 100644 third_party/python/blessings/blessings-1.7.dist-info/top_level.txt delete mode 100644 third_party/python/blessings/setup.cfg delete mode 100644 third_party/python/blessings/setup.py delete mode 100644 third_party/python/blessings/tox.ini delete mode 100644 third_party/python/certifi/MANIFEST.in delete mode 100644 third_party/python/certifi/PKG-INFO rename third_party/python/certifi/{README.rst => certifi-2018.4.16.dist-info/DESCRIPTION.rst} (99%) rename third_party/python/certifi/{LICENSE => certifi-2018.4.16.dist-info/LICENSE.txt} (100%) create mode 100644 third_party/python/certifi/certifi-2018.4.16.dist-info/METADATA create mode 100644 third_party/python/certifi/certifi-2018.4.16.dist-info/RECORD create mode 100644 third_party/python/certifi/certifi-2018.4.16.dist-info/WHEEL create mode 100644 third_party/python/certifi/certifi-2018.4.16.dist-info/metadata.json create mode 100644 third_party/python/certifi/certifi-2018.4.16.dist-info/top_level.txt delete mode 100644 third_party/python/certifi/setup.cfg delete mode 100755 third_party/python/certifi/setup.py delete mode 100644 third_party/python/chardet/MANIFEST.in delete mode 100644 third_party/python/chardet/NOTES.rst delete mode 100644 third_party/python/chardet/PKG-INFO rename third_party/python/chardet/{ => chardet-4.0.0.dist-info}/LICENSE (100%) rename third_party/python/chardet/{README.rst => chardet-4.0.0.dist-info/METADATA} (61%) create mode 100644 third_party/python/chardet/chardet-4.0.0.dist-info/RECORD create mode 100644 third_party/python/chardet/chardet-4.0.0.dist-info/WHEEL create mode 100644 third_party/python/chardet/chardet-4.0.0.dist-info/entry_points.txt create mode 100644 third_party/python/chardet/chardet-4.0.0.dist-info/top_level.txt delete mode 100644 third_party/python/chardet/setup.cfg delete mode 100755 third_party/python/chardet/setup.py delete mode 100644 third_party/python/chardet/test.py delete mode 100644 third_party/python/compare-locales/PKG-INFO delete mode 100644 third_party/python/compare-locales/compare_locales/tests/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/android/test_checks.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/android/test_merge.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/android/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/data/bug121341.properties delete mode 100644 third_party/python/compare-locales/compare_locales/tests/data/test.properties delete mode 100644 third_party/python/compare-locales/compare_locales/tests/data/triple-license.dtd delete mode 100644 third_party/python/compare-locales/compare_locales/tests/dtd/test_checks.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/dtd/test_merge.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/dtd/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/fluent/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/fluent/test_checks.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/fluent/test_merge.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/fluent/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/lint/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/lint/test_linter.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/lint/test_util.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/merge/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/merge/test_comments.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/merge/test_messages.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/merge/test_unknown.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/merge/test_whitespace.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_configparser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_files.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_ini.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_matcher.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_paths.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/paths/test_project.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/po/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/po/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/properties/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/properties/test_checks.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/properties/test_merge.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/properties/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/serializer/__init__.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/serializer/test_android.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/serializer/test_fluent.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/serializer/test_properties.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_apps.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_checks.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_compare.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_defines.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_ini.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_keyedtuple.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_merge.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_mozpath.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_parser.py delete mode 100644 third_party/python/compare-locales/compare_locales/tests/test_util.py delete mode 100644 third_party/python/compare-locales/setup.cfg delete mode 100755 third_party/python/compare-locales/setup.py rename third_party/python/{compare-locales/README.md => compare_locales/compare_locales-8.1.0.dist-info/DESCRIPTION.rst} (99%) create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/METADATA create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/RECORD create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/WHEEL create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/entry_points.txt create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/metadata.json create mode 100644 third_party/python/compare_locales/compare_locales-8.1.0.dist-info/top_level.txt rename third_party/python/{compare-locales => compare_locales}/compare_locales/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/android.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/base.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/dtd.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/fluent.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/checks/properties.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/commands.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/compare/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/compare/content.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/compare/observer.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/compare/utils.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/integration_tests/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/integration_tests/test_plurals.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/keyedtuple.py (100%) rename third_party/python/{Click/examples/complex/complex => compare_locales/compare_locales/lint}/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/lint/cli.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/lint/linter.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/lint/util.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/merge.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/mozpath.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/android.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/base.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/defines.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/dtd.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/fluent.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/ini.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/po.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/parser/properties.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/__init__.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/configparser.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/files.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/ini.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/matcher.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/paths/project.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/plurals.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/serializer.py (100%) rename third_party/python/{compare-locales => compare_locales}/compare_locales/util.py (100%) delete mode 100644 third_party/python/cookies/PKG-INFO rename third_party/python/cookies/{README => cookies-2.2.1.dist-info/DESCRIPTION.rst} (99%) create mode 100644 third_party/python/cookies/cookies-2.2.1.dist-info/METADATA create mode 100644 third_party/python/cookies/cookies-2.2.1.dist-info/RECORD create mode 100644 third_party/python/cookies/cookies-2.2.1.dist-info/WHEEL create mode 100644 third_party/python/cookies/cookies-2.2.1.dist-info/metadata.json create mode 100644 third_party/python/cookies/cookies-2.2.1.dist-info/top_level.txt delete mode 100644 third_party/python/cookies/setup.cfg delete mode 100644 third_party/python/cookies/setup.py delete mode 100644 third_party/python/diskcache/MANIFEST.in delete mode 100644 third_party/python/diskcache/PKG-INFO rename third_party/python/diskcache/{ => diskcache-4.1.0.dist-info}/LICENSE (100%) rename third_party/python/diskcache/{README.rst => diskcache-4.1.0.dist-info/METADATA} (94%) create mode 100644 third_party/python/diskcache/diskcache-4.1.0.dist-info/RECORD create mode 100644 third_party/python/diskcache/diskcache-4.1.0.dist-info/WHEEL create mode 100644 third_party/python/diskcache/diskcache-4.1.0.dist-info/top_level.txt delete mode 100644 third_party/python/diskcache/setup.cfg delete mode 100644 third_party/python/diskcache/setup.py delete mode 100644 third_party/python/distro/CHANGELOG.md delete mode 100644 third_party/python/distro/CONTRIBUTING.md delete mode 100644 third_party/python/distro/CONTRIBUTORS.md delete mode 100644 third_party/python/distro/MANIFEST.in delete mode 100644 third_party/python/distro/Makefile delete mode 100644 third_party/python/distro/PKG-INFO delete mode 100644 third_party/python/distro/dev-requirements.txt rename third_party/python/distro/{ => distro-1.4.0.dist-info}/LICENSE (100%) rename third_party/python/distro/{README.md => distro-1.4.0.dist-info/METADATA} (82%) create mode 100644 third_party/python/distro/distro-1.4.0.dist-info/RECORD create mode 100644 third_party/python/distro/distro-1.4.0.dist-info/WHEEL create mode 100644 third_party/python/distro/distro-1.4.0.dist-info/entry_points.txt create mode 100644 third_party/python/distro/distro-1.4.0.dist-info/top_level.txt mode change 100755 => 100644 third_party/python/distro/distro.py delete mode 100755 third_party/python/distro/query_local_distro.py delete mode 100644 third_party/python/distro/setup.cfg delete mode 100644 third_party/python/distro/setup.py delete mode 100644 third_party/python/ecdsa/MANIFEST.in delete mode 100644 third_party/python/ecdsa/NEWS delete mode 100644 third_party/python/ecdsa/PKG-INFO rename third_party/python/ecdsa/{ => ecdsa-0.15.dist-info}/LICENSE (100%) rename third_party/python/ecdsa/{README.md => ecdsa-0.15.dist-info/METADATA} (95%) create mode 100644 third_party/python/ecdsa/ecdsa-0.15.dist-info/RECORD create mode 100644 third_party/python/ecdsa/ecdsa-0.15.dist-info/WHEEL create mode 100644 third_party/python/ecdsa/ecdsa-0.15.dist-info/top_level.txt rename third_party/python/ecdsa/{src => }/ecdsa/__init__.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/_compat.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/_rwlock.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/_version.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/curves.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/der.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/ecdh.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/ecdsa.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/ellipticcurve.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/keys.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/numbertheory.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/rfc6979.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_der.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_ecdh.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_ecdsa.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_ellipticcurve.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_jacobi.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_keys.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_malformed_sigs.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_numbertheory.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_pyecdsa.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/test_rw_lock.py (100%) rename third_party/python/ecdsa/{src => }/ecdsa/util.py (100%) delete mode 100644 third_party/python/ecdsa/setup.cfg delete mode 100755 third_party/python/ecdsa/setup.py delete mode 100644 third_party/python/ecdsa/versioneer.py delete mode 100644 third_party/python/fluent.syntax/PKG-INFO rename third_party/python/fluent.syntax/{README.rst => fluent.syntax-0.18.1.dist-info/DESCRIPTION.rst} (99%) create mode 100644 third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/METADATA create mode 100644 third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/RECORD create mode 100644 third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/WHEEL create mode 100644 third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/metadata.json create mode 100644 third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/top_level.txt delete mode 100644 third_party/python/fluent.syntax/setup.cfg delete mode 100755 third_party/python/fluent.syntax/setup.py delete mode 100644 third_party/python/glean_parser/.circleci/config.yml delete mode 100644 third_party/python/glean_parser/.editorconfig delete mode 100644 third_party/python/glean_parser/.flake8 delete mode 100644 third_party/python/glean_parser/.github/ISSUE_TEMPLATE.md delete mode 100644 third_party/python/glean_parser/.github/dependabot.yml delete mode 100644 third_party/python/glean_parser/.github/pull_request_template.md delete mode 100644 third_party/python/glean_parser/.gitignore delete mode 100644 third_party/python/glean_parser/.swiftlint.yml delete mode 100644 third_party/python/glean_parser/CODE_OF_CONDUCT.md delete mode 100644 third_party/python/glean_parser/CONTRIBUTING.md delete mode 100644 third_party/python/glean_parser/MANIFEST.in delete mode 100644 third_party/python/glean_parser/Makefile delete mode 100644 third_party/python/glean_parser/PKG-INFO delete mode 100644 third_party/python/glean_parser/README.md rename third_party/python/glean_parser/{ => glean_parser-3.6.0.dist-info}/AUTHORS.md (100%) rename third_party/python/glean_parser/{ => glean_parser-3.6.0.dist-info}/LICENSE (100%) rename third_party/python/glean_parser/{CHANGELOG.md => glean_parser-3.6.0.dist-info/METADATA} (84%) create mode 100644 third_party/python/glean_parser/glean_parser-3.6.0.dist-info/RECORD create mode 100644 third_party/python/glean_parser/glean_parser-3.6.0.dist-info/WHEEL create mode 100644 third_party/python/glean_parser/glean_parser-3.6.0.dist-info/entry_points.txt create mode 100644 third_party/python/glean_parser/glean_parser-3.6.0.dist-info/top_level.txt delete mode 100644 third_party/python/glean_parser/requirements_dev.txt delete mode 100644 third_party/python/glean_parser/setup.cfg delete mode 100755 third_party/python/glean_parser/setup.py delete mode 100755 third_party/python/glean_parser/tools/extract_data_categories.py delete mode 100644 third_party/python/idna/HISTORY.rst delete mode 100644 third_party/python/idna/MANIFEST.in delete mode 100644 third_party/python/idna/PKG-INFO rename third_party/python/idna/{ => idna-2.10.dist-info}/LICENSE.rst (100%) rename third_party/python/idna/{README.rst => idna-2.10.dist-info/METADATA} (85%) create mode 100644 third_party/python/idna/idna-2.10.dist-info/RECORD create mode 100644 third_party/python/idna/idna-2.10.dist-info/WHEEL create mode 100644 third_party/python/idna/idna-2.10.dist-info/top_level.txt delete mode 100644 third_party/python/idna/setup.cfg delete mode 100644 third_party/python/idna/setup.py delete mode 100755 third_party/python/idna/tools/idna-data delete mode 100644 third_party/python/idna/tools/intranges.py delete mode 100644 third_party/python/importlib_metadata/.coveragerc delete mode 100644 third_party/python/importlib_metadata/.editorconfig delete mode 100644 third_party/python/importlib_metadata/.flake8 delete mode 100644 third_party/python/importlib_metadata/.github/workflows/automerge.yml delete mode 100644 third_party/python/importlib_metadata/.github/workflows/main.yml delete mode 100644 third_party/python/importlib_metadata/.gitignore delete mode 100644 third_party/python/importlib_metadata/.pre-commit-config.yaml delete mode 100644 third_party/python/importlib_metadata/.readthedocs.yml delete mode 100644 third_party/python/importlib_metadata/CHANGES.rst delete mode 100644 third_party/python/importlib_metadata/PKG-INFO delete mode 100644 third_party/python/importlib_metadata/conftest.py rename third_party/python/importlib_metadata/{ => importlib_metadata-3.10.1.dist-info}/LICENSE (100%) rename third_party/python/importlib_metadata/{README.rst => importlib_metadata-3.10.1.dist-info/METADATA} (53%) create mode 100644 third_party/python/importlib_metadata/importlib_metadata-3.10.1.dist-info/RECORD create mode 100644 third_party/python/importlib_metadata/importlib_metadata-3.10.1.dist-info/WHEEL rename third_party/python/importlib_metadata/{importlib_metadata.egg-info => importlib_metadata-3.10.1.dist-info}/top_level.txt (100%) delete mode 100644 third_party/python/importlib_metadata/importlib_metadata.egg-info/PKG-INFO delete mode 100644 third_party/python/importlib_metadata/importlib_metadata.egg-info/SOURCES.txt delete mode 100644 third_party/python/importlib_metadata/importlib_metadata.egg-info/dependency_links.txt delete mode 100644 third_party/python/importlib_metadata/importlib_metadata.egg-info/requires.txt delete mode 100644 third_party/python/importlib_metadata/mypy.ini delete mode 100644 third_party/python/importlib_metadata/prepare/example/example/__init__.py delete mode 100644 third_party/python/importlib_metadata/prepare/example/setup.py delete mode 100644 third_party/python/importlib_metadata/pyproject.toml delete mode 100644 third_party/python/importlib_metadata/pytest.ini delete mode 100644 third_party/python/importlib_metadata/setup.cfg delete mode 100644 third_party/python/importlib_metadata/setup.py delete mode 100644 third_party/python/importlib_metadata/skeleton.md delete mode 100644 third_party/python/importlib_metadata/tox.ini delete mode 100644 third_party/python/iso8601/MANIFEST.in delete mode 100644 third_party/python/iso8601/PKG-INFO delete mode 100644 third_party/python/iso8601/dev-requirements.txt rename third_party/python/iso8601/{ => iso8601-0.1.14.dist-info}/LICENSE (100%) rename third_party/python/iso8601/{README.rst => iso8601-0.1.14.dist-info/METADATA} (93%) create mode 100644 third_party/python/iso8601/iso8601-0.1.14.dist-info/RECORD create mode 100644 third_party/python/iso8601/iso8601-0.1.14.dist-info/WHEEL create mode 100644 third_party/python/iso8601/iso8601-0.1.14.dist-info/top_level.txt delete mode 100644 third_party/python/iso8601/setup.cfg delete mode 100644 third_party/python/iso8601/setup.py delete mode 100644 third_party/python/iso8601/tox.ini delete mode 100644 third_party/python/jsonschema/.appveyor.yml delete mode 100644 third_party/python/jsonschema/.coveragerc delete mode 100644 third_party/python/jsonschema/.github/FUNDING.yml delete mode 100644 third_party/python/jsonschema/.github/SECURITY.md delete mode 100644 third_party/python/jsonschema/.gitignore delete mode 100644 third_party/python/jsonschema/.travis.yml delete mode 100644 third_party/python/jsonschema/CHANGELOG.rst delete mode 100644 third_party/python/jsonschema/DEMO.ipynb delete mode 100644 third_party/python/jsonschema/MANIFEST.in delete mode 100644 third_party/python/jsonschema/PKG-INFO delete mode 100644 third_party/python/jsonschema/codecov.yml delete mode 100644 third_party/python/jsonschema/demo.yml delete mode 100644 third_party/python/jsonschema/json/.gitignore delete mode 100644 third_party/python/jsonschema/json/.travis.yml delete mode 100644 third_party/python/jsonschema/json/LICENSE delete mode 100644 third_party/python/jsonschema/json/README.md delete mode 100755 third_party/python/jsonschema/json/bin/jsonschema_suite delete mode 100644 third_party/python/jsonschema/json/index.js delete mode 100644 third_party/python/jsonschema/json/package.json delete mode 100644 third_party/python/jsonschema/json/remotes/folder/folderInteger.json delete mode 100644 third_party/python/jsonschema/json/remotes/integer.json delete mode 100644 third_party/python/jsonschema/json/remotes/name-defs.json delete mode 100644 third_party/python/jsonschema/json/remotes/name.json delete mode 100644 third_party/python/jsonschema/json/remotes/subSchemas.json delete mode 100644 third_party/python/jsonschema/json/test-schema.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/allOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/anchor.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/anyOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/boolean_schema.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/const.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/contains.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/default.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/defs.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/exclusiveMaximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/exclusiveMinimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/if-then-else.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/items.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/maxProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/minProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/multipleOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/not.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/oneOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/content.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/date-time.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/date.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/email.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/idn-email.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/idn-hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/ipv4.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/ipv6.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/iri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/iri.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/relative-json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/time.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/uri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/uri-template.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/format/uri.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/propertyNames.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/required.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/type.json delete mode 100644 third_party/python/jsonschema/json/tests/draft2019-09/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/default.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/disallow.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/divisibleBy.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/extends.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/items.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/optional/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/required.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/type.json delete mode 100644 third_party/python/jsonschema/json/tests/draft3/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/allOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/anyOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/default.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/definitions.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/items.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/maxProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/minProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/multipleOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/not.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/oneOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/optional/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/required.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/type.json delete mode 100644 third_party/python/jsonschema/json/tests/draft4/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/allOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/anyOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/boolean_schema.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/const.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/contains.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/default.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/definitions.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/exclusiveMaximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/exclusiveMinimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/items.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/maxProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/minProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/multipleOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/not.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/oneOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/optional/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/propertyNames.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/required.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/type.json delete mode 100644 third_party/python/jsonschema/json/tests/draft6/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/allOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/anyOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/boolean_schema.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/const.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/contains.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/default.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/definitions.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/exclusiveMaximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/exclusiveMinimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/format.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/if-then-else.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/items.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/maxProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/minProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/multipleOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/not.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/oneOf.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/content.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/date-time.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/date.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/email.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/idn-email.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/idn-hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/ipv4.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/ipv6.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/iri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/iri.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/regex.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/relative-json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/time.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/uri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/uri-template.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/format/uri.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/propertyNames.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/required.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/type.json delete mode 100644 third_party/python/jsonschema/json/tests/draft7/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/additionalItems.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/additionalProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/allOf.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/anchor.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/anyOf.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/boolean_schema.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/const.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/contains.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/default.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/defs.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/dependencies.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/enum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/exclusiveMaximum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/exclusiveMinimum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/format.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/if-then-else.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/items.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/maxItems.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/maxLength.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/maxProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/maximum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/minItems.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/minLength.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/minProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/minimum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/multipleOf.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/not.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/oneOf.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/bignum.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/content.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/ecmascript-regex.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/date-time.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/date.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/email.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/idn-email.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/idn-hostname.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/ipv4.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/ipv6.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/iri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/iri.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/regex.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/relative-json-pointer.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/time.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/uri-reference.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/uri-template.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/format/uri.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/optional/zeroTerminatedFloats.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/pattern.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/patternProperties.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/properties.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/propertyNames.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/ref.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/refRemote.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/required.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/type.json delete mode 100644 third_party/python/jsonschema/json/tests/latest/uniqueItems.json delete mode 100644 third_party/python/jsonschema/json/tox.ini rename third_party/python/jsonschema/{ => jsonschema-3.2.0.dist-info}/COPYING (100%) rename third_party/python/jsonschema/{README.rst => jsonschema-3.2.0.dist-info/METADATA} (75%) create mode 100644 third_party/python/jsonschema/jsonschema-3.2.0.dist-info/RECORD create mode 100644 third_party/python/jsonschema/jsonschema-3.2.0.dist-info/WHEEL rename third_party/python/jsonschema/{jsonschema.egg-info => jsonschema-3.2.0.dist-info}/entry_points.txt (100%) rename third_party/python/jsonschema/{jsonschema.egg-info => jsonschema-3.2.0.dist-info}/top_level.txt (100%) delete mode 100644 third_party/python/jsonschema/jsonschema.egg-info/PKG-INFO delete mode 100644 third_party/python/jsonschema/jsonschema.egg-info/SOURCES.txt delete mode 100644 third_party/python/jsonschema/jsonschema.egg-info/dependency_links.txt delete mode 100644 third_party/python/jsonschema/jsonschema.egg-info/requires.txt delete mode 100644 third_party/python/jsonschema/jsonschema/benchmarks/issue232/issue.json delete mode 100644 third_party/python/jsonschema/jsonschema/tests/__init__.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/_helpers.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/_suite.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_cli.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_exceptions.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_format.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_jsonschema_test_suite.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_types.py delete mode 100644 third_party/python/jsonschema/jsonschema/tests/test_validators.py delete mode 100644 third_party/python/jsonschema/pyproject.toml delete mode 100644 third_party/python/jsonschema/setup.cfg delete mode 100644 third_party/python/jsonschema/setup.py delete mode 100644 third_party/python/jsonschema/test-requirements.txt delete mode 100644 third_party/python/jsonschema/tox.ini delete mode 100644 third_party/python/more-itertools/LICENSE delete mode 100644 third_party/python/more-itertools/MANIFEST.in delete mode 100644 third_party/python/more-itertools/PKG-INFO delete mode 100644 third_party/python/more-itertools/more_itertools/tests/__init__.py delete mode 100644 third_party/python/more-itertools/more_itertools/tests/test_more.py delete mode 100644 third_party/python/more-itertools/more_itertools/tests/test_recipes.py delete mode 100644 third_party/python/more-itertools/setup.cfg delete mode 100644 third_party/python/more-itertools/setup.py delete mode 100644 third_party/python/more-itertools/tox.ini rename third_party/python/{more-itertools/README.rst => more_itertools/more_itertools-4.3.0.dist-info/METADATA} (72%) create mode 100644 third_party/python/more_itertools/more_itertools-4.3.0.dist-info/RECORD create mode 100644 third_party/python/more_itertools/more_itertools-4.3.0.dist-info/WHEEL create mode 100644 third_party/python/more_itertools/more_itertools-4.3.0.dist-info/top_level.txt rename third_party/python/{more-itertools => more_itertools}/more_itertools/__init__.py (100%) rename third_party/python/{more-itertools => more_itertools}/more_itertools/more.py (100%) rename third_party/python/{more-itertools => more_itertools}/more_itertools/recipes.py (100%) delete mode 100644 third_party/python/mozilla-version/MANIFEST.in delete mode 100644 third_party/python/mozilla-version/README.md delete mode 100644 third_party/python/mozilla-version/mozilla_version/test/__init__.py delete mode 100644 third_party/python/mozilla-version/mozilla_version/test/test_balrog.py delete mode 100644 third_party/python/mozilla-version/mozilla_version/test/test_gecko.py delete mode 100644 third_party/python/mozilla-version/mozilla_version/test/test_maven.py delete mode 100644 third_party/python/mozilla-version/mozilla_version/test/test_version.py delete mode 100644 third_party/python/mozilla-version/requirements-coveralls.txt delete mode 100644 third_party/python/mozilla-version/requirements-docs.txt delete mode 100644 third_party/python/mozilla-version/requirements-test.txt delete mode 100644 third_party/python/mozilla-version/requirements.txt delete mode 100644 third_party/python/mozilla-version/requirements.txt.in delete mode 100644 third_party/python/mozilla-version/setup.cfg delete mode 100644 third_party/python/mozilla-version/setup.py delete mode 100644 third_party/python/mozilla-version/version.txt rename third_party/python/{mozilla-version => mozilla_version/mozilla_version-0.3.4.dist-info}/LICENSE (100%) rename third_party/python/{mozilla-version/PKG-INFO => mozilla_version/mozilla_version-0.3.4.dist-info/METADATA} (74%) create mode 100644 third_party/python/mozilla_version/mozilla_version-0.3.4.dist-info/RECORD create mode 100644 third_party/python/mozilla_version/mozilla_version-0.3.4.dist-info/WHEEL create mode 100644 third_party/python/mozilla_version/mozilla_version-0.3.4.dist-info/top_level.txt rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/__init__.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/balrog.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/errors.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/gecko.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/maven.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/parser.py (100%) rename third_party/python/{mozilla-version => mozilla_version}/mozilla_version/version.py (100%) create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/DESCRIPTION.rst create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/METADATA create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/RECORD create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/WHEEL create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/metadata.json create mode 100644 third_party/python/pathlib2/pathlib2-2.3.2.dist-info/top_level.txt delete mode 100644 third_party/python/pathspec/CHANGES.rst delete mode 100644 third_party/python/pathspec/MANIFEST.in delete mode 100644 third_party/python/pathspec/PKG-INFO delete mode 100644 third_party/python/pathspec/README.rst rename third_party/python/pathspec/{ => pathspec-0.8.0.dist-info}/LICENSE (100%) create mode 100644 third_party/python/pathspec/pathspec-0.8.0.dist-info/METADATA create mode 100644 third_party/python/pathspec/pathspec-0.8.0.dist-info/RECORD create mode 100644 third_party/python/pathspec/pathspec-0.8.0.dist-info/WHEEL create mode 100644 third_party/python/pathspec/pathspec-0.8.0.dist-info/top_level.txt delete mode 100644 third_party/python/pathspec/pathspec/tests/__init__.py delete mode 100644 third_party/python/pathspec/pathspec/tests/test_gitwildmatch.py delete mode 100644 third_party/python/pathspec/pathspec/tests/test_pathspec.py delete mode 100644 third_party/python/pathspec/pathspec/tests/test_util.py delete mode 100644 third_party/python/pathspec/setup.cfg delete mode 100644 third_party/python/pathspec/setup.py delete mode 100644 third_party/python/pip-tools/.bandit delete mode 100644 third_party/python/pip-tools/.coveragerc delete mode 100644 third_party/python/pip-tools/.fussyfox.yml delete mode 100644 third_party/python/pip-tools/.github/ISSUE_TEMPLATE/bug-report.md delete mode 100644 third_party/python/pip-tools/.github/ISSUE_TEMPLATE/feature-request.md delete mode 100644 third_party/python/pip-tools/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 third_party/python/pip-tools/.github/workflows/ci.yml delete mode 100644 third_party/python/pip-tools/.github/workflows/cron.yml delete mode 100644 third_party/python/pip-tools/.github/workflows/qa.yml delete mode 100644 third_party/python/pip-tools/.github/workflows/release.yml delete mode 100644 third_party/python/pip-tools/.gitignore delete mode 100644 third_party/python/pip-tools/.pre-commit-config.yaml delete mode 100644 third_party/python/pip-tools/.pre-commit-hooks.yaml delete mode 100644 third_party/python/pip-tools/CHANGELOG.md delete mode 100644 third_party/python/pip-tools/CONTRIBUTING.md delete mode 100644 third_party/python/pip-tools/PKG-INFO delete mode 100644 third_party/python/pip-tools/examples/django.in delete mode 100644 third_party/python/pip-tools/examples/flask.in delete mode 100644 third_party/python/pip-tools/examples/hypothesis.in delete mode 100644 third_party/python/pip-tools/examples/protection.in delete mode 100644 third_party/python/pip-tools/examples/sentry.in delete mode 100644 third_party/python/pip-tools/img/pip-tools-overview.png delete mode 100644 third_party/python/pip-tools/piptools/scripts/__init__.py delete mode 100644 third_party/python/pip-tools/setup.cfg delete mode 100644 third_party/python/pip-tools/setup.py delete mode 100644 third_party/python/pip-tools/tox.ini rename third_party/python/{pip-tools => pip_tools/pip_tools-5.5.0.dist-info}/LICENSE (100%) rename third_party/python/{pip-tools/README.rst => pip_tools/pip_tools-5.5.0.dist-info/METADATA} (92%) create mode 100644 third_party/python/pip_tools/pip_tools-5.5.0.dist-info/RECORD create mode 100644 third_party/python/pip_tools/pip_tools-5.5.0.dist-info/WHEEL create mode 100644 third_party/python/pip_tools/pip_tools-5.5.0.dist-info/entry_points.txt create mode 100644 third_party/python/pip_tools/pip_tools-5.5.0.dist-info/top_level.txt rename third_party/python/{pip-tools => pip_tools}/piptools/__init__.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/__main__.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/_compat/__init__.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/_compat/contextlib.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/_compat/pip_compat.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/_compat/tempfile.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/cache.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/click.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/exceptions.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/locations.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/logging.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/repositories/__init__.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/repositories/base.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/repositories/local.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/repositories/pypi.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/resolver.py (100%) rename third_party/python/{Click/examples/complex/complex/commands => pip_tools/piptools/scripts}/__init__.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/scripts/compile.py (100%) mode change 100755 => 100644 rename third_party/python/{pip-tools => pip_tools}/piptools/scripts/sync.py (100%) mode change 100755 => 100644 rename third_party/python/{pip-tools => pip_tools}/piptools/sync.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/utils.py (100%) rename third_party/python/{pip-tools => pip_tools}/piptools/writer.py (100%) delete mode 100644 third_party/python/pluggy/MANIFEST.in delete mode 100644 third_party/python/pluggy/PKG-INFO rename third_party/python/pluggy/{README.rst => pluggy-0.6.0.dist-info/DESCRIPTION.rst} (99%) rename third_party/python/pluggy/{LICENSE => pluggy-0.6.0.dist-info/LICENSE.txt} (100%) create mode 100644 third_party/python/pluggy/pluggy-0.6.0.dist-info/METADATA create mode 100644 third_party/python/pluggy/pluggy-0.6.0.dist-info/RECORD create mode 100644 third_party/python/pluggy/pluggy-0.6.0.dist-info/WHEEL create mode 100644 third_party/python/pluggy/pluggy-0.6.0.dist-info/metadata.json create mode 100644 third_party/python/pluggy/pluggy-0.6.0.dist-info/top_level.txt delete mode 100644 third_party/python/pluggy/setup.cfg delete mode 100644 third_party/python/pluggy/setup.py delete mode 100644 third_party/python/pluggy/testing/benchmark.py delete mode 100644 third_party/python/pluggy/testing/conftest.py delete mode 100644 third_party/python/pluggy/testing/test_details.py delete mode 100644 third_party/python/pluggy/testing/test_helpers.py delete mode 100644 third_party/python/pluggy/testing/test_hookrelay.py delete mode 100644 third_party/python/pluggy/testing/test_method_ordering.py delete mode 100644 third_party/python/pluggy/testing/test_multicall.py delete mode 100644 third_party/python/pluggy/testing/test_pluginmanager.py delete mode 100644 third_party/python/pluggy/testing/test_tracer.py delete mode 100644 third_party/python/pluggy/tox.ini delete mode 100644 third_party/python/py/.flake8 delete mode 100644 third_party/python/py/.gitattributes delete mode 100644 third_party/python/py/.github/workflows/main.yml delete mode 100644 third_party/python/py/.gitignore delete mode 100644 third_party/python/py/AUTHORS delete mode 100644 third_party/python/py/CHANGELOG.rst delete mode 100644 third_party/python/py/MANIFEST.in delete mode 100644 third_party/python/py/PKG-INFO delete mode 100644 third_party/python/py/README.rst delete mode 100644 third_party/python/py/RELEASING.rst delete mode 100644 third_party/python/py/bench/localpath.py delete mode 100644 third_party/python/py/codecov.yml delete mode 100644 third_party/python/py/conftest.py rename third_party/python/py/{ => py-1.10.0.dist-info}/LICENSE (100%) create mode 100644 third_party/python/py/py-1.10.0.dist-info/METADATA create mode 100644 third_party/python/py/py-1.10.0.dist-info/RECORD create mode 100644 third_party/python/py/py-1.10.0.dist-info/WHEEL create mode 100644 third_party/python/py/py-1.10.0.dist-info/top_level.txt delete mode 100644 third_party/python/py/setup.cfg delete mode 100644 third_party/python/py/setup.py delete mode 100644 third_party/python/py/tasks/__init__.py delete mode 100644 third_party/python/py/tasks/vendoring.py delete mode 100644 third_party/python/py/testing/code/test_assertion.py delete mode 100644 third_party/python/py/testing/code/test_code.py delete mode 100644 third_party/python/py/testing/code/test_excinfo.py delete mode 100644 third_party/python/py/testing/code/test_source.py delete mode 100644 third_party/python/py/testing/conftest.py delete mode 100644 third_party/python/py/testing/io_/__init__.py delete mode 100644 third_party/python/py/testing/io_/test_capture.py delete mode 100644 third_party/python/py/testing/io_/test_saferepr.py delete mode 100644 third_party/python/py/testing/io_/test_terminalwriter.py delete mode 100644 third_party/python/py/testing/io_/test_terminalwriter_linewidth.py delete mode 100644 third_party/python/py/testing/log/__init__.py delete mode 100644 third_party/python/py/testing/log/test_log.py delete mode 100644 third_party/python/py/testing/log/test_warning.py delete mode 100644 third_party/python/py/testing/path/common.py delete mode 100644 third_party/python/py/testing/path/conftest.py delete mode 100644 third_party/python/py/testing/path/repotest.dump delete mode 100644 third_party/python/py/testing/path/svntestbase.py delete mode 100644 third_party/python/py/testing/path/test_cacheutil.py delete mode 100644 third_party/python/py/testing/path/test_local.py delete mode 100644 third_party/python/py/testing/path/test_svnauth.py delete mode 100644 third_party/python/py/testing/path/test_svnurl.py delete mode 100644 third_party/python/py/testing/path/test_svnwc.py delete mode 100644 third_party/python/py/testing/process/__init__.py delete mode 100644 third_party/python/py/testing/process/test_cmdexec.py delete mode 100644 third_party/python/py/testing/process/test_forkedfunc.py delete mode 100644 third_party/python/py/testing/process/test_killproc.py delete mode 100644 third_party/python/py/testing/root/__init__.py delete mode 100644 third_party/python/py/testing/root/test_builtin.py delete mode 100644 third_party/python/py/testing/root/test_error.py delete mode 100644 third_party/python/py/testing/root/test_py_imports.py delete mode 100644 third_party/python/py/testing/root/test_std.py delete mode 100644 third_party/python/py/testing/root/test_xmlgen.py delete mode 100644 third_party/python/py/tox.ini delete mode 100644 third_party/python/pyasn1/CHANGES.rst delete mode 100644 third_party/python/pyasn1/MANIFEST.in delete mode 100644 third_party/python/pyasn1/PKG-INFO delete mode 100644 third_party/python/pyasn1/README.md delete mode 100644 third_party/python/pyasn1/TODO.rst rename third_party/python/pyasn1/{ => pyasn1-0.4.8.dist-info}/LICENSE.rst (100%) rename third_party/python/pyasn1/{pyasn1.egg-info/PKG-INFO => pyasn1-0.4.8.dist-info/METADATA} (92%) create mode 100644 third_party/python/pyasn1/pyasn1-0.4.8.dist-info/RECORD create mode 100644 third_party/python/pyasn1/pyasn1-0.4.8.dist-info/WHEEL rename third_party/python/pyasn1/{pyasn1.egg-info => pyasn1-0.4.8.dist-info}/top_level.txt (100%) rename third_party/python/pyasn1/{pyasn1.egg-info => pyasn1-0.4.8.dist-info}/zip-safe (100%) delete mode 100644 third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt delete mode 100644 third_party/python/pyasn1/pyasn1.egg-info/dependency_links.txt delete mode 100644 third_party/python/pyasn1/setup.cfg delete mode 100644 third_party/python/pyasn1/setup.py delete mode 100644 third_party/python/pytest/.coveragerc delete mode 100644 third_party/python/pytest/.gitattributes delete mode 100644 third_party/python/pytest/.github/ISSUE_TEMPLATE.md delete mode 100644 third_party/python/pytest/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 third_party/python/pytest/.gitignore delete mode 100644 third_party/python/pytest/.pre-commit-config.yaml delete mode 100644 third_party/python/pytest/.travis.yml delete mode 100644 third_party/python/pytest/AUTHORS delete mode 100644 third_party/python/pytest/CHANGELOG.rst delete mode 100644 third_party/python/pytest/CONTRIBUTING.rst delete mode 100644 third_party/python/pytest/HOWTORELEASE.rst delete mode 100644 third_party/python/pytest/PKG-INFO rename third_party/python/pytest/{src => }/_pytest/__init__.py (100%) rename third_party/python/pytest/{src => }/_pytest/_argcomplete.py (100%) rename third_party/python/pytest/{src => }/_pytest/_code/__init__.py (100%) rename third_party/python/pytest/{src => }/_pytest/_code/_py2traceback.py (100%) rename third_party/python/pytest/{src => }/_pytest/_code/code.py (100%) rename third_party/python/pytest/{src => }/_pytest/_code/source.py (100%) rename third_party/python/pytest/{src => }/_pytest/_version.py (100%) rename third_party/python/pytest/{src => }/_pytest/assertion/__init__.py (100%) rename third_party/python/pytest/{src => }/_pytest/assertion/rewrite.py (100%) rename third_party/python/pytest/{src => }/_pytest/assertion/truncate.py (100%) rename third_party/python/pytest/{src => }/_pytest/assertion/util.py (100%) rename third_party/python/pytest/{src => }/_pytest/cacheprovider.py (100%) mode change 100755 => 100644 rename third_party/python/pytest/{src => }/_pytest/capture.py (100%) rename third_party/python/pytest/{src => }/_pytest/compat.py (100%) rename third_party/python/pytest/{src => }/_pytest/config/__init__.py (100%) rename third_party/python/pytest/{src => }/_pytest/config/argparsing.py (100%) rename third_party/python/pytest/{src => }/_pytest/config/exceptions.py (100%) rename third_party/python/pytest/{src => }/_pytest/config/findpaths.py (100%) rename third_party/python/pytest/{src => }/_pytest/debugging.py (100%) rename third_party/python/pytest/{src => }/_pytest/deprecated.py (100%) rename third_party/python/pytest/{src => }/_pytest/doctest.py (100%) rename third_party/python/pytest/{src => }/_pytest/fixtures.py (100%) rename third_party/python/pytest/{src => }/_pytest/freeze_support.py (100%) rename third_party/python/pytest/{src => }/_pytest/helpconfig.py (100%) rename third_party/python/pytest/{src => }/_pytest/hookspec.py (100%) rename third_party/python/pytest/{src => }/_pytest/junitxml.py (100%) rename third_party/python/pytest/{src => }/_pytest/logging.py (100%) rename third_party/python/pytest/{src => }/_pytest/main.py (100%) rename third_party/python/pytest/{src => }/_pytest/mark/__init__.py (100%) rename third_party/python/pytest/{src => }/_pytest/mark/evaluate.py (100%) rename third_party/python/pytest/{src => }/_pytest/mark/legacy.py (100%) rename third_party/python/pytest/{src => }/_pytest/mark/structures.py (100%) rename third_party/python/pytest/{src => }/_pytest/monkeypatch.py (100%) rename third_party/python/pytest/{src => }/_pytest/nodes.py (100%) rename third_party/python/pytest/{src => }/_pytest/nose.py (100%) rename third_party/python/pytest/{src => }/_pytest/outcomes.py (100%) rename third_party/python/pytest/{src => }/_pytest/pastebin.py (100%) rename third_party/python/pytest/{src => }/_pytest/pytester.py (100%) rename third_party/python/pytest/{src => }/_pytest/python.py (100%) rename third_party/python/pytest/{src => }/_pytest/python_api.py (100%) rename third_party/python/pytest/{src => }/_pytest/recwarn.py (100%) rename third_party/python/pytest/{src => }/_pytest/resultlog.py (100%) rename third_party/python/pytest/{src => }/_pytest/runner.py (100%) rename third_party/python/pytest/{src => }/_pytest/setuponly.py (100%) rename third_party/python/pytest/{src => }/_pytest/setupplan.py (100%) rename third_party/python/pytest/{src => }/_pytest/skipping.py (100%) rename third_party/python/pytest/{src => }/_pytest/terminal.py (100%) rename third_party/python/pytest/{src => }/_pytest/tmpdir.py (100%) rename third_party/python/pytest/{src => }/_pytest/unittest.py (100%) rename third_party/python/pytest/{src => }/_pytest/warnings.py (100%) delete mode 100644 third_party/python/pytest/appveyor.yml delete mode 100644 third_party/python/pytest/bench/bench.py delete mode 100644 third_party/python/pytest/bench/bench_argcomplete.py delete mode 100644 third_party/python/pytest/bench/empty.py delete mode 100644 third_party/python/pytest/bench/manyparam.py delete mode 100644 third_party/python/pytest/bench/skip.py delete mode 100644 third_party/python/pytest/changelog/README.rst delete mode 100644 third_party/python/pytest/changelog/_template.rst delete mode 100644 third_party/python/pytest/extra/get_issues.py delete mode 100644 third_party/python/pytest/extra/setup-py.test/setup.py delete mode 100644 third_party/python/pytest/pyproject.toml rename third_party/python/pytest/{LICENSE => pytest-3.6.2.dist-info/LICENSE.txt} (100%) rename third_party/python/pytest/{README.rst => pytest-3.6.2.dist-info/METADATA} (68%) create mode 100644 third_party/python/pytest/pytest-3.6.2.dist-info/RECORD create mode 100644 third_party/python/pytest/pytest-3.6.2.dist-info/WHEEL create mode 100644 third_party/python/pytest/pytest-3.6.2.dist-info/entry_points.txt create mode 100644 third_party/python/pytest/pytest-3.6.2.dist-info/top_level.txt rename third_party/python/pytest/{src => }/pytest.py (100%) delete mode 100644 third_party/python/pytest/scripts/call-tox.bat delete mode 100644 third_party/python/pytest/scripts/install-pypy.bat delete mode 100644 third_party/python/pytest/setup.cfg delete mode 100644 third_party/python/pytest/setup.py delete mode 100644 third_party/python/pytest/tasks/__init__.py delete mode 100644 third_party/python/pytest/tasks/generate.py delete mode 100644 third_party/python/pytest/tasks/release.minor.rst delete mode 100644 third_party/python/pytest/tasks/release.patch.rst delete mode 100644 third_party/python/pytest/tasks/requirements.txt delete mode 100644 third_party/python/pytest/testing/acceptance_test.py delete mode 100644 third_party/python/pytest/testing/code/test_code.py delete mode 100644 third_party/python/pytest/testing/code/test_excinfo.py delete mode 100644 third_party/python/pytest/testing/code/test_source.py delete mode 100644 third_party/python/pytest/testing/code/test_source_multiline_block.py delete mode 100644 third_party/python/pytest/testing/deprecated_test.py delete mode 100644 third_party/python/pytest/testing/freeze/.gitignore delete mode 100644 third_party/python/pytest/testing/freeze/create_executable.py delete mode 100644 third_party/python/pytest/testing/freeze/runtests_script.py delete mode 100644 third_party/python/pytest/testing/freeze/tests/test_doctest.txt delete mode 100644 third_party/python/pytest/testing/freeze/tests/test_trivial.py delete mode 100644 third_party/python/pytest/testing/freeze/tox_run.py delete mode 100644 third_party/python/pytest/testing/logging/test_fixture.py delete mode 100644 third_party/python/pytest/testing/logging/test_formatter.py delete mode 100644 third_party/python/pytest/testing/logging/test_reporting.py delete mode 100644 third_party/python/pytest/testing/python/approx.py delete mode 100644 third_party/python/pytest/testing/python/collect.py delete mode 100644 third_party/python/pytest/testing/python/fixture.py delete mode 100644 third_party/python/pytest/testing/python/integration.py delete mode 100644 third_party/python/pytest/testing/python/metafunc.py delete mode 100644 third_party/python/pytest/testing/python/raises.py delete mode 100644 third_party/python/pytest/testing/python/setup_only.py delete mode 100644 third_party/python/pytest/testing/python/setup_plan.py delete mode 100644 third_party/python/pytest/testing/python/show_fixtures_per_test.py delete mode 100644 third_party/python/pytest/testing/python/test_deprecations.py delete mode 100644 third_party/python/pytest/testing/test_argcomplete.py delete mode 100644 third_party/python/pytest/testing/test_assertion.py delete mode 100644 third_party/python/pytest/testing/test_assertrewrite.py delete mode 100644 third_party/python/pytest/testing/test_cacheprovider.py delete mode 100644 third_party/python/pytest/testing/test_capture.py delete mode 100644 third_party/python/pytest/testing/test_collection.py delete mode 100644 third_party/python/pytest/testing/test_compat.py delete mode 100644 third_party/python/pytest/testing/test_config.py delete mode 100644 third_party/python/pytest/testing/test_conftest.py delete mode 100644 third_party/python/pytest/testing/test_doctest.py delete mode 100644 third_party/python/pytest/testing/test_entry_points.py delete mode 100644 third_party/python/pytest/testing/test_helpconfig.py delete mode 100644 third_party/python/pytest/testing/test_junitxml.py delete mode 100644 third_party/python/pytest/testing/test_mark.py delete mode 100644 third_party/python/pytest/testing/test_modimport.py delete mode 100644 third_party/python/pytest/testing/test_monkeypatch.py delete mode 100644 third_party/python/pytest/testing/test_nodes.py delete mode 100644 third_party/python/pytest/testing/test_nose.py delete mode 100644 third_party/python/pytest/testing/test_parseopt.py delete mode 100644 third_party/python/pytest/testing/test_pastebin.py delete mode 100644 third_party/python/pytest/testing/test_pdb.py delete mode 100644 third_party/python/pytest/testing/test_pluginmanager.py delete mode 100644 third_party/python/pytest/testing/test_pytester.py delete mode 100644 third_party/python/pytest/testing/test_recwarn.py delete mode 100644 third_party/python/pytest/testing/test_resultlog.py delete mode 100644 third_party/python/pytest/testing/test_runner.py delete mode 100644 third_party/python/pytest/testing/test_runner_xunit.py delete mode 100644 third_party/python/pytest/testing/test_session.py delete mode 100644 third_party/python/pytest/testing/test_skipping.py delete mode 100644 third_party/python/pytest/testing/test_terminal.py delete mode 100644 third_party/python/pytest/testing/test_tmpdir.py delete mode 100644 third_party/python/pytest/testing/test_unittest.py delete mode 100644 third_party/python/pytest/testing/test_warnings.py delete mode 100644 third_party/python/pytest/tox.ini delete mode 100644 third_party/python/redo/README.md create mode 100644 third_party/python/redo/redo-2.0.3.dist-info/AUTHORS rename third_party/python/redo/{PKG-INFO => redo-2.0.3.dist-info/METADATA} (82%) create mode 100644 third_party/python/redo/redo-2.0.3.dist-info/RECORD create mode 100644 third_party/python/redo/redo-2.0.3.dist-info/WHEEL rename third_party/python/redo/{redo.egg-info => redo-2.0.3.dist-info}/entry_points.txt (100%) rename third_party/python/redo/{redo.egg-info => redo-2.0.3.dist-info}/top_level.txt (100%) delete mode 100644 third_party/python/redo/redo.egg-info/PKG-INFO delete mode 100644 third_party/python/redo/redo.egg-info/SOURCES.txt delete mode 100644 third_party/python/redo/redo.egg-info/dependency_links.txt delete mode 100644 third_party/python/redo/setup.cfg delete mode 100644 third_party/python/redo/setup.py delete mode 100644 third_party/python/requests/HISTORY.md delete mode 100644 third_party/python/requests/MANIFEST.in delete mode 100644 third_party/python/requests/NOTICE delete mode 100644 third_party/python/requests/PKG-INFO delete mode 100644 third_party/python/requests/pytest.ini rename third_party/python/requests/{ => requests-2.25.1.dist-info}/LICENSE (100%) rename third_party/python/requests/{README.md => requests-2.25.1.dist-info/METADATA} (59%) create mode 100644 third_party/python/requests/requests-2.25.1.dist-info/RECORD create mode 100644 third_party/python/requests/requests-2.25.1.dist-info/WHEEL rename third_party/python/requests/{requests.egg-info => requests-2.25.1.dist-info}/top_level.txt (100%) delete mode 100644 third_party/python/requests/requests.egg-info/PKG-INFO delete mode 100644 third_party/python/requests/requests.egg-info/SOURCES.txt delete mode 100644 third_party/python/requests/requests.egg-info/dependency_links.txt delete mode 100644 third_party/python/requests/requests.egg-info/not-zip-safe delete mode 100644 third_party/python/requests/requests.egg-info/requires.txt delete mode 100644 third_party/python/requests/requirements-dev.txt delete mode 100644 third_party/python/requests/setup.cfg delete mode 100755 third_party/python/requests/setup.py delete mode 100644 third_party/python/responses/CHANGES delete mode 100644 third_party/python/responses/MANIFEST.in delete mode 100644 third_party/python/responses/PKG-INFO rename third_party/python/responses/{ => responses-0.10.6.dist-info}/LICENSE (100%) rename third_party/python/responses/{README.rst => responses-0.10.6.dist-info/METADATA} (90%) create mode 100644 third_party/python/responses/responses-0.10.6.dist-info/RECORD create mode 100644 third_party/python/responses/responses-0.10.6.dist-info/WHEEL create mode 100644 third_party/python/responses/responses-0.10.6.dist-info/top_level.txt delete mode 100644 third_party/python/responses/setup.cfg delete mode 100644 third_party/python/responses/setup.py delete mode 100644 third_party/python/responses/test_responses.py delete mode 100644 third_party/python/responses/tox.ini delete mode 100644 third_party/python/sentry-sdk/MANIFEST.in delete mode 100644 third_party/python/sentry-sdk/README.md delete mode 100644 third_party/python/sentry-sdk/sentry_sdk.egg-info/PKG-INFO delete mode 100644 third_party/python/sentry-sdk/sentry_sdk.egg-info/SOURCES.txt delete mode 100644 third_party/python/sentry-sdk/sentry_sdk.egg-info/dependency_links.txt delete mode 100644 third_party/python/sentry-sdk/sentry_sdk.egg-info/not-zip-safe delete mode 100644 third_party/python/sentry-sdk/sentry_sdk.egg-info/requires.txt delete mode 100644 third_party/python/sentry-sdk/setup.cfg delete mode 100644 third_party/python/sentry-sdk/setup.py rename third_party/python/{sentry-sdk => sentry_sdk/sentry_sdk-0.14.3.dist-info}/LICENSE (100%) rename third_party/python/{sentry-sdk/PKG-INFO => sentry_sdk/sentry_sdk-0.14.3.dist-info/METADATA} (58%) create mode 100644 third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/RECORD create mode 100644 third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/WHEEL rename third_party/python/{sentry-sdk/sentry_sdk.egg-info => sentry_sdk/sentry_sdk-0.14.3.dist-info}/top_level.txt (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/__init__.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/_compat.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/_types.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/api.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/client.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/consts.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/debug.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/envelope.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/hub.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/__init__.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/_wsgi_common.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/aiohttp.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/argv.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/asgi.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/atexit.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/aws_lambda.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/beam.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/bottle.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/celery.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/dedupe.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/django/__init__.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/django/asgi.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/django/middleware.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/django/templates.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/django/transactions.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/excepthook.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/falcon.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/flask.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/gnu_backtrace.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/logging.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/modules.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/pyramid.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/redis.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/rq.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/sanic.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/serverless.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/spark/__init__.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/spark/spark_driver.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/spark/spark_worker.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/sqlalchemy.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/stdlib.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/threading.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/tornado.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/trytond.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/integrations/wsgi.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/py.typed (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/scope.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/serializer.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/sessions.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/tracing.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/transport.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/utils.py (100%) rename third_party/python/{sentry-sdk => sentry_sdk}/sentry_sdk/worker.py (100%) delete mode 100644 third_party/python/six/CHANGES delete mode 100644 third_party/python/six/MANIFEST.in delete mode 100644 third_party/python/six/PKG-INFO delete mode 100644 third_party/python/six/documentation/Makefile delete mode 100644 third_party/python/six/documentation/conf.py delete mode 100644 third_party/python/six/documentation/index.rst delete mode 100644 third_party/python/six/setup.cfg delete mode 100644 third_party/python/six/setup.py rename third_party/python/six/{ => six-1.13.0.dist-info}/LICENSE (100%) rename third_party/python/six/{README.rst => six-1.13.0.dist-info/METADATA} (68%) create mode 100644 third_party/python/six/six-1.13.0.dist-info/RECORD create mode 100644 third_party/python/six/six-1.13.0.dist-info/WHEEL create mode 100644 third_party/python/six/six-1.13.0.dist-info/top_level.txt delete mode 100644 third_party/python/six/test_six.py delete mode 100644 third_party/python/typing_extensions/MANIFEST.in delete mode 100644 third_party/python/typing_extensions/README.rst delete mode 100644 third_party/python/typing_extensions/setup.cfg delete mode 100644 third_party/python/typing_extensions/setup.py delete mode 100644 third_party/python/typing_extensions/src_py2/test_typing_extensions.py delete mode 100644 third_party/python/typing_extensions/src_py2/typing_extensions.py delete mode 100644 third_party/python/typing_extensions/src_py3/test_typing_extensions.py rename third_party/python/typing_extensions/{ => typing_extensions-3.7.4.3.dist-info}/LICENSE (100%) rename third_party/python/typing_extensions/{PKG-INFO => typing_extensions-3.7.4.3.dist-info/METADATA} (50%) create mode 100644 third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/RECORD create mode 100644 third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/WHEEL create mode 100644 third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/top_level.txt rename third_party/python/typing_extensions/{src_py3 => }/typing_extensions.py (100%) delete mode 100644 third_party/python/urllib3/CONTRIBUTORS.txt delete mode 100644 third_party/python/urllib3/MANIFEST.in delete mode 100644 third_party/python/urllib3/PKG-INFO delete mode 100644 third_party/python/urllib3/README.rst delete mode 100644 third_party/python/urllib3/dev-requirements.txt delete mode 100644 third_party/python/urllib3/dummyserver/__init__.py delete mode 100644 third_party/python/urllib3/dummyserver/certs/README.rst delete mode 100644 third_party/python/urllib3/dummyserver/certs/cacert.key delete mode 100644 third_party/python/urllib3/dummyserver/certs/cacert.pem delete mode 100644 third_party/python/urllib3/dummyserver/certs/server.crt delete mode 100644 third_party/python/urllib3/dummyserver/certs/server.key delete mode 100644 third_party/python/urllib3/dummyserver/handlers.py delete mode 100755 third_party/python/urllib3/dummyserver/proxy.py delete mode 100755 third_party/python/urllib3/dummyserver/server.py delete mode 100644 third_party/python/urllib3/dummyserver/testcase.py delete mode 100644 third_party/python/urllib3/setup.cfg delete mode 100755 third_party/python/urllib3/setup.py delete mode 100644 third_party/python/urllib3/src/urllib3.egg-info/PKG-INFO delete mode 100644 third_party/python/urllib3/src/urllib3.egg-info/SOURCES.txt delete mode 100644 third_party/python/urllib3/src/urllib3.egg-info/dependency_links.txt delete mode 100644 third_party/python/urllib3/src/urllib3.egg-info/requires.txt delete mode 100644 third_party/python/urllib3/src/urllib3/contrib/__init__.py delete mode 100644 third_party/python/urllib3/src/urllib3/contrib/_securetransport/__init__.py delete mode 100644 third_party/python/urllib3/src/urllib3/packages/backports/__init__.py rename third_party/python/urllib3/{ => urllib3-1.25.9.dist-info}/LICENSE.txt (100%) rename third_party/python/urllib3/{CHANGES.rst => urllib3-1.25.9.dist-info/METADATA} (86%) create mode 100644 third_party/python/urllib3/urllib3-1.25.9.dist-info/RECORD create mode 100644 third_party/python/urllib3/urllib3-1.25.9.dist-info/WHEEL rename third_party/python/urllib3/{src/urllib3.egg-info => urllib3-1.25.9.dist-info}/top_level.txt (100%) rename third_party/python/urllib3/{src => }/urllib3/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/_collections.py (100%) rename third_party/python/urllib3/{src => }/urllib3/connection.py (100%) rename third_party/python/urllib3/{src => }/urllib3/connectionpool.py (100%) rename third_party/python/{compare-locales/compare_locales/lint => urllib3/urllib3/contrib}/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/_appengine_environ.py (100%) rename third_party/python/{compare-locales/compare_locales/tests/android => urllib3/urllib3/contrib/_securetransport}/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/_securetransport/bindings.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/_securetransport/low_level.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/appengine.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/ntlmpool.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/pyopenssl.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/securetransport.py (100%) rename third_party/python/urllib3/{src => }/urllib3/contrib/socks.py (100%) rename third_party/python/urllib3/{src => }/urllib3/exceptions.py (100%) rename third_party/python/urllib3/{src => }/urllib3/fields.py (100%) rename third_party/python/urllib3/{src => }/urllib3/filepost.py (100%) rename third_party/python/urllib3/{src => }/urllib3/packages/__init__.py (100%) rename third_party/python/{compare-locales/compare_locales/tests/dtd => urllib3/urllib3/packages/backports}/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/packages/backports/makefile.py (100%) rename third_party/python/urllib3/{src => }/urllib3/packages/six.py (100%) rename third_party/python/urllib3/{src => }/urllib3/packages/ssl_match_hostname/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/packages/ssl_match_hostname/_implementation.py (100%) rename third_party/python/urllib3/{src => }/urllib3/poolmanager.py (100%) rename third_party/python/urllib3/{src => }/urllib3/request.py (100%) rename third_party/python/urllib3/{src => }/urllib3/response.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/__init__.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/connection.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/queue.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/request.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/response.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/retry.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/ssl_.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/timeout.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/url.py (100%) rename third_party/python/urllib3/{src => }/urllib3/util/wait.py (100%) delete mode 100644 third_party/python/voluptuous/CHANGELOG.md delete mode 100644 third_party/python/voluptuous/COPYING delete mode 100644 third_party/python/voluptuous/MANIFEST.in delete mode 100644 third_party/python/voluptuous/PKG-INFO delete mode 100644 third_party/python/voluptuous/setup.cfg delete mode 100644 third_party/python/voluptuous/setup.py rename third_party/python/voluptuous/{README.md => voluptuous-0.11.5.dist-info/METADATA} (95%) create mode 100644 third_party/python/voluptuous/voluptuous-0.11.5.dist-info/RECORD create mode 100644 third_party/python/voluptuous/voluptuous-0.11.5.dist-info/WHEEL create mode 100644 third_party/python/voluptuous/voluptuous-0.11.5.dist-info/top_level.txt delete mode 100644 third_party/python/voluptuous/voluptuous/tests/__init__.py delete mode 100644 third_party/python/voluptuous/voluptuous/tests/tests.md delete mode 100644 third_party/python/voluptuous/voluptuous/tests/tests.py delete mode 100644 third_party/python/yamllint/MANIFEST.in delete mode 100644 third_party/python/yamllint/README.rst delete mode 100644 third_party/python/yamllint/setup.cfg delete mode 100644 third_party/python/yamllint/setup.py rename third_party/python/yamllint/{ => yamllint-1.23.0.dist-info}/LICENSE (100%) rename third_party/python/yamllint/{PKG-INFO => yamllint-1.23.0.dist-info/METADATA} (79%) create mode 100644 third_party/python/yamllint/yamllint-1.23.0.dist-info/RECORD create mode 100644 third_party/python/yamllint/yamllint-1.23.0.dist-info/WHEEL create mode 100644 third_party/python/yamllint/yamllint-1.23.0.dist-info/entry_points.txt create mode 100644 third_party/python/yamllint/yamllint-1.23.0.dist-info/top_level.txt delete mode 100644 third_party/python/zipp/.coveragerc delete mode 100644 third_party/python/zipp/.editorconfig delete mode 100644 third_party/python/zipp/.flake8 delete mode 100644 third_party/python/zipp/.github/workflows/automerge.yml delete mode 100644 third_party/python/zipp/.github/workflows/main.yml delete mode 100644 third_party/python/zipp/.pre-commit-config.yaml delete mode 100644 third_party/python/zipp/.readthedocs.yml delete mode 100644 third_party/python/zipp/CHANGES.rst delete mode 100644 third_party/python/zipp/PKG-INFO delete mode 100644 third_party/python/zipp/README.rst delete mode 100644 third_party/python/zipp/conftest.py delete mode 100644 third_party/python/zipp/mypy.ini delete mode 100644 third_party/python/zipp/pyproject.toml delete mode 100644 third_party/python/zipp/pytest.ini delete mode 100644 third_party/python/zipp/setup.cfg delete mode 100644 third_party/python/zipp/setup.py delete mode 100644 third_party/python/zipp/skeleton.md delete mode 100644 third_party/python/zipp/test_zipp.py delete mode 100644 third_party/python/zipp/tox.ini rename third_party/python/zipp/{ => zipp-3.4.1.dist-info}/LICENSE (100%) create mode 100644 third_party/python/zipp/zipp-3.4.1.dist-info/METADATA create mode 100644 third_party/python/zipp/zipp-3.4.1.dist-info/RECORD create mode 100644 third_party/python/zipp/zipp-3.4.1.dist-info/WHEEL create mode 100644 third_party/python/zipp/zipp-3.4.1.dist-info/top_level.txt diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt index 278513b879bf..cad49ce3762d 100644 --- a/build/common_virtualenv_packages.txt +++ b/build/common_virtualenv_packages.txt @@ -39,18 +39,18 @@ mozilla.pth:testing/web-platform/tests/tools/wptrunner mozilla.pth:testing/xpcshell mozilla.pth:third_party/python/appdirs mozilla.pth:third_party/python/atomicwrites -mozilla.pth:third_party/python/attrs/src +mozilla.pth:third_party/python/attrs mozilla.pth:third_party/python/blessings mozilla.pth:third_party/python/cbor2 mozilla.pth:third_party/python/chardet mozilla.pth:third_party/python/Click -mozilla.pth:third_party/python/compare-locales +mozilla.pth:third_party/python/compare_locales mozilla.pth:third_party/python/cookies mozilla.pth:third_party/python/cram mozilla.pth:third_party/python/diskcache mozilla.pth:third_party/python/distro mozilla.pth:third_party/python/dlmanager -mozilla.pth:third_party/python/ecdsa/src +mozilla.pth:third_party/python/ecdsa mozilla.pth:third_party/python/esprima mozilla.pth:third_party/python/fluent.migrate mozilla.pth:third_party/python/fluent.syntax @@ -59,14 +59,14 @@ mozilla.pth:third_party/python/gyp/pylib mozilla.pth:third_party/python/idna mozilla.pth:third_party/python/importlib_metadata mozilla.pth:third_party/python/iso8601 -mozilla.pth:third_party/python/Jinja2/src +mozilla.pth:third_party/python/Jinja2 mozilla.pth:third_party/python/jsmin mozilla.pth:third_party/python/json-e mozilla.pth:third_party/python/jsonschema mozilla.pth:third_party/python/MarkupSafe/src mozilla.pth:third_party/python/mohawk -mozilla.pth:third_party/python/more-itertools -mozilla.pth:third_party/python/mozilla-version +mozilla.pth:third_party/python/more_itertools +mozilla.pth:third_party/python/mozilla_version mozilla.pth:third_party/python/pathspec mozilla.pth:third_party/python/pep487/lib mozilla.pth:third_party/python/pluggy @@ -77,7 +77,7 @@ mozilla.pth:third_party/python/pyasn1-modules mozilla.pth:third_party/python/pylru mozilla.pth:third_party/python/pyrsistent mozilla.pth:third_party/python/pystache -mozilla.pth:third_party/python/pytest/src +mozilla.pth:third_party/python/pytest mozilla.pth:third_party/python/python-hglib mozilla.pth:third_party/python/pytoml mozilla.pth:third_party/python/PyYAML/lib3/ @@ -86,13 +86,13 @@ mozilla.pth:third_party/python/requests mozilla.pth:third_party/python/requests-unixsocket mozilla.pth:third_party/python/responses mozilla.pth:third_party/python/rsa -mozilla.pth:third_party/python/sentry-sdk +mozilla.pth:third_party/python/sentry_sdk mozilla.pth:third_party/python/six mozilla.pth:third_party/python/slugid mozilla.pth:third_party/python/taskcluster mozilla.pth:third_party/python/taskcluster-urls -mozilla.pth:third_party/python/typing_extensions/src_py3 -mozilla.pth:third_party/python/urllib3/src +mozilla.pth:third_party/python/typing_extensions +mozilla.pth:third_party/python/urllib3 mozilla.pth:third_party/python/voluptuous mozilla.pth:third_party/python/yamllint mozilla.pth:third_party/python/zipp diff --git a/python/mozbuild/mozbuild/vendor/vendor_python.py b/python/mozbuild/mozbuild/vendor/vendor_python.py index 7b5592f749e4..a661fb11c992 100644 --- a/python/mozbuild/mozbuild/vendor/vendor_python.py +++ b/python/mozbuild/mozbuild/vendor/vendor_python.py @@ -26,7 +26,7 @@ class VendorPython(MozbuildObject): pip_compile = os.path.join(self.virtualenv_manager.bin_path, "pip-compile") if not os.path.exists(pip_compile): path = os.path.normpath( - os.path.join(self.topsrcdir, "third_party", "python", "pip-tools") + os.path.join(self.topsrcdir, "third_party", "python", "pip_tools") ) self.virtualenv_manager.install_pip_package(path, vendored=True) spec = os.path.join(vendor_dir, "requirements.in") @@ -64,8 +64,10 @@ class VendorPython(MozbuildObject): "--no-deps", "--dest", tmp, - "--no-binary", - ":all:", + "--abi", + "none", + "--platform", + "any", ] ) self._extract(tmp, vendor_dir, keep_extra_files) @@ -99,21 +101,51 @@ class VendorPython(MozbuildObject): if not keep_extra_files: ignore = ("*/doc", "*/docs", "*/test", "*/tests") finder = FileFinder(src) - for path, _ in finder.find("*"): - base, ext = os.path.splitext(path) - # packages extract into package-version directory name and we strip the version - tld = mozfile.extract(os.path.join(finder.base, path), dest, ignore=ignore)[ - 0 - ] - target = os.path.join(dest, tld.rpartition("-")[0]) - mozfile.remove(target) # remove existing version of vendored package - mozfile.move(tld, target) + for archive, _ in finder.find("*"): + _, ext = os.path.splitext(archive) + archive_path = os.path.join(finder.base, archive) + if ext == ".whl": + # Archive is named like "$package-name-1.0-py2.py3-none-any.whl", and should + # have four dashes that aren't part of the package name. + package_name, version, spec, abi, platform_and_suffix = archive.rsplit( + "-", 4 + ) + target_package_dir = os.path.join(dest, package_name) + mozfile.remove(target_package_dir) + os.mkdir(target_package_dir) - # If any files inside the vendored package were symlinks, turn them into normal files - # because hg.mozilla.org forbids symlinks in the repository. - link_finder = FileFinder(target) - for _, f in link_finder.find("**"): - if os.path.islink(f.path): - link_target = os.path.realpath(f.path) - os.unlink(f.path) - shutil.copyfile(link_target, f.path) + # Extract all the contents of the wheel into the package subdirectory. + # We're expecting at least a code directory and a ".dist-info" directory, + # though there may be a ".data" directory as well. + mozfile.extract(archive_path, target_package_dir, ignore=ignore) + _denormalize_symlinks(target_package_dir) + else: + # Archive is named like "$package-name-1.0.tar.gz", and the rightmost + # dash should separate the package name from the rest of the archive + # specifier. + package_name, archive_postfix = archive.rsplit("-", 1) + package_dir = os.path.join(dest, package_name) + mozfile.remove(package_dir) + + # The archive should only contain one top-level directory, which has + # the source files. We extract this directory directly to + # the vendor directory. + extracted_files = mozfile.extract(archive_path, dest, ignore=ignore) + assert len(extracted_files) == 1 + extracted_package_dir = extracted_files[0] + + # The extracted package dir includes the version in the name, + # which we don't we don't want. + mozfile.move(extracted_package_dir, package_dir) + _denormalize_symlinks(package_dir) + + +def _denormalize_symlinks(target): + # If any files inside the vendored package were symlinks, turn them into normal files + # because hg.mozilla.org forbids symlinks in the repository. + link_finder = FileFinder(target) + for _, f in link_finder.find("**"): + if os.path.islink(f.path): + link_target = os.path.realpath(f.path) + os.unlink(f.path) + shutil.copyfile(link_target, f.path) diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py index 05f445ebc5bd..e99d0a8ac285 100644 --- a/python/mozbuild/mozbuild/virtualenv.py +++ b/python/mozbuild/mozbuild/virtualenv.py @@ -494,6 +494,9 @@ class VirtualenvManager(VirtualenvHelper): If vendored is True, no package index will be used and no dependencies will be installed. """ + import mozfile + from mozfile import TemporaryDirectory + if sys.executable.startswith(self.bin_path): # If we're already running in this interpreter, we can optimize in # the case that the package requirement is already satisfied. @@ -504,7 +507,8 @@ class VirtualenvManager(VirtualenvHelper): if req.satisfied_by is not None: return - args = ["install", package] + args = ["install"] + vendored_dist_info_dir = None if vendored: args.extend( @@ -523,8 +527,23 @@ class VirtualenvManager(VirtualenvHelper): "--no-build-isolation", ] ) + vendored_dist_info_dir = next( + (d for d in os.listdir(package) if d.endswith(".dist-info")), None + ) - return self._run_pip(args) + with TemporaryDirectory() as tmp: + if vendored_dist_info_dir: + # This is a vendored wheel. We have to re-pack it in order for pip + # to install it. + wheel_file = os.path.join( + tmp, "{}-1.0-py3-none-any.whl".format(os.path.basename(package)) + ) + shutil.make_archive(wheel_file, "zip", package) + mozfile.move("{}.zip".format(wheel_file), wheel_file) + package = wheel_file + + args.append(package) + return self._run_pip(args) def install_pip_requirements( self, path, require_hashes=True, quiet=False, vendored=False diff --git a/third_party/python/Click/CHANGES.rst b/third_party/python/Click/CHANGES.rst deleted file mode 100644 index a98fabdb0dd8..000000000000 --- a/third_party/python/Click/CHANGES.rst +++ /dev/null @@ -1,635 +0,0 @@ -Click Changelog -=============== - - -Version 7.0 ------------ - -Released 2018-09-25 - -- Drop support for Python 2.6 and 3.3. (`#967`_, `#976`_) -- Wrap ``click.Choice``'s missing message. (`#202`_, `#1000`_) -- Add native ZSH autocompletion support. (`#323`_, `#865`_) -- Document that ANSI color info isn't parsed from bytearrays in - Python 2. (`#334`_) -- Document byte-stripping behavior of ``CliRunner``. (`#334`_, - `#1010`_) -- Usage errors now hint at the ``--help`` option. (`#393`_, `#557`_) -- Implement streaming pager. (`#409`_, `#889`_) -- Extract bar formatting to its own method. (`#414`_) -- Add ``DateTime`` type for converting input in given date time - formats. (`#423`_) -- ``secho``'s first argument can now be ``None``, like in ``echo``. - (`#424`_) -- Fixes a ``ZeroDivisionError`` in ``ProgressBar.make_step``, when the - arg passed to the first call of ``ProgressBar.update`` is 0. - (`#447`_, `#1012`_) -- Show progressbar only if total execution time is visible. (`#487`_) -- Added the ability to hide commands and options from help. (`#500`_) -- Document that options can be ``required=True``. (`#514`_, `#1022`_) -- Non-standalone calls to ``Context.exit`` return the exit code, - rather than calling ``sys.exit``. (`#533`_, `#667`_, `#1098`_) -- ``click.getchar()`` returns Unicode in Python 3 on Windows, - consistent with other platforms. (`#537`_, `#821`_, `#822`_, - `#1088`_, `#1108`_) -- Added ``FloatRange`` type. (`#538`_, `#553`_) -- Added support for bash completion of ``type=click.Choice`` for - ``Options`` and ``Arguments``. (`#535`_, `#681`_) -- Only allow one positional arg for ``Argument`` parameter - declaration. (`#568`_, `#574`_, `#1014`_) -- Add ``case_sensitive=False`` as an option to Choice. (`#569`_) -- ``click.getchar()`` correctly raises ``KeyboardInterrupt`` on "^C" - and ``EOFError`` on "^D" on Linux. (`#583`_, `#1115`_) -- Fix encoding issue with ``click.getchar(echo=True)`` on Linux. - (`#1115`_) -- ``param_hint`` in errors now derived from param itself. (`#598`_, - `#704`_, `#709`_) -- Add a test that ensures that when an argument is formatted into a - usage error, its metavar is used, not its name. (`#612`_) -- Allow setting ``prog_name`` as extra in ``CliRunner.invoke``. - (`#616`_, `#999`_) -- Help text taken from docstrings truncates at the ``\f`` form feed - character, useful for hiding Sphinx-style parameter documentation. - (`#629`_, `#1091`_) -- ``launch`` now works properly under Cygwin. (`#650`_) -- Update progress after iteration. (`#651`_, `#706`_) -- ``CliRunner.invoke`` now may receive ``args`` as a string - representing a Unix shell command. (`#664`_) -- Make ``Argument.make_metavar()`` default to type metavar. (`#675`_) -- Add documentation for ``ignore_unknown_options``. (`#684`_) -- Add bright colors support for ``click.style`` and fix the reset - option for parameters ``fg`` and ``bg``. (`#703`_, `#809`_) -- Add ``show_envvar`` for showing environment variables in help. - (`#710`_) -- Avoid ``BrokenPipeError`` during interpreter shutdown when stdout or - stderr is a closed pipe. (`#712`_, `#1106`_) -- Document customizing option names. (`#725`_, `#1016`_) -- Disable ``sys._getframes()`` on Python interpreters that don't - support it. (`#728`_) -- Fix bug in test runner when calling ``sys.exit`` with ``None``. - (`#739`_) -- Clarify documentation on command line options. (`#741`_, `#1003`_) -- Fix crash on Windows console. (`#744`_) -- Fix bug that caused bash completion to give improper completions on - chained commands. (`#754`_, `#774`_) -- Added support for dynamic bash completion from a user-supplied - callback. (`#755`_) -- Added support for bash completions containing spaces. (`#773`_) -- Allow autocompletion function to determine whether or not to return - completions that start with the incomplete argument. (`#790`_, - `#806`_) -- Fix option naming routine to match documentation and be - deterministic. (`#793`_, `#794`_) -- Fix path validation bug. (`#795`_, `#1020`_) -- Add test and documentation for ``Option`` naming: functionality. - (`#799`_) -- Update doc to match arg name for ``path_type``. (`#801`_) -- Raw strings added so correct escaping occurs. (`#807`_) -- Fix 16k character limit of ``click.echo`` on Windows. (`#816`_, - `#819`_) -- Overcome 64k character limit when writing to binary stream on - Windows 7. (`#825`_, `#830`_) -- Add bool conversion for "t" and "f". (`#842`_) -- ``NoSuchOption`` errors take ``ctx`` so that ``--help`` hint gets - printed in error output. (`#860`_) -- Fixed the behavior of Click error messages with regards to Unicode - on 2.x and 3.x. Message is now always Unicode and the str and - Unicode special methods work as you expect on that platform. - (`#862`_) -- Progress bar now uses stderr by default. (`#863`_) -- Add support for auto-completion documentation. (`#866`_, `#869`_) -- Allow ``CliRunner`` to separate stdout and stderr. (`#868`_) -- Fix variable precedence. (`#873`_, `#874`_) -- Fix invalid escape sequences. (`#877`_) -- Fix ``ResourceWarning`` that occurs during some tests. (`#878`_) -- When detecting a misconfigured locale, don't fail if the ``locale`` - command fails. (`#880`_) -- Add ``case_sensitive=False`` as an option to ``Choice`` types. - (`#887`_) -- Force stdout/stderr writable. This works around issues with badly - patched standard streams like those from Jupyter. (`#918`_) -- Fix completion of subcommand options after last argument (`#919`_, - `#930`_) -- ``_AtomicFile`` now uses the ``realpath`` of the original filename - so that changing the working directory does not affect it. - (`#920`_) -- Fix incorrect completions when defaults are present (`#925`_, - `#930`_) -- Add copy option attrs so that custom classes can be re-used. - (`#926`_, `#994`_) -- "x" and "a" file modes now use stdout when file is ``"-"``. - (`#929`_) -- Fix missing comma in ``__all__`` list. (`#935`_) -- Clarify how parameters are named. (`#949`_, `#1009`_) -- Stdout is now automatically set to non blocking. (`#954`_) -- Do not set options twice. (`#962`_) -- Move ``fcntl`` import. (`#965`_) -- Fix Google App Engine ``ImportError``. (`#995`_) -- Better handling of help text for dynamic default option values. - (`#996`_) -- Fix ``get_winter_size()`` so it correctly returns ``(0,0)``. - (`#997`_) -- Add test case checking for custom param type. (`#1001`_) -- Allow short width to address cmd formatting. (`#1002`_) -- Add details about Python version support. (`#1004`_) -- Added deprecation flag to commands. (`#1005`_) -- Fixed issues where ``fd`` was undefined. (`#1007`_) -- Fix formatting for short help. (`#1008`_) -- Document how ``auto_envvar_prefix`` works with command groups. - (`#1011`_) -- Don't add newlines by default for progress bars. (`#1013`_) -- Use Python sorting order for ZSH completions. (`#1047`_, `#1059`_) -- Document that parameter names are converted to lowercase by default. - (`#1055`_) -- Subcommands that are named by the function now automatically have - the underscore replaced with a dash. If you register a function - named ``my_command`` it becomes ``my-command`` in the command line - interface. -- Hide hidden commands and options from completion. (`#1058`_, - `#1061`_) -- Fix absolute import blocking Click from being vendored into a - project on Windows. (`#1068`_, `#1069`_) -- Fix issue where a lowercase ``auto_envvar_prefix`` would not be - converted to uppercase. (`#1105`_) - -.. _#202: https://github.com/pallets/click/issues/202 -.. _#323: https://github.com/pallets/click/issues/323 -.. _#334: https://github.com/pallets/click/issues/334 -.. _#393: https://github.com/pallets/click/issues/393 -.. _#409: https://github.com/pallets/click/issues/409 -.. _#414: https://github.com/pallets/click/pull/414 -.. _#423: https://github.com/pallets/click/pull/423 -.. _#424: https://github.com/pallets/click/pull/424 -.. _#447: https://github.com/pallets/click/issues/447 -.. _#487: https://github.com/pallets/click/pull/487 -.. _#500: https://github.com/pallets/click/pull/500 -.. _#514: https://github.com/pallets/click/issues/514 -.. _#533: https://github.com/pallets/click/pull/533 -.. _#535: https://github.com/pallets/click/issues/535 -.. _#537: https://github.com/pallets/click/issues/537 -.. _#538: https://github.com/pallets/click/pull/538 -.. _#553: https://github.com/pallets/click/pull/553 -.. _#557: https://github.com/pallets/click/pull/557 -.. _#568: https://github.com/pallets/click/issues/568 -.. _#569: https://github.com/pallets/click/issues/569 -.. _#574: https://github.com/pallets/click/issues/574 -.. _#583: https://github.com/pallets/click/issues/583 -.. _#598: https://github.com/pallets/click/issues/598 -.. _#612: https://github.com/pallets/click/pull/612 -.. _#616: https://github.com/pallets/click/issues/616 -.. _#629: https://github.com/pallets/click/pull/629 -.. _#650: https://github.com/pallets/click/pull/650 -.. _#651: https://github.com/pallets/click/issues/651 -.. _#664: https://github.com/pallets/click/pull/664 -.. _#667: https://github.com/pallets/click/issues/667 -.. _#675: https://github.com/pallets/click/pull/675 -.. _#681: https://github.com/pallets/click/pull/681 -.. _#684: https://github.com/pallets/click/pull/684 -.. _#703: https://github.com/pallets/click/issues/703 -.. _#704: https://github.com/pallets/click/issues/704 -.. _#706: https://github.com/pallets/click/pull/706 -.. _#709: https://github.com/pallets/click/pull/709 -.. _#710: https://github.com/pallets/click/pull/710 -.. _#712: https://github.com/pallets/click/pull/712 -.. _#719: https://github.com/pallets/click/issues/719 -.. _#725: https://github.com/pallets/click/issues/725 -.. _#728: https://github.com/pallets/click/pull/728 -.. _#739: https://github.com/pallets/click/pull/739 -.. _#741: https://github.com/pallets/click/issues/741 -.. _#744: https://github.com/pallets/click/issues/744 -.. _#754: https://github.com/pallets/click/issues/754 -.. _#755: https://github.com/pallets/click/pull/755 -.. _#773: https://github.com/pallets/click/pull/773 -.. _#774: https://github.com/pallets/click/pull/774 -.. _#790: https://github.com/pallets/click/issues/790 -.. _#793: https://github.com/pallets/click/issues/793 -.. _#794: https://github.com/pallets/click/pull/794 -.. _#795: https://github.com/pallets/click/issues/795 -.. _#799: https://github.com/pallets/click/pull/799 -.. _#801: https://github.com/pallets/click/pull/801 -.. _#806: https://github.com/pallets/click/pull/806 -.. _#807: https://github.com/pallets/click/pull/807 -.. _#809: https://github.com/pallets/click/pull/809 -.. _#816: https://github.com/pallets/click/pull/816 -.. _#819: https://github.com/pallets/click/pull/819 -.. _#821: https://github.com/pallets/click/issues/821 -.. _#822: https://github.com/pallets/click/issues/822 -.. _#825: https://github.com/pallets/click/issues/825 -.. _#830: https://github.com/pallets/click/pull/830 -.. _#842: https://github.com/pallets/click/pull/842 -.. _#860: https://github.com/pallets/click/issues/860 -.. _#862: https://github.com/pallets/click/issues/862 -.. _#863: https://github.com/pallets/click/pull/863 -.. _#865: https://github.com/pallets/click/pull/865 -.. _#866: https://github.com/pallets/click/issues/866 -.. _#868: https://github.com/pallets/click/pull/868 -.. _#869: https://github.com/pallets/click/pull/869 -.. _#873: https://github.com/pallets/click/issues/873 -.. _#874: https://github.com/pallets/click/pull/874 -.. _#877: https://github.com/pallets/click/pull/877 -.. _#878: https://github.com/pallets/click/pull/878 -.. _#880: https://github.com/pallets/click/pull/880 -.. _#883: https://github.com/pallets/click/pull/883 -.. _#887: https://github.com/pallets/click/pull/887 -.. _#889: https://github.com/pallets/click/pull/889 -.. _#918: https://github.com/pallets/click/pull/918 -.. _#919: https://github.com/pallets/click/issues/919 -.. _#920: https://github.com/pallets/click/pull/920 -.. _#925: https://github.com/pallets/click/issues/925 -.. _#926: https://github.com/pallets/click/issues/926 -.. _#929: https://github.com/pallets/click/pull/929 -.. _#930: https://github.com/pallets/click/pull/930 -.. _#935: https://github.com/pallets/click/pull/935 -.. _#949: https://github.com/pallets/click/issues/949 -.. _#954: https://github.com/pallets/click/pull/954 -.. _#962: https://github.com/pallets/click/pull/962 -.. _#965: https://github.com/pallets/click/pull/965 -.. _#967: https://github.com/pallets/click/pull/967 -.. _#976: https://github.com/pallets/click/pull/976 -.. _#990: https://github.com/pallets/click/pull/990 -.. _#991: https://github.com/pallets/click/pull/991 -.. _#993: https://github.com/pallets/click/pull/993 -.. _#994: https://github.com/pallets/click/pull/994 -.. _#995: https://github.com/pallets/click/pull/995 -.. _#996: https://github.com/pallets/click/pull/996 -.. _#997: https://github.com/pallets/click/pull/997 -.. _#999: https://github.com/pallets/click/pull/999 -.. _#1000: https://github.com/pallets/click/pull/1000 -.. _#1001: https://github.com/pallets/click/pull/1001 -.. _#1002: https://github.com/pallets/click/pull/1002 -.. _#1003: https://github.com/pallets/click/pull/1003 -.. _#1004: https://github.com/pallets/click/pull/1004 -.. _#1005: https://github.com/pallets/click/pull/1005 -.. _#1007: https://github.com/pallets/click/pull/1007 -.. _#1008: https://github.com/pallets/click/pull/1008 -.. _#1009: https://github.com/pallets/click/pull/1009 -.. _#1010: https://github.com/pallets/click/pull/1010 -.. _#1011: https://github.com/pallets/click/pull/1011 -.. _#1012: https://github.com/pallets/click/pull/1012 -.. _#1013: https://github.com/pallets/click/pull/1013 -.. _#1014: https://github.com/pallets/click/pull/1014 -.. _#1016: https://github.com/pallets/click/pull/1016 -.. _#1020: https://github.com/pallets/click/pull/1020 -.. _#1022: https://github.com/pallets/click/pull/1022 -.. _#1027: https://github.com/pallets/click/pull/1027 -.. _#1047: https://github.com/pallets/click/pull/1047 -.. _#1055: https://github.com/pallets/click/pull/1055 -.. _#1058: https://github.com/pallets/click/pull/1058 -.. _#1059: https://github.com/pallets/click/pull/1059 -.. _#1061: https://github.com/pallets/click/pull/1061 -.. _#1068: https://github.com/pallets/click/issues/1068 -.. _#1069: https://github.com/pallets/click/pull/1069 -.. _#1088: https://github.com/pallets/click/issues/1088 -.. _#1091: https://github.com/pallets/click/pull/1091 -.. _#1098: https://github.com/pallets/click/pull/1098 -.. _#1105: https://github.com/pallets/click/pull/1105 -.. _#1106: https://github.com/pallets/click/pull/1106 -.. _#1108: https://github.com/pallets/click/pull/1108 -.. _#1115: https://github.com/pallets/click/pull/1115 - - -Version 6.7 ------------ - -(bugfix release; released on January 6th 2017) - -- Make ``click.progressbar`` work with ``codecs.open`` files. See #637. -- Fix bug in bash completion with nested subcommands. See #639. -- Fix test runner not saving caller env correctly. See #644. -- Fix handling of SIGPIPE. See #626 -- Deal with broken Windows environments such as Google App Engine's. See #711. - -Version 6.6 ------------ - -(bugfix release; released on April 4th 2016) - -- Fix bug in ``click.Path`` where it would crash when passed a ``-``. See #551. - -Version 6.4 ------------ - -(bugfix release; released on March 24th 2016) - -- Fix bug in bash completion where click would discard one or more trailing - arguments. See #471. - -Version 6.3 ------------ - -(bugfix release; released on February 22 2016) - -- Fix argument checks for interpreter invoke with ``-m`` and ``-c`` - on Windows. -- Fixed a bug that cased locale detection to error out on Python 3. - -Version 6.2 ------------ - -(bugfix release, released on November 27th 2015) - -- Correct fix for hidden progress bars. - -Version 6.1 ------------ - -(bugfix release, released on November 27th 2015) - -- Resolved an issue with invisible progress bars no longer rendering. -- Disable chain commands with subcommands as they were inherently broken. -- Fix ``MissingParameter`` not working without parameters passed. - -Version 6.0 ------------ - -(codename "pow pow", released on November 24th 2015) - -- Optimized the progressbar rendering to not render when it did not - actually change. -- Explicitly disallow ``nargs=-1`` with a set default. -- The context is now closed before it's popped from the stack. -- Added support for short aliases for the false flag on toggles. -- Click will now attempt to aid you with debugging locale errors - better by listing with the help of the OS what locales are - available. -- Click used to return byte strings on Python 2 in some unit-testing - situations. This has been fixed to correctly return unicode strings - now. -- For Windows users on Python 2, Click will now handle Unicode more - correctly handle Unicode coming in from the system. This also has - the disappointing side effect that filenames will now be always - unicode by default in the ``Path`` type which means that this can - introduce small bugs for code not aware of this. -- Added a ``type`` parameter to ``Path`` to force a specific string type - on the value. -- For users running Python on Windows the ``echo`` and ``prompt`` functions - now work with full unicode functionality in the Python windows console - by emulating an output stream. This also applies to getting the - virtual output and input streams via ``click.get_text_stream(...)``. -- Unittests now always force a certain virtual terminal width. -- Added support for allowing dashes to indicate standard streams to the - ``Path`` type. -- Multi commands in chain mode no longer propagate arguments left over - from parsing to the callbacks. It's also now disallowed through an - exception when optional arguments are attached to multi commands if chain - mode is enabled. -- Relaxed restriction that disallowed chained commands to have other - chained commands as child commands. -- Arguments with positive nargs can now have defaults implemented. - Previously this configuration would often result in slightly unexpected - values be returned. - -Version 5.1 ------------ - -(bugfix release, released on 17th August 2015) - -- Fix a bug in ``pass_obj`` that would accidentally pass the context too. - -Version 5.0 ------------ - -(codename "tok tok", released on 16th August 2015) - -- Removed various deprecated functionality. -- Atomic files now only accept the ``w`` mode. -- Change the usage part of help output for very long commands to wrap - their arguments onto the next line, indented by 4 spaces. -- Fix a bug where return code and error messages were incorrect when - using ``CliRunner``. -- added ``get_current_context``. -- added a ``meta`` dictionary to the context which is shared across the - linked list of contexts to allow click utilities to place state there. -- introduced ``Context.scope``. -- The ``echo`` function is now threadsafe: It calls the ``write`` method of the - underlying object only once. -- ``prompt(hide_input=True)`` now prints a newline on ``^C``. -- Click will now warn if users are using ``unicode_literals``. -- Click will now ignore the ``PAGER`` environment variable if it is empty or - contains only whitespace. -- The ``click-contrib`` GitHub organization was created. - -Version 4.1 ------------ - -(bugfix release, released on July 14th 2015) - -- Fix a bug where error messages would include a trailing ``None`` string. -- Fix a bug where Click would crash on docstrings with trailing newlines. -- Support streams with encoding set to ``None`` on Python 3 by barfing with - a better error. -- Handle ^C in less-pager properly. -- Handle return value of ``None`` from ``sys.getfilesystemencoding`` -- Fix crash when writing to unicode files with ``click.echo``. -- Fix type inference with multiple options. - -Version 4.0 ------------ - -(codename "zoom zoom", released on March 31st 2015) - -- Added ``color`` parameters to lots of interfaces that directly or indirectly - call into echoing. This previously was always autodetection (with the - exception of the ``echo_via_pager`` function). Now you can forcefully - enable or disable it, overriding the auto detection of Click. -- Added an ``UNPROCESSED`` type which does not perform any type changes which - simplifies text handling on 2.x / 3.x in some special advanced usecases. -- Added ``NoSuchOption`` and ``BadOptionUsage`` exceptions for more generic - handling of errors. -- Added support for handling of unprocessed options which can be useful in - situations where arguments are forwarded to underlying tools. -- Added ``max_content_width`` parameter to the context which can be used to - change the maximum width of help output. By default Click will not format - content for more than 80 characters width. -- Added support for writing prompts to stderr. -- Fix a bug when showing the default for multiple arguments. -- Added support for custom subclasses to ``option`` and ``argument``. -- Fix bug in ``clear()`` on Windows when colorama is installed. -- Reject ``nargs=-1`` for options properly. Options cannot be variadic. -- Fixed an issue with bash completion not working properly for commands with - non ASCII characters or dashes. -- Added a way to manually update the progressbar. -- Changed the formatting of missing arguments. Previously the internal - argument name was shown in error messages, now the metavar is shown if - passed. In case an automated metavar is selected, it's stripped of - extra formatting first. - -Version 3.3 ------------ - -(bugfix release, released on September 8th 2014) - -- Fixed an issue with error reporting on Python 3 for invalid forwarding - of commands. - -Version 3.2 ------------ - -(bugfix release, released on August 22nd 2014) - -- Added missing ``err`` parameter forwarding to the ``secho`` function. -- Fixed default parameters not being handled properly by the context - invoke method. This is a backwards incompatible change if the function - was used improperly. See :ref:`upgrade-to-3.2` for more information. -- Removed the `invoked_subcommands` attribute largely. It is not possible - to provide it to work error free due to how the parsing works so this - API has been deprecated. See :ref:`upgrade-to-3.2` for more information. -- Restored the functionality of `invoked_subcommand` which was broken as - a regression in 3.1. - -Version 3.1 ------------ - -(bugfix release, released on August 13th 2014) - -- Fixed a regression that caused contexts of subcommands to be - created before the parent command was invoked which was a - regression from earlier Click versions. - -Version 3.0 ------------ - -(codename "clonk clonk", released on August 12th 2014) - -- formatter now no longer attempts to accomodate for terminals - smaller than 50 characters. If that happens it just assumes - a minimal width. -- added a way to not swallow exceptions in the test system. -- added better support for colors with pagers and ways to - override the autodetection. -- the CLI runner's result object now has a traceback attached. -- improved automatic short help detection to work better with - dots that do not terminate sentences. -- when definining options without actual valid option strings - now, Click will give an error message instead of silently - passing. This should catch situations where users wanted to - created arguments instead of options. -- Restructured Click internally to support vendoring. -- Added support for multi command chaining. -- Added support for defaults on options with ``multiple`` and - options and arguments with ``nargs != 1``. -- label passed to ``progressbar`` is no longer rendered with - whitespace stripped. -- added a way to disable the standalone mode of the ``main`` - method on a Click command to be able to handle errors better. -- added support for returning values from command callbacks. -- added simplifications for printing to stderr from ``echo``. -- added result callbacks for groups. -- entering a context multiple times defers the cleanup until - the last exit occurs. -- added ``open_file``. - -Version 2.6 ------------ - -(bugfix release, released on August 11th 2014) - -- Fixed an issue where the wrapped streams on Python 3 would be reporting - incorrect values for seekable. - -Version 2.5 ------------ - -(bugfix release, released on July 28th 2014) - -- Fixed a bug with text wrapping on Python 3. - -Version 2.4 ------------ - -(bugfix release, released on July 4th 2014) - -- Corrected a bug in the change of the help option in 2.3. - -Version 2.3 ------------ - -(bugfix release, released on July 3rd 2014) - -- Fixed an incorrectly formatted help record for count options. -- Add support for ansi code stripping on Windows if colorama - is not available. -- restored the Click 1.0 handling of the help parameter for certain - edge cases. - -Version 2.2 ------------ - -(bugfix release, released on June 26th 2014) - -- fixed tty detection on PyPy. -- fixed an issue that progress bars were not rendered when the - context manager was entered. - -Version 2.1 ------------ - -(bugfix release, released on June 14th 2014) - -- fixed the :func:`launch` function on windows. -- improved the colorama support on windows to try hard to not - screw up the console if the application is interrupted. -- fixed windows terminals incorrectly being reported to be 80 - characters wide instead of 79 -- use colorama win32 bindings if available to get the correct - dimensions of a windows terminal. -- fixed an issue with custom function types on Python 3. -- fixed an issue with unknown options being incorrectly reported - in error messages. - -Version 2.0 ------------ - -(codename "tap tap tap", released on June 6th 2014) - -- added support for opening stdin/stdout on Windows in - binary mode correctly. -- added support for atomic writes to files by going through - a temporary file. -- introduced :exc:`BadParameter` which can be used to easily perform - custom validation with the same error messages as in the type system. -- added :func:`progressbar`; a function to show progress bars. -- added :func:`get_app_dir`; a function to calculate the home folder - for configs. -- Added transparent handling for ANSI codes into the :func:`echo` - function through ``colorama``. -- Added :func:`clear` function. -- Breaking change: parameter callbacks now get the parameter object - passed as second argument. There is legacy support for old callbacks - which will warn but still execute the script. -- Added :func:`style`, :func:`unstyle` and :func:`secho` for ANSI - styles. -- Added an :func:`edit` function that invokes the default editor. -- Added an :func:`launch` function that launches browsers and applications. -- nargs of -1 for arguments can now be forced to be a single item through - the required flag. It defaults to not required. -- setting a default for arguments now implicitly makes it non required. -- changed "yN" / "Yn" to "y/N" and "Y/n" in confirmation prompts. -- added basic support for bash completion. -- added :func:`getchar` to fetch a single character from the terminal. -- errors now go to stderr as intended. -- fixed various issues with more exotic parameter formats like DOS/Windows - style arguments. -- added :func:`pause` which works similar to the Windows ``pause`` cmd - built-in but becomes an automatic noop if the application is not run - through a terminal. -- added a bit of extra information about missing choice parameters. -- changed how the help function is implemented to allow global overriding - of the help option. -- added support for token normalization to implement case insensitive handling. -- added support for providing defaults for context settings. - -Version 1.1 ------------ - -(bugfix release, released on May 23rd 2014) - -- fixed a bug that caused text files in Python 2 to not accept - native strings. - -Version 1.0 ------------ - -(no codename, released on May 21st 2014) - -- Initial release. diff --git a/third_party/python/Click/CONTRIBUTING.rst b/third_party/python/Click/CONTRIBUTING.rst deleted file mode 100644 index 4db9b65a3a17..000000000000 --- a/third_party/python/Click/CONTRIBUTING.rst +++ /dev/null @@ -1,61 +0,0 @@ -========================== -How to contribute to Click -========================== - -Thanks for considering contributing to Click. - -Support questions -================= - -Please, don't use the issue tracker for this. Check whether the -``#pocoo`` IRC channel on Freenode can help with your issue. If your problem -is not strictly Click-specific, ``#python`` on Freenode is generally more -active. `StackOverflow `_ is also worth -considering. - -Reporting issues -================ - -- Under which versions of Python does this happen? This is even more important - if your issue is encoding related. - -- Under which versions of Click does this happen? Check if this issue is fixed - in the repository. - -Submitting patches -================== - -- Include tests if your patch is supposed to solve a bug, and explain clearly - under which circumstances the bug happens. Make sure the test fails without - your patch. - -- Try to follow `PEP8 `_, but you - may ignore the line-length-limit if following it would make the code uglier. - -- For features: Consider whether your feature would be a better fit for an - `external package `_ - -- For docs and bug fixes: Submit against the latest maintenance branch instead of master! - -Running the testsuite ---------------------- - -You probably want to set up a `virtualenv -`_. - -The minimal requirement for running the testsuite is ``py.test``. You can -install it with:: - - pip install pytest - -Then you can run the testsuite with:: - - py.test - -For a more isolated test environment, you can also install ``tox`` instead of -``pytest``. You can install it with:: - - pip install tox - -The ``tox`` command will then run all tests against multiple combinations of -Python versions and dependency versions. diff --git a/third_party/python/Click/LICENSE.rst b/third_party/python/Click/Click-7.0.dist-info/LICENSE.txt similarity index 100% rename from third_party/python/Click/LICENSE.rst rename to third_party/python/Click/Click-7.0.dist-info/LICENSE.txt diff --git a/third_party/python/Click/README.rst b/third_party/python/Click/Click-7.0.dist-info/METADATA similarity index 67% rename from third_party/python/Click/README.rst rename to third_party/python/Click/Click-7.0.dist-info/METADATA index e4c047151cce..625bdaddbba1 100644 --- a/third_party/python/Click/README.rst +++ b/third_party/python/Click/Click-7.0.dist-info/METADATA @@ -1,3 +1,31 @@ +Metadata-Version: 2.1 +Name: Click +Version: 7.0 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets Team +Maintainer-email: contact@palletsprojects.com +License: BSD +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/click +Project-URL: Issue tracker, https://github.com/pallets/click/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* + \$ click\_ ========== @@ -39,7 +67,7 @@ What does it look like? Here is an example of a simple Click program: .. code-block:: python import click - + @click.command() @click.option("--count", default=1, help="Number of greetings.") @click.option("--name", prompt="Your name", @@ -48,7 +76,7 @@ What does it look like? Here is an example of a simple Click program: """Simple program that greets NAME for a total of COUNT times.""" for _ in range(count): click.echo("Hello, %s!" % name) - + if __name__ == '__main__': hello() @@ -89,3 +117,5 @@ Links * Windows: https://ci.appveyor.com/project/pallets/click * Test coverage: https://codecov.io/gh/pallets/click + + diff --git a/third_party/python/Click/Click-7.0.dist-info/RECORD b/third_party/python/Click/Click-7.0.dist-info/RECORD new file mode 100644 index 000000000000..370e8ce1b0ab --- /dev/null +++ b/third_party/python/Click/Click-7.0.dist-info/RECORD @@ -0,0 +1,22 @@ +Click-7.0.dist-info/LICENSE.txt,sha256=4hIxn676T0Wcisk3_chVcECjyrivKTZsoqSNI5AlIlw,1876 +Click-7.0.dist-info/METADATA,sha256=-r8jeke3Zer4diRvT1MjFZuiJ6yTT_qFP39svLqdaLI,3516 +Click-7.0.dist-info/RECORD,, +Click-7.0.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110 +Click-7.0.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=HjGThQ7tef9kkwCV371TBnrf0SAi6fKfU_jtEnbYTvQ,2789 +click/_bashcomplete.py,sha256=iaNUmtxag0YPfxba3TDYCNietiTMQIrvhRLj-H8okFU,11014 +click/_compat.py,sha256=vYmvoj4opPxo-c-2GMQQjYT_r_QkOKybkfGoeVrt0dA,23399 +click/_termui_impl.py,sha256=xHmLtOJhKUCVD6168yucJ9fknUJPAMs0eUTPgVUO-GQ,19611 +click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198 +click/_unicodefun.py,sha256=QHy2_5jYlX-36O-JVrTHNnHOqg8tquUR0HmQFev7Ics,4364 +click/_winconsole.py,sha256=PPWVak8Iikm_gAPsxMrzwsVFCvHgaW3jPaDWZ1JBl3U,8965 +click/core.py,sha256=q8FLcDZsagBGSRe5Y9Hi_FGvAeZvusNfoO5EkhkSQ8Y,75305 +click/decorators.py,sha256=idKt6duLUUfAFftrHoREi8MJSd39XW36pUVHthdglwk,11226 +click/exceptions.py,sha256=CNpAjBAE7qjaV4WChxQeak95e5yUOau8AsvT-8m6wss,7663 +click/formatting.py,sha256=eh-cypTUAhpI3HD-K4ZpR3vCiURIO62xXvKkR3tNUTM,8889 +click/globals.py,sha256=oQkou3ZQ5DgrbVM6BwIBirwiqozbjfirzsLGAlLRRdg,1514 +click/parser.py,sha256=m-nGZz4VwprM42_qtFlWFGo7yRJQxkBlRcZodoH593Y,15510 +click/termui.py,sha256=o_ZXB2jyvL2Rce7P_bFGq452iyBq9ykJyRApIPMCZO0,23207 +click/testing.py,sha256=aYGqY_iWLu2p4k7lkuJ6t3fqpf6aPGqTsyLzNY_ngKg,13062 +click/types.py,sha256=2Q929p-aBP_ZYuMFJqJR-Ipucofv3fmDc5JzBDPmzJU,23287 +click/utils.py,sha256=6-D0WkAxvv9FkgHXSHwDIv0l9Gdx9Mm6Z5vuKNLIfZI,15763 diff --git a/third_party/python/Click/Click-7.0.dist-info/WHEEL b/third_party/python/Click/Click-7.0.dist-info/WHEEL new file mode 100644 index 000000000000..1316c41d0706 --- /dev/null +++ b/third_party/python/Click/Click-7.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/Click/Click-7.0.dist-info/top_level.txt b/third_party/python/Click/Click-7.0.dist-info/top_level.txt new file mode 100644 index 000000000000..dca9a909647e --- /dev/null +++ b/third_party/python/Click/Click-7.0.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/third_party/python/Click/MANIFEST.in b/third_party/python/Click/MANIFEST.in deleted file mode 100644 index 33a336f26ab7..000000000000 --- a/third_party/python/Click/MANIFEST.in +++ /dev/null @@ -1,11 +0,0 @@ -include CHANGES.rst -include CONTRIBUTING.rst -include LICENSE.rst -include README.rst -include tox.ini -graft artwork -graft docs -prune docs/_build -graft examples -graft tests -global-exclude *.py[co] .DS_Store diff --git a/third_party/python/Click/PKG-INFO b/third_party/python/Click/PKG-INFO deleted file mode 100644 index fa75a91f445b..000000000000 --- a/third_party/python/Click/PKG-INFO +++ /dev/null @@ -1,119 +0,0 @@ -Metadata-Version: 1.2 -Name: Click -Version: 7.0 -Summary: Composable command line interface toolkit -Home-page: https://palletsprojects.com/p/click/ -Author: Armin Ronacher -Author-email: armin.ronacher@active-4.com -Maintainer: Pallets Team -Maintainer-email: contact@palletsprojects.com -License: BSD -Project-URL: Documentation, https://click.palletsprojects.com/ -Project-URL: Code, https://github.com/pallets/click -Project-URL: Issue tracker, https://github.com/pallets/click/issues -Description: \$ click\_ - ========== - - Click is a Python package for creating beautiful command line interfaces - in a composable way with as little code as necessary. It's the "Command - Line Interface Creation Kit". It's highly configurable but comes with - sensible defaults out of the box. - - It aims to make the process of writing command line tools quick and fun - while also preventing any frustration caused by the inability to - implement an intended CLI API. - - Click in three points: - - - Arbitrary nesting of commands - - Automatic help page generation - - Supports lazy loading of subcommands at runtime - - - Installing - ---------- - - Install and update using `pip`_: - - .. code-block:: text - - $ pip install click - - Click supports Python 3.4 and newer, Python 2.7, and PyPy. - - .. _pip: https://pip.pypa.io/en/stable/quickstart/ - - - A Simple Example - ---------------- - - What does it look like? Here is an example of a simple Click program: - - .. code-block:: python - - import click - - @click.command() - @click.option("--count", default=1, help="Number of greetings.") - @click.option("--name", prompt="Your name", - help="The person to greet.") - def hello(count, name): - """Simple program that greets NAME for a total of COUNT times.""" - for _ in range(count): - click.echo("Hello, %s!" % name) - - if __name__ == '__main__': - hello() - - And what it looks like when run: - - .. code-block:: text - - $ python hello.py --count=3 - Your name: Click - Hello, Click! - Hello, Click! - Hello, Click! - - - Donate - ------ - - The Pallets organization develops and supports Click and other popular - packages. In order to grow the community of contributors and users, and - allow the maintainers to devote more time to the projects, `please - donate today`_. - - .. _please donate today: https://palletsprojects.com/donate - - - Links - ----- - - * Website: https://palletsprojects.com/p/click/ - * Documentation: https://click.palletsprojects.com/ - * License: `BSD `_ - * Releases: https://pypi.org/project/click/ - * Code: https://github.com/pallets/click - * Issue tracker: https://github.com/pallets/click/issues - * Test status: - - * Linux, Mac: https://travis-ci.org/pallets/click - * Windows: https://ci.appveyor.com/project/pallets/click - - * Test coverage: https://codecov.io/gh/pallets/click - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff --git a/third_party/python/Click/artwork/logo.svg b/third_party/python/Click/artwork/logo.svg deleted file mode 100644 index e0e1b5883912..000000000000 --- a/third_party/python/Click/artwork/logo.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/third_party/python/Click/examples/README b/third_party/python/Click/examples/README deleted file mode 100644 index 6be32961f4d3..000000000000 --- a/third_party/python/Click/examples/README +++ /dev/null @@ -1,12 +0,0 @@ -Click Examples - - This folder contains various Click examples. Note that - all of these are not runnable by themselves but should be - installed into a virtualenv. - - This is done this way so that scripts also properly work - on Windows and in virtualenvs without accidentally executing - through the wrong interpreter. - - For more information about this see the documentation: - https://click.palletsprojects.com/en/7.x/setuptools/ diff --git a/third_party/python/Click/examples/aliases/README b/third_party/python/Click/examples/aliases/README deleted file mode 100644 index 5a4a0665663b..000000000000 --- a/third_party/python/Click/examples/aliases/README +++ /dev/null @@ -1,17 +0,0 @@ -$ aliases_ - - aliases is a fairly advanced example that shows how - to implement command aliases with Click. It uses a - subclass of the default group to customize how commands - are located. - - It supports both aliases read from a config file as well - as automatic abbreviations. - - The aliases from the config are read from the aliases.ini - file. Try `aliases st` and `aliases ci`! - -Usage: - - $ pip install --editable . - $ aliases --help diff --git a/third_party/python/Click/examples/aliases/aliases.ini b/third_party/python/Click/examples/aliases/aliases.ini deleted file mode 100644 index 4f1d54cd6b28..000000000000 --- a/third_party/python/Click/examples/aliases/aliases.ini +++ /dev/null @@ -1,2 +0,0 @@ -[aliases] -ci=commit diff --git a/third_party/python/Click/examples/aliases/aliases.py b/third_party/python/Click/examples/aliases/aliases.py deleted file mode 100644 index 38ef72c5c4d5..000000000000 --- a/third_party/python/Click/examples/aliases/aliases.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import click - -try: - import ConfigParser as configparser -except ImportError: - import configparser - - -class Config(object): - """The config in this example only holds aliases.""" - - def __init__(self): - self.path = os.getcwd() - self.aliases = {} - - def read_config(self, filename): - parser = configparser.RawConfigParser() - parser.read([filename]) - try: - self.aliases.update(parser.items('aliases')) - except configparser.NoSectionError: - pass - - -pass_config = click.make_pass_decorator(Config, ensure=True) - - -class AliasedGroup(click.Group): - """This subclass of a group supports looking up aliases in a config - file and with a bit of magic. - """ - - def get_command(self, ctx, cmd_name): - # Step one: bulitin commands as normal - rv = click.Group.get_command(self, ctx, cmd_name) - if rv is not None: - return rv - - # Step two: find the config object and ensure it's there. This - # will create the config object is missing. - cfg = ctx.ensure_object(Config) - - # Step three: lookup an explicit command aliase in the config - if cmd_name in cfg.aliases: - actual_cmd = cfg.aliases[cmd_name] - return click.Group.get_command(self, ctx, actual_cmd) - - # Alternative option: if we did not find an explicit alias we - # allow automatic abbreviation of the command. "status" for - # instance will match "st". We only allow that however if - # there is only one command. - matches = [x for x in self.list_commands(ctx) - if x.lower().startswith(cmd_name.lower())] - if not matches: - return None - elif len(matches) == 1: - return click.Group.get_command(self, ctx, matches[0]) - ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) - - -def read_config(ctx, param, value): - """Callback that is used whenever --config is passed. We use this to - always load the correct config. This means that the config is loaded - even if the group itself never executes so our aliases stay always - available. - """ - cfg = ctx.ensure_object(Config) - if value is None: - value = os.path.join(os.path.dirname(__file__), 'aliases.ini') - cfg.read_config(value) - return value - - -@click.command(cls=AliasedGroup) -@click.option('--config', type=click.Path(exists=True, dir_okay=False), - callback=read_config, expose_value=False, - help='The config file to use instead of the default.') -def cli(): - """An example application that supports aliases.""" - - -@cli.command() -def push(): - """Pushes changes.""" - click.echo('Push') - - -@cli.command() -def pull(): - """Pulls changes.""" - click.echo('Pull') - - -@cli.command() -def clone(): - """Clones a repository.""" - click.echo('Clone') - - -@cli.command() -def commit(): - """Commits pending changes.""" - click.echo('Commit') - - -@cli.command() -@pass_config -def status(config): - """Shows the status.""" - click.echo('Status for %s' % config.path) diff --git a/third_party/python/Click/examples/aliases/setup.py b/third_party/python/Click/examples/aliases/setup.py deleted file mode 100644 index 8d1d6a406824..000000000000 --- a/third_party/python/Click/examples/aliases/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-aliases', - version='1.0', - py_modules=['aliases'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - aliases=aliases:cli - ''', -) diff --git a/third_party/python/Click/examples/bashcompletion/README b/third_party/python/Click/examples/bashcompletion/README deleted file mode 100644 index f8a0d51ef91d..000000000000 --- a/third_party/python/Click/examples/bashcompletion/README +++ /dev/null @@ -1,12 +0,0 @@ -$ bashcompletion - - bashcompletion is a simple example of an application that - tries to autocomplete commands, arguments and options. - - This example requires Click 2.0 or higher. - -Usage: - - $ pip install --editable . - $ eval "$(_BASHCOMPLETION_COMPLETE=source bashcompletion)" - $ bashcompletion --help diff --git a/third_party/python/Click/examples/bashcompletion/bashcompletion.py b/third_party/python/Click/examples/bashcompletion/bashcompletion.py deleted file mode 100644 index 107284003554..000000000000 --- a/third_party/python/Click/examples/bashcompletion/bashcompletion.py +++ /dev/null @@ -1,45 +0,0 @@ -import click -import os - - -@click.group() -def cli(): - pass - - -def get_env_vars(ctx, args, incomplete): - # Completions returned as strings do not have a description displayed. - for key in os.environ.keys(): - if incomplete in key: - yield key - - -@cli.command(help='A command to print environment variables') -@click.argument("envvar", type=click.STRING, autocompletion=get_env_vars) -def cmd1(envvar): - click.echo('Environment variable: %s' % envvar) - click.echo('Value: %s' % os.environ[envvar]) - - -@click.group(help='A group that holds a subcommand') -def group(): - pass - - -def list_users(ctx, args, incomplete): - # You can generate completions with descriptions by returning - # tuples in the form (completion, description). - users = [('bob', 'butcher'), - ('alice', 'baker'), - ('jerry', 'candlestick maker')] - # Ths will allow completion matches based on matches within the description string too! - return [user for user in users if incomplete in user[0] or incomplete in user[1]] - - -@group.command(help='Choose a user') -@click.argument("user", type=click.STRING, autocompletion=list_users) -def subcmd(user): - click.echo('Chosen user is %s' % user) - - -cli.add_command(group) diff --git a/third_party/python/Click/examples/bashcompletion/setup.py b/third_party/python/Click/examples/bashcompletion/setup.py deleted file mode 100644 index ad200818cd3b..000000000000 --- a/third_party/python/Click/examples/bashcompletion/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-bashcompletion', - version='1.0', - py_modules=['bashcompletion'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - bashcompletion=bashcompletion:cli - ''', -) diff --git a/third_party/python/Click/examples/colors/README b/third_party/python/Click/examples/colors/README deleted file mode 100644 index 4b5b44f69683..000000000000 --- a/third_party/python/Click/examples/colors/README +++ /dev/null @@ -1,11 +0,0 @@ -$ colors_ - - colors is a simple example that shows how you can - colorize text. - - For this to work on Windows, colorama is required. - -Usage: - - $ pip install --editable . - $ colors diff --git a/third_party/python/Click/examples/colors/colors.py b/third_party/python/Click/examples/colors/colors.py deleted file mode 100644 index 193b927121ce..000000000000 --- a/third_party/python/Click/examples/colors/colors.py +++ /dev/null @@ -1,28 +0,0 @@ -import click - - -all_colors = 'black', 'red', 'green', 'yellow', 'blue', 'magenta', \ - 'cyan', 'white', 'bright_black', 'bright_red', \ - 'bright_green', 'bright_yellow', 'bright_blue', \ - 'bright_magenta', 'bright_cyan', 'bright_white' - - -@click.command() -def cli(): - """This script prints some colors. If colorama is installed this will - also work on Windows. It will also automatically remove all ANSI - styles if data is piped into a file. - - Give it a try! - """ - for color in all_colors: - click.echo(click.style('I am colored %s' % color, fg=color)) - for color in all_colors: - click.echo(click.style('I am colored %s and bold' % color, - fg=color, bold=True)) - for color in all_colors: - click.echo(click.style('I am reverse colored %s' % color, fg=color, - reverse=True)) - - click.echo(click.style('I am blinking', blink=True)) - click.echo(click.style('I am underlined', underline=True)) diff --git a/third_party/python/Click/examples/colors/setup.py b/third_party/python/Click/examples/colors/setup.py deleted file mode 100644 index 3f8e105fab67..000000000000 --- a/third_party/python/Click/examples/colors/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-colors', - version='1.0', - py_modules=['colors'], - include_package_data=True, - install_requires=[ - 'click', - # Colorama is only required for Windows. - 'colorama', - ], - entry_points=''' - [console_scripts] - colors=colors:cli - ''', -) diff --git a/third_party/python/Click/examples/complex/README b/third_party/python/Click/examples/complex/README deleted file mode 100644 index 7eaac9037207..000000000000 --- a/third_party/python/Click/examples/complex/README +++ /dev/null @@ -1,16 +0,0 @@ -$ complex_ - - complex is an example of building very complex cli - applications that load subcommands dynamically from - a plugin folder and other things. - - All the commands are implemented as plugins in the - `complex.commands` package. If a python module is - placed named "cmd_foo" it will show up as "foo" - command and the `cli` object within it will be - loaded as nested Click command. - -Usage: - - $ pip install --editable . - $ complex --help diff --git a/third_party/python/Click/examples/complex/complex/cli.py b/third_party/python/Click/examples/complex/complex/cli.py deleted file mode 100644 index bcfd14a132b6..000000000000 --- a/third_party/python/Click/examples/complex/complex/cli.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import sys -import click - - -CONTEXT_SETTINGS = dict(auto_envvar_prefix='COMPLEX') - - -class Context(object): - - def __init__(self): - self.verbose = False - self.home = os.getcwd() - - def log(self, msg, *args): - """Logs a message to stderr.""" - if args: - msg %= args - click.echo(msg, file=sys.stderr) - - def vlog(self, msg, *args): - """Logs a message to stderr only if verbose is enabled.""" - if self.verbose: - self.log(msg, *args) - - -pass_context = click.make_pass_decorator(Context, ensure=True) -cmd_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), - 'commands')) - - -class ComplexCLI(click.MultiCommand): - - def list_commands(self, ctx): - rv = [] - for filename in os.listdir(cmd_folder): - if filename.endswith('.py') and \ - filename.startswith('cmd_'): - rv.append(filename[4:-3]) - rv.sort() - return rv - - def get_command(self, ctx, name): - try: - if sys.version_info[0] == 2: - name = name.encode('ascii', 'replace') - mod = __import__('complex.commands.cmd_' + name, - None, None, ['cli']) - except ImportError: - return - return mod.cli - - -@click.command(cls=ComplexCLI, context_settings=CONTEXT_SETTINGS) -@click.option('--home', type=click.Path(exists=True, file_okay=False, - resolve_path=True), - help='Changes the folder to operate on.') -@click.option('-v', '--verbose', is_flag=True, - help='Enables verbose mode.') -@pass_context -def cli(ctx, verbose, home): - """A complex command line interface.""" - ctx.verbose = verbose - if home is not None: - ctx.home = home diff --git a/third_party/python/Click/examples/complex/complex/commands/cmd_init.py b/third_party/python/Click/examples/complex/complex/commands/cmd_init.py deleted file mode 100644 index 8c30186c3e16..000000000000 --- a/third_party/python/Click/examples/complex/complex/commands/cmd_init.py +++ /dev/null @@ -1,13 +0,0 @@ -import click -from complex.cli import pass_context - - -@click.command('init', short_help='Initializes a repo.') -@click.argument('path', required=False, type=click.Path(resolve_path=True)) -@pass_context -def cli(ctx, path): - """Initializes a repository.""" - if path is None: - path = ctx.home - ctx.log('Initialized the repository in %s', - click.format_filename(path)) diff --git a/third_party/python/Click/examples/complex/complex/commands/cmd_status.py b/third_party/python/Click/examples/complex/complex/commands/cmd_status.py deleted file mode 100644 index 99e736eee6cc..000000000000 --- a/third_party/python/Click/examples/complex/complex/commands/cmd_status.py +++ /dev/null @@ -1,10 +0,0 @@ -import click -from complex.cli import pass_context - - -@click.command('status', short_help='Shows file changes.') -@pass_context -def cli(ctx): - """Shows file changes in the current working directory.""" - ctx.log('Changed files: none') - ctx.vlog('bla bla bla, debug info') diff --git a/third_party/python/Click/examples/complex/setup.py b/third_party/python/Click/examples/complex/setup.py deleted file mode 100644 index dee002c13523..000000000000 --- a/third_party/python/Click/examples/complex/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-complex', - version='1.0', - packages=['complex', 'complex.commands'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - complex=complex.cli:cli - ''', -) diff --git a/third_party/python/Click/examples/imagepipe/.gitignore b/third_party/python/Click/examples/imagepipe/.gitignore deleted file mode 100644 index 63280895b10d..000000000000 --- a/third_party/python/Click/examples/imagepipe/.gitignore +++ /dev/null @@ -1 +0,0 @@ -processed-* diff --git a/third_party/python/Click/examples/imagepipe/README b/third_party/python/Click/examples/imagepipe/README deleted file mode 100644 index 91ec0cd26ffa..000000000000 --- a/third_party/python/Click/examples/imagepipe/README +++ /dev/null @@ -1,13 +0,0 @@ -$ imagepipe_ - - imagepipe is an example application that implements some - multi commands that chain image processing instructions - together. - - This requires pillow. - -Usage: - - $ pip install --editable . - $ imagepipe open -i example01.jpg resize -w 128 display - $ imagepipe open -i example02.jpg blur save diff --git a/third_party/python/Click/examples/imagepipe/example01.jpg b/third_party/python/Click/examples/imagepipe/example01.jpg deleted file mode 100644 index f2d9397755be888e0377fe923c03068606b69cf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51677 zcmbT61yo!?)}UY0xI=Ic9xS*^fZzdwI|LdD?jC3$xI4jv2M_Lq;2PZB-QAbW?9R;Y zIcxvzbE?0ty7gY&s(Mwo>)q#>=M?}`R#HY10D(Zjr>Ya1sAWhpTVO)YH-gg*cbfCRt;Yye;gakP_HkyHg9eT7Y2WL;XoI2 z6W14>cwuTQXKV8pzIkCBYZF690DwjPo9|=-`TWAHFO2G-sx1D(f&hSsYW5#&^dIbG z;`Y)`01&seb9XQ|`|LzP4|zku#>dA?A#LJnW#Z(-{Lv6%Y3N`~A#Q7JXK3RN0ROc4 zZ!G}(Z{Je9bTT&^A2&BMJIhP=|4aUlh5yp}Kf~X#{invc(m%!wgg5x_ynomIcb;uF z0PtSE^iA}?^Nf-Kpe_Ia2gvj3ZUSNX z+oAuG|Et2kH2?STANOPVd%u769mRVSQ$uGfCyKwF3bD1ab#|a|v@?X5P%!_mllZ?} z@jsgNAMIdLHZe7EFtK^LmHNvpGq*8&8EzY6b0>3K8wzuq|J?}x7pwh88~)-y=k*J` z%6$TG3|IinVH^N_I0(SLLIJ?K880QEe~sG*Bz55Llczzx{m*&-!Y}3jNdKnp1<(V`06V|~2mtQ@2|yN51XKYn zKp%hrp8;#Y0dNJr0KPyV5C%j82|x;v3FHEWKp9X8)B(-FZ=f3(07igGU>;ZjHi3QM z1h@k3UluY15E|$eh!8{$q5(02*g?D?VUPsq14tR91^NUs1KEI_L0>>$L1Ca+Pzopu zR0yg7HGqDD`aq+gS!!r;J=!qCFJh2ez}g^`0%h0%jCgRzJ4fboZk zg!u-O4O0SB3-cRh0A>?>FbSY}uOSZP=_SO}~=tT${pYzpiT*jm_5*m2lZ*b~?%I5apC zI7T>rI2kxiI5Rj`xInl>xO})8xGuO!xJ|e#czAd`csh6_;C1i_;UC* z_)++E_)7!?1VRKx1R(@P1VaQTgg}I3gc5{b2xADF2sel*h~$Xuh?0ofh&G6Rh>3_r zh^>fYh}($wNSH`8Nc>2ONXAI+NKr_+NR3FtNSjFa$XLj9$U?}f$QH=H$ls95kh_o< zkk3(2P$*IOP?S*2QG8Ioq5MSYMOj6;Ma4#CKov*TMRi7vL@hvVL!CuEM?*uSMSF*) zjpl?FiB^c#fwqKpgZ>Jg1ziT+7#)h9ie8I8hJJ*Bgh7KLilL9;fsu$&g)xkAfQf`j ziz$w2i0O@)irIiUjd_Xn3X2U(5z87Y9IFVc4{HY-0h<Uy<_1CK+8BZFgs6NXcY^9Sby7aNxoR~^?4Hx;)9cLfiOM~f$eXN4Dq zSBW=;cZW}kFN$x1AA(aFGa>h=E9n z$dxFAsEg=;7>8JZ7(yIMTuD4f0z<+;qD1Z`*gJ|n$cjyS{WavET zis=^U(db3!?dh}WC*Hun;eBKICjHF_0}KNf!)Jz6hG9k+Ms7xP#&pI}CO9TOCL5+~ zrfFtWW>IDr=3?em7Ce>@EPgC?EJtst-)g^&dE4{$iIt1hiZz#Yo(-E#md%f?k?o9~ zfgQr0%09t?#v#c8<*4U49G@5;l&_iZmYh9cP_YwxJu8NbVaw=Mcc)IzjG^hk_V%t5S1>{^^(+)KReJ@~!U`_T7) zB(NpaBvK@nBq=4$B#R|aq`0I!rP`$7q~)Yzq^D&_Wgs$zGAFV;vR<;Ca;S1Daw&3a z9~eG3d}x%1k(ZT^lV4DvQLs^{Qv?)c6yp>ZKhk})|JbAiuk=wVRcT9^P5Fy*kIE|* z1C=6`D^)SoDAjp2dNpUYc6AJOUG+lsYmN6Bu^KCyZ#BI%2egQ^%(d#Z5wz8{^R+K^ zByA_IZFx&9bNX975=ma7T zNrLPfzcY?E-Zc?2i8a|a6*7%A-7ym~i!joQa8%vu`TQXZW+fh44yFj}Ydw%-_`x6H_hkQqnqn=~E6V8h>HRw$5 z9N@g_BJ7gta^tG*TIGi2X5%*K&fp&6zU?9Dk>?5P3GrbX66ym^KBMEPO)j|DabD?gNfbQbay z78a2dMHRyoI~VVk=$4F>zAvpWV=l`o$14x}3H)^axmWS2VyaTEvb~D8s;ru(I<4ka zO=vBs*1h(m?sMHry;l8bgKR^4qd;R#6H8M;^Xul+7TlJoR^(Ry*5_Xyzb@PC+75o3 z{a$Z3XrJ%U?3n0O>ip9s*VWrC+1=42+ViVdsJFR~zptU6x4&+Hd!TlZYp`aBYpCWA z_n+Efp5gitzLCaJ!O_++k+I+7@5j3*WF`hC6(&cg)TU;pb*EQmjAwRct!7W>T;}fQ zeHP#rLKiU?6PHMqvX|d1m#=WIw5+~g9b8jcn_q{l?{7G6JZ$=Jp=~8@lW!O9uFjOp+wI>U1Ri1?rXA5ARUf}Q9z4-J**tYPeLf36Cp<5>;Jj$R{CK%^Wqoyj z9eP7}^W&EHw&zacZu{Q#0pa1> z1K<||{q-h5L@)lqKm7_>5b?iQ8ASizbzlG>$owCU#9!az#lQcDe0oX${{H7T_&ey| zSNsn1KeS;+zJvbr9BS2Z%h^Iy+&sK|{NnE=B&DQfWK~qv)HPn*K8Uf2so7_93r8ns7gslTkFWj# zfkD9`p|NrC35iMHl2fvCa`W;FeiRl}R#n&3*3~yOws&-Pb@%l4^^c8DOioSD%+9T@ zt#52@ZSU;vot~XvTwYz@+}{1Q>t%fYY1Y3i`(NzBda(-z78VSP@YgO7jO$;+v0&j| zv%zDFDj^u!zoKOKMZ^({$*TB`M8%-+#%ne;M{~ zyXF8?Fz99Qz*v9?a2e4v716VlJ;bti!$>Y~BtOwq#59_MV3bi_#FBjFZYF*u1!a*z zc&MT~iWTCYTwIOErTE%Qafz#cx5PLgV_iTPDe?R2LPSY7GN4HJ^IhzYN8&P#jAkAk z!SLeMocopmWg?-p-~eHpMxC65gnA(suE?s8$VcOXNz(|qX1XdsE|Pt84aQmnMrBYg)^W4498 z#xE+(q_t&y21r#N%|B)E#ZX6#uGxsc>80A&#rRsY%+sZv-c$=|PFNC#hA5J!JOc~? zipgwZN$l26Ld4$QHQUSBHFSxZOq6lg$gRe{3gT?Mz$4pOQw%L4#guw_)^3XZqP02Z zm&BzG`#$Pej`3Ja`dJI>fV9sOSFsuu+a8L(&ZJV;`mN8`})-XIC`t`-k^XpbzeiUFFfO)Cwz`flQSRoMX5j$F2d-UM>6Xb)CA3BXe`B4!JJY*Bd{K zb-f1XINQR}M3ped)+^F13y4%h%vN=6OJzLB(b^uNUY@VxcmS=}$d%D!Z5E5~BrE)o(Cn ztXarrBlYJbOe3DY-YC{T6xWu_eHmS@`O`Qt$>%t3@mOw|p=OCTsEousAf1yNQ`mvA z$1uO3+iO?RSwN~AbEi>ap-mbT{E5e9>Y7Mm%aM{(Q(bs}n^ zbXnvM*M!96ZS}!D`)Xt!jd`oa%qsQ0I-eWD18hnuUFPGB;sb2xA@xZSqmkUT?dLV{ z?N+he_t~xv;-F{1{puNbt?gxzDJ~I`dsh|pc)PptB$;mgqtA?GR*Q)Ce)PLQYtB+5 zVRaKL_pN-CJMn`>^4NiDdhM#r5y|#>!Qm>6X-K*njj;@FTbg^K1NC<@NtbBoH?EkX z-Nd`FCduxl(-2dPw&+XhXCSz^G*{b3BV3-C4p~_lv2c($XI7xP&4I8DRRl{3@B1;l zY1Uv3pFB^;Tv=Wr8h?Acd)awJa5IL(B5+OH>URSr$BLNOKy^_6PRv2Y{4dClSm6H?pR?=TKu$laGRe)K!) zUOg-;UEWAQClnaYQV==LOG`;4LpKy|M$b7YoW9hhLOWfaf zz+RAHY^3=_P$r_TLqO9Ir&ufJNdwtv&q#-t*@&CS^tg~Sz~t&_XQtihOHFNZsx>{* z{89#`;o2ViQQxY0dS7fu+OqICdV>ySI5X4ENey2LzBmhYtS%b%ib+B%45c*L(zxBA zntnLd?^;nrhqjA+*IQo9UliNIb3rKijFX_a=k=5jbMg#y7+oDY3seu4FyALog^;-3 zVQlL`!!GyH-pbe4HDo?AxXn@pc$-m&n~??y$(!(xWd!o&zs;~jk!$_6`D8Y%)G4bO z*GENte^9!N;T8x*9(Hy%x5b&p$3l$nSC{}|6%h1u!b5#aD`>4XJUF)X0e z8Uq`zz(x;E!0Y3Fic^Yn>BXJNK_*W;Im&Br{%Rk&7{-JKb!`%!N}sJg*(`+DZTK9a zo^$8>IZ}MM@k2((^uCVLBFbZJW2!Hw1u9QCpHgNMUD5qjsmhhMl-ez^tZZG&+u&nw zq6g{vu?$8uk2Sdnn#hUz=tNJ*)2Lwll4J8dkIv#dJSDUZs}a0EzGW z817lI^tSu2%YGR3T!)$PHS3-Qa@mWu*Hs@+I2^wJ3mp{MsiqUi^p@1SX>NO$r4LGWEI)nH8 z=yZx6Lpb~yc(mvbjl0gb4A{1uo4Cnb37#YpaCN2n6PGCLe*!1NX}Idv#Gdf@W*RK4 z{0w+VJhDUc1a5pqw09H>cRDJdzcsd|J3UBOdC9EoMeb!^)?Pt=^=?i{7HtfbnF)~0EtV|h(;hHj$F6~jO}%{(fj(yCRvYa|jvgk+QHMeUe5izT zGBDOP?UoR?@j3;+=~itEAXwc^UNGztaibPQOIXra6HY5hmgv$I8GBquJ*a#so7Sgn zt_`@?c~2SPRr!ncVgKvICCb2VnC_CU-p^g?v8HEWM~Z7!Z~j)fI;IQ~{jkHg-2h%5 zYglxY*TiBeeFi2P=2TsTmnP@MR3~F)$mFfC{oM->Hyn@15vVcRv!h%N&Me&FujlyD ztF2*72-_%|5`&WH^))1?12`upxp2>MzP%2WEE+k$8%jSnxVH;J9bWw30#ZuW86*loarfLgfW$WQ_Bgnrf@9p(yqpZ<0^Svrf#9ynhJiv%u0aLgP^y#lME22_) zwJLp1&y9UBAkV;5`TG-EAI^DuXNRwcv5_2o5g3<3ikq7Hc;j80_sfe>3!Po9HsRZu zz0PGR$DMXZQO=)k5H2`} z(X=!rR^=@9#AZtHGk3{b_Mwt?wmVPNSl$DYCxW6eJU$S-(2$e(pfbyi#m#O8<U(FI(JsHqlZ@(}J|VQb;d-u=zqpxYRIW|V4;pN*_~r4wjv9@FOJfyR>;0Zl&} zVz<`V)h$gK{8^9uU8tgw9xPoI(vn*3Ckte4uY)fbp`qHs_RiK&t6$3|8sHOUdAf+r zaY2)nruhgm9nW2+WK%eN=Cklhr$4fBU2eHoO1Y8cgxFaf)D1L>SqL#IyZq^YBHWU= zvAIeHx<&hWpZ3xHJ;^(8rqJIMb~t9_BXe#Ppb;_MSaV9(Xa?39;{M5`#TIXf@5YdU z$Jjnpa=Q`|kv-+kG0UG7MSj;G6F}@kta`M~N5`e3nX#B}nabPzZNY~7F~`VVX|G|! z(_VMu&snc42S*)K=f4IdQ|- zVY^1EDSA#54jyWZcarYm9llN_AkVaDo5+<5E2Iu(!%>#jq9Si=30h&(!%At1*`A2J zUMQ~4LPa1&`@EYNqd&0GXZKUO_;{(r?N0?L`SBaS2cdre!pobu? zj8Kj6hnAKu?&EA0oLhsKE0(*Dlknz_1~mP4nwie8xya0URA;bh7IlXsImf*Um^(3V zlkm0$$z)v#jw4_E-7MN~otUCKZbCmQT96|nBzP|bk2{u_k`yrKmY&YKa2OH{QrPyN zMy?);TSM0bg4H!?WGL+j^%O*LHySUKD<*BMLtJKV)eZX)qP?D4Cl!X3ntrC6RHbLf zaQLPb4u90hLI|ar&3OC*%b2H}7?IIG^nqD-DP(OxNI|tOp4c)G42tUCCJ7MHJ+X8T zDdkgS9!=mGp!xCJm3UF!hWL7vq3O-jz8S&=)k!hi&`gG>23FA?WzQOV>U|g1!n{|C zQigv8z2bVfmu1OUdJmzjhp zsC5)oW-1Ni=JC+CAQvDNcz!l>Gtf;$nQzi0^huf1m4t2=6`D|ZfgP7Bz7X@IuA%VZ ziIU(QUWJ%Id}1h#D}>X0Zzj>yuiCpmA3F&Qth%DuXl@0_kcxtmHU-K2)ua5IdAU4a zSw6PpOIR~9Rf(D|nRNJGtJOgOvUk4;w^I(T?3ElmXjStQ4ks>2@pbgPGA!W|ICqTa zw;B&Q>JM@%Be#E%-Oime@+j8Sjay|^RfqS$GS;Z3WjZK2C{j;GTyFdsx^E&mf{VCF z-D|z$nV8{|8rT|$$Ji_olVXClH}9|6gpf8zTe$4Wwo-m`9za)p5)xs!V7*jPua=kW zD$ONSH@1P!euCyXsT9+s>y<8b2** z`g|Fou+!%Vu`Za!I?HJ=Z!I9f$g|ecnx8Gy`K&B>Hi$5|v~kI0rPivW-M$@;n;prc zFfkw%tBXdmhmizLaRSw8Jf%yJ66X$jYmS6ke9fKJxHC38Z%+WoA@kK3A3Vm?1lPy z_i}xtrg4=mKPULOvrxN`&^{@?Y$XNeDe8=t5#Jxi$-eIHnJaUN^*7Mn%%mj>Z#BL$ zbHX;&P0Se%h64m3fy3Z(k*V5;H)|-v$d(lYV7!1}3}UZYs$m9b)`3@qk_gv18!wh5 z!bs*bpvIDAF-V55SDCd!)-zUZE#jQwN$`hR$i|V3B9#8JsRGftjzfmpvm3o#hVTJh z1o_TvWjWBG!y6-bv8VFsHehhi<2w~%rr)~o#&n3AVfC$Z3+1}Dn00BH>Yx{}VfL7I zNH;@t_YJdyL6kJOOt-tqPIYwEG{))Hyfh-#ZtrEUf?u~#OM z(px6OsSYDqrrS4CSqH)imR;9$DyKB_-e|p>|O+Bw_7a+9V1>zV&f}M z8;ByZ^+P?Xo(*L*kNVhOZ)zUUWew2W9NXq3x_@5fAMGtVk|Z&=Bo8AO@xv(Qxk*-V zbr(Q6ryU4c$`%GVGg^NINq|Q*${uVdv~tHet3@c#9Onr-fCY-d^E0%Zlylrw>ub)8ApVkTincZ-?+!apP4Ut#Lh zNEe3;>FD0*CMVE5IVoPwqMwPNgC^`Y6nJ ztHaCooAlR$P^M}B&jwhRLS*~O4bl_|mncy+3S(J(URk^pC#*T)8d7wf2@@ryZ)@ZT z{O$Ctq$%Q`Zv8egQwdsVF*E}<27yqFCG6qTfp-N?brr9Od z9pcfJm1lb$$?lz>`6-09s+ivS?9c{CczQueq@5`|f8;DfZkhN!Y!0il5E zHll#zgVYJ`o`bAIwU?p;$&hEZ9&UKIvB|qK47xN2epSh{nK#0QbhBn~bd96LV{=YR^JGNzKOD+phNWe+>wGzH9Z@r$ zS$8FM>$@l-WBgTHm3ok(x3(nRaBlNjF-|xpt`B^_h+(lX!Aw1VsZrOU7b|vbOF>%k z;)HK_S&r0@2kPU!94rJKm8YPj-hW#gl-x5?ZL$+qYdhBT^l+L>dy=C0pg|RGwA?at zIxmOk_lMJ)_S=?thWo~oSh<|JJ$hPQFO1mHD3w_;3lhNvxW%G0b;zZii)AJFBgPuU z52}lN_yzi%C1F($zMqvao4q7lBveXo5Q@z}#>`#jI#E<8i<5Zvh<}@=m;Rk!=&9JA zrgGl=m>`kQF&TWqymtJ>&iCv@` z&LMKnU#XTh%||Uu{P?9QiTSA$;v+(&T1#hzx1#`$D^;TiUubVeo%h;58GTJ(SnB(* zE^@Kgnn0yJ_0U#}Zb7?(qW-U55@eMK#CD`0UA%ShFT?v0~}(m!={S(&vS+D^D<4ECj}8rvya- zZ>~74vG~hP47ziqbCW~c!#7aVa|#+Rid~LvqEhRP6Fhv%tGzh~4kfjsyYQF~e+3fM zlZPDZobf(LVp}&+o9QuR%{L3U&i9f>D8|L$_5iWw>uRfPp*fhOZ+pyc;nw&%EIuM3=uQ=uH=+3&~J?*_9_-2gurfag+L?u_4;74k=jI3yJRmv5f5UJBxQe9oC&<_0I>5P^Stu zlKy8v)K|?oP*~2`cbZubr|^fBp>if&6L!M5HG#5AhV;Jt_@VcxE0N3=tSe~Hyd_Xk zLVtTiCGjm+AHaZ~z*U*>ZXjBe@AvP!N6Vc2Ai*T@nd-VAxs$;w5ALtUC8kIyf-#gF zY${0(gGeF+HEsfLhww+B4A;McwC63gza(lzZRxc&$z@bZc7USlH^|$Yg^yQ)U;q&5-C9E)F38l# z@LQ<1Jl|rfiiFTg^KIgzOMD*%By0Dg(AfZSamI~N?i4v$usGkA54s&2cb|X9dU+(_ zK({I4EK2qjzAmcu7(Xk$T-f;Hz{@e^<0PJYmk@%Zfe<9L^XpQ2iV2JT%;=||YZL8K z9+uKMe*MBFaI~&Y+dGc3UGyz~40=2?=1PQTk+(bz6MNL7>L2)@oVOg#N5ZG;c_{qY z`7tHj6~mmQ##q8*V604R7kRERt}!kyAKo}z3Jo@46;vkmZtDiBbh#{{opKCQnm5KB z#h=0sx_b++lWmV&ck^Ga=IzH!sKQGslTn3W2C9ssqD$>DY8IzY7ItS>EiB(eo!zAM z7QoJT{*FIGWFEPTWUM*KsCq2V={#n#_9U3MYx%taPqj=~&UfmV*IhDQ;fQv@wooup zM&Jzx)fOZy9>}-+$Yfsbwb!mXkCMbJOhFnVhIUL0p03S{7z$Y@=IC#++8Mh zb-L@<5q*&T8cF++xX4M%_D1Gkp-egoEvA9%3NUhV@jxY2#h~>bh>#RK|~86umsX>8E;BAo5@M~9qCy3_nq{dG%6La9{c>%bB& zA<7wT{pI`|n_qhi#Y{0T+mtIt57kl~&&2CUzT6=@`38YXcbV%EqVGezT=HMzf0inu zsr@cg9p{LpQ&E2N13OPPdnr1@`m<6ENuj}<5I2>Mp={a}&m?c!25ONA%(xSXpOo2zZ} z;e*dpLTDe&>>?}M{3X^i@ah?8hUS?QOPRl)rjQdkp*$zwe$V~K+lZRZ!|Gr$gw z&P}eBJn~>jd}NeY2o}zxkxW_ID1Xbr{^J?wk#KprZ?*c^WtfgnedyUD`@8j_cVLW8 zYZ2d)Uohr$N~dITpH(^Se`Z)czpQ1pk0{oj_?>8&`%A?2p}6p8iH z3^ff5l61^g+FAN(`itIX!(u{J4FFF3myTNK-CE23s&M68K|n0hLe0?E$Mn99%60me z*IGVaU2dNU34!n{L99c)<=?5}wri=WVhZz3Ms3g%;`};?Qwb7%z8vZz(p=T@(QeOrAxgja(Xur_Oq}SYYgD}xV%7!N z+*g~ry7eh&KX?=lpAA_hy$|!m#8PDwp2>GsE88>N{r#9Yz2Rotm55Kq*7(j{GdoDw z2WAjTTlnz$|TmKE10)9@xw+C{d<&6Qml&t@2^W76m$> zHVpd=RQcXa=YzrlRso}$tBB8`g~3-!9|QMY+|h>H7v<#$xKId1`2-T8Gt2cYQ%;MCPhQ2H&U&)P z8ow+{6VeK$BtPD(t2BNeIqZ zmgvBiA{Ye2b+nOYe6KbTZ&{qo6H&Xj!EhZN$?o+d+H?(v6bGO8A?Up9PX9n@e_Ver zN-X{RXX7)?O=GEV{F4a})j4pkEIBQ(`}0bskPvc7s14 zTh0m93lQh3)X(`A%{uF}7Y~v&&a_fP0Mya^!Dv<_LO!nfJp*jWl#_Icjg>YbZgg|Z zASuCHg?b@-?K|7wy_kWMT*)SvI-hY7wr074etgFBP$f6y4tC}()6+NYGpFLEm-OS_@{#mHrK2=EY+mf_V=dPmgWR%IqnSMLPE&S(Z3^7G@=|q&SX_E+gVVP3eh{U-ytcEY` ztk@sDj}*m6?lm$B8>?zK-4pDUi$m2Qqq{p%I5+;S`soD>k+J;iJB)!;1B$v%=AK#lXwZweQcbFt-h9i;QY#~oKb`i zp1CBMG{EOD_ZS-5$|$}f%xsl#ff9J|Y2_+bo5?TLPbjt%LvYA%Ec(B;BK9v$vnGo?Rzd8E$O1Z}! z!zIiQqcOuGM65*3SDiGtOT*lB{MdWcVvGGDQ}T+c#b$3>c_6ogrt4P%XAiNa@sIr* z(~$en&B8v;j5^kQs|*GOm)Xv8YU@Tl4;5&SJO(D*EaoM zXOLs>K)7k2Fw)pq9H(E7C0pS9D=@d-Ydiz4_T*z(t+kG}v?ej3;XZZe{Kt^%)bh^KtEk$VC|M_=eOINqn&{$lacS zj7ytEQys%C=`kCt?@ZDcySHPv5|W^e>+8!>_lR9(S&}o4)(uP30mG{_>!=~j0#XGe zk?6cJ>-SelJ>-I{TvPk|HWOc7`*Pc4NJYiMw9>kxRW#FVR_M z@)b77-LnZj_X_+NCJ+0=iEm6}C?k+ucvU3^$iI_3sT$hF1-0;Lo~z;2#0h7_$@P-y zP3+cv?-fbPQ%)Js4pB_tN!{{VDGm2hEFY`u(T>;nwj*(vRc-$&%Iu6+##u;qp$}!? zEuo|m?SZ%OFLABI;-zkfI@hrI67Ak*4-UrzB` z{wSs1W6jFTg%)VK3>A+v0!cWLpVWSW{mo09w2|6a6=b6kTT{xWEeRWq)VAMA=@<5A{vWEVjXgh90P9o@5Iv-Ej{}g>thx~y|Z&6u9 zZ9$P2tsMz#aE5hlo9)L1Rg6vVV;BW>}Xi# zKD>PG5V#N73E}yDDtR9gu#uDDQG~QlO((s~j4L0M=$1e2?U|1Xl#-G<3Lz$uMmWqnwr6rMu;qE~t z5d+>{zmV-yr6<)@rvmWP zs_Rf6dP*#IwqdP}dJyCHAtPdhXT6Opk0Il_S)Hh5?|xAML%P!PP`P_lQrmr0K?ud< z*M~`Y6Vb-T2zD;FnJ_MD=t}un0;|T#I6rg$PJCp1gtvb=f=e`<77spb?7mDA`Rx zA%v^);PT6cK*NZLmNGAVzmCgC%j{NcMHBY9dKnrqtlm`z{-^4F;?E@|tF?7{74Nff zJdw{8@o@QGGum9-Ix~gpjyuYte`X_j(|IaC1dLEPVN*%AVXlOeU1s7a?ac{Q_G?*h zzB7)1hNBlL=6l>t1q)6x;~~^moSDGlCMt70j%`GZOi~j|ZeDyW`tkiGAQ}NcZaakr zkBe8&Vrtpu87xXFqCAazLiwA@EJkS+=cZdqeU@vd*a92?kgm zIDYD1?DstOH=K3 z@)(bk3^L&wLLhyokGKC;!(&sPixB=M`BW2q?Q}DQURK$mb)&Cvv0L~|#<%-&`yAJF zUW=VFnfXNVn*7(gLesc>Ye>F9#nzQh0JwH0S>raPzwRAsMNBk?B1C-^$U*`NlKpx7KhDH&W=cBSMDN3K8_u6mWs*g+-sHE;vY*<9?~tiP%Wry zME>N=;nj#MVAT6OF6?t65_KRbWi`6^?ZBB{!zsGSr%a^T|B`G`!q_cJXC(KuD{Nse z5y{q?z?_~Kb zr6l1PDAA2!JsHKg2(b_2urQ59=1J0Cido=;fV;Jzd}?a)*e4@hy9U1B-7-D8Yt0$% zD!jjATHr*f-}|<5>OM}O{IS&5L>y0I_elHsn?bo*Z%zoID+8%+JiBV7I&Ai>t*wbx z?3{Iuq1x*WCSFylNY8cL?Q=Iz<*y%O=e8B=&y7R`?cbA5Kr02J?7PfAU*9E0xv?-E zeQDS*V6KZ;`LO}c+_BKgO;xWqzqB^pu<(@*AF9D8^^1uV3S@LUSJrMSpV)~cD@jqF zSUREEz>~bQ%%2Fzh_f%HyX?(3&L4e;~cjIufL-Ec!1_Y3ETx78L5iWNU}E_RXR#(CY!IT zFqVdBIp)FRGiKxgx?x+*^|nU=ihIy>kq(!6P885$^smPYnS$L@!M@iKgefwbJ_uH8 z@tem2xP!kZbO8}5NBOO14Y|b;h(JaXy^XSP31@PHC63V#FKrsWX^^x`E7MXbD=N27`s#>h3IZ9KQ<)B= z%z0;h;6UDW-fe{Wx$5u(L;7>M|oe+HTgS$DZ!ANs`&(&EZ$l@i|YUra+zTuY*Opef{lhziq)qSm4X>FZk%~$6E z$lpI<7^vJ#smNf*+#v)3;`stQ~&T%dPjsgijn4e^&U` zDdIvm{nn%Q6-iY4zbs=VSmD0euQ(zo#EmQ-n9xMrfQXNjJv_6?CGB{RoXdagfeN^wPz)d(PwCBQh(;*AoEdo2$___RnLft z**d?$S3(OuDy1e3StvOBUGfqfh~8yLAEh$wG+>S)tciMji`=pnMJSv_tYdCu>4voB z)kP+{8(AbmGL1KgiOtIHpjepwhH5tFaFck#<(9}*X~*R>ljT^sB`F^gU>Nlh*GDK4 z@TqrIQgcNmeZXru-XrrQ*AF)q(kMzqzeruiQSF6LxB{B03zz5CNysz(1oijGsF`_S zuBvYKQaR+_rTQKb^GBRsz!&g)IW`WB-hfP(kG0^hGM9wm6*%pPNgG8V5&QvJMcGK` zE;ErvdK@}5rMrz~sdc_u{{0N-9xXhD%bQwgYXnn;WJ;all+u$(c%oWiJRqq;&bY>W z6;O0XOR0y2s>LlyV&=u-`b`r)BE`KC0Q{?f6nv z+=1iJ6^jIkODK^tkrA)b@TQW?>x2PJgr7e^O!Fbs8Tq-mu>m!n$vO>`6Mi|`Zu#QW z+JmR6^7gCyJ4&v7l&}()Mv}|ZxVdP&$}PSEocFk#XndRz>?rRk;&0P~PWkv=&S1bD z9xsQfFOh%?znF`M=zEV8$?r%#K6N?HNt7q7dwG1Zr)G`0*%rA&Ge?@08=Om*jGtf3 z$w$cJC5lW#b4<(mUGfWi$EB5GEU&VepqG~K-GJm`@Ka7bS2p^awn^HxqtNg)y;1Rw z{7om%&$iufnWuY`NC}f7I%dMLE=%88#Md6#8a4RI`=iBXZAhm}jeH%s!)93W+DS-l zq-ko38lvYM91E4f?gQoF{8rfSQuBXfmqR_tSSmv)zDXr;LAavUR=mS;tboiBjj$=E z{3%5zO=2_PDNjIVQ--RJICu`>=dgv2Eu1``il<$4w}{{C`jksB}0r- z;v7;VoQHH<)pca{1RNrR+oy*&Y7sUN>l}kY{vKN@jQfqrQB^^)4AX!g1=ppyMN_8-AMXMmA#x?`yPJjwblJb*7|lof&O*7 z;k`I(i*=-?#lPBaELpe?z-d(EKOSZ7;lQ9o_7)m$iq_ zh9l3LCr#u1(at?cJ*%QKboVxO)fz6WmrIxaDELTeKMednkpRa?Wl7r|e8Gor`|OJG zjhk*qqpm*@Ut?XcwccwBo0CmrxdU+Z5dYr0*|k*VF-UW{E?%2mJG$2*6! zDF^YY!_;kAoOwNURuZQ#i97x0b?_SPt^8$iYySW&?yTGX`i+4fqZ;<@Z${H~yKl2< z)=*wW*h-lyeL?CE(!PE8Q*jlSj_fD6nIX4G=JO0QtAE|X&`~V zSue=Lxc>mAW3c}KX!GgoS=OZ~R8A&%{2f}j&)qJH@3GH(OVYeC;oGLQ(XOu~zs@AK z-X)43V#H^6`yl(8^Vf~$;lFhs_eb6}bISnk87zN@_2!!RMJ(L~bwP5gUgx<=i>FOS zq?@r-k~?_vtI6PclSD8Ocgcex{{Y8*sqmvn-gAt0LH*HF?e?o|xYJGE#)gv)gqtok z`>jQlUkhnr2oB#_ScL=W&%Jhb{x{L|n^sQ__(lk01O}SsRV+`r0f|42d9~vH;GaeZ z^{49ki`wX^Yi{N_X1FrDfz<+mkETswIts0?uiyF{mGJc2a;bK^T9ZSv!Bwu_g{+b?nL*u65WRTv&iMo>(JHRGg3>fsV~Vf>FD22e`>#ZZ!Gqb zMGT%>k=z0gvCU};aicGFSg&D5bni_ZTW$w~xO?@d+uRj#f=cvd&N3>)*@)1rw-F`4 z;iF(iKOU7rKr_kthjCr1(mdJoLsQoLIu-mgVJe)ezv?fRU#~;qMJV2tyK);w{_g2gXeRkk~I`HJ$s^YtjHF=|dBbV^ru9~f? zq@*qCATBxwAKo9GZ23ANzdV3 z6{w{q;C54|FJ`33;8W&_rBjp02e9o=zFFhb-b)>>(R{%eXL9!+TCsNPFpg-)T&oX4 zDwMjERv)~QWn6y`Qhy4XaJ8D;Q>o3XIeWhmT+IVUVu?cx61mPQc)UXdmNDDQ5ro83 zWyTSp0~N0F%tziTyquohxc9ED*YM}^u1n#ip_1nI<$*q2OB$ZpW0U#{?JlA$fd^MR zbLcyt%lX$1DJ4EtvN~|}9HY$4+hxi$r>w2J@aR8Elgkg4BZI-KW-M?90N?>lG55uC zx2d{%8P*G%Nb}WlpOM8_xsgBzYNTi~K>bNHwy|w9ulHqd*PrW9>JgbFiV_HohUY%O z@G82F4#=X2-)ElT#u`izJr^Sat_|t9M&U>&f-*l5Mxcc)XI5RMQ>UkTR^nAT;r?I8 zxAm&M&7#)KTPwzj;7bS)-9mC>U>$y=Jy+P*d!#mlui8m1-k)g=)GNAh7jGZl1a|&a z=hH$Y+CvqQc}E?;#8TVL#JZfvC{nHg>Zh;OO+@3(swSiqw7r>H?(EBbD_O=Owk%l? zf=Z|GjGpJMRZHpJu0|sZ69peHw>|3n!{x&?xZSZ@R>z>{`~_opY@3sMl5)g{KaN4I z(~m2cW2v=x#`~W~f$dHMnw4TS^@#VbYac7jL^3JZ80%7be$^ezCB3|}&UVETmv+W* z2PTt3=DvtztdYjgBdSKDEX;5edXru~<6jU-tZEWP6odOZ7Q{-8m4EinueYG2@sEmI zUz#|fj!0~yZ;}$(GBL&rC?9*#dF$&(3Nujis1T?{mxaJr4f>T$^o-U%3YlaQ^`6)A9Zz>_1AM z#@cjxCB>$h2Ih%j6SS-_(@04KpFjY>9kX88w(A^g9B2^~U@D9O^cCX26y|f|3#5~T ziYSqP-P^eSq}9@wJgl}crHOT?`(bsO~m0EvXj@SDoJ~FvMaM zrDRtNPQ_Re8gPf$)(GWw3c*bqJu29Sm&r8jPqZm*qitPiJK~ebK9pEJp-?R-TDTzg zrSd(gSUsXD1*e6pK0&95O(uwS3hKBuB8spfr>r$C8A_oFij_r5u+)nlDjG9$L~1co z0Z$Q{c#Qf|X^`YGY2uzErv$0xWVs9!;ntob$4Xx=mnl5MG0j$jExN7Txcl)$GxRN2 zf)Uz*796*70HVRnAf>16G`lHsis)b&r5sbjns8G`Aae{HQq%TQgrPuJ8Y#k@5}p#N zKvx(AI8%ZecFLszTxb;FDZz0|wzNaL-O zAS($`Dery_f4v3VtUmDssehp8KNIO)cB|q$OG!KEflxlcHTwihY`9f0F<_Q}9G=CQ7%n(B9+=4mIL`FUkx%->RLp{Cu>r*!Motg0#6 z3#WfmJ(j8M`%IjFs6+n%eHybNH*y%EIEWve{eG1&h$4lJ2?GIDMoB$@_a?R2>%TMd zHar>O)8Y+L(pF@$w@~xC@J@OlJ&DI&!nM96=(={6nse#avD%ksjn*-Mz%D^P{{Hpo zJ`m8qusl5#yrD(hr_Q(|`{Z=bpco&8a98W&Z$nsOyn=mT*hh5D(%%#8$+y?uJ2*s%h31(B4CD4a$~^O`))G ze>&^t%;73g4~?lHWd?j~}Hd;;2+txyI>MguT*De%38VPCA8yERPWR@zk%sp&!b* z1LpI>*G_cVv~n(HzgQcQwjf!b+XsXA*E?{_zY!?_^aSR*sL4NvRB>YB`MIT|J$vB< zPj}$U=v)F)^_P!Ah~MK(_`iI%T4lDLqj~8TvNArV zA^sKT9}_hpt9Z{+l0IUA{>u*^!yg~3Zag6B0X*(a4ex1+ae~_!1MTxM`wEGSgNZ?r5j>j2e`k&IRJ-UV90HA(ASDjJwNwTT? zu}H*{ECx6PfOsbvHJzhPcYR3k<@i6oQp<`S{}2Vd0x04mC(v~E>OoRDnueQPq!s5kfC zQ~H{&6ise`oNhsaI~;I-I=y`f^R86qJLDg!s&+t|C=dGroL{HO<&K=7jJnnTNU74;cZF~P`;XFEr!^*`ZH zxX>;RnQMIr^I?)Dm=!-fK#r%>RCXRBOFL6> z?qVEMgjHt(lu={ldD)Y#>K2+Nm2s$Q5(Kt|a^9?aDEB9d^QiQn5qRqU3!PKW)3i1v z(lu;+p!5sXnEwEIhB4B;M*B>&)Frli*b;GW{$xoY$_MP*dJ;Px)pKvHCXu}?SFw%Y zz30{R^#1@e3d_T~U4gf2JwDziw?iCHuohJ(CzITsN$Xe4JoKxCb4W#I(Tl4oJGM}0 zMKHrx%G6|3G*X)=`2dhTO?fYbbaCRZ9qQWk%7)YJuG`8TM3OHEK8h7v>P346=$Gtw zA7xP29$R^8P62JF13z3=cZRfRGz|*NOtt1ac*2*)43E{A{Z4A3B?!Le)bS1xmA85p ze39I9N+9EjMMa)OAdQynRN&z(OzVvbnn1^7c*gYyzxTNTL z6uCmT%CM1qiNz+8y zltstMAMXhD$4}O~9Mugv6^&iTR^#xiwU!lr?)}YcPo6`wQC!B;K_qJB3$ES6sLxz` z)Rb3IiI{Yhk{IpemD0{N2)6JO8tokcBj!Jt6?)Rv-qH~jtTDqF=&`6#`c&AZ#XGh) zCi;og^{*lLiQ@*;OuAN+AzJ`;%`%>6J=7oW{{TOwbYBsCOXNW=lc!1h_Zw~{Q~s@S z_W}O#@8~PZZk-?jN|NM!k)X>r(0Y5;)alz+d-+aWn)=0Mr$zez0Fg#jR6@)`s2rZc zvfN30#bL~L`NKIJx3~WQTl1|pvzFz<-VhXWu&L?wHGfXh?zJh!wwr4A5{@>+IA5vg z2iCXP`WZ^<@^(fbg&~V-fT*J+=O2kR=^qWe9U*wNy-qV4ugz%#j!DP*#vjOjKA7k{ zCGh487mo8?G2GoL43_K6QIW_e`{aH?yQx<_YYLOTi12awv}TH54y-^6lwBBO-h5+aD z%_>&xUQJdqn~k-%>T`lT@$1D$rYRP%kU3xIYe6IAeQG^A6XgU0C(UI8-*s&*V$ttE zisr&wi1*EK`{zG;L%>n!2Vq#+wxb+SNYOD>QIjSI=ns0+zp>P0W9M5-fzSXjD~R!Q zlEZNwlOYd*BPUan&{q~42Dz^{f5=m>7{&6lp1-=5>SFS{J0H8a=K`4xt4OR>kiSx- z;F_}@opR$QJ)_l*D|1br$4ZC&PoHwjhj|zPJ%IH7b?VNiENumI%l0l$nrEndB)GNE zJOSdZOU_A6n;FWh4b8Fz!2_=>a6Xmc_O2FDCER~#P(hhXV|hP#gV^Mgn$fwqwvh*w z7nL(^61vF5NTlR0++YFe(DgM0aKgzVBYpgS9M*KGs%~@sZ}?-5of}n@ufE2d8WTrx zZ+oQNE!ClLz%kh(jPeNRNbirzwPghf3<&zxMxGwjc~MCsMfPa{*YE4y1TGlx&uB33=B#&`Cxfc>PNbeZzKl=51!nQAa;wT}Je|G`%e6H5!HVaitZXFS;@c=;~4e#_7#TOQTTaxXQ*78>mG_q(p%HnuFAFN;JCpM1+NCu#`AzA~w60?Kx_eaCuA$SUX>A~Fkd{1>Kqu>h zarjn!jB4AOXDbAJ$oS-*$~{>6R(O!e(X$+}1<4)B{{Z#Vp7KVCZR2dBv2eYE9tl3D z99O9tc8@AL<5QJ#n|Ipv)V676CU~rr{_X@kpJGQ}r$JC@wsYz?NeoNL=Wk?RR;aXn zDtqZ$%Q32t^|v#yM2vfr{D(hIwccs7=sHcO+3mF(SCI20g~2X;{k;WaHmR#cYHF(T ztr6|u(}Adg;+ze0pBl+QrOij0Gg3(6X@t;CG@8wT6N-(ED>X(nr8Q<%ryerJ~~r;-*HuZ+K9=5MMIfN1@AJCHmLc&^m&BT^AC`_ z=F*8hYMQyH2Q;~d%3Jd&^D3_IdT?rd!sRUQrQB)&d8etWOjae`PYqDh#aadn-( zyDdDFl0zi@p@?pC_zs_qYN2q7a(0TjqF3cP`qvZUzZUFAv(elaKP%jhLi&XDKK&_g z&bzOIiEP%khxiL@2mRyJ{#3SJ2UCN8c2D~djDDuIQH*tGejb$yFP{+aFTy&d{#xG5!y9tb&UORu&nCTdPSG^oJchKijbtD4(T3*y&1o7=qUd(j z&m_ItQTeli(f%Ci@r0XFxqH$^;F0{1AIp+I8trWC?d+|@HgH7*L!w5ZN9kTsscU+N z!=D(-YD3)kcJP~sZOO@rN%{P<*sCAA(1J0F^?fe>*HqKszSHJe?PpNQBKIHA`%;o; z207v+qf)H7qb;9LPbNrGqh$80L}r-6v$4XRiW0^!Ysda3i+Q|6uWZ5OScG%!=olP< z^}*-xuH)htisI1iUf$i*UNYsR>L5eLd$j5QNy)ftF`n?zn`J!B0p+%lUv%{quj_6HJH0`lZ@x3TnUg4I@Z62 zZA0n>$^s)o+>YmgT{CZ$v+1i%Mh;K0i>vsr%w|nK0Ke_a$^QVpNA<2U zJDv9BnEwDu_IsEk-psL}b{H%a1NqmJK`QDVDAuncC83t}Ax}cFfI5A1SkZbn*x|!h zgOY?Hxsmo$D*zH{nD*rUf}oZG9IX(HEQoO9A9VU3dhhjXwzRT$h=DU5v6IjrQ}i6y z4JO!Q<0Nz$6t7$c_ON9kRTeGYG{rtZpiu?xeTGm>QTA;jYlH+ zcMC7@Kg$0AUdFT|ZLyVQ+&X{;PHP&qEU#;tBUj0MM{kJS58TWWe%nRyPNvO^Wj zh|01oMVzj1NdR%vf<uz!{OFB zEhZ(VwQZY^S3)w4`Em6Ivmla4m@wxZ*ZPXkYm|!i%TSAe13_|`$H~+Yp142E)zhq| zxfn(lc1K%b#z&~BX4R~$KjY@%RsR6EzcYS9xQmYzOm1WQ5*>)@#aErc9zj1(O3l1C z7gyIZ#C(Wkk)2e5xB_#|JJa@8-0r7@yR`oR1Gc~MgmOahTG_j2qs-e!>fj z8Uh(lp&8)S%3Q182+1Spg*+N1Dftz~d~0Mm#V$okdF#za@%LZKlP2Q{ zq|G-pgw||eO)^? zm6msLNxG_;z3HZKD!GTq%e#dkZ+fI>9<;`|9<=#}sk1=IifhZqTFy5DnD;*|9K-fT zm!0oP=Z{*+Hx!>}_o;FpvNg>9^qzfWnawAiP~;~_*84}jC!T$4GtM~cN+mwEE<*NZ zpP%nZ=bu{7Sr4r{eM4g8G-I2o_oo?2sxdbQnwNHHxg4dRFw%L3tAkDkf!LpMq}@?w zmo$RJp{b5}6a!3imZZTB-A)bYX{#HN!kUp_elkG)X(Ynva5$%mdcZreKT4HiL64U| zTBQa7n*iQt!RiGIHv*4FcI~mKJ}tvBqR>BZXK#G#;RXWb#A_75DS$Z zV^-S#0Ec7r;+l6FS9UKp7!cfp)EbHyB7kBDql|yDpjR;dH?fU~lG5>Acq&5VA5OJG z>*6K4XYBfQ!yi|XRDPMOQJL8czY{-(8hnoPG?}j|y7-l;bM|`+ME?MJ+5Z5-vt{_3 zuPOOq(}&g;Kl?R5X3mw8;+olg=d=J#JPcQgMe%c2iHDu0>GO{JWO&c=HPLAQ02j1d zhY{+Q*P44CH|-L~`L7^-MIOzV)yi>n)!Z-XskQM>!)@X}3`i|gcB5uZ#jqV*f%7N) z335KTuOawf<5uw2sC8hjNllc-6pX|NNg+_7nqS0V{dT>2yaK<7PbV8x0gWkP0xChp>M z`7g(x4>gYtYBPwer@PZPpCaZIG7XveLjjVc4i0$Zt!sqjvx7VEwN+OoTU(v3m91KM zjydmbE!xw!FujV)(-Z^GJ(z-8+m$6=JT4t3L zs?ik}GP0gLq4Q_)!ivPQ-{-cV>4#uMAdk8_X0TD@pzqY_z{h5{{=eW1*JtytiU$4M zV{hZ$u@W;YiAW%HLGA1K)|ByijAJ<|)z7cD_|u`amgeF(AVTv>!4XGtf6wGAI&xIv zqPiZV*H^Kp;Y)Rb$5PbfP9R;V$Jk`!^cBmpF`g~h+(Q%f;=My#(Z90%89lUe2~WlmKPjw!1o5CyR>K~Az4g`z+uscq5l9pS2U;0fv%{(cX4HF8nwJC?%fF) z=gY2E-S;2DwWB2V z-0q>v$#hhNVi5fC3=sqsH=#}DsG9@m)EW+L9$sC1CjHLdLRD2X&T)e`H>Qm z5uM53>N*iQJ6 zOwwD1mfJs8LFj#cwT_XP`G{o?@PCK+RCB4V4vJ7#?vJYhrvp`d(MO$JO`jFYTFnKj znVyXcsgIC^`@DLtenkNGf28KR6N|#ywvlSsh5q#FQ3I{Zuh4KCyF`E6*OEk z)NMDtSIr@(&RU8mGiI7)H37{gb5+b*fiaSp@^Mk-qh=)2<|#mz%%u-dW|SH(4g~w@ z;i|Ya^)#+z(O@+^HCI;Snw2ugkEz8@md*T3qu5bnCeTFq zZ?6?&G}VDSl4{ICFhD9krl~~Dv_cMgbM&cJCnN5W^{WHhig!M=`Apo1L=D`5`qYa8 zj-`!AqMip7`B5%IL};TigD+qC|Ws1Z~~qIp;n{y z3PIMN&}8(gu`Ph>QY}PW4|7fPPizWzLa}E!9MXA!d(~~!Zl}yXQpj?Bg*Y5kDtM<1 z_o_^miMLU@qx@+yezfiuCEY<_MMSwhDpXJodYWm8qZ?fC^`@|;rBe;YIGsBFBe<_K z@h6A14H&cBL}az?aUUu8{{VOK{Oj5eG++=x0D>?<83wk6MzlNdnU!2CvekAzY`IjB zWq>2srDjb6^Rh{hdq_|7uXxw|0i^0>q_y3r+#Yv80Y*OPc>J+meXM*o@fE3KX&t_y z5bp$=AO87o@ven5&!VB4;j8ZXU!I?d=W?X$owphGkpccyQRKN?<~W>st75v=@NbFU zK^o{9hU4lG56^ZhTGQb_iEdYP?WbA;+DXf>`h^(%YPr(f>YgtRPghYdozFE}sUVn4 zkSyoDF&}g;*C<~)$J$N^$9JU6=-I-Vyq8PcXCJ6)}M@gE2;QW^4<+h z+qk$^Xr#At%G*c>Ab>&SS2*A|-T;qrO14SJbnRd$8H@2ieW$kwn-fcuVwH*!=DcLv%r=& z*Ku51Y7ElFCB?L*OO=s;B~DbFW1LY_*~N2A@pC0XwNj$LO%7{R`03&sf<=|KnP$GB z8fN^-1N5#^>*9Zlt|Tn}AiG?ikt!e`fLiq1?|~Mqf6(>$(0WU1jrxKsgYgH3d?Vq> zq_@5CE#{|qhYfG0+b7C>8b&2S_ReUfDiZh?;BZD*dwY?;$mF%36Y3hu1=XaE@yFek zSQpJ-qo@ZS$2A7EtBq3APHA#)En)jBF+9kMa);^xApR9wRJgU0fAlM7w}f!0@|hg_ zlY#jGiqDWS1dsq9op;74xqGU}(zn&Fq6DPJb3`EA-!m!?;Th;VS9{@jr~boByQh*_ zt`6niNjpah2c~-dHRbk^Nj%FGIP)Z6i=R?(Kb?ELcCp*T94Up01PZ=@D8_5b&8jL< zj2BjVc~g~1IlYoHzR$F6>cr%qQfmo(VJ3;Kth!o3FpLy)G8R|QP^5A_Gxe)Fr--zB zl)SPRcaY_FrQNbCBOY?6KQ`a?mbW}T@TSi2MSA`qw!G5F-MZ2|76Yg(Nel1BYYH%p zIP>B<^f$)iAk(KEi|ymv4-n`#mXcZBTHU$?7(*mQ$;cbWPM^dDb5{`&HM4)yTz+8I zy{)8PBiG^6vZ>N~4~K{Av1hIK7Pe6a0-&s-3YBoEGosJ!_xZrkiDA zs!EOU%@sag3K1IthnPnkgV?mw+V=df(1;S^SVZitIG-J2pIhGYe+|x^CL({lVYvU?&OYMfm>sJ4FZau zTXp+o+%5MR*nS76^Qu;iWVajs`kjyU6|#3%Hd7u4LI|kZ1>L;~iOKuP(EUe4PFR{B z^?CKd!9sOypVsik{t4tF!|VDq6d-9}k)fh2s9?~bGO6-n*h z23b^zBT^g8UYs2B>0M3Y#d!&q!U*lIm*zI>_Z(xLzK6YH$9e?HB)1u0er0TD)DiTp zY0gc1rBalwbalnEh8@O#I?cV(EpC{&Un*1lNHL$N?^9WsUfwws!y_mlH&N|Y)MvLf zl9ic1ylkH46 ztuL~~F_2Hx(}ZZhbrgOTYAk-ybTYy-94fK=DrL8n^-#Z4ioZ$TpD8k^%IRo-iO1k7 zcT_UQgDnpxQ7h)KP?{#EJ;hqAq@wWN7U@+Cp7ktEfu81s!o}qv3OCdWOJf5yGA26m ze@f91$0;m$sgVHd%`j8NQbZDCIHVnER-8xaR*AS!DMv~(fz4IGc%&`qQI{v!R!@mF z>rW49Z+m)JjO~sj`|`hKQT=)W){EanI8&8LD8*f~PUhkpOL-@{nIVM+T1glxsP`tk z=fqzZG|MgVXqNA(N;*tWmk2*o%MYN%d7q0sN2z$0>&?_<{lc8ZYZ?92e?k0B{?Ys~ zT(tA$%0N8F9Z5eb{cEN)znJ=5E=LF@EJM5OU-3_fFSY$aul0+7@?&Bujj0;{0Cg9) z>Q8>vg5l;o?GkbRy>?G`CH7B)bt-gP+bzo%2SMtvGgDPdfh7?>Vkwh60%z& zn*k!o>M($8Ks#5z{2SIR?K~%8r`^gRo_TI1gUsP&Q6b&5`i|h&h}_xDXz2~bywE<- z;Uz+cY3SHJjdyzd`hJ)2yTR5MN*em?wbCE?=Nl4Pn0E(qj32LRipf+;CzXt&8k~@m z_@4g&c}L>E#OsY_;(aT__bmpJhhxtZ6??3EjzW3?*Qw*Lk-HK$s2CrRt?hqI*_(@D zwlaTsgZO>NwNcVEtIb;aD=jkGOPi@a>_|C2=g@kS#dOh7rwuePcx8uNn|YavoyJM( zO+_&1qrG}Jjc+vA^EzCm+;GIFuT4iXf|`=zo;;I`jRE6;JdVtU|KwCX9Y zWwFhq!|MN}fxdnP&(tU$TZgVDuTl zC-AJRB$~s*S9kW{gL!fG7LXhiP@Z7}-Lu!wS33{gD%d#Sk6P!I6;`jcmrW7V3XU*z zq1S)%C%dt@vAdE9;+6}D&K?<%t1r|Vx29_Mwh26Tw=%$&39@L_u(GdkM?>}N?_Qdo zDbh9H0S55}owfeGZ;M1}h8QRr6BZnSj=rQ~tLeW9ZuJccJH@?QS>^eX-sUoLnBbB* z1og%`8i`_}lU0?B<0TdE=yjh8buBLE!~R8&$*3XoF5`X~oBPAnF~IciRD4Tq<+h^` z9hukP_=RyYcr(S`8N5r|TWKBPJC=Jl665gTk?oFat+eq3ejtrnc)rc4#J*kCvnf(N z90ShNpTfL+WfY&brtXgX3reF)W?s`6Jn^{bQ+Me}aUa@c-hb5&pY4D3syziaBr&%; zQKN5sas4Y+b@t#_3{~Bp$3`vQYtYD%0`Q|4rmN)O_5O8cb>^wayw^*o8LJUOtf{>= zAi0ZdnH?ISXv2-CzaO1j-Wf_s)3Nlb?UX$A6>z(cEVnMKBK_#>#I^Y$O!X==R^yW$ z>a6S%W>x6CQ>@97*%+x@W~ib`groR|58+uQ3|HWEOM#F082!JzOan!F3tcL|b7&!#-RP|jwxwr~44(0>Ycl<_cTh0{MaOy$i8q%HP zD~g^Wsa!PAmdYX6XCIwiKndwpAVCTuXQf<+k||VLu~nD8>~z7Y!K#W~#@$C9NVMd&llY3S>sBMRT>Q>Y(~5@{OOiw@QZF@XI3r)-&(!9uAOr4z zK9so$b6pBc6Sv()KZQ(|(jL1<)YY+0T0NRV=VS|M{pTm>Dn+)8e+fTRQ+A~k)I{dS z1XcU0qwt`N)WRks)9X$!5APq!pCBoe$fmHXZ2|rg57&x;(U*o4`B|cx=s-qkn5oLs zcF|(gh)ATzH9wb15}HGE847&a^s5TJDPc~$RO+>&iG-v^7Nu0Ds?>_LY9=j=RN|#o zrBTI88sy@gjN1s}&t8=-z`X@Mco^+NcA~~@iHdNhmsRRV(vfA)AbxZRm_`_U!jX!{ z!6Kt9&D7Iy2qJ*6<1sx3KD5U>#v7WCIO3NynN}LH@DRbwqM$x(6gmW-6sC07hxu%McrIDqBbC(u;xJ6KgL=j8^p5->jT z&$Uzp0fEI`9D!Oz8Of8O-~q)*Dh2IU5N5STEP9HSMIx<8Dv=F}qNDqkW zi(E+@FCFSV+2=IO=7Yse%Sa@ZB8}vcf}#S<$DjkPco&Uz**rn3z0;Dmv4WQIo&v}H zKsgKc^m z-xcpHHLn%h&1Zcawvt+;QcR7z%K_VW;sHOUa2_(&&xm!ou2gw;$g2gqANgeh3?lyk zGJV+AywbOxC6Xyd1~?nAe+r7)^4i-_g7IUuYlvHV{iYqup4n53{{W3uHORKTj(K5X zp%oYKt7=L#?NZl4vA)!7ri$L@DGZV?`rrp#br~5WJ#oc*AHn6(hlRsw7I9nMsq*g| zJDx@#b&DQKka7n>)3tE=r^H+BXG)gGRMT|J$mAF-3#JI@zzpDy*fo>z=U@K-gm=Yu z;%CL3(O6~&jtSwv;4E|WCb?_Ibt$yfnazo#R=yqkMQJUq*ZTa-PmA}Bd+`rhb~#w2 zSP*(DApWG+6B2Qpa>q5&_}VL*uNCWZEE6{C>9AD^1aBY^et=efnWbJ|U)xzh3#8W) zEJ$5SfKPHyVafa}(5EFBBy-cJ%N2fz^^XhqNwvR%muVbd>6aHTe{2ZqWBF7M_mxQe zYsCufaKkwF{VVHxi`_H9-W;@teqgqVV1hItyro7s=kX-)GhaFQy25*#yWM6RF&&h% z{`5qr%Z5kiZhiXwPi%_f!QvdJE9~BfHW|4#-o)PvBD1*hwwrCKDSLU`uEKs&;1*5Z zqa&x%zL}65w{aj45)>qWmO$Z917>}wW~;p5$~D5*c^UlyoWwsrQwwMlY-dg zbfL2SeI3ci)N}gQwCmQfWV$JMXNn*O^5IzY_Tq`Phm^9c)4;ZAZ=&96w~QgTlcbNp z^4C8%(2{ZMiqfpPDe80LB%ubv^&_#jmg3`qoS$>hDEvRIans#A(=?8LW<3XQYMaD* z+iKT@#u+V8krFpw_m8>#KRVR#uZPn16}-L#!pHY)5*M&JbvzM$ezvoL-FhR)h%u#Z#-|%NWZABN;++< zrFYv$@{quRj32_Xd`sbH)GW|gN{K9NSS-C8jAK2&Dy%+X2~BfoVL4kv&jh~pBFj)- z+T7S(HMQ(71nbopbsnSCdx~Udn)a2Nx+OD8IWvxG^bN?YsEue_o<(Ib^BRc+?b0#_ zzZGUXIX{V!ew@{v)b&4=XJe7gjE>4N_t~5Dt5LxU^g;OZO$|;4iz7DMEJi^4xF11^ zl}%Pw=A~ApVi`C&rwWByqz0j(Se;EhO;=KCRW&vwoEmzbDkVPkAf?J7>zs^rt8qpY zbAr_svSgM&g<1lsM9xwSQHpq4a9VaIUUjil1+_F4}e}OwN)GhmJ)z%dICs z%0a5dG1iwUYNg8CJ*e4J?V}V}u5qz08x=5LYG54Hia`}E~8I3IKq z`U+%jSOTSul|d{(?ODw;w|spnNDl=2&?g-W%{U))XX{YBtjDh&)f+GauQbqjqU6|k zJk@}30IIp0(94<-p6+CftG9SQFs8w7j08_!u z7A3yKiGVOL2emv?6jZ3SNfOxg8LMy{t~-i>7N?95aw?KClPsvsPK(V)9th&5QI55( zj2k2zQkM(XqcRRc{&dXKxU5LdTdg(D20dw|fE@l+5p0@GjUoA_yo!if$O@w*`U+uc z!10yohf6l-aV5dpas9#9{3wcYb~mF-+RZ_AJj=zGvuhfy#EMFZkKX?Po^cKU9_RX# zSxIVLqPDe(nT{4X&}5&d_}5QmqtB_`G;m>1b0n?zSNu=4cKS}0XQW0&tYFIDerDy{ z@$5Z?bycq#OO*Pm*xFb~C`VUqjBf|{PCX@-`%&92p^uSAD+klnz58~qYvNVh+TN&| zb%+KlIbwm|8O-xIKnJeSSmW6GS99VWN%Z|PNiEmRyK*A7h<_Z7z#mTM*jFc}X-f}_ z^lc?ioBf*%n!Wtp-sVB&L{H)7W9TcIl-#81Nb-KMJG@Nay!2jQ*XBD{@Eq84q+BGZ zya?wzPaciX{x!zxJ|EUCU4+_Q;OByonF0J)HSS>J0C9?PvuA>GeJUf1n)tOeqnlQO zw5-nowD88eesgQ2-EBX|GWkG%-&jATCavKOV@k7}8nIZoGS-t%;<(j;f=?ae`Bp&|&{d(tEyx@h(M0&9tx6pQ`Sy)SZ zyuy5|Ve*C~;Pc4?y>v>SS0kpfwy52nV;>S-+r#KP{-%(}E2lRym0{Chy3+mz;=pp#@XZwtZ7j1O)rUf0C>zMEww zjD=*=+!cFyVp$<@dgKwFf8MPB0J29QDuW2QRs6X>pYo~fiJmxtJ6Mp1jNs=7j`eND zEs9js{yj`7w7YADcCw$!W0J8qA#>0U_y-v4Uq;2PnRM%Bju%PZCEO)lyG{mpt|!7; z28|S-Y`2~(+r;3VyL_haggk@pd9JO~y?pL#nK`vio%HI?TGXl3lDgQVd*;<+gVFsK@9lVb-h57Hh}`kcp-IVZ1fgWo)kYuSZ6 z%bonZk2OjV+Rg9#diQS=q$7MAxH4~s}-oz&+MscuI& zK9%fFre#Qwl=BD9dN5paJ&EaFMt1qRBYxtWvjmyukfoXj+Hlgh+*9f9ewBI)Ne(>e zUx(_axQGId^gjlmRTdb zyoku`_yGtRB;%3On&v!5;EVkl7P&`DyCvnMLA8*7w5PYY{Hy42b!f&skb3!(POKJ} zIhaRE(6{SVV@kOK;MZK4yE+WisN7Y2^HL|>6zp>{aMbYC64S*i2$5LS%4!uAG76g$ zB30{Btww^TMWoRUiaONFDWQ3(k!e_#$0(^(QYfiZQOZMQn|1xzs|vLoAL_@oOe)k& zThwqA;3=Tffuod>LeYvdMrg2HLsg|1k-oKLo;l!E3GNU`*!hloRI;OS-RT&G8DoL( zRbJuG-NOAU7Gh3G$@i%>Q7t{f54)EBRSR55e(BmhsvOf#T4mW2i8Iuk)5B-IRn0DF z6^mQ3)QWUdD0~j}Pc&}FB7kVoCnuT%Rd}Y}yyJIqPA%_27AD=rOs|oe&uKZONy3~H z!Js)y#!6w6-mA2gUTN|2gUu$!qjFhh%N}^?Q8cw*c_#yt?Ndh!9%MN79cl|o$ODpa z0VmR)@nH{`*v}XhDg{CEfTO)ZB%9lV@{W|65@3KJ!hi)l8e-IlD6sB0RH`~sBGmD% z2@>6fMdqhPp%=YQi&mm!kBs7WF*S8LBegwHr98Y-tj+`}16ur5u{Ru*n(y)PE-K z%A=|LPHSsZycV`I&dszUlb=e#xA6vpr`aieV#DSenY`e4A8%UHoViny-1IQ9lrK0d zy^*;TaazK#z=305)cT)#MtbA!{vr5&79nnDpWYjGVfpkmrJ?wPP4NoIx>e$|%DHIV z6p;t6)6e75xus60#Uwdl>cw+TEf&;AaepSEbm465Rn|6cfPwqR{Wg!G^{QS1j!Eq= zb=#yVajebughm|4ZU)$w+vWL)^FaH32aKDXQ*8EeV zXe38}eGF270^7z6k^#_stH`UfakN&i^8WyW%;cq2r4_NioSrMre0SpMS*6o-iA-^V zQhSs?F+I@_Z$f`BTCc8rO|zQLcr>eP<&nnUK1EatJCF&^aa;t~o^k}YQjB}II2FAN zJ)bp1dl`OQ)AqHN+ae2z7B}+IcS?EKKbfkA5?DOVy~jX4>iq|L(2m?j0!FUR=hH0b z`u!`T)3imgj9lMr6OKZ$`C|V77XDS)R;+2QPhO>1(^sDTj4NFrvU!)PLXpHrxc>la z{69LibjcFsh*cjdfImPhQgbAk@)rRA0Lw`SAAstAN~r~elU*cs@x8^=pC~xXA7R)E z<8>Uhk;Lk`yR$YMIrSTu;V6D{g@hhYe6jj-?MZUN7#)*o1BBbqlfcDxn(c&M8_`nL zSV^j10w$GuBtxpNu{as;&2cmQ_i)As2t3yQL;Prj`Mm{7r#fwHA}5v-G5jm}^H3-e z+`1pTDBeE3$MUOKCg1=GB{%?bd9J@j@GRHM6~?P1ma(e`SWpizkM^_oLGLi~V?1%5yi*%j);vEl!LQqy;r5_RpO<8o@IUj-KSA$<4PNQm2y8KQk)%TxR z{zfjHe`l%NnXG16RB*t3wOE%R~%z6MaO;xzDSh>59Mt|p; z4bT1q@viz+8LzZS>SWs8?1b9fg7%DZSG;HY$>>L?darkFBx@oz-h?U6H+m86SDr;l zLctoq80|6>x%uyt)9@9aAZ3w+ncfKvlare5QtFC|)wQL}cCwswP~S$auM7Bp?eetu z%EH+jXikPh_4E}Ua1D1lL~9P60N?=_Vt%6}{{T9?R$*2&`D42=trZ2KdeRhzHI5k7 zBVGciz!ht1J0h?LC%O+t2za#VOR->28{{UWwG5z7n{(Zk1d`rbyNcSln&1o2%H6}{{R#3`8 z2cZW!t4N_nTY>6$s#f-^B8eg<2|tT(O!owIH9CV6ZoPy^zw^~b;69_ZZ4-)e>|BaS zNdQY3Kko`=wW8YVdUM)d?()eDu8o3>Ixy||@mAr631bYY8!6~Qf(=a_v`BLr>_6-r zew{0#ozuEF=RI^hCtcAlbUj6_F2;X~IY9YjPwx-vJAPGOA%kAq;>`&)-67z>7cuBV)} zhQU^(RN|#X&N!)7KWZ#y*&3xvh-y_#cBxfGD-h%{6PleAPz5_QSeC_6QmsY}JQ^$_ zMX3R(LsR!rVoP@Kf=91PvJGZ~=~FG_V}@bB+r0!h+`J7gew9V8N#Q^q=bDVjTkjHR zCzQ}>(09r76$@N3`=BjV-S0@!1sP+3QpTc5EQbWK$@i*6`sR{ZOo!NXrWUAXu~r|N zOw%_~ZlqZ9MIki8)Y8-plXW3)dWD>N)NLT3X%;u)nDW(QH@!mhP*RC(%vX?bX~OvQ zarlbNX}#%&UbL=Pvo+1+WPR__qI<+2#h=2myv&>qPqkQz-PmQ$#r99*3<}i54;P4tt*UChAC+Zib3^XfTCGzImX|ihAVw3ZSQ&c;cPN(|nwXD)f^=}eu;T0(eU1u#=o^Glivug+pVGMd^_ND~+}d4*yR(^=Dec&tl{~WhdiLrM6{UHr zYS&BUUTW8}AsI1=il`p=?Ovhqx5IY&Zi^lK(5bw?T$1aOk$(yd^vLA>YtZ(tlDzdj z3|!|<4ppr0rIF^^myY#aLFb+p7T0$WtP{^3Ln;n-$NkXVNgVbbwP(X#2DsKX{{Y1A zN`gs8m||JH*^YV3D8bLvlU(inu!8#OQa>z5G^yo|${mJ34nHbIMT-(I%FFYsuLKd! zK^+Zj(owZN38jMNUgNX-&dwhKUR*I*!arYHV`;KoH<<)J zZhAg)2hi2O5Jq*2*mP7U?D!Mju>R(LRQj>~1#iZw9BCYCsE7ipuSEl}t_eA5DLb}# z)hkNMa(9zCh`cW>t(&RRCG=03kMymbCq=f?F6NrtHt7*!8=E8nl26o=&#)Dtnn#mr zGk$frk@*(n5=(!)yHO$%%F{hujkF|f@99FibOjeT3 z{AGCeWB&l_q|@}tCJSq9rR7M8R2^K7a6Qd;L8!p>;M7uG5noNyZnZ61-rmI-rC`9E z;6^w*iR=Y?K9yr7j-M60_fp-+gPCPKll~u>_o)0Q;pp@&I3WSACBsi3?ti*HhxnS= zX#W7b!GBZvSBs6r`)A6wM-6OGJha%L$xyob){6+2qBEcNjz5(|&yTwtOaA}?&3Vo! zQKfLJ|c(I-kW95IF>KNq8a&1=O$^eAU|ckf+YP9)q~S ztJg90rgRbp3Nn6Bgslx)F$nEN+`RNS3BVCg|<^ z-d`U0G?6V#1}-6QP*DE>Kj~aiN0m}V+j1R4FGKoO=$AD`2bCuO0N`#L*!uqfL-AH5{>84XOQ~YTz|z`5NS5iOK%}9 zD0rtBDy%xG@5+;d?OpWap{@?2jdgCP9Q)_*KI%eh9pF=1UTSO>C*4hF#a3x*Hk;m)MJTes4i#07+l~m=m6&yL0~1_WFw6o+i-uk3$ETC_zTI-gH_okTlC#El2L< zi6q_KvIknVJnIAxGXg@4;B{lz53fqX@RHnGX{S!TO_vsJv|!{kXO&=kj-&9cmmB0w z-*G-*Jx_1Tn&O_byFA*_wN{(DxZO6?+Q#iJ4b1K4%)`4L-#|DYO1rwE4NJPBPnq4A z$+4#YjbJk2=(C_swYzI4opuqL1++yFZ6IL6Y`; zPC!CMn49S8`AJ(eeJ4t|e zQPD?1QsdmxH5{~w14$epi*?KQk%#gXLO{&Ln3Bh-HFegYk!v{}RMJ|MgeF-QH2chP zQC;nMj?cKiBK-&XHKVu5w=dD<1ShihH9^xAl$Di@>C2j2-3m^%UPZ{O(he%Kip8DK zk(n$FB!Lio%y21|sIs-}G4m5zI)BQc-m58y>wnm?EDstz#K-v@Me*-2TRpQGKa z{ggKe{A-pU-EQKv$`+61`^tAO)K{8#Yguh7ZEjG?hSZ^GhD|Kgr0c9^a(2{{DG}2PZ8@@WO+K3!2|eY zB0zsIYrchQb6m*hsg%`(z1b_G%_!+ip`B1=$WiZIqp5q!fU ziy2Bot>VTB9M#CrKrdADS~v%`~+pG3BX^B}DRKppslvmZCmMF;%3NqLOaB z)k!7EtlKt>38a@bfvrz9)xfc~%K!sO>G=B!(w0Ma)8mkcN&I*p)~0^!TP4SrR!O7j;(cb> z8AdnxjsE}v=lmJrsja$o6AyXy>;-dpS>z1Tl zlV=_#PnkAVWG8?*rnVycm@<0yA4<041CG7TR(0mEYQ|A_+@&ItNhc@N)DFJ2b=IJ9 z&1EEYLPZx^V#d6@nevyfs~ro=MXK@&#z$o~lCmi})FLqKcjwDdxzD%%0AHnBkW@2pn*qqqSo)t&!n3zi zrcNse)E@ipnV(U7xap-!kf#RJ%Q;{Ggt*)D-Qgmbf%XB}Xt#1;l$>FU|6C%cC zwviQx&pS!r4o?8^E5uObf_ooaS6`}lgzEkax3``5YBAlaJ~%9@HwXN9A6oOO(SM@ox6pL@=Cv&Cyrx%P3i2~tm2nC>BieNzEz>DmS#z9zHKh%xTye;&-)B@H zqTw5mJr8kHEIeb8?kmrfr6;L_ugtDfHv81B2Rv3|Ayy%{BZ4bV^3r&tG6`Np9Gsq3 zsCDbfuWv7>?Bd#$(>Ur+osN6SSey`}{hq&_L%TUAB>I|*y*oAZCzg^!`&F2@LGR5} z-Njl{!1_`N5(7(`W@&THAy|HC*{IDfXbTq5{DPG7F;K$%VAPwr>p=|>W{uSoJ_-8M z8bL^QWc%ncU~q9&8ft~6_oP=Ld8X%@qbHtmnATdJBy+Nv=KW2DtaC z4K_y=9{Q7I0_#tn^%;{jSA9jHmUw5so=GaK2Ofx zt<&wvHkX-)~m`01C67d8om~C^YOt*K$nJnr3N5D+qRKN{v^VnN-nX zF;=BTp;xvl#BubZ#5NJ7T8ckWOB{IZR-=!KEMqAINsiTW-3Cd=YGi6E#6Sa8V;MV= zs?xNAKD?hwh3Cf!$@QqS&U%wU7A1Esa^HZXG{9+dO2ZxvC^Z-~xugQhcpqAeG_tor zP&3kHBuLFsJea8DlisS!HA5~jC6ZpXQdzp-)Kbk=B$Vc%vv|OjLIsrR(?mhcbd7M>KB{8POWZBUgci6k;deCMa&1K1Rj`dnw z+;^neq;Sof4{$Nb6-MUdc0ATZ+J-yT8Slx@G$W!IR*ScHcqitp*VGD=%~83#$UN3$ z*9SdoSfj2q4x-;u z{5pL}uJnq@yVdkR4qC-)J>|W!M1fKjZO#Dy0AzA&nbf`{*``LFV?6$kF%hZ!IW>&w z%1rQFYT{?j7`q+I3a>jPakINBqViar0re)lqW9t+xiKOSvRg0vF>gPcAL(4Sx2)p_(hG5^Hx^B5{><=)=?>N@I`Cyea%m zt$-DEYt>PJ6gU76ZYhi6y?!>z>lbIf7^@G}XqI0mvpQp!)Ll{S?la9m>U!YfylQV6 z_=Z)%)ZKm3BvbsWGV55>uQD$63&}z145SapU{rr*P46RUV5%+I>$<+Trs=sCcSt1v z0G>(nIs6527yc=p`%<+qqg&a>GO=9coCY6wkK`+mi-W+$T#a(3x+&mk)4Sc9dmcm9 z7d!v1Qe-T@#o_y-r==Uf*EQu$`8G@gb_v58;>OnaJ1F-b3L`bp#Bd1F9*%xKR ztJz(L>TA=$D{~|is&hATj(MYXH$2gr`ZFFb#~(0OVXo8Gfp^}mY; z^r)WnbJsMB_Ds-uz3RM^;1W&;y-VGP%UY{5) zRaA3Q&1_DYb^%6BUWpbp!2D0GMG^?t1C!kP)PT^D64aM8xv29-X_I15-t>*gre>QY zqBPHb!`798#8)$I8yD{$r_fb4G}dBRl6lQEn$7BO1!Oges3c>9Q!%KVR5Wx#Nfc&d zjw?QPJl3?SlT@aNAFW3z-A<}8re@7incB7|gnCwW!U5K)BeoMv&5@5eHBwgQt;{(! zQbEmY17aQA`h6>;J}uSevyR3)*)1#)7BO#Xe5D`&0cIaF9y*iwS2jikHCTr0Tcet- zDAczyy^fyB-~*5VB;=n{@9SD|%eiZmw4A9KHMea(M_NrBlc#2AJ5^~LtvtR(K_RCU z5kwAgP_t&Fknn1`HL6C@Kurv*UN(*r;#5t?*4r+`X^{p#$z^IZr>LYW*nO$1c zj_gO~4R(w}091kxaa4&S^go?;@W=9iM>(%MBRn3J-09kcR{9mC z&D(s;gaCTEP=CU_Y|{+qIMj~sLsdRl*tw`($ER7DpA6aBiRyp-T-ME?N#aRjA)|HN ztUH5VVJ+0xE?##emoJXMp1;U`Rk7jydTlAT74xl0$&WZI?x*^6sd;OSHOl?tmZvjX z9+HvnAo}z8)wm+gRP=5?9@UeiYx-UDtZ`g~l=O~au%D)QKZSHwp(cqXiIt;axmX;6 zE1TI$FWyI)R&8j=QXmFTYVx*mB=WfE&dfg&YtuYYsYj&gZtNJm;i8Oz(e{!v`B#@i zzym!vuR{qARN1}~?Ku@QMrnnGG_`xC$rA3Q-OWN|rWtwWrJAUhQgWjQky3fe-3?{5 z!lP+vGSw@Z%_T!5>NAsBW=f5pJ?cwTi<8}w2u?lfo5)QunxZUdDO0el{M2mu&u@B0 zq>eY0u!>3j1p~4`>fmIl+v+(KLmZPFMx^`pAB|{Q+q5b}K6CsdrB0`4+6DmhtX*D7 zT6;dGs*;>rr>k8G@K~brDc;_lzxwrb8~^~o9fdR+P-|m}ruQTbP8ApwqpbqvB?g|R zq6Vc=lZpi5Nf^&sofLHy8jh7R3S`)Fikdaa=|U|}8dI?hM2j^tN7|*1I-OFPlVc-} ztRhg0ikU?gGm`}vseuYI#{<@)cU1cNR1D?LSp5YfHm*x7<&F~}d!Jg4nomklc%&9X z!KV(D9%(_%0wkp-qt61DJW>%LVmcE;J07N@-BG-h1&JO?uPnSCYAI&-s&h^6QrU5d zB-4A8N8POOMOD=oVEd10g`J_y{1yPb}Y-*yBGH!O-y-jLcppGyH zC%LN7Mj~7eSoJkxHtkBra(5>Nmo*k?!K#QP2A6e5x`1f`A#k9Rz^XFLWPJ1;1trwk zI~Snq^{VXH2Bn%tJwUf6khc`f(i2c>hZ9k=deFy;h1=edqC&G(XN2cIk+-(OQ#XR-3eVvaCx&Jnyr?-z`Im;mOeeVz9cx+swS(6pg;>0oGUl0Azlr0;zeI7UyXQ%-?aD zvcFu8quQ<5K(^jvmNHK%23cFHk<;i0U^uS2a)m|A(dSpB;OuH65Q-gxFc@M60Y6G> zwL|7p8S0Eu9Pd@-ZnQj=UEZ24L`Q0Y+LhX(W~(%?x#p&l;z?tL9kP(F#9qL4KZ*6K zxup$C$?7JHDAh8zrBhd_75JjYZ5KBJFnJZzcvr=DIx8d+gFc_0V*Vu0Qiu9}Sgt`@ zrbgzXP*PTAH7Q1-<&o-N5UwG=@XnukXCli3T!I~a(TCuDtAvTF8(aBfu(-1BO^ zm!DdeZx|K~xuo+ALx%0mE^1k{VoRDzK~Gg@I8aIUsVc(_BBMFN0!>_w&}TA{{^+Y9 z1shZVJp}|dQ;NtAWjl}eM@q5)Py&FUb^@Gfv>8cULTMNhr<@;JT7qkZh-Z?0D>|w& zk1UNSDXHF?)M8$sm&%*>Z~7l`?fk0VasdY*_Z81-7k1YmuPXg;4_|*!ed(GN^QHK; zk&7&u+x7ndA6h9zsMzVRhvrUcS)DfU7%3xh$ph)uo;p`Hx`;j|+Q;`mn{m(U`PWLK zwQ9#DS}vWh)Oyv3haXyn1zLr86pnckAgeL2YGi3vqfTj~CM;=IV_s<^TAdcH7|439 zOoEz%q%0I=jWa0=j31>&()M1yw8Mb?y7N%WHapcB=l7&(7!yrDTBS7k%|R^nQb~R48POOM zNi9NNsodNcnK8&Y$f+WKG=Q9w+r4Ga9&TQzQ=urqRJM$ra_kjGNv#`r#7pYOsi_w zih@R|X7Gs=&&6iW{F=Eb&q|{(&TBS$6k?G^Qb{!lQ<}8PP1#K&sm&xpvF4d7?GYDfKw1p^qn;X56M9cBgoq$Qp|r(t!orDsa9s=iY(IQ?x7Y*BTifh_6~P;#a{a)cIp~-4Bfpy0p7K| z7iayc;;Se&NFj_h!?F2(R0DzEsb9l2rB8AWPog%IeViQS(ChSF6H>K}WYu+Rn~8`S ziAwoueKU-==~|Ln6P_@jWRf~pM$jDXLGvEb7fl@}Lhzg{iN|tDl^{G`0oB&DosbRGvnGQXLXxiIuA0P_8xTqgBiV12*`p?K! zq*YOX02QXTu>s2NKJ@V#c18TD6VG!lkc`%o+eY8O0rebJN$s97k@GLFr2@KTW~Q2b zAru9M8jeWPL5D!Y-lZaw6f~IC*38Jh(bjNG4ix_YazVI$eQO5d$5615E(N@ez0 zK5@b1df<*aS84@w`k#pY%_A+GX#03FIXL_P>MH5p_D4-RwHj*IFm)TKF0aw_6Fj9&MWA_>}NImI5 z6pY&nS}-XMB3KhmX2mqMK`fZ0G>6G0RGMsesOO)9S@X~DNY*hXntr_13FjS21M#S4 zo2_GNkt2^WV;jNbj^eYaClz#d;i$%>)MV{)-PWXv+feUda7VY+q5Ed(Miqi%ob{~4 z1aMd7_Urjon}3}H4oKkFpE~p1A4N|tp%rGXSdom)o`7@}J)@ZA5+^w09;3ZO8g(5A zKc!Cyz+eUlYytJINmP@3*VOG)p&EY9+8S1qnO;KtbinkhSpa2-1ExvEQHDHWYa7LJ z$*WvhXqN8CC1G=QAnO!Lct29zJ;i!B8M@bux*s{2VWCQC!$i)fIHe6ylg$9vQ%9Cf znm2H2AZo4T{bE!8_xMs8S7J{$nEW4*bpHSvW@-@B?bQs~B0y>TvruN94JL+=^3>93 z#(L02OD-cA)Dl$eIH(@8XG|GhLCsc?deyfT1eC0FMrAfyZYpLK8LCA$ajrP3vaV{| z)C@9eiiuqlCbTW1sA5ifRoGV;szg+gGJ*%CFP8EgAS`{U-KmZ;D@1dXN2JXsGk)zo zI+IpD&m0l#iEuwtSyD3~`B{h1kyT{4oOGH``{>t9S~@9BN1>%M^PF?*U01?2R`FHR zzus#$+CGfA{*~tvPdV!>hyDd!2g3-by7B&yt2B!oZ1c`{l^#+dCp`4rQ;I9c+ESEz ziyK)>4>h)j&=OnWPro09Ql1^4vFN<#)84p09Q;*+AvKSM)ox|ML#Q$R+8&=E{xUs& z@7EZwG1ax5Usqh}x`oxku>Sy7(iKd4Y+M8QgI+B>s&zG!vOHWC2EBb=i_Gpkb>q8z zJbj-;cEE_1uC`A~RFom4ms8wWB^Y~;Rrr^DYpk}j zcoG4&!UtuD{{YWM=v@B*Pj9U{&T}oaPREj?KU&UM*X+v(=%4}kRMrO&g*}O`*iwxu zYMd5`a!JQdhM=+#P?yw3K52a0N2fEwC>fo=r`PS0YaAKq)a&0ZERu zToBArPsIdMxHB^H0FAu{6!rG1q*lza`H`~vipnC3n!()=kwz*_wB?NYQYgyTXEyq5 zn+Xpm$Pd@4{IgtFkn-}eNZ@o4p=^Ft=yU1u-Ab);H==#m{{V+Q$@Q!8AV3uqDvp6h z1!)QLo5Hkd#>-ZD`e;*4;d|Mng_daL6GRy>%%O0@9dLa;z3Zj$9rImjM&3s)C9w() ze)MPV{#=j3x+Oq*fI;dHdgnYpr#6w|o2y~|qF4-&`>0{Z;7Juur#xC_UhPFL=UE!n zloZ5V3YA7HG;mFlN5xEJRqNN%s3-8gMm8&60+rJktTC z6+|*j)5k$kjIfWKn9qu9Ns6x|fKmjmI%zofsx!~ll6#D2n#;PM zp0zC6Fu5f69eJ$jr>N$eIl-!LB}vm56Fj-kH4KMxk<%j;8G31Kel;?;Q+P%5d%KKO zA+fmRdSa$X0U^F%{WoWkO1laSDc(;kP6yCbv7(;9{x#!Oc5juRRYkeMIjb>Lv}_Ex z+l&?*eqydDRe0qmDS|RRdw*Zfk_dq0C?7#q*4bEPep8U#4h{}^70=9@9Z6XV(j}dw zmp1_6a7wQvl5na$$siANRrK3uht9aU+HY=HJj5J@$3zGFsyO=O_p7p4eX{P_W^N!2 zwGS#7}CtN^mu+b*1h^ z7NRsf;=#>Ak~gHZ!c4M~+^P;*i#?NEbDoK%I0vq3c&Y|@iSl@Up(o}Nx= zhM}WqkiQiKoYjZvRobPS#D#@MMNGn@BBtinBgREAr!^r29w|V{r*hH~HLFM}D8?#v z6=|7CTz6_?Q|YbJv`osyX}RL6NVR#v%|Pj#*70Ln6eL<=O*AlE!xV-%?o=efcrqY4 z*iZL!$sPOTaaNr>R4$dWWoY**!ylP4Dd(Pkl|A!$Hu63`VZa`w@G5&4vpGJBX)j~* zFKyz-%DIuh4wbBRI_Wz?{!Jw;;K$VjJ(nlxq~D9u2pwOF@oNIee*v8vjOaoo5hwpXERceDN^ZCP#Da=~#Xr zjKO0ivE;!s$CKP=ApS=BE;j2XvW7vo1gOTI|ANT}Ze~ zea;H>lw_J2NuGEa?_FPq^dPMj&FDMGZLpDzy+%p;e>&Q?@a2lw-CElrjpmHTW@Ej^ ze!aR?JY*BG$v4V*$uxx4&bQ&)-7jMh*D%*6Qxw`ibEeYY{!Ge1v6CHiYe@) zZYt4_nrTmJha*JGO1~og1t?ro;rXFc=rC#c^`&z@q$E;eq$4zKqUGF+6k?{uCfaF= zba`s4~9Fa-~nQo)VFK*AplC30e zRBlY|KAGUup=qq)I&x{5xe{b2CYW5e(xS;HCY&jwDKbE5;M8NaJXILUj}+i)Flpe` zBPPd#P8Aq5;Y^0f5YzKespgcm25f%nW4%Vtj`dnuah_-zM6${SQJ&)+>M7^{mX!?zdD-B5-j| z-BAO;r3RBgN(~tznVMbIB_Z3Xq|#=ZO+z(`15h5dDK!x}tl85|3^dXy#*o%-M?_*U zia;sgQh`&>X~-&MaB5XP)W9l1RHSDp21%n7>UKD-qcfgr#3gf4vS+PY#W9w*jEtKo zymbplSKT_)Mm$#0kx7y1vHtzP-9OTmVcmOl{f5|w<&*sC-kBb5NcBTjCX7QAj>D4W zzNGa2Lbrsy+nuyp;?$&(QyE5nIyC@ViVyv=L z3e5xrPiR5-TR8TvUyZKdwLQnd}+~*wLD~uRJfGIIB6Sak7#sk51N|vesN(MvhP-ZR z#W3?Fexg5=0o?V+@)dFmsKz0U{MpI*gnuy}r`oX6-YD4pvPmR|cIDiDKuPF8@Aa*l zXR;tD5aDV;z{dP;FpnE3n8m8%gC*hIVwQ)a~(#})#8;K zB__`{GAWVmOdt%^wn~YTvvM^|ZM2(PY2iB#>WNCyZK)Ki zebNms(^Y$roy*z!di(N2&Cv9F{phl~sb^?oZv|RA!w>)X8!Xbf*eTQq?49 zDGwB&(?u;i7|D_fP-%jfJkzlZcr>M{nWmPeOCDO0qy!#n2a^?6YmK?Z0F}w+n;q(m z_a5~O_aK9VS+md9k+fh-adYT+suN9~^%S#p=Bi0Asi5eL37%dKO;u+lvr)X8zLd@0 zl#P>EB{zv=jNn{gg@g5`C@&JFmkTdyzI^=^>^$VxDyP1sANfDLZHxs~P z@6(J`eAl^3pCnXHD-#1s4r(B2+4QXjNt$pq5H#%4uvnQJwLBWG4k_WYNugMqG@#UZ z;(&Olu}KdmjMH;XEsD-Y@It$BQRa}EOxHY_+fE{yK}9GW))JA|7zR0~Vt^^?J!?K= zUO-V#1DXQViYka0IXmsuEi;~txh8fjSX;AS`*ut_)oVANWr!b^QKM%&joQaWH(j;vu%R&Nez zE?AUy(n`E1`=X@YJA+MZ9`%fCMp`CUB%!)1veXVL)Ay>+R+&hEfVDJi8vq=8=cPjb z09u8OOz1{?Xm!)CDCxPc9{^x++O0-HE=fH1JxyiUhB=kkoQwcXXvM({#Aoys zt$Ut?CCwY!#n^Yb`H4mT>h(WU{uO$~qbleC86@pJ$4|soQp(#)C(58?5;;FXSK=SL zMac}KgWMXy>A96y+}44%VmA4sZWNwz?0=)C+1#r^yf6wJnE1(?c{Bv=0?wP#d+7ndv=FdS)TC9w+p>tW+cOm1CHBC zADwowW;WdsZHJP8^!Fd(T+hVZKAmAOi60V`^N-$KjP3dyeuBDi^7rg>QjaZE&H{OETr$7+n$sS4u`Pkho5Po|Mng5z;W!?@CEsHBquqmoQ#nx#DW9cUVj$!44kFaK&)9l@_3H36jOQXiXw5JhUDO$m2AmB?o+)!c5@wta6%J{@ z)U=-9n_Ckkg%yIFZWuVHMJvYpk&3o4l|0lLs`s}(Qf*W7xBfaRc^0~EG~2T5b($`( z72`d$j23kPK_?zzInF;SqvI`BQ83e>lM#7;zZeH`JqO?i>s*4dRt$uOQVO3!IR>V@ zxqG|0t|iBrD{gFb&2vW!7}V!m9TJmj%uLgRR5`$>16?L$p{e5}-~vhL1xE_Bt`#{a z^sQ@nQW5g~?(BM+EKHq>vD!@BovJ;}Oe|X*O23s_%`Rv&b7dE`l{x_5Lr~=O=~~&S zr-f!5@ZFk~hZ*-X!yj5*=9uB5Vy-YnAT#DxoREsg#w&9 z(h7QxYnDfJ5a23B9Exg+nMGvTprL8%w5qi-tyEcr#wznq2~sNh)PXZwMn?@qL9&gN zXJMeBu87Fwk}0y(Y%nwY>f@$8>a5VSpPQ$pDwv4VTJBXkT<^%EGX^*ZBBT0NlzL-G zzGJe(5B&6y;2)sse+quf3vu$nHRJyPdS~*}@KMj_Tr#Q7?#}qiFkG?J%EciSrq`QP zY}2&mQ=UAGpUj$vd^ZeLts{ivad=5kpmilqML4#d(N0b2C83zal1G0*LfgCd3;NZA zhJTP?9)rFr<)xhWBNnhpC>#>2$LG?zWr~+g4E>Z~uGy5lOl>8k(b0ped%>5>mkKZfvjNXj-}+U^ zBq+cix_WziR(dga8;8mioF2TN{;{i3wno#*_5QWyO=)AbtD30%hX;|@+*VGntY2w5 zpepMvti(tW$3cuTgWK2fs#?~oab#jh3NG~|lDQz{4l5T`)SFQ@?IMMeG$`A89&?a8 zS6&+rFN#|;&#frl$5P%m5xk-+CS(}$*`&cfyM{QZHJ=t)>e_w9jMjG$B#Id($YPQX zK_GU|r>$|U)f+W+MuZ~nk%Ej{xHEC-Q5K=wH6ClBMA682HD(^7s;^qL1#K9db!L4C z$C{0)%xX3@$0Nc_jp`QbQn{#@)=bqhGfbzkrW(%XiH)ZLO{Y^#E-3e>gG|jepF9pL zXtGDMfxzU{WaQ-XX}P4$YM2k*Ns&$ONP5=M5Tw&dq$ZG>w84Qi)9Fi1HDobpq|F(s zMr>T-g4EJ!j@3dOPAVBC>&-_jpj8`-i~~T_NhhBG^I4Y{KJ^vN&t7XT=Hn-=2Sh28 zPjT;A^371oHcwiv&zcUH!o;s8YBJvS5p2<%(y^t9H&&&Ew#-Q=`MRo}-sj$;u(jKX zW*;~3f;xNE@My7|rO^^*mp=6vG`Xc?GC*l_Oa_WVBnOI6YC2rdB23bQQRbH;9G*JT z0cMy*8FuJ8dz#338b>bYENHv9^Q7RNi^Bf^jYJJ2SjO6tW|SI?H7GO{VqDXKs6nR# zo;_&+v0)y_L!Z3-{vE2&H4r!e4uE2vnk;j@SuSV>qs=a9SXLzllp2g0T+kvL_`^r$ z54^p8l|wbC*kxdQf-4*zI_9OTo6~nhpwi}}2A!TO8Kb5fk^{{+bg03ngT-=GM|~1O z+Mc4AwIbIPk3t&~D5+xyJk)E}tVi0iY_>>(r&XpPsnL0%GYN{T#Y(A~axG4aTB#hf zL_sKI;;aRy!xxz}Nzi=oR)5xHC^p}t9Zr7N{yi&lq$^8O(UI>*V>Zm+sKc|UL+(m zq#om<{u#;lKGo630F6xe*6_t6{`exuKI^v# z$I-z4WAUb5%Xz%RcJi*yJg>T|>=bd2&b1A<2afe9wp+V+t>qv~f*_Fnf7PF3+tAlc zEAwtC$wl)$QO+YYWHfHb!=Y9n)RM|(`K9Jg?gk0^`u%D1+p;kQO0YN}_B8$PXy}WRUCTI#O2xdj+NAZyd($&erzBMBD|byT5rV6I zSk~sFYM7~}I{Q@e8Y+c$G?=MMb4sXaQ3+JgNY<{voQjS(`ev@dA0o6!;;A#+%X-ro z(M5T(JkmBb6CP-yu#u!l+L@Xttl6RpLUBbD(8iOVw3Ja=#A1plqPB|x3G}9uMHRGI zhSE_*YKan)G*Mb27?g#mqNvP`n-yMJangz^hKd&x<2=?~&CgzFqJyHEMpebfJ!?K$ zbHx-;bww4~>4m7Gix*(cX;@n063jX3s(+cHiU^ysG;>RuD4@gvr3acQqyw`?Xrh1} zo+)!h6of8nhM{rR6hH3~{HUUW;I2{4C~7FAYA$Kn;)*E%15OQ&eL13vEJ?q+JdTH& zT+u}%o$e?!pwUGDI1@{nD5YTmZK_G^39Mm76q&6d;M1t0vYFQb;M3Qo6jv2PzL6@_ zsYMmTGrk)WD60{5qKd?(S&UVL6j4Eh%LpoT6j4@=X%YcXieU&PP!>JOqKdv%C1!HW zX}h|XK#(dHJ%axLjb65b;eKn0m5=vTMhD|X6~&8Druia~gq@vP>f`kkQBD$Q z(Yv%ksKNG#lItJ5C(D=JfZ@Lp{Hqpwe`+YM+H-eCv|W>3j&sE@;>8^Q00e^v>Ikk) zhcr=NTa~uxCeB=6#wOlrq-FmAN+_>IoMniXtj3g4ShCR}N@GQJhB{S_iYcIM Ru^fEW*khuKQaR**|Jge^Kj#1d diff --git a/third_party/python/Click/examples/imagepipe/example02.jpg b/third_party/python/Click/examples/imagepipe/example02.jpg deleted file mode 100644 index b1f802ed85825e5202f85c8fdee2c56183b21647..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39106 zcmbSy1y~%x^5-n>?(XiexQ5_vi@PoacLc9dBDi~ScelW8-n)D6 z-F@HLzxUgo-&EJkRCRUF)Ku3z%|5LFc&dsjiU0@%0<7Ra;AsuZNJU=WQd?I`QAJ$= z-T(kt%IZ)zcLY2DaCP(X(p7p!XJl+bhdK-(0O$Y;zz+b{w%#5ZdW!l0yr?M1(|N<0 z{^Ea^t7!m!CIFb=R@SDY`#1gn3E|s%c=-STNE^;AXlL(j3&(HZ_=UfZ$6xvh9242N z{KW`Jf3X)_KsYA*iyi-ox&FcPPb~Wv+qt^g!Fm45>|y6>_ZRoV@jE|XdpJf^hvO(e zsJ%ZNPr@FdhFu_OSXVLAQ>w)qe2 zV;=yQ69DAhJp#R;j!r&wY_{xl{9bbL-KdLIQjT^i1YIL`}^}i?QMDf zcIdy#|CQliod0|9AJ^mgd%b`49o=(#2W#IKK6HOO)z=O2_Tx~!dpQ9vYR?O1o%7i3~9IjIqu;Y-u{pJf2t4?;kyXl zP)EAIWO-eEI$K{azrPqhC;nE*00w{y5CP->4ZsMn0o;H9AOc7LvVa1h3TOfPfH7bJ z*aA*~E8qqA122KsKok%Qya&>NEFcdk1}cDBpaEzBI)HAVANU1~0#m>OumWrX`@jis z1>D1LWT+r)5Fv;hLJ--2#yGz2tf#M5E2kF z5DF2h5t|A*>+mBU~Z^h?s~Zi1diuh@yz{h+2pyhz^Keh@prvi0O!hh_#6A zhy#cdh%1N(h_^^6NQ6jqNZd#gNXkeCNVZ6xNTEn^NLfhbNXvkqqn1vpl_nzW8h=3Vn|`=V>n~H#>l{^#puIW z#5l*q#ALt}!_>iqV!p!6!2E>y9di})7K;Fj14|yu49gcQ0jmt_E7ly=IW{&n3$`q_ z3APV*0(J#<5B4(l4Gtj=4~`0s9ZncdHcm6nIL;9+IxaJ=9Igd!5N<1jItb5aIyhY~oJh6%s@e77`Vb7bJ-! z4J6Yfccj#$a-{a8(WJGcB3gj;2N#rf$OB6^H927bf z{uH?seG~_jM3fSgwv;iH4V3d#2vi(Yx>UhbMO1@Sm((=WO4J_InbbYh2Q(x!vNX;# zsWe?QyR?L~(zH<8RN61JdvwHfa&#}~GU$5gPUxxVmFa!y3+RXG?-^Jb3>d;0>KK+7 zF&IS|9T-y?zcHRL(K2Z;y=1ClnrB957G-u~{=huIe9gkjV#xBArG;gOm5fz|HHfu} zb&(C5O@_^rt&nY!9fe(#-G%)l`zQwj2bjZ&Bb#G{6M<8h6UzCKbBqg_ON`5ntB`Ak z8;e_x+mE}7dzFWTN1Z2}r-kQ;mxEKICJ>{eV@+(*1Y{8)lp!bPG|Vn>oy(q6Jya$Sl+%37*GYDJn(+DbZK zdPRm_##*LOW=)n+)=sumc3X~J&RMQn?&ulcGp}c`XV>!L@*(nHpCdk3dLHw9Sb;#n zKp{(ES&>1}QL#$#LX^!FJzH z)-Kg<*Ivp#*?!wW$|2cd$5F~L#c|h3#wp$D04fj7f}T1nJLfrHyJ)$Txjelvd{O6$ z=4$2I=0@P=;@0a<;~wBX=E3O^<+0)^?wRI!;-%(Q>J9QX_iptef;&@#zHGjczN>!H ze%XFE{t*Ah0Q>;AfWbhH!05p3AjP1PV5DH%;BPPKU%r018X^}`5DE&l3H=tv81^P? z^Oe%8^4A!zU0x4`^MxmeUql#2w7;Q#^Xkodq*7#66i$>^)XZCnw|Vc7-a+3DM+-)0 zMnA^b#r%xri%pMxh_j9R8P6Y|5&x9nkT9GmoS6F_<-Obc=_Hw?@?`wvpyc%wjg;n8 zy40A|i!{r$AL&Brc^@!7_`Hv*-E)?d2fYCMMWi5 zWnvXVm2cH4|A@C4vSa`U3 zL}a9ORBW_;OmeJiTxPs`;`v1Xq{`&4Db1;|X@lw68MB#{S-aVtxfgS%^M3R93$GTD z7h{(2meQB0mJ5Hg|E^mRUg=zYzB;(3x3;iuyS~5Sz45U5W(#{OeVcZ>Vn<-7V^?u^ zbkB5ebKhhC{vhfQ|1jr>?WpNk_IU8b=w$QM>-6a??wtI*>_X_`+oks9@|Ek={dLR@ z`Azw)=1Yi%+gkPfx2roI(K90RS{K01mh}fCeCg2mnMl z0{!(SKooHQ;GcelDv0u5SQo_h-+2%K;4SnYj>KQz1Mc7dqgcV~zx)5(BIbksea3u* z|G|wgnveKDFsK#I4LmIX@&F1FG72&h3JNj`Dk=&Z1|9|mIywds4lWiRDG?bNDG>WjcV^(_ueg5;2mui;FDe>31}2;Vh6f;k5D^iO z5Rs9Q;NBG|1l|rH;Ug2!^UI+S>R6*PcoGS`PAWiSd{*C0tUGqXBxvImj*dY>N=8n> z%)-jX&LIRA77-N_mw&FHsHCi-s;6%NF@(E)ws!Uoj!sZ#Zy#Sj|A4@th&Pc@Z{J17 zB&VdNrGLoC%qlD@E-5W5uc&NjY=Sknw6?W>>*?+5ANc;`=lI0r)bz~k-2Cd=`o`wg z_Rj9!>Dl?k<<<4g?cHC!;P&~aTL04Qf6)sct``Cl5+V}nU%fyG{(lw6M?$9OM+FmHG6qYX8ve|4p&*|B`0^QtaP)%>!77 zAh_`m@c|j&GG{Ey&8cogtH8EVB};u2YL?F9G{j6^xKTe>QaZjB8?zSUA=KT+R_19I zAk8=5;539t+n!31 zD0DDcKN|{7D2U{NddpTjnwxG*LhRljx*_`zV1H|L(@W9*r5-bOqTo9J<2~ocrTX^i z$m&00eX2IeB7#Z#I-y5Zv6ySl=B0ab$a_%A4usAw)B4&8?u@h4E^cxLjl$UX)1 z@5d0-RsBpZpiJkoq{Qo48!!1wsgvv2jG;=Cc1u^Zmh>~SO~41W5tRD|-`tg0e@`=e zE25E5)ijSkU}0srrJ(qOiQq?vZaEu9^A6fkf)&pZ^5dSSa5KD~)&N^~jJsaMo}z_bosT zH3m|`-jH7qU==*<_tw0s(lV;5<2?iG9R=Yy4GFN@W-%v|6DZHxo0IV|&c=jz&iA>I z7YXSoTW1L>5CINxV+z3EeOW-1q4f#Ce8%;lQX%^wOvc-~l((VaM?4&m+;4P5sMpAB zmq>YaNw)KQ^j_DcLTB&uM=~LYwtHTDdRbn2d-r3d?=o+73@+o%YxTRGjOiJ-yu014 zcQ_)yAKQjf-W!*kt+hpN>^AWY84m@X^?e<1%Q!Soi1nF)*ba%M3&IlX3i7=Y*$e)P z6^%8P#g>mK$v{;cHo{BPcYp1f?cE zp{SDu3dQRyOpY-mBo%5()oqO|)ALrvt&z6I8RCJqm7v5X^h6SsM|MW4)|Ve;Bi97i3w)pEbcI#(nRRNyYP<5x6FGgNmYL&AEcMEE~*Dpj(T0}yAjV)IWm5Z3rMc33PU_xZ)w|vx9-3L*b;B#uI3ExjS z(BvhO<2mt=C9Y;ygUK}oWcL2unF?JQ3@+ZX&uc^&!Y1j4?Cy$h~Y2)I1)Wp`<(2pP_eVXJ)>9>bQ8@Q*(S zXY_MC$v1Xv!%|KNsdrMbZQkUGGcK;g+@&9(?h!<)Lw~j;;%$FXZxxPgHaTbu6zV?X zUE$2l)|qZ{Rr>X@P?vAnB>!x~vd(gkEn9oBweOeO$EZ$s@<=8O#HfDRJ@$DdX)^+4 zC7xMYIc@OFRa$3be_Z7rEp!k4(BwpsA(GJ|h97eA{I?o`jsh_P23z4P47PH&BSu(L z)|&0RRmG&lPvk;}{#Go79sWIEh;r9Wo9~0`=6IQmnn8)2p5Kx#m=O0Z`X(Yw42n23 z$5Cop;pcgeOr#_GKmCbyp8)OfA7Mdr-eaT{PXNX?udiBcNBpvx<)YrqUhoX~r9M0K zGoizu@SN*050i}K z8UEvyOd7hU09A1V;z55Eq9#fk)n@SGk0O%=NG2L#=w(O{*j1iGgDjb`4L4{*(4-yf z-c4QUsP+3@%yIYH_F#dC&#yQ0eh!xiG04Fz+d|lErPn1xM*Nfc6AIjFb~uGG9F&9@ z5@QOS?@UZwxjA1oU6>D0S7cVK((;5juU3(>{b3toajH!!a4Ig6s*J)xM8JmZcsTbv zcRWakxQNx3CQ)dxK%3gChmuJp#|c%k1dr8=Bg+ughk#KD0*6!zE6MRu5+>9v6Dvsy z4PUg$Ui(A#L=5@u$i8+<%W@r;g8|a5T-5pv1UD8O=sLyqLM^1y%&yD;^%ZJc z^#V45E7ylMr@`~rU$-5lMnXMr^~(Z{NeW69z*yp?<^2X}1&KFaeM&2+toxdurretL zry8dPVO<*oEtA(Ye?HIf@%sKoHj4&>MS`9uMw64ZKGQN7;Rs1YEi>7F&_XhtC)9i+ zszAtyvlsMeHIZs!_TAORu|9g8HcFcMR6<2!AsbuaR>aSWk^c#B4c&ial)hYjwj)$H$vnXcP&0j+H=GP%kZhR*d-9*{eJ1aCqA)$ z&ft?yPHiFB#uOjZK&!1pcOSER_<&gZ9h6QP>??CVZk==kgniUpMwqnOKJ;t5T2fhe zQdsy%tt z|9VY^tNvbqM&V_*_o}NR*HHpH|1#_T4Hd*V=3e!4!m9L`izoh14RW?$7mQE9l(A+! zmf|PBP|FPkb+C!*S*+6Bq~XXT-px>jG1|&0_{&vfi<~bWy66)S;8AyDbx(1Xh<)=x z`INaLPoXPjgZH=G*$>)A`VHFhI_YMT5^j_BBirV!KB81ZzP{>^FvG@AZ~7$2Sv-@7 z0=O?P5cdr)F<(P%Jw4->_3cmhUt5F~&8k#87n>4;AWcE?Sl=OUTXd&Rb1agL51CiW)b3TG$UR-bM5Z!bzdCXQ<(5ISigSpey09yPk&nR zrM*`!X!W&sxPO7(Ou0*r?xgTGA#b*2LxB5ubSNa6jO5K^-Q3Ht!A*!P&S!ovAAkB?ze`{z}VB zbmAelt38(eJb&VKNpn+c+dvXlf|Td$+pLKQ`BpdkfOVR@fGNdDl?S$={w+5bt!I(N z9RyYfiDJ?>yM}b5EAp9kfgxQxe>inTr-jB zN8!ovCkmd9nu?w$1{;yCwvc%BvoJr7W(5^YtHaBxGEQYbF5L-G33$rm*|;>M)LuB~zb+YtS}vJ0af4-~x^?*FCB2svbD396$;sAX9Rtw7`6 z>qe;4PN&kEpxNb*PYB8i8KrY##Z(E&MnL-bqZC*ogUKcoA~a!1g-OPq12zI^7Ywyp z)ViFoN^VCVsi6$F{zZ5YF}IjNYhSMjqS3b1#OTIxo4q*vgQO+MfZC`X%^_~3pg%;4 z8b852Ko{T6oAoC6Q_5|>oD>hO}sxX{4 zMjRgNIJNtj*kR=#XAaxF^u3~)3M?)`T7wal<}?Xh?pK-1_sld8?{@{L2UCh6T|eN8 zRka&*c7xlu=PeQ^(OGGbCn&MsTsu< zbGtjGs%Y#r<`p{IOc`@2Gt{_~K44AzrnaAh$km<2av3A{zZUj5$BG0CH0q+wsU{)mr_aZ@R5k@k zW))>w>r95T74Q~Iwvr^9Me5HIDbof%F(y59R^@j#=KhpzEJgH6DC1b4q`9<=mgSZhgAe;qxYi>+dw$JpJ;;Jf0;C!z}a8 zp{7s5m&SMnblWxF^X`#bVQglgXRX%Ij+b;#X=GM+`Cz=w|gk_rM2w+EQ9=nD# zCO*3Rse6@(=R|)tiJ4xT;eDm8(RYgT;(V@T;ZHLa9$R`8e2HbBXw+(@V7^Hf~X+YM>)zjrLH(^Kj+mym1P_dXbEx`$*!~yP1%6jo^F2 zZ`ao`vaOh#UqkHN)55s6PwGG|8Hany)FWbdGexgsJ{;rxbkElJNiy@-K4_x|od$Q_2t4nwQfYZZvC)e>fhmanKpCQTMOl?$ z*4X5lDz=M>OH2B+&AcGZ6q%uQy3VfA!Yia?fGRl{@-pi~HgAemmrLIIfy_unRSEg> zi9jmh;&f{phKX74-*~H|Z^+#fp`BBEel$LD%ZPxrdgVDKtRWnJhkE>OIu5Mdl4|XeE+ipBMzz&;!Nx0d*5qtsyA8qfZSs$1h{hDJR@4;La z%-h$~9YIA;K)mlnIt3-UXk!r(4AOsxxxwvr%UGEdMXLj;YUc*~&=tn8ze+nd>@^R2 zB;X}BTkM}}Y#D-mx>S&Cc|dOneeE(M%^UD;CzssC#TdhKk33wU44IHt;t}!n(YLM; zc({@b@fE7`anG|~d2JJKqdErf)b%2@sIzT(R)RrU9}a9A^LhPj`e zLtlLhN7Z#-L0S`!^W&!VMn%c^{%dld&SX8ljocW-0rLuSE<*~sNG};p5 zZNemG6lDzOx+;8qhER}DZc)9EBt<8F^-VU|OL#?>K3znwMPH&`Ez6%iC2Cg_TN|Zh zNpG z#pF!6u#m6Y99rwzqKWOTcYNSq!kcXi8s!IZyT}F}@^%Dh7d2uG@m&X>wTj|GVY&h4 zC`KN^@X_yru27@-)0c3xNJ1#iF+K82K66bv;%4RyKDAYG?moB~4t9lYx!(k@q0|-3*R-A0x!Ra9d2a}SW<|GY zdMR35PwxiH?+xF&r`3<7cv9j%1Vd|0pN(gmPFYQ)E%QsSjME_%u53mHTs-Vk_I<&E z9pfHnE%P2qAa4)Do|!A%>s&q<%0vcbs3@vViR`>w_Jn(qm75TENU(e4BiD_sgB2vZw!0(qx9nNN1uR5KMTy8h?*PY^#t^;nX<%A zM+pLWc+Kik{$hQ;x$5nguK^Q1PXPO+d?W9Y#M>g8FqzZxhf9Zr?_ozRs82xM4TLpP zQp8y z!_;5GE{#+}hu@HX*sl1k;?>7+w}?FeU6<7V<$Y|#Vi@^TnXjk3f@FKSMMxxc;#k8a zFVuzdQ2JuJ?K&S@g-29!O2tiTFLu#)D?c#$xK9Fk_zCD183MnVKG=B2^b;WnWn=wx z$QPY8=sXc*<~r$SJM#M-RS51AVDWh}Wx30rzvP$k?MEN;H7H}mbWvAVct1YVaonFt zszzFCqoA%%lB`mp1?DkwG%YkK(+7^yq*AT&p{ph1oGLH;R>zBxYs2}r)i3EYjT{q&c54Sk7Ml81hSx#7;7Baaa&$i@Y z2tw8YzHv^Zwt&hGYK?eD&$?C&c6|7bFz;hpKz6OM7Jtv5-&IM8`R>ja>=VAsKO@Q7 zr1b+oBy>D~sj;ROyJ7QU=34mG)w?j#2ei$uH$jFPCkw0l`-Oqa^+q0C~I8ir)jf4J5V6L^Ela;B5nxI>DN zo&u&Kl#S@CpQo}(hKAyhtboVGr89gvRdH7~)6thvhM3Hay?RnW!Lf3@jl3dgf<`hX z9T~lpZc>eZ3Bvm7+@K>F8_oV6DrkZ)g3xd{8DY34sV8Wk5B1iG=;Ky%cmZD@f!~x7 zb-Y=`5{dRHA?PPkEY;V_XEe^+0Q2+NKqz%Bd#jAt#tMtm`J~!#h9@=Z$ ziV{HIE%#Ye*k##K;t~9XHmtqAC_nd!0Y?q|Ih&DZJI}ZmEa5pHq#h7~BAA}@^1x@9SLj{{zWg_KRK6r9B zaS$;^dCBLB^$RFzUhe9a*HnoZKnMJ9;4>5#%Vi{g4`qwfsATao89&|YoQE=4(C@b| zm8@$AvXwZ+<2rDA>b|sI6R)KhnSbk*B=B5PT)mA+Aa`hLO>nYMW{o>ivP?^zd6w)b zEC^B~J?@(~A2B&~@A-q;+gIB9YW_EV-%>69$bC=IBSS}?{*BTar@5jiSA5N3b$n#o zxnu#^Ws;`y6Y%Qj$3>m(iRC*(%ZXUEHysg}0yv-x>w~ad1y|K4K{$p~Z-{P#UF5);Xt*y{@M2 z;+pG^r4*qw%~gYipyXsf&zaN9g5q)uIWq$e*4C&$#Z^c-$Zmtu`(cqb0mD~n<^*z> z4QiZRsy{tsC39%=YoNx)sx5Sv#NTg57$lVC39>W4N-2>&!i+EtdcX0ShcT)`#TW-3 zTpc&G+{+mr8mN==45`9Hix^LcE!exsQ4`u~&$TCPC!20-SXS-L+z^?KyvRb(P&(=d z@9Za=4R>^%OraN7jI)<0UB@4?#C;@qe_rzL#gP+et)W8iAOXqQz5xw%&&9}pfb~^0 zx)GD1fbM_xIF)qC=mUJvkI0$(g_N#)} zIg`gxWyQ(feJ+OijhHrXz{7&J+9k>A7Z}!I?!^pY2JDkCJcizmz zA&B^J zZ<}=EcrNKoyw9s$hbR7QT}n?)73ab-lD((PR5-hPH4RFJ7;D*?3(AxA_in3uli}1D zZLTgHmx|E~w#7bQp_L1FRGx1~8S zMY3oxHTkC^M3kanC#EOB7)#?)*4f15xc-~IxNEf7J#|;uentgDQ%me0gATT^Ia!V% zcCXs*@;nn0c5FVumrB*9JL25aCH^T?obO+qGtv;Fwuut2c43dYJp`|Pu39qxW%BmC z&dkRv^nfFT54h6VldF-55x>8QFiX^!_>nw5t;GS>du;deOSy4$dIDY>RtLyGi|xt6 zZq6g2P@vp;k9(O++wpre7-XLGp+0i@VCKf-3&f>An#hI9x%?eMW%*aY2O*a&-;h2! znSJF{Cqj#Ow}I?bvlPRloVl=M`|kK#!4TJRJA^T5RF8A8qB@(K-aA4O+E&;|9sYj& zk!W#LS5`|XGe64}o#cJ-IH8e2!CWy*b{4iltg_j-E}@*Hj!oYX zdFi-A#sJ~2V&GP`nmRB+rvK5Yj|73P>4cB{-cycJRv#+!1$^4o<~3_1_bM zR*fk76+dyRa#Tmuz`a&ulKNx`dWO{SDuHx*eS(2}gxc@rf}M$DVg32(5DW!J)?0`5e6mTYVu0ISq+XW4U&t+*=py5 z&*Z9`M!p+{deC(jm3QWf%WD2lKyFg#X&C;@?F=bcBQa;U3rrh7vnE2PqsQ8drUSc9utZGw6eFR zCJRnc`O;3(ti+t1&iR@NYzOsjR4Ao5`n(`vY5PrFd)&}sWfaD-=umy=%q#vqw^SJW z54L^U$lO{1>+f@FFqFmHbKubEk>{k?f(~XFoldRD+^d_{-gBRru>7|C&dyMYC=})< zx_>;GV?H)H?mT!qpx5wuyv}4o`}N@w>Bq#ypo*QIMFVT*5Y~#FW{RP*IhdMqZNVO5 zg8p3vRmC+*tA^<+76E?z$81Bt8c8a+= ziMH_qb7wKWoIBY!1%gO}JCM#VS_@9}$*r*$u4twZyC1ZowY-NDD!#&0uIH3gIGNyi z7rj_&;jN7);Fl0naEq*r_<0q}S0E?ro2Tv)CCl`HiVLUAvRDnV(n2cb+x&fFk{6;i zzr^?xT(U|Da;B%*^^>`Gh229pb*4Ng{cCG~eH;B=^s+HxkN=Sv_03`K*#)0y0v`Er z;1%(2Id~#;op3V^Q6A4K$M}vTR2(@nmMf{JU1w}V;@w>kWR|QLk!Wv-shQ8U(?~~w z8G$5*&of6~M1;?z->xl7RNGfTROfD#GsTeilu|!W^`v*ishfw@)2%L7TiC1TH}L4I zXLh<7Unl^LzWQ;8B4#wOKKV%dF)+QY(tK~m(rMC7!$tLNvbRL!_$7n88h>W zT|tI_|ImQuaMn6h?r^#grESk(d<>aDZv2DLS7+r9!FCtK{bLYXs^B(Bj8u-gB_epP z!KVY>AQvF$mD7k&W|{SDl=A1YO>II$MU{1?dwoNaaoSAn`?!gE)oVon;e!yYAx2SS=@rpuq68)BCT$${vv<*> zWv!Q`f>s7mR*Kk;gZE_NE*MFhLg8NM%>9AoFHiRkj#yUC^-b2d_RY@xB

*%&7?K zMi>j9Zxe@#d2s~RTI_0wC ztG`SKscb5L2m9@cR=Y&n%o;G=>-eP2dBR}gvE~LmD9q;Zdt$_r8GC#RUd@ko0bH_I zLnbc!uRiO9Ct90b@(ZO89}sIoTz+!oRHJyw-evtvHcUDGet5}J;9lY-sd1(B+>>OE zfEK}3M9)+~!ZM)Fc{R7mX!X-_?gek^cfq}A$ zNW|DRqNHjUXs{_Pto9%D=O4|qt2ZO07jgI} zr=aUb-2<$XGraaBUG4FWi&6v04eTEF7KV~1*uI9^gQJ-Sp_*D2TB{b*xVW15UGYV^ z#U%e=CmmuH{n3j1d-P{ z<=5MyHT4Geim8=y=Cx7SbLLcIC%Er;sFjjjF>*^yUk|M0&lCkn$ZBCb{kA2{j<%2& z8b6%Je2+o||0Y6gt2w&6n@lY>09ZvRKC^>W#2w>%q#Q-A+XD9QXrX`k}RiY@rgDRn-N`&2AnBm~AsW)aD*}QRB7FiOb z_I{9w(%O#M;M%B@>x{HBRFU=dkVhPr+qdxdb({BnNFP+e@G5=+2y)*(+-d(*ye#gB z*=-U^@OS4+CZ$4**%Wf3IQ+5H%)HWaK|HF3VDhY?o9T4~;I-tvtBk946XHhTs*##P zk+F_+w~{QQW1dgEDNS)&QW{%007Xu{CgmDpsvX2vOBwZL0=>>Lcmi&;VCacQ)isPX z2P2QfYikZU3pV;?to1t=u&)aNJvz3T^f2p#YMGiBMmM$WWZa9`Bw_J5tGB+j3KpcW zZ~6|f`UwMUuZ!Jzjj8c+hj@Yf3$6g#imD_vsxhu4@piuN_F^avFD)A%@jtI@lglO6 zt|m@5xvRa0L22xL!-Bm9Riu`B+K#t~X%LSkcv7*~$8ers4IN96IW{#h)QGhcZT5K5dTv{~h7pc<3iq_Z^^fT)w?%{^57 z{OUIE7G!Q2DJk_Q$&pDU+EFss+AfXpwmElzQOet#n79ElyPc+@rRZr%_>vo?Wi|Ul zb90ko`9$Z zp6K-v;u{yycY|(+-N&P!Xu2)nDFYzz1a4?*(So)~U+sKuk!;~>vtBBJTxSEYxrQn( zaZ^0{ul?<&Wr;#~Z|2{HHuPeIt+?&ilM{l+TCX1e z2<~gp&wi#rn@Q*#sS!P6N2Wf3zN-=7s)7xSUK1zL@qgy@MMY^whx~Oj5XG$xDWzP17$S{Sca=nCLC|9hD`UIM35dF))9gC@1#V zOUgw=yB##SU0#`N?$~L+XK0*6L?b(7YiK)K5c!$sm-pvRh=BKWIahBkOhDKrN~y5? ztVk7=u@h?gW4wNqrHM|g&-+JXI!x%r^IKx5IK+o(YIX=L90<0y`C8`o^@pUM;p9c- zgsRzkVNBL+#(4blHns}en~CGqprEYkff~`ANmmQ7>Urfci}%tm&(e(koL-#LA{#Ba z+sR@VBB5#* z%#nlb6T~MdrS^?J`v}J##1I%U=KNwx2pM9XgdDUnO2x1``it$-jwdwj+O}x!W;#vfkBL-xbVP@`>Wdi z-v*gq&l%$KY!tjrUScBge~ZARh@^c>+~U;9nN^F5Yp@KTQ?(yZWW&x!D3+7{XAVVN4i0-{ zTV1ABx?$AYXRm8qEAqd7goi7jfwXBa<`x%59&4Qz7DQ#zJmaRYl3&l%1WgK>jEy_5 z`w&VYY^_Z%iI|ynjgGZt2R-U?`nTsk)7mEXH`~5r+wiu4uyiUOv$&EKH*uIPI3VNsR0V@vePF zAKTef@@>v#QO($(Q+r8=uyP`ulCBq;kS? z;~C-;ke@aB1|D~PhTAT30bYURiF`ZqRVX!%2Z+VF1sEvHP)FkoQcYG;Sc>D_aV(`u z=6ic@33B+PqIaA}dNFI7)2FQ-#$_^oE9~Cojkn!rI)pQvm~{TaT~WdaGwGYy?)uz( z4iTza-2@_R90iA;k=e+cCL3{Gg5W zlV&;vcV#2h&x>n>#BoHV#og6kT^t)f0XR+MLOVRZl%v00I_coqEWr*cKdx<59;#G* ziQKo$47tqm%yEWaDb%R!@%_I4E+3>}FRf_xD!{ zGcT#M7cD6|kCXH4iRcFw2^paaDnc{!DY$f4oQ4F29AZK6Egyy1m~|pN(x4Yf0-CF^ zN^!YE?2~2p)^Ji2suaVPC%RXpP1@J3#}X)}Ephw!eJ=A_Biw~$bI8@K)Vt5dlIR`5 z0cwl4yc8BVQ&r_zxY4Q-)3i_uxr3wB9j=`2^6+>w@GZz+#-zHijYD-CrbtzJ0K>2H z^sChIt$IJhmE_GUKe60IFU2X2GZjklO?kD_smIU;{EX1BP!i%N+5SBj(i=d%SAVQK z^dOyvX_yk7;!8b()7)sQr5bmxGv@e?!idKq~`vT>`|<&FYd(>D~mGeGVL9CCp8&|wIA1MbV`eauE5T}G}F(-Xap*WR@@#LcUAGd{1iXvOl2ObvozOSh%F7w zQ!{GbYp#W+rTEjPcnc}fF%pwsj1U)XcpTYWa{eamx3MihRnx=45!F`aFQMB zuYB6uhDS$QN=OFS*{T{prk)?`Z%NLS?X^o{=3AITo4+?SAn*wc%b}7>CVN`ATyeIQ zo)tE=1`5U(vW%S7&UP2EP3jqnxjGC#=aovb3TkKXzDqo*mZBAONq4>#OXVMF*1D*3 z8-0nzgelxKTzt_S|0!%mUFQA6zC`~c$*&zRb3h>F`CAkvo2g8N_idU3@LQRa34Xt7{@)`MJKB zn|v|y{fiMSC8iJwgUGRm?k9kjOy(%;a;HU#Qxmn8Iot+J+P*V#Qv5F1L%kd$mq}NAvciP9?_7z!kELtvI&QF1r(G5ePYuJ85b2YPfEmiOKKJC*jq}4;0kMlUeCsfE5f;QEQwkh2!bX ze;CJ-jZotjl$n{-3@VVNz3^C1{<3~iK`ciD6F`va(~^ko@E6EAtmJaaW&8*>l_Gfp zG|%P@7%*e~mIy0(H03rmQ8isEbM3-O)AgE#$ZdBxGhvI#Oz&jv#ZWJ5veO>NCYYl= z8u)fX;JNLb3q3Ydz7Ey!Y$(0*;)B7d)+yM_&J^bOQV;4V^DiT}VB&$dFwQUO$Hx9~ zm*&-iHwehuQ($fz2{mqBrB{8P^k=!7ucR%dKele9><+Nh4iqi!q$iuj`|GslyfQOu z_3?WG?6sC2Bn&MXTp&I!)UiR9kxlocDn{VmO0QB`;fhNP(V9Cubqgj3GG;l(iI@;o z6}*M?YBnNm_Sak86)RH)?mlAmmD0xkYs`Wvvx^ObPbN4LqeH$45<}Ofl z2{wW$nl7jKnkbamn8VxlxF_8zmF-G8cb0VAii8eGSeAw;E4e2>SIly$wdY{VXK7Cw zacN|M%FmA#_aNkK|A_5=9kZg%@^hAie}jaUBGmS^R5wE54czO_!sdl1M`EpJ;I}^d zCI;eoo4QYc6*m>JS$wrWW)5kQpjWO2)|eI}g5~T#Q#;NSqLqaYEVa*r4A2tcsS)L#l0WOYKP~6@ZB=FE3Reg-QZ;NZxAK#@ z`43T#@W5~!2V=OWYv%tOM^^#W)cgLyLJwuR-!M=- zKLQ(JfZgRC0sXVT)1FRJ%+f|$yPu1|BF(Y+XiFCrd&dceyY9Jp*$RBNNXC-0%C~CH z3^;{m%^+6`dikaB={KgIEgiC<*L!%d^(u*Fo(Ae2&qQrIJNmY$qJr%~% zy0{ihMP`xdyxc+;c_e*ZsE@IFTuKiap8B{AZk;kSQ**{k63*Z6M=_ZVc9@FGG}Xlp znXBD5M4vEeo(r8At!;X@=183_#YI!4&G}Uxe)2fc@t(ZqkeUq$f%xzC_ll3pkU+o=M(x)LKA8?-lf~E^Z zqIaPpKiSyehXbRM*nHpcMWx{$BBs{-gL?)SzfFliA|a2TM;-bFcR`7E5qe5&wY{|A z!-pPngYpf_(OF_?!F5vGITB(6Y1k!6yA6Hc`;$XGY{S9)^Zcdu4(Zbo^S&vf-eOf` zyZnU6dcmb}6XqT?0C}C&8lTzG*4)BXp7z%G{_3Xqw8~Gce){)n##k{+N2BqaJNjo( zAgW-?Y+UO!%F6iWXX@3=pyMRH-C#Up&STT5st-Qd$}r2tk(?y8*>!FON+zCLMYLRk z)$rKdppSfmM!EC9JuB1Wqg662d$Kk*jW>X8bTvNzM`qLc5rsS}L~*_oz1SKh2cQ zl!Lz6_n0&oCw_1)=N^=y+>j!L>7;)ykB%oosN7m7YNFwyTq~=)& zNng2Bcp>oFPr7QI|| zf5-2iwEg+Asg{8aCU9duQF{zx_C>3ut~dk=JN zvJl`^4~0oCuAWPA{)eY{0veXisBARmC`pXHQj}!gYVrsr+*z4KL$Pm1xakv8aa{xu z!=yD`1Bw7)g(0r0eQRoKY7 zmxZ`aZq~Lr`a5Wd{Wd=oWx4IuZ*I(7xLxC&jn=zwaC6M~tVo0p#4w&=V6^F~cw!H6 zfbCtrViTvtw%!LwC9(65(%6MMLideU5EPHd#%{+z)gwMx(a^Evt?auWhxp|()37R@ zp2RpO^~V&$lj+9qA{YVCUmlRDd|vr&%)s`y%HjFa_32l#m`naaWcwcMeaBnrm;5FP zr+`|_1Z=R_nacLS_#I>{W_mzJCrPt>B4+yQ96}j_aZFb$Fy#0>FaA!CQd55V9f^2G zYOiGG1QNI8R+N@Jsdd`O)ncBCI2kb})*Vq94P^OXV~+Bsqh~}eMYW)EOuu>6sxI{q zMVyIG5%emC1YT&_G1GlLM&*~*K*e8|u71h2OigrwFX$?Iyi2|rmb!iXVcxvo~O-GhA#&wLD(k5v_g3Qjfd3WZpetI0vYFA zV7419c3mz9eH1VXh#?Io4J5!A zw*?6H2v%;BS&SMVq^1*hT1EDs*fsu%>TeIE@B_SivBnYg=8SUUqgYS0jv$dQ%I$=gHo4vLUG`1^1y#nbFR3}FJEyQ*_%JMNT} z*}nnY9I^WZKr6xWg*-K*w)S@so-8ROD%-{PR}V_l8)iY2({ZG+tiEXv8=Zb@&;?27 zB5t2jo?&A{8LLW6cZG@gF(DnBjA?+`Gzx!VKa;QNq&Kk_J!Kq-lK|b_&+ z`8?pHWntxkF5V@33f`g9L_?y2QEG8rfe&ghF#~0Xd58hmAOFn=JSYU@Zc&LOJYg5i#xzUev#ylRVE{<2nX=^yj#D@kjWQ(?<0)YQ?nL(r@T$1)8&Kl_QgXLx#XV9DPRSJoOVd0ym@ z^b$XhYHL14_s?<}WH!1RCgOhTvu(48`I#}c4oNCr>6^3GE%3x~_dw4pq5GoNSFedJ zy#`JCOahhcrp`um$AA%|)h$T@HyKiFzmtkjP=Qqi>TQ!pu}^}vns35E(W}zQ!^WVJ zk8d$(BhF$9|C;1ArndC6mHW53$L=!`EkmmldlU`B&YvVE1TRnvIU0J$7KsJ_E|sok zRMYrk7$u0Ji+Kiad%cEUCT**wM3qG$=Mi1)d+o*JPPKGN^#|uB3TW=2EHab2R@_o? z{SZfL>iz%G>xm&5a`(&P&~~NPbYDZI8j0)I!5EonG+i_rw=y&ZPqZx+E~*{{@yU=M z7W-oh7d6c{@Y)zM$OLkHD)r< zGuA?mI$rZ3!UL|<$%=H4`}d; zeTyBY4@s*w!Hpp0UGR~I&qyfqd=@~1bhyUipjli*x_W4TIQK8;Z?A^%X3>bZ`sI#O zECpubyqp4a;%y2OSpd1Sfml!mzHqzDLO(!l6tZ`+O6j=}&6Nrer z=Yh6Ug5`rF6~TC&{rA=T33yK^JP6<#A6SWsSM0aMEusk?tCx~TjA(O6i)_|NXEYE$ z2+pa`)GB0$s6MQGYOzJ{Y4$S8;-b8XG(hqis0Cia=J*@XBVW6qqu8laL|+gn9s%E@ zMa3SDaB;o%dnY9&Q**UhzUyRa_u;LIMd?7eGWTrPS(&uEhZBo{sYMTuI=FIymCaSx z6H{PTxfiJb5A?dUO!|juF?QU#uqrS!Y>?C`evpEu@5>*rpyHEn*qq7S)SAy?%Y=^I z%eqWmti-JgxHc}1;@BU4x~rMCG?^inaUgV3s@VBJU&DEZwbk4C0JPDt1`m0bH>w$I z^&RZnTf@Lx+0uAX(Sm;cV<`h)ll$kKvhhu`f&n(Gd+kH~^B1vhtOX;^Sr?~f{jD?% zprofG{tATOah<~)7ER-{nE`C*#wJmtiW$zuSrSnB=BD(s^&dz#kdH**MX} zTNwfL{B%MAUOyj!?0gDI+^6zG*RB%0RQ)|l(oyp$VqZtc&F#QUXzpw^XGWEmvE|PJ zc-d?UySlvL8OEplmpq8+gVF+cSi?%H?5?QKH-FTW`KxF93&}J2;@{Yv6M36)fK498h zo)0bsYUu)+UOJYH=s%Wba^Bin8FO`lgR*x2m~Kf74$KD`0y3k^tpb2%8df3`lF#{U z*0q?B1qPT;mV5JO^EtsclI|57rZ!N2wxl&&t?x24Zk4qddw6b^JN}Pxd0n&S{z<9w zh&saX(OKnJplnwmKxTWoLICt*C${d2w*DJ!_etbRgl4eGIk)87uR3WxQKy=r| zw7lGr z-{iO8Zn{){?){XS(F$w)Koxzgv9MZ5DD^jyQr!4|V2yWu&?`QiaYO$}v9C^eZ{C?Z@&@5= zF!YLRS@k-?S76to(AMqjL%IJ%huHq3`RzshL-?X@rzUNduM*5+!iIBED}VYaMBk~J zA*p~HHblUHd3a6_%AJw>X7$*w(fjk3S4eQ&(vueWtLzc(+2j!!StFYhEm*jgU+S|L zn@r4iI@V8$W0gITN!{dT5gZ7iLmb8;13+#S9XZKGh`q#j$Z%1m;i3K3od%{ zQtcj*tapgRsz07+=L?Go(ro{v^z?HmvnwFhT^uv}Lhlg(C$@Yg&PlA*c3K_=AHidf zjvHw`GF~`#k>6@p9vv3N3};nBga;9DdRPKar8C=N#JJZBNRMr?3QD+2mzOn%E5;Vx zJNYdZvf!e!xoH7u}uU)Rt%Clsa zA3-@qt38+!rg&wPzhV?gc)nTu_0tjkDFk_cn3KNE{=Rnoul8)_HK?e8+9Kgnc4pMu z_cf5&p%jWreQW>Ghhdk8oTxJh`#sG77%YMrfhgh4 zw9ucH)i9oqXbC4uxfNDTJ8-mYfE%y+DN!HXrsCQ>i$}^v8Wn%AeljIcIzJQlnp~jw zwAzsBE82{2mExeHax_YsnuFgkF#s-#z26t_)GkASPx)>8Hks2jB=PVE*)J%ZX!G+{ z=^px*3_HYH|MD0xNUg~g$ycMl!7e0c!RBcG@}8cHls3+f;)L|%Nu53nsG_z6(Lbue zME*$c->x*Ro=^9i7q;#n&Y$#tJY;)`oc`Fxw(CJ^#KXbARO-;Ma!L%}G{c<9X>;BD zx>Lhh3?pRKy#M5^QFi_n8??Se-7Q}`GgUPoomaeengp3U^#n@(wf`x3dB*hl7V@R- zd*4g@W=XexF4kNJH-l-zFTA}|u!;ZhjO8;YkI=p{Vy)GATuq^^+X2^1O8b!0xT^v+ ztl*h5P9(mNc^GI@wh?-naU7Z#BzVi-+HjvkYq?Mqoj@g2met0V9}KSReVgGvar!SI z4lQ+)rmGOUJM?|C=2oj%4KWuO7ja-fJg_*hYb<|G5YezcU16s&khG&J)c*v;Ku;2? zJKa!jtytDMsk^4oo%j11-*U$gtjEk?hYALYj@ZVj;Pu_K7u<&4`9gT0Psw>= zuJeummVH|o{@u5#D<|R&2Fnc?V~mH(_X^KM^ROi~+?~wpv`sHTbS|#tX^X?`=T@lv zE9+xK)bzWHe?P27<#F|2U^x+zIw)mr_m;V2MPzFiP!&^87ZR+I*0-xs48DS{dcjS6 z*nQsZ2cW8F=cOO8d_k;}7FDRZrv8VATqrn9PyPk>ncCFdUd=tK`CD2CUk>;HOzXZ9 zG2T>V@>ALWbXSKJMOw1K?29A6~HNL6kOyYRIbKzc)dSLZMp7zgL^+?+K_lSyxfFOmo_Wp4IRak zqAuGI3=VxUXoZIN%p;VHWSaN1TH|p*jNxIqw^nOjc+YIHuQCY&K7wy+gS(s*vw|_f z@wXBEkHGhN6}OE_#OHGg-8DX@=_O;Ta=Z1Hn%U2yLdU^64Qp0ry}VLxKU4IS z7L0zJj}5vFOS!eM;7qIQFpDYC9W7Wj9#H#cRJ~TWN&lwq=4=vmvn#u(9 zb{-`GdO4yh)R=Jk7DSr7%KL%W@k*@8I8sSo8kh?3(dRj(uj^T8Asvd?1=utYx8a}W z=OG6uymAc@<@mZ3ga)R~v7>9zn&C=Wk_U$B^F~3i&$O8d?EUZKET&YXTeiqKDQvSS zirc+4NJSaz-NqPpwSjBaIby2PvEh|Zcz$o@zse__v0$^Mp*9OJOW~L0@KNP-jsH-N zoFPkjbC587T-KqPri zIlOPL+f7M}k^<$=+Kf&b^#16tE^RD?3ypR%52EpD2p`fHnALo6tu9-{AG1C#tG8Za zQR}cC`abk`%g>yOh6ACPR_J?@b{nO4J$bNst|bk zW6k2&l0q^B&K~fE{IbNhf0;g1cE+_1QdkUrxzUk{@QLP;@|Ym zSDXoe>9tDhBkxBjZuuU!4?9+ofT-GFkzD7Jk<)B}gRhsa()YPDrY^J%83x4_F$Ts# zXYUr`R=&DPiqHI0UD2>PuAwXZbRV61y_w0$-=FQnM)q9wvSp&XUAXHYX!o=egV>V95-F||GS=1#+|Ns zp+qL=v}7u$fA{mB-z}i``+R|Yxn0&xS?*25QmKJ%K$`O08rxL}Z)M)=R;dl%Ls@~x z0ZqMbR5vm`p{}u>kFT?Z2p%YY{tvH!;BVFY?b2_)14gTrA*zpB73srXqP+)=QmWf4bDb4cXa{kE|60=;>j< zY5>EZUQd5>auw>ri?b+dF~>Evu7h={X&pnwi-r>#ilaxF%QyrvIFj z0NBf1Be0t(xsl<(=EwNW)9e+P=P9ueF<0R_VSDanxi`zNnlC3>OoHU)mlU0|mGSH^ z0PyKF?PqUZS{rmKm{Ih=7lsybGe27k12l~2#Z$312ukjr=Q z9?wt&Fc+8SbA1QMn?Ad=z&X>nE~&!w(awY)TWi;zLk4l7;NqkRsy(B={s>))2|WYD z-;wZMJYbFCgU1vr-^Zn=B02jirBu|5DY^`KHsRI&oSIMw1tJ4eYswmzFZFb9pxkI` z$6_!&R;}>cP!M;2OS!X(K#6cqTHrTBZuS+>ml*sp@s}K_b_tVlIkx$~uYsDBl9hpJ z<6q0TH$U^Ncv?&qX+8n_-HxamqTup$`jz&q^~u%E7!)UM54JEV*~yn&LvfP0fG)n zy15}~yinTdcLrqETKmN{)30o`=vaR8Fqu`ZHZ3X<2@S|4I$F*Ls(GD8pH-A;pbaLT zS-;KjJo@x$dk>fz7M5U?TKc;mu|8#CnBbb|&kSjU&tIj9m3%~WUQdI~w$X04@%G8h z^mi@=WW1`s%5^P}Jw(kr`n8}f%`oiue$s>?-HhHaxB_=4gUK0X;W{93>R5(*7t+v^ z$UL7|F3r7TxY`QqD-Kew9HC&^RmF(~$pa62zeN)&oqC?im#q{N0pOrJ!g%17m(A{Dzi(rCmT?Gp_OJu;^8Ty+y!2DN-%ep(iL zQO*2W7k}kUmds+LsfRc)Z$n{r5HjpX7ZaBv+BqO)D;Mbp@LTx0!i&WMmRcD*sM!+M zgYxSyQb`}OAs@VXoI{@<{ylE1KWKQTcJ4nsz0a2pwdo3Bwr_4xj7J7DABuc_OuGxX zEl26^ZKQ6$d3atKX_hDMHx#8~WlgSi^dBDE^4pUEaW(6S73^7X{PT*)6bE|W#Av|J zZI>RP!8AWxq8&z%Ey3f#XeY@}@#6PudZcDdSq9EoH+4nL_iyeScE&TfD7p6o&#OVs zI=zQU%8WV!yYZ56Vsplg*suXOB`Gcq2=8zBQ#oQocj}1W)14sz_}KMoNF--889sbO z6_@y+$v#F2FYaM}q;*M1AK%W7Zf|J}E=~z}J)bQMhy_vAGCBo@vN)gzQma8n%vkP&;hF zTN}94=nXnN`0}}xNaH`e!qD?w2fZ2t=$QitYbg+vu?h#mwp`0z4#83b%SkavCy_J` ziu!Tq&dux`_3{3%Z-P!U0(Xd=e-(#bfX zpd0=mn`yxsu37XY#*;H4fe14Mcq9(Eb8%AdQxC9$yveT@e7KY)K3=NE9qD;q>IU#4 z5$6`0!Xk9q`-h?hXuK1E)JETI#pS2T^BZP06IhNo5C92#Z3vfSSqrjuFyXIxjw;)1 z`%ZGSA$oxA31ZL#e@~l=O%}%I`fZTjjYH2Jz}Z!*=Yf80_05ogp#2?(ol~jl)au`= zcNU&)T*sTOudN|l^*70NW8Ya)2j)<@UM^*L8FZf)liuvWR(g6HlY&MNlr+y)UN~1g zvP$II?zju8|H&YIJ^kKn1JcvGP{z%tB|Ip%+g3#xh()#HU}Gb8L*G(%#o9@G)sBGc z8^clE&Yb1C+!Y+f!O8n*0J* z=G4~mNR}%rE))5EqwzbVgeV&5oc34yatYoM{J}};e5C{P2a3IxToZ=>cdZOz6vr&( zett>@6POtkOJJ6?;#N&aAoAm=D}bpo6rdlpuzdsI-aJepx(0)~S2mj}$SWJWHuJl#NvIZ0$yX^fALu>+uqqs z(2@FU!8p6E0GJ=~tuLt<%jvhx(`fG9F1UTLZrBe6+dQYo(-jFpDv+yk9%B(N&XqVS z;-34AKD&=kq7ZxWLDj)&BG49CQ7gqtE8xP06+j zhAMAMirL2tBM=N{di{mayvrosZh(miV`?`VT(i?aLUKMHqhZ$&8LnL>#c!*U73g)~^JVw@rmr zl}Ynymgc^I2_te7F4d4iXNFsd41fU_aG3(gT{q9qi0aP4XZ{<%VTR z*?f7Awc`!?0K+coQ2>5T#GbAS%3yBzCog&GerdXLlWi+pV5s(;&&~F)`{Q0Zp2vr8 zUS@r0(5b#CrsRA289`yVn)_G@-^eJArx+~@HpKTd!>YfW)$_Ybba-g~>bJxM+1-RD zUAkN>4>38V&j;Aos62$w&D%BH!<&WacxeO=?`SQm z)QgM2kcpF}U_?zustu2Gg4 zq{jw}Jv4~=R*h2iV;>QR6*&v*e{U$_c{6TIOnR}3lx;9RK;b#2R)4lH&>V$bF13{p zod}50IcC%mjx`rli5G}pT0s(KT8_-~NPpJ$_KuP~LF9CkSV3|xW!h%sRvBze%->Om z6e)gTEI0_wKM!K}1OEIgLp$Muyw07-qI>QJJd~^q#~w>aRZ%sy0~SNg&IIuXeJde6 z@1FA4e@L^w+RQJzA_1O>$4m75nU?%3m%4LL*C^W3;_hq{|2Cf*giZ%exCxJWYCc{M_}C1(I*&W~Ou~+Ogf!5FIOy_G1) zo^o^ag~0IHj*gaXF^eOiB>S2?^zknO?syjxBp$J@0MjfgMItwAvS##5M zp1?}fGnWO^a+b3nuLv}bUwr-Hkc%Rs7Zjt%%j*q&HEn@m^8P|Q7@_B=M zv3-_rC$)VOs@8E9x_NF1^CtQ_{40B`WZZ2l+m6Q+?&fjL)#iWL_!)7Zdp$6>A^%(?Ux<>K;D z+iOg^4nVR=qTaZxxFJpN5+vlW6 z5sgmD-zM|u@6TWUO)A4&iW?XUAp{JtnI7}Wi{*=p$()s8+KNDKw1gC0v)e!y4Pz9- z(iy>NMoMsc-c4wM z4){&zv8G@|zEB)PWGC`nc!*iGu}L|S+_qe)1J_^!$eRrlkzBF?aaa~_i!K#d`c)~p zkqyQmiu20+rqd&|yNtZ=Coe16{W01o{r4|u(OYMlZiFK4ppL0Py31=yWXQRvm#JWfW=lXH>r39W>;Z{ilmIM!+OmqN> z{rwJ0)V>gO1VM;lZ~5zZdtQH4di0+C?(ZFMt`0cZ8XBEVb*Zr)LhQQumQEJTzgWE$ zhvn(F!xrve1)8#8(exjusFO?L)b=J(dKIS3?2A1iVS{(P0*AkeuyPoa5m)4oGJB!3 z4a_*^yLO@Gtg2~82XiNrB4&og-;@2czD`D_X3!2ZjleuKa-b|qe{U%*6x|)8{Dtv+ z+Sy6~Q?dW!Cw!>Ytx%@K{9P=EtDX12Cr1TsJGj@&7tRyvpjK?&Q?#l$)%VIEiS%-+ z^k5m${ED7Th1ktDe(Ckr%k-*anJ@(TWwCgk{SwgXQ`lC2HLb zjEzn#+;#)K$9&AO}plPCYEcElr%WTB7qSKt+JZm zN%`gJ&sy}D4{7pXi^D@&Kd>|Kx}3|~zdFwgzb6z@&^)*w%V`p8l(K_Pr(eRGQgN74Z+zo4|~$ z1MA3}B=LONufgb6-lAI4Ayq|&-Mm~rX3q5|{?EHFood%_&p6L+ak^rj z)s`H~=f4;?7n9pZ%$wrFn{Sp!vt8IlQphk(g)7(u;qZqq)NFam#m*&njV5~oRxc{v z+t}N-i+EnmD24*e=IdS)bw;lJ;Dr%TSGEe*kfx`uye%<{$4z(GA7S}_LK<9+sI# zUe3gnN$2N4Q=|lBuxNrM$oV5i1rfQ&nMlSft~!Qun99pw9CoF2$k-Ij+;?NzUx$io za=ZfF?HUEaf56p{ICP^JQbRL{=PUkJ0_BIk*}kv$N*Ng#0O9%28-*cj^8s%bK=lqT z>F$@`8dPA$J-pH8GF0L*o zX9bJpr^0GN*(=UNfrfk;lcJttkLr(JFO@&z`8ZS`vo0W(fBq=V7kR+1$i8&0()VyH z1#F2M#PymB9-{567S1w|(BOe+O@B4yGlY*lq|R_Wy?XUD`R+$ht$cSBO}D=S(`aW4Yf7BJMxTl_>7KjHd762&Rm&*wAuZc(39fF^atl$m|-JUZp0k7`vr_e^!7*26__OM2bQF4M_o)y`!J zj|(VVW`3}@YoXsLKe8!NkB>~$7@f#3TWJwpdu* zczyXXnS84L7g}?@%i*~WYvS0f9n+GZEc2xTS|x^91)BGaa(>8L&9`|b^qZ#yFL!sL{~*Nv`~MU6x79YySE~Zm?Ft5tFnb;c7J)X zn0!{5)y>HJ{rD{WfmsNDj)?hxc>Z_gcO*?p=bJe>O>He>rbY>Yh~3)(zE4a6X`3s8 zzdw!IU42Q{jib1s&5x`HZmzjgZroRd!GMN}ECpf4ty@_w4slA~pU@NJ+E-NDZ&&<5Y)4+&Vb~Es0D@PEEN`wUxb?3$pa+Pir$}BENCfLoORzCaqL9y zc)?h0F=0qz48bNs*|nAyu8M?Ai!{i*{8c^;;p%$iOCV0%P?3c1%6z$Z1^Rcu#$cK# zpf(=OQ3I!o(pOwbzXuFFf{K{G~egQW1HAMFt*`qRIh(Z`DJ9gxCW1V`;)yaXB-Tdl?E?!&grimm&uS zmqo#CT}_rXHjOwC@N(K%w!tG1XVy}t8WK3*5m>Z&wzI3~t3VkWEG)HIxzHk2fxy6W z@}bo1`d>3Szs;r_oAKpm#8WjGN?S|XRw zyk?Z0l)d_=D9!b+rK!0QdcD$OB9aeUO1!!J?L-3Dw(J8g2az8j=5lzu8vDG(F0S-| z@cwpi%NOYHGWq+`<_+EJ{As}Lk9}S6^@uq)E`R&Jr@ z@}>&5jdUyw*)ep>yLwEDM`m*v7aQ5r(MWZ|!Nl2vgc%BByr7we$TZlN%$lY+0DyLD z8b$)Ss8@V(H<&u!%x}7${tgW7uMcc)R#=Qv$gVs86S@L2wgKS;;OptPd*7qg+(`cP zp@RJ)1%1WTAEZVlaoOO>Z*e4JUQEx9*$RUwxw+Bn`#(b014n)~;9lQUGnH6WsGm2d z*9Q}=9i#uldo+kY?J#*1y7mhkzwZ@Vd;4{Mm+n8jx0J~u>z|nK>%U0nO)%6Vh@vN= zneS~t-V0c?pfdr<-awVF3p@FUn}@KN?u5GZ$03hU1JFh8fxBK6I>oYQo~^?#Bb)6-=)6B zX1_;aF`@kXv8KOg6{wQ-wZ0Ld+XhN?^snJ*@(yw9(PnpT?uhXpdOPaF^ZsN>eJvL0 zveVCBkzFCCkzYO>fm8pLk=5(LJj9>u28h3vwGb2s@T;?}PfZJ3)xAfu@|z|G0m%Tv z&T*sK0`lTJU^3^Jc0jivWxOpVxS%l?W%#(K{gv|Ajb3J%Gb! zPBv_xjb=k6ss)N>0PLIVG>o!-dUht4DD73pTH&6QK^uVE$3+q5x4R=bD+KY|jqs&w z-%aHwKdcM}=4u4;5PbGa?ylN>U4$hMm&N{3D{J>oOU&9A3MFU~3ql`C#BuIJC?RISP~CdjEuGcU`vfc}#kfS#LjV%TRnZg=i# zks)yx=kd=)#!SK+iu=5@iysGz^^O=_3YB(1)C)t!+vZAO(rGbqM^PnV{z8<&P?ujp zb_lVd(g5nIiv&JjH)j_xVhWa686^+89g*Jff4fu+D{|qH$S&dQ*Wn$!OlAy6*6hKc ziElScre(-#O5Hc1$>KD!(<19%}rLrcPeZxOReUdQrPF1!Vq~R(Dy$4_NCI#@;!q!XA{x z#y{MuGz5)2Cf<6^Puu(W=SQ&hk1Bs$5~UtxCURh;*n+CYm=pxw z?42`^z@2sLAt=!q6J)@EG)N9RX5hHDEj_8KIvm0_OWFAHXh{;2pNm**AmS9#g%nh9$HrYyJ^`x^S+N2c>Fh*ZQ2 z{hE?G!fb0fV!Le3{O_Rnz`se5)OfYW8(z-8C@oI|cQjeH#J5`*7J5O+usm|OHtPlA zr2=HskViPRtieR3OpQSsabVK&xDPqijfu<097AQhTb}&Xu}7Knz@3^cN(K#TL0HY$ znK423g-xflgP76eo(U+N*NP&wJXjh$_ zw&PHp1Xl0sP8w<7VmLJu+F$V~XXk%4E8;)W;n(an$@t+!tnZGCZ=sRj)t|<*!{*Y7 zRXj<8E$^gmEnk6mVVnHxryFVvMiG`2?oS`lM-0f< zbjfuMv;*=Xi%;aIi-f*CrhfPhjoX~uurXZik@JM2d|5g$T-wISv@EWTO(x07F2(B` zlR>Y9%(L80mKKE{0k~bN>i0g>O9|ei_2joEn@I5r-_Us`_`&yEnmDlQ6VzlovY$@f zLuai|;34dG>tFxF>&$Fel#pUVa{?G76Tz96QaNo>HZ-Z9td9g)5z@x?zfu&}X}hQS zzDH~-EBN$N-|zfy3p|8gmXXh7RR|5vW;X&(mBz;R7vRci#i1_`%?OhjrZI-&yB$N_ z)wFT)Tm!4+cp(D@j5)VO@Dq+gsj^0_g>Qh$7H8;*ETLZ}fjj1}5D6gjfGf0&PiLvu zbgDc4WIp*zQl1HZ8JY|%=v6dDwwPU*VOXy!l*3yxcap3Q=9F6ef)u(SktV%1nG50E zGu5DxQy<(+%YZrC@a7vle}T)2E;`*a!ceJ9nVOQ2lkF{#&#KY%f09Fe!z``O)tY=3 zV82qT=}hqdaC})V7W`BU<&}cVEfUcT!fE(OAZ(15y8G;f(N=S2zl!cmC8CRGw~tpB zm9&RmX(StODSRF~Ln{fk8#p7P%pm-2b{ zw*Ex_0F7nnw#_B&t0zd=U5G`^zT>v zSEt3PL1^+jua?BATz4MzL8RxcYhOP74hcO16a1@IkCdvfK7Q=Yw~jk_Ryal!di6f$ zl1B732bw);8c%wc1#JrUXE(2CMq9zCX^fHGs|P6DD>tb0KD~`y)Ac90LYGjzz1n^F z*kB)ZJ;(B^(>HpdEZvEv&h2R(@SB`eXRV83UTVxzgIH$c2dzsD);rZ9&X$J6&5=d3 z{P?W)x&?4eExh@0&1jAp!o$oS)OjA&s9~h?YiUSIW^jwzp0QQ$CX_?%SveG>R9Nao zO0puwI7eAI514=@F4~`E8!22lh<4Ko)q=Fv6-kB4%(c$l}xXe--ai)`6q69RQ6HO+n z!ZY>P3t&ffbp!d=He24bHT$tGz=aN0E~I~Zy<@Z1Qr1URHE5E%@ldn-)Nb_)JyJ%N zCTS`*lAvil>Nk?KNOmV_Dl;MVs0@`GNmh_pvSjzB7x${|C(@c<=}yD3IeKY&fVClN zEHYx=^xfX|7V+yqYAhBe-ATLNqTNawiwv7}I5!!n0jCC~VOX-JwKUtnn2J+{{uVvG zs~K9QMyYxeDBWsxh}B^mkzCES0*u_xZMY)T!?8LkYnZaq2y=qWeVC6n`~i7Pu7V#$2eWvVUt zq}@#-i~4xanBPHHDwdkxEQ{ZRSAflImWDEVfTfTo^Mk~y#{Tlr-V%t#@!fVtreu( z&1bmOjy_1pBp#xmWcIB~l>Pj;>A3#@I*_D4MBa&;jT zvF%8loSKJuat}Z{3Yt2`PUaFs>&T~yjZP^`)@;H^aWxCIBRxSQ=Cf#?PlR zXYMMYAoO4kf1M{3mZznc;6Alc!Re*$cZNz~lDQo#S(X-&ZyHIE;|Dn^K*!};+HRn3 zqmaH8)rrTV_NNyejces~u<5q0ms3@wsM<=Wb9W88t6WVSNX#P)>;NoI0Q!?oFY8?j z4%aypO4`z_mcWn;1^^#GYd1rIl&shrHWcgMiq*I~;$e*O$JVLo!)3lX&P_v)zIxPZ zwS{r>EXdr};raY6p5h{ZBV6=`x?3%i_Kdv#y_wN!IZJ64gp*r#T!&ZQ+umvl@WPjN`bxiajHxfrW@ zgNhqbyBrINKRVtsGxkrTI(BR+W5V|*psY<#SXEYz&9cXXAm~1xzgot)xRzu4*&Y7? z-fY!L9~{+lH?gE>_a4tsJJTLYf#l+a6MGM7Dkpl0sgQd0t1;T3>z1o2ZyrAGKN{Z5##IqsHR7fR6(d2%$bSP+HbKGQ z)V&OwxhCvW8cK||DmH48Y(3wKf!>FHDh7InH4?4%tz%|N-CjW(58yAB{D(EjYW^mg z;&8fgXrqntvI0Xt9SWW?T?dGC@u^rmaim{p1Q^};!OyR_;=J@m%EU1$LBR*H6rP9B zZpT z4??GdSWPqNp%}+yVpu@h+~*l2)#y_JM|!Wb7;b|gKhrg%Y=z`F83W}XUiE|5QfkXX zKgIAJR_jO7LlCmh_NmJDiZRdT%%kzHjJ`?jSz2&et}ZnJ$e0MBKlI5-!T$h(F=qO0 ztNG7PO?y&rl|}UY&x@ArB0|JeagB?&+|q8R&cn?4PDNuVzI1B`Xf^0D>vO{g{SthW z{OZ$&Z#* z4WDtr{*}z!RHb!u*uz!kf@N2bih)+5SITl$J?y6x#*VEOrZU$InesfvR!WSeT4ku%Rt=P-RAs2yYRig+ z$6AY;DHWVlE-J%{f=-obmZU)bl*1W4PAb4%qbKiwDr4|#q6n^HyF{b8s`5qXe>$@v zs9md~DHNM1$_kt{R*|awxFCbj)@{eg5A&h)Z9 zRgy~4M9~WGj`ah-y)oXPcg1L;RfoIvsF~@E^$~i}A*4uNnp&bQO)XBvSdhIY>Wg(L zYIYeRYBy9_rQJnG0jX@ngUR!Qkam# z<~A|%j!j-v0ALIO=}BuIBhRU;AuG0%vJ;)i)oN83rv*K!`*^L?h`AF~Q%Ajh$4Z@s zDmJRPCT6+jp<`AqhS?9H=BhdCShuO7)N8du?M`D+H7k~o(obsSd_km$XA@dQBP){5 z0+tGM*YW1M;A@%IHH*luWPu?N061p(n2%A|Q7574<(}16{nyOHkLXQVRW2|>9h5&NgrHVf�BbB=^JBCLIt<Q8Ryj0aG4aS zDvVD|5wUqBwq?6E*?keRQs}`yAD;;-<;q$cCbxgcReshcu z;`;Gi4a4U(-syURYIY~g!IehIQ`feBhPaJ)O`A@b?#o+~@=4f_L+F2HC2@_?qG82KY9`{alPNMM>rlN+^#fLSG)#g@hZ$~aXQ-5X z--T%hsiI?Fy;pv9uP{(W^s2J6xT0*nbWvQ%xDq}TT zL$LDHg{nN#6Hdb<-9~CW&rMuMBnF+Di!`9p3lip>4Mmzz)T~J^aZe3U15XV~!D4l4ky{m6PdwDBeW_TMTaBvJ zP484=HEt8qrJ*xQ1Jbl@>n;PFR-Ls(k(A9_degTRn{C>)ZN+5K%QjzudR5q#s=-&{ ztfX^ElA_eey(zKOtHBkEMh%a}F@;D-rZK3JGr1E~PxPr6)NE^-O2fGe3W?JyYG$Uk z2sF;vo#QUO5~x{$6{ zVNo!v3@Rrab6O@+W@YX?&%&ulD&*&LvF+NbN#3z?yEab6cBq=AlAva$nW|$=avmhO z6KY!)HwGoxNf_PEay_f7mP{!iZXk5dGh9xiCB(Xfrt4zL2vQW}FB}0?KZN$OXkN3I zWHvp=7}`G^)r2mjV52eUFhx~X#xU$j=m8(CTen@Vq>{|Qf_;5It#e6RR(&ga8W!ua zRLRM3K|bS={cBDEiPVnkkI4T3_3Jr0#(f-Cls|qm^{Gb zg>3|m6cWX@_4*3sukU5Pm&~{knNL?l3QyM^YRp)7c$y3?eF4>@GFxQ9DTmhx{3eGft^ z*=np)wam+D=CimHK-h7?2cr)|?OSo{w$rIgxQtmCIUCgf0H1MLEgpK)q0{HO-S&8y z_Wj~I55}^oN;1|%nuPU{CDx0l-U9Y=h{^u|o@^O^F4d25;k$tNS>Y?{au4NGO>R-h zDpkS3>_tQ_E@5C&X$T*}SdeNxm00`|zp1QcQY+n&i+`ufWj~iT(n!cEatNs5hbFom zVFk*;GLA8irg^H6Tld9nMx&e)mgcdpa|)*@qKeulL`rjXs*;>hMQ;;CRetpY8Yrz%q9SAI zQIka#XtXyp1H}|j0h%*K6a|INC^S(_EG}t5qKZU|noww>fD{^B(M1gia5SN)qL2;- zmo!mQ0)t8o6i~!JbxMsz6oko;)yPd0RI(YNY-?8AwG>ut#%8st=~~w3r4&|7<&mWc z;8oaACVT8b;0XbAUHWNZ(u6jv=xfia6x ztrS-=M5)09bro_p4aa{mCpfA%GUp+BcQjE>ZLJMrQIPej z(wZo!MyRPNs`45rtzu~stdE0ScBdLgs7#1UoaFC4&nAj0rLpd0t@~EIgp6Suxg(Q~ zwRS(ezf=6EqPXPlPBgnbw4D)qGJXEB}_bob+$D669tB=6B4UM_AeTdOaqCKhp! z+1?2D{{ZV&i`*M~NoFV?%2MDC17rD7MG)1a&#tsMmms?p7zC0Br?n<%qP?3~^T)KZ zG;15lBSwcRg^5)@!=S5LW5>RDW^IXa8IN~hatf39iYTa-#I80@c8^OB>{{So@Na@m>1n_U#?XdPO(Ec=0SSQI*#yb-x)3P<9OaWG71BxiFk{h}I E*%*(DtpET3 diff --git a/third_party/python/Click/examples/imagepipe/imagepipe.py b/third_party/python/Click/examples/imagepipe/imagepipe.py deleted file mode 100644 index 37a152113367..000000000000 --- a/third_party/python/Click/examples/imagepipe/imagepipe.py +++ /dev/null @@ -1,266 +0,0 @@ -import click -from functools import update_wrapper -from PIL import Image, ImageFilter, ImageEnhance - - -@click.group(chain=True) -def cli(): - """This script processes a bunch of images through pillow in a unix - pipe. One commands feeds into the next. - - Example: - - \b - imagepipe open -i example01.jpg resize -w 128 display - imagepipe open -i example02.jpg blur save - """ - - -@cli.resultcallback() -def process_commands(processors): - """This result callback is invoked with an iterable of all the chained - subcommands. As in this example each subcommand returns a function - we can chain them together to feed one into the other, similar to how - a pipe on unix works. - """ - # Start with an empty iterable. - stream = () - - # Pipe it through all stream processors. - for processor in processors: - stream = processor(stream) - - # Evaluate the stream and throw away the items. - for _ in stream: - pass - - -def processor(f): - """Helper decorator to rewrite a function so that it returns another - function from it. - """ - def new_func(*args, **kwargs): - def processor(stream): - return f(stream, *args, **kwargs) - return processor - return update_wrapper(new_func, f) - - -def generator(f): - """Similar to the :func:`processor` but passes through old values - unchanged and does not pass through the values as parameter. - """ - @processor - def new_func(stream, *args, **kwargs): - for item in stream: - yield item - for item in f(*args, **kwargs): - yield item - return update_wrapper(new_func, f) - - -def copy_filename(new, old): - new.filename = old.filename - return new - - -@cli.command('open') -@click.option('-i', '--image', 'images', type=click.Path(), - multiple=True, help='The image file to open.') -@generator -def open_cmd(images): - """Loads one or multiple images for processing. The input parameter - can be specified multiple times to load more than one image. - """ - for image in images: - try: - click.echo('Opening "%s"' % image) - if image == '-': - img = Image.open(click.get_binary_stdin()) - img.filename = '-' - else: - img = Image.open(image) - yield img - except Exception as e: - click.echo('Could not open image "%s": %s' % (image, e), err=True) - - -@cli.command('save') -@click.option('--filename', default='processed-%04d.png', type=click.Path(), - help='The format for the filename.', - show_default=True) -@processor -def save_cmd(images, filename): - """Saves all processed images to a series of files.""" - for idx, image in enumerate(images): - try: - fn = filename % (idx + 1) - click.echo('Saving "%s" as "%s"' % (image.filename, fn)) - yield image.save(fn) - except Exception as e: - click.echo('Could not save image "%s": %s' % - (image.filename, e), err=True) - - -@cli.command('display') -@processor -def display_cmd(images): - """Opens all images in an image viewer.""" - for image in images: - click.echo('Displaying "%s"' % image.filename) - image.show() - yield image - - -@cli.command('resize') -@click.option('-w', '--width', type=int, help='The new width of the image.') -@click.option('-h', '--height', type=int, help='The new height of the image.') -@processor -def resize_cmd(images, width, height): - """Resizes an image by fitting it into the box without changing - the aspect ratio. - """ - for image in images: - w, h = (width or image.size[0], height or image.size[1]) - click.echo('Resizing "%s" to %dx%d' % (image.filename, w, h)) - image.thumbnail((w, h)) - yield image - - -@cli.command('crop') -@click.option('-b', '--border', type=int, help='Crop the image from all ' - 'sides by this amount.') -@processor -def crop_cmd(images, border): - """Crops an image from all edges.""" - for image in images: - box = [0, 0, image.size[0], image.size[1]] - - if border is not None: - for idx, val in enumerate(box): - box[idx] = max(0, val - border) - click.echo('Cropping "%s" by %dpx' % (image.filename, border)) - yield copy_filename(image.crop(box), image) - else: - yield image - - -def convert_rotation(ctx, param, value): - if value is None: - return - value = value.lower() - if value in ('90', 'r', 'right'): - return (Image.ROTATE_90, 90) - if value in ('180', '-180'): - return (Image.ROTATE_180, 180) - if value in ('-90', '270', 'l', 'left'): - return (Image.ROTATE_270, 270) - raise click.BadParameter('invalid rotation "%s"' % value) - - -def convert_flip(ctx, param, value): - if value is None: - return - value = value.lower() - if value in ('lr', 'leftright'): - return (Image.FLIP_LEFT_RIGHT, 'left to right') - if value in ('tb', 'topbottom', 'upsidedown', 'ud'): - return (Image.FLIP_LEFT_RIGHT, 'top to bottom') - raise click.BadParameter('invalid flip "%s"' % value) - - -@cli.command('transpose') -@click.option('-r', '--rotate', callback=convert_rotation, - help='Rotates the image (in degrees)') -@click.option('-f', '--flip', callback=convert_flip, - help='Flips the image [LR / TB]') -@processor -def transpose_cmd(images, rotate, flip): - """Transposes an image by either rotating or flipping it.""" - for image in images: - if rotate is not None: - mode, degrees = rotate - click.echo('Rotate "%s" by %ddeg' % (image.filename, degrees)) - image = copy_filename(image.transpose(mode), image) - if flip is not None: - mode, direction = flip - click.echo('Flip "%s" %s' % (image.filename, direction)) - image = copy_filename(image.transpose(mode), image) - yield image - - -@cli.command('blur') -@click.option('-r', '--radius', default=2, show_default=True, - help='The blur radius.') -@processor -def blur_cmd(images, radius): - """Applies gaussian blur.""" - blur = ImageFilter.GaussianBlur(radius) - for image in images: - click.echo('Blurring "%s" by %dpx' % (image.filename, radius)) - yield copy_filename(image.filter(blur), image) - - -@cli.command('smoothen') -@click.option('-i', '--iterations', default=1, show_default=True, - help='How many iterations of the smoothen filter to run.') -@processor -def smoothen_cmd(images, iterations): - """Applies a smoothening filter.""" - for image in images: - click.echo('Smoothening "%s" %d time%s' % - (image.filename, iterations, iterations != 1 and 's' or '',)) - for x in xrange(iterations): - image = copy_filename(image.filter(ImageFilter.BLUR), image) - yield image - - -@cli.command('emboss') -@processor -def emboss_cmd(images): - """Embosses an image.""" - for image in images: - click.echo('Embossing "%s"' % image.filename) - yield copy_filename(image.filter(ImageFilter.EMBOSS), image) - - -@cli.command('sharpen') -@click.option('-f', '--factor', default=2.0, - help='Sharpens the image.', show_default=True) -@processor -def sharpen_cmd(images, factor): - """Sharpens an image.""" - for image in images: - click.echo('Sharpen "%s" by %f' % (image.filename, factor)) - enhancer = ImageEnhance.Sharpness(image) - yield copy_filename(enhancer.enhance(max(1.0, factor)), image) - - -@cli.command('paste') -@click.option('-l', '--left', default=0, help='Offset from left.') -@click.option('-r', '--right', default=0, help='Offset from right.') -@processor -def paste_cmd(images, left, right): - """Pastes the second image on the first image and leaves the rest - unchanged. - """ - imageiter = iter(images) - image = next(imageiter, None) - to_paste = next(imageiter, None) - - if to_paste is None: - if image is not None: - yield image - return - - click.echo('Paste "%s" on "%s"' % - (to_paste.filename, image.filename)) - mask = None - if to_paste.mode == 'RGBA' or 'transparency' in to_paste.info: - mask = to_paste - image.paste(to_paste, (left, right), mask) - image.filename += '+' + to_paste.filename - yield image - - for image in imageiter: - yield image diff --git a/third_party/python/Click/examples/imagepipe/setup.py b/third_party/python/Click/examples/imagepipe/setup.py deleted file mode 100644 index d2d8d9911a24..000000000000 --- a/third_party/python/Click/examples/imagepipe/setup.py +++ /dev/null @@ -1,16 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-imagepipe', - version='1.0', - py_modules=['imagepipe'], - include_package_data=True, - install_requires=[ - 'click', - 'pillow', - ], - entry_points=''' - [console_scripts] - imagepipe=imagepipe:cli - ''', -) diff --git a/third_party/python/Click/examples/inout/README b/third_party/python/Click/examples/inout/README deleted file mode 100644 index 6309bc873e0f..000000000000 --- a/third_party/python/Click/examples/inout/README +++ /dev/null @@ -1,10 +0,0 @@ -$ inout_ - - inout is a simple example of an application that - can read from files and write to files but also - accept input from stdin or write to stdout. - -Usage: - - $ pip install --editable . - $ inout input_file.txt output_file.txt diff --git a/third_party/python/Click/examples/inout/inout.py b/third_party/python/Click/examples/inout/inout.py deleted file mode 100644 index b93f306629fa..000000000000 --- a/third_party/python/Click/examples/inout/inout.py +++ /dev/null @@ -1,30 +0,0 @@ -import click - - -@click.command() -@click.argument('input', type=click.File('rb'), nargs=-1) -@click.argument('output', type=click.File('wb')) -def cli(input, output): - """This script works similar to the Unix `cat` command but it writes - into a specific file (which could be the standard output as denoted by - the ``-`` sign). - - \b - Copy stdin to stdout: - inout - - - - \b - Copy foo.txt and bar.txt to stdout: - inout foo.txt bar.txt - - - \b - Write stdin into the file foo.txt - inout - foo.txt - """ - for f in input: - while True: - chunk = f.read(1024) - if not chunk: - break - output.write(chunk) - output.flush() diff --git a/third_party/python/Click/examples/inout/setup.py b/third_party/python/Click/examples/inout/setup.py deleted file mode 100644 index 5c613646e2c0..000000000000 --- a/third_party/python/Click/examples/inout/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-inout', - version='0.1', - py_modules=['inout'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - inout=inout:cli - ''', -) diff --git a/third_party/python/Click/examples/naval/README b/third_party/python/Click/examples/naval/README deleted file mode 100644 index aa289a28e702..000000000000 --- a/third_party/python/Click/examples/naval/README +++ /dev/null @@ -1,14 +0,0 @@ -$ naval_ - - naval is a simple example of an application that - is ported from the docopt example of the same name. - - Unlike the original this one also runs some code and - prints messages and it's command line interface was - changed slightly to make more sense with established - POSIX semantics. - -Usage: - - $ pip install --editable . - $ naval --help diff --git a/third_party/python/Click/examples/naval/naval.py b/third_party/python/Click/examples/naval/naval.py deleted file mode 100644 index 2d173d84bd0c..000000000000 --- a/third_party/python/Click/examples/naval/naval.py +++ /dev/null @@ -1,70 +0,0 @@ -import click - - -@click.group() -@click.version_option() -def cli(): - """Naval Fate. - - This is the docopt example adopted to Click but with some actual - commands implemented and not just the empty parsing which really - is not all that interesting. - """ - - -@cli.group() -def ship(): - """Manages ships.""" - - -@ship.command('new') -@click.argument('name') -def ship_new(name): - """Creates a new ship.""" - click.echo('Created ship %s' % name) - - -@ship.command('move') -@click.argument('ship') -@click.argument('x', type=float) -@click.argument('y', type=float) -@click.option('--speed', metavar='KN', default=10, - help='Speed in knots.') -def ship_move(ship, x, y, speed): - """Moves SHIP to the new location X,Y.""" - click.echo('Moving ship %s to %s,%s with speed %s' % (ship, x, y, speed)) - - -@ship.command('shoot') -@click.argument('ship') -@click.argument('x', type=float) -@click.argument('y', type=float) -def ship_shoot(ship, x, y): - """Makes SHIP fire to X,Y.""" - click.echo('Ship %s fires to %s,%s' % (ship, x, y)) - - -@cli.group('mine') -def mine(): - """Manages mines.""" - - -@mine.command('set') -@click.argument('x', type=float) -@click.argument('y', type=float) -@click.option('ty', '--moored', flag_value='moored', - default=True, - help='Moored (anchored) mine. Default.') -@click.option('ty', '--drifting', flag_value='drifting', - help='Drifting mine.') -def mine_set(x, y, ty): - """Sets a mine at a specific coordinate.""" - click.echo('Set %s mine at %s,%s' % (ty, x, y)) - - -@mine.command('remove') -@click.argument('x', type=float) -@click.argument('y', type=float) -def mine_remove(x, y): - """Removes a mine at a specific coordinate.""" - click.echo('Removed mine at %s,%s' % (x, y)) diff --git a/third_party/python/Click/examples/naval/setup.py b/third_party/python/Click/examples/naval/setup.py deleted file mode 100644 index 124addf4305c..000000000000 --- a/third_party/python/Click/examples/naval/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-naval', - version='2.0', - py_modules=['naval'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - naval=naval:cli - ''', -) diff --git a/third_party/python/Click/examples/repo/README b/third_party/python/Click/examples/repo/README deleted file mode 100644 index 52d1fa7d0be9..000000000000 --- a/third_party/python/Click/examples/repo/README +++ /dev/null @@ -1,9 +0,0 @@ -$ repo_ - - repo is a simple example of an application that looks - and works similar to hg or git. - -Usage: - - $ pip install --editable . - $ repo --help diff --git a/third_party/python/Click/examples/repo/repo.py b/third_party/python/Click/examples/repo/repo.py deleted file mode 100644 index 2b1992d3e896..000000000000 --- a/third_party/python/Click/examples/repo/repo.py +++ /dev/null @@ -1,151 +0,0 @@ -import os -import sys -import posixpath - -import click - - -class Repo(object): - - def __init__(self, home): - self.home = home - self.config = {} - self.verbose = False - - def set_config(self, key, value): - self.config[key] = value - if self.verbose: - click.echo(' config[%s] = %s' % (key, value), file=sys.stderr) - - def __repr__(self): - return '' % self.home - - -pass_repo = click.make_pass_decorator(Repo) - - -@click.group() -@click.option('--repo-home', envvar='REPO_HOME', default='.repo', - metavar='PATH', help='Changes the repository folder location.') -@click.option('--config', nargs=2, multiple=True, - metavar='KEY VALUE', help='Overrides a config key/value pair.') -@click.option('--verbose', '-v', is_flag=True, - help='Enables verbose mode.') -@click.version_option('1.0') -@click.pass_context -def cli(ctx, repo_home, config, verbose): - """Repo is a command line tool that showcases how to build complex - command line interfaces with Click. - - This tool is supposed to look like a distributed version control - system to show how something like this can be structured. - """ - # Create a repo object and remember it as as the context object. From - # this point onwards other commands can refer to it by using the - # @pass_repo decorator. - ctx.obj = Repo(os.path.abspath(repo_home)) - ctx.obj.verbose = verbose - for key, value in config: - ctx.obj.set_config(key, value) - - -@cli.command() -@click.argument('src') -@click.argument('dest', required=False) -@click.option('--shallow/--deep', default=False, - help='Makes a checkout shallow or deep. Deep by default.') -@click.option('--rev', '-r', default='HEAD', - help='Clone a specific revision instead of HEAD.') -@pass_repo -def clone(repo, src, dest, shallow, rev): - """Clones a repository. - - This will clone the repository at SRC into the folder DEST. If DEST - is not provided this will automatically use the last path component - of SRC and create that folder. - """ - if dest is None: - dest = posixpath.split(src)[-1] or '.' - click.echo('Cloning repo %s to %s' % (src, os.path.abspath(dest))) - repo.home = dest - if shallow: - click.echo('Making shallow checkout') - click.echo('Checking out revision %s' % rev) - - -@cli.command() -@click.confirmation_option() -@pass_repo -def delete(repo): - """Deletes a repository. - - This will throw away the current repository. - """ - click.echo('Destroying repo %s' % repo.home) - click.echo('Deleted!') - - -@cli.command() -@click.option('--username', prompt=True, - help='The developer\'s shown username.') -@click.option('--email', prompt='E-Mail', - help='The developer\'s email address') -@click.password_option(help='The login password.') -@pass_repo -def setuser(repo, username, email, password): - """Sets the user credentials. - - This will override the current user config. - """ - repo.set_config('username', username) - repo.set_config('email', email) - repo.set_config('password', '*' * len(password)) - click.echo('Changed credentials.') - - -@cli.command() -@click.option('--message', '-m', multiple=True, - help='The commit message. If provided multiple times each ' - 'argument gets converted into a new line.') -@click.argument('files', nargs=-1, type=click.Path()) -@pass_repo -def commit(repo, files, message): - """Commits outstanding changes. - - Commit changes to the given files into the repository. You will need to - "repo push" to push up your changes to other repositories. - - If a list of files is omitted, all changes reported by "repo status" - will be committed. - """ - if not message: - marker = '# Files to be committed:' - hint = ['', '', marker, '#'] - for file in files: - hint.append('# U %s' % file) - message = click.edit('\n'.join(hint)) - if message is None: - click.echo('Aborted!') - return - msg = message.split(marker)[0].rstrip() - if not msg: - click.echo('Aborted! Empty commit message') - return - else: - msg = '\n'.join(message) - click.echo('Files to be committed: %s' % (files,)) - click.echo('Commit message:\n' + msg) - - -@cli.command(short_help='Copies files.') -@click.option('--force', is_flag=True, - help='forcibly copy over an existing managed file') -@click.argument('src', nargs=-1, type=click.Path()) -@click.argument('dst', type=click.Path()) -@pass_repo -def copy(repo, src, dst, force): - """Copies one or multiple files to a new location. This copies all - files from SRC to DST. - """ - for fn in src: - click.echo('Copy from %s -> %s' % (fn, dst)) diff --git a/third_party/python/Click/examples/repo/setup.py b/third_party/python/Click/examples/repo/setup.py deleted file mode 100644 index 19aab7087a4a..000000000000 --- a/third_party/python/Click/examples/repo/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-repo', - version='0.1', - py_modules=['repo'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - repo=repo:cli - ''', -) diff --git a/third_party/python/Click/examples/termui/README b/third_party/python/Click/examples/termui/README deleted file mode 100644 index 2c9d9dd045e9..000000000000 --- a/third_party/python/Click/examples/termui/README +++ /dev/null @@ -1,9 +0,0 @@ -$ termui_ - - termui showcases the different terminal UI helpers that - Click provides. - -Usage: - - $ pip install --editable . - $ termui --help diff --git a/third_party/python/Click/examples/termui/setup.py b/third_party/python/Click/examples/termui/setup.py deleted file mode 100644 index 14558e85c185..000000000000 --- a/third_party/python/Click/examples/termui/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-termui', - version='1.0', - py_modules=['termui'], - include_package_data=True, - install_requires=[ - 'click', - # Colorama is only required for Windows. - 'colorama', - ], - entry_points=''' - [console_scripts] - termui=termui:cli - ''', -) diff --git a/third_party/python/Click/examples/termui/termui.py b/third_party/python/Click/examples/termui/termui.py deleted file mode 100644 index 793afa419bdc..000000000000 --- a/third_party/python/Click/examples/termui/termui.py +++ /dev/null @@ -1,156 +0,0 @@ -# coding: utf-8 -import click -import math -import time -import random - -try: - range_type = xrange -except NameError: - range_type = range - - -@click.group() -def cli(): - """This script showcases different terminal UI helpers in Click.""" - pass - - -@cli.command() -def colordemo(): - """Demonstrates ANSI color support.""" - for color in 'red', 'green', 'blue': - click.echo(click.style('I am colored %s' % color, fg=color)) - click.echo(click.style('I am background colored %s' % color, bg=color)) - - -@cli.command() -def pager(): - """Demonstrates using the pager.""" - lines = [] - for x in range_type(200): - lines.append('%s. Hello World!' % click.style(str(x), fg='green')) - click.echo_via_pager('\n'.join(lines)) - - -@cli.command() -@click.option('--count', default=8000, type=click.IntRange(1, 100000), - help='The number of items to process.') -def progress(count): - """Demonstrates the progress bar.""" - items = range_type(count) - - def process_slowly(item): - time.sleep(0.002 * random.random()) - - def filter(items): - for item in items: - if random.random() > 0.3: - yield item - - with click.progressbar(items, label='Processing accounts', - fill_char=click.style('#', fg='green')) as bar: - for item in bar: - process_slowly(item) - - def show_item(item): - if item is not None: - return 'Item #%d' % item - - with click.progressbar(filter(items), label='Committing transaction', - fill_char=click.style('#', fg='yellow'), - item_show_func=show_item) as bar: - for item in bar: - process_slowly(item) - - with click.progressbar(length=count, label='Counting', - bar_template='%(label)s %(bar)s | %(info)s', - fill_char=click.style(u'█', fg='cyan'), - empty_char=' ') as bar: - for item in bar: - process_slowly(item) - - with click.progressbar(length=count, width=0, show_percent=False, - show_eta=False, - fill_char=click.style('#', fg='magenta')) as bar: - for item in bar: - process_slowly(item) - - # 'Non-linear progress bar' - steps = [math.exp( x * 1. / 20) - 1 for x in range(20)] - count = int(sum(steps)) - with click.progressbar(length=count, show_percent=False, - label='Slowing progress bar', - fill_char=click.style(u'█', fg='green')) as bar: - for item in steps: - time.sleep(item) - bar.update(item) - - -@cli.command() -@click.argument('url') -def open(url): - """Opens a file or URL In the default application.""" - click.launch(url) - - -@cli.command() -@click.argument('url') -def locate(url): - """Opens a file or URL In the default application.""" - click.launch(url, locate=True) - - -@cli.command() -def edit(): - """Opens an editor with some text in it.""" - MARKER = '# Everything below is ignored\n' - message = click.edit('\n\n' + MARKER) - if message is not None: - msg = message.split(MARKER, 1)[0].rstrip('\n') - if not msg: - click.echo('Empty message!') - else: - click.echo('Message:\n' + msg) - else: - click.echo('You did not enter anything!') - - -@cli.command() -def clear(): - """Clears the entire screen.""" - click.clear() - - -@cli.command() -def pause(): - """Waits for the user to press a button.""" - click.pause() - - -@cli.command() -def menu(): - """Shows a simple menu.""" - menu = 'main' - while 1: - if menu == 'main': - click.echo('Main menu:') - click.echo(' d: debug menu') - click.echo(' q: quit') - char = click.getchar() - if char == 'd': - menu = 'debug' - elif char == 'q': - menu = 'quit' - else: - click.echo('Invalid input') - elif menu == 'debug': - click.echo('Debug menu') - click.echo(' b: back') - char = click.getchar() - if char == 'b': - menu = 'main' - else: - click.echo('Invalid input') - elif menu == 'quit': - return diff --git a/third_party/python/Click/examples/validation/README b/third_party/python/Click/examples/validation/README deleted file mode 100644 index a69e3f4276e6..000000000000 --- a/third_party/python/Click/examples/validation/README +++ /dev/null @@ -1,12 +0,0 @@ -$ validation_ - - validation is a simple example of an application that - performs custom validation of parameters in different - ways. - - This example requires Click 2.0 or higher. - -Usage: - - $ pip install --editable . - $ validation --help diff --git a/third_party/python/Click/examples/validation/setup.py b/third_party/python/Click/examples/validation/setup.py deleted file mode 100644 index 9491f709c723..000000000000 --- a/third_party/python/Click/examples/validation/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -from setuptools import setup - -setup( - name='click-example-validation', - version='1.0', - py_modules=['validation'], - include_package_data=True, - install_requires=[ - 'click', - ], - entry_points=''' - [console_scripts] - validation=validation:cli - ''', -) diff --git a/third_party/python/Click/examples/validation/validation.py b/third_party/python/Click/examples/validation/validation.py deleted file mode 100644 index 00fa0a60011c..000000000000 --- a/third_party/python/Click/examples/validation/validation.py +++ /dev/null @@ -1,44 +0,0 @@ -import click -try: - from urllib import parse as urlparse -except ImportError: - import urlparse - - -def validate_count(ctx, param, value): - if value < 0 or value % 2 != 0: - raise click.BadParameter('Should be a positive, even integer.') - return value - - -class URL(click.ParamType): - name = 'url' - - def convert(self, value, param, ctx): - if not isinstance(value, tuple): - value = urlparse.urlparse(value) - if value.scheme not in ('http', 'https'): - self.fail('invalid URL scheme (%s). Only HTTP URLs are ' - 'allowed' % value.scheme, param, ctx) - return value - - -@click.command() -@click.option('--count', default=2, callback=validate_count, - help='A positive even number.') -@click.option('--foo', help='A mysterious parameter.') -@click.option('--url', help='A URL', type=URL()) -@click.version_option() -def cli(count, foo, url): - """Validation. - - This example validates parameters in different ways. It does it - through callbacks, through a custom type as well as by validating - manually in the function. - """ - if foo is not None and foo != 'wat': - raise click.BadParameter('If a value is provided it needs to be the ' - 'value "wat".', param_hint=['--foo']) - click.echo('count: %s' % count) - click.echo('foo: %s' % foo) - click.echo('url: %s' % repr(url)) diff --git a/third_party/python/Click/setup.cfg b/third_party/python/Click/setup.cfg deleted file mode 100644 index 525a9e744700..000000000000 --- a/third_party/python/Click/setup.cfg +++ /dev/null @@ -1,25 +0,0 @@ -[metadata] -license_file = LICENSE.rst - -[bdist_wheel] -universal = 1 - -[tool:pytest] -testpaths = tests - -[coverage:run] -branch = True -source = - click - tests - -[coverage:paths] -source = - click - .tox/*/lib/python*/site-packages/click - .tox/pypy/site-packages/click - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/Click/setup.py b/third_party/python/Click/setup.py deleted file mode 100644 index 1c18dc7843d4..000000000000 --- a/third_party/python/Click/setup.py +++ /dev/null @@ -1,44 +0,0 @@ -import io -import re -from setuptools import setup - -with io.open("README.rst", "rt", encoding="utf8") as f: - readme = f.read() - -with io.open("click/__init__.py", "rt", encoding="utf8") as f: - version = re.search(r"__version__ = \'(.*?)\'", f.read()).group(1) - -setup( - name="Click", - version=version, - url="https://palletsprojects.com/p/click/", - project_urls={ - "Documentation": "https://click.palletsprojects.com/", - "Code": "https://github.com/pallets/click", - "Issue tracker": "https://github.com/pallets/click/issues", - }, - license="BSD", - author="Armin Ronacher", - author_email="armin.ronacher@active-4.com", - maintainer="Pallets Team", - maintainer_email="contact@palletsprojects.com", - description="Composable command line interface toolkit", - long_description=readme, - packages=["click"], - include_package_data=True, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - ], -) diff --git a/third_party/python/Click/tox.ini b/third_party/python/Click/tox.ini deleted file mode 100644 index a44b11070229..000000000000 --- a/third_party/python/Click/tox.ini +++ /dev/null @@ -1,39 +0,0 @@ -[tox] -envlist = - py{37,36,35,34,27,py3,py} - docs-html - coverage-report -skip_missing_interpreters = true - -[testenv] -passenv = LANG -deps = - pytest - coverage - colorama -commands = coverage run -p -m pytest {posargs} - -[testenv:docs-html] -deps = -r docs/requirements.txt -commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html - -[testenv:docs-linkcheck] -deps = -r docs/requirements.txt -commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs {envtmpdir}/linkcheck - -[testenv:coverage-report] -deps = coverage -skip_install = true -commands = - coverage combine - coverage report - coverage html - -[testenv:codecov] -passenv = CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* -deps = codecov -skip_install = true -commands = - coverage combine - coverage report - codecov diff --git a/third_party/python/Jinja2/CHANGES.rst b/third_party/python/Jinja2/CHANGES.rst deleted file mode 100644 index 511b22be6339..000000000000 --- a/third_party/python/Jinja2/CHANGES.rst +++ /dev/null @@ -1,784 +0,0 @@ -.. currentmodule:: jinja2 - -Version 2.11.3 --------------- - -Released 2021-01-31 - -- Improve the speed of the ``urlize`` filter by reducing regex - backtracking. Email matching requires a word character at the start - of the domain part, and only word characters in the TLD. :pr:`1343` - - -Version 2.11.2 --------------- - -Released 2020-04-13 - -- Fix a bug that caused callable objects with ``__getattr__``, like - :class:`~unittest.mock.Mock` to be treated as a - :func:`contextfunction`. :issue:`1145` -- Update ``wordcount`` filter to trigger :class:`Undefined` methods - by wrapping the input in :func:`soft_unicode`. :pr:`1160` -- Fix a hang when displaying tracebacks on Python 32-bit. - :issue:`1162` -- Showing an undefined error for an object that raises - ``AttributeError`` on access doesn't cause a recursion error. - :issue:`1177` -- Revert changes to :class:`~loaders.PackageLoader` from 2.10 which - removed the dependency on setuptools and pkg_resources, and added - limited support for namespace packages. The changes caused issues - when using Pytest. Due to the difficulty in supporting Python 2 and - :pep:`451` simultaneously, the changes are reverted until 3.0. - :pr:`1182` -- Fix line numbers in error messages when newlines are stripped. - :pr:`1178` -- The special ``namespace()`` assignment object in templates works in - async environments. :issue:`1180` -- Fix whitespace being removed before tags in the middle of lines when - ``lstrip_blocks`` is enabled. :issue:`1138` -- :class:`~nativetypes.NativeEnvironment` doesn't evaluate - intermediate strings during rendering. This prevents early - evaluation which could change the value of an expression. - :issue:`1186` - - -Version 2.11.1 --------------- - -Released 2020-01-30 - -- Fix a bug that prevented looking up a key after an attribute - (``{{ data.items[1:] }}``) in an async template. :issue:`1141` - - -Version 2.11.0 --------------- - -Released 2020-01-27 - -- Drop support for Python 2.6, 3.3, and 3.4. This will be the last - version to support Python 2.7 and 3.5. -- Added a new ``ChainableUndefined`` class to support getitem and - getattr on an undefined object. :issue:`977` -- Allow ``{%+`` syntax (with NOP behavior) when ``lstrip_blocks`` is - disabled. :issue:`748` -- Added a ``default`` parameter for the ``map`` filter. :issue:`557` -- Exclude environment globals from - :func:`meta.find_undeclared_variables`. :issue:`931` -- Float literals can be written with scientific notation, like - 2.56e-3. :issue:`912`, :pr:`922` -- Int and float literals can be written with the '_' separator for - legibility, like 12_345. :pr:`923` -- Fix a bug causing deadlocks in ``LRUCache.setdefault``. :pr:`1000` -- The ``trim`` filter takes an optional string of characters to trim. - :pr:`828` -- A new ``jinja2.ext.debug`` extension adds a ``{% debug %}`` tag to - quickly dump the current context and available filters and tests. - :issue:`174`, :pr:`798, 983` -- Lexing templates with large amounts of whitespace is much faster. - :issue:`857`, :pr:`858` -- Parentheses around comparisons are preserved, so - ``{{ 2 * (3 < 5) }}`` outputs "2" instead of "False". - :issue:`755`, :pr:`938` -- Add new ``boolean``, ``false``, ``true``, ``integer`` and ``float`` - tests. :pr:`824` -- The environment's ``finalize`` function is only applied to the - output of expressions (constant or not), not static template data. - :issue:`63` -- When providing multiple paths to ``FileSystemLoader``, a template - can have the same name as a directory. :issue:`821` -- Always return :class:`Undefined` when omitting the ``else`` clause - in a ``{{ 'foo' if bar }}`` expression, regardless of the - environment's ``undefined`` class. Omitting the ``else`` clause is a - valid shortcut and should not raise an error when using - :class:`StrictUndefined`. :issue:`710`, :pr:`1079` -- Fix behavior of ``loop`` control variables such as ``length`` and - ``revindex0`` when looping over a generator. :issue:`459, 751, 794`, - :pr:`993` -- Async support is only loaded the first time an environment enables - it, in order to avoid a slow initial import. :issue:`765` -- In async environments, the ``|map`` filter will await the filter - call if needed. :pr:`913` -- In for loops that access ``loop`` attributes, the iterator is not - advanced ahead of the current iteration unless ``length``, - ``revindex``, ``nextitem``, or ``last`` are accessed. This makes it - less likely to break ``groupby`` results. :issue:`555`, :pr:`1101` -- In async environments, the ``loop`` attributes ``length`` and - ``revindex`` work for async iterators. :pr:`1101` -- In async environments, values from attribute/property access will - be awaited if needed. :pr:`1101` -- :class:`~loader.PackageLoader` doesn't depend on setuptools or - pkg_resources. :issue:`970` -- ``PackageLoader`` has limited support for :pep:`420` namespace - packages. :issue:`1097` -- Support :class:`os.PathLike` objects in - :class:`~loader.FileSystemLoader` and :class:`~loader.ModuleLoader`. - :issue:`870` -- :class:`~nativetypes.NativeTemplate` correctly handles quotes - between expressions. ``"'{{ a }}', '{{ b }}'"`` renders as the tuple - ``('1', '2')`` rather than the string ``'1, 2'``. :issue:`1020` -- Creating a :class:`~nativetypes.NativeTemplate` directly creates a - :class:`~nativetypes.NativeEnvironment` instead of a default - :class:`Environment`. :issue:`1091` -- After calling ``LRUCache.copy()``, the copy's queue methods point to - the correct queue. :issue:`843` -- Compiling templates always writes UTF-8 instead of defaulting to the - system encoding. :issue:`889` -- ``|wordwrap`` filter treats existing newlines as separate paragraphs - to be wrapped individually, rather than creating short intermediate - lines. :issue:`175` -- Add ``break_on_hyphens`` parameter to ``|wordwrap`` filter. - :issue:`550` -- Cython compiled functions decorated as context functions will be - passed the context. :pr:`1108` -- When chained comparisons of constants are evaluated at compile time, - the result follows Python's behavior of returning ``False`` if any - comparison returns ``False``, rather than only the last one. - :issue:`1102` -- Tracebacks for exceptions in templates show the correct line numbers - and source for Python >= 3.7. :issue:`1104` -- Tracebacks for template syntax errors in Python 3 no longer show - internal compiler frames. :issue:`763` -- Add a ``DerivedContextReference`` node that can be used by - extensions to get the current context and local variables such as - ``loop``. :issue:`860` -- Constant folding during compilation is applied to some node types - that were previously overlooked. :issue:`733` -- ``TemplateSyntaxError.source`` is not empty when raised from an - included template. :issue:`457` -- Passing an ``Undefined`` value to ``get_template`` (such as through - ``extends``, ``import``, or ``include``), raises an - ``UndefinedError`` consistently. ``select_template`` will show the - undefined message in the list of attempts rather than the empty - string. :issue:`1037` -- ``TemplateSyntaxError`` can be pickled. :pr:`1117` - - -Version 2.10.3 --------------- - -Released 2019-10-04 - -- Fix a typo in Babel entry point in ``setup.py`` that was preventing - installation. - - -Version 2.10.2 --------------- - -Released 2019-10-04 - -- Fix Python 3.7 deprecation warnings. -- Using ``range`` in the sandboxed environment uses ``xrange`` on - Python 2 to avoid memory use. :issue:`933` -- Use Python 3.7's better traceback support to avoid a core dump when - using debug builds of Python 3.7. :issue:`1050` - - -Version 2.10.1 --------------- - -Released 2019-04-06 - -- ``SandboxedEnvironment`` securely handles ``str.format_map`` in - order to prevent code execution through untrusted format strings. - The sandbox already handled ``str.format``. - - -Version 2.10 ------------- - -Released 2017-11-08 - -- Added a new extension node called ``OverlayScope`` which can be used - to create an unoptimized scope that will look up all variables from - a derived context. -- Added an ``in`` test that works like the in operator. This can be - used in combination with ``reject`` and ``select``. -- Added ``previtem`` and ``nextitem`` to loop contexts, providing - access to the previous/next item in the loop. If such an item does - not exist, the value is undefined. -- Added ``changed(*values)`` to loop contexts, providing an easy way - of checking whether a value has changed since the last iteration (or - rather since the last call of the method) -- Added a ``namespace`` function that creates a special object which - allows attribute assignment using the ``set`` tag. This can be used - to carry data across scopes, e.g. from a loop body to code that - comes after the loop. -- Added a ``trimmed`` modifier to ``{% trans %}`` to strip linebreaks - and surrounding whitespace. Also added a new policy to enable this - for all ``trans`` blocks. -- The ``random`` filter is no longer incorrectly constant folded and - will produce a new random choice each time the template is rendered. - :pr:`478` -- Added a ``unique`` filter. :pr:`469` -- Added ``min`` and ``max`` filters. :pr:`475` -- Added tests for all comparison operators: ``eq``, ``ne``, ``lt``, - ``le``, ``gt``, ``ge``. :pr:`665` -- ``import`` statement cannot end with a trailing comma. :pr:`617`, - :pr:`618` -- ``indent`` filter will not indent blank lines by default. :pr:`685` -- Add ``reverse`` argument for ``dictsort`` filter. :pr:`692` -- Add a ``NativeEnvironment`` that renders templates to native Python - types instead of strings. :pr:`708` -- Added filter support to the block ``set`` tag. :pr:`489` -- ``tojson`` filter marks output as safe to match documented behavior. - :pr:`718` -- Resolved a bug where getting debug locals for tracebacks could - modify template context. -- Fixed a bug where having many ``{% elif ... %}`` blocks resulted in - a "too many levels of indentation" error. These blocks now compile - to native ``elif ..:`` instead of ``else: if ..:`` :issue:`759` - - -Version 2.9.6 -------------- - -Released 2017-04-03 - -- Fixed custom context behavior in fast resolve mode :issue:`675` - - -Version 2.9.5 -------------- - -Released 2017-01-28 - -- Restored the original repr of the internal ``_GroupTuple`` because - this caused issues with ansible and it was an unintended change. - :issue:`654` -- Added back support for custom contexts that override the old - ``resolve`` method since it was hard for people to spot that this - could cause a regression. -- Correctly use the buffer for the else block of for loops. This - caused invalid syntax errors to be caused on 2.x and completely - wrong behavior on Python 3 :issue:`669` -- Resolve an issue where the ``{% extends %}`` tag could not be used - with async environments. :issue:`668` -- Reduce memory footprint slightly by reducing our unicode database - dump we use for identifier matching on Python 3 :issue:`666` -- Fixed autoescaping not working for macros in async compilation mode. - :issue:`671` - - -Version 2.9.4 -------------- - -Released 2017-01-10 - -- Solved some warnings for string literals. :issue:`646` -- Increment the bytecode cache version which was not done due to an - oversight before. -- Corrected bad code generation and scoping for filtered loops. - :issue:`649` -- Resolved an issue where top-level output silencing after known - extend blocks could generate invalid code when blocks where - contained in if statements. :issue:`651` -- Made the ``truncate.leeway`` default configurable to improve - compatibility with older templates. - - -Version 2.9.3 -------------- - -Released 2017-01-08 - -- Restored the use of blocks in macros to the extend that was possible - before. On Python 3 it would render a generator repr instead of the - block contents. :issue:`645` -- Set a consistent behavior for assigning of variables in inner scopes - when the variable is also read from an outer scope. This now sets - the intended behavior in all situations however it does not restore - the old behavior where limited assignments to outer scopes was - possible. For more information and a discussion see :issue:`641` -- Resolved an issue where ``block scoped`` would not take advantage of - the new scoping rules. In some more exotic cases a variable - overriden in a local scope would not make it into a block. -- Change the code generation of the ``with`` statement to be in line - with the new scoping rules. This resolves some unlikely bugs in edge - cases. This also introduces a new internal ``With`` node that can be - used by extensions. - - -Version 2.9.2 -------------- - -Released 2017-01-08 - -- Fixed a regression that caused for loops to not be able to use the - same variable for the target as well as source iterator. - :issue:`640` -- Add support for a previously unknown behavior of macros. It used to - be possible in some circumstances to explicitly provide a caller - argument to macros. While badly buggy and unintended it turns out - that this is a common case that gets copy pasted around. To not - completely break backwards compatibility with the most common cases - it's now possible to provide an explicit keyword argument for caller - if it's given an explicit default. :issue:`642` - - -Version 2.9.1 -------------- - -Released 2017-01-07 - -- Resolved a regression with call block scoping for macros. Nested - caller blocks that used the same identifiers as outer macros could - refer to the wrong variable incorrectly. - - -Version 2.9 ------------ - -Released 2017-01-07, codename Derivation - -- Change cache key definition in environment. This fixes a performance - regression introduced in 2.8. -- Added support for ``generator_stop`` on supported Python versions - (Python 3.5 and later) -- Corrected a long standing issue with operator precedence of math - operations not being what was expected. -- Added support for Python 3.6 async iterators through a new async - mode. -- Added policies for filter defaults and similar things. -- Urlize now sets "rel noopener" by default. -- Support attribute fallback for old-style classes in 2.x. -- Support toplevel set statements in extend situations. -- Restored behavior of Cycler for Python 3 users. -- Subtraction now follows the same behavior as other operators on - undefined values. -- ``map`` and friends will now give better error messages if you - forgot to quote the parameter. -- Depend on MarkupSafe 0.23 or higher. -- Improved the ``truncate`` filter to support better truncation in - case the string is barely truncated at all. -- Change the logic for macro autoescaping to be based on the runtime - autoescaping information at call time instead of macro define time. -- Ported a modified version of the ``tojson`` filter from Flask to - Jinja and hooked it up with the new policy framework. -- Block sets are now marked ``safe`` by default. -- On Python 2 the asciification of ASCII strings can now be disabled - with the ``compiler.ascii_str`` policy. -- Tests now no longer accept an arbitrary expression as first argument - but a restricted one. This means that you can now properly use - multiple tests in one expression without extra parentheses. In - particular you can now write ``foo is divisibleby 2 or foo is - divisibleby 3`` as you would expect. -- Greatly changed the scoping system to be more consistent with what - template designers and developers expect. There is now no more magic - difference between the different include and import constructs. - Context is now always propagated the same way. The only remaining - differences is the defaults for ``with context`` and ``without - context``. -- The ``with`` and ``autoescape`` tags are now built-in. -- Added the new ``select_autoescape`` function which helps configuring - better autoescaping easier. -- Fixed a runtime error in the sandbox when attributes of async - generators were accessed. - - -Version 2.8.1 -------------- - -Released 2016-12-29 - -- Fixed the ``for_qs`` flag for ``urlencode``. -- Fixed regression when applying ``int`` to non-string values. -- SECURITY: if the sandbox mode is used format expressions are now - sandboxed with the same rules as in Jinja. This solves various - information leakage problems that can occur with format strings. - - -Version 2.8 ------------ - -Released 2015-07-26, codename Replacement - -- Added ``target`` parameter to urlize function. -- Added support for ``followsymlinks`` to the file system loader. -- The truncate filter now counts the length. -- Added equalto filter that helps with select filters. -- Changed cache keys to use absolute file names if available instead - of load names. -- Fixed loop length calculation for some iterators. -- Changed how Jinja enforces strings to be native strings in Python 2 - to work when people break their default encoding. -- Added ``make_logging_undefined`` which returns an undefined - object that logs failures into a logger. -- If unmarshalling of cached data fails the template will be reloaded - now. -- Implemented a block ``set`` tag. -- Default cache size was increased to 400 from a low 50. -- Fixed ``is number`` test to accept long integers in all Python - versions. -- Changed ``is number`` to accept Decimal as a number. -- Added a check for default arguments followed by non-default - arguments. This change makes ``{% macro m(x, y=1, z) %}`` a syntax - error. The previous behavior for this code was broken anyway - (resulting in the default value being applied to ``y``). -- Add ability to use custom subclasses of - ``jinja2.compiler.CodeGenerator`` and ``jinja2.runtime.Context`` by - adding two new attributes to the environment - (``code_generator_class`` and ``context_class``). :pr:`404` -- Added support for context/environment/evalctx decorator functions on - the finalize callback of the environment. -- Escape query strings for urlencode properly. Previously slashes were - not escaped in that place. -- Add 'base' parameter to 'int' filter. - - -Version 2.7.3 -------------- - -Released 2014-06-06 - -- Security issue: Corrected the security fix for the cache folder. - This fix was provided by RedHat. - - -Version 2.7.2 -------------- - -Released 2014-01-10 - -- Prefix loader was not forwarding the locals properly to inner - loaders. This is now fixed. -- Security issue: Changed the default folder for the filesystem cache - to be user specific and read and write protected on UNIX systems. - See `Debian bug 734747`_ for more information. - -.. _Debian bug 734747: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=734747 - - -Version 2.7.1 -------------- - -Released 2013-08-07 - -- Fixed a bug with ``call_filter`` not working properly on environment - and context filters. -- Fixed lack of Python 3 support for bytecode caches. -- Reverted support for defining blocks in included templates as this - broke existing templates for users. -- Fixed some warnings with hashing of undefineds and nodes if Python - is run with warnings for Python 3. -- Added support for properly hashing undefined objects. -- Fixed a bug with the title filter not working on already uppercase - strings. - - -Version 2.7 ------------ - -Released 2013-05-20, codename Translation - -- Choice and prefix loaders now dispatch source and template lookup - separately in order to work in combination with module loaders as - advertised. -- Fixed filesizeformat. -- Added a non-silent option for babel extraction. -- Added ``urlencode`` filter that automatically quotes values for URL - safe usage with utf-8 as only supported encoding. If applications - want to change this encoding they can override the filter. -- Added ``keep-trailing-newline`` configuration to environments and - templates to optionally preserve the final trailing newline. -- Accessing ``last`` on the loop context no longer causes the iterator - to be consumed into a list. -- Python requirement changed: 2.6, 2.7 or >= 3.3 are required now, - supported by same source code, using the "six" compatibility - library. -- Allow ``contextfunction`` and other decorators to be applied to - ``__call__``. -- Added support for changing from newline to different signs in the - ``wordwrap`` filter. -- Added support for ignoring memcache errors silently. -- Added support for keeping the trailing newline in templates. -- Added finer grained support for stripping whitespace on the left - side of blocks. -- Added ``map``, ``select``, ``reject``, ``selectattr`` and - ``rejectattr`` filters. -- Added support for ``loop.depth`` to figure out how deep inside a - recursive loop the code is. -- Disabled py_compile for pypy and python 3. - - -Version 2.6 ------------ - -Released 2011-07-24, codename Convolution - -- Internal attributes now raise an internal attribute error now - instead of returning an undefined. This fixes problems when passing - undefined objects to Python semantics expecting APIs. -- Traceback support now works properly for PyPy. (Tested with 1.4) -- Implemented operator intercepting for sandboxed environments. This - allows application developers to disable builtin operators for - better security. (For instance limit the mathematical operators to - actual integers instead of longs) -- Groupby filter now supports dotted notation for grouping by - attributes of attributes. -- Scoped blocks now properly treat toplevel assignments and imports. - Previously an import suddenly "disappeared" in a scoped block. -- Automatically detect newer Python interpreter versions before - loading code from bytecode caches to prevent segfaults on invalid - opcodes. The segfault in earlier Jinja versions here was not a - Jinja bug but a limitation in the underlying Python interpreter. If - you notice Jinja segfaulting in earlier versions after an upgrade - of the Python interpreter you don't have to upgrade, it's enough to - flush the bytecode cache. This just no longer makes this necessary, - Jinja will automatically detect these cases now. -- The sum filter can now sum up values by attribute. This is a - backwards incompatible change. The argument to the filter previously - was the optional starting index which defaults to zero. This now - became the second argument to the function because it's rarely used. -- Like sum, sort now also makes it possible to order items by - attribute. -- Like sum and sort, join now also is able to join attributes of - objects as string. -- The internal eval context now has a reference to the environment. -- Added a mapping test to see if an object is a dict or an object with - a similar interface. - - -Version 2.5.5 -------------- - -Released 2010-10-18 - -- Built documentation is no longer part of release. - - -Version 2.5.4 -------------- - -Released 2010-10-17 - -- Fixed extensions not loading properly with overlays. -- Work around a bug in cpython for the debugger that causes segfaults - on 64bit big-endian architectures. - - -Version 2.5.3 -------------- - -Released 2010-10-17 - -- Fixed an operator precedence error introduced in 2.5.2. Statements - like "-foo.bar" had their implicit parentheses applied around the - first part of the expression ("(-foo).bar") instead of the more - correct "-(foo.bar)". - - -Version 2.5.2 -------------- - -Released 2010-08-18 - -- Improved setup.py script to better work with assumptions people - might still have from it (``--with-speedups``). -- Fixed a packaging error that excluded the new debug support. - - -Version 2.5.1 -------------- - -Released 2010-08-17 - -- StopIteration exceptions raised by functions called from templates - are now intercepted and converted to undefineds. This solves a lot - of debugging grief. (StopIteration is used internally to abort - template execution) -- Improved performance of macro calls slightly. -- Babel extraction can now properly extract newstyle gettext calls. -- Using the variable ``num`` in newstyle gettext for something else - than the pluralize count will no longer raise a :exc:`KeyError`. -- Removed builtin markup class and switched to markupsafe. For - backwards compatibility the pure Python implementation still exists - but is pulled from markupsafe by the Jinja developers. The debug - support went into a separate feature called "debugsupport" and is - disabled by default because it is only relevant for Python 2.4 -- Fixed an issue with unary operators having the wrong precedence. - - -Version 2.5 ------------ - -Released 2010-05-29, codename Incoherence - -- Improved the sort filter (should have worked like this for a long - time) by adding support for case insensitive searches. -- Fixed a bug for getattribute constant folding. -- Support for newstyle gettext translations which result in a nicer - in-template user interface and more consistent catalogs. -- It's now possible to register extensions after an environment was - created. - - -Version 2.4.1 -------------- - -Released 2010-04-20 - -- Fixed an error reporting bug for undefined. - - -Version 2.4 ------------ - -Released 2010-04-13, codename Correlation - -- The environment template loading functions now transparently pass - through a template object if it was passed to it. This makes it - possible to import or extend from a template object that was passed - to the template. -- Added a ``ModuleLoader`` that can load templates from - precompiled sources. The environment now features a method to - compile the templates from a configured loader into a zip file or - folder. -- The _speedups C extension now supports Python 3. -- Added support for autoescaping toggling sections and support for - evaluation contexts. -- Extensions have a priority now. - - -Version 2.3.1 -------------- - -Released 2010-02-19 - -- Fixed an error reporting bug on all python versions -- Fixed an error reporting bug on Python 2.4 - - -Version 2.3 ------------ - -Released 2010-02-10, codename 3000 Pythons - -- Fixes issue with code generator that causes unbound variables to be - generated if set was used in if-blocks and other small identifier - problems. -- Include tags are now able to select between multiple templates and - take the first that exists, if a list of templates is given. -- Fixed a problem with having call blocks in outer scopes that have an - argument that is also used as local variable in an inner frame - :issue:`360`. -- Greatly improved error message reporting :pr:`339` -- Implicit tuple expressions can no longer be totally empty. This - change makes ``{% if %}`` a syntax error now. :issue:`364` -- Added support for translator comments if extracted via babel. -- Added with-statement extension. -- Experimental Python 3 support. - - -Version 2.2.1 -------------- - -Released 2009-09-14 - -- Fixes some smaller problems for Jinja on Jython. - - -Version 2.2 ------------ - -Released 2009-09-13, codename Kong - -- Include statements can now be marked with ``ignore missing`` to skip - non existing templates. -- Priority of ``not`` raised. It's now possible to write ``not foo in - bar`` as an alias to ``foo not in bar`` like in python. Previously - the grammar required parentheses (``not (foo in bar)``) which was - odd. -- Fixed a bug that caused syntax errors when defining macros or using - the ``{% call %}`` tag inside loops. -- Fixed a bug in the parser that made ``{{ foo[1, 2] }}`` impossible. -- Made it possible to refer to names from outer scopes in included - templates that were unused in the callers frame :issue:`327` -- Fixed a bug that caused internal errors if names where used as - iteration variable and regular variable *after* the loop if that - variable was unused *before* the loop. :pr:`331` -- Added support for optional ``scoped`` modifier to blocks. -- Added support for line-comments. -- Added the ``meta`` module. -- Renamed (undocumented) attribute "overlay" to "overlayed" on the - environment because it was clashing with a method of the same name. -- Speedup extension is now disabled by default. - - -Version 2.1.1 -------------- - -Released 2008-12-25 - -- Fixed a translation error caused by looping over empty recursive - loops. - - -Version 2.1 ------------ - -Released 2008-11-23, codename Yasuzō - -- Fixed a bug with nested loops and the special loop variable. Before - the change an inner loop overwrote the loop variable from the outer - one after iteration. -- Fixed a bug with the i18n extension that caused the explicit - pluralization block to look up the wrong variable. -- Fixed a limitation in the lexer that made ``{{ foo.0.0 }}`` - impossible. -- Index based subscribing of variables with a constant value returns - an undefined object now instead of raising an index error. This was - a bug caused by eager optimizing. -- The i18n extension looks up ``foo.ugettext`` now followed by - ``foo.gettext`` if an translations object is installed. This makes - dealing with custom translations classes easier. -- Fixed a confusing behavior with conditional extending. loops were - partially executed under some conditions even though they were not - part of a visible area. -- Added ``sort`` filter that works like ``dictsort`` but for arbitrary - sequences. -- Fixed a bug with empty statements in macros. -- Implemented a bytecode cache system. -- The template context is now weakref-able -- Inclusions and imports "with context" forward all variables now, not - only the initial context. -- Added a cycle helper called ``cycler``. -- Added a joining helper called ``joiner``. -- Added a ``compile_expression`` method to the environment that allows - compiling of Jinja expressions into callable Python objects. -- Fixed an escaping bug in urlize - - -Version 2.0 ------------ - -Released 2008-07-17, codename Jinjavitus - -- The subscribing of objects (looking up attributes and items) changed - from slightly. It's now possible to give attributes or items a - higher priority by either using dot-notation lookup or the bracket - syntax. This also changed the AST slightly. ``Subscript`` is gone - and was replaced with ``Getitem`` and ``Getattr``. -- Added support for preprocessing and token stream filtering for - extensions. This would allow extensions to allow simplified gettext - calls in template data and something similar. -- Added ``TemplateStream.dump``. -- Added missing support for implicit string literal concatenation. - ``{{ "foo" "bar" }}`` is equivalent to ``{{ "foobar" }}`` -- ``else`` is optional for conditional expressions. If not given it - evaluates to ``false``. -- Improved error reporting for undefined values by providing a - position. -- ``filesizeformat`` filter uses decimal prefixes now per default and - can be set to binary mode with the second parameter. -- Fixed bug in finalizer - - -Version 2.0rc1 --------------- - -Released 2008-06-09 - -- First release of Jinja 2. diff --git a/third_party/python/Jinja2/LICENSE.rst b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/LICENSE.rst similarity index 100% rename from third_party/python/Jinja2/LICENSE.rst rename to third_party/python/Jinja2/Jinja2-2.11.3.dist-info/LICENSE.rst diff --git a/third_party/python/Jinja2/README.rst b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/METADATA similarity index 52% rename from third_party/python/Jinja2/README.rst rename to third_party/python/Jinja2/Jinja2-2.11.3.dist-info/METADATA index 060b19efee61..1af8df0f716e 100644 --- a/third_party/python/Jinja2/README.rst +++ b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/METADATA @@ -1,3 +1,41 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 2.11.3 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/jinja +Project-URL: Issue tracker, https://github.com/pallets/jinja/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/x-rst +Requires-Dist: MarkupSafe (>=0.23) +Provides-Extra: i18n +Requires-Dist: Babel (>=0.8) ; extra == 'i18n' + Jinja ===== @@ -64,3 +102,5 @@ Links - Issue tracker: https://github.com/pallets/jinja/issues - Test status: https://dev.azure.com/pallets/jinja/_build - Official chat: https://discord.gg/t6rrQZH + + diff --git a/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/RECORD b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/RECORD new file mode 100644 index 000000000000..5362e8cb49cc --- /dev/null +++ b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/RECORD @@ -0,0 +1,33 @@ +jinja2/__init__.py,sha256=LZUXmxJc2GIchfSAeMWsxCWiQYO-w1-736f2Q3I8ms8,1549 +jinja2/_compat.py,sha256=B6Se8HjnXVpzz9-vfHejn-DV2NjaVK-Iewupc5kKlu8,3191 +jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775 +jinja2/asyncfilters.py,sha256=XJtYXTxFvcJ5xwk6SaDL4S0oNnT0wPYvXBCSzc482fI,4250 +jinja2/asyncsupport.py,sha256=ZBFsDLuq3Gtji3Ia87lcyuDbqaHZJRdtShZcqwpFnSQ,7209 +jinja2/bccache.py,sha256=3Pmp4jo65M9FQuIxdxoDBbEDFwe4acDMQf77nEJfrHA,12139 +jinja2/compiler.py,sha256=Ta9W1Lit542wItAHXlDcg0sEOsFDMirCdlFPHAurg4o,66284 +jinja2/constants.py,sha256=RR1sTzNzUmKco6aZicw4JpQpJGCuPuqm1h1YmCNUEFY,1458 +jinja2/debug.py,sha256=neR7GIGGjZH3_ILJGVUYy3eLQCCaWJMXOb7o0kGInWc,8529 +jinja2/defaults.py,sha256=85B6YUUCyWPSdrSeVhcqFVuu_bHUAQXeey--FIwSeVQ,1126 +jinja2/environment.py,sha256=XDSLKc4SqNLMOwTSq3TbWEyA5WyXfuLuVD0wAVjEFwM,50629 +jinja2/exceptions.py,sha256=VjNLawcmf2ODffqVMCQK1cRmvFaUfQWF4u8ouP3QPcE,5425 +jinja2/ext.py,sha256=AtwL5O5enT_L3HR9-oBvhGyUTdGoyaqG_ICtnR_EVd4,26441 +jinja2/filters.py,sha256=9ORilsZrUoydSI9upz8_qGy7gozDWLYoFmlIBFSVRnQ,41439 +jinja2/idtracking.py,sha256=J3O4VHsrbf3wzwiBc7Cro26kHb6_5kbULeIOzocchIU,9211 +jinja2/lexer.py,sha256=nUFLRKhhKmmEWkLI65nQePgcQs7qsRdjVYZETMt_v0g,30331 +jinja2/loaders.py,sha256=C-fST_dmFjgWkp0ZuCkrgICAoOsoSIF28wfAFink0oU,17666 +jinja2/meta.py,sha256=QjyYhfNRD3QCXjBJpiPl9KgkEkGXJbAkCUq4-Ur10EQ,4131 +jinja2/nativetypes.py,sha256=Ul__gtVw4xH-0qvUvnCNHedQeNDwmEuyLJztzzSPeRg,2753 +jinja2/nodes.py,sha256=Mk1oJPVgIjnQw9WOqILvcu3rLepcFZ0ahxQm2mbwDwc,31095 +jinja2/optimizer.py,sha256=gQLlMYzvQhluhzmAIFA1tXS0cwgWYOjprN-gTRcHVsc,1457 +jinja2/parser.py,sha256=fcfdqePNTNyvosIvczbytVA332qpsURvYnCGcjDHSkA,35660 +jinja2/runtime.py,sha256=0y-BRyIEZ9ltByL2Id6GpHe1oDRQAwNeQvI0SKobNMw,30618 +jinja2/sandbox.py,sha256=knayyUvXsZ-F0mk15mO2-ehK9gsw04UhB8td-iUOtLc,17127 +jinja2/tests.py,sha256=iO_Y-9Vo60zrVe1lMpSl5sKHqAxe2leZHC08OoZ8K24,4799 +jinja2/utils.py,sha256=Wy4yC3IByqUWwnKln6SdaixdzgK74P6F5nf-gQZrYnU,22436 +jinja2/visitor.py,sha256=DUHupl0a4PGp7nxRtZFttUzAi1ccxzqc2hzetPYUz8U,3240 +Jinja2-2.11.3.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-2.11.3.dist-info/METADATA,sha256=PscpJ1C3RSp8xcjV3fAuTz13rKbGxmzJXnMQFH-WKhs,3535 +Jinja2-2.11.3.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +Jinja2-2.11.3.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61 +Jinja2-2.11.3.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +Jinja2-2.11.3.dist-info/RECORD,, diff --git a/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/WHEEL b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/WHEEL new file mode 100644 index 000000000000..01b8fc7d4a10 --- /dev/null +++ b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/entry_points.txt b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/entry_points.txt new file mode 100644 index 000000000000..3619483fd4fc --- /dev/null +++ b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract [i18n] + diff --git a/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/top_level.txt b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/top_level.txt new file mode 100644 index 000000000000..7f7afbf3bf54 --- /dev/null +++ b/third_party/python/Jinja2/Jinja2-2.11.3.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/third_party/python/Jinja2/MANIFEST.in b/third_party/python/Jinja2/MANIFEST.in deleted file mode 100644 index 909102a77aa6..000000000000 --- a/third_party/python/Jinja2/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include CHANGES.rst -include tox.ini -graft artwork -graft docs -prune docs/_build -graft examples -graft ext -graft tests -global-exclude *.pyc diff --git a/third_party/python/Jinja2/PKG-INFO b/third_party/python/Jinja2/PKG-INFO deleted file mode 100644 index 0f3dea3b527c..000000000000 --- a/third_party/python/Jinja2/PKG-INFO +++ /dev/null @@ -1,102 +0,0 @@ -Metadata-Version: 2.1 -Name: Jinja2 -Version: 2.11.3 -Summary: A very fast and expressive template engine. -Home-page: https://palletsprojects.com/p/jinja/ -Author: Armin Ronacher -Author-email: armin.ronacher@active-4.com -Maintainer: Pallets -Maintainer-email: contact@palletsprojects.com -License: BSD-3-Clause -Project-URL: Documentation, https://jinja.palletsprojects.com/ -Project-URL: Code, https://github.com/pallets/jinja -Project-URL: Issue tracker, https://github.com/pallets/jinja/issues -Description: Jinja - ===== - - Jinja is a fast, expressive, extensible templating engine. Special - placeholders in the template allow writing code similar to Python - syntax. Then the template is passed data to render the final document. - - It includes: - - - Template inheritance and inclusion. - - Define and import macros within templates. - - HTML templates can use autoescaping to prevent XSS from untrusted - user input. - - A sandboxed environment can safely render untrusted templates. - - AsyncIO support for generating templates and calling async - functions. - - I18N support with Babel. - - Templates are compiled to optimized Python code just-in-time and - cached, or can be compiled ahead-of-time. - - Exceptions point to the correct line in templates to make debugging - easier. - - Extensible filters, tests, functions, and even syntax. - - Jinja's philosophy is that while application logic belongs in Python if - possible, it shouldn't make the template designer's job difficult by - restricting functionality too much. - - - Installing - ---------- - - Install and update using `pip`_: - - .. code-block:: text - - $ pip install -U Jinja2 - - .. _pip: https://pip.pypa.io/en/stable/quickstart/ - - - In A Nutshell - ------------- - - .. code-block:: jinja - - {% extends "base.html" %} - {% block title %}Members{% endblock %} - {% block content %} -

- {% endblock %} - - - Links - ----- - - - Website: https://palletsprojects.com/p/jinja/ - - Documentation: https://jinja.palletsprojects.com/ - - Releases: https://pypi.org/project/Jinja2/ - - Code: https://github.com/pallets/jinja - - Issue tracker: https://github.com/pallets/jinja/issues - - Test status: https://dev.azure.com/pallets/jinja/_build - - Official chat: https://discord.gg/t6rrQZH - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Text Processing :: Markup :: HTML -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* -Description-Content-Type: text/x-rst -Provides-Extra: i18n diff --git a/third_party/python/Jinja2/artwork/jinjalogo.svg b/third_party/python/Jinja2/artwork/jinjalogo.svg deleted file mode 100644 index 0bc9ea4e8b4f..000000000000 --- a/third_party/python/Jinja2/artwork/jinjalogo.svg +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/third_party/python/Jinja2/examples/basic/cycle.py b/third_party/python/Jinja2/examples/basic/cycle.py deleted file mode 100644 index 25dcb0b090ec..000000000000 --- a/third_party/python/Jinja2/examples/basic/cycle.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment - -env = Environment( - line_statement_prefix="#", variable_start_string="${", variable_end_string="}" -) -print( - env.from_string( - """\ -
    -# for item in range(10) -
  • ${item}
  • -# endfor -
\ -""" - ).render() -) diff --git a/third_party/python/Jinja2/examples/basic/debugger.py b/third_party/python/Jinja2/examples/basic/debugger.py deleted file mode 100644 index d3c1a60a7ae8..000000000000 --- a/third_party/python/Jinja2/examples/basic/debugger.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment -from jinja2.loaders import FileSystemLoader - -env = Environment(loader=FileSystemLoader("templates")) -tmpl = env.get_template("broken.html") -print(tmpl.render(seq=[3, 2, 4, 5, 3, 2, 0, 2, 1])) diff --git a/third_party/python/Jinja2/examples/basic/inheritance.py b/third_party/python/Jinja2/examples/basic/inheritance.py deleted file mode 100644 index 4a881bf8a87c..000000000000 --- a/third_party/python/Jinja2/examples/basic/inheritance.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment -from jinja2.loaders import DictLoader - -env = Environment( - loader=DictLoader( - { - "a": "[A[{% block body %}{% endblock %}]]", - "b": "{% extends 'a' %}{% block body %}[B]{% endblock %}", - "c": "{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}", - } - ) -) -print(env.get_template("c").render()) diff --git a/third_party/python/Jinja2/examples/basic/templates/broken.html b/third_party/python/Jinja2/examples/basic/templates/broken.html deleted file mode 100644 index 294d5c99894d..000000000000 --- a/third_party/python/Jinja2/examples/basic/templates/broken.html +++ /dev/null @@ -1,6 +0,0 @@ -{% from 'subbroken.html' import may_break %} -
    -{% for item in seq %} -
  • {{ may_break(item) }}
  • -{% endfor %} -
diff --git a/third_party/python/Jinja2/examples/basic/templates/subbroken.html b/third_party/python/Jinja2/examples/basic/templates/subbroken.html deleted file mode 100644 index 245eb7e6e6f7..000000000000 --- a/third_party/python/Jinja2/examples/basic/templates/subbroken.html +++ /dev/null @@ -1,3 +0,0 @@ -{% macro may_break(item) -%} - [{{ item / 0 }}] -{%- endmacro %} diff --git a/third_party/python/Jinja2/examples/basic/test.py b/third_party/python/Jinja2/examples/basic/test.py deleted file mode 100644 index 80b9d1f052b3..000000000000 --- a/third_party/python/Jinja2/examples/basic/test.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment -from jinja2.loaders import DictLoader - -env = Environment( - loader=DictLoader( - { - "child.html": u"""\ -{% extends master_layout or 'master.html' %} -{% include helpers = 'helpers.html' %} -{% macro get_the_answer() %}42{% endmacro %} -{% title = 'Hello World' %} -{% block body %} - {{ get_the_answer() }} - {{ helpers.conspirate() }} -{% endblock %} -""", - "master.html": u"""\ - -{{ title }} -{% block body %}{% endblock %} -""", - "helpers.html": u"""\ -{% macro conspirate() %}23{% endmacro %} -""", - } - ) -) -tmpl = env.get_template("child.html") -print(tmpl.render()) diff --git a/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py b/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py deleted file mode 100644 index 673b67ed76ae..000000000000 --- a/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment - -env = Environment( - line_statement_prefix="%", variable_start_string="${", variable_end_string="}" -) -tmpl = env.from_string( - """\ -% macro foo() - ${caller(42)} -% endmacro -
    -% for item in seq -
  • ${item}
  • -% endfor -
-% call(var) foo() - [${var}] -% endcall -% filter escape - - % for item in [1, 2, 3] - - ${item} - % endfor -% endfilter -""" -) -print(tmpl.render(seq=range(10))) diff --git a/third_party/python/Jinja2/examples/basic/test_loop_filter.py b/third_party/python/Jinja2/examples/basic/test_loop_filter.py deleted file mode 100644 index 39be08d61c2b..000000000000 --- a/third_party/python/Jinja2/examples/basic/test_loop_filter.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment - -tmpl = Environment().from_string( - """\ -
    -{%- for item in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if item % 2 == 0 %} -
  • {{ loop.index }} / {{ loop.length }}: {{ item }}
  • -{%- endfor %} -
-if condition: {{ 1 if foo else 0 }} -""" -) -print(tmpl.render(foo=True)) diff --git a/third_party/python/Jinja2/examples/basic/translate.py b/third_party/python/Jinja2/examples/basic/translate.py deleted file mode 100644 index 71547f4649ca..000000000000 --- a/third_party/python/Jinja2/examples/basic/translate.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import print_function - -from jinja2 import Environment - -env = Environment(extensions=["jinja2.ext.i18n"]) -env.globals["gettext"] = {"Hello %(user)s!": "Hallo %(user)s!"}.__getitem__ -env.globals["ngettext"] = lambda s, p, n: { - "%(count)s user": "%(count)d Benutzer", - "%(count)s users": "%(count)d Benutzer", -}[n == 1 and s or p] -print( - env.from_string( - """\ -{% trans %}Hello {{ user }}!{% endtrans %} -{% trans count=users|count -%} -{{ count }} user{% pluralize %}{{ count }} users -{% endtrans %} -""" - ).render(user="someone", users=[1, 2, 3]) -) diff --git a/third_party/python/Jinja2/ext/Vim/jinja.vim b/third_party/python/Jinja2/ext/Vim/jinja.vim deleted file mode 100644 index e2a5bbf6c9ab..000000000000 --- a/third_party/python/Jinja2/ext/Vim/jinja.vim +++ /dev/null @@ -1,138 +0,0 @@ -" Vim syntax file -" Language: Jinja template -" Maintainer: Armin Ronacher -" Last Change: 2008 May 9 -" Version: 1.1 -" -" Known Bugs: -" because of odd limitations dicts and the modulo operator -" appear wrong in the template. -" -" Changes: -" -" 2008 May 9: Added support for Jinja 2 changes (new keyword rules) - -" .vimrc variable to disable html highlighting -if !exists('g:jinja_syntax_html') - let g:jinja_syntax_html=1 -endif - -" For version 5.x: Clear all syntax items -" For version 6.x: Quit when a syntax file was already loaded -if !exists("main_syntax") - if v:version < 600 - syntax clear - elseif exists("b:current_syntax") - finish - endif - let main_syntax = 'jinja' -endif - -" Pull in the HTML syntax. -if g:jinja_syntax_html - if v:version < 600 - so :p:h/html.vim - else - runtime! syntax/html.vim - unlet b:current_syntax - endif -endif - -syntax case match - -" Jinja template built-in tags and parameters (without filter, macro, is and raw, they -" have special threatment) -syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained and if else in not or recursive as import - -syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained is filter skipwhite nextgroup=jinjaFilter -syn keyword jinjaStatement containedin=jinjaTagBlock contained macro skipwhite nextgroup=jinjaFunction -syn keyword jinjaStatement containedin=jinjaTagBlock contained block skipwhite nextgroup=jinjaBlockName - -" Variable Names -syn match jinjaVariable containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[a-zA-Z_][a-zA-Z0-9_]*/ -syn keyword jinjaSpecial containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained false true none False True None loop super caller varargs kwargs - -" Filters -syn match jinjaOperator "|" containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained skipwhite nextgroup=jinjaFilter -syn match jinjaFilter contained /[a-zA-Z_][a-zA-Z0-9_]*/ -syn match jinjaFunction contained /[a-zA-Z_][a-zA-Z0-9_]*/ -syn match jinjaBlockName contained /[a-zA-Z_][a-zA-Z0-9_]*/ - -" Jinja template constants -syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/"/ skip=/\(\\\)\@\)*\\"/ end=/"/ -syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/'/ skip=/\(\\\)\@\)*\\'/ end=/'/ -syn match jinjaNumber containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[0-9]\+\(\.[0-9]\+\)\?/ - -" Operators -syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[+\-*\/<>=!,:]/ -syn match jinjaPunctuation containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[()\[\]]/ -syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /\./ nextgroup=jinjaAttribute -syn match jinjaAttribute contained /[a-zA-Z_][a-zA-Z0-9_]*/ - -" Jinja template tag and variable blocks -syn region jinjaNested matchgroup=jinjaOperator start="(" end=")" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained -syn region jinjaNested matchgroup=jinjaOperator start="\[" end="\]" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained -syn region jinjaNested matchgroup=jinjaOperator start="{" end="}" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained -syn region jinjaTagBlock matchgroup=jinjaTagDelim start=/{%-\?/ end=/-\?%}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment - -syn region jinjaVarBlock matchgroup=jinjaVarDelim start=/{{-\?/ end=/-\?}}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment - -" Jinja template 'raw' tag -syn region jinjaRaw matchgroup=jinjaRawDelim start="{%\s*raw\s*%}" end="{%\s*endraw\s*%}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString,jinjaComment - -" Jinja comments -syn region jinjaComment matchgroup=jinjaCommentDelim start="{#" end="#}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString,jinjaComment -" help support folding for some setups -setlocal commentstring={#%s#} -setlocal comments=s:{#,e:#} - -" Block start keywords. A bit tricker. We only highlight at the start of a -" tag block and only if the name is not followed by a comma or equals sign -" which usually means that we have to deal with an assignment. -syn match jinjaStatement containedin=jinjaTagBlock contained /\({%-\?\s*\)\@<=\<[a-zA-Z_][a-zA-Z0-9_]*\>\(\s*[,=]\)\@!/ - -" and context modifiers -syn match jinjaStatement containedin=jinjaTagBlock contained /\/ - - -" Define the default highlighting. -" For version 5.7 and earlier: only when not done already -" For version 5.8 and later: only when an item doesn't have highlighting yet -if v:version >= 508 || !exists("did_jinja_syn_inits") - if v:version < 508 - let did_jinja_syn_inits = 1 - command -nargs=+ HiLink hi link - else - command -nargs=+ HiLink hi def link - endif - - HiLink jinjaPunctuation jinjaOperator - HiLink jinjaAttribute jinjaVariable - HiLink jinjaFunction jinjaFilter - - HiLink jinjaTagDelim jinjaTagBlock - HiLink jinjaVarDelim jinjaVarBlock - HiLink jinjaCommentDelim jinjaComment - HiLink jinjaRawDelim jinja - - HiLink jinjaSpecial Special - HiLink jinjaOperator Normal - HiLink jinjaRaw Normal - HiLink jinjaTagBlock PreProc - HiLink jinjaVarBlock PreProc - HiLink jinjaStatement Statement - HiLink jinjaFilter Function - HiLink jinjaBlockName Function - HiLink jinjaVariable Identifier - HiLink jinjaString Constant - HiLink jinjaNumber Constant - HiLink jinjaComment Comment - - delcommand HiLink -endif - -let b:current_syntax = "jinja" - -if main_syntax ==# 'jinja' - unlet main_syntax -endif diff --git a/third_party/python/Jinja2/src/jinja2/__init__.py b/third_party/python/Jinja2/jinja2/__init__.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/__init__.py rename to third_party/python/Jinja2/jinja2/__init__.py diff --git a/third_party/python/Jinja2/src/jinja2/_compat.py b/third_party/python/Jinja2/jinja2/_compat.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/_compat.py rename to third_party/python/Jinja2/jinja2/_compat.py diff --git a/third_party/python/Jinja2/src/jinja2/_identifier.py b/third_party/python/Jinja2/jinja2/_identifier.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/_identifier.py rename to third_party/python/Jinja2/jinja2/_identifier.py diff --git a/third_party/python/Jinja2/src/jinja2/asyncfilters.py b/third_party/python/Jinja2/jinja2/asyncfilters.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/asyncfilters.py rename to third_party/python/Jinja2/jinja2/asyncfilters.py diff --git a/third_party/python/Jinja2/src/jinja2/asyncsupport.py b/third_party/python/Jinja2/jinja2/asyncsupport.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/asyncsupport.py rename to third_party/python/Jinja2/jinja2/asyncsupport.py diff --git a/third_party/python/Jinja2/src/jinja2/bccache.py b/third_party/python/Jinja2/jinja2/bccache.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/bccache.py rename to third_party/python/Jinja2/jinja2/bccache.py diff --git a/third_party/python/Jinja2/src/jinja2/compiler.py b/third_party/python/Jinja2/jinja2/compiler.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/compiler.py rename to third_party/python/Jinja2/jinja2/compiler.py diff --git a/third_party/python/Jinja2/src/jinja2/constants.py b/third_party/python/Jinja2/jinja2/constants.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/constants.py rename to third_party/python/Jinja2/jinja2/constants.py diff --git a/third_party/python/Jinja2/src/jinja2/debug.py b/third_party/python/Jinja2/jinja2/debug.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/debug.py rename to third_party/python/Jinja2/jinja2/debug.py diff --git a/third_party/python/Jinja2/src/jinja2/defaults.py b/third_party/python/Jinja2/jinja2/defaults.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/defaults.py rename to third_party/python/Jinja2/jinja2/defaults.py diff --git a/third_party/python/Jinja2/src/jinja2/environment.py b/third_party/python/Jinja2/jinja2/environment.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/environment.py rename to third_party/python/Jinja2/jinja2/environment.py diff --git a/third_party/python/Jinja2/src/jinja2/exceptions.py b/third_party/python/Jinja2/jinja2/exceptions.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/exceptions.py rename to third_party/python/Jinja2/jinja2/exceptions.py diff --git a/third_party/python/Jinja2/src/jinja2/ext.py b/third_party/python/Jinja2/jinja2/ext.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/ext.py rename to third_party/python/Jinja2/jinja2/ext.py diff --git a/third_party/python/Jinja2/src/jinja2/filters.py b/third_party/python/Jinja2/jinja2/filters.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/filters.py rename to third_party/python/Jinja2/jinja2/filters.py diff --git a/third_party/python/Jinja2/src/jinja2/idtracking.py b/third_party/python/Jinja2/jinja2/idtracking.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/idtracking.py rename to third_party/python/Jinja2/jinja2/idtracking.py diff --git a/third_party/python/Jinja2/src/jinja2/lexer.py b/third_party/python/Jinja2/jinja2/lexer.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/lexer.py rename to third_party/python/Jinja2/jinja2/lexer.py diff --git a/third_party/python/Jinja2/src/jinja2/loaders.py b/third_party/python/Jinja2/jinja2/loaders.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/loaders.py rename to third_party/python/Jinja2/jinja2/loaders.py diff --git a/third_party/python/Jinja2/src/jinja2/meta.py b/third_party/python/Jinja2/jinja2/meta.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/meta.py rename to third_party/python/Jinja2/jinja2/meta.py diff --git a/third_party/python/Jinja2/src/jinja2/nativetypes.py b/third_party/python/Jinja2/jinja2/nativetypes.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/nativetypes.py rename to third_party/python/Jinja2/jinja2/nativetypes.py diff --git a/third_party/python/Jinja2/src/jinja2/nodes.py b/third_party/python/Jinja2/jinja2/nodes.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/nodes.py rename to third_party/python/Jinja2/jinja2/nodes.py diff --git a/third_party/python/Jinja2/src/jinja2/optimizer.py b/third_party/python/Jinja2/jinja2/optimizer.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/optimizer.py rename to third_party/python/Jinja2/jinja2/optimizer.py diff --git a/third_party/python/Jinja2/src/jinja2/parser.py b/third_party/python/Jinja2/jinja2/parser.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/parser.py rename to third_party/python/Jinja2/jinja2/parser.py diff --git a/third_party/python/Jinja2/src/jinja2/runtime.py b/third_party/python/Jinja2/jinja2/runtime.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/runtime.py rename to third_party/python/Jinja2/jinja2/runtime.py diff --git a/third_party/python/Jinja2/src/jinja2/sandbox.py b/third_party/python/Jinja2/jinja2/sandbox.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/sandbox.py rename to third_party/python/Jinja2/jinja2/sandbox.py diff --git a/third_party/python/Jinja2/src/jinja2/tests.py b/third_party/python/Jinja2/jinja2/tests.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/tests.py rename to third_party/python/Jinja2/jinja2/tests.py diff --git a/third_party/python/Jinja2/src/jinja2/utils.py b/third_party/python/Jinja2/jinja2/utils.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/utils.py rename to third_party/python/Jinja2/jinja2/utils.py diff --git a/third_party/python/Jinja2/src/jinja2/visitor.py b/third_party/python/Jinja2/jinja2/visitor.py similarity index 100% rename from third_party/python/Jinja2/src/jinja2/visitor.py rename to third_party/python/Jinja2/jinja2/visitor.py diff --git a/third_party/python/Jinja2/setup.cfg b/third_party/python/Jinja2/setup.cfg deleted file mode 100644 index 3387720ba827..000000000000 --- a/third_party/python/Jinja2/setup.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[metadata] -license_file = LICENSE.rst -long_description_content_type = text/x-rst - -[bdist_wheel] -universal = true - -[tool:pytest] -testpaths = tests -filterwarnings = - error - ignore:the sets module:DeprecationWarning:jinja2.sandbox - -[coverage:run] -branch = True -source = - jinja2 - tests - -[coverage:paths] -source = - src - */site-packages - -[flake8] -select = B, E, F, W, B9 -ignore = - E203 - E501 - E722 - W503 -max-line-length = 80 -per-file-ignores = - src/jinja2/__init__.py: F401 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/Jinja2/setup.py b/third_party/python/Jinja2/setup.py deleted file mode 100644 index 7d94cd3ae001..000000000000 --- a/third_party/python/Jinja2/setup.py +++ /dev/null @@ -1,56 +0,0 @@ -import io -import re - -from setuptools import find_packages -from setuptools import setup - -with io.open("README.rst", "rt", encoding="utf8") as f: - readme = f.read() - -with io.open("src/jinja2/__init__.py", "rt", encoding="utf8") as f: - version = re.search(r'__version__ = "(.*?)"', f.read(), re.M).group(1) - -setup( - name="Jinja2", - version=version, - url="https://palletsprojects.com/p/jinja/", - project_urls={ - "Documentation": "https://jinja.palletsprojects.com/", - "Code": "https://github.com/pallets/jinja", - "Issue tracker": "https://github.com/pallets/jinja/issues", - }, - license="BSD-3-Clause", - author="Armin Ronacher", - author_email="armin.ronacher@active-4.com", - maintainer="Pallets", - maintainer_email="contact@palletsprojects.com", - description="A very fast and expressive template engine.", - long_description=readme, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Web Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Internet :: WWW/HTTP :: Dynamic Content", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Text Processing :: Markup :: HTML", - ], - packages=find_packages("src"), - package_dir={"": "src"}, - include_package_data=True, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", - install_requires=["MarkupSafe>=0.23"], - extras_require={"i18n": ["Babel>=0.8"]}, - entry_points={"babel.extractors": ["jinja2 = jinja2.ext:babel_extract[i18n]"]}, -) diff --git a/third_party/python/Jinja2/tox.ini b/third_party/python/Jinja2/tox.ini deleted file mode 100644 index 679ebebe91cf..000000000000 --- a/third_party/python/Jinja2/tox.ini +++ /dev/null @@ -1,20 +0,0 @@ -[tox] -envlist = - py{38,37,36,35,27,py3,py} - style - docs -skip_missing_interpreters = true - -[testenv] -deps = - pytest -commands = pytest --tb=short --basetemp={envtmpdir} {posargs} - -[testenv:style] -deps = pre-commit -skip_install = true -commands = pre-commit run --all-files --show-diff-on-failure - -[testenv:docs] -deps = -r docs/requirements.txt -commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html diff --git a/third_party/python/appdirs/.gitignore b/third_party/python/appdirs/.gitignore deleted file mode 100644 index 9bef3459aef5..000000000000 --- a/third_party/python/appdirs/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.pyc -*.egg-info -tmp/ -build/ -dist/ -.tox/ -MANIFEST -*.komodoproject diff --git a/third_party/python/appdirs/.travis.yml b/third_party/python/appdirs/.travis.yml deleted file mode 100644 index 684833b20c1d..000000000000 --- a/third_party/python/appdirs/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: python -python: - - "2.7" - - "pypy" - - "3.4" - - "3.5" - - "3.6" - - "3.7" - - "3.8" -script: python setup.py test diff --git a/third_party/python/appdirs/CHANGES.rst b/third_party/python/appdirs/CHANGES.rst deleted file mode 100644 index e9987c7ee205..000000000000 --- a/third_party/python/appdirs/CHANGES.rst +++ /dev/null @@ -1,93 +0,0 @@ -appdirs Changelog -================= - -appdirs 1.4.4 -------------- -- [PR #92] Don't import appdirs from setup.py - -Project officially classified as Stable which is important -for inclusion in other distros such as ActivePython. - -First of several incremental releases to catch up on maintenance. - -appdirs 1.4.3 -------------- -- [PR #76] Python 3.6 invalid escape sequence deprecation fixes -- Fix for Python 3.6 support - -appdirs 1.4.2 -------------- -- [PR #84] Allow installing without setuptools -- [PR #86] Fix string delimiters in setup.py description -- Add Python 3.6 support - -appdirs 1.4.1 -------------- -- [issue #38] Fix _winreg import on Windows Py3 -- [issue #55] Make appname optional - -appdirs 1.4.0 -------------- -- [PR #42] AppAuthor is now optional on Windows -- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows - support requires `JNA `_. -- [PR #44] Fix incorrect behaviour of the site_config_dir method - -appdirs 1.3.0 -------------- -- [Unix, issue 16] Conform to XDG standard, instead of breaking it for - everybody -- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are - usually case sensitive, so mangling is not wise -- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result - based on XDG_DATA_DIRS and make room for respecting the standard which - specifies XDG_DATA_DIRS is a multiple-value variable -- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to - XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` - -appdirs 1.2.0 -------------- - -- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more - typical. -- [issue 9] Make ``unicode`` work on py3k. - -appdirs 1.1.0 -------------- - -- [issue 4] Add ``AppDirs.user_log_dir``. -- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec - `_. -- [Mac, issue 5] Fix ``site_data_dir()`` on Mac. -- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports - Python3 now. -- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use - ``opinion=False`` option to disable this. -- Add ``appdirs.AppDirs`` convenience class. Usage: - - >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - -- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short - paths if there are high bit chars. -- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. - "~/.superapp/cache". -- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) - and change the default ``user_data_dir`` behaviour to use a *non*-roaming - profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because - a large roaming profile can cause login speed issues. The "only syncs on - logout" behaviour can cause surprises in appdata info. - - -appdirs 1.0.1 (never released) ------------------------------- - -Started this changelog 27 July 2010. Before that this module originated in the -`Komodo `_ product as ``applib.py`` and then -as `applib/location.py -`_ (used by -`PyPM `_ in `ActivePython -`_). This is basically a fork of -applib.py 1.0.1 and applib/location.py 1.0.1. - diff --git a/third_party/python/appdirs/Dockerfile b/third_party/python/appdirs/Dockerfile deleted file mode 100644 index 93dd737bd6d6..000000000000 --- a/third_party/python/appdirs/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM activestate/activepython:2.7 - -# For Python3 compact -RUN apt-get -y update && apt-get -y install python3-setuptools && \ - apt-get -y clean - -WORKDIR /app -ADD . /app -RUN python setup.py install && python setup.py test -RUN python3 setup.py install && python3 setup.py test - -RUN python -m appdirs -RUN python3 -m appdirs diff --git a/third_party/python/appdirs/HACKING.md b/third_party/python/appdirs/HACKING.md deleted file mode 100644 index f98b053adb45..000000000000 --- a/third_party/python/appdirs/HACKING.md +++ /dev/null @@ -1,16 +0,0 @@ -# HACKING - -## release - -ensure correct version in CHANGES.md and appdirs.py, and: - -``` -python setup.py register sdist bdist_wheel upload -``` - -## docker image - -``` -docker build -t appdirs . -``` - diff --git a/third_party/python/appdirs/MANIFEST.in b/third_party/python/appdirs/MANIFEST.in deleted file mode 100644 index 6c3ac1b1dbb7..000000000000 --- a/third_party/python/appdirs/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst -include CHANGES.rst -include LICENSE.txt -include *.py -include test/*.py diff --git a/third_party/python/appdirs/PKG-INFO b/third_party/python/appdirs/PKG-INFO deleted file mode 100644 index 6e98536505cb..000000000000 --- a/third_party/python/appdirs/PKG-INFO +++ /dev/null @@ -1,262 +0,0 @@ -Metadata-Version: 1.2 -Name: appdirs -Version: 1.4.4 -Summary: A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir". -Home-page: http://github.com/ActiveState/appdirs -Author: Trent Mick -Author-email: trentm@gmail.com -Maintainer: Jeff Rouse -Maintainer-email: jr@its.to -License: MIT -Description: - .. image:: https://secure.travis-ci.org/ActiveState/appdirs.png - :target: http://travis-ci.org/ActiveState/appdirs - - the problem - =========== - - What directory should your app use for storing user data? If running on Mac OS X, you - should use:: - - ~/Library/Application Support/ - - If on Windows (at least English Win XP) that should be:: - - C:\Documents and Settings\\Application Data\Local Settings\\ - - or possibly:: - - C:\Documents and Settings\\Application Data\\ - - for `roaming profiles `_ but that is another story. - - On Linux (and other Unices) the dir, according to the `XDG - spec `_, is:: - - ~/.local/share/ - - - ``appdirs`` to the rescue - ========================= - - This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will - help you choose an appropriate: - - - user data dir (``user_data_dir``) - - user config dir (``user_config_dir``) - - user cache dir (``user_cache_dir``) - - site data dir (``site_data_dir``) - - site config dir (``site_config_dir``) - - user log dir (``user_log_dir``) - - and also: - - - is a single module so other Python packages can include their own private copy - - is slightly opinionated on the directory names used. Look for "OPINION" in - documentation and code for when an opinion is being applied. - - - some example output - =================== - - On Mac OS X:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/Users/trentm/Library/Application Support/SuperApp' - >>> site_data_dir(appname, appauthor) - '/Library/Application Support/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/Users/trentm/Library/Caches/SuperApp' - >>> user_log_dir(appname, appauthor) - '/Users/trentm/Library/Logs/SuperApp' - - On Windows 7:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' - >>> user_data_dir(appname, appauthor, roaming=True) - 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' - >>> user_cache_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' - >>> user_log_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' - - On Linux:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/home/trentm/.local/share/SuperApp - >>> site_data_dir(appname, appauthor) - '/usr/local/share/SuperApp' - >>> site_data_dir(appname, appauthor, multipath=True) - '/usr/local/share/SuperApp:/usr/share/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/home/trentm/.cache/SuperApp' - >>> user_log_dir(appname, appauthor) - '/home/trentm/.cache/SuperApp/log' - >>> user_config_dir(appname) - '/home/trentm/.config/SuperApp' - >>> site_config_dir(appname) - '/etc/xdg/SuperApp' - >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' - >>> site_config_dir(appname, multipath=True) - '/etc/SuperApp:/usr/local/etc/SuperApp' - - - ``AppDirs`` for convenience - =========================== - - :: - - >>> from appdirs import AppDirs - >>> dirs = AppDirs("SuperApp", "Acme") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp' - - - - Per-version isolation - ===================== - - If you have multiple versions of your app in use that you want to be - able to run side-by-side, then you may want version-isolation for these - dirs:: - - >>> from appdirs import AppDirs - >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp/1.0' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp/1.0' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp/1.0' - - - - appdirs Changelog - ================= - - appdirs 1.4.4 - ------------- - - [PR #92] Don't import appdirs from setup.py - - Project officially classified as Stable which is important - for inclusion in other distros such as ActivePython. - - First of several incremental releases to catch up on maintenance. - - appdirs 1.4.3 - ------------- - - [PR #76] Python 3.6 invalid escape sequence deprecation fixes - - Fix for Python 3.6 support - - appdirs 1.4.2 - ------------- - - [PR #84] Allow installing without setuptools - - [PR #86] Fix string delimiters in setup.py description - - Add Python 3.6 support - - appdirs 1.4.1 - ------------- - - [issue #38] Fix _winreg import on Windows Py3 - - [issue #55] Make appname optional - - appdirs 1.4.0 - ------------- - - [PR #42] AppAuthor is now optional on Windows - - [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows - support requires `JNA `_. - - [PR #44] Fix incorrect behaviour of the site_config_dir method - - appdirs 1.3.0 - ------------- - - [Unix, issue 16] Conform to XDG standard, instead of breaking it for - everybody - - [Unix] Removes gratuitous case mangling of the case, since \*nix-es are - usually case sensitive, so mangling is not wise - - [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result - based on XDG_DATA_DIRS and make room for respecting the standard which - specifies XDG_DATA_DIRS is a multiple-value variable - - [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to - XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` - - appdirs 1.2.0 - ------------- - - - [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more - typical. - - [issue 9] Make ``unicode`` work on py3k. - - appdirs 1.1.0 - ------------- - - - [issue 4] Add ``AppDirs.user_log_dir``. - - [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec - `_. - - [Mac, issue 5] Fix ``site_data_dir()`` on Mac. - - [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports - Python3 now. - - [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use - ``opinion=False`` option to disable this. - - Add ``appdirs.AppDirs`` convenience class. Usage: - - >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - - - [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short - paths if there are high bit chars. - - [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. - "~/.superapp/cache". - - [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) - and change the default ``user_data_dir`` behaviour to use a *non*-roaming - profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because - a large roaming profile can cause login speed issues. The "only syncs on - logout" behaviour can cause surprises in appdata info. - - - appdirs 1.0.1 (never released) - ------------------------------ - - Started this changelog 27 July 2010. Before that this module originated in the - `Komodo `_ product as ``applib.py`` and then - as `applib/location.py - `_ (used by - `PyPM `_ in `ActivePython - `_). This is basically a fork of - applib.py 1.0.1 and applib/location.py 1.0.1. - - -Keywords: application directory log cache user -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/third_party/python/appdirs/README.rst b/third_party/python/appdirs/README.rst deleted file mode 100644 index dfafbdfbe6a6..000000000000 --- a/third_party/python/appdirs/README.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png - :target: http://travis-ci.org/ActiveState/appdirs - -the problem -=========== - -What directory should your app use for storing user data? If running on Mac OS X, you -should use:: - - ~/Library/Application Support/ - -If on Windows (at least English Win XP) that should be:: - - C:\Documents and Settings\\Application Data\Local Settings\\ - -or possibly:: - - C:\Documents and Settings\\Application Data\\ - -for `roaming profiles `_ but that is another story. - -On Linux (and other Unices) the dir, according to the `XDG -spec `_, is:: - - ~/.local/share/ - - -``appdirs`` to the rescue -========================= - -This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will -help you choose an appropriate: - -- user data dir (``user_data_dir``) -- user config dir (``user_config_dir``) -- user cache dir (``user_cache_dir``) -- site data dir (``site_data_dir``) -- site config dir (``site_config_dir``) -- user log dir (``user_log_dir``) - -and also: - -- is a single module so other Python packages can include their own private copy -- is slightly opinionated on the directory names used. Look for "OPINION" in - documentation and code for when an opinion is being applied. - - -some example output -=================== - -On Mac OS X:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/Users/trentm/Library/Application Support/SuperApp' - >>> site_data_dir(appname, appauthor) - '/Library/Application Support/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/Users/trentm/Library/Caches/SuperApp' - >>> user_log_dir(appname, appauthor) - '/Users/trentm/Library/Logs/SuperApp' - -On Windows 7:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' - >>> user_data_dir(appname, appauthor, roaming=True) - 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' - >>> user_cache_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' - >>> user_log_dir(appname, appauthor) - 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' - -On Linux:: - - >>> from appdirs import * - >>> appname = "SuperApp" - >>> appauthor = "Acme" - >>> user_data_dir(appname, appauthor) - '/home/trentm/.local/share/SuperApp - >>> site_data_dir(appname, appauthor) - '/usr/local/share/SuperApp' - >>> site_data_dir(appname, appauthor, multipath=True) - '/usr/local/share/SuperApp:/usr/share/SuperApp' - >>> user_cache_dir(appname, appauthor) - '/home/trentm/.cache/SuperApp' - >>> user_log_dir(appname, appauthor) - '/home/trentm/.cache/SuperApp/log' - >>> user_config_dir(appname) - '/home/trentm/.config/SuperApp' - >>> site_config_dir(appname) - '/etc/xdg/SuperApp' - >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' - >>> site_config_dir(appname, multipath=True) - '/etc/SuperApp:/usr/local/etc/SuperApp' - - -``AppDirs`` for convenience -=========================== - -:: - - >>> from appdirs import AppDirs - >>> dirs = AppDirs("SuperApp", "Acme") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp' - - - -Per-version isolation -===================== - -If you have multiple versions of your app in use that you want to be -able to run side-by-side, then you may want version-isolation for these -dirs:: - - >>> from appdirs import AppDirs - >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") - >>> dirs.user_data_dir - '/Users/trentm/Library/Application Support/SuperApp/1.0' - >>> dirs.site_data_dir - '/Library/Application Support/SuperApp/1.0' - >>> dirs.user_cache_dir - '/Users/trentm/Library/Caches/SuperApp/1.0' - >>> dirs.user_log_dir - '/Users/trentm/Library/Logs/SuperApp/1.0' - diff --git a/third_party/python/appdirs/TODO.md b/third_party/python/appdirs/TODO.md deleted file mode 100644 index 81e466f90412..000000000000 --- a/third_party/python/appdirs/TODO.md +++ /dev/null @@ -1 +0,0 @@ -- add some Windows 7 examples diff --git a/third_party/python/appdirs/LICENSE.txt b/third_party/python/appdirs/appdirs-1.4.4.dist-info/LICENSE.txt similarity index 100% rename from third_party/python/appdirs/LICENSE.txt rename to third_party/python/appdirs/appdirs-1.4.4.dist-info/LICENSE.txt diff --git a/third_party/python/appdirs/appdirs-1.4.4.dist-info/METADATA b/third_party/python/appdirs/appdirs-1.4.4.dist-info/METADATA new file mode 100644 index 000000000000..f95073104453 --- /dev/null +++ b/third_party/python/appdirs/appdirs-1.4.4.dist-info/METADATA @@ -0,0 +1,264 @@ +Metadata-Version: 2.1 +Name: appdirs +Version: 1.4.4 +Summary: A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir". +Home-page: http://github.com/ActiveState/appdirs +Author: Trent Mick +Author-email: trentm@gmail.com +Maintainer: Jeff Rouse +Maintainer-email: jr@its.to +License: MIT +Keywords: application directory log cache user +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries :: Python Modules + + +.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png + :target: http://travis-ci.org/ActiveState/appdirs + +the problem +=========== + +What directory should your app use for storing user data? If running on Mac OS X, you +should use:: + + ~/Library/Application Support/ + +If on Windows (at least English Win XP) that should be:: + + C:\Documents and Settings\\Application Data\Local Settings\\ + +or possibly:: + + C:\Documents and Settings\\Application Data\\ + +for `roaming profiles `_ but that is another story. + +On Linux (and other Unices) the dir, according to the `XDG +spec `_, is:: + + ~/.local/share/ + + +``appdirs`` to the rescue +========================= + +This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will +help you choose an appropriate: + +- user data dir (``user_data_dir``) +- user config dir (``user_config_dir``) +- user cache dir (``user_cache_dir``) +- site data dir (``site_data_dir``) +- site config dir (``site_config_dir``) +- user log dir (``user_log_dir``) + +and also: + +- is a single module so other Python packages can include their own private copy +- is slightly opinionated on the directory names used. Look for "OPINION" in + documentation and code for when an opinion is being applied. + + +some example output +=================== + +On Mac OS X:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/Users/trentm/Library/Application Support/SuperApp' + >>> site_data_dir(appname, appauthor) + '/Library/Application Support/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/Users/trentm/Library/Caches/SuperApp' + >>> user_log_dir(appname, appauthor) + '/Users/trentm/Library/Logs/SuperApp' + +On Windows 7:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + >>> user_data_dir(appname, appauthor, roaming=True) + 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' + >>> user_cache_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' + >>> user_log_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' + +On Linux:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/home/trentm/.local/share/SuperApp + >>> site_data_dir(appname, appauthor) + '/usr/local/share/SuperApp' + >>> site_data_dir(appname, appauthor, multipath=True) + '/usr/local/share/SuperApp:/usr/share/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp' + >>> user_log_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp/log' + >>> user_config_dir(appname) + '/home/trentm/.config/SuperApp' + >>> site_config_dir(appname) + '/etc/xdg/SuperApp' + >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' + >>> site_config_dir(appname, multipath=True) + '/etc/SuperApp:/usr/local/etc/SuperApp' + + +``AppDirs`` for convenience +=========================== + +:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp' + + + +Per-version isolation +===================== + +If you have multiple versions of your app in use that you want to be +able to run side-by-side, then you may want version-isolation for these +dirs:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp/1.0' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp/1.0' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp/1.0' + + + +appdirs Changelog +================= + +appdirs 1.4.4 +------------- +- [PR #92] Don't import appdirs from setup.py + +Project officially classified as Stable which is important +for inclusion in other distros such as ActivePython. + +First of several incremental releases to catch up on maintenance. + +appdirs 1.4.3 +------------- +- [PR #76] Python 3.6 invalid escape sequence deprecation fixes +- Fix for Python 3.6 support + +appdirs 1.4.2 +------------- +- [PR #84] Allow installing without setuptools +- [PR #86] Fix string delimiters in setup.py description +- Add Python 3.6 support + +appdirs 1.4.1 +------------- +- [issue #38] Fix _winreg import on Windows Py3 +- [issue #55] Make appname optional + +appdirs 1.4.0 +------------- +- [PR #42] AppAuthor is now optional on Windows +- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows + support requires `JNA `_. +- [PR #44] Fix incorrect behaviour of the site_config_dir method + +appdirs 1.3.0 +------------- +- [Unix, issue 16] Conform to XDG standard, instead of breaking it for + everybody +- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are + usually case sensitive, so mangling is not wise +- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result + based on XDG_DATA_DIRS and make room for respecting the standard which + specifies XDG_DATA_DIRS is a multiple-value variable +- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to + XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` + +appdirs 1.2.0 +------------- + +- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more + typical. +- [issue 9] Make ``unicode`` work on py3k. + +appdirs 1.1.0 +------------- + +- [issue 4] Add ``AppDirs.user_log_dir``. +- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec + `_. +- [Mac, issue 5] Fix ``site_data_dir()`` on Mac. +- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports + Python3 now. +- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use + ``opinion=False`` option to disable this. +- Add ``appdirs.AppDirs`` convenience class. Usage: + + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + +- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short + paths if there are high bit chars. +- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. + "~/.superapp/cache". +- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) + and change the default ``user_data_dir`` behaviour to use a *non*-roaming + profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because + a large roaming profile can cause login speed issues. The "only syncs on + logout" behaviour can cause surprises in appdata info. + + +appdirs 1.0.1 (never released) +------------------------------ + +Started this changelog 27 July 2010. Before that this module originated in the +`Komodo `_ product as ``applib.py`` and then +as `applib/location.py +`_ (used by +`PyPM `_ in `ActivePython +`_). This is basically a fork of +applib.py 1.0.1 and applib/location.py 1.0.1. + + + diff --git a/third_party/python/appdirs/appdirs-1.4.4.dist-info/RECORD b/third_party/python/appdirs/appdirs-1.4.4.dist-info/RECORD new file mode 100644 index 000000000000..9cbb30620ebf --- /dev/null +++ b/third_party/python/appdirs/appdirs-1.4.4.dist-info/RECORD @@ -0,0 +1,6 @@ +appdirs.py,sha256=g99s2sXhnvTEm79oj4bWI0Toapc-_SmKKNXvOXHkVic,24720 +appdirs-1.4.4.dist-info/LICENSE.txt,sha256=Nt200KdFqTqyAyA9cZCBSxuJcn0lTK_0jHp6-71HAAs,1097 +appdirs-1.4.4.dist-info/METADATA,sha256=k5TVfXMNKGHTfp2wm6EJKTuGwGNuoQR5TqQgH8iwG8M,8981 +appdirs-1.4.4.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +appdirs-1.4.4.dist-info/top_level.txt,sha256=nKncE8CUqZERJ6VuQWL4_bkunSPDNfn7KZqb4Tr5YEM,8 +appdirs-1.4.4.dist-info/RECORD,, diff --git a/third_party/python/appdirs/appdirs-1.4.4.dist-info/WHEEL b/third_party/python/appdirs/appdirs-1.4.4.dist-info/WHEEL new file mode 100644 index 000000000000..ef99c6cf3283 --- /dev/null +++ b/third_party/python/appdirs/appdirs-1.4.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/appdirs/appdirs-1.4.4.dist-info/top_level.txt b/third_party/python/appdirs/appdirs-1.4.4.dist-info/top_level.txt new file mode 100644 index 000000000000..d64bc321a11c --- /dev/null +++ b/third_party/python/appdirs/appdirs-1.4.4.dist-info/top_level.txt @@ -0,0 +1 @@ +appdirs diff --git a/third_party/python/appdirs/setup.cfg b/third_party/python/appdirs/setup.cfg deleted file mode 100644 index 1e3eb367c116..000000000000 --- a/third_party/python/appdirs/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/appdirs/setup.py b/third_party/python/appdirs/setup.py deleted file mode 100644 index 293c1c44d45a..000000000000 --- a/third_party/python/appdirs/setup.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -import sys -import os -import os.path -# appdirs is a dependency of setuptools, so allow installing without it. -try: - from setuptools import setup -except ImportError: - from distutils.core import setup -import ast - -tests_require = [] -if sys.version_info < (2, 7): - tests_require.append("unittest2") - - -def read(fname): - inf = open(os.path.join(os.path.dirname(__file__), fname)) - out = "\n" + inf.read().replace("\r\n", "\n") - inf.close() - return out - - -# Do not import `appdirs` yet, lest we import some random version on sys.path. -for line in read("appdirs.py").splitlines(): - if line.startswith("__version__"): - version = ast.literal_eval(line.split("=", 1)[1].strip()) - break - - -setup( - name='appdirs', - version=version, - description='A small Python module for determining appropriate ' + \ - 'platform-specific dirs, e.g. a "user data dir".', - long_description=read('README.rst') + '\n' + read('CHANGES.rst'), - classifiers=[c.strip() for c in """ - Development Status :: 5 - Production/Stable - Intended Audience :: Developers - License :: OSI Approved :: MIT License - Operating System :: OS Independent - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - Programming Language :: Python :: 3.5 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: Implementation :: PyPy - Programming Language :: Python :: Implementation :: CPython - Topic :: Software Development :: Libraries :: Python Modules - """.split('\n') if c.strip()], - test_suite='test.test_api', - tests_require=tests_require, - keywords='application directory log cache user', - author='Trent Mick', - author_email='trentm@gmail.com', - maintainer='Jeff Rouse', - maintainer_email='jr@its.to', - url='http://github.com/ActiveState/appdirs', - license='MIT', - py_modules=["appdirs"], -) diff --git a/third_party/python/appdirs/tox.ini b/third_party/python/appdirs/tox.ini deleted file mode 100644 index 85e3dd324f87..000000000000 --- a/third_party/python/appdirs/tox.ini +++ /dev/null @@ -1,5 +0,0 @@ -[tox] -envlist = py26, py27, py32, py33, py34, py35, py36 - -[testenv] -commands = python setup.py test diff --git a/third_party/python/atomicwrites/LICENSE b/third_party/python/atomicwrites/LICENSE deleted file mode 100644 index 3bbadc3af2cc..000000000000 --- a/third_party/python/atomicwrites/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2016 Markus Unterwaditzer - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/python/atomicwrites/MANIFEST.in b/third_party/python/atomicwrites/MANIFEST.in deleted file mode 100644 index 1b28469174f3..000000000000 --- a/third_party/python/atomicwrites/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include LICENSE -include README.rst - -recursive-include docs * -recursive-include tests * -prune docs/_build diff --git a/third_party/python/atomicwrites/PKG-INFO b/third_party/python/atomicwrites/PKG-INFO deleted file mode 100644 index eec6b7c305f2..000000000000 --- a/third_party/python/atomicwrites/PKG-INFO +++ /dev/null @@ -1,112 +0,0 @@ -Metadata-Version: 1.0 -Name: atomicwrites -Version: 1.1.5 -Summary: Atomic file writes. -Home-page: https://github.com/untitaker/python-atomicwrites -Author: Markus Unterwaditzer -Author-email: markus@unterwaditzer.net -License: MIT -Description: =================== - python-atomicwrites - =================== - - .. image:: https://travis-ci.org/untitaker/python-atomicwrites.svg?branch=master - :target: https://travis-ci.org/untitaker/python-atomicwrites - - .. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true - :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master - - Atomic file writes. - - .. code-block:: python - - from atomicwrites import atomic_write - - with atomic_write('foo.txt', overwrite=True) as f: - f.write('Hello world.') - # "foo.txt" doesn't exist yet. - - # Now it does. - - - Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): - - - Race-free assertion that the target file doesn't yet exist. This can be - controlled with the ``overwrite`` parameter. - - - Windows support, although not well-tested. The MSDN resources are not very - explicit about which operations are atomic. - - - Simple high-level API that wraps a very flexible class-based API. - - - Consistent error handling across platforms. - - - How it works - ============ - - It uses a temporary file in the same directory as the given path. This ensures - that the temporary file resides on the same filesystem. - - The temporary file will then be atomically moved to the target location: On - POSIX, it will use ``rename`` if files should be overwritten, otherwise a - combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through - stdlib's ``ctypes`` with the appropriate flags. - - Note that with ``link`` and ``unlink``, there's a timewindow where the file - might be available under two entries in the filesystem: The name of the - temporary file, and the name of the target file. - - Also note that the permissions of the target file may change this way. In some - situations a ``chmod`` can be issued without any concurrency problems, but - since that is not always the case, this library doesn't do it by itself. - - .. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx - - fsync - ----- - - On POSIX, ``fsync`` is invoked on the temporary file after it is written (to - flush file content and metadata), and on the parent directory after the file is - moved (to flush filename). - - ``fsync`` does not take care of disks' internal buffers, but there don't seem - to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with - ``F_FULLFSYNC`` instead of ``fsync`` for that reason. - - On Windows, `_commit `_ - is used, but there are no guarantees about disk internal buffers. - - Alternatives and Credit - ======================= - - Atomicwrites is directly inspired by the following libraries (and shares a - minimal amount of code): - - - The Trac project's `utility functions - `_, - also used in `Werkzeug `_ and - `mitsuhiko/python-atomicfile - `_. The idea to use - ``ctypes`` instead of ``PyWin32`` originated there. - - - `abarnert/fatomic `_. Windows support - (based on ``PyWin32``) was originally taken from there. - - Other alternatives to atomicwrites include: - - - `sashka/atomicfile `_. Originally I - considered using that, but at the time it was lacking a lot of features I - needed (Windows support, overwrite-parameter, overriding behavior through - subclassing). - - - The `Boltons library collection `_ - features a class for atomic file writes, which seems to have a very similar - ``overwrite`` parameter. It is lacking Windows support though. - - License - ======= - - Licensed under the MIT, see ``LICENSE``. - -Platform: UNKNOWN diff --git a/third_party/python/atomicwrites/README.rst b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/DESCRIPTION.rst similarity index 99% rename from third_party/python/atomicwrites/README.rst rename to third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/DESCRIPTION.rst index 3a5658cbd8f3..ab0e07980781 100644 --- a/third_party/python/atomicwrites/README.rst +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/DESCRIPTION.rst @@ -100,3 +100,5 @@ License ======= Licensed under the MIT, see ``LICENSE``. + + diff --git a/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/METADATA b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/METADATA new file mode 100644 index 000000000000..b729095150a5 --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/METADATA @@ -0,0 +1,114 @@ +Metadata-Version: 2.0 +Name: atomicwrites +Version: 1.1.5 +Summary: Atomic file writes. +Home-page: https://github.com/untitaker/python-atomicwrites +Author: Markus Unterwaditzer +Author-email: markus@unterwaditzer.net +License: MIT +Platform: UNKNOWN + +=================== +python-atomicwrites +=================== + +.. image:: https://travis-ci.org/untitaker/python-atomicwrites.svg?branch=master + :target: https://travis-ci.org/untitaker/python-atomicwrites + +.. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true + :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master + +Atomic file writes. + +.. code-block:: python + + from atomicwrites import atomic_write + + with atomic_write('foo.txt', overwrite=True) as f: + f.write('Hello world.') + # "foo.txt" doesn't exist yet. + + # Now it does. + + +Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): + +- Race-free assertion that the target file doesn't yet exist. This can be + controlled with the ``overwrite`` parameter. + +- Windows support, although not well-tested. The MSDN resources are not very + explicit about which operations are atomic. + +- Simple high-level API that wraps a very flexible class-based API. + +- Consistent error handling across platforms. + + +How it works +============ + +It uses a temporary file in the same directory as the given path. This ensures +that the temporary file resides on the same filesystem. + +The temporary file will then be atomically moved to the target location: On +POSIX, it will use ``rename`` if files should be overwritten, otherwise a +combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through +stdlib's ``ctypes`` with the appropriate flags. + +Note that with ``link`` and ``unlink``, there's a timewindow where the file +might be available under two entries in the filesystem: The name of the +temporary file, and the name of the target file. + +Also note that the permissions of the target file may change this way. In some +situations a ``chmod`` can be issued without any concurrency problems, but +since that is not always the case, this library doesn't do it by itself. + +.. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx + +fsync +----- + +On POSIX, ``fsync`` is invoked on the temporary file after it is written (to +flush file content and metadata), and on the parent directory after the file is +moved (to flush filename). + +``fsync`` does not take care of disks' internal buffers, but there don't seem +to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with +``F_FULLFSYNC`` instead of ``fsync`` for that reason. + +On Windows, `_commit `_ +is used, but there are no guarantees about disk internal buffers. + +Alternatives and Credit +======================= + +Atomicwrites is directly inspired by the following libraries (and shares a +minimal amount of code): + +- The Trac project's `utility functions + `_, + also used in `Werkzeug `_ and + `mitsuhiko/python-atomicfile + `_. The idea to use + ``ctypes`` instead of ``PyWin32`` originated there. + +- `abarnert/fatomic `_. Windows support + (based on ``PyWin32``) was originally taken from there. + +Other alternatives to atomicwrites include: + +- `sashka/atomicfile `_. Originally I + considered using that, but at the time it was lacking a lot of features I + needed (Windows support, overwrite-parameter, overriding behavior through + subclassing). + +- The `Boltons library collection `_ + features a class for atomic file writes, which seems to have a very similar + ``overwrite`` parameter. It is lacking Windows support though. + +License +======= + +Licensed under the MIT, see ``LICENSE``. + + diff --git a/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/RECORD b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/RECORD new file mode 100644 index 000000000000..4b4c30c06075 --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/RECORD @@ -0,0 +1,7 @@ +atomicwrites-1.1.5.dist-info/DESCRIPTION.rst,sha256=Ia6eAs4RhHYEFnlTyHiv-2KRbqc3nsvs9h1qZjswZpI,3793 +atomicwrites-1.1.5.dist-info/metadata.json,sha256=LhGqv-JWg00kC8dQy7ViPGi1WhkZ7kWtDSw9Z04z05w,431 +atomicwrites-1.1.5.dist-info/RECORD,, +atomicwrites-1.1.5.dist-info/top_level.txt,sha256=ks64zKVUkrl2ZrrP046CsytXlSGf8gLG-IcoXpNyeoc,13 +atomicwrites-1.1.5.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +atomicwrites-1.1.5.dist-info/METADATA,sha256=l9iz0IXOVeIS3sa_DpBG4HwePk0kKPqWhOGj_pxZqaM,4038 +atomicwrites/__init__.py,sha256=qqGl8x1hJTc7dqug1kO-jMsjQe11SSWZZIdUp_IQx8A,5965 diff --git a/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/WHEEL b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/WHEEL new file mode 100644 index 000000000000..9dff69d86102 --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/metadata.json b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/metadata.json new file mode 100644 index 000000000000..326eed99acac --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/metadata.json @@ -0,0 +1 @@ +{"metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "license": "MIT", "name": "atomicwrites", "extensions": {"python.details": {"contacts": [{"role": "author", "email": "markus@unterwaditzer.net", "name": "Markus Unterwaditzer"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/untitaker/python-atomicwrites"}}}, "version": "1.1.5", "summary": "Atomic file writes."} \ No newline at end of file diff --git a/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/top_level.txt b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/top_level.txt new file mode 100644 index 000000000000..5fa5a87d8bcb --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites-1.1.5.dist-info/top_level.txt @@ -0,0 +1 @@ +atomicwrites diff --git a/third_party/python/atomicwrites/setup.cfg b/third_party/python/atomicwrites/setup.cfg deleted file mode 100644 index 3e89eac2c0dd..000000000000 --- a/third_party/python/atomicwrites/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[wheel] -universal = 1 - -[egg_info] -tag_date = 0 -tag_svn_revision = 0 -tag_build = - diff --git a/third_party/python/atomicwrites/setup.py b/third_party/python/atomicwrites/setup.py deleted file mode 100644 index 98488e9b9830..000000000000 --- a/third_party/python/atomicwrites/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -import ast -import re - -from setuptools import find_packages, setup - - -_version_re = re.compile(r'__version__\s+=\s+(.*)') - - -with open('atomicwrites/__init__.py', 'rb') as f: - version = str(ast.literal_eval(_version_re.search( - f.read().decode('utf-8')).group(1))) - -setup( - name='atomicwrites', - version=version, - author='Markus Unterwaditzer', - author_email='markus@unterwaditzer.net', - url='https://github.com/untitaker/python-atomicwrites', - description='Atomic file writes.', - license='MIT', - long_description=open('README.rst').read(), - packages=find_packages(exclude=['tests.*', 'tests']), - include_package_data=True, -) diff --git a/third_party/python/attrs/.coveragerc b/third_party/python/attrs/.coveragerc deleted file mode 100644 index 093c119431ae..000000000000 --- a/third_party/python/attrs/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[run] -branch = True -source = - attr - -[paths] -source = - src/attr - .tox/*/lib/python*/site-packages/attr - .tox/pypy/site-packages/attr - -[report] -show_missing = True diff --git a/third_party/python/attrs/.github/CODE_OF_CONDUCT.rst b/third_party/python/attrs/.github/CODE_OF_CONDUCT.rst deleted file mode 100644 index 56e8914ce2be..000000000000 --- a/third_party/python/attrs/.github/CODE_OF_CONDUCT.rst +++ /dev/null @@ -1,55 +0,0 @@ -Contributor Covenant Code of Conduct -==================================== - -Our Pledge ----------- - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -Our Standards -------------- - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -Our Responsibilities --------------------- - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -Scope ------ - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. -Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -Representation of a project may be further defined and clarified by project maintainers. - -Enforcement ------------ - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hs@ox.cx. -All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. -The project team is obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -Attribution ------------ - -This Code of Conduct is adapted from the `Contributor Covenant `_, version 1.4, available at . diff --git a/third_party/python/attrs/.github/CONTRIBUTING.rst b/third_party/python/attrs/.github/CONTRIBUTING.rst deleted file mode 100644 index c43c2f1ff69b..000000000000 --- a/third_party/python/attrs/.github/CONTRIBUTING.rst +++ /dev/null @@ -1,250 +0,0 @@ -How To Contribute -================= - -First off, thank you for considering contributing to ``attrs``! -It's people like *you* who make it such a great tool for everyone. - -This document intends to make contribution more accessible by codifying tribal knowledge and expectations. -Don't be afraid to open half-finished PRs, and ask questions if something is unclear! - - -Support -------- - -In case you'd like to help out but don't want to deal with GitHub, there's a great opportunity: -help your fellow developers on `StackOverflow `_! - -The offical tag is ``python-attrs`` and helping out in support frees us up to improve ``attrs`` instead! - - -Workflow --------- - -- No contribution is too small! - Please submit as many fixes for typos and grammar bloopers as you can! -- Try to limit each pull request to *one* change only. -- Since we squash on merge, it's up to you how you handle updates to the master branch. - Whether you prefer to rebase on master or merge master into your branch, do whatever is more comfortable for you. -- *Always* add tests and docs for your code. - This is a hard rule; patches with missing tests or documentation can't be merged. -- Make sure your changes pass our CI_. - You won't get any feedback until it's green unless you ask for it. -- Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done. -- Don’t break `backward compatibility`_. - - -Code ----- - -- Obey `PEP 8`_ and `PEP 257`_. - We use the ``"""``\ -on-separate-lines style for docstrings: - - .. code-block:: python - - def func(x): - """ - Do something. - - :param str x: A very important parameter. - - :rtype: str - """ -- If you add or change public APIs, tag the docstring using ``.. versionadded:: 16.0.0 WHAT`` or ``.. versionchanged:: 16.2.0 WHAT``. -- We use isort_ to sort our imports, and we follow the Black_ code style with a line length of 79 characters. - As long as you run our full tox suite before committing, or install our pre-commit_ hooks (ideally you'll do both -- see below "Local Development Environment"), you won't have to spend any time on formatting your code at all. - If you don't, CI will catch it for you -- but that seems like a waste of your time! - - -Tests ------ - -- Write your asserts as ``expected == actual`` to line them up nicely: - - .. code-block:: python - - x = f() - - assert 42 == x.some_attribute - assert "foo" == x._a_private_attribute - -- To run the test suite, all you need is a recent tox_. - It will ensure the test suite runs with all dependencies against all Python versions just as it will on Travis CI. - If you lack some Python versions, you can can always limit the environments like ``tox -e py27,py35`` (in that case you may want to look into pyenv_, which makes it very easy to install many different Python versions in parallel). -- Write `good test docstrings`_. -- To ensure new features work well with the rest of the system, they should be also added to our `Hypothesis`_ testing strategy, which is found in ``tests/strategies.py``. -- If you've changed or added public APIs, please update our type stubs (files ending in ``.pyi``). - - -Documentation -------------- - -- Use `semantic newlines`_ in reStructuredText_ files (files ending in ``.rst``): - - .. code-block:: rst - - This is a sentence. - This is another sentence. - -- If you start a new section, add two blank lines before and one blank line after the header, except if two headers follow immediately after each other: - - .. code-block:: rst - - Last line of previous section. - - - Header of New Top Section - ------------------------- - - Header of New Section - ^^^^^^^^^^^^^^^^^^^^^ - - First line of new section. - -- If you add a new feature, demonstrate its awesomeness on the `examples page`_! - - -Changelog -^^^^^^^^^ - -If your change is noteworthy, there needs to be a changelog entry so our users can learn about it! - -To avoid merge conflicts, we use the towncrier_ package to manage our changelog. -``towncrier`` uses independent files for each pull request -- so called *news fragments* -- instead of one monolithic changelog file. -On release, those news fragments are compiled into our ``CHANGELOG.rst``. - -You don't need to install ``towncrier`` yourself, you just have to abide by a few simple rules: - -- For each pull request, add a new file into ``changelog.d`` with a filename adhering to the ``pr#.(change|deprecation|breaking).rst`` schema: - For example, ``changelog.d/42.change.rst`` for a non-breaking change that is proposed in pull request #42. -- As with other docs, please use `semantic newlines`_ within news fragments. -- Wrap symbols like modules, functions, or classes into double backticks so they are rendered in a ``monospace font``. -- Wrap arguments into asterisks like in docstrings: *these* or *attributes*. -- If you mention functions or other callables, add parentheses at the end of their names: ``attr.func()`` or ``attr.Class.method()``. - This makes the changelog a lot more readable. -- Prefer simple past tense or constructions with "now". - For example: - - + Added ``attr.validators.func()``. - + ``attr.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. -- If you want to reference multiple issues, copy the news fragment to another filename. - ``towncrier`` will merge all news fragments with identical contents into one entry with multiple links to the respective pull requests. - -Example entries: - - .. code-block:: rst - - Added ``attr.validators.func()``. - The feature really *is* awesome. - -or: - - .. code-block:: rst - - ``attr.func()`` now doesn't crash the Large Hadron Collider anymore when passed the *foobar* argument. - The bug really *was* nasty. - ----- - -``tox -e changelog`` will render the current changelog to the terminal if you have any doubts. - - -Local Development Environment ------------------------------ - -You can (and should) run our test suite using tox_. -However, you’ll probably want a more traditional environment as well. -We highly recommend to develop using the latest Python 3 release because ``attrs`` tries to take advantage of modern features whenever possible. - -First create a `virtual environment `_. -It’s out of scope for this document to list all the ways to manage virtual environments in Python, but if you don’t already have a pet way, take some time to look at tools like `pew `_, `virtualfish `_, and `virtualenvwrapper `_. - -Next, get an up to date checkout of the ``attrs`` repository: - -.. code-block:: bash - - $ git clone git@github.com:python-attrs/attrs.git - -or if you want to use git via ``https``: - -.. code-block:: bash - - $ git clone https://github.com/python-attrs/attrs.git - -Change into the newly created directory and **after activating your virtual environment** install an editable version of ``attrs`` along with its tests and docs requirements: - -.. code-block:: bash - - $ cd attrs - $ pip install -e '.[dev]' - -At this point, - -.. code-block:: bash - - $ python -m pytest - -should work and pass, as should: - -.. code-block:: bash - - $ cd docs - $ make html - -The built documentation can then be found in ``docs/_build/html/``. - -To avoid committing code that violates our style guide, we strongly advise you to install pre-commit_ [#f1]_ hooks: - -.. code-block:: bash - - $ pre-commit install - -You can also run them anytime (as our tox does) using: - -.. code-block:: bash - - $ pre-commit run --all-files - - -.. [#f1] pre-commit should have been installed into your virtualenv automatically when you ran ``pip install -e '.[dev]'`` above. If pre-commit is missing, it may be that you need to re-run ``pip install -e '.[dev]'``. - - -Governance ----------- - -``attrs`` is maintained by `team of volunteers`_ that is always open to new members that share our vision of a fast, lean, and magic-free library that empowers programmers to write better code with less effort. -If you'd like to join, just get a pull request merged and ask to be added in the very same pull request! - -**The simple rule is that everyone is welcome to review/merge pull requests of others but nobody is allowed to merge their own code.** - -`Hynek Schlawack`_ acts reluctantly as the BDFL_ and has the final say over design decisions. - - -**** - -Please note that this project is released with a Contributor `Code of Conduct`_. -By participating in this project you agree to abide by its terms. -Please report any harm to `Hynek Schlawack`_ in any way you find appropriate. - -Thank you for considering contributing to ``attrs``! - - -.. _`Hynek Schlawack`: https://hynek.me/about/ -.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ -.. _`PEP 257`: https://www.python.org/dev/peps/pep-0257/ -.. _`good test docstrings`: https://jml.io/pages/test-docstrings.html -.. _`Code of Conduct`: https://github.com/python-attrs/attrs/blob/master/.github/CODE_OF_CONDUCT.rst -.. _changelog: https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst -.. _`backward compatibility`: https://www.attrs.org/en/latest/backward-compatibility.html -.. _tox: https://tox.readthedocs.io/ -.. _pyenv: https://github.com/pyenv/pyenv -.. _reStructuredText: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html -.. _semantic newlines: https://rhodesmill.org/brandon/2012/one-sentence-per-line/ -.. _examples page: https://github.com/python-attrs/attrs/blob/master/docs/examples.rst -.. _Hypothesis: https://hypothesis.readthedocs.io/ -.. _CI: https://travis-ci.org/python-attrs/attrs/ -.. _`team of volunteers`: https://github.com/python-attrs -.. _BDFL: https://en.wikipedia.org/wiki/Benevolent_dictator_for_life -.. _towncrier: https://pypi.org/project/towncrier -.. _black: https://github.com/ambv/black -.. _pre-commit: https://pre-commit.com/ -.. _isort: https://github.com/timothycrosley/isort diff --git a/third_party/python/attrs/.github/PULL_REQUEST_TEMPLATE.md b/third_party/python/attrs/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8ac4f7aea4d3..000000000000 --- a/third_party/python/attrs/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,18 +0,0 @@ -# Pull Request Check List - -This is just a reminder about the most common mistakes. Please make sure that you tick all *appropriate* boxes. But please read our [contribution guide](https://www.attrs.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles! - -If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing to do. - -- [ ] Added **tests** for changed code. -- [ ] New features have been added to our [Hypothesis testing strategy](https://github.com/python-attrs/attrs/blob/master/tests/strategies.py). -- [ ] Changes or additions to public APIs are reflected in our type stubs (files ending in ``.pyi``). - - [ ] ...and used in the stub test file `tests/typing_example.py`. -- [ ] Updated **documentation** for changed code. - - [ ] New functions/classes have to be added to `docs/api.rst` by hand. - - [ ] Changes to the signature of `@attr.s()` have to be added by hand too. - - [ ] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded). -- [ ] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/). -- [ ] Changes (and possible deprecations) have news fragments in [`changelog.d`](https://github.com/python-attrs/attrs/blob/master/changelog.d). - -If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! diff --git a/third_party/python/attrs/.pre-commit-config.yaml b/third_party/python/attrs/.pre-commit-config.yaml deleted file mode 100644 index a35fff26c80e..000000000000 --- a/third_party/python/attrs/.pre-commit-config.yaml +++ /dev/null @@ -1,33 +0,0 @@ -repos: - - repo: https://github.com/ambv/black - rev: 18.9b0 - hooks: - - id: black - language_version: python3.7 - # override until resolved: https://github.com/ambv/black/issues/402 - files: \.pyi?$ - types: [] - - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.6 - hooks: - - id: flake8 - language_version: python3.7 - - - repo: https://github.com/asottile/seed-isort-config - rev: v1.6.0 - hooks: - - id: seed-isort-config - - - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.4 - hooks: - - id: isort - language_version: python3.7 - - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.1.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: debug-statements diff --git a/third_party/python/attrs/.readthedocs.yml b/third_party/python/attrs/.readthedocs.yml deleted file mode 100644 index e6a8043b2d9e..000000000000 --- a/third_party/python/attrs/.readthedocs.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -version: 2 -python: - version: 3.7 - - install: - - method: pip - path: . - extra_requirements: - - docs diff --git a/third_party/python/attrs/.travis.yml b/third_party/python/attrs/.travis.yml deleted file mode 100644 index 8b135d6e652a..000000000000 --- a/third_party/python/attrs/.travis.yml +++ /dev/null @@ -1,77 +0,0 @@ -dist: xenial -group: travis_latest -cache: - directories: - - $HOME/.cache/pip - -language: python - - -matrix: - fast_finish: true - - include: - # lint - - python: "3.7" - stage: lint - env: TOXENV=lint - - python: "3.7" - env: TOXENV=manifest - - python: "3.7" - env: TOXENV=typing - - # test - - python: "2.7" - stage: test - env: TOXENV=py27 - - python: "3.4" - env: TOXENV=py34 - - python: "3.5" - env: TOXENV=py35 - - python: "3.6" - env: TOXENV=py36 - - python: "pypy" - env: TOXENV=pypy - dist: trusty - - python: "pypy3" - env: TOXENV=pypy3 - dist: trusty - - python: "3.7" - env: TOXENV=py37 - - # Prevent breakage by new releases - - python: "3.7-dev" - env: TOXENV=py37 - - # Docs - - python: "3.7" - stage: docs - env: TOXENV=docs - - python: "3.7" - env: TOXENV=pypi-description - - python: "3.7" - env: TOXENV=changelog - - allow_failures: - - python: "3.7-dev" - - -install: - - pip install --upgrade tox - - -script: - - tox - - -before_install: - - pip install codecov - - -after_success: - - tox -e coverage-report - - codecov - - -notifications: - email: false diff --git a/third_party/python/attrs/AUTHORS.rst b/third_party/python/attrs/AUTHORS.rst deleted file mode 100644 index f14ef6c60749..000000000000 --- a/third_party/python/attrs/AUTHORS.rst +++ /dev/null @@ -1,11 +0,0 @@ -Credits -======= - -``attrs`` is written and maintained by `Hynek Schlawack `_. - -The development is kindly supported by `Variomedia AG `_. - -A full list of contributors can be found in `GitHub's overview `_. - -It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. -Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? diff --git a/third_party/python/attrs/CHANGELOG.rst b/third_party/python/attrs/CHANGELOG.rst deleted file mode 100644 index 1bcfb431e72a..000000000000 --- a/third_party/python/attrs/CHANGELOG.rst +++ /dev/null @@ -1,559 +0,0 @@ -Changelog -========= - -Versions follow `CalVer `_ with a strict backwards compatibility policy. -The third digit is only for regressions. - -.. towncrier release notes start - -19.1.0 (2019-03-03) -------------------- - -Backward-incompatible Changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Fixed a bug where deserialized objects with ``cache_hash=True`` could have incorrect hash code values. - This change breaks classes with ``cache_hash=True`` when a custom ``__setstate__`` is present. - An exception will be thrown when applying the ``attrs`` annotation to such a class. - This limitation is tracked in issue `#494 `_. - `#482 `_ - - -Changes -^^^^^^^ - -- Add ``is_callable``, ``deep_iterable``, and ``deep_mapping`` validators. - - * ``is_callable``: validates that a value is callable - * ``deep_iterable``: Allows recursion down into an iterable, - applying another validator to every member in the iterable - as well as applying an optional validator to the iterable itself. - * ``deep_mapping``: Allows recursion down into the items in a mapping object, - applying a key validator and a value validator to the key and value in every item. - Also applies an optional validator to the mapping object itself. - - You can find them in the ``attr.validators`` package. - `#425 `_ -- Fixed stub files to prevent errors raised by mypy's ``disallow_any_generics = True`` option. - `#443 `_ -- Attributes with ``init=False`` now can follow after ``kw_only=True`` attributes. - `#450 `_ -- ``attrs`` now has first class support for defining exception classes. - - If you define a class using ``@attr.s(auto_exc=True)`` and subclass an exception, the class will behave like a well-behaved exception class including an appropriate ``__str__`` method, and all attributes additionally available in an ``args`` attribute. - `#500 `_ -- Clarified documentation for hashing to warn that hashable objects should be deeply immutable (in their usage, even if this is not enforced). - `#503 `_ - - ----- - - -18.2.0 (2018-09-01) -------------------- - -Deprecations -^^^^^^^^^^^^ - -- Comparing subclasses using ``<``, ``>``, ``<=``, and ``>=`` is now deprecated. - The docs always claimed that instances are only compared if the types are identical, so this is a first step to conform to the docs. - - Equality operators (``==`` and ``!=``) were always strict in this regard. - `#394 `_ - - -Changes -^^^^^^^ - -- ``attrs`` now ships its own `PEP 484 `_ type hints. - Together with `mypy `_'s ``attrs`` plugin, you've got all you need for writing statically typed code in both Python 2 and 3! - - At that occasion, we've also added `narrative docs `_ about type annotations in ``attrs``. - `#238 `_ -- Added *kw_only* arguments to ``attr.ib`` and ``attr.s``, and a corresponding *kw_only* attribute to ``attr.Attribute``. - This change makes it possible to have a generated ``__init__`` with keyword-only arguments on Python 3, relaxing the required ordering of default and non-default valued attributes. - `#281 `_, - `#411 `_ -- The test suite now runs with ``hypothesis.HealthCheck.too_slow`` disabled to prevent CI breakage on slower computers. - `#364 `_, - `#396 `_ -- ``attr.validators.in_()`` now raises a ``ValueError`` with a useful message even if the options are a string and the value is not a string. - `#383 `_ -- ``attr.asdict()`` now properly handles deeply nested lists and dictionaries. - `#395 `_ -- Added ``attr.converters.default_if_none()`` that allows to replace ``None`` values in attributes. - For example ``attr.ib(converter=default_if_none(""))`` replaces ``None`` by empty strings. - `#400 `_, - `#414 `_ -- Fixed a reference leak where the original class would remain live after being replaced when ``slots=True`` is set. - `#407 `_ -- Slotted classes can now be made weakly referenceable by passing ``@attr.s(weakref_slot=True)``. - `#420 `_ -- Added *cache_hash* option to ``@attr.s`` which causes the hash code to be computed once and stored on the object. - `#425 `_ -- Attributes can be named ``property`` and ``itemgetter`` now. - `#430 `_ -- It is now possible to override a base class' class variable using only class annotations. - `#431 `_ - - ----- - - -18.1.0 (2018-05-03) -------------------- - -Changes -^^^^^^^ - -- ``x=X(); x.cycle = x; repr(x)`` will no longer raise a ``RecursionError``, and will instead show as ``X(x=...)``. - - `#95 `_ -- ``attr.ib(factory=f)`` is now syntactic sugar for the common case of ``attr.ib(default=attr.Factory(f))``. - - `#178 `_, - `#356 `_ -- Added ``attr.field_dict()`` to return an ordered dictionary of ``attrs`` attributes for a class, whose keys are the attribute names. - - `#290 `_, - `#349 `_ -- The order of attributes that are passed into ``attr.make_class()`` or the *these* argument of ``@attr.s()`` is now retained if the dictionary is ordered (i.e. ``dict`` on Python 3.6 and later, ``collections.OrderedDict`` otherwise). - - Before, the order was always determined by the order in which the attributes have been defined which may not be desirable when creating classes programatically. - - `#300 `_, - `#339 `_, - `#343 `_ -- In slotted classes, ``__getstate__`` and ``__setstate__`` now ignore the ``__weakref__`` attribute. - - `#311 `_, - `#326 `_ -- Setting the cell type is now completely best effort. - This fixes ``attrs`` on Jython. - - We cannot make any guarantees regarding Jython though, because our test suite cannot run due to dependency incompatabilities. - - `#321 `_, - `#334 `_ -- If ``attr.s`` is passed a *these* argument, it will no longer attempt to remove attributes with the same name from the class body. - - `#322 `_, - `#323 `_ -- The hash of ``attr.NOTHING`` is now vegan and faster on 32bit Python builds. - - `#331 `_, - `#332 `_ -- The overhead of instantiating frozen dict classes is virtually eliminated. - `#336 `_ -- Generated ``__init__`` methods now have an ``__annotations__`` attribute derived from the types of the fields. - - `#363 `_ -- We have restructured the documentation a bit to account for ``attrs``' growth in scope. - Instead of putting everything into the `examples `_ page, we have started to extract narrative chapters. - - So far, we've added chapters on `initialization `_ and `hashing `_. - - Expect more to come! - - `#369 `_, - `#370 `_ - - ----- - - -17.4.0 (2017-12-30) -------------------- - -Backward-incompatible Changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- The traversal of MROs when using multiple inheritance was backward: - If you defined a class ``C`` that subclasses ``A`` and ``B`` like ``C(A, B)``, ``attrs`` would have collected the attributes from ``B`` *before* those of ``A``. - - This is now fixed and means that in classes that employ multiple inheritance, the output of ``__repr__`` and the order of positional arguments in ``__init__`` changes. - Because of the nature of this bug, a proper deprecation cycle was unfortunately impossible. - - Generally speaking, it's advisable to prefer ``kwargs``-based initialization anyways – *especially* if you employ multiple inheritance and diamond-shaped hierarchies. - - `#298 `_, - `#299 `_, - `#304 `_ -- The ``__repr__`` set by ``attrs`` no longer produces an ``AttributeError`` when the instance is missing some of the specified attributes (either through deleting or after using ``init=False`` on some attributes). - - This can break code that relied on ``repr(attr_cls_instance)`` raising ``AttributeError`` to check if any ``attrs``-specified members were unset. - - If you were using this, you can implement a custom method for checking this:: - - def has_unset_members(self): - for field in attr.fields(type(self)): - try: - getattr(self, field.name) - except AttributeError: - return True - return False - - `#308 `_ - - -Deprecations -^^^^^^^^^^^^ - -- The ``attr.ib(convert=callable)`` option is now deprecated in favor of ``attr.ib(converter=callable)``. - - This is done to achieve consistency with other noun-based arguments like *validator*. - - *convert* will keep working until at least January 2019 while raising a ``DeprecationWarning``. - - `#307 `_ - - -Changes -^^^^^^^ - -- Generated ``__hash__`` methods now hash the class type along with the attribute values. - Until now the hashes of two classes with the same values were identical which was a bug. - - The generated method is also *much* faster now. - - `#261 `_, - `#295 `_, - `#296 `_ -- ``attr.ib``\ ’s *metadata* argument now defaults to a unique empty ``dict`` instance instead of sharing a common empty ``dict`` for all. - The singleton empty ``dict`` is still enforced. - - `#280 `_ -- ``ctypes`` is optional now however if it's missing, a bare ``super()`` will not work in slotted classes. - This should only happen in special environments like Google App Engine. - - `#284 `_, - `#286 `_ -- The attribute redefinition feature introduced in 17.3.0 now takes into account if an attribute is redefined via multiple inheritance. - In that case, the definition that is closer to the base of the class hierarchy wins. - - `#285 `_, - `#287 `_ -- Subclasses of ``auto_attribs=True`` can be empty now. - - `#291 `_, - `#292 `_ -- Equality tests are *much* faster now. - - `#306 `_ -- All generated methods now have correct ``__module__``, ``__name__``, and (on Python 3) ``__qualname__`` attributes. - - `#309 `_ - - ----- - - -17.3.0 (2017-11-08) -------------------- - -Backward-incompatible Changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Attributes are no longer defined on the class body. - - This means that if you define a class ``C`` with an attribute ``x``, the class will *not* have an attribute ``x`` for introspection. - Instead of ``C.x``, use ``attr.fields(C).x`` or look at ``C.__attrs_attrs__``. - The old behavior has been deprecated since version 16.1. - (`#253 `_) - - -Changes -^^^^^^^ - -- ``super()`` and ``__class__`` now work with slotted classes on Python 3. - (`#102 `_, `#226 `_, `#269 `_, `#270 `_, `#272 `_) -- Added *type* argument to ``attr.ib()`` and corresponding ``type`` attribute to ``attr.Attribute``. - - This change paves the way for automatic type checking and serialization (though as of this release ``attrs`` does not make use of it). - In Python 3.6 or higher, the value of ``attr.Attribute.type`` can alternately be set using variable type annotations - (see `PEP 526 `_). - (`#151 `_, `#214 `_, `#215 `_, `#239 `_) -- The combination of ``str=True`` and ``slots=True`` now works on Python 2. - (`#198 `_) -- ``attr.Factory`` is hashable again. - (`#204 `_) -- Subclasses now can overwrite attribute definitions of their base classes. - - That means that you can -- for example -- change the default value for an attribute by redefining it. - (`#221 `_, `#229 `_) -- Added new option *auto_attribs* to ``@attr.s`` that allows to collect annotated fields without setting them to ``attr.ib()``. - - Setting a field to an ``attr.ib()`` is still possible to supply options like validators. - Setting it to any other value is treated like it was passed as ``attr.ib(default=value)`` -- passing an instance of ``attr.Factory`` also works as expected. - (`#262 `_, `#277 `_) -- Instances of classes created using ``attr.make_class()`` can now be pickled. - (`#282 `_) - - ----- - - -17.2.0 (2017-05-24) -------------------- - - -Changes: -^^^^^^^^ - -- Validators are hashable again. - Note that validators may become frozen in the future, pending availability of no-overhead frozen classes. - `#192 `_ - - ----- - - -17.1.0 (2017-05-16) -------------------- - -To encourage more participation, the project has also been moved into a `dedicated GitHub organization `_ and everyone is most welcome to join! - -``attrs`` also has a logo now! - -.. image:: https://www.attrs.org/en/latest/_static/attrs_logo.png - :alt: attrs logo - - -Backward-incompatible Changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- ``attrs`` will set the ``__hash__()`` method to ``None`` by default now. - The way hashes were handled before was in conflict with `Python's specification `_. - This *may* break some software although this breakage is most likely just surfacing of latent bugs. - You can always make ``attrs`` create the ``__hash__()`` method using ``@attr.s(hash=True)``. - See `#136`_ for the rationale of this change. - - .. warning:: - - Please *do not* upgrade blindly and *do* test your software! - *Especially* if you use instances as dict keys or put them into sets! - -- Correspondingly, ``attr.ib``'s *hash* argument is ``None`` by default too and mirrors the *cmp* argument as it should. - - -Deprecations: -^^^^^^^^^^^^^ - -- ``attr.assoc()`` is now deprecated in favor of ``attr.evolve()`` and will stop working in 2018. - - -Changes: -^^^^^^^^ - -- Fix default hashing behavior. - Now *hash* mirrors the value of *cmp* and classes are unhashable by default. - `#136`_ - `#142 `_ -- Added ``attr.evolve()`` that, given an instance of an ``attrs`` class and field changes as keyword arguments, will instantiate a copy of the given instance with the changes applied. - ``evolve()`` replaces ``assoc()``, which is now deprecated. - ``evolve()`` is significantly faster than ``assoc()``, and requires the class have an initializer that can take the field values as keyword arguments (like ``attrs`` itself can generate). - `#116 `_ - `#124 `_ - `#135 `_ -- ``FrozenInstanceError`` is now raised when trying to delete an attribute from a frozen class. - `#118 `_ -- Frozen-ness of classes is now inherited. - `#128 `_ -- ``__attrs_post_init__()`` is now run if validation is disabled. - `#130 `_ -- Added ``attr.validators.in_(options)`` that, given the allowed `options`, checks whether the attribute value is in it. - This can be used to check constants, enums, mappings, etc. - `#181 `_ -- Added ``attr.validators.and_()`` that composes multiple validators into one. - `#161 `_ -- For convenience, the *validator* argument of ``@attr.s`` now can take a list of validators that are wrapped using ``and_()``. - `#138 `_ -- Accordingly, ``attr.validators.optional()`` now can take a list of validators too. - `#161 `_ -- Validators can now be defined conveniently inline by using the attribute as a decorator. - Check out the `validator examples `_ to see it in action! - `#143 `_ -- ``attr.Factory()`` now has a *takes_self* argument that makes the initializer to pass the partially initialized instance into the factory. - In other words you can define attribute defaults based on other attributes. - `#165`_ - `#189 `_ -- Default factories can now also be defined inline using decorators. - They are *always* passed the partially initialized instance. - `#165`_ -- Conversion can now be made optional using ``attr.converters.optional()``. - `#105 `_ - `#173 `_ -- ``attr.make_class()`` now accepts the keyword argument ``bases`` which allows for subclassing. - `#152 `_ -- Metaclasses are now preserved with ``slots=True``. - `#155 `_ - -.. _`#136`: https://github.com/python-attrs/attrs/issues/136 -.. _`#165`: https://github.com/python-attrs/attrs/issues/165 - - ----- - - -16.3.0 (2016-11-24) -------------------- - -Changes: -^^^^^^^^ - -- Attributes now can have user-defined metadata which greatly improves ``attrs``'s extensibility. - `#96 `_ -- Allow for a ``__attrs_post_init__()`` method that -- if defined -- will get called at the end of the ``attrs``-generated ``__init__()`` method. - `#111 `_ -- Added ``@attr.s(str=True)`` that will optionally create a ``__str__()`` method that is identical to ``__repr__()``. - This is mainly useful with ``Exception``\ s and other classes that rely on a useful ``__str__()`` implementation but overwrite the default one through a poor own one. - Default Python class behavior is to use ``__repr__()`` as ``__str__()`` anyways. - - If you tried using ``attrs`` with ``Exception``\ s and were puzzled by the tracebacks: this option is for you. -- ``__name__`` is no longer overwritten with ``__qualname__`` for ``attr.s(slots=True)`` classes. - `#99 `_ - - ----- - - -16.2.0 (2016-09-17) -------------------- - -Changes: -^^^^^^^^ - -- Added ``attr.astuple()`` that -- similarly to ``attr.asdict()`` -- returns the instance as a tuple. - `#77 `_ -- Converters now work with frozen classes. - `#76 `_ -- Instantiation of ``attrs`` classes with converters is now significantly faster. - `#80 `_ -- Pickling now works with slotted classes. - `#81 `_ -- ``attr.assoc()`` now works with slotted classes. - `#84 `_ -- The tuple returned by ``attr.fields()`` now also allows to access the ``Attribute`` instances by name. - Yes, we've subclassed ``tuple`` so you don't have to! - Therefore ``attr.fields(C).x`` is equivalent to the deprecated ``C.x`` and works with slotted classes. - `#88 `_ - - ----- - - -16.1.0 (2016-08-30) -------------------- - -Backward-incompatible Changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- All instances where function arguments were called ``cl`` have been changed to the more Pythonic ``cls``. - Since it was always the first argument, it's doubtful anyone ever called those function with in the keyword form. - If so, sorry for any breakage but there's no practical deprecation path to solve this ugly wart. - - -Deprecations: -^^^^^^^^^^^^^ - -- Accessing ``Attribute`` instances on class objects is now deprecated and will stop working in 2017. - If you need introspection please use the ``__attrs_attrs__`` attribute or the ``attr.fields()`` function that carry them too. - In the future, the attributes that are defined on the class body and are usually overwritten in your ``__init__`` method are simply removed after ``@attr.s`` has been applied. - - This will remove the confusing error message if you write your own ``__init__`` and forget to initialize some attribute. - Instead you will get a straightforward ``AttributeError``. - In other words: decorated classes will work more like plain Python classes which was always ``attrs``'s goal. -- The serious business aliases ``attr.attributes`` and ``attr.attr`` have been deprecated in favor of ``attr.attrs`` and ``attr.attrib`` which are much more consistent and frankly obvious in hindsight. - They will be purged from documentation immediately but there are no plans to actually remove them. - - -Changes: -^^^^^^^^ - -- ``attr.asdict()``\ 's ``dict_factory`` arguments is now propagated on recursion. - `#45 `_ -- ``attr.asdict()``, ``attr.has()`` and ``attr.fields()`` are significantly faster. - `#48 `_ - `#51 `_ -- Add ``attr.attrs`` and ``attr.attrib`` as a more consistent aliases for ``attr.s`` and ``attr.ib``. -- Add *frozen* option to ``attr.s`` that will make instances best-effort immutable. - `#60 `_ -- ``attr.asdict()`` now takes ``retain_collection_types`` as an argument. - If ``True``, it does not convert attributes of type ``tuple`` or ``set`` to ``list``. - `#69 `_ - - ----- - - -16.0.0 (2016-05-23) -------------------- - -Backward-incompatible Changes: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- Python 3.3 and 2.6 are no longer supported. - They may work by chance but any effort to keep them working has ceased. - - The last Python 2.6 release was on October 29, 2013 and is no longer supported by the CPython core team. - Major Python packages like Django and Twisted dropped Python 2.6 a while ago already. - - Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release. - -Changes: -^^^^^^^^ - -- ``__slots__`` have arrived! - Classes now can automatically be `slotted `_-style (and save your precious memory) just by passing ``slots=True``. - `#35 `_ -- Allow the case of initializing attributes that are set to ``init=False``. - This allows for clean initializer parameter lists while being able to initialize attributes to default values. - `#32 `_ -- ``attr.asdict()`` can now produce arbitrary mappings instead of Python ``dict``\ s when provided with a ``dict_factory`` argument. - `#40 `_ -- Multiple performance improvements. - - ----- - - -15.2.0 (2015-12-08) -------------------- - -Changes: -^^^^^^^^ - -- Added a ``convert`` argument to ``attr.ib``, which allows specifying a function to run on arguments. - This allows for simple type conversions, e.g. with ``attr.ib(convert=int)``. - `#26 `_ -- Speed up object creation when attribute validators are used. - `#28 `_ - - ----- - - -15.1.0 (2015-08-20) -------------------- - -Changes: -^^^^^^^^ - -- Added ``attr.validators.optional()`` that wraps other validators allowing attributes to be ``None``. - `#16 `_ -- Multi-level inheritance now works. - `#24 `_ -- ``__repr__()`` now works with non-redecorated subclasses. - `#20 `_ - - ----- - - -15.0.0 (2015-04-15) -------------------- - -Changes: -^^^^^^^^ - -Initial release. diff --git a/third_party/python/attrs/MANIFEST.in b/third_party/python/attrs/MANIFEST.in deleted file mode 100644 index 852830df304a..000000000000 --- a/third_party/python/attrs/MANIFEST.in +++ /dev/null @@ -1,23 +0,0 @@ -include LICENSE *.rst *.toml *.yml *.yaml -graft .github - -# Stubs -include src/attr/py.typed -recursive-include src *.pyi - -# Tests -include tox.ini .coveragerc conftest.py -recursive-include tests *.py - -# Documentation -include docs/Makefile docs/docutils.conf -recursive-include docs *.png -recursive-include docs *.svg -recursive-include docs *.py -recursive-include docs *.rst -prune docs/_build - -# Just to keep check-manifest happy; on releases those files are gone. -# Last rule wins! -exclude changelog.d/*.rst -include changelog.d/towncrier_template.rst diff --git a/third_party/python/attrs/PKG-INFO b/third_party/python/attrs/PKG-INFO deleted file mode 100644 index dd7a8f0b3657..000000000000 --- a/third_party/python/attrs/PKG-INFO +++ /dev/null @@ -1,231 +0,0 @@ -Metadata-Version: 2.1 -Name: attrs -Version: 19.1.0 -Summary: Classes Without Boilerplate -Home-page: https://www.attrs.org/ -Author: Hynek Schlawack -Author-email: hs@ox.cx -Maintainer: Hynek Schlawack -Maintainer-email: hs@ox.cx -License: MIT -Project-URL: Documentation, https://www.attrs.org/ -Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues -Project-URL: Source Code, https://github.com/python-attrs/attrs -Description: .. image:: https://www.attrs.org/en/latest/_static/attrs_logo.png - :alt: attrs Logo - - ====================================== - ``attrs``: Classes Without Boilerplate - ====================================== - - .. image:: https://readthedocs.org/projects/attrs/badge/?version=stable - :target: https://www.attrs.org/en/stable/?badge=stable - :alt: Documentation Status - - .. image:: https://travis-ci.org/python-attrs/attrs.svg?branch=master - :target: https://travis-ci.org/python-attrs/attrs - :alt: CI Status - - .. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg - :target: https://codecov.io/github/python-attrs/attrs - :alt: Test Coverage - - .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/ambv/black - :alt: Code style: black - - .. teaser-begin - - ``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder `_ methods). - - Its main goal is to help you to write **concise** and **correct** software without slowing down your code. - - .. -spiel-end- - - For that, it gives you a class decorator and a way to declaratively define the attributes on that class: - - .. -code-begin- - - .. code-block:: pycon - - >>> import attr - - >>> @attr.s - ... class SomeClass(object): - ... a_number = attr.ib(default=42) - ... list_of_numbers = attr.ib(factory=list) - ... - ... def hard_math(self, another_number): - ... return self.a_number + sum(self.list_of_numbers) * another_number - - - >>> sc = SomeClass(1, [1, 2, 3]) - >>> sc - SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) - - >>> sc.hard_math(3) - 19 - >>> sc == SomeClass(1, [1, 2, 3]) - True - >>> sc != SomeClass(2, [3, 2, 1]) - True - - >>> attr.asdict(sc) - {'a_number': 1, 'list_of_numbers': [1, 2, 3]} - - >>> SomeClass() - SomeClass(a_number=42, list_of_numbers=[]) - - >>> C = attr.make_class("C", ["a", "b"]) - >>> C("foo", "bar") - C(a='foo', b='bar') - - - After *declaring* your attributes ``attrs`` gives you: - - - a concise and explicit overview of the class's attributes, - - a nice human-readable ``__repr__``, - - a complete set of comparison methods, - - an initializer, - - and much more, - - *without* writing dull boilerplate code again and again and *without* runtime performance penalties. - - On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations `_. - - This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving `_ ``namedtuple``\ s. - Which in turn encourages you to write *small classes* that do `one thing well `_. - Never again violate the `single responsibility principle `_ just because implementing ``__init__`` et al is a painful drag. - - - .. -testimonials- - - Testimonials - ============ - - **Amber Hawkie Brown**, Twisted Release Manager and Computer Owl: - - Writing a fully-functional class using attrs takes me less time than writing this testimonial. - - - **Glyph Lefkowitz**, creator of `Twisted `_, `Automat `_, and other open source software, in `The One Python Library Everyone Needs `_: - - I’m looking forward to is being able to program in Python-with-attrs everywhere. - It exerts a subtle, but positive, design influence in all the codebases I’ve see it used in. - - - **Kenneth Reitz**, author of `Requests `_ and Developer Advocate at DigitalOcean, (`on paper no less `_!): - - attrs—classes for humans. I like it. - - - **Łukasz Langa**, prolific CPython core developer and Production Engineer at Facebook: - - I'm increasingly digging your attr.ocity. Good job! - - - .. -end- - - .. -project-information- - - Getting Help - ============ - - Please use the ``python-attrs`` tag on `StackOverflow `_ to get help. - - Answering questions of your fellow developers is also great way to help the project! - - - Project Information - =================== - - ``attrs`` is released under the `MIT `_ license, - its documentation lives at `Read the Docs `_, - the code on `GitHub `_, - and the latest release on `PyPI `_. - It’s rigorously tested on Python 2.7, 3.4+, and PyPy. - - We collect information on **third-party extensions** in our `wiki `_. - Feel free to browse and add your own! - - If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide `_ to get you started! - - - Release Information - =================== - - 19.1.0 (2019-03-03) - ------------------- - - Backward-incompatible Changes - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - - Fixed a bug where deserialized objects with ``cache_hash=True`` could have incorrect hash code values. - This change breaks classes with ``cache_hash=True`` when a custom ``__setstate__`` is present. - An exception will be thrown when applying the ``attrs`` annotation to such a class. - This limitation is tracked in issue `#494 `_. - `#482 `_ - - - Changes - ^^^^^^^ - - - Add ``is_callable``, ``deep_iterable``, and ``deep_mapping`` validators. - - * ``is_callable``: validates that a value is callable - * ``deep_iterable``: Allows recursion down into an iterable, - applying another validator to every member in the iterable - as well as applying an optional validator to the iterable itself. - * ``deep_mapping``: Allows recursion down into the items in a mapping object, - applying a key validator and a value validator to the key and value in every item. - Also applies an optional validator to the mapping object itself. - - You can find them in the ``attr.validators`` package. - `#425 `_ - - Fixed stub files to prevent errors raised by mypy's ``disallow_any_generics = True`` option. - `#443 `_ - - Attributes with ``init=False`` now can follow after ``kw_only=True`` attributes. - `#450 `_ - - ``attrs`` now has first class support for defining exception classes. - - If you define a class using ``@attr.s(auto_exc=True)`` and subclass an exception, the class will behave like a well-behaved exception class including an appropriate ``__str__`` method, and all attributes additionally available in an ``args`` attribute. - `#500 `_ - - Clarified documentation for hashing to warn that hashable objects should be deeply immutable (in their usage, even if this is not enforced). - `#503 `_ - - `Full changelog `_. - - Credits - ======= - - ``attrs`` is written and maintained by `Hynek Schlawack `_. - - The development is kindly supported by `Variomedia AG `_. - - A full list of contributors can be found in `GitHub's overview `_. - - It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. - Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? - -Keywords: class,attribute,boilerplate -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* -Provides-Extra: tests -Provides-Extra: dev -Provides-Extra: docs diff --git a/third_party/python/attrs/src/attr/__init__.py b/third_party/python/attrs/attr/__init__.py similarity index 100% rename from third_party/python/attrs/src/attr/__init__.py rename to third_party/python/attrs/attr/__init__.py diff --git a/third_party/python/attrs/src/attr/__init__.pyi b/third_party/python/attrs/attr/__init__.pyi similarity index 100% rename from third_party/python/attrs/src/attr/__init__.pyi rename to third_party/python/attrs/attr/__init__.pyi diff --git a/third_party/python/attrs/src/attr/_compat.py b/third_party/python/attrs/attr/_compat.py similarity index 100% rename from third_party/python/attrs/src/attr/_compat.py rename to third_party/python/attrs/attr/_compat.py diff --git a/third_party/python/attrs/src/attr/_config.py b/third_party/python/attrs/attr/_config.py similarity index 100% rename from third_party/python/attrs/src/attr/_config.py rename to third_party/python/attrs/attr/_config.py diff --git a/third_party/python/attrs/src/attr/_funcs.py b/third_party/python/attrs/attr/_funcs.py similarity index 100% rename from third_party/python/attrs/src/attr/_funcs.py rename to third_party/python/attrs/attr/_funcs.py diff --git a/third_party/python/attrs/src/attr/_make.py b/third_party/python/attrs/attr/_make.py similarity index 100% rename from third_party/python/attrs/src/attr/_make.py rename to third_party/python/attrs/attr/_make.py diff --git a/third_party/python/attrs/src/attr/converters.py b/third_party/python/attrs/attr/converters.py similarity index 100% rename from third_party/python/attrs/src/attr/converters.py rename to third_party/python/attrs/attr/converters.py diff --git a/third_party/python/attrs/src/attr/converters.pyi b/third_party/python/attrs/attr/converters.pyi similarity index 100% rename from third_party/python/attrs/src/attr/converters.pyi rename to third_party/python/attrs/attr/converters.pyi diff --git a/third_party/python/attrs/src/attr/exceptions.py b/third_party/python/attrs/attr/exceptions.py similarity index 100% rename from third_party/python/attrs/src/attr/exceptions.py rename to third_party/python/attrs/attr/exceptions.py diff --git a/third_party/python/attrs/src/attr/exceptions.pyi b/third_party/python/attrs/attr/exceptions.pyi similarity index 100% rename from third_party/python/attrs/src/attr/exceptions.pyi rename to third_party/python/attrs/attr/exceptions.pyi diff --git a/third_party/python/attrs/src/attr/filters.py b/third_party/python/attrs/attr/filters.py similarity index 100% rename from third_party/python/attrs/src/attr/filters.py rename to third_party/python/attrs/attr/filters.py diff --git a/third_party/python/attrs/src/attr/filters.pyi b/third_party/python/attrs/attr/filters.pyi similarity index 100% rename from third_party/python/attrs/src/attr/filters.pyi rename to third_party/python/attrs/attr/filters.pyi diff --git a/third_party/python/attrs/src/attr/py.typed b/third_party/python/attrs/attr/py.typed similarity index 100% rename from third_party/python/attrs/src/attr/py.typed rename to third_party/python/attrs/attr/py.typed diff --git a/third_party/python/attrs/src/attr/validators.py b/third_party/python/attrs/attr/validators.py similarity index 100% rename from third_party/python/attrs/src/attr/validators.py rename to third_party/python/attrs/attr/validators.py diff --git a/third_party/python/attrs/src/attr/validators.pyi b/third_party/python/attrs/attr/validators.pyi similarity index 100% rename from third_party/python/attrs/src/attr/validators.pyi rename to third_party/python/attrs/attr/validators.pyi diff --git a/third_party/python/attrs/LICENSE b/third_party/python/attrs/attrs-19.1.0.dist-info/LICENSE similarity index 100% rename from third_party/python/attrs/LICENSE rename to third_party/python/attrs/attrs-19.1.0.dist-info/LICENSE diff --git a/third_party/python/attrs/README.rst b/third_party/python/attrs/attrs-19.1.0.dist-info/METADATA similarity index 50% rename from third_party/python/attrs/README.rst rename to third_party/python/attrs/attrs-19.1.0.dist-info/METADATA index db287f73b9ee..81b6fc8cfbe1 100644 --- a/third_party/python/attrs/README.rst +++ b/third_party/python/attrs/attrs-19.1.0.dist-info/METADATA @@ -1,3 +1,55 @@ +Metadata-Version: 2.1 +Name: attrs +Version: 19.1.0 +Summary: Classes Without Boilerplate +Home-page: https://www.attrs.org/ +Author: Hynek Schlawack +Author-email: hs@ox.cx +Maintainer: Hynek Schlawack +Maintainer-email: hs@ox.cx +License: MIT +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues +Project-URL: Source Code, https://github.com/python-attrs/attrs +Keywords: class,attribute,boilerplate +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Provides-Extra: dev +Requires-Dist: coverage ; extra == 'dev' +Requires-Dist: hypothesis ; extra == 'dev' +Requires-Dist: pympler ; extra == 'dev' +Requires-Dist: pytest ; extra == 'dev' +Requires-Dist: six ; extra == 'dev' +Requires-Dist: zope.interface ; extra == 'dev' +Requires-Dist: sphinx ; extra == 'dev' +Requires-Dist: pre-commit ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: zope.interface ; extra == 'docs' +Provides-Extra: tests +Requires-Dist: coverage ; extra == 'tests' +Requires-Dist: hypothesis ; extra == 'tests' +Requires-Dist: pympler ; extra == 'tests' +Requires-Dist: pytest ; extra == 'tests' +Requires-Dist: six ; extra == 'tests' +Requires-Dist: zope.interface ; extra == 'tests' + .. image:: https://www.attrs.org/en/latest/_static/attrs_logo.png :alt: attrs Logo @@ -136,3 +188,62 @@ We collect information on **third-party extensions** in our `wiki `_ to get you started! + + +Release Information +=================== + +19.1.0 (2019-03-03) +------------------- + +Backward-incompatible Changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Fixed a bug where deserialized objects with ``cache_hash=True`` could have incorrect hash code values. + This change breaks classes with ``cache_hash=True`` when a custom ``__setstate__`` is present. + An exception will be thrown when applying the ``attrs`` annotation to such a class. + This limitation is tracked in issue `#494 `_. + `#482 `_ + + +Changes +^^^^^^^ + +- Add ``is_callable``, ``deep_iterable``, and ``deep_mapping`` validators. + + * ``is_callable``: validates that a value is callable + * ``deep_iterable``: Allows recursion down into an iterable, + applying another validator to every member in the iterable + as well as applying an optional validator to the iterable itself. + * ``deep_mapping``: Allows recursion down into the items in a mapping object, + applying a key validator and a value validator to the key and value in every item. + Also applies an optional validator to the mapping object itself. + + You can find them in the ``attr.validators`` package. + `#425 `_ +- Fixed stub files to prevent errors raised by mypy's ``disallow_any_generics = True`` option. + `#443 `_ +- Attributes with ``init=False`` now can follow after ``kw_only=True`` attributes. + `#450 `_ +- ``attrs`` now has first class support for defining exception classes. + + If you define a class using ``@attr.s(auto_exc=True)`` and subclass an exception, the class will behave like a well-behaved exception class including an appropriate ``__str__`` method, and all attributes additionally available in an ``args`` attribute. + `#500 `_ +- Clarified documentation for hashing to warn that hashable objects should be deeply immutable (in their usage, even if this is not enforced). + `#503 `_ + +`Full changelog `_. + +Credits +======= + +``attrs`` is written and maintained by `Hynek Schlawack `_. + +The development is kindly supported by `Variomedia AG `_. + +A full list of contributors can be found in `GitHub's overview `_. + +It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. +Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? + + diff --git a/third_party/python/attrs/attrs-19.1.0.dist-info/RECORD b/third_party/python/attrs/attrs-19.1.0.dist-info/RECORD new file mode 100644 index 000000000000..034b3cbff804 --- /dev/null +++ b/third_party/python/attrs/attrs-19.1.0.dist-info/RECORD @@ -0,0 +1,20 @@ +attr/__init__.py,sha256=3XomfUfit8bVVEmSf1bRhLnRMPKauPbzFqPUnVRPgXw,1244 +attr/__init__.pyi,sha256=OON4rNWdgL69frd_WdrxtuQe8CEczl3aFpgifFeESN8,7769 +attr/_compat.py,sha256=GcjqWHrwUWGVCbDKY7twYt-Rr_4nPJqBnfrf5SeHsIY,4583 +attr/_config.py,sha256=_KvW0mQdH2PYjHc0YfIUaV_o2pVfM7ziMEYTxwmEhOA,514 +attr/_funcs.py,sha256=7v3MNMHdOUP2NkiLPwEiWAorBs3uNQq5Rn70Odr5uqo,9725 +attr/_make.py,sha256=be1PmzR8EDGfVA2Cx6ljsTIuXRxW2tEWPpTqtQXde0Y,68317 +attr/converters.py,sha256=SFPiz6-hAs2pw3kn7SzkBcdpE9AjW8iT9wjpe2eLDrQ,2155 +attr/converters.pyi,sha256=wAhCoOT1MFV8t323rpD87O7bxQ8CYLTPiBQd-29BieI,351 +attr/exceptions.py,sha256=N0WQfKvBVd4GWgDxTbFScg4ajy7-HlyvXiwlSQBA0jA,1272 +attr/exceptions.pyi,sha256=sq7TbBEGGSf81uFXScW9_aO62vd0v6LAvqz0a8Hrsxw,257 +attr/filters.py,sha256=s6NrcRWJKlCQauPEH0S4lmgFwlCdUQcHKcNkDHpptN4,1153 +attr/filters.pyi,sha256=xDpmKQlFdssgxGa5tsl1ADh_3zwAwAT4vUhd8h-8-Tk,214 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/validators.py,sha256=ZAf_y5wNHyq2Rdlin_fwplQnU2u5wZnvmYJq1JddPtM,8750 +attr/validators.pyi,sha256=p2xr2ob8RaKW3PqlKDrQQVAyl8ZH4pNdlZzWXapGPjk,897 +attrs-19.1.0.dist-info/LICENSE,sha256=v2WaKLSSQGAvVrvfSQy-LsUJsVuY-Z17GaUsdA4yeGM,1082 +attrs-19.1.0.dist-info/METADATA,sha256=5yXp3BTFGRkY2hQDs18h-2dT7xnSlExRUfxvujCtHTE,10275 +attrs-19.1.0.dist-info/WHEEL,sha256=_wJFdOYk7i3xxT8ElOkUJvOdOvfNGbR9g-bf6UQT6sU,110 +attrs-19.1.0.dist-info/top_level.txt,sha256=tlRYMddkRlKPqJ96wP2_j9uEsmcNHgD2SbuWd4CzGVU,5 +attrs-19.1.0.dist-info/RECORD,, diff --git a/third_party/python/attrs/attrs-19.1.0.dist-info/WHEEL b/third_party/python/attrs/attrs-19.1.0.dist-info/WHEEL new file mode 100644 index 000000000000..c4bde3037775 --- /dev/null +++ b/third_party/python/attrs/attrs-19.1.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.32.3) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/attrs/attrs-19.1.0.dist-info/top_level.txt b/third_party/python/attrs/attrs-19.1.0.dist-info/top_level.txt new file mode 100644 index 000000000000..66a062d889de --- /dev/null +++ b/third_party/python/attrs/attrs-19.1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +attr diff --git a/third_party/python/attrs/changelog.d/towncrier_template.rst b/third_party/python/attrs/changelog.d/towncrier_template.rst deleted file mode 100644 index 29ca74c4e8f2..000000000000 --- a/third_party/python/attrs/changelog.d/towncrier_template.rst +++ /dev/null @@ -1,35 +0,0 @@ -{% for section, _ in sections.items() %} -{% set underline = underlines[0] %}{% if section %}{{section}} -{{ underline * section|length }}{% set underline = underlines[1] %} - -{% endif %} - -{% if sections[section] %} -{% for category, val in definitions.items() if category in sections[section]%} -{{ definitions[category]['name'] }} -{{ underline * definitions[category]['name']|length }} - -{% if definitions[category]['showcontent'] %} -{% for text, values in sections[section][category].items() %} -- {{ text }} - {{ values|join(',\n ') }} -{% endfor %} - -{% else %} -- {{ sections[section][category]['']|join(', ') }} - -{% endif %} -{% if sections[section][category]|length == 0 %} -No significant changes. - -{% else %} -{% endif %} - -{% endfor %} -{% else %} -No significant changes. - - -{% endif %} -{% endfor %} ----- diff --git a/third_party/python/attrs/codecov.yml b/third_party/python/attrs/codecov.yml deleted file mode 100644 index 60a1e5c12e72..000000000000 --- a/third_party/python/attrs/codecov.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -comment: false -coverage: - status: - patch: - default: - target: "100" - project: - default: - target: "100" diff --git a/third_party/python/attrs/conftest.py b/third_party/python/attrs/conftest.py deleted file mode 100644 index cce4950cbd37..000000000000 --- a/third_party/python/attrs/conftest.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import sys - -import pytest - -from hypothesis import HealthCheck, settings - -from attr._compat import PYPY - - -def pytest_configure(config): - # HealthCheck.too_slow causes more trouble than good -- especially in CIs. - settings.register_profile( - "patience", settings(suppress_health_check=[HealthCheck.too_slow]) - ) - settings.load_profile("patience") - - -@pytest.fixture(scope="session") -def C(): - """ - Return a simple but fully featured attrs class with an x and a y attribute. - """ - import attr - - @attr.s - class C(object): - x = attr.ib() - y = attr.ib() - - return C - - -collect_ignore = [] -if sys.version_info[:2] < (3, 6): - collect_ignore.extend( - ["tests/test_annotations.py", "tests/test_init_subclass.py"] - ) -elif PYPY: # FIXME: Currently our tests fail on pypy3. See #509 - collect_ignore.extend(["tests/test_annotations.py"]) diff --git a/third_party/python/attrs/pyproject.toml b/third_party/python/attrs/pyproject.toml deleted file mode 100644 index 5657791dfded..000000000000 --- a/third_party/python/attrs/pyproject.toml +++ /dev/null @@ -1,36 +0,0 @@ -[build-system] -requires = ["setuptools>=40.6.0", "wheel"] -build-backend = "setuptools.build_meta" - - -[tool.black] -line-length = 79 - - -[tool.towncrier] - package = "attr" - package_dir = "src" - filename = "CHANGELOG.rst" - template = "changelog.d/towncrier_template.rst" - issue_format = "`#{issue} `_" - directory = "changelog.d" - title_format = "{version} ({project_date})" - underlines = ["-", "^"] - - [[tool.towncrier.section]] - path = "" - - [[tool.towncrier.type]] - directory = "breaking" - name = "Backward-incompatible Changes" - showcontent = true - - [[tool.towncrier.type]] - directory = "deprecation" - name = "Deprecations" - showcontent = true - - [[tool.towncrier.type]] - directory = "change" - name = "Changes" - showcontent = true diff --git a/third_party/python/attrs/setup.cfg b/third_party/python/attrs/setup.cfg deleted file mode 100644 index 0dfa1a84cc20..000000000000 --- a/third_party/python/attrs/setup.cfg +++ /dev/null @@ -1,31 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE - -[tool:pytest] -minversion = 3.0 -strict = true -addopts = -ra -testpaths = tests -filterwarnings = - once::Warning - ignore:::pympler[.*] - -[isort] -atomic = true -force_grid_wrap = 0 -include_trailing_comma = true -lines_after_imports = 2 -lines_between_types = 1 -multi_line_output = 3 -not_skip = __init__.py -use_parentheses = true -known_first_party = attr -known_third_party = hypothesis,pytest,setuptools,six,zope - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/attrs/setup.py b/third_party/python/attrs/setup.py deleted file mode 100644 index a181c95ff793..000000000000 --- a/third_party/python/attrs/setup.py +++ /dev/null @@ -1,122 +0,0 @@ -import codecs -import os -import re - -from setuptools import find_packages, setup - - -############################################################################### - -NAME = "attrs" -PACKAGES = find_packages(where="src") -META_PATH = os.path.join("src", "attr", "__init__.py") -KEYWORDS = ["class", "attribute", "boilerplate"] -PROJECT_URLS = { - "Documentation": "https://www.attrs.org/", - "Bug Tracker": "https://github.com/python-attrs/attrs/issues", - "Source Code": "https://github.com/python-attrs/attrs", -} -CLASSIFIERS = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Natural Language :: English", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Software Development :: Libraries :: Python Modules", -] -INSTALL_REQUIRES = [] -EXTRAS_REQUIRE = { - "docs": ["sphinx", "zope.interface"], - "tests": [ - "coverage", - "hypothesis", - "pympler", - "pytest", - "six", - "zope.interface", - ], -} -EXTRAS_REQUIRE["dev"] = ( - EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] -) - -############################################################################### - -HERE = os.path.abspath(os.path.dirname(__file__)) - - -def read(*parts): - """ - Build an absolute path from *parts* and and return the contents of the - resulting file. Assume UTF-8 encoding. - """ - with codecs.open(os.path.join(HERE, *parts), "rb", "utf-8") as f: - return f.read() - - -META_FILE = read(META_PATH) - - -def find_meta(meta): - """ - Extract __*meta*__ from META_FILE. - """ - meta_match = re.search( - r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta), META_FILE, re.M - ) - if meta_match: - return meta_match.group(1) - raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) - - -VERSION = find_meta("version") -URL = find_meta("url") -LONG = ( - read("README.rst") - + "\n\n" - + "Release Information\n" - + "===================\n\n" - + re.search( - r"(\d+.\d.\d \(.*?\)\n.*?)\n\n\n----\n\n\n", - read("CHANGELOG.rst"), - re.S, - ).group(1) - + "\n\n`Full changelog " - + "<{url}en/stable/changelog.html>`_.\n\n".format(url=URL) - + read("AUTHORS.rst") -) - - -if __name__ == "__main__": - setup( - name=NAME, - description=find_meta("description"), - license=find_meta("license"), - url=URL, - project_urls=PROJECT_URLS, - version=VERSION, - author=find_meta("author"), - author_email=find_meta("email"), - maintainer=find_meta("author"), - maintainer_email=find_meta("email"), - keywords=KEYWORDS, - long_description=LONG, - packages=PACKAGES, - package_dir={"": "src"}, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", - zip_safe=False, - classifiers=CLASSIFIERS, - install_requires=INSTALL_REQUIRES, - extras_require=EXTRAS_REQUIRE, - include_package_data=True, - ) diff --git a/third_party/python/attrs/tox.ini b/third_party/python/attrs/tox.ini deleted file mode 100644 index 0d2f3c32c5be..000000000000 --- a/third_party/python/attrs/tox.ini +++ /dev/null @@ -1,85 +0,0 @@ -[tox] -envlist = typing,lint,py27,py34,py35,py36,py37,pypy,pypy3,manifest,docs,pypi-description,changelog,coverage-report -isolated_build = True - - -[testenv] -# Prevent random setuptools/pip breakages like -# https://github.com/pypa/setuptools/issues/1042 from breaking our builds. -setenv = - VIRTUALENV_NO_DOWNLOAD=1 -extras = tests -commands = python -m pytest {posargs} - - -[testenv:py27] -extras = tests -commands = coverage run --parallel -m pytest {posargs} - - -[testenv:py37] -# Python 3.6+ has a number of compile-time warnings on invalid string escapes. -# PYTHONWARNINGS=d and --no-compile below make them visible during the Tox run. -install_command = pip install --no-compile {opts} {packages} -setenv = - PYTHONWARNINGS=d -extras = tests -commands = coverage run --parallel -m pytest {posargs} - - -[testenv:coverage-report] -basepython = python3.7 -skip_install = true -deps = coverage -commands = - coverage combine - coverage report - - -[testenv:lint] -basepython = python3.7 -skip_install = true -deps = pre-commit -passenv = HOMEPATH # needed on Windows -commands = pre-commit run --all-files - - -[testenv:docs] -# RTD only allows for 3.7 -basepython = python3.7 -extras = docs -commands = - sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html - python -m doctest README.rst - - -[testenv:manifest] -basepython = python3.7 -deps = check-manifest -skip_install = true -commands = check-manifest - - -[testenv:pypi-description] -basepython = python3.7 -skip_install = true -deps = - twine - pip >= 18.0.0 -commands = - pip wheel -w {envtmpdir}/build --no-deps . - twine check {envtmpdir}/build/* - - -[testenv:changelog] -basepython = python3.7 -deps = towncrier -skip_install = true -commands = towncrier --draft - - -[testenv:typing] -basepython = python3.7 -deps = mypy -commands = mypy tests/typing_example.py diff --git a/third_party/python/blessings/LICENSE b/third_party/python/blessings/LICENSE deleted file mode 100644 index 3d3a44e65b8c..000000000000 --- a/third_party/python/blessings/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2011 Erik Rose - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/python/blessings/MANIFEST.in b/third_party/python/blessings/MANIFEST.in deleted file mode 100644 index 3f4fbd708437..000000000000 --- a/third_party/python/blessings/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include README.rst -include LICENSE -include tox.ini diff --git a/third_party/python/blessings/PKG-INFO b/third_party/python/blessings/PKG-INFO deleted file mode 100644 index 34dd25e99a73..000000000000 --- a/third_party/python/blessings/PKG-INFO +++ /dev/null @@ -1,560 +0,0 @@ -Metadata-Version: 1.1 -Name: blessings -Version: 1.7 -Summary: A thin, practical wrapper around terminal coloring, styling, and positioning -Home-page: https://github.com/erikrose/blessings -Author: Erik Rose -Author-email: erikrose@grinchcentral.com -License: MIT -Description: ========= - Blessings - ========= - - Coding with Blessings looks like this... :: - - from blessings import Terminal - - t = Terminal() - - print t.bold('Hi there!') - print t.bold_red_on_bright_green('It hurts my eyes!') - - with t.location(0, t.height - 1): - print 'This is at the bottom.' - - Or, for byte-level control, you can drop down and play with raw terminal - capabilities:: - - print '{t.bold}All your {t.red}bold and red base{t.normal}'.format(t=t) - print t.wingo(2) - - `Full API Reference `_ - - The Pitch - ========= - - Blessings lifts several of curses_' limiting assumptions, and it makes your - code pretty, too: - - * Use styles, color, and maybe a little positioning without necessarily - clearing the whole - screen first. - * Leave more than one screenful of scrollback in the buffer after your program - exits, like a well-behaved command-line app should. - * Get rid of all those noisy, C-like calls to ``tigetstr`` and ``tparm``, so - your code doesn't get crowded out by terminal bookkeeping. - * Act intelligently when somebody redirects your output to a file, omitting the - terminal control codes the user doesn't want to see (optional). - - .. _curses: http://docs.python.org/library/curses.html - - Before And After - ---------------- - - Without Blessings, this is how you'd print some underlined text at the bottom - of the screen:: - - from curses import tigetstr, setupterm, tparm - from fcntl import ioctl - from os import isatty - import struct - import sys - from termios import TIOCGWINSZ - - # If we want to tolerate having our output piped to other commands or - # files without crashing, we need to do all this branching: - if hasattr(sys.stdout, 'fileno') and isatty(sys.stdout.fileno()): - setupterm() - sc = tigetstr('sc') - cup = tigetstr('cup') - rc = tigetstr('rc') - underline = tigetstr('smul') - normal = tigetstr('sgr0') - else: - sc = cup = rc = underline = normal = '' - print sc # Save cursor position. - if cup: - # tigetnum('lines') doesn't always update promptly, hence this: - height = struct.unpack('hhhh', ioctl(0, TIOCGWINSZ, '\000' * 8))[0] - print tparm(cup, height - 1, 0) # Move cursor to bottom. - print 'This is {under}underlined{normal}!'.format(under=underline, - normal=normal) - print rc # Restore cursor position. - - That was long and full of incomprehensible trash! Let's try it again, this time - with Blessings:: - - from blessings import Terminal - - term = Terminal() - with term.location(0, term.height - 1): - print 'This is', term.underline('pretty!') - - Much better. - - What It Provides - ================ - - Blessings provides just one top-level object: ``Terminal``. Instantiating a - ``Terminal`` figures out whether you're on a terminal at all and, if so, does - any necessary terminal setup. After that, you can proceed to ask it all sorts - of things about the terminal. Terminal terminal terminal. - - Simple Formatting - ----------------- - - Lots of handy formatting codes ("capabilities" in low-level parlance) are - available as attributes on a ``Terminal``. For example:: - - from blessings import Terminal - - term = Terminal() - print 'I am ' + term.bold + 'bold' + term.normal + '!' - - Though they are strings at heart, you can also use them as callable wrappers so - you don't have to say ``normal`` afterward:: - - print 'I am', term.bold('bold') + '!' - - Or, if you want fine-grained control while maintaining some semblance of - brevity, you can combine it with Python's string formatting, which makes - attributes easy to access:: - - print 'All your {t.red}base {t.underline}are belong to us{t.normal}'.format(t=term) - - Simple capabilities of interest include... - - * ``bold`` - * ``reverse`` - * ``underline`` - * ``no_underline`` (which turns off underlining) - * ``blink`` - * ``normal`` (which turns off everything, even colors) - - Here are a few more which are less likely to work on all terminals: - - * ``dim`` - * ``italic`` and ``no_italic`` - * ``shadow`` and ``no_shadow`` - * ``standout`` and ``no_standout`` - * ``subscript`` and ``no_subscript`` - * ``superscript`` and ``no_superscript`` - * ``flash`` (which flashes the screen once) - - Note that, while the inverse of ``underline`` is ``no_underline``, the only way - to turn off ``bold`` or ``reverse`` is ``normal``, which also cancels any - custom colors. This is because there's no portable way to tell the terminal to - undo certain pieces of formatting, even at the lowest level. - - You might also notice that the above aren't the typical incomprehensible - terminfo capability names; we alias a few of the harder-to-remember ones for - readability. However, you aren't limited to these: you can reference any - string-returning capability listed on the `terminfo man page`_ by the name - under the "Cap-name" column: for example, ``term.rum``. - - .. _`terminfo man page`: http://www.manpagez.com/man/5/terminfo/ - - Color - ----- - - 16 colors, both foreground and background, are available as easy-to-remember - attributes:: - - from blessings import Terminal - - term = Terminal() - print term.red + term.on_green + 'Red on green? Ick!' + term.normal - print term.bright_red + term.on_bright_blue + 'This is even worse!' + term.normal - - You can also call them as wrappers, which sets everything back to normal at the - end:: - - print term.red_on_green('Red on green? Ick!') - print term.yellow('I can barely see it.') - - The available colors are... - - * ``black`` - * ``red`` - * ``green`` - * ``yellow`` - * ``blue`` - * ``magenta`` - * ``cyan`` - * ``white`` - - You can set the background color instead of the foreground by prepending - ``on_``, as in ``on_blue``. There is also a ``bright`` version of each color: - for example, ``on_bright_blue``. - - There is also a numerical interface to colors, which takes an integer from - 0-15:: - - term.color(5) + 'Hello' + term.normal - term.on_color(3) + 'Hello' + term.normal - - term.color(5)('Hello') - term.on_color(3)('Hello') - - If some color is unsupported (for instance, if only the normal colors are - available, not the bright ones), trying to use it will, on most terminals, have - no effect: the foreground and background colors will stay as they were. You can - get fancy and do different things depending on the supported colors by checking - `number_of_colors`_. - - .. _`number_of_colors`: http://packages.python.org/blessings/#blessings.Terminal.number_of_colors - - Compound Formatting - ------------------- - - If you want to do lots of crazy formatting all at once, you can just mash it - all together:: - - from blessings import Terminal - - term = Terminal() - print term.bold_underline_green_on_yellow + 'Woo' + term.normal - - Or you can use your newly coined attribute as a wrapper, which implicitly sets - everything back to normal afterward:: - - print term.bold_underline_green_on_yellow('Woo') - - This compound notation comes in handy if you want to allow users to customize - the formatting of your app: just have them pass in a format specifier like - "bold_green" on the command line, and do a quick ``getattr(term, - that_option)('Your text')`` when you do your formatting. - - I'd be remiss if I didn't credit couleur_, where I probably got the idea for - all this mashing. - - .. _couleur: http://pypi.python.org/pypi/couleur - - Moving The Cursor - ----------------- - - When you want to move the cursor to output text at a specific spot, you have - a few choices. - - Moving Temporarily - ~~~~~~~~~~~~~~~~~~ - - Most often, you'll need to flit to a certain location, print something, and - then return: for example, when updating a progress bar at the bottom of the - screen. ``Terminal`` provides a context manager for doing this concisely:: - - from blessings import Terminal - - term = Terminal() - with term.location(0, term.height - 1): - print 'Here is the bottom.' - print 'This is back where I came from.' - - Parameters to ``location()`` are ``x`` and then ``y``, but you can also pass - just one of them, leaving the other alone. For example... :: - - with term.location(y=10): - print 'We changed just the row.' - - If you're doing a series of ``move`` calls (see below) and want to return the - cursor to its original position afterward, call ``location()`` with no - arguments, and it will do only the position restoring:: - - with term.location(): - print term.move(1, 1) + 'Hi' - print term.move(9, 9) + 'Mom' - - Note that, since ``location()`` uses the terminal's built-in - position-remembering machinery, you can't usefully nest multiple calls. Use - ``location()`` at the outermost spot, and use simpler things like ``move`` - inside. - - Moving Permanently - ~~~~~~~~~~~~~~~~~~ - - If you just want to move and aren't worried about returning, do something like - this:: - - from blessings import Terminal - - term = Terminal() - print term.move(10, 1) + 'Hi, mom!' - - ``move`` - Position the cursor elsewhere. Parameters are y coordinate, then x - coordinate. - ``move_x`` - Move the cursor to the given column. - ``move_y`` - Move the cursor to the given row. - - How does all this work? These are simply more terminal capabilities, wrapped to - give them nicer names. The added wrinkle--that they take parameters--is also - given a pleasant treatment: rather than making you dig up ``tparm()`` all the - time, we simply make these capabilities into callable strings. You'd get the - raw capability strings if you were to just print them, but they're fully - parametrized if you pass params to them as if they were functions. - - Consequently, you can also reference any other string-returning capability - listed on the `terminfo man page`_ by its name under the "Cap-name" column. - - .. _`terminfo man page`: http://www.manpagez.com/man/5/terminfo/ - - One-Notch Movement - ~~~~~~~~~~~~~~~~~~ - - Finally, there are some parameterless movement capabilities that move the - cursor one character in various directions: - - * ``move_left`` - * ``move_right`` - * ``move_up`` - * ``move_down`` - - For example... :: - - print term.move_up + 'Howdy!' - - Height And Width - ---------------- - - It's simple to get the height and width of the terminal, in characters:: - - from blessings import Terminal - - term = Terminal() - height = term.height - width = term.width - - These are newly updated each time you ask for them, so they're safe to use from - SIGWINCH handlers. - - Clearing The Screen - ------------------- - - Blessings provides syntactic sugar over some screen-clearing capabilities: - - ``clear`` - Clear the whole screen. - ``clear_eol`` - Clear to the end of the line. - ``clear_bol`` - Clear backward to the beginning of the line. - ``clear_eos`` - Clear to the end of screen. - - Full-Screen Mode - ---------------- - - Perhaps you have seen a full-screen program, such as an editor, restore the - exact previous state of the terminal upon exiting, including, for example, the - command-line prompt from which it was launched. Curses pretty much forces you - into this behavior, but Blessings makes it optional. If you want to do the - state-restoration thing, use these capabilities: - - ``enter_fullscreen`` - Switch to the terminal mode where full-screen output is sanctioned. Print - this before you do any output. - ``exit_fullscreen`` - Switch back to normal mode, restoring the exact state from before - ``enter_fullscreen`` was used. - - Using ``exit_fullscreen`` will wipe away any trace of your program's output, so - reserve it for when you don't want to leave anything behind in the scrollback. - - There's also a context manager you can use as a shortcut:: - - from blessings import Terminal - - term = Terminal() - with term.fullscreen(): - # Print some stuff. - - Besides brevity, another advantage is that it switches back to normal mode even - if an exception is raised in the ``with`` block. - - Pipe Savvy - ---------- - - If your program isn't attached to a terminal, like if it's being piped to - another command or redirected to a file, all the capability attributes on - ``Terminal`` will return empty strings. You'll get a nice-looking file without - any formatting codes gumming up the works. - - If you want to override this--like if you anticipate your program being piped - through ``less -r``, which handles terminal escapes just fine--pass - ``force_styling=True`` to the ``Terminal`` constructor. - - In any case, there is a ``does_styling`` attribute on ``Terminal`` that lets - you see whether your capabilities will return actual, working formatting codes. - If it's false, you should refrain from drawing progress bars and other frippery - and just stick to content, since you're apparently headed into a pipe:: - - from blessings import Terminal - - term = Terminal() - if term.does_styling: - with term.location(0, term.height - 1): - print 'Progress: [=======> ]' - print term.bold('Important stuff') - - Shopping List - ============= - - There are decades of legacy tied up in terminal interaction, so attention to - detail and behavior in edge cases make a difference. Here are some ways - Blessings has your back: - - * Uses the terminfo database so it works with any terminal type - * Provides up-to-the-moment terminal height and width, so you can respond to - terminal size changes (SIGWINCH signals). (Most other libraries query the - ``COLUMNS`` and ``LINES`` environment variables or the ``cols`` or ``lines`` - terminal capabilities, which don't update promptly, if at all.) - * Avoids making a mess if the output gets piped to a non-terminal - * Works great with standard Python string templating - * Provides convenient access to all terminal capabilities, not just a sugared - few - * Outputs to any file-like object, not just stdout - * Keeps a minimum of internal state, so you can feel free to mix and match with - calls to curses or whatever other terminal libraries you like - - Blessings does not provide... - - * Native color support on the Windows command prompt. However, it should work - when used in concert with colorama_. - - .. _colorama: http://pypi.python.org/pypi/colorama/0.2.4 - - Bugs - ==== - - Bugs or suggestions? Visit the `issue tracker`_. - - .. _`issue tracker`: https://github.com/erikrose/blessings/issues/ - - Blessings tests are run automatically by `Travis CI`_. - - .. _`Travis CI`: https://travis-ci.org/erikrose/blessings/ - - .. image:: https://travis-ci.org/erikrose/blessings.svg?branch=master - :target: https://travis-ci.org/erikrose/blessings - - - License - ======= - - Blessings is under the MIT License. See the LICENSE file. - - Version History - =============== - - 1.7 - * Drop support for Python 2.6 and 3.3, which are end-of-lifed. - * Switch from 2to3 to the ``six`` library. - - 1.6.1 - * Don't crash if ``number_of_colors()`` is called when run in a non-terminal - or when ``does_styling`` is otherwise false. - - 1.6 - * Add ``does_styling`` property. This takes ``force_styling`` into account - and should replace most uses of ``is_a_tty``. - * Make ``is_a_tty`` a read-only property, like ``does_styling``. Writing to - it never would have done anything constructive. - * Add ``fullscreen()`` and ``hidden_cursor()`` to the auto-generated docs. - * Fall back to ``LINES`` and ``COLUMNS`` environment vars to find height and - width. (jquast) - * Support terminal types, such as kermit and avatar, that use bytes 127-255 - in their escape sequences. (jquast) - - 1.5.1 - * Clean up fabfile, removing the redundant ``test`` command. - * Add Travis support. - * Make ``python setup.py test`` work without spurious errors on 2.6. - * Work around a tox parsing bug in its config file. - * Make context managers clean up after themselves even if there's an - exception. (Vitja Makarov) - * Parametrizing a capability no longer crashes when there is no tty. (Vitja - Makarov) - - 1.5 - * Add syntactic sugar and documentation for ``enter_fullscreen`` and - ``exit_fullscreen``. - * Add context managers ``fullscreen()`` and ``hidden_cursor()``. - * Now you can force a ``Terminal`` never to emit styles by passing - ``force_styling=None``. - - 1.4 - * Add syntactic sugar for cursor visibility control and single-space-movement - capabilities. - * Endorse the ``location()`` idiom for restoring cursor position after a - series of manual movements. - * Fix a bug in which ``location()`` wouldn't do anything when passed zeroes. - * Allow tests to be run with ``python setup.py test``. - - 1.3 - * Added ``number_of_colors``, which tells you how many colors the terminal - supports. - * Made ``color(n)`` and ``on_color(n)`` callable to wrap a string, like the - named colors can. Also, make them both fall back to the ``setf`` and - ``setb`` capabilities (like the named colors do) if the ANSI ``setaf`` and - ``setab`` aren't available. - * Allowed ``color`` attr to act as an unparametrized string, not just a - callable. - * Made ``height`` and ``width`` examine any passed-in stream before falling - back to stdout. (This rarely if ever affects actual behavior; it's mostly - philosophical.) - * Made caching simpler and slightly more efficient. - * Got rid of a reference cycle between Terminals and FormattingStrings. - * Updated docs to reflect that terminal addressing (as in ``location()``) is - 0-based. - - 1.2 - * Added support for Python 3! We need 3.2.3 or greater, because the curses - library couldn't decide whether to accept strs or bytes before that - (http://bugs.python.org/issue10570). - * Everything that comes out of the library is now unicode. This lets us - support Python 3 without making a mess of the code, and Python 2 should - continue to work unless you were testing types (and badly). Please file a - bug if this causes trouble for you. - * Changed to the MIT License for better world domination. - * Added Sphinx docs. - - 1.1 - * Added nicely named attributes for colors. - * Introduced compound formatting. - * Added wrapper behavior for styling and colors. - * Let you force capabilities to be non-empty, even if the output stream is - not a terminal. - * Added the ``is_a_tty`` attribute for telling whether the output stream is a - terminal. - * Sugared the remaining interesting string capabilities. - * Let ``location()`` operate on just an x *or* y coordinate. - - 1.0 - * Extracted Blessings from nose-progressive, my `progress-bar-having, - traceback-shortcutting, rootin', tootin' testrunner`_. It provided the - tootin' functionality. - - .. _`progress-bar-having, traceback-shortcutting, rootin', tootin' testrunner`: http://pypi.python.org/pypi/nose-progressive/ - -Keywords: terminal,tty,curses,ncurses,formatting,style,color,console -Platform: UNKNOWN -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Environment :: Console :: Curses -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Software Development :: User Interfaces -Classifier: Topic :: Terminals diff --git a/third_party/python/blessings/README.rst b/third_party/python/blessings/blessings-1.7.dist-info/METADATA similarity index 93% rename from third_party/python/blessings/README.rst rename to third_party/python/blessings/blessings-1.7.dist-info/METADATA index 77da433c192d..70d9e52d7f60 100644 --- a/third_party/python/blessings/README.rst +++ b/third_party/python/blessings/blessings-1.7.dist-info/METADATA @@ -1,3 +1,34 @@ +Metadata-Version: 2.1 +Name: blessings +Version: 1.7 +Summary: A thin, practical wrapper around terminal coloring, styling, and positioning +Home-page: https://github.com/erikrose/blessings +Author: Erik Rose +Author-email: erikrose@grinchcentral.com +License: MIT +Keywords: terminal,tty,curses,ncurses,formatting,style,color,console +Platform: UNKNOWN +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Environment :: Console :: Curses +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: User Interfaces +Classifier: Topic :: Terminals +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: six + ========= Blessings ========= @@ -529,3 +560,5 @@ Version History tootin' functionality. .. _`progress-bar-having, traceback-shortcutting, rootin', tootin' testrunner`: http://pypi.python.org/pypi/nose-progressive/ + + diff --git a/third_party/python/blessings/blessings-1.7.dist-info/RECORD b/third_party/python/blessings/blessings-1.7.dist-info/RECORD new file mode 100644 index 000000000000..adc9dabea6c9 --- /dev/null +++ b/third_party/python/blessings/blessings-1.7.dist-info/RECORD @@ -0,0 +1,6 @@ +blessings/__init__.py,sha256=fuk_wcBYDooRZYG7HxMBllmeg-sUlJkb1fn2PIobK-8,21885 +blessings/tests.py,sha256=YkYrnSUfgqKH1JRFYuOJDCfAJxroNNsTdkgYgPLgwp4,8506 +blessings-1.7.dist-info/METADATA,sha256=z2xOZcraJNCmzceEsxR-d3s5omjTakjQv69BRX2vJcs,19687 +blessings-1.7.dist-info/RECORD,, +blessings-1.7.dist-info/WHEEL,sha256=NzFAKnL7g-U64xnS1s5e3mJnxKpOTeOtlXdFwS9yNXI,92 +blessings-1.7.dist-info/top_level.txt,sha256=vzAJmOe2K6vUJXLCDJIkIX05x4C-TjBDN7LcVcV-SpM,10 diff --git a/third_party/python/blessings/blessings-1.7.dist-info/WHEEL b/third_party/python/blessings/blessings-1.7.dist-info/WHEEL new file mode 100644 index 000000000000..bff023edf224 --- /dev/null +++ b/third_party/python/blessings/blessings-1.7.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/third_party/python/blessings/blessings-1.7.dist-info/top_level.txt b/third_party/python/blessings/blessings-1.7.dist-info/top_level.txt new file mode 100644 index 000000000000..57087d01d6d7 --- /dev/null +++ b/third_party/python/blessings/blessings-1.7.dist-info/top_level.txt @@ -0,0 +1 @@ +blessings diff --git a/third_party/python/blessings/setup.cfg b/third_party/python/blessings/setup.cfg deleted file mode 100644 index 861a9f554263..000000000000 --- a/third_party/python/blessings/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - diff --git a/third_party/python/blessings/setup.py b/third_party/python/blessings/setup.py deleted file mode 100644 index 01488fcdf4db..000000000000 --- a/third_party/python/blessings/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -import sys - -# Prevent spurious errors during `python setup.py test`, a la -# http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html: -try: - import multiprocessing -except ImportError: - pass - -from setuptools import setup, find_packages - - -setup( - name='blessings', - version='1.7', - description='A thin, practical wrapper around terminal coloring, styling, and positioning', - long_description=open('README.rst').read(), - author='Erik Rose', - author_email='erikrose@grinchcentral.com', - license='MIT', - packages=find_packages(exclude=['ez_setup']), - install_requires=['six'], - tests_require=['nose'], - test_suite='nose.collector', - url='https://github.com/erikrose/blessings', - include_package_data=True, - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - classifiers=[ - 'Intended Audience :: Developers', - 'Natural Language :: English', - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Environment :: Console :: Curses', - 'License :: OSI Approved :: MIT License', - 'Operating System :: POSIX', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: User Interfaces', - 'Topic :: Terminals' - ], - keywords=['terminal', 'tty', 'curses', 'ncurses', 'formatting', 'style', 'color', 'console'], -) diff --git a/third_party/python/blessings/tox.ini b/third_party/python/blessings/tox.ini deleted file mode 100644 index 558601ec2bf8..000000000000 --- a/third_party/python/blessings/tox.ini +++ /dev/null @@ -1,8 +0,0 @@ -[tox] -envlist = py{27,34,35,36,py} - -[testenv] -commands = nosetests blessings -deps = - nose - six diff --git a/third_party/python/certifi/MANIFEST.in b/third_party/python/certifi/MANIFEST.in deleted file mode 100644 index 6077b5ff84d2..000000000000 --- a/third_party/python/certifi/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include MANIFEST.in README.rst LICENSE certifi/cacert.pem diff --git a/third_party/python/certifi/PKG-INFO b/third_party/python/certifi/PKG-INFO deleted file mode 100644 index 73f3643804f1..000000000000 --- a/third_party/python/certifi/PKG-INFO +++ /dev/null @@ -1,69 +0,0 @@ -Metadata-Version: 1.1 -Name: certifi -Version: 2018.4.16 -Summary: Python package for providing Mozilla's CA Bundle. -Home-page: http://certifi.io/ -Author: Kenneth Reitz -Author-email: me@kennethreitz.com -License: MPL-2.0 -Description: Certifi: Python SSL Certificates - ================================ - - `Certifi`_ is a carefully curated collection of Root Certificates for - validating the trustworthiness of SSL certificates while verifying the identity - of TLS hosts. It has been extracted from the `Requests`_ project. - - Installation - ------------ - - ``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - - Usage - ----- - - To reference the installed certificate authority (CA) bundle, you can use the - built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python2.7/site-packages/certifi/cacert.pem' - - Enjoy! - - 1024-bit Root Certificates - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Browsers and certificate authorities have concluded that 1024-bit keys are - unacceptably weak for certificates, particularly root certificates. For this - reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its - bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) - certificate from the same CA. Because Mozilla removed these certificates from - its bundle, ``certifi`` removed them as well. - - In previous versions, ``certifi`` provided the ``certifi.old_where()`` function - to intentionally re-add the 1024-bit roots back into your bundle. This was not - recommended in production and therefore was removed. To assist in migrating old - code, the function ``certifi.old_where()`` continues to exist as an alias of - ``certifi.where()``. Please update your code to use ``certifi.where()`` - instead. ``certifi.old_where()`` will be removed in 2018. - - .. _`Certifi`: http://certifi.io/en/latest/ - .. _`Requests`: http://docs.python-requests.org/en/latest/ - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 diff --git a/third_party/python/certifi/README.rst b/third_party/python/certifi/certifi-2018.4.16.dist-info/DESCRIPTION.rst similarity index 99% rename from third_party/python/certifi/README.rst rename to third_party/python/certifi/certifi-2018.4.16.dist-info/DESCRIPTION.rst index 64b3e38e1072..643a4f9b0242 100644 --- a/third_party/python/certifi/README.rst +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/DESCRIPTION.rst @@ -44,3 +44,5 @@ instead. ``certifi.old_where()`` will be removed in 2018. .. _`Certifi`: http://certifi.io/en/latest/ .. _`Requests`: http://docs.python-requests.org/en/latest/ + + diff --git a/third_party/python/certifi/LICENSE b/third_party/python/certifi/certifi-2018.4.16.dist-info/LICENSE.txt similarity index 100% rename from third_party/python/certifi/LICENSE rename to third_party/python/certifi/certifi-2018.4.16.dist-info/LICENSE.txt diff --git a/third_party/python/certifi/certifi-2018.4.16.dist-info/METADATA b/third_party/python/certifi/certifi-2018.4.16.dist-info/METADATA new file mode 100644 index 000000000000..b710cd5dc2c3 --- /dev/null +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/METADATA @@ -0,0 +1,71 @@ +Metadata-Version: 2.0 +Name: certifi +Version: 2018.4.16 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: http://certifi.io/ +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 + +Certifi: Python SSL Certificates +================================ + +`Certifi`_ is a carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python2.7/site-packages/certifi/cacert.pem' + +Enjoy! + +1024-bit Root Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Browsers and certificate authorities have concluded that 1024-bit keys are +unacceptably weak for certificates, particularly root certificates. For this +reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its +bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) +certificate from the same CA. Because Mozilla removed these certificates from +its bundle, ``certifi`` removed them as well. + +In previous versions, ``certifi`` provided the ``certifi.old_where()`` function +to intentionally re-add the 1024-bit roots back into your bundle. This was not +recommended in production and therefore was removed. To assist in migrating old +code, the function ``certifi.old_where()`` continues to exist as an alias of +``certifi.where()``. Please update your code to use ``certifi.where()`` +instead. ``certifi.old_where()`` will be removed in 2018. + +.. _`Certifi`: http://certifi.io/en/latest/ +.. _`Requests`: http://docs.python-requests.org/en/latest/ + + diff --git a/third_party/python/certifi/certifi-2018.4.16.dist-info/RECORD b/third_party/python/certifi/certifi-2018.4.16.dist-info/RECORD new file mode 100644 index 000000000000..50061f5d1fb0 --- /dev/null +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/RECORD @@ -0,0 +1,11 @@ +certifi/__init__.py,sha256=KHDlQtQQTRmOG0TJi12ZIE5WWq2tYHM5ax30EX6UJ04,63 +certifi/__main__.py,sha256=FiOYt1Fltst7wk9DRa6GCoBr8qBUxlNQu_MKJf04E6s,41 +certifi/cacert.pem,sha256=0lwMLbfi4umzDdOmdLMdrNkgZxw-5y6PCE10PrnJy-k,268839 +certifi/core.py,sha256=xPQDdG_siy5A7BfqGWa7RJhcA61xXEqPiSrw9GNyhHE,836 +certifi-2018.4.16.dist-info/DESCRIPTION.rst,sha256=jXrtxvB2mFIsHbuK8aP8RXrMx5yecyAIMZ2cn8Xb_ro,1679 +certifi-2018.4.16.dist-info/LICENSE.txt,sha256=anCkv2sBABbVmmS4rkrY3H9e8W8ftFPMLs13HFo0ETE,1048 +certifi-2018.4.16.dist-info/METADATA,sha256=uYCLBFPwRU0XfEULiHO8iLo1QELisMwd9CSJ_Bw4DIc,2570 +certifi-2018.4.16.dist-info/RECORD,, +certifi-2018.4.16.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113 +certifi-2018.4.16.dist-info/metadata.json,sha256=ayQwq1S2ID9f_MxGU0ZEouhzp5UoCwVtNT3ZLM23p7g,1006 +certifi-2018.4.16.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 diff --git a/third_party/python/certifi/certifi-2018.4.16.dist-info/WHEEL b/third_party/python/certifi/certifi-2018.4.16.dist-info/WHEEL new file mode 100644 index 000000000000..7bf9daa1ada4 --- /dev/null +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0.a0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/certifi/certifi-2018.4.16.dist-info/metadata.json b/third_party/python/certifi/certifi-2018.4.16.dist-info/metadata.json new file mode 100644 index 000000000000..ddab4a7358de --- /dev/null +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6"], "extensions": {"python.details": {"contacts": [{"email": "me@kennethreitz.com", "name": "Kenneth Reitz", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://certifi.io/"}}}, "generator": "bdist_wheel (0.30.0.a0)", "license": "MPL-2.0", "metadata_version": "2.0", "name": "certifi", "summary": "Python package for providing Mozilla's CA Bundle.", "version": "2018.4.16"} \ No newline at end of file diff --git a/third_party/python/certifi/certifi-2018.4.16.dist-info/top_level.txt b/third_party/python/certifi/certifi-2018.4.16.dist-info/top_level.txt new file mode 100644 index 000000000000..963eac530b9b --- /dev/null +++ b/third_party/python/certifi/certifi-2018.4.16.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/third_party/python/certifi/setup.cfg b/third_party/python/certifi/setup.cfg deleted file mode 100644 index 163eba3165f1..000000000000 --- a/third_party/python/certifi/setup.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE - -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - diff --git a/third_party/python/certifi/setup.py b/third_party/python/certifi/setup.py deleted file mode 100755 index 2c20c269f649..000000000000 --- a/third_party/python/certifi/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from __future__ import with_statement -import re -import os -import sys - -# While I generally consider it an antipattern to try and support both -# setuptools and distutils with a single setup.py, in this specific instance -# where certifi is a dependency of setuptools, it can create a circular -# dependency when projects attempt to unbundle stuff from setuptools and pip. -# Though we don't really support that, it makes things easier if we do this and -# should hopefully cause less issues for end users. -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - - -version_regex = r'__version__ = ["\']([^"\']*)["\']' -with open('certifi/__init__.py', 'r') as f: - text = f.read() - match = re.search(version_regex, text) - - if match: - VERSION = match.group(1) - else: - raise RuntimeError("No version number found!") - -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel upload') - sys.exit() - -required = [] -setup( - name='certifi', - version=VERSION, - description='Python package for providing Mozilla\'s CA Bundle.', - long_description=open('README.rst').read(), - author='Kenneth Reitz', - author_email='me@kennethreitz.com', - url='http://certifi.io/', - packages=[ - 'certifi', - ], - package_dir={'certifi': 'certifi'}, - package_data={'certifi': ['*.pem']}, - # data_files=[('certifi', ['certifi/cacert.pem'])], - include_package_data=True, - zip_safe=False, - license='MPL-2.0', - classifiers=( - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - ), -) diff --git a/third_party/python/chardet/MANIFEST.in b/third_party/python/chardet/MANIFEST.in deleted file mode 100644 index be5768dd9a6c..000000000000 --- a/third_party/python/chardet/MANIFEST.in +++ /dev/null @@ -1,8 +0,0 @@ -include LICENSE -include *.rst -include requirements.txt -include test.py -recursive-include docs * -recursive-include tests * -global-exclude *.pyc -global-exclude __pycache__ diff --git a/third_party/python/chardet/NOTES.rst b/third_party/python/chardet/NOTES.rst deleted file mode 100644 index 998db58d49f2..000000000000 --- a/third_party/python/chardet/NOTES.rst +++ /dev/null @@ -1,140 +0,0 @@ -Class Hierarchy for chardet -=========================== - -Universal Detector ------------------- -Has a list of probers. - -CharSetProber -------------- -Mostly abstract parent class. - -CharSetGroupProber ------------------- -Runs a bunch of related probers at the same time and decides which is best. - -SBCSGroupProber ---------------- -SBCS = Single-ByteCharSet. Runs a bunch of SingleByteCharSetProbers. Always -contains the same SingleByteCharSetProbers. - -SingleByteCharSetProber ------------------------ -A CharSetProber that is used for detecting single-byte encodings by using -a "precedence matrix" (i.e., a character bigram model). - -MBCSGroupProber ---------------- -Runs a bunch of MultiByteCharSetProbers. It also uses a UTF8Prober, which is -essentially a MultiByteCharSetProber that only has a state machine. Always -contains the same MultiByteCharSetProbers. - -MultiByteCharSetProber ----------------------- -A CharSetProber that uses both a character unigram model (or "character -distribution analysis") and an independent state machine for trying to -detect and encoding. - -CodingStateMachine ------------------- -Used for "coding scheme" detection, where we just look for either invalid -byte sequences or sequences that only occur for that particular encoding. - -CharDistributionAnalysis ------------------------- -Used for character unigram distribution encoding detection. Takes a mapping -from characters to a "frequency order" (i.e., what frequency rank that byte has -in the given encoding) and a "typical distribution ratio", which is the number -of occurrences of the 512 most frequently used characters divided by the number -of occurrences of the rest of the characters for a typical document. -The "characters" in this case are 2-byte sequences and they are first converted -to an "order" (name comes from ord() function, I believe). This "order" is used -to index into the frequency order table to determine the frequency rank of that -byte sequence. The reason this extra step is necessary is that the frequency -rank table is language-specific (and not encoding-specific). - - -What's where -============ - - -Bigram files ------------- - -- ``hebrewprober.py`` -- ``jpcntxprober.py`` -- ``langbulgarianmodel.py`` -- ``langcyrillicmodel.py`` -- ``langgreekmodel.py`` -- ``langhebrewmodel.py`` -- ``langhungarianmodel.py`` -- ``langthaimodel.py`` -- ``latin1prober.py`` -- ``sbcharsetprober.py`` -- ``sbcsgroupprober.py`` - - -Coding Scheme files -------------------- - -- ``escprober.py`` -- ``escsm.py`` -- ``utf8prober.py`` -- ``codingstatemachine.py`` -- ``mbcssmprober.py`` - - -Unigram files -------------- - -- ``big5freqprober.py`` -- ``chardistribution.py`` -- ``euckrfreqprober.py`` -- ``euctwfreqprober.py`` -- ``gb2312freqprober.py`` -- ``jisfreqprober.py`` - -Multibyte probers ------------------ - -- ``big5prober.py`` -- ``cp949prober.py`` -- ``eucjpprober.py`` -- ``euckrprober.py`` -- ``euctwprober.py`` -- ``gb2312prober.py`` -- ``mbcharsetprober.py`` -- ``mbcsgroupprober.py`` -- ``sjisprober.py`` - -Misc files ----------- - -- ``__init__.py`` (currently has ``detect`` function in it) -- ``compat.py`` -- ``enums.py`` -- ``universaldetector.py`` -- ``version.py`` - - -Useful links -============ - -This is just a collection of information that I've found useful or thought -might be useful in the future: - -- `BOM by Encoding`_ - -- `A Composite Approach to Language/Encoding Detection`_ - -- `What Every Programmer Absolutely...`_ - -- The actual `source`_ - - -.. _BOM by Encoding: - https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding -.. _A Composite Approach to Language/Encoding Detection: - http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html -.. _What Every Programmer Absolutely...: http://kunststube.net/encoding/ -.. _source: https://dxr.mozilla.org/mozilla/source/intl/chardet/ diff --git a/third_party/python/chardet/PKG-INFO b/third_party/python/chardet/PKG-INFO deleted file mode 100644 index 839c9f08ed20..000000000000 --- a/third_party/python/chardet/PKG-INFO +++ /dev/null @@ -1,99 +0,0 @@ -Metadata-Version: 1.2 -Name: chardet -Version: 4.0.0 -Summary: Universal encoding detector for Python 2 and 3 -Home-page: https://github.com/chardet/chardet -Author: Mark Pilgrim -Author-email: mark@diveintomark.org -Maintainer: Daniel Blanchard -Maintainer-email: dan.blanchard@gmail.com -License: LGPL -Description: Chardet: The Universal Character Encoding Detector - -------------------------------------------------- - - .. image:: https://img.shields.io/travis/chardet/chardet/stable.svg - :alt: Build status - :target: https://travis-ci.org/chardet/chardet - - .. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg - :target: https://coveralls.io/r/chardet/chardet - - .. image:: https://img.shields.io/pypi/v/chardet.svg - :target: https://warehouse.python.org/project/chardet/ - :alt: Latest version on PyPI - - .. image:: https://img.shields.io/pypi/l/chardet.svg - :alt: License - - - Detects - - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) - - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) - - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) - - EUC-KR, ISO-2022-KR (Korean) - - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) - - ISO-8859-5, windows-1251 (Bulgarian) - - ISO-8859-1, windows-1252 (Western European languages) - - ISO-8859-7, windows-1253 (Greek) - - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) - - TIS-620 (Thai) - - .. note:: - Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily - disabled until we can retrain the models. - - Requires Python 2.7 or 3.5+. - - Installation - ------------ - - Install from `PyPI `_:: - - pip install chardet - - Documentation - ------------- - - For users, docs are now available at https://chardet.readthedocs.io/. - - Command-line Tool - ----------------- - - chardet comes with a command-line script which reports on the encodings of one - or more files:: - - % chardetect somefile someotherfile - somefile: windows-1252 with confidence 0.5 - someotherfile: ascii with confidence 1.0 - - About - ----- - - This is a continuation of Mark Pilgrim's excellent chardet. Previously, two - versions needed to be maintained: one that supported python 2.x and one that - supported python 3.x. We've recently merged with `Ian Cordasco `_'s - `charade `_ fork, so now we have one - coherent version that works for Python 2.7+ and 3.4+. - - :maintainer: Dan Blanchard - -Keywords: encoding,i18n,xml -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Text Processing :: Linguistic -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* diff --git a/third_party/python/chardet/LICENSE b/third_party/python/chardet/chardet-4.0.0.dist-info/LICENSE similarity index 100% rename from third_party/python/chardet/LICENSE rename to third_party/python/chardet/chardet-4.0.0.dist-info/LICENSE diff --git a/third_party/python/chardet/README.rst b/third_party/python/chardet/chardet-4.0.0.dist-info/METADATA similarity index 61% rename from third_party/python/chardet/README.rst rename to third_party/python/chardet/chardet-4.0.0.dist-info/METADATA index 425cc0baa68e..590bcc32a750 100644 --- a/third_party/python/chardet/README.rst +++ b/third_party/python/chardet/chardet-4.0.0.dist-info/METADATA @@ -1,3 +1,34 @@ +Metadata-Version: 2.1 +Name: chardet +Version: 4.0.0 +Summary: Universal encoding detector for Python 2 and 3 +Home-page: https://github.com/chardet/chardet +Author: Mark Pilgrim +Author-email: mark@diveintomark.org +Maintainer: Daniel Blanchard +Maintainer-email: dan.blanchard@gmail.com +License: LGPL +Keywords: encoding,i18n,xml +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Linguistic +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + Chardet: The Universal Character Encoding Detector -------------------------------------------------- @@ -66,3 +97,5 @@ supported python 3.x. We've recently merged with `Ian Cordasco .+?)\1""", - version_file.read()).group('version') - - -def readme(): - with open('README.rst') as f: - return f.read() - - -setup(name='chardet', - version=get_version(), - description='Universal encoding detector for Python 2 and 3', - long_description=readme(), - author='Mark Pilgrim', - author_email='mark@diveintomark.org', - maintainer='Daniel Blanchard', - maintainer_email='dan.blanchard@gmail.com', - url='https://github.com/chardet/chardet', - license="LGPL", - keywords=['encoding', 'i18n', 'xml'], - classifiers=["Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - ("License :: OSI Approved :: GNU Library or Lesser General" - " Public License (LGPL)"), - "Operating System :: OS Independent", - "Programming Language :: Python", - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - ('Programming Language :: Python :: Implementation :: ' - 'CPython'), - 'Programming Language :: Python :: Implementation :: PyPy', - ("Topic :: Software Development :: Libraries :: Python " - "Modules"), - "Topic :: Text Processing :: Linguistic"], - packages=find_packages(), - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", - entry_points={'console_scripts': - ['chardetect = chardet.cli.chardetect:main']}) diff --git a/third_party/python/chardet/test.py b/third_party/python/chardet/test.py deleted file mode 100644 index ad2b75368147..000000000000 --- a/third_party/python/chardet/test.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -Run chardet on a bunch of documents and see that we get the correct encodings. - -:author: Dan Blanchard -:author: Ian Cordasco -""" - -from __future__ import with_statement - -import textwrap -from difflib import ndiff -from io import open -from os import listdir -from os.path import dirname, isdir, join, realpath, relpath, splitext - -try: - import hypothesis.strategies as st - from hypothesis import given, assume, settings, Verbosity - HAVE_HYPOTHESIS = True -except ImportError: - HAVE_HYPOTHESIS = False -import pytest - -import chardet - - -# TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) after we -# retrain model. -MISSING_ENCODINGS = {'iso-8859-2', 'iso-8859-6', 'windows-1250', - 'windows-1254', 'windows-1256'} -EXPECTED_FAILURES = {'tests/iso-8859-7-greek/disabled.gr.xml', - 'tests/iso-8859-9-turkish/divxplanet.com.xml', - 'tests/iso-8859-9-turkish/subtitle.srt', - 'tests/iso-8859-9-turkish/wikitop_tr_ISO-8859-9.txt'} - -def gen_test_params(): - """Yields tuples of paths and encodings to use for test_encoding_detection""" - base_path = relpath(join(dirname(realpath(__file__)), 'tests')) - for encoding in listdir(base_path): - path = join(base_path, encoding) - # Skip files in tests directory - if not isdir(path): - continue - # Remove language suffixes from encoding if pressent - encoding = encoding.lower() - for postfix in ['-arabic', '-bulgarian', '-cyrillic', '-greek', - '-hebrew', '-hungarian', '-turkish']: - if encoding.endswith(postfix): - encoding = encoding.rpartition(postfix)[0] - break - # Skip directories for encodings we don't handle yet. - if encoding in MISSING_ENCODINGS: - continue - # Test encoding detection for each file we have of encoding for - for file_name in listdir(path): - ext = splitext(file_name)[1].lower() - if ext not in ['.html', '.txt', '.xml', '.srt']: - continue - full_path = join(path, file_name) - test_case = full_path, encoding - if full_path in EXPECTED_FAILURES: - test_case = pytest.param(*test_case, marks=pytest.mark.xfail) - yield test_case - - -@pytest.mark.parametrize ('file_name, encoding', gen_test_params()) -def test_encoding_detection(file_name, encoding): - with open(file_name, 'rb') as f: - input_bytes = f.read() - result = chardet.detect(input_bytes) - try: - expected_unicode = input_bytes.decode(encoding) - except LookupError: - expected_unicode = '' - try: - detected_unicode = input_bytes.decode(result['encoding']) - except (LookupError, UnicodeDecodeError, TypeError): - detected_unicode = '' - if result: - encoding_match = (result['encoding'] or '').lower() == encoding - else: - encoding_match = False - # Only care about mismatches that would actually result in different - # behavior when decoding - if not encoding_match and expected_unicode != detected_unicode: - wrapped_expected = '\n'.join(textwrap.wrap(expected_unicode, 100)) + '\n' - wrapped_detected = '\n'.join(textwrap.wrap(detected_unicode, 100)) + '\n' - diff = ''.join(ndiff(wrapped_expected.splitlines(True), - wrapped_detected.splitlines(True))) - else: - diff = '' - encoding_match = True - assert encoding_match, ("Expected %s, but got %s for %s. Character " - "differences: \n%s" % (encoding, - result, - file_name, - diff)) - - -if HAVE_HYPOTHESIS: - class JustALengthIssue(Exception): - pass - - - @pytest.mark.xfail - @given(st.text(min_size=1), st.sampled_from(['ascii', 'utf-8', 'utf-16', - 'utf-32', 'iso-8859-7', - 'iso-8859-8', 'windows-1255']), - st.randoms()) - @settings(max_examples=200) - def test_never_fails_to_detect_if_there_is_a_valid_encoding(txt, enc, rnd): - try: - data = txt.encode(enc) - except UnicodeEncodeError: - assume(False) - detected = chardet.detect(data)['encoding'] - if detected is None: - with pytest.raises(JustALengthIssue): - @given(st.text(), random=rnd) - @settings(verbosity=Verbosity.quiet, max_shrinks=0, max_examples=50) - def string_poisons_following_text(suffix): - try: - extended = (txt + suffix).encode(enc) - except UnicodeEncodeError: - assume(False) - result = chardet.detect(extended) - if result and result['encoding'] is not None: - raise JustALengthIssue() - - - @given(st.text(min_size=1), st.sampled_from(['ascii', 'utf-8', 'utf-16', - 'utf-32', 'iso-8859-7', - 'iso-8859-8', 'windows-1255']), - st.randoms()) - @settings(max_examples=200) - def test_detect_all_and_detect_one_should_agree(txt, enc, rnd): - try: - data = txt.encode(enc) - except UnicodeEncodeError: - assume(False) - try: - result = chardet.detect(data) - results = chardet.detect_all(data) - assert result['encoding'] == results[0]['encoding'] - except Exception: - raise Exception('%s != %s' % (result, results)) diff --git a/third_party/python/compare-locales/PKG-INFO b/third_party/python/compare-locales/PKG-INFO deleted file mode 100644 index 5daa15c4a53d..000000000000 --- a/third_party/python/compare-locales/PKG-INFO +++ /dev/null @@ -1,82 +0,0 @@ -Metadata-Version: 2.1 -Name: compare-locales -Version: 8.1.0 -Summary: Lint Mozilla localizations -Home-page: UNKNOWN -Author: Axel Hecht -Author-email: axel@mozilla.com -License: MPL 2.0 -Description: [![Build Status](https://travis-ci.org/Pike/compare-locales.svg?branch=master)](https://travis-ci.org/Pike/compare-locales) - # compare-locales - Lint Mozilla localizations - - Finds - * missing strings - * obsolete strings - * errors on runtime errors without false positives - * warns on possible runtime errors - - It also includes `l10n-merge` functionality, which pads localizations with - missing English strings, and replaces entities with errors with English. - - If you want to check your original code for errors like duplicated messages, - use `moz-l10n-lint`, which is also part of this package. You can also use - this to check for conflicts between your strings and those already exposed - to l10n. - - # Configuration - - You configure `compare-locales` (and `moz-l10n-lint`) through a - [project configuration](https://moz-l10n-config.readthedocs.io/en/latest/fileformat.html) - file, `l10n.toml`. - - # Examples - - To check all locales in a project use - - ```bash - compare-locales l10n.toml . - ``` - - To check Firefox against a local check-out of l10n-central, use - - ```bash - compare-locales browser/locales/l10n.toml ../l10n-central - ``` - - If you just want to check particular locales, specify them as additional - commandline parameters. - - To lint your local work, use - - ```bash - moz-l10n-lint l10n.toml - ``` - - To check for conflicts against already existing strings: - - ```bash - moz-l10n-lint --reference-project ../android-l10n/mozilla-mobile/fenix l10n.toml - moz-l10n-lint --l10n-reference ../gecko-strings browser/locales/l10n.toml - ``` - - to check for a monolithic project like Fenix or a gecko project like Firefox, - resp. - -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Localization -Classifier: Topic :: Software Development :: Testing -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 -Description-Content-Type: text/markdown diff --git a/third_party/python/compare-locales/compare_locales/tests/__init__.py b/third_party/python/compare-locales/compare_locales/tests/__init__.py deleted file mode 100644 index 8e4df179611f..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/__init__.py +++ /dev/null @@ -1,82 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -'''Mixins for parser tests. -''' - -from __future__ import absolute_import - -from pkg_resources import resource_string -import re -import unittest - -from compare_locales import parser -from compare_locales.checks import getChecker -import six -from six.moves import zip_longest - - -class ParserTestMixin(): - '''Utility methods used by the parser tests. - ''' - filename = None - - def setUp(self): - '''Create a parser for this test. - ''' - self.parser = parser.getParser(self.filename) - - def tearDown(self): - 'tear down this test' - del self.parser - - def resource(self, name): - testcontent = resource_string(__name__, 'data/' + name) - # fake universal line endings - testcontent = re.sub(b'\r\n?', lambda m: b'\n', testcontent) - return testcontent - - def _test(self, unicode_content, refs): - '''Helper to test the parser. - Compares the result of parsing content with the given list - of reference keys and values. - ''' - self.parser.readUnicode(unicode_content) - entities = list(self.parser.walk()) - for entity, ref in zip_longest(entities, refs): - self.assertTrue(entity, - 'excess reference entity ' + six.text_type(ref)) - self.assertTrue(ref, - 'excess parsed entity ' + six.text_type(entity)) - if isinstance(entity, parser.Entity): - self.assertEqual(entity.key, ref[0]) - self.assertEqual(entity.val, ref[1]) - if len(ref) == 3: - self.assertIn(ref[2], entity.pre_comment.val) - else: - self.assertIsInstance(entity, ref[0]) - self.assertIn(ref[1], entity.all) - - -class BaseHelper(unittest.TestCase): - file = None - refContent = None - - def setUp(self): - p = parser.getParser(self.file.file) - p.readContents(self.refContent) - self.refList = p.parse() - - def _test(self, content, refWarnOrErrors): - p = parser.getParser(self.file.file) - p.readContents(content) - l10n = [e for e in p] - assert len(l10n) == 1 - l10n = l10n[0] - checker = getChecker(self.file) - if checker.needs_reference: - checker.set_reference(self.refList) - ref = self.refList[l10n.key] - found = tuple(checker.check(ref, l10n)) - self.assertEqual(found, refWarnOrErrors) diff --git a/third_party/python/compare-locales/compare_locales/tests/android/test_checks.py b/third_party/python/compare-locales/compare_locales/tests/android/test_checks.py deleted file mode 100644 index 382a7f8bdbeb..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/android/test_checks.py +++ /dev/null @@ -1,344 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals - -from compare_locales.tests import BaseHelper -from compare_locales.paths import File - - -ANDROID_WRAPPER = b''' - - %s - -''' - - -class SimpleStringsTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = ANDROID_WRAPPER % b'plain' - - def test_simple_string(self): - self._test( - ANDROID_WRAPPER % b'foo', - tuple() - ) - - def test_empty_string(self): - self._test( - ANDROID_WRAPPER % b'', - tuple() - ) - - def test_single_cdata(self): - self._test( - ANDROID_WRAPPER % b'', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'', - tuple() - ) - - def test_mix_cdata(self): - self._test( - ANDROID_WRAPPER % b' with ', - ( - ( - "error", - 0, - "Only plain text allowed, " - "or one CDATA surrounded by whitespace", - "android" - ), - ) - ) - - def test_element_fails(self): - self._test( - ANDROID_WRAPPER % b'one
two', - ( - ( - "error", - 0, - "Only plain text allowed, " - "or one CDATA surrounded by whitespace", - "android" - ), - ) - ) - - def test_bad_encoding(self): - self._test( - ANDROID_WRAPPER % 'touché'.encode('latin-1'), - ( - ( - "warning", - 24, - "\ufffd in: foo", - "encodings" - ), - ) - ) - - -class QuotesTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = ANDROID_WRAPPER % b'plain' - - def test_straightquotes(self): - self._test( - ANDROID_WRAPPER % b'""', - ( - ( - "error", - 0, - "Double straight quotes not allowed", - "android" - ), - ) - ) - self._test( - ANDROID_WRAPPER % b'"some"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'some\\"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'some"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'some', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'some""', - ( - ( - "error", - 4, - "Double straight quotes not allowed", - "android" - ), - ) - ) - - def test_apostrophes(self): - self._test( - ANDROID_WRAPPER % b'''"some'apos"''', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'''some\\'apos''', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'''some'apos''', - ( - ( - "error", - 4, - "Apostrophe must be escaped", - "android" - ), - ) - ) - - -class TranslatableTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = (ANDROID_WRAPPER % b'plain').replace( - b'name="foo"', - b'translatable="false" name="foo"') - - def test_translatable(self): - self._test( - ANDROID_WRAPPER % b'"some"', - ( - ( - "error", - 0, - "strings must be translatable", - "android" - ), - ) - ) - - -class AtStringTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = (ANDROID_WRAPPER % b'@string/foo') - - def test_translatable(self): - self._test( - ANDROID_WRAPPER % b'"some"', - ( - ( - "warning", - 0, - "strings must be translatable", - "android" - ), - ) - ) - - -class PrintfSTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = ANDROID_WRAPPER % b'%s' - - def test_match(self): - self._test( - ANDROID_WRAPPER % b'"%s"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"%1$s"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"$s %1$s"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"$1$s %1$s"', - tuple() - ) - - def test_mismatch(self): - self._test( - ANDROID_WRAPPER % b'"%d"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - self._test( - ANDROID_WRAPPER % b'"%S"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - - def test_off_position(self): - self._test( - ANDROID_WRAPPER % b'%2$s', - ( - ( - "error", - 0, - "Formatter %2$s not found in reference", - "android" - ), - ) - ) - - -class PrintfCapSTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = ANDROID_WRAPPER % b'%S' - - def test_match(self): - self._test( - ANDROID_WRAPPER % b'"%S"', - tuple() - ) - - def test_mismatch(self): - self._test( - ANDROID_WRAPPER % b'"%s"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - self._test( - ANDROID_WRAPPER % b'"%d"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - - -class PrintfDTest(BaseHelper): - file = File('values/strings.xml', 'values/strings.xml') - refContent = ANDROID_WRAPPER % b'%d' - - def test_match(self): - self._test( - ANDROID_WRAPPER % b'"%d"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"%1$d"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"$d %1$d"', - tuple() - ) - self._test( - ANDROID_WRAPPER % b'"$1$d %1$d"', - tuple() - ) - - def test_mismatch(self): - self._test( - ANDROID_WRAPPER % b'"%s"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - self._test( - ANDROID_WRAPPER % b'"%S"', - ( - ( - "error", - 0, - "Mismatching formatter", - "android" - ), - ) - ) - - def test_off_position(self): - self._test( - ANDROID_WRAPPER % b'%2$d', - ( - ( - "error", - 0, - "Formatter %2$d not found in reference", - "android" - ), - ) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/android/test_merge.py b/third_party/python/compare-locales/compare_locales/tests/android/test_merge.py deleted file mode 100644 index 32e13a743960..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/android/test_merge.py +++ /dev/null @@ -1,82 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMerge(unittest.TestCase): - name = "strings.xml" - - def test_no_changes(self): - channels = (b'''\ - - - - value - -''', b'''\ - - - - value - -''') - self.assertEqual( - merge_channels(self.name, channels), b'''\ - - - - value - -''') - - def test_a_and_b(self): - channels = (b'''\ - - - - value - -''', b'''\ - - - - other value - -''') - self.assertEqual( - merge_channels(self.name, channels), b'''\ - - - - other value - - value - -''') - - def test_namespaces(self): - channels = ( - b'''\ - - - string - -''', - b'''\ - - - string - -''' - ) - self.assertEqual( - merge_channels(self.name, channels), b'''\ - - - string - string - -''') diff --git a/third_party/python/compare-locales/compare_locales/tests/android/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/android/test_parser.py deleted file mode 100644 index f5949a1b8656..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/android/test_parser.py +++ /dev/null @@ -1,128 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from compare_locales.tests import ParserTestMixin -from compare_locales.parser import ( - Comment, - Junk, - Whitespace, -) -from compare_locales.parser.android import DocumentWrapper - - -class TestAndroidParser(ParserTestMixin, unittest.TestCase): - maxDiff = None - filename = 'strings.xml' - - def test_simple_string(self): - source = '''\ - - - - value - - - multi-line comment - - - - so lonely - -''' - self._test( - source, - ( - (DocumentWrapper, ''), - (Whitespace, '\n '), - ('foo', 'value', 'bar'), - (Whitespace, '\n'), - ('bar', 'multi-line comment', 'bar\nfoo'), - (Whitespace, '\n '), - (Comment, 'standalone'), - (Whitespace, '\n '), - ('baz', 'so lonely'), - (Whitespace, '\n'), - (DocumentWrapper, '') - ) - ) - - def test_bad_doc(self): - source = '''\ - - -''' - self._test( - source, - ( - (Junk, ''), - ) - ) - - def test_bad_elements(self): - source = '''\ - - - value - value - value - value - value - -''' - self._test( - source, - ( - (DocumentWrapper, ''), - (Whitespace, '\n '), - ('first', 'value'), - (Whitespace, '\n '), - (Junk, ''), - (Whitespace, '\n '), - ('mid', 'value'), - (Whitespace, '\n '), - (Junk, ''), - (Whitespace, '\n '), - ('last', 'value'), - (Whitespace, '\n'), - (DocumentWrapper, '') - ) - ) - - def test_xml_parse_error(self): - source = 'no xml' - self._test( - source, - ( - (Junk, 'no xml'), - ) - ) - - def test_empty_strings(self): - source = '''\ - - - - - -''' - self._test( - source, - ( - (DocumentWrapper, ''), - (Whitespace, '\n '), - ('one', ''), - (Whitespace, '\n '), - ('two', ''), - (Whitespace, '\n'), - (DocumentWrapper, '') - ) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/data/bug121341.properties b/third_party/python/compare-locales/compare_locales/tests/data/bug121341.properties deleted file mode 100644 index b45fc9698c42..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/data/bug121341.properties +++ /dev/null @@ -1,68 +0,0 @@ -# simple check -1=abc -# test whitespace trimming in key and value - 2 = xy -# test parsing of escaped values -3 = \u1234\t\r\n\uAB\ -\u1\n -# test multiline properties -4 = this is \ -multiline property -5 = this is \ - another multiline property -# property with DOS EOL -6 = test\u0036 -# test multiline property with with DOS EOL -7 = yet another multi\ - line propery -# trimming should not trim escaped whitespaces -8 = \ttest5\u0020 -# another variant of #8 -9 = \ test6\t -# test UTF-8 encoded property/value -10aሴb = c췯d -# next property should test unicode escaping at the boundary of parsing buffer -# buffer size is expected to be 4096 so add comments to get to this offset -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -################################################################################ -############################################################################### -11 = \uABCD diff --git a/third_party/python/compare-locales/compare_locales/tests/data/test.properties b/third_party/python/compare-locales/compare_locales/tests/data/test.properties deleted file mode 100644 index 19cae9702830..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/data/test.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -1=1 - 2=2 -3 =3 - 4 =4 -5=5 -6= 6 -7=7 -8= 8 -# this is a comment -9=this is the first part of a continued line \ - and here is the 2nd part diff --git a/third_party/python/compare-locales/compare_locales/tests/data/triple-license.dtd b/third_party/python/compare-locales/compare_locales/tests/data/triple-license.dtd deleted file mode 100644 index 4a28b17a6fa6..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/data/triple-license.dtd +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/third_party/python/compare-locales/compare_locales/tests/dtd/test_checks.py b/third_party/python/compare-locales/compare_locales/tests/dtd/test_checks.py deleted file mode 100644 index 5967c016d9d4..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/dtd/test_checks.py +++ /dev/null @@ -1,335 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from compare_locales.checks import getChecker -from compare_locales.parser import getParser, Parser, DTDEntity -from compare_locales.paths import File -from compare_locales.tests import BaseHelper -import six -from six.moves import range - - -class TestDTDs(BaseHelper): - file = File('foo.dtd', 'foo.dtd') - refContent = b''' - - - - - - -''' - - def testWarning(self): - self._test(b''' -''', - (('warning', (0, 0), 'Referencing unknown entity `not`', - 'xmlparse'),)) - # make sure we only handle translated entity references - self._test(''' -'''.encode('utf-8'), - (('warning', (0, 0), 'Referencing unknown entity `ƞǿŧ`', - 'xmlparse'),)) - - def testErrorFirstLine(self): - self._test(b''' stuff"> -''', - (('error', (1, 10), 'mismatched tag', 'xmlparse'),)) - - def testErrorSecondLine(self): - self._test(b''' -stuff"> -''', - (('error', (2, 4), 'mismatched tag', 'xmlparse'),)) - - def testKeyErrorSingleAmpersand(self): - self._test(b''' -''', - (('error', (1, 1), 'not well-formed (invalid token)', - 'xmlparse'),)) - - def testXMLEntity(self): - self._test(b''' -''', - tuple()) - - def testPercentEntity(self): - self._test(b''' -''', - tuple()) - self._test(b''' -''', - (('error', (0, 32), 'not well-formed (invalid token)', - 'xmlparse'),)) - - def testNoNumber(self): - self._test(b'''''', - (('warning', 0, 'reference is a number', 'number'),)) - - def testNoLength(self): - self._test(b'''''', - (('error', 0, 'reference is a CSS length', 'css'),)) - - def testNoStyle(self): - self._test(b'''''', - (('error', 0, 'reference is a CSS spec', 'css'),)) - self._test(b'''''', - (('error', 0, 'reference is a CSS spec', 'css'),)) - - def testStyleWarnings(self): - self._test(b'''''', - (('warning', 0, 'height only in reference', 'css'),)) - self._test(b'''''', - (('warning', 0, "units for width don't match (em != ch)", - 'css'),)) - - def testNoWarning(self): - self._test(b'''''', tuple()) - self._test(b'''''', tuple()) - self._test(b'''''', tuple()) - - def test_bad_encoding(self): - self._test( - ''.encode('latin-1'), - ( - ( - "warning", - 19, - "\ufffd in: foo", - "encodings" - ), - ) - ) - - -class TestEntitiesInDTDs(BaseHelper): - file = File('foo.dtd', 'foo.dtd') - refContent = b''' - - - -''' - - def testOK(self): - self._test(b'''''', - tuple()) - - def testMismatch(self): - self._test(b'''''', - (('warning', (0, 0), - 'Entity brandShortName referenced, ' - 'but brandShorterName used in context', - 'xmlparse'),)) - - def testAcross(self): - self._test(b'''''', - tuple()) - - def testAcrossWithMismatch(self): - '''If we could tell that ent.start and ent.end are one string, - we should warn. Sadly, we can't, so this goes without warning.''' - self._test(b'''''', - tuple()) - - def testUnknownWithRef(self): - self._test(b'''''', - (('warning', - (0, 0), - 'Referencing unknown entity `foopy` ' - '(brandShorterName used in context, ' - 'brandShortName known)', - 'xmlparse'),)) - - def testUnknown(self): - self._test(b'''''', - (('warning', - (0, 0), - 'Referencing unknown entity `foopy`' - ' (brandShortName, brandShorterName known)', - 'xmlparse'),)) - - -class TestAndroid(unittest.TestCase): - """Test Android checker - - Make sure we're hitting our extra rules only if - we're passing in a DTD file in the embedding/android module. - """ - apos_msg = "Apostrophes in Android DTDs need escaping with \\' or " + \ - "\\u0027, or use \u2019, or put string in quotes." - quot_msg = "Quotes in Android DTDs need escaping with \\\" or " + \ - "\\u0022, or put string in apostrophes." - - def getNext(self, v): - ctx = Parser.Context(v) - return DTDEntity( - ctx, None, None, (0, len(v)), (), (0, len(v))) - - def getDTDEntity(self, v): - if isinstance(v, six.binary_type): - v = v.decode('utf-8') - v = v.replace('"', '"') - ctx = Parser.Context('' % v) - return DTDEntity( - ctx, None, None, (0, len(v) + 16), (9, 12), (14, len(v) + 14)) - - def test_android_dtd(self): - """Testing the actual android checks. The logic is involved, - so this is a lot of nitty gritty detail tests. - """ - f = File("embedding/android/strings.dtd", "strings.dtd", - "embedding/android") - checker = getChecker(f, extra_tests=['android-dtd']) - # good string - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # dtd warning - l10n = self.getDTDEntity("plain localized string &ref;") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('warning', (0, 0), - 'Referencing unknown entity `ref`', 'xmlparse'),)) - # no report on stray ampersand or quote, if not completely quoted - for i in range(3): - # make sure we're catching unescaped apostrophes, - # try 0..5 backticks - l10n = self.getDTDEntity("\\"*(2*i) + "'") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 2*i, self.apos_msg, 'android'),)) - l10n = self.getDTDEntity("\\"*(2*i + 1) + "'") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # make sure we don't report if apos string is quoted - l10n = self.getDTDEntity('"' + "\\"*(2*i) + "'\"") - tpl = tuple(checker.check(ref, l10n)) - self.assertEqual(tpl, (), - "`%s` shouldn't fail but got %s" - % (l10n.val, str(tpl))) - l10n = self.getDTDEntity('"' + "\\"*(2*i+1) + "'\"") - tpl = tuple(checker.check(ref, l10n)) - self.assertEqual(tpl, (), - "`%s` shouldn't fail but got %s" - % (l10n.val, str(tpl))) - # make sure we're catching unescaped quotes, try 0..5 backticks - l10n = self.getDTDEntity("\\"*(2*i) + "\"") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 2*i, self.quot_msg, 'android'),)) - l10n = self.getDTDEntity("\\"*(2*i + 1) + "'") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # make sure we don't report if quote string is single quoted - l10n = self.getDTDEntity("'" + "\\"*(2*i) + "\"'") - tpl = tuple(checker.check(ref, l10n)) - self.assertEqual(tpl, (), - "`%s` shouldn't fail but got %s" % - (l10n.val, str(tpl))) - l10n = self.getDTDEntity('"' + "\\"*(2*i+1) + "'\"") - tpl = tuple(checker.check(ref, l10n)) - self.assertEqual(tpl, (), - "`%s` shouldn't fail but got %s" % - (l10n.val, str(tpl))) - # check for mixed quotes and ampersands - l10n = self.getDTDEntity("'\"") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 0, self.apos_msg, 'android'), - ('error', 1, self.quot_msg, 'android'))) - l10n = self.getDTDEntity("''\"'") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 1, self.apos_msg, 'android'),)) - l10n = self.getDTDEntity('"\'""') - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 2, self.quot_msg, 'android'),)) - - # broken unicode escape - l10n = self.getDTDEntity(b"Some broken \u098 unicode") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 12, 'truncated \\uXXXX escape', - 'android'),)) - # broken unicode escape, try to set the error off - l10n = self.getDTDEntity("\u9690"*14+"\\u006"+" "+"\\u0064") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 14, 'truncated \\uXXXX escape', - 'android'),)) - - def test_android_prop(self): - f = File("embedding/android/strings.properties", "strings.properties", - "embedding/android") - checker = getChecker(f, extra_tests=['android-dtd']) - # good plain string - ref = self.getNext("plain string") - l10n = self.getNext("plain localized string") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # no dtd warning - ref = self.getNext("plain string") - l10n = self.getNext("plain localized string &ref;") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # no report on stray ampersand - ref = self.getNext("plain string") - l10n = self.getNext("plain localized string with apos: '") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # report on bad printf - ref = self.getNext("string with %s") - l10n = self.getNext("string with %S") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('error', 0, 'argument 1 `S` should be `s`', - 'printf'),)) - - def test_non_android_dtd(self): - f = File("browser/strings.dtd", "strings.dtd", "browser") - checker = getChecker(f) - # good string - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # dtd warning - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string &ref;") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('warning', (0, 0), - 'Referencing unknown entity `ref`', 'xmlparse'),)) - # no report on stray ampersand - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string with apos: '") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - - def test_entities_across_dtd(self): - f = File("browser/strings.dtd", "strings.dtd", "browser") - p = getParser(f.file) - p.readContents(b'') - ref = p.parse() - checker = getChecker(f) - checker.set_reference(ref) - # good string - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - # dtd warning - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string &ref;") - self.assertEqual(tuple(checker.check(ref, l10n)), - (('warning', (0, 0), - 'Referencing unknown entity `ref` (good.ref known)', - 'xmlparse'),)) - # no report on stray ampersand - ref = self.getDTDEntity("plain string") - l10n = self.getDTDEntity("plain localized string with &good.ref;") - self.assertEqual(tuple(checker.check(ref, l10n)), - ()) - - -if __name__ == '__main__': - unittest.main() diff --git a/third_party/python/compare-locales/compare_locales/tests/dtd/test_merge.py b/third_party/python/compare-locales/compare_locales/tests/dtd/test_merge.py deleted file mode 100644 index e1db766e94e4..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/dtd/test_merge.py +++ /dev/null @@ -1,133 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMergeDTD(unittest.TestCase): - name = "foo.dtd" - maxDiff = None - - def test_no_changes(self): - channels = (b""" - -""", b""" - -""") - self.assertEqual( - merge_channels(self.name, channels), b""" - -""") - - def test_trailing_whitespace(self): - channels = (b""" - -""", b""" - \n""") - self.assertEqual( - merge_channels(self.name, channels), b""" - \n""") - - def test_browser_dtd(self): - channels = (b"""\ - - - - - - - - - - - -""", b"""\ - - - - - - - - - - - -""") - - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """\ - - - - - - - - - - - - - - - - -""") - - def test_aboutServiceWorkers_dtd(self): - channels = (b"""\ - - - - - - - - - - -""", b"""\ - - - - - - - - - - -""") - - self.assertEqual( - merge_channels(self.name, channels), b"""\ - - - - - - - - - - -""") diff --git a/third_party/python/compare-locales/compare_locales/tests/dtd/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/dtd/test_parser.py deleted file mode 100644 index 679bd21f84e7..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/dtd/test_parser.py +++ /dev/null @@ -1,271 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -'''Tests for the DTD parser. -''' - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest -import re - -from compare_locales import parser -from compare_locales.parser import ( - Comment, - Junk, - Whitespace, -) -from compare_locales.tests import ParserTestMixin - - -class TestDTD(ParserTestMixin, unittest.TestCase): - '''Tests for the DTD Parser.''' - filename = 'foo.dtd' - - def test_one_entity(self): - self._test('''''', - (('foo.label', 'stuff'),)) - self.assertListEqual( - [e.localized for e in self.parser], - [True] - ) - - quoteContent = ''' - - - - - - -''' - quoteRef = ( - ('good.one', 'one'), - (Whitespace, '\n'), - (Junk, '\n'), - ('good.two', 'two'), - (Whitespace, '\n'), - (Junk, '\n'), - ('good.three', 'three'), - (Whitespace, '\n'), - ('good.four', 'good \' quote'), - (Whitespace, '\n'), - ('good.five', 'good \'quoted\' word'), - (Whitespace, '\n'),) - - def test_quotes(self): - self._test(self.quoteContent, self.quoteRef) - - def test_apos(self): - qr = re.compile('[\'"]', re.M) - - def quot2apos(s): - return qr.sub(lambda m: m.group(0) == '"' and "'" or '"', s) - - self._test(quot2apos(self.quoteContent), - ((ref[0], quot2apos(ref[1])) for ref in self.quoteRef)) - - def test_parsed_ref(self): - self._test(''' - %fooDTD; -''', - (('fooDTD', '"chrome://brand.dtd"'),)) - self._test(''' - %fooDTD; -''', - (('fooDTD', '"chrome://brand.dtd"'),)) - - def test_trailing_comment(self): - self._test(''' - - -''', - ( - ('first', 'string'), - (Whitespace, '\n'), - ('second', 'string'), - (Whitespace, '\n'), - (Comment, 'out'), - (Whitespace, '\n'))) - - def test_license_header(self): - p = parser.getParser('foo.dtd') - p.readContents(self.resource('triple-license.dtd')) - entities = list(p.walk()) - self.assertIsInstance(entities[0], parser.Comment) - self.assertIn('MPL', entities[0].all) - e = entities[2] - self.assertIsInstance(e, parser.Entity) - self.assertEqual(e.key, 'foo') - self.assertEqual(e.val, 'value') - self.assertEqual(len(entities), 4) - p.readContents(b'''\ - - - -''') - entities = list(p.walk()) - self.assertIsInstance(entities[0], parser.Comment) - self.assertIn('MPL', entities[0].all) - e = entities[2] - self.assertIsInstance(e, parser.Entity) - self.assertEqual(e.key, 'foo') - self.assertEqual(e.val, 'value') - self.assertEqual(len(entities), 4) - # Test again without empty line after licence header, and with BOM. - p.readContents(b'''\xEF\xBB\xBF\ - - -''') - entities = list(p.walk()) - self.assertIsInstance(entities[0], parser.Comment) - self.assertIn('MPL', entities[0].all) - e = entities[2] - self.assertIsInstance(e, parser.Entity) - self.assertEqual(e.key, 'foo') - self.assertEqual(e.val, 'value') - self.assertEqual(len(entities), 4) - - def testBOM(self): - self._test(u'\ufeff', - (('foo.label', 'stuff'),)) - - def test_trailing_whitespace(self): - self._test('\n \n', - (('foo.label', 'stuff'), (Whitespace, '\n \n'))) - - def test_unicode_comment(self): - self._test(b''.decode('utf-8'), - ((Comment, u'\u53d6'),)) - - def test_empty_file(self): - self._test('', tuple()) - self._test('\n', ((Whitespace, '\n'),)) - self._test('\n\n', ((Whitespace, '\n\n'),)) - self._test(' \n\n', ((Whitespace, ' \n\n'),)) - - def test_positions(self): - self.parser.readContents(b'''\ - - -''') - one, two = list(self.parser) - self.assertEqual(one.position(), (1, 1)) - self.assertEqual(one.value_position(), (1, 16)) - self.assertEqual(one.position(-1), (1, 23)) - self.assertEqual(two.position(), (2, 1)) - self.assertEqual(two.value_position(), (2, 16)) - self.assertEqual(two.value_position(-1), (3, 14)) - self.assertEqual(two.value_position(10), (3, 5)) - - def test_word_count(self): - self.parser.readContents(b'''\ - -two"> -word"> -two three"> -''') - a, b, c, d = list(self.parser) - self.assertEqual(a.count_words(), 1) - self.assertEqual(b.count_words(), 2) - self.assertEqual(c.count_words(), 1) - self.assertEqual(d.count_words(), 3) - - def test_html_entities(self): - self.parser.readContents(b'''\ - - - - - -''') - entities = iter(self.parser) - - entity = next(entities) - self.assertEqual(entity.raw_val, '&') - self.assertEqual(entity.val, '&') - - entity = next(entities) - self.assertEqual(entity.raw_val, '&') - self.assertEqual(entity.val, '&') - - entity = next(entities) - self.assertEqual(entity.raw_val, '&') - self.assertEqual(entity.val, '&') - - entity = next(entities) - self.assertEqual(entity.raw_val, '&') - self.assertEqual(entity.val, '&') - - entity = next(entities) - self.assertEqual(entity.raw_val, '&unknownEntity;') - self.assertEqual(entity.val, '&unknownEntity;') - - def test_comment_val(self): - self.parser.readContents(b'''\ - - -''') - entities = self.parser.walk() - - entity = next(entities) - self.assertIsInstance(entity, parser.Comment) - self.assertEqual(entity.val, ' comment\nspanning lines ') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - - entity = next(entities) - self.assertIsInstance(entity, parser.Comment) - self.assertEqual(entity.val, '\n') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - - entity = next(entities) - self.assertIsInstance(entity, parser.Comment) - self.assertEqual(entity.val, ' last line ') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - - def test_pre_comment(self): - self.parser.readContents(b'''\ - - - - - - -''') - entities = self.parser.walk() - - entity = next(entities) - self.assertIsInstance(entity.pre_comment, parser.Comment) - self.assertEqual(entity.pre_comment.val, ' comment ') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - - entity = next(entities) - self.assertIsInstance(entity, parser.Comment) - self.assertEqual(entity.val, ' standalone ') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - - entity = next(entities) - self.assertIsInstance(entity.pre_comment, parser.Comment) - self.assertEqual(entity.pre_comment.val, ' glued ') - entity = next(entities) - self.assertIsInstance(entity, parser.Whitespace) - with self.assertRaises(StopIteration): - next(entities) - - -if __name__ == '__main__': - unittest.main() diff --git a/third_party/python/compare-locales/compare_locales/tests/fluent/__init__.py b/third_party/python/compare-locales/compare_locales/tests/fluent/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/compare-locales/compare_locales/tests/fluent/test_checks.py b/third_party/python/compare-locales/compare_locales/tests/fluent/test_checks.py deleted file mode 100644 index 5a906d2a8d2a..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/fluent/test_checks.py +++ /dev/null @@ -1,581 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import textwrap -import unittest - -from compare_locales.tests import BaseHelper -from compare_locales.paths import File - - -def dedent_ftl(text): - return textwrap.dedent(text.rstrip() + "\n").encode("utf-8") - - -REFERENCE = b'''\ -simple = value -term_ref = some { -term } - .attr = is simple -msg-attr-ref = some {button.label} -mixed-attr = value - .and = attribute -only-attr = - .one = exists --term = value need - .attrs = can differ -''' - - -class TestFluent(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = REFERENCE - - def test_simple(self): - self._test(b'''simple = localized''', - tuple()) - - -class TestMessage(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = REFERENCE - - def test_excess_attribute(self): - self._test( - dedent_ftl('''\ - simple = value with - .obsolete = attribute - '''), - ( - ( - 'error', 24, - 'Obsolete attribute: obsolete', 'fluent' - ), - ) - ) - - def test_duplicate_attribute(self): - self._test( - dedent_ftl('''\ - only-attr = - .one = attribute - .one = again - .one = three times - '''), - ( - ( - 'warning', 16, - 'Attribute "one" is duplicated', 'fluent' - ), - ( - 'warning', 37, - 'Attribute "one" is duplicated', 'fluent' - ), - ( - 'warning', 54, - 'Attribute "one" is duplicated', 'fluent' - ), - ) - ) - - def test_only_attributes(self): - self._test( - dedent_ftl('''\ - only-attr = obsolete value - '''), - ( - ( - 'error', 0, - 'Missing attribute: one', 'fluent' - ), - ( - 'error', 12, - 'Obsolete value', 'fluent' - ), - ) - ) - - def test_missing_value(self): - self._test( - dedent_ftl('''\ - mixed-attr = - .and = attribute exists - '''), - ( - ( - 'error', 0, - 'Missing value', 'fluent' - ), - ) - ) - - def test_bad_encoding(self): - self._test( - 'simple = touché'.encode('latin-1'), - ( - ( - "warning", - 14, - "\ufffd in: simple", - "encodings" - ), - ) - ) - - -class TestTerm(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = REFERENCE - - def test_mismatching_attribute(self): - self._test( - dedent_ftl('''\ - -term = value with - .different = attribute - '''), - tuple() - ) - - def test_duplicate_attribute(self): - self._test( - dedent_ftl('''\ - -term = need value - .one = attribute - .one = again - .one = three times - '''), - ( - ( - 'warning', 23, - 'Attribute "one" is duplicated', 'fluent' - ), - ( - 'warning', 44, - 'Attribute "one" is duplicated', 'fluent' - ), - ( - 'warning', 61, - 'Attribute "one" is duplicated', 'fluent' - ), - ) - ) - - -class TestMessageReference(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = REFERENCE - - def test_msg_attr(self): - self._test( - b'''msg-attr-ref = Nice {button.label}''', - tuple() - ) - self._test( - b'''msg-attr-ref = not at all''', - ( - ( - 'warning', 0, - 'Missing message reference: button.label', 'fluent' - ), - ) - ) - self._test( - b'''msg-attr-ref = {button} is not a label''', - ( - ( - 'warning', 0, - 'Missing message reference: button.label', 'fluent' - ), - ( - 'warning', 16, - 'Obsolete message reference: button', 'fluent' - ), - ) - ) - self._test( - b'''msg-attr-ref = {button.tooltip} is not a label''', - ( - ( - 'warning', 0, - 'Missing message reference: button.label', 'fluent' - ), - ( - 'warning', 16, - 'Obsolete message reference: button.tooltip', 'fluent' - ), - ) - ) - - -class TestTermReference(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = REFERENCE - - def test_good_term_ref(self): - self._test( - dedent_ftl('''\ - term_ref = localized to {-term} - .attr = is plain - '''), - tuple() - ) - - def test_missing_term_ref(self): - self._test( - dedent_ftl('''\ - term_ref = localized - .attr = should not refer to {-term} - '''), - ( - ( - 'warning', 0, - 'Missing term reference: -term', 'fluent' - ), - ( - 'warning', 54, - 'Obsolete term reference: -term', 'fluent' - ), - ) - ) - - def test_l10n_only_term_ref(self): - self._test( - b'''simple = localized with { -term }''', - ( - ( - u'warning', 26, - u'Obsolete term reference: -term', u'fluent' - ), - ) - ) - - def test_term_attr(self): - self._test( - dedent_ftl('''\ - term_ref = Depends on { -term.prop -> - *[some] Term prop, doesn't reference the term value, though. - } - .attr = still simple - '''), - ( - ( - u'warning', 0, - u'Missing term reference: -term', u'fluent' - ), - ) - ) - - -class SelectExpressionTest(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = b'''\ -msg = { $val -> - *[other] Show something - } --term = Foopy -''' - - def test_no_select(self): - self._test( - b'''msg = Something''', - tuple() - ) - - def test_good(self): - self._test( - dedent_ftl('''\ - msg = { $val -> - *[one] one - [other] other - } - '''), - tuple() - ) - - def test_duplicate_variant(self): - self._test( - dedent_ftl('''\ - msg = { $val -> - *[one] one - [one] other - } - '''), - ( - ( - 'warning', 19, - 'Variant key "one" is duplicated', 'fluent' - ), - ( - 'warning', 31, - 'Variant key "one" is duplicated', 'fluent' - ), - ) - ) - - def test_term_value(self): - self._test( - dedent_ftl('''\ - -term = { PLATFORM() -> - *[one] one - [two] two - [two] duplicate - } - '''), - ( - ( - 'warning', 39, - 'Variant key "two" is duplicated', 'fluent' - ), - ( - 'warning', 51, - 'Variant key "two" is duplicated', 'fluent' - ), - ) - ) - - def test_term_attribute(self): - self._test( - dedent_ftl('''\ - -term = boring value - .attr = { PLATFORM() -> - *[one] one - [two] two - [two] duplicate - [two] three - } - '''), - ( - ( - 'warning', 66, - 'Variant key "two" is duplicated', 'fluent' - ), - ( - 'warning', 80, - 'Variant key "two" is duplicated', 'fluent' - ), - ( - 'warning', 100, - 'Variant key "two" is duplicated', 'fluent' - ), - ) - ) - - -class PluralTest(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = b'''\ -msg = { $val -> - *[other] Show something - } -''' - - def test_missing_plural(self): - self.file.locale = 'ru' - self._test( - dedent_ftl('''\ - msg = { $val -> - [one] thing - [3] is ok - *[many] stuff - } - '''), - ( - ( - 'warning', 19, - 'Plural categories missing: few', 'fluent' - ), - ) - ) - - def test_ignoring_other(self): - self.file.locale = 'de' - self._test( - dedent_ftl('''\ - msg = { $val -> - [1] thing - *[other] stuff - } - '''), - tuple() - ) - - -class CSSStyleTest(BaseHelper): - file = File('foo.ftl', 'foo.ftl') - refContent = b'''\ -simple = - .style = width:1px -select = - .style = {PLATFORM() -> - [windows] width:1px - *[unix] max-width:1px - } -ref = - .style = {simple.style} -broken = - .style = 28em -''' - - def test_simple(self): - self._test(dedent_ftl( - '''\ - simple = - .style = width:2px - '''), - tuple()) - self._test(dedent_ftl( - '''\ - simple = - .style = max-width:2px - '''), - ( - ( - 'warning', 0, - 'width only in reference, max-width only in l10n', 'fluent' - ), - )) - self._test(dedent_ftl( - '''\ - simple = - .style = stuff - '''), - ( - ( - 'error', 0, - 'reference is a CSS spec', 'fluent' - ), - )) - # Cover the current limitations of only plain strings - self._test(dedent_ftl( - '''\ - simple = - .style = {"width:3px"} - '''), - tuple()) - - def test_select(self): - self._test(dedent_ftl( - '''\ - select = - .style = width:2px - '''), - ( - ( - 'warning', 0, - 'width only in l10n', 'fluent' - ), - )) - self._test(dedent_ftl( - '''\ - select = - .style = max-width:2px - '''), - ( - ( - 'warning', 0, - 'max-width only in l10n', 'fluent' - ), - )) - self._test(dedent_ftl( - '''\ - select = - .style = stuff - '''), - ( - ( - 'error', 0, - 'reference is a CSS spec', 'fluent' - ), - )) - # Cover the current limitations of only plain strings - self._test(dedent_ftl( - '''\ - select = - .style = {"width:1px"} - '''), - tuple()) - - def test_ref(self): - self._test(dedent_ftl( - '''\ - ref = - .style = width:2px - '''), - ( - ( - 'warning', 0, - 'width only in l10n', 'fluent' - ), - ( - 'warning', 0, - 'Missing message reference: simple.style', 'fluent' - ), - )) - self._test(dedent_ftl( - '''\ - ref = - .style = max-width:2px - '''), - ( - ( - 'warning', 0, - 'max-width only in l10n', 'fluent' - ), - ( - 'warning', 0, - 'Missing message reference: simple.style', 'fluent' - ), - )) - self._test(dedent_ftl( - '''\ - ref = - .style = stuff - '''), - ( - ( - 'error', 0, - 'reference is a CSS spec', 'fluent' - ), - ( - 'warning', 0, - 'Missing message reference: simple.style', 'fluent' - ), - )) - # Cover the current limitations of only plain strings - self._test(dedent_ftl( - '''\ - ref = - .style = {"width:1px"} - '''), - ( - ( - 'warning', 0, - 'Missing message reference: simple.style', 'fluent' - ), - )) - - def test_broken(self): - self._test(dedent_ftl( - '''\ - broken = - .style = 27em - '''), - (('error', 0, 'reference is a CSS spec', 'fluent'),)) - self._test(dedent_ftl( - '''\ - broken = - .style = width: 27em - '''), - ( - ( - 'warning', 0, - 'width only in l10n', 'fluent' - ), - )) - - -if __name__ == '__main__': - unittest.main() diff --git a/third_party/python/compare-locales/compare_locales/tests/fluent/test_merge.py b/third_party/python/compare-locales/compare_locales/tests/fluent/test_merge.py deleted file mode 100644 index 41e69eca3eac..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/fluent/test_merge.py +++ /dev/null @@ -1,283 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMergeFluent(unittest.TestCase): - name = "foo.ftl" - - def test_no_changes(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_attribute_in_first(self): - channels = (b""" -foo = Foo 1 - .attr = Attr 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - .attr = Attr 1 -""") - - def test_attribute_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 - .attr = Attr 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_junk_in_first(self): - channels = (b"""\ -line of junk -""", b"""\ -one = entry -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode('utf-8'), - """\ -one = entry -line of junk -""" - ) - - def test_junk_in_last(self): - channels = (b"""\ -one = entry -""", b"""\ -line of junk -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode('utf-8'), - """\ -line of junk -one = entry -""" - ) - - def test_attribute_changed(self): - channels = (b""" -foo = Foo 1 - .attr = Attr 1 -""", b""" -foo = Foo 2 - .attr = Attr 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - .attr = Attr 1 -""") - - def test_group_comment_in_first(self): - channels = (b""" -## Group Comment 1 -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -## Group Comment 1 -foo = Foo 1 -""") - - def test_group_comment_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -## Group Comment 2 -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -## Group Comment 2 -foo = Foo 1 -""") - - def test_group_comment_changed(self): - channels = (b""" -## Group Comment 1 -foo = Foo 1 -""", b""" -## Group Comment 2 -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -## Group Comment 2 -## Group Comment 1 -foo = Foo 1 -""") - - def test_group_comment_and_section(self): - channels = (b""" -## Group Comment -foo = Foo 1 -""", b""" -// Section Comment -[[ Section ]] -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -// Section Comment -[[ Section ]] -## Group Comment -foo = Foo 1 -""") - - def test_message_comment_in_first(self): - channels = (b""" -# Comment 1 -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -# Comment 1 -foo = Foo 1 -""") - - def test_message_comment_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -# Comment 2 -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_message_comment_changed(self): - channels = (b""" -# Comment 1 -foo = Foo 1 -""", b""" -# Comment 2 -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -# Comment 1 -foo = Foo 1 -""") - - def test_standalone_comment_in_first(self): - channels = (b""" -foo = Foo 1 - -# Comment 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - -# Comment 1 -""") - - def test_standalone_comment_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 - -# Comment 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - -# Comment 2 -""") - - def test_standalone_comment_changed(self): - channels = (b""" -foo = Foo 1 - -# Comment 1 -""", b""" -foo = Foo 2 - -# Comment 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - -# Comment 2 - -# Comment 1 -""") - - def test_resource_comment_in_first(self): - channels = (b""" -### Resource Comment 1 - -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -### Resource Comment 1 - -foo = Foo 1 -""") - - def test_resource_comment_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -### Resource Comment 1 - -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -### Resource Comment 1 - -foo = Foo 1 -""") - - def test_resource_comment_changed(self): - channels = (b""" -### Resource Comment 1 - -foo = Foo 1 -""", b""" -### Resource Comment 2 - -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -### Resource Comment 2 - -### Resource Comment 1 - -foo = Foo 1 -""") diff --git a/third_party/python/compare-locales/compare_locales/tests/fluent/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/fluent/test_parser.py deleted file mode 100644 index db767fd5e2cf..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/fluent/test_parser.py +++ /dev/null @@ -1,310 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales import parser -from compare_locales.tests import ParserTestMixin - - -class TestFluentParser(ParserTestMixin, unittest.TestCase): - maxDiff = None - filename = 'foo.ftl' - - def test_equality_same(self): - source = b'progress = Progress: { NUMBER($num, style: "percent") }.' - - self.parser.readContents(source) - [ent1] = list(self.parser) - - self.parser.readContents(source) - [ent2] = list(self.parser) - - self.assertTrue(ent1.equals(ent2)) - self.assertTrue(ent1.localized) - - def test_equality_different_whitespace(self): - source1 = b'foo = { $arg }' - source2 = b'foo = { $arg }' - - self.parser.readContents(source1) - [ent1] = list(self.parser) - - self.parser.readContents(source2) - [ent2] = list(self.parser) - - self.assertTrue(ent1.equals(ent2)) - - def test_word_count(self): - self.parser.readContents(b'''\ -a = One -b = One two three -c = One { $arg } two -d = - One { $arg -> - *[x] Two three - [y] Four - } five. -e = - .attr = One -f = - .attr1 = One - .attr2 = Two -g = One two - .attr = Three -h = - One { $arg -> - *[x] Two three - [y] Four - } five. - .attr1 = - Six { $arg -> - *[x] Seven eight - [y] Nine - } ten. --i = One - .prop = Do not count -''') - - a, b, c, d, e, f, g, h, i = list(self.parser) - self.assertEqual(a.count_words(), 1) - self.assertEqual(b.count_words(), 3) - self.assertEqual(c.count_words(), 2) - self.assertEqual(d.count_words(), 5) - self.assertEqual(e.count_words(), 1) - self.assertEqual(f.count_words(), 2) - self.assertEqual(g.count_words(), 3) - self.assertEqual(h.count_words(), 10) - self.assertEqual(i.count_words(), 1) - - def test_simple_message(self): - self.parser.readContents(b'a = A') - - [a] = list(self.parser) - self.assertEqual(a.key, 'a') - self.assertEqual(a.raw_val, 'A') - self.assertEqual(a.all, 'a = A') - attributes = list(a.attributes) - self.assertEqual(len(attributes), 0) - - def test_complex_message(self): - self.parser.readContents(b'abc = A { $arg } B { msg } C') - - [abc] = list(self.parser) - self.assertEqual(abc.key, 'abc') - self.assertEqual(abc.raw_val, 'A { $arg } B { msg } C') - self.assertEqual(abc.all, 'abc = A { $arg } B { msg } C') - - def test_multiline_message(self): - self.parser.readContents(b'''\ -abc = - A - B - C -''') - - [abc] = list(self.parser) - self.assertEqual(abc.key, 'abc') - self.assertEqual(abc.raw_val, ' A\n B\n C') - self.assertEqual(abc.all, 'abc =\n A\n B\n C') - - def test_message_with_attribute(self): - self.parser.readContents(b'''\ - - -abc = ABC - .attr = Attr -''') - - [abc] = list(self.parser) - self.assertEqual(abc.key, 'abc') - self.assertEqual(abc.raw_val, 'ABC') - self.assertEqual(abc.all, 'abc = ABC\n .attr = Attr') - self.assertEqual(abc.position(), (3, 1)) - self.assertEqual(abc.value_position(), (3, 7)) - attr = list(abc.attributes)[0] - self.assertEqual(attr.value_position(), (4, 13)) - - def test_message_with_attribute_and_no_value(self): - self.parser.readContents(b'''\ -abc = - .attr = Attr -''') - - [abc] = list(self.parser) - self.assertEqual(abc.key, 'abc') - self.assertEqual(abc.raw_val, None) - self.assertEqual(abc.all, 'abc =\n .attr = Attr') - attributes = list(abc.attributes) - self.assertEqual(len(attributes), 1) - attr = attributes[0] - self.assertEqual(attr.key, 'attr') - self.assertEqual(attr.raw_val, 'Attr') - self.assertEqual(abc.value_position(), (1, 4)) - self.assertEqual(attr.value_position(), (2, 13)) - - def test_non_localizable(self): - self.parser.readContents(b'''\ -### Resource Comment - -foo = Foo - -## Group Comment - --bar = Bar - -## - -# Standalone Comment - -# Baz Comment -baz = Baz -''') - entities = self.parser.walk() - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentComment)) - self.assertEqual(entity.all, '### Resource Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentMessage)) - self.assertEqual(entity.raw_val, 'Foo') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentComment)) - self.assertEqual(entity.all, '## Group Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentTerm)) - self.assertEqual(entity.raw_val, 'Bar') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentComment)) - self.assertEqual(entity.all, '##') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentComment)) - self.assertEqual(entity.all, '# Standalone Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentMessage)) - self.assertEqual(entity.raw_val, 'Baz') - self.assertEqual(entity.entry.comment.content, 'Baz Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n') - - with self.assertRaises(StopIteration): - next(entities) - - def test_comments_val(self): - self.parser.readContents(b'''\ -// Legacy Comment - -### Resource Comment - -## Section Comment - -# Standalone Comment -''') - entities = self.parser.walk() - - entity = next(entities) - # ensure that fluent comments are FluentComments and Comments - # Legacy comments (//) are Junk - self.assertTrue(isinstance(entity, parser.Junk)) - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Comment)) - self.assertEqual(entity.val, 'Resource Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Comment)) - self.assertEqual(entity.val, 'Section Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Comment)) - self.assertEqual(entity.val, 'Standalone Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.all, '\n') - - with self.assertRaises(StopIteration): - next(entities) - - def test_junk(self): - self.parser.readUnicode('''\ -# Comment - -Line of junk - -# Comment -msg = value -''') - entities = self.parser.walk() - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentComment)) - self.assertEqual(entity.val, 'Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.raw_val, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Junk)) - self.assertEqual(entity.raw_val, 'Line of junk') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.raw_val, '\n\n') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.FluentEntity)) - self.assertEqual(entity.raw_val, 'value') - self.assertEqual(entity.entry.comment.content, 'Comment') - - entity = next(entities) - self.assertTrue(isinstance(entity, parser.Whitespace)) - self.assertEqual(entity.raw_val, '\n') - - with self.assertRaises(StopIteration): - next(entities) diff --git a/third_party/python/compare-locales/compare_locales/tests/lint/__init__.py b/third_party/python/compare-locales/compare_locales/tests/lint/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/compare-locales/compare_locales/tests/lint/test_linter.py b/third_party/python/compare-locales/compare_locales/tests/lint/test_linter.py deleted file mode 100644 index 9abdc57c0835..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/lint/test_linter.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales.lint import linter -from compare_locales.parser import base as parser - - -class MockChecker(object): - def __init__(self, mocked): - self.results = mocked - - def check(self, ent, ref): - for r in self.results: - yield r - - -class EntityTest(unittest.TestCase): - def test_junk(self): - el = linter.EntityLinter([], None, {}) - ctx = parser.Parser.Context('foo\nbar\n') - ent = parser.Junk(ctx, (4, 7)) - res = el.handle_junk(ent) - self.assertIsNotNone(res) - self.assertEqual(res['lineno'], 2) - self.assertEqual(res['column'], 1) - ent = parser.LiteralEntity('one', 'two', 'one = two') - self.assertIsNone(el.handle_junk(ent)) - - def test_full_entity(self): - ctx = parser.Parser.Context('''\ -one = two -two = three -one = four -''') - entities = [ - parser.Entity(ctx, None, None, (0, 10), (0, 3), (6, 9)), - parser.Entity(ctx, None, None, (10, 22), (10, 13), (16, 21)), - parser.Entity(ctx, None, None, (22, 33), (22, 25), (28, 32)), - ] - self.assertEqual( - (entities[0].all, entities[0].key, entities[0].val), - ('one = two\n', 'one', 'two') - ) - self.assertEqual( - (entities[1].all, entities[1].key, entities[1].val), - ('two = three\n', 'two', 'three') - ) - self.assertEqual( - (entities[2].all, entities[2].key, entities[2].val), - ('one = four\n', 'one', 'four') - ) - el = linter.EntityLinter(entities, None, {}) - results = list(el.lint_full_entity(entities[1])) - self.assertListEqual(results, []) - results = list(el.lint_full_entity(entities[2])) - self.assertEqual(len(results), 1) - result = results[0] - self.assertEqual(result['level'], 'error') - self.assertEqual(result['lineno'], 3) - self.assertEqual(result['column'], 1) - # finally check for conflict - el.reference = { - 'two': parser.LiteralEntity('two = other', 'two', 'other') - } - results = list(el.lint_full_entity(entities[1])) - self.assertEqual(len(results), 1) - result = results[0] - self.assertEqual(result['level'], 'warning') - self.assertEqual(result['lineno'], 2) - self.assertEqual(result['column'], 1) - - def test_in_value(self): - ctx = parser.Parser.Context('''\ -one = two -''') - entities = [ - parser.Entity(ctx, None, None, (0, 10), (0, 3), (6, 9)), - ] - self.assertEqual( - (entities[0].all, entities[0].key, entities[0].val), - ('one = two\n', 'one', 'two') - ) - checker = MockChecker([ - ('error', 2, 'Incompatible resource types', 'android'), - ]) - el = linter.EntityLinter(entities, checker, {}) - results = list(el.lint_value(entities[0])) - self.assertEqual(len(results), 1) - result = results[0] - self.assertEqual(result['level'], 'error') - self.assertEqual(result['lineno'], 1) - self.assertEqual(result['column'], 9) diff --git a/third_party/python/compare-locales/compare_locales/tests/lint/test_util.py b/third_party/python/compare-locales/compare_locales/tests/lint/test_util.py deleted file mode 100644 index 2a8d30bf2a7d..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/lint/test_util.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import - -import unittest - -from compare_locales.lint import util -from compare_locales.paths.project import ProjectConfig -from compare_locales.paths.files import ProjectFiles -from compare_locales import mozpath - - -class MirrorReferenceTest(unittest.TestCase): - def test_empty(self): - files = ProjectFiles(None, []) - get_reference_and_tests = util.mirror_reference_and_tests(files, 'tld') - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertIsNone(ref) - self.assertIsNone(tests) - - def test_no_tests(self): - pc = ProjectConfig(None) - pc.add_paths({ - 'reference': 'some/path/file.ftl', - 'l10n': 'some/{locale}/file.ftl', - }) - files = ProjectFiles(None, [pc]) - get_reference_and_tests = util.mirror_reference_and_tests(files, 'tld') - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertEqual(mozpath.relpath(ref, 'tld'), 'some/path/file.ftl') - self.assertEqual(tests, set()) - - def test_with_tests(self): - pc = ProjectConfig(None) - pc.add_paths({ - 'reference': 'some/path/file.ftl', - 'l10n': 'some/{locale}/file.ftl', - 'test': ['more_stuff'], - }) - files = ProjectFiles(None, [pc]) - get_reference_and_tests = util.mirror_reference_and_tests(files, 'tld') - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertEqual(mozpath.relpath(ref, 'tld'), 'some/path/file.ftl') - self.assertEqual(tests, {'more_stuff'}) - - -class L10nBaseReferenceTest(unittest.TestCase): - def test_empty(self): - files = ProjectFiles(None, []) - get_reference_and_tests = util.l10n_base_reference_and_tests(files) - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertIsNone(ref) - self.assertIsNone(tests) - - def test_no_tests(self): - pc = ProjectConfig(None) - pc.add_environment(l10n_base='l10n_orig') - pc.add_paths({ - 'reference': 'some/path/file.ftl', - 'l10n': '{l10n_base}/{locale}/some/file.ftl', - }) - pc.set_locales(['gecko'], deep=True) - files = ProjectFiles('gecko', [pc]) - get_reference_and_tests = util.l10n_base_reference_and_tests(files) - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertEqual( - mozpath.relpath(ref, 'l10n_orig/gecko'), - 'some/file.ftl' - ) - self.assertEqual(tests, set()) - - def test_with_tests(self): - pc = ProjectConfig(None) - pc.add_environment(l10n_base='l10n_orig') - pc.add_paths({ - 'reference': 'some/path/file.ftl', - 'l10n': '{l10n_base}/{locale}/some/file.ftl', - 'test': ['more_stuff'], - }) - pc.set_locales(['gecko'], deep=True) - files = ProjectFiles('gecko', [pc]) - get_reference_and_tests = util.l10n_base_reference_and_tests(files) - ref, tests = get_reference_and_tests('some/path/file.ftl') - self.assertEqual( - mozpath.relpath(ref, 'l10n_orig/gecko'), - 'some/file.ftl' - ) - self.assertEqual(tests, {'more_stuff'}) diff --git a/third_party/python/compare-locales/compare_locales/tests/merge/__init__.py b/third_party/python/compare-locales/compare_locales/tests/merge/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/compare-locales/compare_locales/tests/merge/test_comments.py b/third_party/python/compare-locales/compare_locales/tests/merge/test_comments.py deleted file mode 100644 index 71241c8768cf..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/merge/test_comments.py +++ /dev/null @@ -1,188 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMergeComments(unittest.TestCase): - name = "foo.properties" - - def test_comment_added_in_first(self): - channels = (b""" -foo = Foo 1 -# Bar Comment 1 -bar = Bar 1 -""", b""" -foo = Foo 2 -bar = Bar 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -foo = Foo 1 -# Bar Comment 1 -bar = Bar 1 -""") - - def test_comment_still_in_last(self): - channels = (b""" -foo = Foo 1 -bar = Bar 1 -""", b""" -foo = Foo 2 -# Bar Comment 2 -bar = Bar 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -foo = Foo 1 -bar = Bar 1 -""") - - def test_comment_changed(self): - channels = (b""" -foo = Foo 1 -# Bar Comment 1 -bar = Bar 1 -""", b""" -foo = Foo 2 -# Bar Comment 2 -bar = Bar 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -foo = Foo 1 -# Bar Comment 1 -bar = Bar 1 -""") - - -class TestMergeStandaloneComments(unittest.TestCase): - name = "foo.properties" - - def test_comment_added_in_first(self): - channels = (b""" -# Standalone Comment 1 - -# Foo Comment 1 -foo = Foo 1 -""", b""" -# Foo Comment 2 -foo = Foo 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Standalone Comment 1 - -# Foo Comment 1 -foo = Foo 1 -""") - - def test_comment_still_in_last(self): - channels = (b""" -# Foo Comment 1 -foo = Foo 1 -""", b""" -# Standalone Comment 2 - -# Foo Comment 2 -foo = Foo 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Standalone Comment 2 - -# Foo Comment 1 -foo = Foo 1 -""") - - def test_comments_in_both(self): - channels = (b""" -# Standalone Comment 1 - -# Foo Comment 1 -foo = Foo 1 -""", b""" -# Standalone Comment 2 - -# Foo Comment 2 -foo = Foo 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Standalone Comment 2 - -# Standalone Comment 1 - -# Foo Comment 1 -foo = Foo 1 -""") - - def test_identical_comments_in_both(self): - channels = (b""" -# Standalone Comment - -# Foo Comment 1 -foo = Foo 1 -""", b""" -# Standalone Comment - -# Foo Comment 2 -foo = Foo 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Standalone Comment - -# Foo Comment 1 -foo = Foo 1 -""") - - def test_standalone_which_is_attached_in_first(self): - channels = (b""" -# Ambiguous Comment -foo = Foo 1 - -# Bar Comment 1 -bar = Bar 1 -""", b""" -# Ambiguous Comment - -# Bar Comment 2 -bar = Bar 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Ambiguous Comment - -# Ambiguous Comment -foo = Foo 1 - -# Bar Comment 1 -bar = Bar 1 -""") - - def test_standalone_which_is_attached_in_second(self): - channels = (b""" -# Ambiguous Comment - -# Bar Comment 1 -bar = Bar 1 -""", b""" -# Ambiguous Comment -foo = Foo 1 - -# Bar Comment 2 -bar = Bar 2 -""") - self.assertMultiLineEqual( - merge_channels(self.name, channels).decode("utf-8"), """ -# Ambiguous Comment -foo = Foo 1 - -# Ambiguous Comment - -# Bar Comment 1 -bar = Bar 1 -""") diff --git a/third_party/python/compare-locales/compare_locales/tests/merge/test_messages.py b/third_party/python/compare-locales/compare_locales/tests/merge/test_messages.py deleted file mode 100644 index 664bbd16c591..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/merge/test_messages.py +++ /dev/null @@ -1,93 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMergeTwo(unittest.TestCase): - name = "foo.properties" - - def test_no_changes(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_message_added_in_first(self): - channels = (b""" -foo = Foo 1 -bar = Bar 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -bar = Bar 1 -""") - - def test_message_still_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -bar = Bar 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -bar = Bar 2 -""") - - def test_message_reordered(self): - channels = (b""" -foo = Foo 1 -bar = Bar 1 -""", b""" -bar = Bar 2 -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -bar = Bar 1 -""") - - -class TestMergeThree(unittest.TestCase): - name = "foo.properties" - - def test_no_changes(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""", b""" -foo = Foo 3 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_message_still_in_last(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""", b""" -foo = Foo 3 -bar = Bar 3 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -bar = Bar 3 -""") diff --git a/third_party/python/compare-locales/compare_locales/tests/merge/test_unknown.py b/third_party/python/compare-locales/compare_locales/tests/merge/test_unknown.py deleted file mode 100644 index ce74e1a10b85..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/merge/test_unknown.py +++ /dev/null @@ -1,22 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -import six - -from compare_locales.merge import merge_channels, MergeNotSupportedError - - -class TestMergeUnknown(unittest.TestCase): - name = "foo.unknown" - - def test_not_supported_error(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - pattern = r"Unsupported file format \(foo\.unknown\)\." - with six.assertRaisesRegex(self, MergeNotSupportedError, pattern): - merge_channels(self.name, channels) diff --git a/third_party/python/compare-locales/compare_locales/tests/merge/test_whitespace.py b/third_party/python/compare-locales/compare_locales/tests/merge/test_whitespace.py deleted file mode 100644 index adaedc70d1b9..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/merge/test_whitespace.py +++ /dev/null @@ -1,76 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest -from compare_locales.merge import merge_channels - - -class TestMergeWhitespace(unittest.TestCase): - name = "foo.properties" - - def test_trailing_spaces(self): - channels = (b""" -foo = Foo 1 - """, b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - """) - - def test_blank_lines_between_messages(self): - channels = (b""" -foo = Foo 1 - -bar = Bar 1 -""", b""" -foo = Foo 2 -bar = Bar 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 - -bar = Bar 1 -""") - - def test_no_eol(self): - channels = (b""" -foo = Foo 1""", b""" -foo = Foo 2 -bar = Bar 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -bar = Bar 2 -""") - - def test_still_in_last_with_blank(self): - channels = (b""" - -foo = Foo 1 - -baz = Baz 1 - -""", b""" - -foo = Foo 2 - -bar = Bar 2 - -baz = Baz 2 - -""") - self.assertEqual( - merge_channels(self.name, channels), b""" - -foo = Foo 1 - -bar = Bar 2 - -baz = Baz 1 - -""") diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/__init__.py b/third_party/python/compare-locales/compare_locales/tests/paths/__init__.py deleted file mode 100644 index 1a99c53e2f2e..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/__init__.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import - -from collections import defaultdict -import six -import tempfile -from compare_locales.paths import ( - ProjectConfig, File, ProjectFiles, TOMLParser -) -from compare_locales import mozpath -import pytoml as toml - - -class Rooted(object): - def setUp(self): - # Use tempdir as self.root, that's absolute on all platforms - self.root = mozpath.normpath(tempfile.gettempdir()) - - def path(self, leaf=''): - return self.root + leaf - - def leaf(self, path): - return mozpath.relpath(path, self.root) - - -class SetupMixin(object): - def setUp(self): - self.cfg = ProjectConfig(None) - self.file = File( - '/tmp/somedir/de/browser/one/two/file.ftl', - 'file.ftl', - module='browser', locale='de') - self.other_file = File( - '/tmp/somedir/de/toolkit/two/one/file.ftl', - 'file.ftl', - module='toolkit', locale='de') - self.cfg.set_locales(['de']) - - -class MockOS(object): - '''Mock `os.path.isfile` and `os.walk` based on a list of files. - ''' - def __init__(self, root, paths): - self.root = root - self.files = [] - self.dirs = {} - if not paths: - return - if isinstance(paths[0], six.string_types): - paths = [ - mozpath.split(path) - for path in sorted(paths) - ] - child_paths = defaultdict(list) - for segs in paths: - if len(segs) == 1: - self.files.append(segs[0]) - else: - child_paths[segs[0]].append(segs[1:]) - for root, leafs in child_paths.items(): - self.dirs[root] = MockOS(mozpath.join(self.root, root), leafs) - - def find(self, dir_path): - relpath = mozpath.relpath(dir_path, self.root) - if relpath.startswith('..'): - return None - if relpath in ('', '.'): - return self - segs = mozpath.split(relpath) - node = self - while segs: - seg = segs.pop(0) - if seg not in node.dirs: - return None - node = node.dirs[seg] - return node - - def isfile(self, path): - dirname = mozpath.dirname(path) - if dirname: - node = self.find(dirname) - else: - node = self - return node and mozpath.basename(path) in node.files - - def walk(self, path=None): - if path is None: - node = self - else: - node = self.find(path) - if node is None: - return - subdirs = sorted(node.dirs) - if node.root is not None: - yield node.root, subdirs, node.files - for subdir in subdirs: - child = node.dirs[subdir] - for tpl in child.walk(): - yield tpl - - -class MockProjectFiles(ProjectFiles): - def __init__(self, mocks, locale, projects, mergebase=None): - (super(MockProjectFiles, self) - .__init__(locale, projects, mergebase=mergebase)) - root = mozpath.commonprefix(mocks) - files = [mozpath.relpath(f, root) for f in mocks] - self.mocks = MockOS(root, files) - - def _isfile(self, path): - return self.mocks.isfile(path) - - def _walk(self, base): - base = mozpath.normpath(base) - root = self.mocks.find(base) - if not root: - return - for tpl in root.walk(): - yield tpl - - -class MockTOMLParser(TOMLParser): - def __init__(self, mock_data): - self.mock_data = mock_data - - def load(self, ctx): - p = mozpath.basename(ctx.path) - ctx.data = toml.loads(self.mock_data[p]) diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_configparser.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_configparser.py deleted file mode 100644 index fe9d7dcf6eca..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_configparser.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import, unicode_literals -import unittest -import six - -from . import MockTOMLParser -from compare_locales.paths.matcher import Matcher -from compare_locales.paths.project import ProjectConfig, ExcludeError -from compare_locales import mozpath - - -class TestConfigParser(unittest.TestCase): - def test_includes(self): - parser = MockTOMLParser({ - "root.toml": """ -basepath = "." -[env] - o = "toolkit" -[[includes]] - path = "{o}/other.toml" -[[includes]] - path = "dom/more.toml" -""", - "other.toml": """ -basepath = "." -""", - "more.toml": """ -basepath = "." -""" - }) - config = parser.parse("root.toml") - self.assertIsInstance(config, ProjectConfig) - configs = list(config.configs) - self.assertEqual(configs[0], config) - self.assertListEqual( - [c.path for c in configs], - [ - "root.toml", - mozpath.abspath("toolkit/other.toml"), - mozpath.abspath("dom/more.toml"), - ] - ) - - def test_excludes(self): - parser = MockTOMLParser({ - "root.toml": """ -basepath = "." -[[excludes]] - path = "exclude.toml" -[[excludes]] - path = "other-exclude.toml" - """, - "exclude.toml": """ -basepath = "." -""", - "other-exclude.toml": """ -basepath = "." -""", - "grandparent.toml": """ -basepath = "." -[[includes]] - path = "root.toml" -""", - "wrapped.toml": """ -basepath = "." -[[excludes]] - path = "root.toml" - """ - }) - config = parser.parse("root.toml") - self.assertIsInstance(config, ProjectConfig) - configs = list(config.configs) - self.assertListEqual(configs, [config]) - self.assertEqual( - [c.path for c in config.excludes], - [ - mozpath.abspath("exclude.toml"), - mozpath.abspath("other-exclude.toml"), - ] - ) - with six.assertRaisesRegex(self, ExcludeError, 'Included configs'): - parser.parse("grandparent.toml") - with six.assertRaisesRegex(self, ExcludeError, 'Excluded configs'): - parser.parse("wrapped.toml") - - def test_paths(self): - parser = MockTOMLParser({ - "l10n.toml": """ -[[paths]] - l10n = "some/{locale}/*" -""", - "ref.toml": """ -[[paths]] - reference = "ref/l10n/*" - l10n = "some/{locale}/*" -""", - "tests.toml": """ -[[paths]] - l10n = "some/{locale}/*" - test = [ - "run_this", - ] -""", - }) - - paths = parser.parse("l10n.toml").paths - self.assertIn("l10n", paths[0]) - self.assertIsInstance(paths[0]["l10n"], Matcher) - self.assertNotIn("reference", paths[0]) - self.assertNotIn("test", paths[0]) - paths = parser.parse("ref.toml").paths - self.assertIn("l10n", paths[0]) - self.assertIsInstance(paths[0]["l10n"], Matcher) - self.assertIn("reference", paths[0]) - self.assertIsInstance(paths[0]["reference"], Matcher) - self.assertNotIn("test", paths[0]) - paths = parser.parse("tests.toml").paths - self.assertIn("l10n", paths[0]) - self.assertIsInstance(paths[0]["l10n"], Matcher) - self.assertNotIn("reference", paths[0]) - self.assertIn("test", paths[0]) - self.assertListEqual(paths[0]["test"], ["run_this"]) diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_files.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_files.py deleted file mode 100644 index 997d7d2ffc20..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_files.py +++ /dev/null @@ -1,572 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest -import mock - -from compare_locales.paths import ( - File, - ProjectConfig, - ProjectFiles, -) -from . import ( - MockOS, - MockProjectFiles, - MockTOMLParser, - Rooted, -) - - -class TestMockOS(Rooted, unittest.TestCase): - def setUp(self): - self.node = MockOS('jazz', [ - 'one/bit', - 'two/deep/in/directories/with/file1', - 'two/deep/in/directories/with/file2', - 'three/feet', - ]) - - def test_isfile(self): - self.assertTrue(self.node.isfile('jazz/one/bit')) - self.assertFalse(self.node.isfile('jazz/one')) - self.assertFalse(self.node.isfile('foo')) - - def test_walk(self): - self.assertListEqual( - list(self.node.walk()), - [ - ('jazz', ['one', 'three', 'two'], []), - ('jazz/one', [], ['bit']), - ('jazz/three', [], ['feet']), - ('jazz/two', ['deep'], []), - ('jazz/two/deep', ['in'], []), - ('jazz/two/deep/in', ['directories'], []), - ('jazz/two/deep/in/directories', ['with'], []), - ('jazz/two/deep/in/directories/with', [], [ - 'file1', - 'file2', - ]), - ] - ) - - def test_find(self): - self.assertIsNone(self.node.find('foo')) - self.assertIsNone(self.node.find('jazz/one/bit')) - self.assertIsNone(self.node.find('jazz/one/bit/too/much')) - self.assertIsNotNone(self.node.find('jazz/one')) - self.assertListEqual(list(self.node.find('jazz/one').walk()), [ - ('jazz/one', [], ['bit']), - ]) - self.assertEqual(self.node.find('jazz'), self.node) - - -class TestProjectPaths(Rooted, unittest.TestCase): - def test_l10n_path(self): - cfg = ProjectConfig(None) - cfg.add_environment(l10n_base=self.root) - cfg.set_locales(['de']) - cfg.add_paths({ - 'l10n': '{l10n_base}/{locale}/*' - }) - mocks = [ - self.path(leaf) - for leaf in ( - '/de/good.ftl', - '/de/not/subdir/bad.ftl', - '/fr/good.ftl', - '/fr/not/subdir/bad.ftl', - ) - ] - files = MockProjectFiles(mocks, 'de', [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/de/good.ftl'), None, None, set()) - ] - ) - self.assertTupleEqual( - files.match(self.path('/de/good.ftl')), - (self.path('/de/good.ftl'), None, None, set()) - ) - self.assertIsNone(files.match(self.path('/fr/something.ftl'))) - files = MockProjectFiles(mocks, 'de', [cfg], mergebase='merging') - self.assertListEqual( - list(files), - [ - (self.path('/de/good.ftl'), None, 'merging/de/good.ftl', set()) - ] - ) - self.assertTupleEqual( - files.match(self.path('/de/something.ftl')), - (self.path('/de/something.ftl'), - None, - 'merging/de/something.ftl', - set())) - # 'fr' is not in the locale list, should return no files - files = MockProjectFiles(mocks, 'fr', [cfg]) - self.assertListEqual(list(files), []) - - def test_single_reference_path(self): - cfg = ProjectConfig(None) - cfg.add_environment(l10n_base=self.path('/l10n')) - cfg.set_locales(['de']) - cfg.add_paths({ - 'l10n': '{l10n_base}/{locale}/good.ftl', - 'reference': self.path('/reference/good.ftl') - }) - mocks = [ - self.path('/reference/good.ftl'), - self.path('/reference/not/subdir/bad.ftl'), - ] - files = MockProjectFiles(mocks, 'de', [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - ]) - self.assertTupleEqual( - files.match(self.path('/reference/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - ) - self.assertTupleEqual( - files.match(self.path('/l10n/de/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - ) - - def test_reference_path(self): - cfg = ProjectConfig(None) - cfg.add_environment(l10n_base=self.path('/l10n')) - cfg.set_locales(['de']) - cfg.add_paths({ - 'l10n': '{l10n_base}/{locale}/*', - 'reference': self.path('/reference/*') - }) - mocks = [ - self.path(leaf) - for leaf in [ - '/l10n/de/good.ftl', - '/l10n/de/not/subdir/bad.ftl', - '/l10n/fr/good.ftl', - '/l10n/fr/not/subdir/bad.ftl', - '/reference/ref.ftl', - '/reference/not/subdir/bad.ftl', - ] - ] - files = MockProjectFiles(mocks, 'de', [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - (self.path('/l10n/de/ref.ftl'), - self.path('/reference/ref.ftl'), - None, - set()), - ]) - self.assertTupleEqual( - files.match(self.path('/l10n/de/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - ) - self.assertTupleEqual( - files.match(self.path('/reference/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - None, - set()), - ) - self.assertIsNone(files.match(self.path('/l10n/de/subdir/bad.ftl'))) - self.assertIsNone(files.match(self.path('/reference/subdir/bad.ftl'))) - files = MockProjectFiles(mocks, 'de', [cfg], mergebase='merging') - self.assertListEqual( - list(files), - [ - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - 'merging/de/good.ftl', set()), - (self.path('/l10n/de/ref.ftl'), - self.path('/reference/ref.ftl'), - 'merging/de/ref.ftl', set()), - ]) - self.assertTupleEqual( - files.match(self.path('/l10n/de/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - 'merging/de/good.ftl', set()), - ) - self.assertTupleEqual( - files.match(self.path('/reference/good.ftl')), - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - 'merging/de/good.ftl', set()), - ) - # 'fr' is not in the locale list, should return no files - files = MockProjectFiles(mocks, 'fr', [cfg]) - self.assertListEqual(list(files), []) - - def test_partial_l10n(self): - cfg = ProjectConfig(None) - cfg.set_locales(['de', 'fr']) - cfg.add_paths({ - 'l10n': self.path('/{locale}/major/*') - }, { - 'l10n': self.path('/{locale}/minor/*'), - 'locales': ['de'] - }) - mocks = [ - self.path(leaf) - for leaf in [ - '/de/major/good.ftl', - '/de/major/not/subdir/bad.ftl', - '/de/minor/good.ftl', - '/fr/major/good.ftl', - '/fr/major/not/subdir/bad.ftl', - '/fr/minor/good.ftl', - ] - ] - files = MockProjectFiles(mocks, 'de', [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/de/major/good.ftl'), None, None, set()), - (self.path('/de/minor/good.ftl'), None, None, set()), - ]) - self.assertTupleEqual( - files.match(self.path('/de/major/some.ftl')), - (self.path('/de/major/some.ftl'), None, None, set())) - self.assertIsNone(files.match(self.path('/de/other/some.ftl'))) - # 'fr' is not in the locale list of minor, should only return major - files = MockProjectFiles(mocks, 'fr', [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/fr/major/good.ftl'), None, None, set()), - ]) - self.assertIsNone(files.match(self.path('/fr/minor/some.ftl'))) - - def test_validation_mode(self): - cfg = ProjectConfig(None) - cfg.add_environment(l10n_base=self.path('/l10n')) - cfg.set_locales(['de']) - cfg.add_paths({ - 'l10n': '{l10n_base}/{locale}/*', - 'reference': self.path('/reference/*') - }) - mocks = [ - self.path(leaf) - for leaf in [ - '/l10n/de/good.ftl', - '/l10n/de/not/subdir/bad.ftl', - '/l10n/fr/good.ftl', - '/l10n/fr/not/subdir/bad.ftl', - '/reference/ref.ftl', - '/reference/not/subdir/bad.ftl', - ] - ] - # `None` switches on validation mode - files = MockProjectFiles(mocks, None, [cfg]) - self.assertListEqual( - list(files), - [ - (self.path('/reference/ref.ftl'), - self.path('/reference/ref.ftl'), - None, - set()), - ]) - - -@mock.patch('os.path.isfile') -@mock.patch('os.walk') -class TestExcludes(Rooted, unittest.TestCase): - def _list(self, locale, _walk, _isfile): - parser = MockTOMLParser({ - "pontoon.toml": - '''\ -basepath = "." - -[[includes]] - path = "configs-pontoon.toml" - -[[excludes]] - path = "configs-vendor.toml" -[[excludes]] - path = "configs-special-templates.toml" -''', - "vendor.toml": - '''\ -basepath = "." - -[[includes]] - path = "configs-vendor.toml" - -[[excludes]] - path = "configs-special-templates.toml" -''', - "configs-pontoon.toml": - '''\ -basepath = "." - -locales = [ - "de", - "gd", - "it", -] - -[[paths]] - reference = "en/**/*.ftl" - l10n = "{locale}/**/*.ftl" -''', - "configs-vendor.toml": - '''\ -basepath = "." - -locales = [ - "de", - "it", -] - -[[paths]] - reference = "en/firefox/*.ftl" - l10n = "{locale}/firefox/*.ftl" -''', - "configs-special-templates.toml": - '''\ -basepath = "." - -[[paths]] - reference = "en/firefox/home.ftl" - l10n = "{locale}/firefox/home.ftl" - locales = [ - "de", - "fr", - ] -[[paths]] - reference = "en/firefox/pagina.ftl" - l10n = "{locale}/firefox/pagina.ftl" - locales = [ - "gd", - ] -''', - }) - pontoon = parser.parse(self.path('/pontoon.toml')) - vendor = parser.parse(self.path('/vendor.toml')) - pc = ProjectFiles(locale, [pontoon, vendor]) - mock_files = [ - '{}/{}/{}'.format(locale, dir, f) - for locale in ('de', 'en', 'gd', 'it') - for dir, files in ( - ('firefox', ('home.ftl', 'feature.ftl')), - ('mozorg', ('mission.ftl',)), - ) - for f in files - ] - os_ = MockOS(self.root, mock_files) - _isfile.side_effect = os_.isfile - _walk.side_effect = os_.walk - local_files = [self.leaf(p).split('/', 1)[1] for p, _, _, _ in pc] - return pontoon, vendor, local_files - - def test_reference(self, _walk, _isfile): - pontoon_config, vendor_config, files = self._list(None, _walk, _isfile) - pontoon_files = ProjectFiles(None, [pontoon_config]) - vendor_files = ProjectFiles(None, [vendor_config]) - self.assertListEqual( - files, - [ - 'firefox/feature.ftl', - 'firefox/home.ftl', - 'mozorg/mission.ftl', - ] - ) - ref_path = self.path('/en/firefox/feature.ftl') - self.assertIsNotNone(pontoon_files.match(ref_path)) - self.assertIsNotNone(vendor_files.match(ref_path)) - ref_path = self.path('/en/firefox/home.ftl') - self.assertIsNotNone(pontoon_files.match(ref_path)) - self.assertIsNotNone(vendor_files.match(ref_path)) - ref_path = self.path('/en/mozorg/mission.ftl') - self.assertIsNotNone(pontoon_files.match(ref_path)) - self.assertIsNone(vendor_files.match(ref_path)) - - def test_de(self, _walk, _isfile): - # home.ftl excluded completely by configs-special-templates.toml - # firefox/* only in vendor - pontoon_config, vendor_config, files = self._list('de', _walk, _isfile) - pontoon_files = ProjectFiles('de', [pontoon_config]) - vendor_files = ProjectFiles('de', [vendor_config]) - self.assertListEqual( - files, - [ - 'firefox/feature.ftl', - # 'firefox/home.ftl', - 'mozorg/mission.ftl', - ] - ) - l10n_path = self.path('/de/firefox/feature.ftl') - ref_path = self.path('/en/firefox/feature.ftl') - self.assertEqual( - pontoon_config.filter( - File( - l10n_path, - 'de/firefox/feature.ftl', - locale='de' - ) - ), - 'ignore' - ) - self.assertIsNone(pontoon_files.match(l10n_path)) - self.assertIsNone(pontoon_files.match(ref_path)) - self.assertIsNotNone(vendor_files.match(l10n_path)) - self.assertIsNotNone(vendor_files.match(ref_path)) - l10n_path = self.path('/de/firefox/home.ftl') - ref_path = self.path('/en/firefox/home.ftl') - self.assertEqual( - pontoon_config.filter( - File( - l10n_path, - 'de/firefox/home.ftl', - locale='de' - ) - ), - 'ignore' - ) - self.assertIsNone(pontoon_files.match(l10n_path)) - self.assertIsNone(pontoon_files.match(ref_path)) - self.assertIsNone(vendor_files.match(l10n_path)) - self.assertIsNone(vendor_files.match(ref_path)) - l10n_path = self.path('/de/mozorg/mission.ftl') - ref_path = self.path('/en/mozorg/mission.ftl') - self.assertEqual( - pontoon_config.filter( - File( - l10n_path, - 'de/mozorg/mission.ftl', - locale='de' - ) - ), - 'error' - ) - self.assertIsNotNone(pontoon_files.match(l10n_path)) - self.assertIsNotNone(pontoon_files.match(ref_path)) - self.assertIsNone(vendor_files.match(l10n_path)) - self.assertIsNone(vendor_files.match(ref_path)) - - def test_gd(self, _walk, _isfile): - # only community localization - pontoon_config, vendor_config, files = self._list('gd', _walk, _isfile) - pontoon_files = ProjectFiles('gd', [pontoon_config]) - vendor_files = ProjectFiles('gd', [vendor_config]) - self.assertListEqual( - files, - [ - 'firefox/feature.ftl', - 'firefox/home.ftl', - 'mozorg/mission.ftl', - ] - ) - l10n_path = self.path('/gd/firefox/home.ftl') - ref_path = self.path('/en/firefox/home.ftl') - self.assertEqual( - pontoon_config.filter( - File( - l10n_path, - 'gd/firefox/home.ftl', - locale='gd' - ) - ), - 'error' - ) - self.assertIsNotNone(pontoon_files.match(l10n_path)) - self.assertIsNotNone(pontoon_files.match(ref_path)) - self.assertIsNone(vendor_files.match(l10n_path)) - self.assertIsNone(vendor_files.match(ref_path)) - - def test_it(self, _walk, _isfile): - # all pages translated, but split between vendor and community - pontoon_config, vendor_config, files = self._list('it', _walk, _isfile) - pontoon_files = ProjectFiles('it', [pontoon_config]) - vendor_files = ProjectFiles('it', [vendor_config]) - self.assertListEqual( - files, - [ - 'firefox/feature.ftl', - 'firefox/home.ftl', - 'mozorg/mission.ftl', - ] - ) - l10n_path = self.path('/it/firefox/home.ftl') - ref_path = self.path('/en/firefox/home.ftl') - file = File( - l10n_path, - 'it/firefox/home.ftl', - locale='it' - ) - self.assertEqual(pontoon_config.filter(file), 'ignore') - self.assertEqual(vendor_config.filter(file), 'error') - self.assertIsNone(pontoon_files.match(l10n_path)) - self.assertIsNone(pontoon_files.match(ref_path)) - self.assertIsNotNone(vendor_files.match(l10n_path)) - self.assertIsNotNone(vendor_files.match(ref_path)) - - -class TestL10nMerge(Rooted, unittest.TestCase): - # need to go through TOMLParser, as that's handling most of the - # environment - def test_merge_paths(self): - parser = MockTOMLParser({ - "base.toml": - '''\ -basepath = "." -locales = [ - "de", -] -[env] - l = "{l10n_base}/{locale}/" -[[paths]] - reference = "reference/*" - l10n = "{l}*" -'''}) - cfg = parser.parse( - self.path('/base.toml'), - env={'l10n_base': self.path('/l10n')} - ) - mocks = [ - self.path(leaf) - for leaf in [ - '/l10n/de/good.ftl', - '/l10n/de/not/subdir/bad.ftl', - '/l10n/fr/good.ftl', - '/l10n/fr/not/subdir/bad.ftl', - '/reference/ref.ftl', - '/reference/not/subdir/bad.ftl', - ] - ] - files = MockProjectFiles(mocks, 'de', [cfg], self.path('/mergers')) - self.assertListEqual( - list(files), - [ - (self.path('/l10n/de/good.ftl'), - self.path('/reference/good.ftl'), - self.path('/mergers/de/good.ftl'), - set()), - (self.path('/l10n/de/ref.ftl'), - self.path('/reference/ref.ftl'), - self.path('/mergers/de/ref.ftl'), - set()), - ]) diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_ini.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_ini.py deleted file mode 100644 index ddb75e2b1be3..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_ini.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from . import ( - SetupMixin, -) - - -class TestConfigLegacy(SetupMixin, unittest.TestCase): - - def test_filter_py_true(self): - 'Test filter.py just return bool(True)' - def filter(mod, path, entity=None): - return True - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'error') - - def test_filter_py_false(self): - 'Test filter.py just return bool(False)' - def filter(mod, path, entity=None): - return False - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'ignore') - - def test_filter_py_error(self): - 'Test filter.py just return str("error")' - def filter(mod, path, entity=None): - return 'error' - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'error') - - def test_filter_py_ignore(self): - 'Test filter.py just return str("ignore")' - def filter(mod, path, entity=None): - return 'ignore' - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'ignore') - - def test_filter_py_report(self): - 'Test filter.py just return str("report") and match to "warning"' - def filter(mod, path, entity=None): - return 'report' - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'warning') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'warning') - - def test_filter_py_module(self): - 'Test filter.py to return str("error") for browser or "ignore"' - def filter(mod, path, entity=None): - return 'error' if mod == 'browser' else 'ignore' - self.cfg.set_filter_py(filter) - with self.assertRaises(AssertionError): - self.cfg.add_rules({}) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file, entity='one_entity') - self.assertEqual(rv, 'ignore') diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_matcher.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_matcher.py deleted file mode 100644 index 74a20a84ce4b..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_matcher.py +++ /dev/null @@ -1,500 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import six -import unittest - -from compare_locales.paths.matcher import Matcher, ANDROID_STANDARD_MAP -from . import Rooted - - -class TestMatcher(unittest.TestCase): - - def test_matcher(self): - one = Matcher('foo/*') - self.assertTrue(one.match('foo/baz')) - self.assertFalse(one.match('foo/baz/qux')) - other = Matcher('bar/*') - self.assertTrue(other.match('bar/baz')) - self.assertFalse(other.match('bar/baz/qux')) - self.assertEqual(one.sub(other, 'foo/baz'), 'bar/baz') - self.assertIsNone(one.sub(other, 'bar/baz')) - one = Matcher('foo/**') - self.assertTrue(one.match('foo/baz')) - self.assertTrue(one.match('foo/baz/qux')) - other = Matcher('bar/**') - self.assertTrue(other.match('bar/baz')) - self.assertTrue(other.match('bar/baz/qux')) - self.assertEqual(one.sub(other, 'foo/baz'), 'bar/baz') - self.assertEqual(one.sub(other, 'foo/baz/qux'), 'bar/baz/qux') - one = Matcher('foo/*/one/**') - self.assertTrue(one.match('foo/baz/one/qux')) - self.assertFalse(one.match('foo/baz/bez/one/qux')) - other = Matcher('bar/*/other/**') - self.assertTrue(other.match('bar/baz/other/qux')) - self.assertFalse(other.match('bar/baz/bez/other/qux')) - self.assertEqual(one.sub(other, 'foo/baz/one/qux'), - 'bar/baz/other/qux') - self.assertEqual(one.sub(other, 'foo/baz/one/qux/zzz'), - 'bar/baz/other/qux/zzz') - self.assertIsNone(one.sub(other, 'foo/baz/bez/one/qux')) - one = Matcher('foo/**/bar/**') - self.assertTrue(one.match('foo/bar/baz.qux')) - self.assertTrue(one.match('foo/tender/bar/baz.qux')) - self.assertFalse(one.match('foo/nobar/baz.qux')) - self.assertFalse(one.match('foo/tender/bar')) - other = Matcher('baz/**/qux/**') - self.assertEqual(one.sub(other, 'foo/bar/baz.qux'), 'baz/qux/baz.qux') - self.assertEqual( - one.sub(other, 'foo/tender/bar/baz.qux'), - 'baz/tender/qux/baz.qux' - ) - - def test_encoded_matcher(self): - one = Matcher('foo/*', encoding='utf-8') - self.assertTrue(one.match(b'foo/bar')) - other = Matcher('bar/*', encoding='utf-8') - self.assertEqual(one.sub(other, b'foo/baz'), b'bar/baz') - - def test_prefix(self): - self.assertEqual( - Matcher('foo/bar.file').prefix, 'foo/bar.file' - ) - self.assertEqual( - Matcher('foo/*').prefix, 'foo/' - ) - self.assertEqual( - Matcher('foo/**').prefix, 'foo/' - ) - self.assertEqual( - Matcher('foo/*/bar').prefix, 'foo/' - ) - self.assertEqual( - Matcher('foo/**/bar').prefix, 'foo/' - ) - self.assertEqual( - Matcher('foo/**/bar/*').prefix, 'foo/' - ) - self.assertEqual( - Matcher('foo/{v}/bar').prefix, - 'foo/' - ) - self.assertEqual( - Matcher('foo/{v}/bar', {'v': 'expanded'}).prefix, - 'foo/expanded/bar' - ) - self.assertEqual( - Matcher('foo/{v}/*/bar').prefix, - 'foo/' - ) - self.assertEqual( - Matcher('foo/{v}/*/bar', {'v': 'expanded'}).prefix, - 'foo/expanded/' - ) - self.assertEqual( - Matcher('foo/{v}/*/bar', {'v': '{missing}'}).prefix, - 'foo/' - ) - - def test_encoded_prefix(self): - self.assertEqual( - Matcher('foo/bar.file', encoding='utf-8').prefix, b'foo/bar.file' - ) - self.assertEqual( - Matcher('foo/*', encoding='utf-8').prefix, b'foo/' - ) - self.assertEqual( - Matcher('foo/{v}/bar', encoding='utf-8').prefix, - b'foo/' - ) - self.assertEqual( - Matcher('foo/{v}/bar', {'v': 'expanded'}, encoding='utf-8').prefix, - b'foo/expanded/bar' - ) - - def test_variables(self): - self.assertDictEqual( - Matcher('foo/bar.file').match('foo/bar.file'), - {} - ) - self.assertDictEqual( - Matcher('{path}/bar.file').match('foo/bar.file'), - { - 'path': 'foo' - } - ) - self.assertDictEqual( - Matcher('{ path }/bar.file').match('foo/bar.file'), - { - 'path': 'foo' - } - ) - self.assertIsNone( - Matcher('{ var }/foopy/{ var }/bears') - .match('one/foopy/other/bears') - ) - self.assertDictEqual( - Matcher('{ var }/foopy/{ var }/bears') - .match('same_value/foopy/same_value/bears'), - { - 'var': 'same_value' - } - ) - self.assertIsNone( - Matcher('{ var }/foopy/bears', {'var': 'other'}) - .match('one/foopy/bears') - ) - self.assertDictEqual( - Matcher('{ var }/foopy/bears', {'var': 'one'}) - .match('one/foopy/bears'), - { - 'var': 'one' - } - ) - self.assertDictEqual( - Matcher('{one}/{two}/something', { - 'one': 'some/segment', - 'two': 'with/a/lot/of' - }).match('some/segment/with/a/lot/of/something'), - { - 'one': 'some/segment', - 'two': 'with/a/lot/of' - } - ) - self.assertDictEqual( - Matcher('{l}**', { - 'l': 'foo/{locale}/' - }).match('foo/it/path'), - { - 'l': 'foo/it/', - 'locale': 'it', - 's1': 'path', - } - ) - self.assertDictEqual( - Matcher('{l}*', { - 'l': 'foo/{locale}/' - }).match('foo/it/path'), - { - 'l': 'foo/it/', - 'locale': 'it', - 's1': 'path', - } - ) - - def test_encoded_variables(self): - self.assertDictEqual( - Matcher('foo/bar.file', encoding='utf-8').match(b'foo/bar.file'), - {} - ) - self.assertDictEqual( - Matcher( - '{path}/bar.file', encoding='utf-8' - ).match(b'foo/bar.file'), - { - 'path': 'foo' - } - ) - self.assertDictEqual( - Matcher('{l}*', { - 'l': 'foo/{locale}/' - }, encoding='utf-8').match(b'foo/it/path'), - { - 'l': 'foo/it/', - 'locale': 'it', - 's1': 'path', - } - ) - - def test_variables_sub(self): - one = Matcher('{base}/{loc}/*', {'base': 'ONE_BASE'}) - other = Matcher('{base}/somewhere/*', {'base': 'OTHER_BASE'}) - self.assertEqual( - one.sub(other, 'ONE_BASE/ab-CD/special'), - 'OTHER_BASE/somewhere/special' - ) - one = Matcher('{base}/{loc}/*', {'base': 'ONE_BASE'}, encoding='utf-8') - other = Matcher( - '{base}/somewhere/*', {'base': 'OTHER_BASE'}, encoding='utf-8' - ) - self.assertEqual( - one.sub(other, b'ONE_BASE/ab-CD/special'), - b'OTHER_BASE/somewhere/special' - ) - - def test_copy(self): - one = Matcher('{base}/{loc}/*', { - 'base': 'ONE_BASE', - 'generic': 'keep' - }) - other = Matcher(one, {'base': 'OTHER_BASE'}) - self.assertEqual( - one.sub(other, 'ONE_BASE/ab-CD/special'), - 'OTHER_BASE/ab-CD/special' - ) - self.assertDictEqual( - one.env, - { - 'base': ['ONE_BASE'], - 'generic': ['keep'] - } - ) - self.assertDictEqual( - other.env, - { - 'base': ['OTHER_BASE'], - 'generic': ['keep'] - } - ) - - def test_eq(self): - self.assertEqual( - Matcher('foo'), - Matcher('foo') - ) - self.assertNotEqual( - Matcher('foo'), - Matcher('bar') - ) - self.assertEqual( - Matcher('foo', root='/bar/'), - Matcher('foo', root='/bar/') - ) - self.assertNotEqual( - Matcher('foo', root='/bar/'), - Matcher('foo', root='/baz/') - ) - self.assertNotEqual( - Matcher('foo'), - Matcher('foo', root='/bar/') - ) - self.assertEqual( - Matcher('foo', env={'one': 'two'}), - Matcher('foo', env={'one': 'two'}) - ) - self.assertEqual( - Matcher('foo'), - Matcher('foo', env={}) - ) - self.assertNotEqual( - Matcher('foo', env={'one': 'two'}), - Matcher('foo', env={'one': 'three'}) - ) - self.assertEqual( - Matcher('foo', env={'other': 'val'}), - Matcher('foo', env={'one': 'two'}) - ) - - -class ConcatTest(unittest.TestCase): - def test_plain(self): - left = Matcher('some/path/') - right = Matcher('with/file') - concatenated = left.concat(right) - self.assertEqual(str(concatenated), 'some/path/with/file') - self.assertEqual(concatenated.prefix, 'some/path/with/file') - pattern_concatenated = left.concat('with/file') - self.assertEqual(concatenated, pattern_concatenated) - - def test_stars(self): - left = Matcher('some/*/path/') - right = Matcher('with/file') - concatenated = left.concat(right) - self.assertEqual(concatenated.prefix, 'some/') - concatenated = right.concat(left) - self.assertEqual(concatenated.prefix, 'with/filesome/') - - -class TestAndroid(unittest.TestCase): - '''special case handling for `android_locale` to handle the funky - locale codes in Android apps - ''' - def test_match(self): - # test matches as well as groupdict aliasing. - one = Matcher('values-{android_locale}/strings.xml') - self.assertEqual( - one.match('values-de/strings.xml'), - { - 'android_locale': 'de', - 'locale': 'de' - } - ) - self.assertEqual( - one.match('values-de-rDE/strings.xml'), - { - 'android_locale': 'de-rDE', - 'locale': 'de-DE' - } - ) - self.assertEqual( - one.match('values-b+sr+Latn/strings.xml'), - { - 'android_locale': 'b+sr+Latn', - 'locale': 'sr-Latn' - } - ) - self.assertEqual( - one.with_env( - {'locale': 'de'} - ).match('values-de/strings.xml'), - { - 'android_locale': 'de', - 'locale': 'de' - } - ) - self.assertEqual( - one.with_env( - {'locale': 'de-DE'} - ).match('values-de-rDE/strings.xml'), - { - 'android_locale': 'de-rDE', - 'locale': 'de-DE' - } - ) - self.assertEqual( - one.with_env( - {'locale': 'sr-Latn'} - ).match('values-b+sr+Latn/strings.xml'), - { - 'android_locale': 'b+sr+Latn', - 'locale': 'sr-Latn' - } - ) - - def test_repeat(self): - self.assertEqual( - Matcher('{android_locale}/{android_locale}').match( - 'b+sr+Latn/b+sr+Latn' - ), - { - 'android_locale': 'b+sr+Latn', - 'locale': 'sr-Latn' - } - ) - self.assertEqual( - Matcher( - '{android_locale}/{android_locale}', - env={'locale': 'sr-Latn'} - ).match( - 'b+sr+Latn/b+sr+Latn' - ), - { - 'android_locale': 'b+sr+Latn', - 'locale': 'sr-Latn' - } - ) - - def test_mismatch(self): - # test failed matches - one = Matcher('values-{android_locale}/strings.xml') - self.assertIsNone( - one.with_env({'locale': 'de'}).match( - 'values-fr.xml' - ) - ) - self.assertIsNone( - one.with_env({'locale': 'de-DE'}).match( - 'values-de-DE.xml' - ) - ) - self.assertIsNone( - one.with_env({'locale': 'sr-Latn'}).match( - 'values-sr-Latn.xml' - ) - ) - self.assertIsNone( - Matcher('{android_locale}/{android_locale}').match( - 'b+sr+Latn/de-rDE' - ) - ) - - def test_prefix(self): - one = Matcher('values-{android_locale}/strings.xml') - self.assertEqual( - one.with_env({'locale': 'de'}).prefix, - 'values-de/strings.xml' - ) - self.assertEqual( - one.with_env({'locale': 'de-DE'}).prefix, - 'values-de-rDE/strings.xml' - ) - self.assertEqual( - one.with_env({'locale': 'sr-Latn'}).prefix, - 'values-b+sr+Latn/strings.xml' - ) - self.assertEqual( - one.prefix, - 'values-' - ) - - def test_aliases(self): - # test legacy locale code mapping - # he <-> iw, id <-> in, yi <-> ji - one = Matcher('values-{android_locale}/strings.xml') - for legacy, standard in six.iteritems(ANDROID_STANDARD_MAP): - self.assertDictEqual( - one.match('values-{}/strings.xml'.format(legacy)), - { - 'android_locale': legacy, - 'locale': standard - } - ) - self.assertEqual( - one.with_env({'locale': standard}).prefix, - 'values-{}/strings.xml'.format(legacy) - ) - - -class TestRootedMatcher(Rooted, unittest.TestCase): - def test_root_path(self): - one = Matcher('some/path', root=self.root) - self.assertIsNone(one.match('some/path')) - self.assertIsNotNone(one.match(self.path('/some/path'))) - - def test_copy(self): - one = Matcher('some/path', root=self.path('/one-root')) - other = Matcher(one, root=self.path('/different-root')) - self.assertIsNone(other.match('some/path')) - self.assertIsNone( - other.match(self.path('/one-root/some/path')) - ) - self.assertIsNotNone( - other.match(self.path('/different-root/some/path')) - ) - - def test_rooted(self): - r1 = self.path('/one-root') - r2 = self.path('/other-root') - one = Matcher(self.path('/one-root/full/path'), root=r2) - self.assertIsNone(one.match(self.path('/other-root/full/path'))) - # concat r2 and r1. r1 is absolute, so we gotta trick that - concat_root = r2 - if not r1.startswith('/'): - # windows absolute paths don't start with '/', add one - concat_root += '/' - concat_root += r1 - self.assertIsNone(one.match(concat_root + '/full/path')) - self.assertIsNotNone(one.match(self.path('/one-root/full/path'))) - - def test_variable(self): - r1 = self.path('/one-root') - r2 = self.path('/other-root') - one = Matcher( - '{var}/path', - env={'var': 'relative-dir'}, - root=r1 - ) - self.assertIsNone(one.match('relative-dir/path')) - self.assertIsNotNone( - one.match(self.path('/one-root/relative-dir/path')) - ) - other = Matcher(one, env={'var': r2}) - self.assertIsNone( - other.match(self.path('/one-root/relative-dir/path')) - ) - self.assertIsNotNone( - other.match(self.path('/other-root/path')) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_paths.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_paths.py deleted file mode 100644 index e72fe9a7a654..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_paths.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales.paths import File - - -class TestFile(unittest.TestCase): - def test_hash_and_equality(self): - f1 = File('/tmp/full/path/to/file', 'path/to/file') - d = {} - d[f1] = True - self.assertIn(f1, d) - f2 = File('/tmp/full/path/to/file', 'path/to/file') - self.assertIn(f2, d) - f2 = File('/tmp/full/path/to/file', 'path/to/file', locale='en') - self.assertNotIn(f2, d) - # trigger hash collisions between File and non-File objects - self.assertEqual(hash(f1), hash(f1.localpath)) - self.assertNotIn(f1.localpath, d) - f1 = File('/tmp/full/other/path', 'other/path') - d[f1.localpath] = True - self.assertIn(f1.localpath, d) - self.assertNotIn(f1, d) diff --git a/third_party/python/compare-locales/compare_locales/tests/paths/test_project.py b/third_party/python/compare-locales/compare_locales/tests/paths/test_project.py deleted file mode 100644 index fe1224548646..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/paths/test_project.py +++ /dev/null @@ -1,229 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales.paths import ProjectConfig -from . import SetupMixin - - -class TestConfigRules(SetupMixin, unittest.TestCase): - - def test_filter_empty(self): - 'Test that an empty config works' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/browser/**' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, entity='one_entity') - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file, entity='one_entity') - self.assertEqual(rv, 'ignore') - - def test_single_file_rule(self): - 'Test a single rule for just a single file, no key' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/browser/**' - }) - self.cfg.add_rules({ - 'path': '/tmp/somedir/{locale}/browser/one/two/file.ftl', - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.file, 'one_entity') - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file, 'one_entity') - self.assertEqual(rv, 'ignore') - - def test_single_key_rule(self): - 'Test a single rule with file and key' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/browser/**' - }) - self.cfg.add_rules({ - 'path': '/tmp/somedir/{locale}/browser/one/two/file.ftl', - 'key': 'one_entity', - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, 'one_entity') - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file, 'one_entity') - self.assertEqual(rv, 'ignore') - - def test_single_non_matching_key_rule(self): - 'Test a single key rule with regex special chars that should not match' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.cfg.add_rules({ - 'path': '/tmp/somedir/{locale}/browser/one/two/file.ftl', - 'key': '.ne_entit.', - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file, 'one_entity') - self.assertEqual(rv, 'error') - - def test_single_matching_re_key_rule(self): - 'Test a single key with regular expression' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.cfg.add_rules({ - 'path': '/tmp/somedir/{locale}/browser/one/two/file.ftl', - 'key': 're:.ne_entit.$', - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file, 'one_entity') - self.assertEqual(rv, 'ignore') - - def test_double_file_rule(self): - 'Test path shortcut, one for each of our files' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.cfg.add_rules({ - 'path': [ - '/tmp/somedir/{locale}/browser/one/two/file.ftl', - '/tmp/somedir/{locale}/toolkit/two/one/file.ftl', - ], - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - - def test_double_file_key_rule(self): - 'Test path and key shortcut, one key matching, one not' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.cfg.add_rules({ - 'path': [ - '/tmp/somedir/{locale}/browser/one/two/file.ftl', - '/tmp/somedir/{locale}/toolkit/two/one/file.ftl', - ], - 'key': [ - 'one_entity', - 'other_entity', - ], - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.file, 'one_entity') - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'error') - rv = self.cfg.filter(self.other_file, 'one_entity') - self.assertEqual(rv, 'ignore') - - def test_single_wildcard_rule(self): - 'Test single wildcard' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/browser/**' - }) - self.cfg.add_rules({ - 'path': [ - '/tmp/somedir/{locale}/browser/one/*/*', - ], - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - - def test_double_wildcard_rule(self): - 'Test double wildcard' - self.cfg.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.cfg.add_rules({ - 'path': [ - '/tmp/somedir/{locale}/**', - ], - 'action': 'ignore' - }) - rv = self.cfg.filter(self.file) - self.assertEqual(rv, 'ignore') - rv = self.cfg.filter(self.other_file) - self.assertEqual(rv, 'ignore') - - -class TestProjectConfig(unittest.TestCase): - def test_children(self): - pc = ProjectConfig(None) - child = ProjectConfig(None) - pc.add_child(child) - self.assertListEqual([pc, child], list(pc.configs)) - - def test_locales_in_children(self): - pc = ProjectConfig(None) - child = ProjectConfig(None) - child.add_paths({ - 'l10n': '/tmp/somedir/{locale}/toolkit/**', - }) - child.set_locales([]) - pc.add_child(child) - self.assertListEqual(pc.all_locales, []) - pc.set_locales(['de', 'fr']) - self.assertListEqual(child.locales, []) - self.assertListEqual(pc.all_locales, ['de', 'fr']) - - def test_locales_in_paths(self): - pc = ProjectConfig(None) - child = ProjectConfig(None) - child.add_paths({ - 'l10n': '/tmp/somedir/{locale}/toolkit/**', - 'locales': ['it'] - }) - child.set_locales([]) - pc.add_child(child) - self.assertListEqual(pc.all_locales, ['it']) - pc.set_locales(['de', 'fr']) - self.assertListEqual(pc.all_locales, ['de', 'fr', 'it']) - - -class TestSameConfig(unittest.TestCase): - - def test_path(self): - one = ProjectConfig('one.toml') - one.set_locales(['ab']) - self.assertTrue(one.same(ProjectConfig('one.toml'))) - self.assertFalse(one.same(ProjectConfig('two.toml'))) - - def test_paths(self): - one = ProjectConfig('one.toml') - one.set_locales(['ab']) - one.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - other = ProjectConfig('one.toml') - self.assertFalse(one.same(other)) - other.add_paths({ - 'l10n': '/tmp/somedir/{locale}/**' - }) - self.assertTrue(one.same(other)) - - def test_children(self): - one = ProjectConfig('one.toml') - one.add_child(ProjectConfig('inner.toml')) - one.set_locales(['ab']) - other = ProjectConfig('one.toml') - self.assertFalse(one.same(other)) - other.add_child(ProjectConfig('inner.toml')) - self.assertTrue(one.same(other)) diff --git a/third_party/python/compare-locales/compare_locales/tests/po/__init__.py b/third_party/python/compare-locales/compare_locales/tests/po/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/compare-locales/compare_locales/tests/po/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/po/test_parser.py deleted file mode 100644 index e02fe6628319..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/po/test_parser.py +++ /dev/null @@ -1,139 +0,0 @@ -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from compare_locales.tests import ParserTestMixin -from compare_locales.parser import ( - BadEntity, - Whitespace, -) - - -class TestPoParser(ParserTestMixin, unittest.TestCase): - maxDiff = None - filename = 'strings.po' - - def test_parse_string_list(self): - self.parser.readUnicode(' ') - ctx = self.parser.ctx - with self.assertRaises(BadEntity): - self.parser._parse_string_list(ctx, 0, 'msgctxt') - self.parser.readUnicode('msgctxt ') - ctx = self.parser.ctx - with self.assertRaises(BadEntity): - self.parser._parse_string_list(ctx, 0, 'msgctxt') - self.parser.readUnicode('msgctxt " "') - ctx = self.parser.ctx - self.assertTupleEqual( - self.parser._parse_string_list(ctx, 0, 'msgctxt'), - (" ", len(ctx.contents)) - ) - self.parser.readUnicode('msgctxt " " \t "A"\r "B"asdf') - ctx = self.parser.ctx - self.assertTupleEqual( - self.parser._parse_string_list(ctx, 0, 'msgctxt'), - (" AB", len(ctx.contents)-4) - ) - self.parser.readUnicode('msgctxt "\\\\ " "A" "B"asdf"fo"') - ctx = self.parser.ctx - self.assertTupleEqual( - self.parser._parse_string_list(ctx, 0, 'msgctxt'), - ("\\ AB", len(ctx.contents)-8) - ) - - def test_simple_string(self): - source = ''' -msgid "untranslated string" -msgstr "translated string" -''' - self._test( - source, - ( - (Whitespace, '\n'), - (('untranslated string', None), 'translated string'), - (Whitespace, '\n'), - ) - ) - - def test_escapes(self): - source = r''' -msgid "untranslated string" -msgstr "\\\t\r\n\"" -''' - self._test( - source, - ( - (Whitespace, '\n'), - (('untranslated string', None), '\\\t\r\n"'), - (Whitespace, '\n'), - ) - ) - - def test_comments(self): - source = ''' -# translator-comments -#. extracted-comments -#: reference... -#, flag... -#| msgctxt previous-context -#| msgid previous-untranslated-string -msgid "untranslated string" -msgstr "translated string" -''' - self._test( - source, - ( - (Whitespace, '\n'), - ( - ('untranslated string', None), - 'translated string', - 'extracted-comments', - ), - (Whitespace, '\n'), - ) - ) - - def test_simple_context(self): - source = ''' -msgctxt "context to use" -msgid "untranslated string" -msgstr "translated string" -''' - self._test( - source, - ( - (Whitespace, '\n'), - ( - ('untranslated string', 'context to use'), - 'translated string' - ), - (Whitespace, '\n'), - ) - ) - - def test_translated(self): - source = ''' -msgid "reference 1" -msgstr "translated string" - -msgid "reference 2" -msgstr "" -''' - self._test( - source, - ( - (Whitespace, '\n'), - (('reference 1', None), 'translated string'), - (Whitespace, '\n'), - (('reference 2', None), 'reference 2'), - (Whitespace, '\n'), - ) - ) - entities = self.parser.parse() - self.assertListEqual( - [e.localized for e in entities], - [True, False] - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/properties/__init__.py b/third_party/python/compare-locales/compare_locales/tests/properties/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/compare-locales/compare_locales/tests/properties/test_checks.py b/third_party/python/compare-locales/compare_locales/tests/properties/test_checks.py deleted file mode 100644 index 68a8e0fd8cc2..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/properties/test_checks.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals - -from compare_locales.paths import File -from compare_locales.tests import BaseHelper - - -class TestProperties(BaseHelper): - file = File('foo.properties', 'foo.properties') - refContent = b'''some = value -''' - - def testGood(self): - self._test(b'''some = localized''', - tuple()) - - def testMissedEscape(self): - self._test(br'''some = \u67ood escape, bad \escape''', - (('warning', 20, r'unknown escape sequence, \e', - 'escape'),)) - - def test_bad_encoding(self): - self._test( - 'some = touché"'.encode('latin-1'), - ( - ( - "warning", - 12, - "\ufffd in: some", - "encodings" - ), - ) - ) - - -class TestPlurals(BaseHelper): - file = File('foo.properties', 'foo.properties') - refContent = b'''\ -# LOCALIZATION NOTE (downloadsTitleFiles): Semi-colon list of plural forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of files -# example: 111 files - Downloads -downloadsTitleFiles=#1 file - Downloads;#1 files - #2 -''' - - def testGood(self): - self._test(b'''\ -# LOCALIZATION NOTE (downloadsTitleFiles): Semi-colon list of plural forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of files -# example: 111 files - Downloads -downloadsTitleFiles=#1 file - Downloads;#1 files - #2;#1 filers -''', - tuple()) - - def testNotUsed(self): - self._test(b'''\ -# LOCALIZATION NOTE (downloadsTitleFiles): Semi-colon list of plural forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of files -# example: 111 files - Downloads -downloadsTitleFiles=#1 file - Downloads;#1 files - Downloads;#1 filers -''', - (('warning', 0, 'not all variables used in l10n', - 'plural'),)) - - def testNotDefined(self): - self._test(b'''\ -# LOCALIZATION NOTE (downloadsTitleFiles): Semi-colon list of plural forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of files -# example: 111 files - Downloads -downloadsTitleFiles=#1 file - Downloads;#1 files - #2;#1 #3 -''', - (('error', 0, 'unreplaced variables in l10n', 'plural'),)) - - -class TestPluralForms(BaseHelper): - file = File('foo.properties', 'foo.properties', locale='en-GB') - refContent = b'''\ -# LOCALIZATION NOTE (downloadsTitleFiles): Semi-colon list of plural forms. -# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals -# #1 number of files -# example: 111 files - Downloads -downloadsTitleFiles=#1 file;#1 files -''' - - def test_matching_forms(self): - self._test(b'''\ -downloadsTitleFiles=#1 fiiilee;#1 fiiilees -''', - tuple()) - - def test_lacking_forms(self): - self._test(b'''\ -downloadsTitleFiles=#1 fiiilee -''', - (('warning', 0, 'expecting 2 plurals, found 1', 'plural'),)) - - def test_excess_forms(self): - self._test(b'''\ -downloadsTitleFiles=#1 fiiilee;#1 fiiilees;#1 fiiilees -''', - (('warning', 0, 'expecting 2 plurals, found 3', 'plural'),)) diff --git a/third_party/python/compare-locales/compare_locales/tests/properties/test_merge.py b/third_party/python/compare-locales/compare_locales/tests/properties/test_merge.py deleted file mode 100644 index 97d98f5167e6..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/properties/test_merge.py +++ /dev/null @@ -1,68 +0,0 @@ -# coding=utf8 - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from codecs import decode, encode -import unittest - -from compare_locales.merge import merge_channels - - -class TestMergeProperties(unittest.TestCase): - name = "foo.properties" - - def test_no_changes(self): - channels = (b""" -foo = Foo 1 -""", b""" -foo = Foo 2 -""") - self.assertEqual( - merge_channels(self.name, channels), b""" -foo = Foo 1 -""") - - def test_encoding(self): - channels = (encode(u""" -foo = Foo 1… -""", "utf8"), encode(u""" -foo = Foo 2… -""", "utf8")) - output = merge_channels(self.name, channels) - self.assertEqual(output, encode(u""" -foo = Foo 1… -""", "utf8")) - - u_output = decode(output, "utf8") - self.assertEqual(u_output, u""" -foo = Foo 1… -""") - - def test_repetitive(self): - channels = (b"""\ -# comment -one = one -# comment -three = three -""", b"""\ -# comment -one = one -# comment -two = two -# comment -three = three -""") - output = merge_channels(self.name, channels) - self.assertMultiLineEqual( - decode(output, "utf-8"), - """\ -# comment -one = one -# comment -two = two -# comment -three = three -""" - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/properties/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/properties/test_parser.py deleted file mode 100644 index 7600baa7538a..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/properties/test_parser.py +++ /dev/null @@ -1,243 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from six.moves import zip -from compare_locales.tests import ParserTestMixin -from compare_locales.parser import ( - Comment, - Junk, - Whitespace, -) - - -class TestPropertiesParser(ParserTestMixin, unittest.TestCase): - - filename = 'foo.properties' - - def testBackslashes(self): - self._test(r'''one_line = This is one line -two_line = This is the first \ -of two lines -one_line_trailing = This line ends in \\ -and has junk -two_lines_triple = This line is one of two and ends in \\\ -and still has another line coming -''', ( - ('one_line', 'This is one line'), - (Whitespace, '\n'), - ('two_line', u'This is the first of two lines'), - (Whitespace, '\n'), - ('one_line_trailing', u'This line ends in \\'), - (Whitespace, '\n'), - (Junk, 'and has junk\n'), - ('two_lines_triple', 'This line is one of two and ends in \\' - 'and still has another line coming'), - (Whitespace, '\n'))) - - def testProperties(self): - # port of netwerk/test/PropertiesTest.cpp - self.parser.readContents(self.resource('test.properties')) - ref = ['1', '2', '3', '4', '5', '6', '7', '8', - 'this is the first part of a continued line ' - 'and here is the 2nd part'] - i = iter(self.parser) - for r, e in zip(ref, i): - self.assertTrue(e.localized) - self.assertEqual(e.val, r) - - def test_bug121341(self): - # port of xpcom/tests/unit/test_bug121341.js - self.parser.readContents(self.resource('bug121341.properties')) - ref = ['abc', 'xy', u"\u1234\t\r\n\u00AB\u0001\n", - "this is multiline property", - "this is another multiline property", u"test\u0036", - "yet another multiline propery", u"\ttest5\u0020", " test6\t", - u"c\uCDEFd", u"\uABCD"] - i = iter(self.parser) - for r, e in zip(ref, i): - self.assertEqual(e.val, r) - - def test_comment_in_multi(self): - self._test(r'''bar=one line with a \ -# part that looks like a comment \ -and an end''', (('bar', 'one line with a # part that looks like a comment ' - 'and an end'),)) - - def test_license_header(self): - self._test('''\ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -foo=value -''', ( - (Comment, 'MPL'), - (Whitespace, '\n\n'), - ('foo', 'value'), - (Whitespace, '\n'))) - - def test_escapes(self): - self.parser.readContents(br''' -# unicode escapes -zero = some \unicode -one = \u0 -two = \u41 -three = \u042 -four = \u0043 -five = \u0044a -six = \a -seven = \n\r\t\\ -''') - ref = ['some unicode', chr(0), 'A', 'B', 'C', 'Da', 'a', '\n\r\t\\'] - for r, e in zip(ref, self.parser): - self.assertEqual(e.val, r) - - def test_trailing_comment(self): - self._test('''first = string -second = string - -# -#commented out -''', ( - ('first', 'string'), - (Whitespace, '\n'), - ('second', 'string'), - (Whitespace, '\n\n'), - (Comment, 'commented out'), - (Whitespace, '\n'))) - - def test_trailing_newlines(self): - self._test('''\ -foo = bar - -\x20\x20 - ''', (('foo', 'bar'), (Whitespace, '\n\n\x20\x20\n '))) - - def test_just_comments(self): - self._test('''\ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# LOCALIZATION NOTE These strings are used inside the Promise debugger -# which is available as a panel in the Debugger. -''', ( - (Comment, 'MPL'), - (Whitespace, '\n\n'), - (Comment, 'LOCALIZATION NOTE'), - (Whitespace, '\n'))) - - def test_just_comments_without_trailing_newline(self): - self._test('''\ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# LOCALIZATION NOTE These strings are used inside the Promise debugger -# which is available as a panel in the Debugger.''', ( - (Comment, 'MPL'), - (Whitespace, '\n\n'), - (Comment, 'LOCALIZATION NOTE'))) - - def test_trailing_comment_and_newlines(self): - self._test('''\ -# LOCALIZATION NOTE These strings are used inside the Promise debugger -# which is available as a panel in the Debugger. - - - -''', ( - (Comment, 'LOCALIZATION NOTE'), - (Whitespace, '\n\n\n'))) - - def test_standalone_license(self): - self._test('''\ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -foo = value -''', ( - (Comment, 'MPL'), - (Whitespace, '\n'), - ('foo', 'value'), - (Whitespace, '\n'))) - - def test_empty_file(self): - self._test('', tuple()) - self._test('\n', ((Whitespace, '\n'),)) - self._test('\n\n', ((Whitespace, '\n\n'),)) - self._test(' \n\n', ((Whitespace, '\n\n'),)) - - def test_positions(self): - self.parser.readContents(b'''\ -one = value -two = other \\ -escaped value -''') - one, two = list(self.parser) - self.assertEqual(one.position(), (1, 1)) - self.assertEqual(one.value_position(), (1, 7)) - self.assertEqual(two.position(), (2, 1)) - self.assertEqual(two.value_position(), (2, 7)) - self.assertEqual(two.value_position(-1), (3, 14)) - self.assertEqual(two.value_position(10), (3, 3)) - - # Bug 1399059 comment 18 - def test_z(self): - self.parser.readContents(b'''\ -one = XYZ ABC -''') - one, = list(self.parser) - self.assertEqual(one.val, 'XYZ ABC') - - def test_white_space_stripping(self): - self._test('''\ -one = one -two = two \n\ -three = three\xa0''', ( - ('one', 'one'), - (Whitespace, '\n'), - ('two', 'two'), - (Whitespace, '\n'), - ('three', 'three\xa0'), - )) - - def test_white_space_keys(self): - self._test('''\ -o\\ e = one -t\fo = two \n\ -t\xa0e = three\xa0''', ( - ('o\\ e', 'one'), - (Whitespace, '\n'), - ('t\fo', 'two'), - (Whitespace, '\n'), - ('t\xa0e', 'three\xa0'), - )) - - def test_pre_comment(self): - self._test('''\ -# comment -one = string - -# standalone - -# glued -second = string -''', ( - ('one', 'string', 'comment'), - (Whitespace, '\n\n'), - (Comment, 'standalone'), - (Whitespace, '\n\n'), - ('second', 'string', 'glued'), - (Whitespace, '\n'), - )) - - -if __name__ == '__main__': - unittest.main() diff --git a/third_party/python/compare-locales/compare_locales/tests/serializer/__init__.py b/third_party/python/compare-locales/compare_locales/tests/serializer/__init__.py deleted file mode 100644 index 9b85098b23af..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/serializer/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from compare_locales.parser import getParser -from compare_locales.serializer import serialize - - -class Helper(object): - """Mixin to test serializers. - - Reads the reference_content into self.reference, and uses - that to serialize in _test. - """ - name = None - reference_content = None - - def setUp(self): - p = self.parser = getParser(self.name) - p.readUnicode(self.reference_content) - self.reference = list(p.walk()) - - def _test(self, old_content, new_data, expected): - """Test with old content, new data, and the reference data - against the expected unicode output. - """ - self.parser.readUnicode(old_content) - old_l10n = list(self.parser.walk()) - output = serialize(self.name, self.reference, old_l10n, new_data) - self.assertMultiLineEqual( - output.decode(self.parser.encoding), - expected - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/serializer/test_android.py b/third_party/python/compare-locales/compare_locales/tests/serializer/test_android.py deleted file mode 100644 index b36f605e8756..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/serializer/test_android.py +++ /dev/null @@ -1,218 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest - -from . import Helper - - -class TestAndroidSerializer(Helper, unittest.TestCase): - name = 'strings.xml' - reference_content = """\ - - - - Unable to connect - -
  • The site could be temporarily unavailable or too busy.
  • - - ]]>
    - - -
  • The site could be temporarily unavailable or too busy.
  • - - ]]> -
    -
    -""" - - def test_nothing_new_or_old(self): - self._test( - "", - {}, - """\ - - - -""" - ) - - def test_new_string(self): - self._test( - "", - { - "title": "Cannot connect" - }, - """\ - - - - Cannot connect - -""" - ) - - def test_new_cdata(self): - self._test( - "", - { - "message": """ -
      -
    • Something else
    • -
    -""" - }, - """\ - - - -
  • Something else
  • - -]]>
    -
    -""" - ) - - def test_new_cdata_wrapped(self): - self._test( - "", - { - "wrapped_message": """ -
      -
    • Something else
    • -
    -""" - }, - """\ - - - - -
  • Something else
  • - -]]> -
    -
    -""" - ) - - def test_remove_string(self): - self._test( - """\ - - - Unable to connect - Unable to connect - Unable to connect - -""", - {}, - """\ - - - Unable to connect - -""" - ) - - def test_same_string(self): - self._test( - """\ - - - Unable to connect - -""", - { - "title": "Unable to connect" - }, - """\ - - - - Unable to connect - -""" - ) - - -class TestAndroidDuplicateComment(Helper, unittest.TestCase): - name = 'strings.xml' - reference_content = """\ - - - - - Open with app - - Share link - -""" - - def test_missing_translation(self): - self._test( - """\ - - - - - - - -""", - { - "contextmenu_link_share": "translation" - }, - """\ - - - - - translation - -""" - ) - - -class TestAndroidTools(Helper, unittest.TestCase): - name = 'strings.xml' - reference_content = ( - """\ - - Take your passwords everywhere. - """ - "search your entries" - """ - -""") - - def test_namespaced_document(self): - self._test( - """\ - - - Localized tag line - -""", - { - "search_your_entries": "Looking for Entries" - }, - ( - """\ - - - Localized tag line - """ - "Looking for Entries" - """ - -""") - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/serializer/test_fluent.py b/third_party/python/compare-locales/compare_locales/tests/serializer/test_fluent.py deleted file mode 100644 index 9aa9acd4f744..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/serializer/test_fluent.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest - -from compare_locales.serializer import serialize -from . import Helper - - -class TestFluentSerializer(Helper, unittest.TestCase): - name = "foo.ftl" - reference_content = """\ -this = is English - -# another one bites -another = message -""" - - def test_nothing_new_or_old(self): - output = serialize(self.name, self.reference, [], {}) - self.assertMultiLineEqual(output.decode(self.parser.encoding), '\n\n') - - def test_obsolete_old_string(self): - self._test( - """\ -# we used to have this -old = stuff with comment -""", - {}, - """\ - - -""") - - def test_nothing_old_new_translation(self): - self._test( - "", - { - "another": "another = localized message" - }, - """\ - - -# another one bites -another = localized message -""" - ) - - def test_old_message_new_other_translation(self): - self._test( - """\ -this = is localized -""", - { - "another": "another = localized message" - }, - """\ -this = is localized - -# another one bites -another = localized message -""" - ) - - def test_old_message_new_same_translation(self): - self._test( - """\ -this = is localized -""", - { - "this": "this = has a better message" - }, - """\ -this = has a better message - -""" - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/serializer/test_properties.py b/third_party/python/compare-locales/compare_locales/tests/serializer/test_properties.py deleted file mode 100644 index 50929fce73a2..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/serializer/test_properties.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import unittest - -from compare_locales.serializer import serialize -from . import Helper - - -class TestPropertiesSerializer(Helper, unittest.TestCase): - name = 'foo.properties' - reference_content = """\ -this = is English - -# another one bites -another = message -""" - - def test_nothing_new_or_old(self): - output = serialize(self.name, self.reference, [], {}) - self.assertMultiLineEqual(output.decode(self.parser.encoding), '\n\n') - - def test_obsolete_old_string(self): - self._test( - """\ -# we used to have this -old = stuff with comment -""", - {}, - """\ - - -""") - - def test_nothing_old_new_translation(self): - self._test( - "", - { - "another": "localized message" - }, - """\ - - -# another one bites -another = localized message -""" - ) - - def test_old_message_new_other_translation(self): - self._test( - """\ -this = is localized -""", - { - "another": "localized message" - }, - """\ -this = is localized - -# another one bites -another = localized message -""" - ) - - def test_old_message_new_same_translation(self): - self._test( - """\ -this = is localized -""", - { - "this": "has a better message" - }, - """\ -this = has a better message - -""" - ) - - -class TestPropertiesDuplicateComment(Helper, unittest.TestCase): - name = 'foo.properties' - reference_content = """\ -# repetitive -one = one -# repetitive -two = two -""" - - def test_missing_translation(self): - self._test( - """\ -# repetitive - -# repetitive -two = two -""", - {}, - """\ -# repetitive - -# repetitive -two = two -""" - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_apps.py b/third_party/python/compare-locales/compare_locales/tests/test_apps.py deleted file mode 100644 index 3fc5091fe5b2..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_apps.py +++ /dev/null @@ -1,168 +0,0 @@ -from __future__ import absolute_import -import unittest -import os -import tempfile -import shutil - -from compare_locales import mozpath -from compare_locales.paths import ( - EnumerateApp, - EnumerateSourceTreeApp, - ProjectFiles, -) - -MAIL_INI = '''\ -[general] -depth = ../.. -all = mail/locales/all-locales - -[compare] -dirs = mail - -[includes] -# non-central apps might want to use %(topsrcdir)s here, or other vars -# RFE: that needs to be supported by compare-locales, too, though -toolkit = mozilla/toolkit/locales/l10n.ini - -[include_toolkit] -type = hg -mozilla = mozilla-central -repo = http://hg.mozilla.org/ -l10n.ini = toolkit/locales/l10n.ini -''' - - -MAIL_ALL_LOCALES = '''af -de -fr -''' - -MAIL_FILTER_PY = ''' -def test(mod, path, entity = None): - if mod == 'toolkit' and path == 'ignored_path': - return 'ignore' - return 'error' -''' - -TOOLKIT_INI = '''[general] -depth = ../.. - -[compare] -dirs = toolkit -''' - - -class TestApp(unittest.TestCase): - def setUp(self): - self.stage = tempfile.mkdtemp() - mail = mozpath.join(self.stage, 'comm', 'mail', 'locales') - toolkit = mozpath.join( - self.stage, 'comm', 'mozilla', 'toolkit', 'locales') - l10n = mozpath.join(self.stage, 'l10n-central', 'de', 'toolkit') - os.makedirs(mozpath.join(mail, 'en-US')) - os.makedirs(mozpath.join(toolkit, 'en-US')) - os.makedirs(l10n) - with open(mozpath.join(mail, 'l10n.ini'), 'w') as f: - f.write(MAIL_INI) - with open(mozpath.join(mail, 'all-locales'), 'w') as f: - f.write(MAIL_ALL_LOCALES) - with open(mozpath.join(mail, 'filter.py'), 'w') as f: - f.write(MAIL_FILTER_PY) - with open(mozpath.join(toolkit, 'l10n.ini'), 'w') as f: - f.write(TOOLKIT_INI) - with open(mozpath.join(mail, 'en-US', 'mail.ftl'), 'w') as f: - f.write('') - with open(mozpath.join(toolkit, 'en-US', 'platform.ftl'), 'w') as f: - f.write('') - with open(mozpath.join(l10n, 'localized.ftl'), 'w') as f: - f.write('') - - def tearDown(self): - shutil.rmtree(self.stage) - - def test_app(self): - 'Test parsing a App' - app = EnumerateApp( - mozpath.join(self.stage, 'comm', 'mail', 'locales', 'l10n.ini'), - mozpath.join(self.stage, 'l10n-central')) - self.assertListEqual(app.config.allLocales(), ['af', 'de', 'fr']) - self.assertEqual(len(app.config.children), 1) - projectconfig = app.asConfig() - self.assertListEqual(projectconfig.locales, ['af', 'de', 'fr']) - files = ProjectFiles('de', [projectconfig]) - files = list(files) - self.assertEqual(len(files), 3) - - l10nfile, reffile, mergefile, test = files[0] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'mail', 'mail.ftl']) - self.assertListEqual(mozpath.split(reffile)[-4:], - ['mail', 'locales', 'en-US', 'mail.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) - - l10nfile, reffile, mergefile, test = files[1] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'toolkit', 'localized.ftl']) - self.assertListEqual( - mozpath.split(reffile)[-6:], - ['comm', 'mozilla', 'toolkit', - 'locales', 'en-US', 'localized.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) - - l10nfile, reffile, mergefile, test = files[2] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'toolkit', 'platform.ftl']) - self.assertListEqual( - mozpath.split(reffile)[-6:], - ['comm', 'mozilla', 'toolkit', 'locales', 'en-US', 'platform.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) - - def test_src_app(self): - 'Test parsing a App in source setup' - # move toolkit to toplevel - shutil.move(mozpath.join(self.stage, 'comm', 'mozilla'), self.stage) - app = EnumerateSourceTreeApp( - mozpath.join(self.stage, 'comm', 'mail', 'locales', 'l10n.ini'), - self.stage, - mozpath.join(self.stage, 'l10n-central'), - { - 'mozilla-central': mozpath.join(self.stage, 'mozilla') - } - ) - self.assertListEqual(app.config.allLocales(), ['af', 'de', 'fr']) - self.assertEqual(len(app.config.children), 1) - projectconfig = app.asConfig() - self.assertListEqual(projectconfig.locales, ['af', 'de', 'fr']) - files = ProjectFiles('de', [projectconfig]) - files = list(files) - self.assertEqual(len(files), 3) - - l10nfile, reffile, mergefile, test = files[0] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'mail', 'mail.ftl']) - self.assertListEqual(mozpath.split(reffile)[-4:], - ['mail', 'locales', 'en-US', 'mail.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) - - l10nfile, reffile, mergefile, test = files[1] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'toolkit', 'localized.ftl']) - self.assertListEqual( - mozpath.split(reffile)[-5:], - ['mozilla', 'toolkit', - 'locales', 'en-US', 'localized.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) - - l10nfile, reffile, mergefile, test = files[2] - self.assertListEqual(mozpath.split(l10nfile)[-3:], - ['de', 'toolkit', 'platform.ftl']) - self.assertListEqual( - mozpath.split(reffile)[-5:], - ['mozilla', 'toolkit', 'locales', 'en-US', 'platform.ftl']) - self.assertIsNone(mergefile) - self.assertSetEqual(test, set()) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_checks.py b/third_party/python/compare-locales/compare_locales/tests/test_checks.py deleted file mode 100644 index 193ac60c6b31..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_checks.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales.checks.base import CSSCheckMixin - - -class CSSParserTest(unittest.TestCase): - def setUp(self): - self.mixin = CSSCheckMixin() - - def test_other(self): - refMap, errors = self.mixin.parse_css_spec('foo') - self.assertIsNone(refMap) - self.assertIsNone(errors) - - def test_css_specs(self): - for prop in ( - 'min-width', 'width', 'max-width', - 'min-height', 'height', 'max-height', - ): - refMap, errors = self.mixin.parse_css_spec('{}:1px;'.format(prop)) - self.assertDictEqual( - refMap, {prop: 'px'} - ) - self.assertIsNone(errors) - - def test_single_whitespace(self): - refMap, errors = self.mixin.parse_css_spec('width:15px;') - self.assertDictEqual( - refMap, {'width': 'px'} - ) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec('width : \t 15px ; ') - self.assertDictEqual( - refMap, {'width': 'px'} - ) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec('width: 15px') - self.assertDictEqual( - refMap, {'width': 'px'} - ) - self.assertIsNone(errors) - - def test_multiple(self): - refMap, errors = self.mixin.parse_css_spec('width:15px;height:20.2em;') - self.assertDictEqual( - refMap, {'height': 'em', 'width': 'px'} - ) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec( - 'width:15px \t\t; height:20em' - ) - self.assertDictEqual( - refMap, {'height': 'em', 'width': 'px'} - ) - self.assertIsNone(errors) - - def test_errors(self): - refMap, errors = self.mixin.parse_css_spec('width:15pxfoo') - self.assertDictEqual( - refMap, {'width': 'px'} - ) - self.assertListEqual( - errors, [{'pos': 10, 'code': 'css-bad-content'}] - ) - refMap, errors = self.mixin.parse_css_spec('width:15px height:20em') - self.assertDictEqual( - refMap, {'height': 'em', 'width': 'px'} - ) - self.assertListEqual( - errors, [{'pos': 10, 'code': 'css-missing-semicolon'}] - ) - refMap, errors = self.mixin.parse_css_spec('witdth:15px') - self.assertIsNone(refMap) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec('width:1,5px') - self.assertIsNone(refMap) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec('width:1.5.1px') - self.assertIsNone(refMap) - self.assertIsNone(errors) - refMap, errors = self.mixin.parse_css_spec('width:1.px') - self.assertIsNone(refMap) - self.assertIsNone(errors) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_compare.py b/third_party/python/compare-locales/compare_locales/tests/test_compare.py deleted file mode 100644 index acc47cff6808..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_compare.py +++ /dev/null @@ -1,229 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales import compare, paths - - -class TestTree(unittest.TestCase): - '''Test the Tree utility class - - Tree value classes need to be in-place editable - ''' - - def test_empty_dict(self): - tree = compare.Tree(dict) - self.assertEqual(list(tree.getContent()), []) - self.assertDictEqual( - tree.toJSON(), - {} - ) - - def test_disjoint_dict(self): - tree = compare.Tree(dict) - tree['one/entry']['leaf'] = 1 - tree['two/other']['leaf'] = 2 - self.assertEqual( - list(tree.getContent()), - [ - (0, 'key', ('one', 'entry')), - (1, 'value', {'leaf': 1}), - (0, 'key', ('two', 'other')), - (1, 'value', {'leaf': 2}) - ] - ) - self.assertDictEqual( - tree.toJSON(), - { - 'one/entry': - {'leaf': 1}, - 'two/other': - {'leaf': 2} - } - ) - self.assertMultiLineEqual( - str(tree), - '''\ -one/entry - {'leaf': 1} -two/other - {'leaf': 2}\ -''' - ) - - def test_overlapping_dict(self): - tree = compare.Tree(dict) - tree['one/entry']['leaf'] = 1 - tree['one/other']['leaf'] = 2 - self.assertEqual( - list(tree.getContent()), - [ - (0, 'key', ('one',)), - (1, 'key', ('entry',)), - (2, 'value', {'leaf': 1}), - (1, 'key', ('other',)), - (2, 'value', {'leaf': 2}) - ] - ) - self.assertDictEqual( - tree.toJSON(), - { - 'one': { - 'entry': - {'leaf': 1}, - 'other': - {'leaf': 2} - } - } - ) - - -class TestObserver(unittest.TestCase): - def test_simple(self): - obs = compare.Observer() - f = paths.File('/some/real/sub/path', 'de/sub/path', locale='de') - obs.notify('missingEntity', f, 'one') - obs.notify('missingEntity', f, 'two') - obs.updateStats(f, {'missing': 15}) - self.assertDictEqual(obs.toJSON(), { - 'summary': { - 'de': { - 'errors': 0, - 'warnings': 0, - 'missing': 15, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - }, - 'details': { - 'de/sub/path': - [{'missingEntity': 'one'}, - {'missingEntity': 'two'}] - } - }) - - def test_module(self): - obs = compare.Observer() - f = paths.File('/some/real/sub/path', 'path', - module='sub', locale='de') - obs.notify('missingEntity', f, 'one') - obs.notify('obsoleteEntity', f, 'bar') - obs.notify('missingEntity', f, 'two') - obs.updateStats(f, {'missing': 15}) - self.assertDictEqual(obs.toJSON(), { - 'summary': { - 'de': { - 'errors': 0, - 'warnings': 0, - 'missing': 15, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - }, - 'details': { - 'de/sub/path': - [ - {'missingEntity': 'one'}, - {'obsoleteEntity': 'bar'}, - {'missingEntity': 'two'}, - ] - } - }) - - -class TestAddRemove(unittest.TestCase): - - def _test(self, left, right, ref_actions): - ar = compare.AddRemove() - ar.set_left(left) - ar.set_right(right) - actions = list(ar) - self.assertListEqual(actions, ref_actions) - - def test_equal(self): - self._test(['z', 'a', 'p'], ['z', 'a', 'p'], [ - ('equal', 'z'), - ('equal', 'a'), - ('equal', 'p'), - ]) - - def test_add_start(self): - self._test(['a', 'p'], ['z', 'a', 'p'], [ - ('add', 'z'), - ('equal', 'a'), - ('equal', 'p'), - ]) - - def test_add_middle(self): - self._test(['z', 'p'], ['z', 'a', 'p'], [ - ('equal', 'z'), - ('add', 'a'), - ('equal', 'p'), - ]) - - def test_add_end(self): - self._test(['z', 'a'], ['z', 'a', 'p'], [ - ('equal', 'z'), - ('equal', 'a'), - ('add', 'p'), - ]) - - def test_delete_start(self): - self._test(['z', 'a', 'p'], ['a', 'p'], [ - ('delete', 'z'), - ('equal', 'a'), - ('equal', 'p'), - ]) - - def test_delete_middle(self): - self._test(['z', 'a', 'p'], ['z', 'p'], [ - ('equal', 'z'), - ('delete', 'a'), - ('equal', 'p'), - ]) - - def test_delete_end(self): - self._test(['z', 'a', 'p'], ['z', 'a'], [ - ('equal', 'z'), - ('equal', 'a'), - ('delete', 'p'), - ]) - - def test_replace_start(self): - self._test(['b', 'a', 'p'], ['z', 'a', 'p'], [ - ('add', 'z'), - ('delete', 'b'), - ('equal', 'a'), - ('equal', 'p'), - ]) - - def test_replace_middle(self): - self._test(['z', 'b', 'p'], ['z', 'a', 'p'], [ - ('equal', 'z'), - ('add', 'a'), - ('delete', 'b'), - ('equal', 'p'), - ]) - - def test_replace_end(self): - self._test(['z', 'a', 'b'], ['z', 'a', 'p'], [ - ('equal', 'z'), - ('equal', 'a'), - ('add', 'p'), - ('delete', 'b'), - ]) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_defines.py b/third_party/python/compare-locales/compare_locales/tests/test_defines.py deleted file mode 100644 index 6f903d82d5e3..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_defines.py +++ /dev/null @@ -1,251 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from compare_locales.tests import ParserTestMixin, BaseHelper -from compare_locales.paths import File -from compare_locales.parser import ( - Comment, - DefinesInstruction, - Junk, - Whitespace, -) - - -mpl2 = '''\ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/.''' - - -class TestDefinesParser(ParserTestMixin, unittest.TestCase): - - filename = 'defines.inc' - - def testBrowser(self): - self._test(mpl2 + ''' -#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -# If non-English locales wish to credit multiple contributors, uncomment this -# variable definition and use the format specified. -# #define MOZ_LANGPACK_CONTRIBUTORS Joe Solon - -#unfilter emptyLines - -''', ( - (Comment, mpl2), - (Whitespace, '\n'), - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n\n'), - (Comment, '#define'), - (Whitespace, '\n\n'), - (DefinesInstruction, 'unfilter emptyLines'), - (Junk, '\n\n'))) - - def testBrowserWithContributors(self): - self._test(mpl2 + ''' -#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -# If non-English locales wish to credit multiple contributors, uncomment this -# variable definition and use the format specified. -#define MOZ_LANGPACK_CONTRIBUTORS Joe Solon - -#unfilter emptyLines - -''', ( - (Comment, mpl2), - (Whitespace, '\n'), - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n\n'), - ( - 'MOZ_LANGPACK_CONTRIBUTORS', - 'Joe Solon', - 'non-English', - ), - (Whitespace, '\n\n'), - (DefinesInstruction, 'unfilter emptyLines'), - (Junk, '\n\n'))) - - def testCommentWithNonAsciiCharacters(self): - self._test(mpl2 + ''' -#filter emptyLines - -# e.g. #define seamonkey_l10n
    SeaMonkey v češtině -#define seamonkey_l10n_long - -#unfilter emptyLines - -''', ( - (Comment, mpl2), - (Whitespace, '\n'), - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n\n'), - ('seamonkey_l10n_long', '', 'češtině'), - (Whitespace, '\n\n'), - (DefinesInstruction, 'unfilter emptyLines'), - (Junk, '\n\n'))) - - def test_no_empty_lines(self): - self._test('''#define MOZ_LANGPACK_CREATOR mozilla.org -#define MOZ_LANGPACK_CREATOR mozilla.org -''', ( - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'))) - - def test_empty_line_between(self): - self._test('''#define MOZ_LANGPACK_CREATOR mozilla.org - -#define MOZ_LANGPACK_CREATOR mozilla.org -''', ( - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Junk, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'))) - - def test_empty_line_at_the_beginning(self): - self._test(''' -#define MOZ_LANGPACK_CREATOR mozilla.org -#define MOZ_LANGPACK_CREATOR mozilla.org -''', ( - (Junk, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'))) - - def test_filter_empty_lines(self): - self._test('''#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org -#define MOZ_LANGPACK_CREATOR mozilla.org -#unfilter emptyLines''', ( - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - (DefinesInstruction, 'unfilter emptyLines'))) - - def test_unfilter_empty_lines_with_trailing(self): - self._test('''#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org -#define MOZ_LANGPACK_CREATOR mozilla.org -#unfilter emptyLines -''', ( - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - ('MOZ_LANGPACK_CREATOR', 'mozilla.org'), - (Whitespace, '\n'), - (DefinesInstruction, 'unfilter emptyLines'), - (Whitespace, '\n'))) - - def testToolkit(self): - self._test('''#define MOZ_LANG_TITLE English (US) -''', ( - ('MOZ_LANG_TITLE', 'English (US)'), - (Whitespace, '\n'))) - - def testToolkitEmpty(self): - self._test('', tuple()) - - def test_empty_file(self): - '''Test that empty files generate errors - - defines.inc are interesting that way, as their - content is added to the generated file. - ''' - self._test('\n', ((Junk, '\n'),)) - self._test('\n\n', ((Junk, '\n\n'),)) - self._test(' \n\n', ((Junk, ' \n\n'),)) - - def test_whitespace_value(self): - '''Test that there's only one whitespace between key and value - ''' - # funny formatting of trailing whitespace to make it explicit - # and flake-8 happy - self._test('''\ -#define one \n\ -#define two \n\ -#define tre \n\ -''', ( - ('one', ''), - (Whitespace, '\n'), - ('two', ' '), - (Whitespace, '\n'), - ('tre', ' '), - (Whitespace, '\n'),)) - - def test_standalone_comments(self): - self._test( - '''\ -#filter emptyLines -# One comment - -# Second comment - -#define foo -# bar comment -#define bar - -#unfilter emptyLines -''', - ( - (DefinesInstruction, 'filter emptyLines'), - (Whitespace, '\n'), - (Comment, 'One comment'), - (Whitespace, '\n\n'), - (Comment, 'Second comment'), - (Whitespace, '\n\n'), - ('foo', ''), - (Whitespace, '\n'), - ('bar', '', 'bar comment'), - (Whitespace, '\n\n'), - (DefinesInstruction, 'unfilter emptyLines'), - (Whitespace, '\n'), - ) - ) - - -class TestChecks(BaseHelper): - file = File('defines.inc', 'defines.inc') - refContent = b'''\ -#define foo bar -''' - - def test_ok(self): - self._test( - b'#define foo other', - tuple() - ) - - def test_bad_encoding(self): - self._test( - '#define foo touché'.encode('latin-1'), - ( - ( - "warning", - 17, - "\ufffd in: foo", - "encodings" - ), - ) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_ini.py b/third_party/python/compare-locales/compare_locales/tests/test_ini.py deleted file mode 100644 index e5d68482c102..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_ini.py +++ /dev/null @@ -1,223 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals -import unittest - -from compare_locales.tests import ParserTestMixin, BaseHelper -from compare_locales.paths import File -from compare_locales.parser import ( - Comment, - IniSection, - Junk, - Whitespace, -) - - -mpl2 = '''\ -; This Source Code Form is subject to the terms of the Mozilla Public -; License, v. 2.0. If a copy of the MPL was not distributed with this file, -; You can obtain one at http://mozilla.org/MPL/2.0/.''' - - -class TestIniParser(ParserTestMixin, unittest.TestCase): - - filename = 'foo.ini' - - def testSimpleHeader(self): - self._test('''; This file is in the UTF-8 encoding -[Strings] -TitleText=Some Title -''', ( - (Comment, 'UTF-8 encoding'), - (Whitespace, '\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def testMPL2_Space_UTF(self): - self._test(mpl2 + ''' - -; This file is in the UTF-8 encoding -[Strings] -TitleText=Some Title -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (Comment, 'UTF-8'), - (Whitespace, '\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def testMPL2_Space(self): - self._test(mpl2 + ''' - -[Strings] -TitleText=Some Title -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def testMPL2_no_space(self): - self._test(mpl2 + ''' -[Strings] -TitleText=Some Title -''', ( - (Comment, mpl2), - (Whitespace, '\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def testMPL2_MultiSpace(self): - self._test(mpl2 + ''' - -; more comments - -[Strings] -TitleText=Some Title -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (Comment, 'more comments'), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def testMPL2_JunkBeforeCategory(self): - self._test(mpl2 + ''' -Junk -[Strings] -TitleText=Some Title -''', ( - (Comment, mpl2), - (Whitespace, '\n'), - (Junk, 'Junk\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'))) - - def test_TrailingComment(self): - self._test(mpl2 + ''' - -[Strings] -TitleText=Some Title -;Stray trailing comment -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n'), - (Comment, 'Stray trailing'), - (Whitespace, '\n'))) - - def test_SpacedTrailingComments(self): - self._test(mpl2 + ''' - -[Strings] -TitleText=Some Title - -;Stray trailing comment -;Second stray comment - -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n\n'), - (Comment, 'Second stray comment'), - (Whitespace, '\n\n'))) - - def test_TrailingCommentsAndJunk(self): - self._test(mpl2 + ''' - -[Strings] -TitleText=Some Title - -;Stray trailing comment -Junk -;Second stray comment - -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n\n'), - (Comment, 'Stray trailing'), - (Whitespace, '\n'), - (Junk, 'Junk\n'), - (Comment, 'Second stray comment'), - (Whitespace, '\n\n'))) - - def test_JunkInbetweenEntries(self): - self._test(mpl2 + ''' - -[Strings] -TitleText=Some Title - -Junk - -Good=other string -''', ( - (Comment, mpl2), - (Whitespace, '\n\n'), - (IniSection, 'Strings'), - (Whitespace, '\n'), - ('TitleText', 'Some Title'), - (Whitespace, '\n\n'), - (Junk, 'Junk\n\n'), - ('Good', 'other string'), - (Whitespace, '\n'))) - - def test_empty_file(self): - self._test('', tuple()) - self._test('\n', ((Whitespace, '\n'),)) - self._test('\n\n', ((Whitespace, '\n\n'),)) - self._test(' \n\n', ((Whitespace, ' \n\n'),)) - - -class TestChecks(BaseHelper): - file = File('foo.ini', 'foo.ini') - refContent = b'''\ -[Strings] -foo=good -''' - - def test_ok(self): - self._test( - b'[Strings]\nfoo=other', - tuple() - ) - - def test_bad_encoding(self): - self._test( - 'foo=touché'.encode('latin-1'), - ( - ( - "warning", - 9, - "\ufffd in: foo", - "encodings" - ), - ) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_keyedtuple.py b/third_party/python/compare-locales/compare_locales/tests/test_keyedtuple.py deleted file mode 100644 index 156a8e868ca2..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_keyedtuple.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from __future__ import unicode_literals - -from collections import namedtuple -import unittest - -from compare_locales.keyedtuple import KeyedTuple - - -KeyedThing = namedtuple('KeyedThing', ['key', 'val']) - - -class TestKeyedTuple(unittest.TestCase): - def test_constructor(self): - keyedtuple = KeyedTuple([]) - self.assertEqual(keyedtuple, tuple()) - - def test_contains(self): - things = [KeyedThing('one', 'thing'), KeyedThing('two', 'things')] - keyedtuple = KeyedTuple(things) - self.assertNotIn(1, keyedtuple) - self.assertIn('one', keyedtuple) - self.assertIn(things[0], keyedtuple) - self.assertIn(things[1], keyedtuple) - self.assertNotIn(KeyedThing('three', 'stooges'), keyedtuple) - - def test_getitem(self): - things = [KeyedThing('one', 'thing'), KeyedThing('two', 'things')] - keyedtuple = KeyedTuple(things) - self.assertEqual(keyedtuple[0], things[0]) - self.assertEqual(keyedtuple[1], things[1]) - self.assertEqual(keyedtuple['one'], things[0]) - self.assertEqual(keyedtuple['two'], things[1]) - - def test_items(self): - things = [KeyedThing('one', 'thing'), KeyedThing('two', 'things')] - things.extend(things) - keyedtuple = KeyedTuple(things) - self.assertEqual(len(keyedtuple), 4) - items = list(keyedtuple.items()) - self.assertEqual(len(items), 4) - self.assertEqual( - keyedtuple, - tuple((v for k, v in items)) - ) - self.assertEqual( - ('one', 'two', 'one', 'two',), - tuple((k for k, v in items)) - ) diff --git a/third_party/python/compare-locales/compare_locales/tests/test_merge.py b/third_party/python/compare-locales/compare_locales/tests/test_merge.py deleted file mode 100644 index a10a04ca16a1..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_merge.py +++ /dev/null @@ -1,1408 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest -import filecmp -import os -from tempfile import mkdtemp -import shutil - -from compare_locales.parser import getParser -from compare_locales.paths import File -from compare_locales.compare.content import ContentComparer -from compare_locales.compare.observer import Observer -from compare_locales import mozpath - - -class ContentMixin(object): - extension = None # OVERLOAD - - @property - def ref(self): - return mozpath.join(self.tmp, "en-reference" + self.extension) - - @property - def l10n(self): - return mozpath.join(self.tmp, "l10n" + self.extension) - - def reference(self, content): - with open(self.ref, "w") as f: - f.write(content) - - def localized(self, content): - with open(self.l10n, "w") as f: - f.write(content) - - -class TestNonSupported(unittest.TestCase, ContentMixin): - extension = '.js' - - def setUp(self): - self.maxDiff = None - self.tmp = mkdtemp() - os.mkdir(mozpath.join(self.tmp, "merge")) - - def tearDown(self): - shutil.rmtree(self.tmp) - del self.tmp - - def test_good(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = 'fooVal';""") - self.localized("""foo = 'lfoo';""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.js", ""), - File(self.l10n, "l10n.js", ""), - mozpath.join(self.tmp, "merge", "l10n.js")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': {}, - 'details': {} - } - ) - self.assertTrue(filecmp.cmp( - self.l10n, - mozpath.join(self.tmp, "merge", 'l10n.js')) - ) - - def test_missing(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = 'fooVal';""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.add(File(self.ref, "en-reference.js", ""), - File(self.l10n, "l10n.js", ""), - mozpath.join(self.tmp, "merge", "l10n.js")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': {}, - 'details': {'l10n.js': [{'missingFile': 'error'}]} - } - ) - self.assertTrue(filecmp.cmp( - self.ref, - mozpath.join(self.tmp, "merge", 'l10n.js')) - ) - - def test_missing_ignored(self): - - def ignore(*args): - return 'ignore' - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = 'fooVal';""") - cc = ContentComparer() - cc.observers.append(Observer(filter=ignore)) - cc.add(File(self.ref, "en-reference.js", ""), - File(self.l10n, "l10n.js", ""), - mozpath.join(self.tmp, "merge", "l10n.js")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': {}, - 'details': {} - } - ) - self.assertTrue(filecmp.cmp( - self.ref, - mozpath.join(self.tmp, "merge", 'l10n.js')) - ) - - -class TestDefines(unittest.TestCase, ContentMixin): - '''Test case for parsers with just CAN_COPY''' - extension = '.inc' - - def setUp(self): - self.maxDiff = None - self.tmp = mkdtemp() - os.mkdir(mozpath.join(self.tmp, "merge")) - - def tearDown(self): - shutil.rmtree(self.tmp) - del self.tmp - - def testGood(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -#define MOZ_LANGPACK_CONTRIBUTORS Suzy Solon - -#unfilter emptyLines -""") - self.localized("""#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -#define MOZ_LANGPACK_CONTRIBUTORS Jane Doe - -#unfilter emptyLines -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.inc", ""), - File(self.l10n, "l10n.inc", ""), - mozpath.join(self.tmp, "merge", "l10n.inc")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 2, - 'unchanged': 1, - 'unchanged_w': 1, - 'keys': 0, - }}, - 'details': {} - } - ) - self.assertTrue(filecmp.cmp( - self.l10n, - mozpath.join(self.tmp, "merge", 'l10n.inc')) - ) - - def testMissing(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -#define MOZ_LANGPACK_CONTRIBUTORS Suzy Solon - -#unfilter emptyLines -""") - self.localized("""#filter emptyLines - -#define MOZ_LANGPACK_CREATOR mozilla.org - -#unfilter emptyLines -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.inc", ""), - File(self.l10n, "l10n.inc", ""), - mozpath.join(self.tmp, "merge", "l10n.inc")) - self.assertDictEqual( - cc.observers.toJSON(), - { - 'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 1, - 'missing_w': 2, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 1, - 'unchanged_w': 1, - 'keys': 0, - }}, - 'details': - { - 'l10n.inc': [ - {'missingEntity': 'MOZ_LANGPACK_CONTRIBUTORS'} - ] - } - } - ) - self.assertTrue(filecmp.cmp( - self.ref, - mozpath.join(self.tmp, "merge", 'l10n.inc')) - ) - - -class TestProperties(unittest.TestCase, ContentMixin): - extension = '.properties' - - def setUp(self): - self.maxDiff = None - self.tmp = mkdtemp() - os.mkdir(mozpath.join(self.tmp, "merge")) - - def tearDown(self): - shutil.rmtree(self.tmp) - del self.tmp - - def testGood(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal word -bar = barVal word -eff = effVal""") - self.localized("""foo = lFoo -bar = lBar -eff = lEff word -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 5, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - - }}, - 'details': {} - } - ) - self.assertTrue(filecmp.cmp( - self.l10n, - mozpath.join(self.tmp, "merge", 'l10n.properties')) - ) - - def testMissing(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -bar = barVal -eff = effVal""") - self.localized("""bar = lBar -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 2, - 'missing_w': 2, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.properties': [ - {'missingEntity': u'foo'}, - {'missingEntity': u'eff'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(os.path.isfile(mergefile)) - p = getParser(mergefile) - p.readFile(mergefile) - entities = p.parse() - self.assertEqual(list(entities.keys()), ["bar", "foo", "eff"]) - - def test_missing_file(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -bar = barVal -eff = effVal""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.add(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 3, - 'missing_w': 3, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.properties': [ - {'missingFile': 'error'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(filecmp.cmp(self.ref, mergefile)) - - def testError(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -bar = %d barVal -eff = effVal""") - self.localized("""\ -bar = %S lBar -eff = leffVal -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 1, - 'warnings': 0, - 'missing': 1, - 'missing_w': 1, - 'report': 0, - 'obsolete': 0, - 'changed': 2, - 'changed_w': 3, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.properties': [ - {'missingEntity': u'foo'}, - {'error': u'argument 1 `S` should be `d` ' - u'at line 1, column 7 for bar'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(os.path.isfile(mergefile)) - p = getParser(mergefile) - p.readFile(mergefile) - entities = p.parse() - self.assertEqual(list(entities.keys()), ["eff", "foo", "bar"]) - self.assertEqual(entities['bar'].val, '%d barVal') - - def testObsolete(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -eff = effVal""") - self.localized("""foo = fooVal -other = obsolete -eff = leffVal -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 1, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 1, - 'unchanged_w': 1, - 'keys': 0, - }}, - 'details': { - 'l10n.properties': [ - {'obsoleteEntity': u'other'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - def test_obsolete_file(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.localized("""foo = fooVal -eff = leffVal -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.remove(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {}, - 'details': { - 'l10n.properties': [ - {'obsoleteFile': u'error'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(os.path.isfile(mergefile)) - - def test_duplicate(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -bar = barVal -eff = effVal -foo = other val for foo""") - self.localized("""foo = localized -bar = lBar -eff = localized eff -bar = duplicated bar -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.properties", ""), - File(self.l10n, "l10n.properties", ""), - mozpath.join(self.tmp, "merge", "l10n.properties")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 1, - 'warnings': 1, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 6, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.properties': [ - {'warning': u'foo occurs 2 times'}, - {'error': u'bar occurs 2 times'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.properties") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - -class TestDTD(unittest.TestCase, ContentMixin): - extension = '.dtd' - - def setUp(self): - self.maxDiff = None - self.tmp = mkdtemp() - os.mkdir(mozpath.join(self.tmp, "merge")) - - def tearDown(self): - shutil.rmtree(self.tmp) - del self.tmp - - def testGood(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference(""" - -""") - self.localized(""" - - -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.dtd", ""), - File(self.l10n, "l10n.dtd", ""), - mozpath.join(self.tmp, "merge", "l10n.dtd")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 3, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': {} - } - ) - self.assertTrue(filecmp.cmp( - self.l10n, - mozpath.join(self.tmp, "merge", 'l10n.dtd')) - ) - - def testMissing(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference(""" - -""") - self.localized(""" -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.dtd", ""), - File(self.l10n, "l10n.dtd", ""), - mozpath.join(self.tmp, "merge", "l10n.dtd")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 2, - 'missing_w': 2, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.dtd': [ - {'missingEntity': u'foo'}, - {'missingEntity': u'eff'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") - self.assertTrue(os.path.isfile(mergefile)) - p = getParser(mergefile) - p.readFile(mergefile) - entities = p.parse() - self.assertEqual(list(entities.keys()), ["bar", "foo", "eff"]) - - def testJunk(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference(""" - -""") - self.localized(""" - - -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.dtd", ""), - File(self.l10n, "l10n.dtd", ""), - mozpath.join(self.tmp, "merge", "l10n.dtd")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 1, - 'warnings': 0, - 'missing': 1, - 'missing_w': 1, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 2, - 'unchanged_w': 2, - 'keys': 0, - }}, - 'details': { - 'l10n.dtd': [ - {'error': u'Unparsed content "\n" ' - u'from line 2 column 1 to ' - u'line 3 column 1'}, - {'missingEntity': u'bar'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") - self.assertTrue(os.path.isfile(mergefile)) - p = getParser(mergefile) - p.readFile(mergefile) - entities = p.parse() - self.assertEqual(list(entities.keys()), ["foo", "eff", "bar"]) - - def test_reference_junk(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference(""" - -""") - self.localized(""" - -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.dtd", ""), - File(self.l10n, "l10n.dtd", ""), - mozpath.join(self.tmp, "merge", "l10n.dtd")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 1, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 0, - 'changed_w': 0, - 'unchanged': 2, - 'unchanged_w': 2, - 'keys': 0, - }}, - 'details': { - 'l10n.dtd': [ - {'warning': 'Parser error in en-US'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - def test_reference_xml_error(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference(""" - -""") - self.localized(""" - - -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.dtd", ""), - File(self.l10n, "l10n.dtd", ""), - mozpath.join(self.tmp, "merge", "l10n.dtd")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 1, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 2, - 'unchanged': 2, - 'unchanged_w': 2, - 'keys': 0, - }}, - 'details': { - 'l10n.dtd': [ - {'warning': u"can't parse en-US value at line 1, " - u"column 0 for bar"}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.dtd") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - -class TestFluent(unittest.TestCase): - maxDiff = None # we got big dictionaries to compare - - def reference(self, content): - self.ref = os.path.join(self.tmp, "en-reference.ftl") - with open(self.ref, "w") as f: - f.write(content) - - def localized(self, content): - self.l10n = os.path.join(self.tmp, "l10n.ftl") - with open(self.l10n, "w") as f: - f.write(content) - - def setUp(self): - self.tmp = mkdtemp() - os.mkdir(os.path.join(self.tmp, "merge")) - self.ref = self.l10n = None - - def tearDown(self): - shutil.rmtree(self.tmp) - del self.tmp - del self.ref - del self.l10n - - def testGood(self): - self.reference("""\ -foo = fooVal -bar = barVal --eff = effVal -""") - self.localized("""\ -foo = lFoo -bar = lBar --eff = lEff -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 3, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': {} - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testMissing(self): - self.reference("""\ -foo = fooVal -bar = barVal --baz = bazVal -eff = effVal -""") - self.localized("""\ -foo = lFoo -eff = lEff -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - {'missingEntity': u'bar'}, - {'missingEntity': u'-baz'}, - ], - }, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 2, - 'missing_w': 2, - 'report': 0, - 'obsolete': 0, - 'changed': 2, - 'changed_w': 2, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testBroken(self): - self.reference("""\ -foo = fooVal -bar = barVal -eff = effVal -""") - self.localized("""\ --- Invalid Comment -foo = lFoo -bar lBar -eff = lEff { -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - {'error': u'Unparsed content "-- Invalid Comment" ' - u'from line 1 column 1 ' - u'to line 1 column 19'}, - {'error': u'Unparsed content "bar lBar" ' - u'from line 3 column 1 ' - u'to line 3 column 9'}, - {'error': u'Unparsed content "eff = lEff {" ' - u'from line 4 column 1 ' - u'to line 4 column 13'}, - {'missingEntity': u'bar'}, - {'missingEntity': u'eff'}, - ], - }, - 'summary': { - None: { - 'errors': 3, - 'warnings': 0, - 'missing': 2, - 'missing_w': 2, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(os.path.exists(mergepath)) - - p = getParser(mergepath) - p.readFile(mergepath) - merged_entities = p.parse() - self.assertEqual(list(merged_entities.keys()), ["foo"]) - merged_foo = merged_entities['foo'] - - # foo should be l10n - p.readFile(self.l10n) - l10n_entities = p.parse() - l10n_foo = l10n_entities['foo'] - self.assertTrue(merged_foo.equals(l10n_foo)) - - def testMatchingReferences(self): - self.reference("""\ -foo = Reference { bar } -""") - self.localized("""\ -foo = Localized { bar } -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': {}, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testMismatchingReferences(self): - self.reference("""\ -foo = Reference { bar } -bar = Reference { baz } -baz = Reference -""") - self.localized("""\ -foo = Localized { qux } -bar = Localized -baz = Localized { qux } -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - { - 'warning': - u'Missing message reference: bar ' - u'at line 1, column 1 for foo' - }, - { - 'warning': - u'Obsolete message reference: qux ' - u'at line 1, column 19 for foo' - }, - { - 'warning': - u'Missing message reference: baz ' - u'at line 2, column 1 for bar' - }, - { - 'warning': - u'Obsolete message reference: qux ' - u'at line 3, column 19 for baz' - }, - ], - }, - 'summary': { - None: { - 'errors': 0, - 'warnings': 4, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 3, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testMismatchingAttributes(self): - self.reference(""" -foo = Foo -bar = Bar - .tender = Attribute value -eff = Eff -""") - self.localized("""\ -foo = lFoo - .obsolete = attr -bar = lBar -eff = lEff -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - { - 'error': - u'Obsolete attribute: ' - 'obsolete at line 2, column 3 for foo' - }, - { - 'error': - u'Missing attribute: tender at line 3,' - ' column 1 for bar', - }, - ], - }, - 'summary': { - None: { - 'errors': 2, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 5, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(os.path.exists(mergepath)) - - p = getParser(mergepath) - p.readFile(mergepath) - merged_entities = p.parse() - self.assertEqual(list(merged_entities.keys()), ["eff"]) - merged_eff = merged_entities['eff'] - - # eff should be l10n - p.readFile(self.l10n) - l10n_entities = p.parse() - l10n_eff = l10n_entities['eff'] - self.assertTrue(merged_eff.equals(l10n_eff)) - - def test_term_attributes(self): - self.reference(""" --foo = Foo --bar = Bar --baz = Baz - .attr = Baz Attribute --qux = Qux - .attr = Qux Attribute --missing = Missing - .attr = An Attribute -""") - self.localized("""\ --foo = Localized Foo --bar = Localized Bar - .attr = Locale-specific Bar Attribute --baz = Localized Baz --qux = Localized Qux - .other = Locale-specific Qux Attribute -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - {'missingEntity': u'-missing'}, - ], - }, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 1, - 'missing_w': 1, - 'report': 0, - 'obsolete': 0, - 'changed': 4, - 'changed_w': 4, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testMismatchingValues(self): - self.reference(""" -foo = Foo - .foottr = something -bar = - .tender = Attribute value -""") - self.localized("""\ -foo = - .foottr = attr -bar = lBar - .tender = localized -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': { - 'l10n.ftl': [ - { - 'error': - u'Missing value at line 1, column 1 for foo' - }, - { - 'error': - u'Obsolete value at line 3, column 7 for bar', - }, - ] - }, - 'summary': { - None: { - 'errors': 2, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 2, - 'changed_w': 4, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(os.path.exists(mergepath)) - - p = getParser(mergepath) - p.readFile(mergepath) - merged_entities = p.parse() - self.assertEqual(merged_entities, tuple()) - - def testMissingGroupComment(self): - self.reference("""\ -foo = fooVal - -## Group Comment -bar = barVal -""") - self.localized("""\ -foo = lFoo -bar = lBar -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': {}, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 2, - 'changed_w': 2, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testMissingAttachedComment(self): - self.reference("""\ -foo = fooVal - -# Attached Comment -bar = barVal -""") - self.localized("""\ -foo = lFoo -bar = barVal -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': {}, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 1, - 'unchanged': 1, - 'unchanged_w': 1, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def testObsoleteStandaloneComment(self): - self.reference("""\ -foo = fooVal -bar = barVal -""") - self.localized("""\ -foo = lFoo - -# Standalone Comment - -bar = lBar -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - - self.assertDictEqual( - cc.observers.toJSON(), - { - 'details': {}, - 'summary': { - None: { - 'errors': 0, - 'warnings': 0, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 2, - 'changed_w': 2, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - } - } - } - ) - - # validate merge results - mergepath = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergepath)) - - def test_duplicate(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal -bar = barVal -eff = effVal -foo = other val for foo""") - self.localized("""foo = localized -bar = lBar -eff = localized eff -bar = duplicated bar -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 1, - 'warnings': 1, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 3, - 'changed_w': 6, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.ftl': [ - {'warning': u'foo occurs 2 times'}, - {'error': u'bar occurs 2 times'}] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - def test_duplicate_attributes(self): - self.assertTrue(os.path.isdir(self.tmp)) - self.reference("""foo = fooVal - .attr = good""") - self.localized("""foo = localized - .attr = not - .attr = so - .attr = good -""") - cc = ContentComparer() - cc.observers.append(Observer()) - cc.compare(File(self.ref, "en-reference.ftl", ""), - File(self.l10n, "l10n.ftl", ""), - mozpath.join(self.tmp, "merge", "l10n.ftl")) - self.assertDictEqual( - cc.observers.toJSON(), - {'summary': - {None: { - 'errors': 0, - 'warnings': 3, - 'missing': 0, - 'missing_w': 0, - 'report': 0, - 'obsolete': 0, - 'changed': 1, - 'changed_w': 2, - 'unchanged': 0, - 'unchanged_w': 0, - 'keys': 0, - }}, - 'details': { - 'l10n.ftl': [ - {'warning': - u'Attribute "attr" is duplicated ' - u'at line 2, column 5 for foo' - }, - {'warning': - u'Attribute "attr" is duplicated ' - u'at line 3, column 5 for foo' - }, - {'warning': - u'Attribute "attr" is duplicated ' - u'at line 4, column 5 for foo' - }, - ] - } - }) - mergefile = mozpath.join(self.tmp, "merge", "l10n.ftl") - self.assertTrue(filecmp.cmp(self.l10n, mergefile)) - - -if __name__ == '__main__': - unittest.main() diff --git a/third_party/python/compare-locales/compare_locales/tests/test_mozpath.py b/third_party/python/compare-locales/compare_locales/tests/test_mozpath.py deleted file mode 100644 index d4bf9ec4b229..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_mozpath.py +++ /dev/null @@ -1,139 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -from compare_locales.mozpath import ( - relpath, - join, - normpath, - dirname, - commonprefix, - basename, - split, - splitext, - basedir, - match, - rebase, -) -import unittest -import os - - -class TestPath(unittest.TestCase): - SEP = os.sep - - def test_relpath(self): - self.assertEqual(relpath('foo', 'foo'), '') - self.assertEqual(relpath(self.SEP.join(('foo', 'bar')), 'foo/bar'), '') - self.assertEqual(relpath(self.SEP.join(('foo', 'bar')), 'foo'), 'bar') - self.assertEqual(relpath(self.SEP.join(('foo', 'bar', 'baz')), 'foo'), - 'bar/baz') - self.assertEqual(relpath(self.SEP.join(('foo', 'bar')), 'foo/bar/baz'), - '..') - self.assertEqual(relpath(self.SEP.join(('foo', 'bar')), 'foo/baz'), - '../bar') - self.assertEqual(relpath('foo/', 'foo'), '') - self.assertEqual(relpath('foo/bar/', 'foo'), 'bar') - - def test_join(self): - self.assertEqual(join('foo', 'bar', 'baz'), 'foo/bar/baz') - self.assertEqual(join('foo', '', 'bar'), 'foo/bar') - self.assertEqual(join('', 'foo', 'bar'), 'foo/bar') - self.assertEqual(join('', 'foo', '/bar'), '/bar') - - def test_normpath(self): - self.assertEqual(normpath(self.SEP.join(('foo', 'bar', 'baz', - '..', 'qux'))), 'foo/bar/qux') - - def test_dirname(self): - self.assertEqual(dirname('foo/bar/baz'), 'foo/bar') - self.assertEqual(dirname('foo/bar'), 'foo') - self.assertEqual(dirname('foo'), '') - self.assertEqual(dirname('foo/bar/'), 'foo/bar') - - def test_commonprefix(self): - self.assertEqual(commonprefix([self.SEP.join(('foo', 'bar', 'baz')), - 'foo/qux', 'foo/baz/qux']), 'foo/') - self.assertEqual(commonprefix([self.SEP.join(('foo', 'bar', 'baz')), - 'foo/qux', 'baz/qux']), '') - - def test_basename(self): - self.assertEqual(basename('foo/bar/baz'), 'baz') - self.assertEqual(basename('foo/bar'), 'bar') - self.assertEqual(basename('foo'), 'foo') - self.assertEqual(basename('foo/bar/'), '') - - def test_split(self): - self.assertEqual(split(self.SEP.join(('foo', 'bar', 'baz'))), - ['foo', 'bar', 'baz']) - - def test_splitext(self): - self.assertEqual(splitext(self.SEP.join(('foo', 'bar', 'baz.qux'))), - ('foo/bar/baz', '.qux')) - - def test_basedir(self): - foobarbaz = self.SEP.join(('foo', 'bar', 'baz')) - self.assertEqual(basedir(foobarbaz, ['foo', 'bar', 'baz']), 'foo') - self.assertEqual(basedir(foobarbaz, ['foo', 'foo/bar', 'baz']), - 'foo/bar') - self.assertEqual(basedir(foobarbaz, ['foo/bar', 'foo', 'baz']), - 'foo/bar') - self.assertEqual(basedir(foobarbaz, ['foo', 'bar', '']), 'foo') - self.assertEqual(basedir(foobarbaz, ['bar', 'baz', '']), '') - - def test_match(self): - self.assertTrue(match('foo', '')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/bar')) - self.assertTrue(match('foo/bar/baz.qux', 'foo')) - self.assertTrue(match('foo', '*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/bar/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/bar/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/bar/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/bar/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/*/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', '*/bar/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', '*/*/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', '*/*/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/*/*')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/*/*.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/b*/*z.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/b*r/ba*z.qux')) - self.assertFalse(match('foo/bar/baz.qux', 'foo/b*z/ba*r.qux')) - self.assertTrue(match('foo/bar/baz.qux', '**')) - self.assertTrue(match('foo/bar/baz.qux', '**/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', '**/bar/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/*.qux')) - self.assertTrue(match('foo/bar/baz.qux', '**/foo/bar/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/bar/baz.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/bar/*.qux')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/*.qux')) - self.assertTrue(match('foo/bar/baz.qux', '**/*.qux')) - self.assertFalse(match('foo/bar/baz.qux', '**.qux')) - self.assertFalse(match('foo/bar', 'foo/*/bar')) - self.assertTrue(match('foo/bar/baz.qux', 'foo/**/bar/**')) - self.assertFalse(match('foo/nobar/baz.qux', 'foo/**/bar/**')) - self.assertTrue(match('foo/bar', 'foo/**/bar/**')) - - def test_rebase(self): - self.assertEqual(rebase('foo', 'foo/bar', 'bar/baz'), 'baz') - self.assertEqual(rebase('foo', 'foo', 'bar/baz'), 'bar/baz') - self.assertEqual(rebase('foo/bar', 'foo', 'baz'), 'bar/baz') - - -if os.altsep: - class TestAltPath(TestPath): - SEP = os.altsep - - class TestReverseAltPath(TestPath): - def setUp(self): - sep = os.sep - os.sep = os.altsep - os.altsep = sep - - def tearDown(self): - self.setUp() - - class TestAltReverseAltPath(TestReverseAltPath): - SEP = os.altsep diff --git a/third_party/python/compare-locales/compare_locales/tests/test_parser.py b/third_party/python/compare-locales/compare_locales/tests/test_parser.py deleted file mode 100644 index 38fe642ddfeb..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_parser.py +++ /dev/null @@ -1,118 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import pkg_resources -import shutil -import tempfile -import textwrap -import unittest - -from compare_locales import parser, mozpath - - -class TestParserContext(unittest.TestCase): - def test_linecol(self): - "Should return 1-based line and column numbers." - ctx = parser.Parser.Context('''first line -second line -third line -''') - self.assertEqual( - ctx.linecol(0), - (1, 1) - ) - self.assertEqual( - ctx.linecol(1), - (1, 2) - ) - self.assertEqual( - ctx.linecol(len('first line')), - (1, len('first line') + 1) - ) - self.assertEqual( - ctx.linecol(len('first line') + 1), - (2, 1) - ) - self.assertEqual( - ctx.linecol(len(ctx.contents)), - (4, 1) - ) - - def test_empty_parser(self): - p = parser.Parser() - entities = p.parse() - self.assertTupleEqual( - entities, - tuple() - ) - - -class TestOffsetComment(unittest.TestCase): - def test_offset(self): - ctx = parser.Parser.Context(textwrap.dedent('''\ - #foo - #bar - # baz - ''' - )) # noqa - offset_comment = parser.OffsetComment(ctx, (0, len(ctx.contents))) - self.assertEqual( - offset_comment.val, - textwrap.dedent('''\ - foo - bar - baz - ''') - ) - - -class TestUniversalNewlines(unittest.TestCase): - def setUp(self): - '''Create a parser for this test. - ''' - self.parser = parser.Parser() - self.dir = tempfile.mkdtemp() - - def tearDown(self): - 'tear down this test' - del self.parser - shutil.rmtree(self.dir) - - def test_universal_newlines(self): - f = mozpath.join(self.dir, 'file') - with open(f, 'wb') as fh: - fh.write(b'one\ntwo\rthree\r\n') - self.parser.readFile(f) - self.assertEqual( - self.parser.ctx.contents, - 'one\ntwo\nthree\n') - - -class TestPlugins(unittest.TestCase): - def setUp(self): - self.old_working_set_state = pkg_resources.working_set.__getstate__() - distribution = pkg_resources.Distribution(__file__) - entry_point = pkg_resources.EntryPoint.parse( - 'test_parser = compare_locales.tests.test_parser:DummyParser', - dist=distribution - ) - distribution._ep_map = { - 'compare_locales.parsers': { - 'test_parser': entry_point - } - } - pkg_resources.working_set.add(distribution) - - def tearDown(self): - pkg_resources.working_set.__setstate__(self.old_working_set_state) - - def test_dummy_parser(self): - p = parser.getParser('some/weird/file.ext') - self.assertIsInstance(p, DummyParser) - - -class DummyParser(parser.Parser): - def use(self, path): - return path.endswith('weird/file.ext') diff --git a/third_party/python/compare-locales/compare_locales/tests/test_util.py b/third_party/python/compare-locales/compare_locales/tests/test_util.py deleted file mode 100644 index f549cd2c67f7..000000000000 --- a/third_party/python/compare-locales/compare_locales/tests/test_util.py +++ /dev/null @@ -1,30 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from __future__ import absolute_import -import unittest - -from compare_locales import util - - -class ParseLocalesTest(unittest.TestCase): - def test_empty(self): - self.assertEqual(util.parseLocales(''), []) - - def test_all(self): - self.assertEqual(util.parseLocales('''af -de'''), ['af', 'de']) - - def test_shipped(self): - self.assertEqual(util.parseLocales('''af -ja win mac -de'''), ['af', 'de', 'ja']) - - def test_sparse(self): - self.assertEqual(util.parseLocales(''' -af - -de - -'''), ['af', 'de']) diff --git a/third_party/python/compare-locales/setup.cfg b/third_party/python/compare-locales/setup.cfg deleted file mode 100644 index adf5ed72aa40..000000000000 --- a/third_party/python/compare-locales/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bdist_wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/compare-locales/setup.py b/third_party/python/compare-locales/setup.py deleted file mode 100755 index b273929dceed..000000000000 --- a/third_party/python/compare-locales/setup.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import absolute_import - -from setuptools import setup, find_packages - -import sys -import os -sys.path.insert(0, os.path.dirname(__file__)) - -from compare_locales import version - -this_directory = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(this_directory, 'README.md'), 'rb') as f: - long_description = f.read().decode('utf-8') - -CLASSIFIERS = """\ -Development Status :: 5 - Production/Stable -Intended Audience :: Developers -License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Operating System :: OS Independent -Programming Language :: Python -Programming Language :: Python :: 2 -Programming Language :: Python :: 2.7 -Programming Language :: Python :: 3 -Programming Language :: Python :: 3.5 -Programming Language :: Python :: 3.6 -Programming Language :: Python :: 3.7 -Topic :: Software Development :: Libraries :: Python Modules -Topic :: Software Development :: Localization -Topic :: Software Development :: Testing\ -""" - -setup(name="compare-locales", - version=version, - author="Axel Hecht", - author_email="axel@mozilla.com", - description='Lint Mozilla localizations', - long_description=long_description, - long_description_content_type='text/markdown', - license="MPL 2.0", - classifiers=CLASSIFIERS.split("\n"), - platforms=["any"], - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', - entry_points={ - 'console_scripts': - [ - 'compare-locales = compare_locales.commands:CompareLocales.call', - 'moz-l10n-lint = compare_locales.lint.cli:main', - ], - }, - packages=find_packages(), - package_data={ - 'compare_locales.tests': ['data/*.properties', 'data/*.dtd'] - }, - install_requires=[ - 'fluent.syntax >=0.18.0, <0.19', - 'pytoml', - 'six', - ], - tests_require=[ - 'mock<4.0', - ], - test_suite='compare_locales.tests') diff --git a/third_party/python/compare-locales/README.md b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/DESCRIPTION.rst similarity index 99% rename from third_party/python/compare-locales/README.md rename to third_party/python/compare_locales/compare_locales-8.1.0.dist-info/DESCRIPTION.rst index a050c7d3c867..7ae4baef0810 100644 --- a/third_party/python/compare-locales/README.md +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/DESCRIPTION.rst @@ -54,3 +54,5 @@ moz-l10n-lint --l10n-reference ../gecko-strings browser/locales/l10n.toml to check for a monolithic project like Fenix or a gecko project like Firefox, resp. + + diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/METADATA b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/METADATA new file mode 100644 index 000000000000..8106916cc65f --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/METADATA @@ -0,0 +1,87 @@ +Metadata-Version: 2.0 +Name: compare-locales +Version: 8.1.0 +Summary: Lint Mozilla localizations +Home-page: UNKNOWN +Author: Axel Hecht +Author-email: axel@mozilla.com +License: MPL 2.0 +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Localization +Classifier: Topic :: Software Development :: Testing +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 +Description-Content-Type: text/markdown +Requires-Dist: fluent.syntax (<0.19,>=0.18.0) +Requires-Dist: pytoml +Requires-Dist: six + +[![Build Status](https://travis-ci.org/Pike/compare-locales.svg?branch=master)](https://travis-ci.org/Pike/compare-locales) +# compare-locales +Lint Mozilla localizations + +Finds +* missing strings +* obsolete strings +* errors on runtime errors without false positives +* warns on possible runtime errors + +It also includes `l10n-merge` functionality, which pads localizations with +missing English strings, and replaces entities with errors with English. + +If you want to check your original code for errors like duplicated messages, +use `moz-l10n-lint`, which is also part of this package. You can also use +this to check for conflicts between your strings and those already exposed +to l10n. + +# Configuration + +You configure `compare-locales` (and `moz-l10n-lint`) through a +[project configuration](https://moz-l10n-config.readthedocs.io/en/latest/fileformat.html) +file, `l10n.toml`. + +# Examples + +To check all locales in a project use + +```bash +compare-locales l10n.toml . +``` + +To check Firefox against a local check-out of l10n-central, use + +```bash +compare-locales browser/locales/l10n.toml ../l10n-central +``` + +If you just want to check particular locales, specify them as additional +commandline parameters. + +To lint your local work, use + +```bash +moz-l10n-lint l10n.toml +``` + +To check for conflicts against already existing strings: + +```bash +moz-l10n-lint --reference-project ../android-l10n/mozilla-mobile/fenix l10n.toml +moz-l10n-lint --l10n-reference ../gecko-strings browser/locales/l10n.toml +``` + +to check for a monolithic project like Fenix or a gecko project like Firefox, +resp. + + diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/RECORD b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/RECORD new file mode 100644 index 000000000000..a7d08d76116c --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/RECORD @@ -0,0 +1,97 @@ +compare_locales/__init__.py,sha256=0vhaYUzL7iGNmxDMJ1wV8uKG8Zp28az1HrQ-IqAS_z0,18 +compare_locales/commands.py,sha256=y-GfISkj9QEHa6hxkc-KA2JWKyer6ALt0yIBu44G6JA,8524 +compare_locales/keyedtuple.py,sha256=LZW0ekyGOGSEPzbstEbkMP5ZlrMIJ0JfUUgO_bYpuY0,1634 +compare_locales/merge.py,sha256=3V-SHO6JxDY1_8z-FNmYM0TQTf-DQbaHzpZjM3kjxOA,4669 +compare_locales/mozpath.py,sha256=G8ICLtD-PvnwrCyd9M8Dr2jtl9tpNvU_u-Vb2VprqUw,4271 +compare_locales/plurals.py,sha256=ZgaH4gGjS6ZygJdlJdzWBZmxzs4i6l-2-cRzyEynylk,3974 +compare_locales/serializer.py,sha256=SaVmgdQD4pZXeUs8nxxRGyn90fz-HxZtbe_bwnHtRzY,4415 +compare_locales/util.py,sha256=ttl1tcGveJpYqoHKVlIplhb0wSjAjAaTRQT0z6xoYrQ,439 +compare_locales/checks/__init__.py,sha256=igkMRAsVC6o-qoMz1nPKVgo7mApD3ZfxJ0HziBkP1Mw,1049 +compare_locales/checks/android.py,sha256=4RXCokuYf3f-XptBGAmDDGpePZbaN7Urj4VEeR9oClQ,8208 +compare_locales/checks/base.py,sha256=vEpbYRTqNUesQD_cvfOgTOoqBgEdifSXrlPNzVQqVrc,4306 +compare_locales/checks/dtd.py,sha256=fon3uNnVrRGjUSdeEqv-UL52Cweq0Slipa7BvYFoS8Y,10240 +compare_locales/checks/fluent.py,sha256=1IQSHoq3b3-bDKDgFtCsjvndqAvK2fm79RHRVSoeyic,13450 +compare_locales/checks/properties.py,sha256=xvyn4lSFH2DsUabl4jvhoTAQMo_vHzbFjo5PUGlT-SI,6966 +compare_locales/compare/__init__.py,sha256=Dqij9bny_S8lPrPCdWSwRFSy20E2-Cn0mDe6p0fYDjc,3373 +compare_locales/compare/content.py,sha256=0s5gEnv08qbABFABf33K3MhlJ28NCOgDpw9r8D-vVUI,11095 +compare_locales/compare/observer.py,sha256=ZZ-dCwtBi-r9DmB9kljIIFWfczeiaQAxPrR1EKO3tkI,7543 +compare_locales/compare/utils.py,sha256=eH4UA1gTj0w4Cn2RV9FDe34PtBzCRNfGHjJGjFrnX_c,4383 +compare_locales/integration_tests/__init__.py,sha256=eOFgaCLveRf8s90SCQUeZRRxG5LAXwUSxQHxi4H4hvc,154 +compare_locales/integration_tests/test_plurals.py,sha256=vsEOEpYPONiAM5AJ2lm-jKSTioa4ORWZsfCu3Kem1Ug,1687 +compare_locales/lint/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/lint/cli.py,sha256=WnjOwoJicS8e1Qm-CXfVIPn3T01tXVZlouSr72hN7ZU,3044 +compare_locales/lint/linter.py,sha256=zHikPhXtmFR8nqBBt1UgmRjo3bcETaJWOoJ8lCdtIw0,4306 +compare_locales/lint/util.py,sha256=Ksk08CUNe-tSUuU3E1dSC4UnNuAjCuM3NxaqvVcEa_o,1369 +compare_locales/parser/__init__.py,sha256=qiITkrdYBbObr2BL8aojDN0QhAhPwNHKxA0uwPius28,2120 +compare_locales/parser/android.py,sha256=TxRv9ODhLHQBThxj8xVHY6JmBUAUEB0M8osMLguPAPY,9360 +compare_locales/parser/base.py,sha256=mG-apfK_ASAVJvvYtRxuzWlQY3vk5LGHIz5Gq_j0ctk,13248 +compare_locales/parser/defines.py,sha256=2CEX0x-GmeQzqWjG0yGFHPhWy7-VKPz_hFe3mJIjdQo,3628 +compare_locales/parser/dtd.py,sha256=aqiL4DbP3t6dcJVTgr1tcLa-tIpKfvJ0FC2Ysck5C0Q,4545 +compare_locales/parser/fluent.py,sha256=z6LXnoksjNlmqjwS1aSM-FlqSvhogb_KcYstFxN2gS8,7168 +compare_locales/parser/ini.py,sha256=42_tYNSYJwONCcoH6OdRBK_5xBtamn4gWQzIi9vi-k0,1654 +compare_locales/parser/po.py,sha256=HDyKdvKzPRGBGrdIr0p5SnL94kaZe2y71H2OaJjz7wQ,3321 +compare_locales/parser/properties.py,sha256=y7Le97-myaRa5Zv1Gn8Mk7qv-zsxrDmhQZz9SkpXLn0,3829 +compare_locales/paths/__init__.py,sha256=ltkGVBHeBbh0VMymXjx2AlGSLZjIPBHYIOTU8bZiEtY,1466 +compare_locales/paths/configparser.py,sha256=Ktm9NI-bsXXEO9IQQEgZY1uMGGhT5mySkHsHW-bcZY8,4480 +compare_locales/paths/files.py,sha256=qpCYLuRh_YtaiPWcec_fTuiSq-KX4m_Nnem1k3MU8ig,9068 +compare_locales/paths/ini.py,sha256=Z0bQXOgIkpgoOaPha8Uh0Kk9tsfaoPGdKFnvXwB4PCM,8518 +compare_locales/paths/matcher.py,sha256=kbWCqO7BIAjOQ7fqeH57UVqk-AQCgWDuIoweDPL_Q30,15261 +compare_locales/paths/project.py,sha256=YVcNvPnGA44rgy2RzFO-RS-inf6VIM4bWkIBQpcLQTU,8986 +compare_locales/tests/__init__.py,sha256=gtR7yDaY0fmHOVnZkqilJY1QTmt0rFMbTsecH4AZl1c,2643 +compare_locales/tests/test_apps.py,sha256=sGtV1eWVTm86g6DEzoHkKg4sEZKZWZsQ4E2gtpwPyw4,5922 +compare_locales/tests/test_checks.py,sha256=Ur-TwEbL2gUYFNvonrWFnYVuLryKyMiTM6p_3oXmkwY,3082 +compare_locales/tests/test_compare.py,sha256=FNe49MBWAD_p6Epo4QS9RUwCLJpE9MZCJpthjy73Ab0,6556 +compare_locales/tests/test_defines.py,sha256=CoxB2KBp88lyfQ0RNQ2dgjhKwV-kuzfyXrzQAD8Zwrc,7419 +compare_locales/tests/test_ini.py,sha256=ojbYCtg4h6XsGPBUOJMC5emb88Ok74pHHP4NxgWt43o,5545 +compare_locales/tests/test_keyedtuple.py,sha256=-k9OfVWfi8RUi4ifImto2kgiQ9bh26QGCosmzkyPTZM,1879 +compare_locales/tests/test_merge.py,sha256=-gaN10LrrwffJ4zDDNN2u7VXcAPoTxK6lBw6jCEIlkQ,44822 +compare_locales/tests/test_mozpath.py,sha256=WpDtafH9JOn5PKGucPI4lIiuKhB33E3DvRkpz3E20oU,5917 +compare_locales/tests/test_parser.py,sha256=i4NGKjOwhWI4fEHFACIkbl2PqYUdS1CUw4bye549k4g,3212 +compare_locales/tests/test_util.py,sha256=UVagNHE-cyOaf6JIl_mzy-rHyegIs700rxvT7oauGHM,728 +compare_locales/tests/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/android/test_checks.py,sha256=CJ7IaTsSTuIaOsNX5wH8iAc_cDwJFblcX3ZgKq2TRhA,8375 +compare_locales/tests/android/test_merge.py,sha256=A-GymwIj88G6IEZGFFE4zGPH7li5WAdYF4NFbJZlnPY,2036 +compare_locales/tests/android/test_parser.py,sha256=GKZlytRICiQLsAq_ck4mSC_77KyyOXtN0V8t4f_n_Lo,3397 +compare_locales/tests/data/bug121341.properties,sha256=BLQKqFxYoxwN4ML3an3By5IxpqD1o2nL95FEMRWfCGE,4103 +compare_locales/tests/data/test.properties,sha256=nrqfW1KcAIIgEJ5Qpyg_ijTDmbApKenwd-kqZAJGGCY,332 +compare_locales/tests/data/triple-license.dtd,sha256=PIebO8DcvRtXZVWnjcvtWFB3hrwWWV4H-nhiMbXF5J0,1771 +compare_locales/tests/dtd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/dtd/test_checks.py,sha256=tVpQacc7f-tD3DZXTd9Nr7zkeFysl6WepZB4kzjgrWo,13852 +compare_locales/tests/dtd/test_merge.py,sha256=iIoW_16EeoZWSqMTCHjnAKUnotticfVEyADuPTAeJqs,6262 +compare_locales/tests/dtd/test_parser.py,sha256=XlgZCTpcVbYaoGxVhW_vUte_OfZ-xJn1AV0gBwR0AIw,8919 +compare_locales/tests/fluent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/fluent/test_checks.py,sha256=0jxNghHITvAq5WqFhWrpDBjerRVtukfPbKph5ZpKhd8,14520 +compare_locales/tests/fluent/test_merge.py,sha256=rUNNiiudokol2bUIT7brVKfgOxHWpg584JF1wZ28hKc,5063 +compare_locales/tests/fluent/test_parser.py,sha256=yIJpg4m96nNs0Wusbg08ucRldJ3EusfYpZy-kQ5iCTc,9109 +compare_locales/tests/lint/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/lint/test_linter.py,sha256=_Ds3XfWM8-jsqpR_tM-J2HYKC8euwcWvV4x96Br4Kak,3399 +compare_locales/tests/lint/test_util.py,sha256=IzkNiLIpanqpAodPNyLbwa5XGvYYawH2il1PbNUw__w,3470 +compare_locales/tests/merge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/merge/test_comments.py,sha256=uxbQSbB8Ed9CCkY5kdiz4Dpx4YyHvDSIwdn0xoU4-9c,3470 +compare_locales/tests/merge/test_messages.py,sha256=uyw_ajphPHw3hJzLlU9mDBdPsRJLnj91NDB7HTaDRr0,1756 +compare_locales/tests/merge/test_unknown.py,sha256=kXbPgkHk3Su8EZxtahyVvUCM86k3m9pigJuZONohlQ0,663 +compare_locales/tests/merge/test_whitespace.py,sha256=GiFguoZYlikyDjv9kJPpjoHGxgX7uWhT1TN6-VGa2bk,1290 +compare_locales/tests/paths/__init__.py,sha256=VoUPmeoFOYBulfuS07nWBj4CwcCcSiwKsJIxCOrWS3k,3889 +compare_locales/tests/paths/test_configparser.py,sha256=no9fflU8ROu7wYSJp-tABFujPL9g5z77guEiRbNVY-8,3577 +compare_locales/tests/paths/test_files.py,sha256=hAz4Z9IUfRp4muskonqFZ1R0bNymlOZQwtzLzCx5Xp8,18885 +compare_locales/tests/paths/test_ini.py,sha256=Qytt5d68xotKZ99msYk4jMULb8LlI-4mQeXfOo3Xuwc,3389 +compare_locales/tests/paths/test_matcher.py,sha256=xz5CUBUe541NiBEgYdDLoskrEOyVDYpZsmSlHvCmLRo,16020 +compare_locales/tests/paths/test_paths.py,sha256=QP7JlojewyM_jPUV3MlG6h0EfuATXvKjNPwNkuDsBa0,1036 +compare_locales/tests/paths/test_project.py,sha256=-llBFCbKFR-lzg4sUBPH5qU15x7_Krgss1rFevE2Atc,7844 +compare_locales/tests/po/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/po/test_parser.py,sha256=B1qbRQs6HwHjr_ob5qec7H_lmErO-UnUgmcwgU8H77U,3784 +compare_locales/tests/properties/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +compare_locales/tests/properties/test_checks.py,sha256=kjfhOExgSkSLHggN5tTa7TrB_sz0Pn1HdlOPUFOyV8s,3533 +compare_locales/tests/properties/test_merge.py,sha256=q0MaTyX9LoLC1aPlVa_0yagrX8pafZQXV30uvgSUYeU,1348 +compare_locales/tests/properties/test_parser.py,sha256=SKcUAGNsO52NgtVhmIr8v_8-sKFDw4W2pI3f0xyZ9z8,7361 +compare_locales/tests/serializer/__init__.py,sha256=BjQqPldYwIaBckqv4XbKUFCxiQ3PtxrvOrY2P-ozMkk,1136 +compare_locales/tests/serializer/test_android.py,sha256=iRNxC742DpmU_q-i0N1c3hXUDa8UpqV4yiR3vQ4h628,5537 +compare_locales/tests/serializer/test_fluent.py,sha256=3DaGmaAbrmBPI_NZ0LStktF1E_3RUW_rNwggsLDUiRU,1645 +compare_locales/tests/serializer/test_properties.py,sha256=qqnv13huEyIzFvp83E3YmaQpe0zLGRj9Zfr3eEv63qA,2007 +compare_locales-8.1.0.dist-info/DESCRIPTION.rst,sha256=VMWXTgwyBMPEQ4xiythrZoK3O-QNMCxz06MwR6FPVS4,1581 +compare_locales-8.1.0.dist-info/METADATA,sha256=xlvVa_pmsGdP2u9Cx7UTXp07ZPK5UHfQUzLuXulLkt4,2722 +compare_locales-8.1.0.dist-info/RECORD,, +compare_locales-8.1.0.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 +compare_locales-8.1.0.dist-info/entry_points.txt,sha256=OCmSzZoRKqFdYlm_UCCYFQfw22nhf8LGcI3fpMRyQ30,128 +compare_locales-8.1.0.dist-info/metadata.json,sha256=51a2OIgUzk0jefj_kx2b0pn3x-zP9vLq0ii1GD_vSxA,1590 +compare_locales-8.1.0.dist-info/top_level.txt,sha256=eSEPLAFZcEPFC1j0N9GtVpMaKCFKw67ehDx9CMcoel0,16 diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/WHEEL b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/WHEEL new file mode 100644 index 000000000000..7332a419cda6 --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/entry_points.txt b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/entry_points.txt new file mode 100644 index 000000000000..d6be6cb65e7c --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +compare-locales = compare_locales.commands:CompareLocales.call +moz-l10n-lint = compare_locales.lint.cli:main + diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/metadata.json b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/metadata.json new file mode 100644 index 000000000000..b1c369a209bc --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Localization", "Topic :: Software Development :: Testing"], "description_content_type": "text/markdown", "extensions": {"python.commands": {"wrap_console": {"compare-locales": "compare_locales.commands:CompareLocales.call", "moz-l10n-lint": "compare_locales.lint.cli:main"}}, "python.details": {"contacts": [{"email": "axel@mozilla.com", "name": "Axel Hecht", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}}, "python.exports": {"console_scripts": {"compare-locales": "compare_locales.commands:CompareLocales.call", "moz-l10n-lint": "compare_locales.lint.cli:main"}}}, "extras": [], "generator": "bdist_wheel (0.30.0)", "license": "MPL 2.0", "metadata_version": "2.0", "name": "compare-locales", "platform": "any", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4", "run_requires": [{"requires": ["fluent.syntax (<0.19,>=0.18.0)", "pytoml", "six"]}], "summary": "Lint Mozilla localizations", "test_requires": [{"requires": ["mock (<4.0)"]}], "version": "8.1.0"} \ No newline at end of file diff --git a/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/top_level.txt b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/top_level.txt new file mode 100644 index 000000000000..d9c74fc101dc --- /dev/null +++ b/third_party/python/compare_locales/compare_locales-8.1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +compare_locales diff --git a/third_party/python/compare-locales/compare_locales/__init__.py b/third_party/python/compare_locales/compare_locales/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/__init__.py rename to third_party/python/compare_locales/compare_locales/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/checks/__init__.py b/third_party/python/compare_locales/compare_locales/checks/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/__init__.py rename to third_party/python/compare_locales/compare_locales/checks/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/checks/android.py b/third_party/python/compare_locales/compare_locales/checks/android.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/android.py rename to third_party/python/compare_locales/compare_locales/checks/android.py diff --git a/third_party/python/compare-locales/compare_locales/checks/base.py b/third_party/python/compare_locales/compare_locales/checks/base.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/base.py rename to third_party/python/compare_locales/compare_locales/checks/base.py diff --git a/third_party/python/compare-locales/compare_locales/checks/dtd.py b/third_party/python/compare_locales/compare_locales/checks/dtd.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/dtd.py rename to third_party/python/compare_locales/compare_locales/checks/dtd.py diff --git a/third_party/python/compare-locales/compare_locales/checks/fluent.py b/third_party/python/compare_locales/compare_locales/checks/fluent.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/fluent.py rename to third_party/python/compare_locales/compare_locales/checks/fluent.py diff --git a/third_party/python/compare-locales/compare_locales/checks/properties.py b/third_party/python/compare_locales/compare_locales/checks/properties.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/checks/properties.py rename to third_party/python/compare_locales/compare_locales/checks/properties.py diff --git a/third_party/python/compare-locales/compare_locales/commands.py b/third_party/python/compare_locales/compare_locales/commands.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/commands.py rename to third_party/python/compare_locales/compare_locales/commands.py diff --git a/third_party/python/compare-locales/compare_locales/compare/__init__.py b/third_party/python/compare_locales/compare_locales/compare/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/compare/__init__.py rename to third_party/python/compare_locales/compare_locales/compare/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/compare/content.py b/third_party/python/compare_locales/compare_locales/compare/content.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/compare/content.py rename to third_party/python/compare_locales/compare_locales/compare/content.py diff --git a/third_party/python/compare-locales/compare_locales/compare/observer.py b/third_party/python/compare_locales/compare_locales/compare/observer.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/compare/observer.py rename to third_party/python/compare_locales/compare_locales/compare/observer.py diff --git a/third_party/python/compare-locales/compare_locales/compare/utils.py b/third_party/python/compare_locales/compare_locales/compare/utils.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/compare/utils.py rename to third_party/python/compare_locales/compare_locales/compare/utils.py diff --git a/third_party/python/compare-locales/compare_locales/integration_tests/__init__.py b/third_party/python/compare_locales/compare_locales/integration_tests/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/integration_tests/__init__.py rename to third_party/python/compare_locales/compare_locales/integration_tests/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/integration_tests/test_plurals.py b/third_party/python/compare_locales/compare_locales/integration_tests/test_plurals.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/integration_tests/test_plurals.py rename to third_party/python/compare_locales/compare_locales/integration_tests/test_plurals.py diff --git a/third_party/python/compare-locales/compare_locales/keyedtuple.py b/third_party/python/compare_locales/compare_locales/keyedtuple.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/keyedtuple.py rename to third_party/python/compare_locales/compare_locales/keyedtuple.py diff --git a/third_party/python/Click/examples/complex/complex/__init__.py b/third_party/python/compare_locales/compare_locales/lint/__init__.py similarity index 100% rename from third_party/python/Click/examples/complex/complex/__init__.py rename to third_party/python/compare_locales/compare_locales/lint/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/lint/cli.py b/third_party/python/compare_locales/compare_locales/lint/cli.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/lint/cli.py rename to third_party/python/compare_locales/compare_locales/lint/cli.py diff --git a/third_party/python/compare-locales/compare_locales/lint/linter.py b/third_party/python/compare_locales/compare_locales/lint/linter.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/lint/linter.py rename to third_party/python/compare_locales/compare_locales/lint/linter.py diff --git a/third_party/python/compare-locales/compare_locales/lint/util.py b/third_party/python/compare_locales/compare_locales/lint/util.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/lint/util.py rename to third_party/python/compare_locales/compare_locales/lint/util.py diff --git a/third_party/python/compare-locales/compare_locales/merge.py b/third_party/python/compare_locales/compare_locales/merge.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/merge.py rename to third_party/python/compare_locales/compare_locales/merge.py diff --git a/third_party/python/compare-locales/compare_locales/mozpath.py b/third_party/python/compare_locales/compare_locales/mozpath.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/mozpath.py rename to third_party/python/compare_locales/compare_locales/mozpath.py diff --git a/third_party/python/compare-locales/compare_locales/parser/__init__.py b/third_party/python/compare_locales/compare_locales/parser/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/__init__.py rename to third_party/python/compare_locales/compare_locales/parser/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/parser/android.py b/third_party/python/compare_locales/compare_locales/parser/android.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/android.py rename to third_party/python/compare_locales/compare_locales/parser/android.py diff --git a/third_party/python/compare-locales/compare_locales/parser/base.py b/third_party/python/compare_locales/compare_locales/parser/base.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/base.py rename to third_party/python/compare_locales/compare_locales/parser/base.py diff --git a/third_party/python/compare-locales/compare_locales/parser/defines.py b/third_party/python/compare_locales/compare_locales/parser/defines.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/defines.py rename to third_party/python/compare_locales/compare_locales/parser/defines.py diff --git a/third_party/python/compare-locales/compare_locales/parser/dtd.py b/third_party/python/compare_locales/compare_locales/parser/dtd.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/dtd.py rename to third_party/python/compare_locales/compare_locales/parser/dtd.py diff --git a/third_party/python/compare-locales/compare_locales/parser/fluent.py b/third_party/python/compare_locales/compare_locales/parser/fluent.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/fluent.py rename to third_party/python/compare_locales/compare_locales/parser/fluent.py diff --git a/third_party/python/compare-locales/compare_locales/parser/ini.py b/third_party/python/compare_locales/compare_locales/parser/ini.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/ini.py rename to third_party/python/compare_locales/compare_locales/parser/ini.py diff --git a/third_party/python/compare-locales/compare_locales/parser/po.py b/third_party/python/compare_locales/compare_locales/parser/po.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/po.py rename to third_party/python/compare_locales/compare_locales/parser/po.py diff --git a/third_party/python/compare-locales/compare_locales/parser/properties.py b/third_party/python/compare_locales/compare_locales/parser/properties.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/parser/properties.py rename to third_party/python/compare_locales/compare_locales/parser/properties.py diff --git a/third_party/python/compare-locales/compare_locales/paths/__init__.py b/third_party/python/compare_locales/compare_locales/paths/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/__init__.py rename to third_party/python/compare_locales/compare_locales/paths/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/paths/configparser.py b/third_party/python/compare_locales/compare_locales/paths/configparser.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/configparser.py rename to third_party/python/compare_locales/compare_locales/paths/configparser.py diff --git a/third_party/python/compare-locales/compare_locales/paths/files.py b/third_party/python/compare_locales/compare_locales/paths/files.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/files.py rename to third_party/python/compare_locales/compare_locales/paths/files.py diff --git a/third_party/python/compare-locales/compare_locales/paths/ini.py b/third_party/python/compare_locales/compare_locales/paths/ini.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/ini.py rename to third_party/python/compare_locales/compare_locales/paths/ini.py diff --git a/third_party/python/compare-locales/compare_locales/paths/matcher.py b/third_party/python/compare_locales/compare_locales/paths/matcher.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/matcher.py rename to third_party/python/compare_locales/compare_locales/paths/matcher.py diff --git a/third_party/python/compare-locales/compare_locales/paths/project.py b/third_party/python/compare_locales/compare_locales/paths/project.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/paths/project.py rename to third_party/python/compare_locales/compare_locales/paths/project.py diff --git a/third_party/python/compare-locales/compare_locales/plurals.py b/third_party/python/compare_locales/compare_locales/plurals.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/plurals.py rename to third_party/python/compare_locales/compare_locales/plurals.py diff --git a/third_party/python/compare-locales/compare_locales/serializer.py b/third_party/python/compare_locales/compare_locales/serializer.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/serializer.py rename to third_party/python/compare_locales/compare_locales/serializer.py diff --git a/third_party/python/compare-locales/compare_locales/util.py b/third_party/python/compare_locales/compare_locales/util.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/util.py rename to third_party/python/compare_locales/compare_locales/util.py diff --git a/third_party/python/cookies/PKG-INFO b/third_party/python/cookies/PKG-INFO deleted file mode 100644 index dc06229f8ac3..000000000000 --- a/third_party/python/cookies/PKG-INFO +++ /dev/null @@ -1,109 +0,0 @@ -Metadata-Version: 1.1 -Name: cookies -Version: 2.2.1 -Summary: Friendlier RFC 6265-compliant cookie parser/renderer -Home-page: https://github.com/sashahart/cookies -Author: Sasha Hart -Author-email: s@sashahart.net -License: UNKNOWN -Description: What is this and what is it for? - -------------------------------- - - cookies.py is a Python module for working with HTTP cookies: parsing and - rendering 'Cookie:' request headers and 'Set-Cookie:' response headers, - and exposing a convenient API for creating and modifying cookies. It can be - used as a replacement of Python's Cookie.py (aka http.cookies). - - Features - -------- - - * Rendering according to the excellent new RFC 6265 - (rather than using a unique ad hoc format inconsistently relating to - unrealistic, very old RFCs which everyone ignored). Uses URL encoding to - represent non-ASCII by default, like many other languages' libraries - * Liberal parsing, incorporating many complaints about Cookie.py barfing - on common cookie formats which can be reliably parsed (e.g. search 'cookie' - on the Python issue tracker) - * Well-documented code, with chapter and verse from RFCs - (rather than arbitrary, undocumented decisions and huge tables of magic - values, as you see in Cookie.py). - * Test coverage at 100%, with a much more comprehensive test suite - than Cookie.py - * Single-source compatible with the following Python versions: - 2.6, 2.7, 3.2, 3.3 and PyPy (2.7). - * Cleaner, less surprising API:: - - # old Cookie.py - this code is all directly from its docstring - >>> from Cookie import SmartCookie - >>> C = SmartCookie() - >>> # n.b. it's "smart" because it automatically pickles Python objects, - >>> # which is actually quite stupid for security reasons! - >>> C["rocky"] = "road" - >>> C["rocky"]["path"] = "/cookie" - >>> # So C["rocky"] is a string, except when it's a dict... - >>> # and why do I have to write [""] to access a fixed set of attrs? - >>> # Look at the atrocious way I render out a request header: - >>> C.output(attrs=[], header="Cookie:") - 'Cookie: rocky=road' - - # new cookies.py - >>> from cookies import Cookies, Cookie - >>> cookies = Cookies(rocky='road') - >>> # Can also write explicitly: cookies['rocky'] = Cookie['road'] - >>> cookies['rocky'].path = "/cookie" - >>> cookies.render_request() - 'rocky=road' - * Friendly to customization, extension, and reuse of its parts. - Unlike Cookie.py, it doesn't lock all implementation inside its own classes - (forcing you to write ugly wrappers as Django, Trac, Werkzeug/Flask, web.py - and Tornado had to do). You can suppress minor parse exceptions with - parameters rather than subclass wrappers. You can plug in your own parsers, - renderers and validators for new or existing cookie attributes. You can - render the data out in a dict. You can easily use the underlying imperative - API or even lift the parser's regexps for your own parser or project. They - are very well documented and relate directly to RFCs, so you know exactly - what you are getting and why. It's MIT-licensed so do - what you want (but I'd love to know what use you are getting from it!) - * One file, so you can just drop cookies.py into your project if you like - * MIT license, so you can use it in whatever you want with no strings - - Things this is not meant to do - ------------------------------ - While this is intended to be a good module for handling cookies, it does not - even try to do any of the following: - - * Maintain backward compatibility with Cookie.py, which would mean - inheriting its confusions and bugs - * Implement RFCs 2109 or 2965, which have always been ignored by almost - everyone and are now obsolete as well - * Handle every conceivable output from terrible legacy apps, which is not - possible to do without lots of silent data loss and corruption (the - parser does try to be liberal as possible otherwise, though) - * Provide a means to store pickled Python objects in cookie values - (that's a big security hole) - - This doesn't compete with the cookielib (http.cookiejar) module in the Python - standard library, which is specifically for implementing cookie storage and - similar behavior in an HTTP client such as a browser. Things cookielib does - that this doesn't: - - * Write to or read from browsers' cookie stores or other proprietary - formats for storing cookie data in files - * Handle the browser/client logic like deciding which cookies to send or - discard, etc. - - If you are looking for a cookie library but neither this one nor cookielib - will help, you might also consider the implementations in WebOb or Bottle. - -Platform: UNKNOWN -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Other Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/third_party/python/cookies/README b/third_party/python/cookies/cookies-2.2.1.dist-info/DESCRIPTION.rst similarity index 99% rename from third_party/python/cookies/README rename to third_party/python/cookies/cookies-2.2.1.dist-info/DESCRIPTION.rst index 2363dadb2f42..6c04d8b1d08c 100644 --- a/third_party/python/cookies/README +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/DESCRIPTION.rst @@ -86,3 +86,5 @@ that this doesn't: If you are looking for a cookie library but neither this one nor cookielib will help, you might also consider the implementations in WebOb or Bottle. + + diff --git a/third_party/python/cookies/cookies-2.2.1.dist-info/METADATA b/third_party/python/cookies/cookies-2.2.1.dist-info/METADATA new file mode 100644 index 000000000000..b523ed38a19c --- /dev/null +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.0 +Name: cookies +Version: 2.2.1 +Summary: Friendlier RFC 6265-compliant cookie parser/renderer +Home-page: https://github.com/sashahart/cookies +Author: Sasha Hart +Author-email: s@sashahart.net +License: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Other Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules + +What is this and what is it for? +-------------------------------- + +cookies.py is a Python module for working with HTTP cookies: parsing and +rendering 'Cookie:' request headers and 'Set-Cookie:' response headers, +and exposing a convenient API for creating and modifying cookies. It can be +used as a replacement of Python's Cookie.py (aka http.cookies). + +Features +-------- + +* Rendering according to the excellent new RFC 6265 + (rather than using a unique ad hoc format inconsistently relating to + unrealistic, very old RFCs which everyone ignored). Uses URL encoding to + represent non-ASCII by default, like many other languages' libraries +* Liberal parsing, incorporating many complaints about Cookie.py barfing + on common cookie formats which can be reliably parsed (e.g. search 'cookie' + on the Python issue tracker) +* Well-documented code, with chapter and verse from RFCs + (rather than arbitrary, undocumented decisions and huge tables of magic + values, as you see in Cookie.py). +* Test coverage at 100%, with a much more comprehensive test suite + than Cookie.py +* Single-source compatible with the following Python versions: + 2.6, 2.7, 3.2, 3.3 and PyPy (2.7). +* Cleaner, less surprising API:: + + # old Cookie.py - this code is all directly from its docstring + >>> from Cookie import SmartCookie + >>> C = SmartCookie() + >>> # n.b. it's "smart" because it automatically pickles Python objects, + >>> # which is actually quite stupid for security reasons! + >>> C["rocky"] = "road" + >>> C["rocky"]["path"] = "/cookie" + >>> # So C["rocky"] is a string, except when it's a dict... + >>> # and why do I have to write [""] to access a fixed set of attrs? + >>> # Look at the atrocious way I render out a request header: + >>> C.output(attrs=[], header="Cookie:") + 'Cookie: rocky=road' + + # new cookies.py + >>> from cookies import Cookies, Cookie + >>> cookies = Cookies(rocky='road') + >>> # Can also write explicitly: cookies['rocky'] = Cookie['road'] + >>> cookies['rocky'].path = "/cookie" + >>> cookies.render_request() + 'rocky=road' +* Friendly to customization, extension, and reuse of its parts. + Unlike Cookie.py, it doesn't lock all implementation inside its own classes + (forcing you to write ugly wrappers as Django, Trac, Werkzeug/Flask, web.py + and Tornado had to do). You can suppress minor parse exceptions with + parameters rather than subclass wrappers. You can plug in your own parsers, + renderers and validators for new or existing cookie attributes. You can + render the data out in a dict. You can easily use the underlying imperative + API or even lift the parser's regexps for your own parser or project. They + are very well documented and relate directly to RFCs, so you know exactly + what you are getting and why. It's MIT-licensed so do + what you want (but I'd love to know what use you are getting from it!) +* One file, so you can just drop cookies.py into your project if you like +* MIT license, so you can use it in whatever you want with no strings + +Things this is not meant to do +------------------------------ +While this is intended to be a good module for handling cookies, it does not +even try to do any of the following: + +* Maintain backward compatibility with Cookie.py, which would mean + inheriting its confusions and bugs +* Implement RFCs 2109 or 2965, which have always been ignored by almost + everyone and are now obsolete as well +* Handle every conceivable output from terrible legacy apps, which is not + possible to do without lots of silent data loss and corruption (the + parser does try to be liberal as possible otherwise, though) +* Provide a means to store pickled Python objects in cookie values + (that's a big security hole) + +This doesn't compete with the cookielib (http.cookiejar) module in the Python +standard library, which is specifically for implementing cookie storage and +similar behavior in an HTTP client such as a browser. Things cookielib does +that this doesn't: + +* Write to or read from browsers' cookie stores or other proprietary + formats for storing cookie data in files +* Handle the browser/client logic like deciding which cookies to send or + discard, etc. + +If you are looking for a cookie library but neither this one nor cookielib +will help, you might also consider the implementations in WebOb or Bottle. + + diff --git a/third_party/python/cookies/cookies-2.2.1.dist-info/RECORD b/third_party/python/cookies/cookies-2.2.1.dist-info/RECORD new file mode 100644 index 000000000000..f29a75c9b068 --- /dev/null +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/RECORD @@ -0,0 +1,8 @@ +cookies.py,sha256=sF8kRzufOPGQAu8iiPfynJj2yRNGkUcC-JxvTX9mKQ8,47318 +test_cookies.py,sha256=cbFPYlNzzgTkVzz7Xb_3GqmQ4SE0EEz1gRIF1We5QTY,96777 +cookies-2.2.1.dist-info/RECORD,, +cookies-2.2.1.dist-info/metadata.json,sha256=mQLffEYibwvk8r15ayQPMqbU4RCgtGlL5u59EY-8t6k,901 +cookies-2.2.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +cookies-2.2.1.dist-info/DESCRIPTION.rst,sha256=cMKRjszZhygoqs2V6ZKoKQGGtBY5RN_vfTYfd-UYFJ0,4351 +cookies-2.2.1.dist-info/METADATA,sha256=pTGwsy7mjUwouhm4j-E7ld4-rbbUCbiK-bHvwaChN2M,5170 +cookies-2.2.1.dist-info/top_level.txt,sha256=cmWJoCZMIIrsNW2u7GQHmLxsBkrQSFDP-t27J7-E_HQ,21 diff --git a/third_party/python/cookies/cookies-2.2.1.dist-info/WHEEL b/third_party/python/cookies/cookies-2.2.1.dist-info/WHEEL new file mode 100644 index 000000000000..9dff69d86102 --- /dev/null +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/cookies/cookies-2.2.1.dist-info/metadata.json b/third_party/python/cookies/cookies-2.2.1.dist-info/metadata.json new file mode 100644 index 000000000000..0009aea8fbf5 --- /dev/null +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"name": "cookies", "classifiers": ["Development Status :: 4 - Beta", "Environment :: Other Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules"], "generator": "bdist_wheel (0.24.0)", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"name": "Sasha Hart", "role": "author", "email": "s@sashahart.net"}], "project_urls": {"Home": "https://github.com/sashahart/cookies"}}}, "version": "2.2.1", "metadata_version": "2.0", "summary": "Friendlier RFC 6265-compliant cookie parser/renderer"} \ No newline at end of file diff --git a/third_party/python/cookies/cookies-2.2.1.dist-info/top_level.txt b/third_party/python/cookies/cookies-2.2.1.dist-info/top_level.txt new file mode 100644 index 000000000000..0358d8a02adb --- /dev/null +++ b/third_party/python/cookies/cookies-2.2.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +cookies +test_cookies diff --git a/third_party/python/cookies/setup.cfg b/third_party/python/cookies/setup.cfg deleted file mode 100644 index 9a777d025394..000000000000 --- a/third_party/python/cookies/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[wheel] -universal = 1 - -[egg_info] -tag_date = 0 -tag_build = -tag_svn_revision = 0 - diff --git a/third_party/python/cookies/setup.py b/third_party/python/cookies/setup.py deleted file mode 100644 index d2554997e657..000000000000 --- a/third_party/python/cookies/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -from setuptools import setup, Command -from cookies import __version__ - -class Test(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - try: - import pytest - except ImportError: - raise AssertionError("Install py.test to run the tests") - import sys, subprocess - errno = subprocess.call([sys.executable, '-m', 'py.test']) - raise SystemExit(errno) - -setup( - name="cookies", - version=__version__, - author="Sasha Hart", - author_email="s@sashahart.net", - url="https://github.com/sashahart/cookies", - py_modules=['cookies', 'test_cookies'], - description="Friendlier RFC 6265-compliant cookie parser/renderer", - long_description=open('README').read(), - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: Other Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.2", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - cmdclass = {'test': Test}, -) diff --git a/third_party/python/diskcache/MANIFEST.in b/third_party/python/diskcache/MANIFEST.in deleted file mode 100644 index 0c738421d6a4..000000000000 --- a/third_party/python/diskcache/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include README.rst LICENSE diff --git a/third_party/python/diskcache/PKG-INFO b/third_party/python/diskcache/PKG-INFO deleted file mode 100644 index 12d0977c7db3..000000000000 --- a/third_party/python/diskcache/PKG-INFO +++ /dev/null @@ -1,428 +0,0 @@ -Metadata-Version: 1.1 -Name: diskcache -Version: 4.1.0 -Summary: Disk Cache -- Disk and file backed persistent cache. -Home-page: http://www.grantjenks.com/docs/diskcache/ -Author: Grant Jenks -Author-email: contact@grantjenks.com -License: Apache 2.0 -Description: DiskCache: Disk Backed Cache - ============================ - - `DiskCache`_ is an Apache2 licensed disk and file backed cache library, written - in pure-Python, and compatible with Django. - - The cloud-based computing of 2019 puts a premium on memory. Gigabytes of empty - space is left on disks as processes vie for memory. Among these processes is - Memcached (and sometimes Redis) which is used as a cache. Wouldn't it be nice - to leverage empty disk space for caching? - - Django is Python's most popular web framework and ships with several caching - backends. Unfortunately the file-based cache in Django is essentially - broken. The culling method is random and large caches repeatedly scan a cache - directory which slows linearly with growth. Can you really allow it to take - sixty milliseconds to store a key in a cache with a thousand items? - - In Python, we can do better. And we can do it in pure-Python! - - :: - - In [1]: import pylibmc - In [2]: client = pylibmc.Client(['127.0.0.1'], binary=True) - In [3]: client[b'key'] = b'value' - In [4]: %timeit client[b'key'] - - 10000 loops, best of 3: 25.4 µs per loop - - In [5]: import diskcache as dc - In [6]: cache = dc.Cache('tmp') - In [7]: cache[b'key'] = b'value' - In [8]: %timeit cache[b'key'] - - 100000 loops, best of 3: 11.8 µs per loop - - **Note:** Micro-benchmarks have their place but are not a substitute for real - measurements. DiskCache offers cache benchmarks to defend its performance - claims. Micro-optimizations are avoided but your mileage may vary. - - DiskCache efficiently makes gigabytes of storage space available for - caching. By leveraging rock-solid database libraries and memory-mapped files, - cache performance can match and exceed industry-standard solutions. There's no - need for a C compiler or running another process. Performance is a feature and - testing has 100% coverage with unit tests and hours of stress. - - Testimonials - ------------ - - `Daren Hasenkamp`_, Founder -- - - "It's a useful, simple API, just like I love about Redis. It has reduced - the amount of queries hitting my Elasticsearch cluster by over 25% for a - website that gets over a million users/day (100+ hits/second)." - - `Mathias Petermann`_, Senior Linux System Engineer -- - - "I implemented it into a wrapper for our Ansible lookup modules and we were - able to speed up some Ansible runs by almost 3 times. DiskCache is saving - us a ton of time." - - Does your company or website use `DiskCache`_? Send us a `message - `_ and let us know. - - .. _`Daren Hasenkamp`: https://www.linkedin.com/in/daren-hasenkamp-93006438/ - .. _`Mathias Petermann`: https://www.linkedin.com/in/mathias-petermann-a8aa273b/ - - Features - -------- - - - Pure-Python - - Fully Documented - - Benchmark comparisons (alternatives, Django cache backends) - - 100% test coverage - - Hours of stress testing - - Performance matters - - Django compatible API - - Thread-safe and process-safe - - Supports multiple eviction policies (LRU and LFU included) - - Keys support "tag" metadata and eviction - - Developed on Python 3.7 - - Tested on CPython 2.7, 3.4, 3.5, 3.6, 3.7 and PyPy - - Tested on Linux, Mac OS X, and Windows - - Tested using Travis CI and AppVeyor CI - - .. image:: https://api.travis-ci.org/grantjenks/python-diskcache.svg?branch=master - :target: http://www.grantjenks.com/docs/diskcache/ - - .. image:: https://ci.appveyor.com/api/projects/status/github/grantjenks/python-diskcache?branch=master&svg=true - :target: http://www.grantjenks.com/docs/diskcache/ - - Quickstart - ---------- - - Installing `DiskCache`_ is simple with `pip `_:: - - $ pip install diskcache - - You can access documentation in the interpreter with Python's built-in help - function:: - - >>> import diskcache - >>> help(diskcache) - - The core of `DiskCache`_ is three data types intended for caching. `Cache`_ - objects manage a SQLite database and filesystem directory to store key and - value pairs. `FanoutCache`_ provides a sharding layer to utilize multiple - caches and `DjangoCache`_ integrates that with `Django`_:: - - >>> from diskcache import Cache, FanoutCache, DjangoCache - >>> help(Cache) - >>> help(FanoutCache) - >>> help(DjangoCache) - - Built atop the caching data types, are `Deque`_ and `Index`_ which work as a - cross-process, persistent replacements for Python's ``collections.deque`` and - ``dict``. These implement the sequence and mapping container base classes:: - - >>> from diskcache import Deque, Index - >>> help(Deque) - >>> help(Index) - - Finally, a number of `recipes`_ for cross-process synchronization are provided - using an underlying cache. Features like memoization with cache stampede - prevention, cross-process locking, and cross-process throttling are available:: - - >>> from diskcache import memoize_stampede, Lock, throttle - >>> help(memoize_stampede) - >>> help(Lock) - >>> help(throttle) - - Python's docstrings are a quick way to get started but not intended as a - replacement for the `DiskCache Tutorial`_ and `DiskCache API Reference`_. - - .. _`Cache`: http://www.grantjenks.com/docs/diskcache/tutorial.html#cache - .. _`FanoutCache`: http://www.grantjenks.com/docs/diskcache/tutorial.html#fanoutcache - .. _`DjangoCache`: http://www.grantjenks.com/docs/diskcache/tutorial.html#djangocache - .. _`Django`: https://www.djangoproject.com/ - .. _`Deque`: http://www.grantjenks.com/docs/diskcache/tutorial.html#deque - .. _`Index`: http://www.grantjenks.com/docs/diskcache/tutorial.html#index - .. _`recipes`: http://www.grantjenks.com/docs/diskcache/tutorial.html#recipes - - User Guide - ---------- - - For those wanting more details, this part of the documentation describes - tutorial, benchmarks, API, and development. - - * `DiskCache Tutorial`_ - * `DiskCache Cache Benchmarks`_ - * `DiskCache DjangoCache Benchmarks`_ - * `Case Study: Web Crawler`_ - * `Case Study: Landing Page Caching`_ - * `Talk: All Things Cached - SF Python 2017 Meetup`_ - * `DiskCache API Reference`_ - * `DiskCache Development`_ - - .. _`DiskCache Tutorial`: http://www.grantjenks.com/docs/diskcache/tutorial.html - .. _`DiskCache Cache Benchmarks`: http://www.grantjenks.com/docs/diskcache/cache-benchmarks.html - .. _`DiskCache DjangoCache Benchmarks`: http://www.grantjenks.com/docs/diskcache/djangocache-benchmarks.html - .. _`Talk: All Things Cached - SF Python 2017 Meetup`: http://www.grantjenks.com/docs/diskcache/sf-python-2017-meetup-talk.html - .. _`Case Study: Web Crawler`: http://www.grantjenks.com/docs/diskcache/case-study-web-crawler.html - .. _`Case Study: Landing Page Caching`: http://www.grantjenks.com/docs/diskcache/case-study-landing-page-caching.html - .. _`DiskCache API Reference`: http://www.grantjenks.com/docs/diskcache/api.html - .. _`DiskCache Development`: http://www.grantjenks.com/docs/diskcache/development.html - - Comparisons - ----------- - - Comparisons to popular projects related to `DiskCache`_. - - Key-Value Stores - ................ - - `DiskCache`_ is mostly a simple key-value store. Feature comparisons with four - other projects are shown in the tables below. - - * `dbm`_ is part of Python's standard library and implements a generic - interface to variants of the DBM database — dbm.gnu or dbm.ndbm. If none of - these modules is installed, the slow-but-simple dbm.dumb is used. - * `shelve`_ is part of Python's standard library and implements a “shelf” as a - persistent, dictionary-like object. The difference with “dbm” databases is - that the values can be anything that the pickle module can handle. - * `sqlitedict`_ is a lightweight wrapper around Python's sqlite3 database with - a simple, Pythonic dict-like interface and support for multi-thread - access. Keys are arbitrary strings, values arbitrary pickle-able objects. - * `pickleDB`_ is a lightweight and simple key-value store. It is built upon - Python's simplejson module and was inspired by Redis. It is licensed with the - BSD three-caluse license. - - .. _`dbm`: https://docs.python.org/3/library/dbm.html - .. _`shelve`: https://docs.python.org/3/library/shelve.html - .. _`sqlitedict`: https://github.com/RaRe-Technologies/sqlitedict - .. _`pickleDB`: https://pythonhosted.org/pickleDB/ - - **Features** - - ================ ============= ========= ========= ============ ============ - Feature diskcache dbm shelve sqlitedict pickleDB - ================ ============= ========= ========= ============ ============ - Atomic? Always Maybe Maybe Maybe No - Persistent? Yes Yes Yes Yes Yes - Thread-safe? Yes No No Yes No - Process-safe? Yes No No Maybe No - Backend? SQLite DBM DBM SQLite File - Serialization? Customizable None Pickle Customizable JSON - Data Types? Mapping/Deque Mapping Mapping Mapping Mapping - Ordering? Insert/Sorted None None None None - Eviction? LRU/LFU/more None None None None - Vacuum? Automatic Maybe Maybe Manual Automatic - Transactions? Yes No No Maybe No - Multiprocessing? Yes No No No No - Forkable? Yes No No No No - Metadata? Yes No No No No - ================ ============= ========= ========= ============ ============ - - **Quality** - - ================ ============= ========= ========= ============ ============ - Project diskcache dbm shelve sqlitedict pickleDB - ================ ============= ========= ========= ============ ============ - Tests? Yes Yes Yes Yes Yes - Coverage? Yes Yes Yes Yes No - Stress? Yes No No No No - CI Tests? Linux/Windows Yes Yes Linux No - Python? 2/3/PyPy All All 2/3 2/3 - License? Apache2 Python Python Apache2 3-Clause BSD - Docs? Extensive Summary Summary Readme Summary - Benchmarks? Yes No No No No - Sources? GitHub GitHub GitHub GitHub GitHub - Pure-Python? Yes Yes Yes Yes Yes - Server? No No No No No - Integrations? Django None None None None - ================ ============= ========= ========= ============ ============ - - **Timings** - - These are rough measurements. See `DiskCache Cache Benchmarks`_ for more - rigorous data. - - ================ ============= ========= ========= ============ ============ - Project diskcache dbm shelve sqlitedict pickleDB - ================ ============= ========= ========= ============ ============ - get 25 µs 36 µs 41 µs 513 µs 92 µs - set 198 µs 900 µs 928 µs 697 µs 1,020 µs - delete 248 µs 740 µs 702 µs 1,717 µs 1,020 µs - ================ ============= ========= ========= ============ ============ - - Caching Libraries - ................. - - * `joblib.Memory`_ provides caching functions and works by explicitly saving - the inputs and outputs to files. It is designed to work with non-hashable and - potentially large input and output data types such as numpy arrays. - * `klepto`_ extends Python’s `lru_cache` to utilize different keymaps and - alternate caching algorithms, such as `lfu_cache` and `mru_cache`. Klepto - uses a simple dictionary-sytle interface for all caches and archives. - - .. _`klepto`: https://pypi.org/project/klepto/ - .. _`joblib.Memory`: https://joblib.readthedocs.io/en/latest/memory.html - - Data Structures - ............... - - * `dict`_ is a mapping object that maps hashable keys to arbitrary - values. Mappings are mutable objects. There is currently only one standard - Python mapping type, the dictionary. - * `pandas`_ is a Python package providing fast, flexible, and expressive data - structures designed to make working with “relational” or “labeled” data both - easy and intuitive. - * `Sorted Containers`_ is an Apache2 licensed sorted collections library, - written in pure-Python, and fast as C-extensions. Sorted Containers - implements sorted list, sorted dictionary, and sorted set data types. - - .. _`dict`: https://docs.python.org/3/library/stdtypes.html#typesmapping - .. _`pandas`: https://pandas.pydata.org/ - .. _`Sorted Containers`: http://www.grantjenks.com/docs/sortedcontainers/ - - Pure-Python Databases - ..................... - - * `ZODB`_ supports an isomorphic interface for database operations which means - there's little impact on your code to make objects persistent and there's no - database mapper that partially hides the datbase. - * `CodernityDB`_ is an open source, pure-Python, multi-platform, schema-less, - NoSQL database and includes an HTTP server version, and a Python client - library that aims to be 100% compatible with the embedded version. - * `TinyDB`_ is a tiny, document oriented database optimized for your - happiness. If you need a simple database with a clean API that just works - without lots of configuration, TinyDB might be the right choice for you. - - .. _`ZODB`: http://www.zodb.org/ - .. _`CodernityDB`: https://pypi.org/project/CodernityDB/ - .. _`TinyDB`: https://tinydb.readthedocs.io/ - - Object Relational Mappings (ORM) - ................................ - - * `Django ORM`_ provides models that are the single, definitive source of - information about data and contains the essential fields and behaviors of the - stored data. Generally, each model maps to a single SQL database table. - * `SQLAlchemy`_ is the Python SQL toolkit and Object Relational Mapper that - gives application developers the full power and flexibility of SQL. It - provides a full suite of well known enterprise-level persistence patterns. - * `Peewee`_ is a simple and small ORM. It has few (but expressive) concepts, - making it easy to learn and intuitive to use. Peewee supports Sqlite, MySQL, - and PostgreSQL with tons of extensions. - * `SQLObject`_ is a popular Object Relational Manager for providing an object - interface to your database, with tables as classes, rows as instances, and - columns as attributes. - * `Pony ORM`_ is a Python ORM with beautiful query syntax. Use Python syntax - for interacting with the database. Pony translates such queries into SQL and - executes them in the database in the most efficient way. - - .. _`Django ORM`: https://docs.djangoproject.com/en/dev/topics/db/ - .. _`SQLAlchemy`: https://www.sqlalchemy.org/ - .. _`Peewee`: http://docs.peewee-orm.com/ - .. _`dataset`: https://dataset.readthedocs.io/ - .. _`SQLObject`: http://sqlobject.org/ - .. _`Pony ORM`: https://ponyorm.com/ - - SQL Databases - ............. - - * `SQLite`_ is part of Python's standard library and provides a lightweight - disk-based database that doesn’t require a separate server process and allows - accessing the database using a nonstandard variant of the SQL query language. - * `MySQL`_ is one of the world’s most popular open source databases and has - become a leading database choice for web-based applications. MySQL includes a - standardized database driver for Python platforms and development. - * `PostgreSQL`_ is a powerful, open source object-relational database system - with over 30 years of active development. Psycopg is the most popular - PostgreSQL adapter for the Python programming language. - * `Oracle DB`_ is a relational database management system (RDBMS) from the - Oracle Corporation. Originally developed in 1977, Oracle DB is one of the - most trusted and widely used enterprise relational database engines. - * `Microsoft SQL Server`_ is a relational database management system developed - by Microsoft. As a database server, it stores and retrieves data as requested - by other software applications. - - .. _`SQLite`: https://docs.python.org/3/library/sqlite3.html - .. _`MySQL`: https://dev.mysql.com/downloads/connector/python/ - .. _`PostgreSQL`: http://initd.org/psycopg/ - .. _`Oracle DB`: https://pypi.org/project/cx_Oracle/ - .. _`Microsoft SQL Server`: https://pypi.org/project/pyodbc/ - - Other Databases - ............... - - * `Memcached`_ is free and open source, high-performance, distributed memory - object caching system, generic in nature, but intended for use in speeding up - dynamic web applications by alleviating database load. - * `Redis`_ is an open source, in-memory data structure store, used as a - database, cache and message broker. It supports data structures such as - strings, hashes, lists, sets, sorted sets with range queries, and more. - * `MongoDB`_ is a cross-platform document-oriented database program. Classified - as a NoSQL database program, MongoDB uses JSON-like documents with - schema. PyMongo is the recommended way to work with MongoDB from Python. - * `LMDB`_ is a lightning-fast, memory-mapped database. With memory-mapped - files, it has the read performance of a pure in-memory database while - retaining the persistence of standard disk-based databases. - * `BerkeleyDB`_ is a software library intended to provide a high-performance - embedded database for key/value data. Berkeley DB is a programmatic toolkit - that provides built-in database support for desktop and server applications. - * `LevelDB`_ is a fast key-value storage library written at Google that - provides an ordered mapping from string keys to string values. Data is stored - sorted by key and users can provide a custom comparison function. - - .. _`Memcached`: https://pypi.org/project/python-memcached/ - .. _`MongoDB`: https://api.mongodb.com/python/current/ - .. _`Redis`: https://redis.io/clients#python - .. _`LMDB`: https://lmdb.readthedocs.io/ - .. _`BerkeleyDB`: https://pypi.org/project/bsddb3/ - .. _`LevelDB`: https://plyvel.readthedocs.io/ - - Reference - --------- - - * `DiskCache Documentation`_ - * `DiskCache at PyPI`_ - * `DiskCache at GitHub`_ - * `DiskCache Issue Tracker`_ - - .. _`DiskCache Documentation`: http://www.grantjenks.com/docs/diskcache/ - .. _`DiskCache at PyPI`: https://pypi.python.org/pypi/diskcache/ - .. _`DiskCache at GitHub`: https://github.com/grantjenks/python-diskcache/ - .. _`DiskCache Issue Tracker`: https://github.com/grantjenks/python-diskcache/issues/ - - License - ------- - - Copyright 2016-2019 Grant Jenks - - Licensed under the Apache License, Version 2.0 (the "License"); you may not use - this file except in compliance with the License. You may obtain a copy of the - License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software distributed - under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. See the License for the - specific language governing permissions and limitations under the License. - - .. _`DiskCache`: http://www.grantjenks.com/docs/diskcache/ - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy diff --git a/third_party/python/diskcache/LICENSE b/third_party/python/diskcache/diskcache-4.1.0.dist-info/LICENSE similarity index 100% rename from third_party/python/diskcache/LICENSE rename to third_party/python/diskcache/diskcache-4.1.0.dist-info/LICENSE diff --git a/third_party/python/diskcache/README.rst b/third_party/python/diskcache/diskcache-4.1.0.dist-info/METADATA similarity index 94% rename from third_party/python/diskcache/README.rst rename to third_party/python/diskcache/diskcache-4.1.0.dist-info/METADATA index 57b7a2e21d4e..dff6db382f78 100644 --- a/third_party/python/diskcache/README.rst +++ b/third_party/python/diskcache/diskcache-4.1.0.dist-info/METADATA @@ -1,3 +1,27 @@ +Metadata-Version: 2.1 +Name: diskcache +Version: 4.1.0 +Summary: Disk Cache -- Disk and file backed persistent cache. +Home-page: http://www.grantjenks.com/docs/diskcache/ +Author: Grant Jenks +Author-email: contact@grantjenks.com +License: Apache 2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy + DiskCache: Disk Backed Cache ============================ @@ -402,3 +426,5 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _`DiskCache`: http://www.grantjenks.com/docs/diskcache/ + + diff --git a/third_party/python/diskcache/diskcache-4.1.0.dist-info/RECORD b/third_party/python/diskcache/diskcache-4.1.0.dist-info/RECORD new file mode 100644 index 000000000000..d4bca0ad4555 --- /dev/null +++ b/third_party/python/diskcache/diskcache-4.1.0.dist-info/RECORD @@ -0,0 +1,12 @@ +diskcache/__init__.py,sha256=6RtBwXsSbdiZ-H44I7nLwF2-1VyVMHq1cJ5ynfnQt-E,1234 +diskcache/cli.py,sha256=JzkI2KtJJ0VRfBAq69lTkItoLwg4vOrTezczetSCfaY,40 +diskcache/core.py,sha256=nZRqL-VuJZZw1Ll5ADBzGivpIN_vXTDC8KSOyQ_XvjI,82426 +diskcache/djangocache.py,sha256=vAWT1FdmvHoHas244yoOblc6GhvozgLuFyjASMFPaK0,15488 +diskcache/fanout.py,sha256=Ha5C8BpClAHKEi6cJvJ5HvmAKlNwfiMpjb_az_hIJE0,21271 +diskcache/persistent.py,sha256=hgsS9-LymHsBeuNx0fBPOsiobvpJmGOIxT1T67BQUYw,37450 +diskcache/recipes.py,sha256=VQty-6AVoXcc6hfp1QOFvQZSf8W5AbQBFe1N3QlyILk,13849 +diskcache-4.1.0.dist-info/LICENSE,sha256=KBQYvOJPaViOo1FzqVpqPSGqW0jDZG6KiE8kLKMzNkw,559 +diskcache-4.1.0.dist-info/METADATA,sha256=wWGlNFCEiyWQ6R5zq3m3RFQbxELo6oJyrpryNir-yFo,19886 +diskcache-4.1.0.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110 +diskcache-4.1.0.dist-info/top_level.txt,sha256=A5fqg_AHgOQc_0o1NZ-Uo5Bsb7CV3fR99J-p1-F4yuA,10 +diskcache-4.1.0.dist-info/RECORD,, diff --git a/third_party/python/diskcache/diskcache-4.1.0.dist-info/WHEEL b/third_party/python/diskcache/diskcache-4.1.0.dist-info/WHEEL new file mode 100644 index 000000000000..78e6f69d1d8f --- /dev/null +++ b/third_party/python/diskcache/diskcache-4.1.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.4) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/diskcache/diskcache-4.1.0.dist-info/top_level.txt b/third_party/python/diskcache/diskcache-4.1.0.dist-info/top_level.txt new file mode 100644 index 000000000000..91667d46b148 --- /dev/null +++ b/third_party/python/diskcache/diskcache-4.1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +diskcache diff --git a/third_party/python/diskcache/setup.cfg b/third_party/python/diskcache/setup.cfg deleted file mode 100644 index 8bfd5a12f85b..000000000000 --- a/third_party/python/diskcache/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/diskcache/setup.py b/third_party/python/diskcache/setup.py deleted file mode 100644 index 90dc280b2767..000000000000 --- a/third_party/python/diskcache/setup.py +++ /dev/null @@ -1,51 +0,0 @@ -from io import open -from setuptools import setup -from setuptools.command.test import test as TestCommand - -import diskcache - - -class Tox(TestCommand): - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - def run_tests(self): - import tox - errno = tox.cmdline(self.test_args) - exit(errno) - - -with open('README.rst', encoding='utf-8') as reader: - readme = reader.read() - -setup( - name=diskcache.__title__, - version=diskcache.__version__, - description='Disk Cache -- Disk and file backed persistent cache.', - long_description=readme, - author='Grant Jenks', - author_email='contact@grantjenks.com', - url='http://www.grantjenks.com/docs/diskcache/', - license='Apache 2.0', - packages=['diskcache'], - tests_require=['tox'], - cmdclass={'test': Tox}, - install_requires=[], - classifiers=( - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - ), -) diff --git a/third_party/python/distro/CHANGELOG.md b/third_party/python/distro/CHANGELOG.md deleted file mode 100644 index fd32d61f4f12..000000000000 --- a/third_party/python/distro/CHANGELOG.md +++ /dev/null @@ -1,147 +0,0 @@ -## 1.4.0 (2019.2.4) - -BACKWARD COMPATIBILITY: -* Prefer the VERSION_CODENAME field of os-release to parsing it from VERSION [[#230](https://github.com/nir0s/distro/pull/230)] - -BUG FIXES: -* Return _uname_info from the uname_info() method [[#233](https://github.com/nir0s/distro/pull/233)] -* Fixed CloudLinux id discovery [[#234](https://github.com/nir0s/distro/pull/234)] -* Update Oracle matching [[#224](https://github.com/nir0s/distro/pull/224)] - -DOCS: -* Update Fedora package link [[#225](https://github.com/nir0s/distro/pull/225)] -* Distro is the recommended replacement for platform.linux_distribution [[#220](https://github.com/nir0s/distro/pull/220)] - -RELEASE: -* Use Markdown for long description in setup.py [[#219](https://github.com/nir0s/distro/pull/219)] - -Additionally, The Python2.6 branch was fixed and rebased on top of master. It is now passing all tests. Thanks [abadger](https://github.com/abadger)! - -## 1.3.0 (2018.05.09) - -ENHANCEMENTS: -* Added support for OpenBSD, FreeBSD, and NetBSD [[#207](https://github.com/nir0s/distro/issues/207)] - -TESTS: -* Add test for Kali Linux Rolling [[#214](https://github.com/nir0s/distro/issues/214)] - -DOCS: -* Update docs with regards to #207 [[#209](https://github.com/nir0s/distro/issues/209)] -* Add Ansible reference implementation and fix arch-linux link [[#213](https://github.com/nir0s/distro/issues/213)] -* Add facter reference implementation [[#213](https://github.com/nir0s/distro/issues/213)] - -## 1.2.0 (2017.12.24) - -BACKWARD COMPATIBILITY: -* Don't raise ImportError on non-linux platforms [[#202](https://github.com/nir0s/distro/issues/202)] - -ENHANCEMENTS: -* Lazily load the LinuxDistribution data [[#201](https://github.com/nir0s/distro/issues/201)] - -BUG FIXES: -* Stdout of shell should be decoded with sys.getfilesystemencoding() [[#203](https://github.com/nir0s/distro/issues/203)] - -TESTS: -* Explicitly set Python versions on Travis for flake [[#204](https://github.com/nir0s/distro/issues/204)] - - -## 1.1.0 (2017.11.28) - -BACKWARD COMPATIBILITY: -* Drop python3.3 support [[#199](https://github.com/nir0s/distro/issues/199)] -* Remove Official Python26 support [[#195](https://github.com/nir0s/distro/issues/195)] - -TESTS: -* Add MandrivaLinux test case [[#181](https://github.com/nir0s/distro/issues/181)] -* Add test cases for CloudLinux 5, 6, and 7 [[#180](https://github.com/nir0s/distro/issues/180)] - -RELEASE: -* Modify MANIFEST to include resources for tests and docs in source tarballs [[97c91a1](97c91a1)] - -## 1.0.4 (2017.04.01) - -BUG FIXES: -* Guess common *-release files if /etc not readable [[#175](https://github.com/nir0s/distro/issues/175)] - -## 1.0.3 (2017.03.19) - -ENHANCEMENTS: -* Show keys for empty values when running distro from the CLI [[#160](https://github.com/nir0s/distro/issues/160)] -* Add manual mapping for `redhatenterpriseserver` (previously only redhatenterpriseworkstation was mapped) [[#148](https://github.com/nir0s/distro/issues/148)] -* Race condition in `_parse_distro_release_file` [[#163](https://github.com/nir0s/distro/issues/163)] - -TESTS: -* Add RHEL5 test case [[#165](https://github.com/nir0s/distro/issues/165)] -* Add OpenELEC test case [[#166](https://github.com/nir0s/distro/issues/166)] -* Replace nose with pytest [[#158](https://github.com/nir0s/distro/issues/158)] - -RELEASE: -* Update classifiers -* Update supported Python versions (with py36) - -## 1.0.2 (2017.01.12) - -TESTS: -* Test on py33, py36 and py3 based flake8 - -RELEASE: -* Add MANIFEST file (which also includes the LICENSE as part of Issue [[#139](https://github.com/nir0s/distro/issues/139)]) -* Default to releasing using Twine [[#121](https://github.com/nir0s/distro/issues/121)] -* Add setup.cfg file [[#145](https://github.com/nir0s/distro/issues/145)] -* Update license in setup.py - -## 1.0.1 (2016-11-03) - -ENHANCEMENTS: -* Prettify distro -j's output and add more elaborate docs [[#147](https://github.com/nir0s/distro/issues/147)] -* Decode output of `lsb_release` as utf-8 [[#144](https://github.com/nir0s/distro/issues/144)] -* Logger now uses `message %s, string` form to not-evaulate log messages if unnecessary [[#145](https://github.com/nir0s/distro/issues/145)] - -TESTS: -* Increase code-coverage [[#146](https://github.com/nir0s/distro/issues/146)] -* Fix landscape code-quality warnings [[#145](https://github.com/nir0s/distro/issues/145)] - -RELEASE: -* Add CONTRIBUTING.md - -## 1.0.0 (2016-09-25) - -BACKWARD COMPATIBILITY: -* raise exception when importing on non-supported platforms [[#129](https://github.com/nir0s/distro/issues/129)] - -ENHANCEMENTS: -* Use `bytes` invariantly [[#135](https://github.com/nir0s/distro/issues/135)] -* Some minor code adjustments plus a CLI [[#134](https://github.com/nir0s/distro/issues/134)] -* Emit stderr if `lsb_release` fails - -BUG FIXES: -* Fix some encoding related issues - -TESTS: -* Add many test cases (e.g. Raspbian 8, CoreOS, Amazon Linux, Scientific Linux, Gentoo, Manjaro) -* Completely redo the testing framework to make it easier to add tests -* Test on pypy - -RELEASE: -* Remove six as a dependency - -## 0.6.0 (2016-04-21) - -This is the first release of `distro`. -All previous work was done on `ld` and therefore unmentioned here. See the release log in GitHub if you want the entire log. - -BACKWARD COMPATIBILITY: -* No longer a package. constants.py has been removed and distro is now a single module - -ENHANCEMENTS: -* distro.info() now receives best and pretty flags -* Removed get_ prefix from get_*_release_attr functions -* Codename is now passed in distro.info() - -TESTS: -* Added Linux Mint test case -* Now testing on Python 3.4 - -DOCS: -* Documentation fixes - diff --git a/third_party/python/distro/CONTRIBUTING.md b/third_party/python/distro/CONTRIBUTING.md deleted file mode 100644 index 4948ef24e9d6..000000000000 --- a/third_party/python/distro/CONTRIBUTING.md +++ /dev/null @@ -1,54 +0,0 @@ -# General - -* Contributing to distro identification currently doesn't have any specific standards and rather depends on the specific implementation. -* A 100% coverage is expected for each PR unless explicitly authorized by the reviewer. -* Please try to maintain maximum code-health (via landscape.io). - -# Contributing distro specific tests - -Distro's tests are implemented via a standardized framework under `tests/test_distro.py` - -For each distribution, tests should be added in the relevant class according to which distribution file(s) exists on it, so, for example, tests should be added under `TestOSRelease` where `/etc/os-release` is available. - -The tests must be self-contained, meaning that the release files for the distribution should be maintained in the repository under `tests/resources/distros/distribution_name+distribution_version`. - -A tests method would like somewhat like this: - -```python -def test_centos7_os_release(self): - desired_outcome = { - 'id': 'centos', - 'name': 'CentOS Linux', - 'pretty_name': 'CentOS Linux 7 (Core)', - 'version': '7', - 'pretty_version': '7 (Core)', - 'best_version': '7', - 'like': 'rhel fedora', - 'codename': 'Core' - } - self._test_outcome(desired_outcome) -``` - -The framework will automatically try to pick up the relevant file according to the method's name (`centos7` meaning the folder should be named `centos7` as well) and compare the `desired_outcome` with the parsed files found under the test dir. - -The exception to the rule is under the `TestDistroRelease` test class which should look somewhat like this: - -```python -def test_centos5_dist_release(self): - desired_outcome = { - 'id': 'centos', - 'name': 'CentOS', - 'pretty_name': 'CentOS 5.11 (Final)', - 'version': '5.11', - 'pretty_version': '5.11 (Final)', - 'best_version': '5.11', - 'codename': 'Final', - 'major_version': '5', - 'minor_version': '11' - } - self._test_outcome(desired_outcome, 'centos', '5') -``` - -Where the name of the method is not indicative of the lookup folder but rather tha two last arguments in `_test_outcome`. - -A test case is mandatory under `TestOverall` for a PR to be complete. \ No newline at end of file diff --git a/third_party/python/distro/CONTRIBUTORS.md b/third_party/python/distro/CONTRIBUTORS.md deleted file mode 100644 index 922f6533e228..000000000000 --- a/third_party/python/distro/CONTRIBUTORS.md +++ /dev/null @@ -1,13 +0,0 @@ -Thanks! - -* https://github.com/andy-maier -* https://github.com/SethMichaelLarson -* https://github.com/asottile -* https://github.com/MartijnBraam -* https://github.com/funkyfuture -* https://github.com/adamjstewart -* https://github.com/xavfernandez -* https://github.com/xsuchy -* https://github.com/marcoceppi -* https://github.com/tgamblin -* https://github.com/sebix diff --git a/third_party/python/distro/MANIFEST.in b/third_party/python/distro/MANIFEST.in deleted file mode 100644 index 4d95f6ce8e8b..000000000000 --- a/third_party/python/distro/MANIFEST.in +++ /dev/null @@ -1,12 +0,0 @@ -include *.md -include *.py -include *.txt -include LICENSE -include CHANGES -include Makefile - -graft tests - -include docs/* - -global-exclude *.py[co] diff --git a/third_party/python/distro/Makefile b/third_party/python/distro/Makefile deleted file mode 100644 index 97eaba7251c9..000000000000 --- a/third_party/python/distro/Makefile +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2015,2016 Nir Cohen -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Name of this package -PACKAGENAME = distro - -# Additional options for Sphinx -SPHINXOPTS = -v - -# Paper format for the Sphinx LaTex/PDF builder. -# Valid values: a4, letter -SPHINXPAPER = a4 - -# Sphinx build subtree. -SPHINXBUILDDIR = build_docs - -# Directory where conf.py is located -SPHINXCONFDIR = docs - -# Directory where input files for Sphinx are located -SPHINXSOURCEDIR = . - -# Sphinx build command (Use 'pip install sphinx' to get it) -SPHINXBUILD = sphinx-build - -# Internal variables for Sphinx -SPHINXPAPEROPT_a4 = -D latex_paper_size=a4 -SPHINXPAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(SPHINXBUILDDIR)/doctrees -c $(SPHINXCONFDIR) \ - $(SPHINXPAPEROPT_$(SPHINXPAPER)) $(SPHINXOPTS) \ - $(SPHINXSOURCEDIR) - -.PHONY: help -help: - @echo 'Please use "make " where is one of' - @echo " release - build a release and publish it" - @echo " dev - prepare a development environment (includes tests)" - @echo " instdev - prepare a development environment (no tests)" - @echo " install - install into current Python environment" - @echo " html - generate docs as standalone HTML files in: $(SPHINXBUILDDIR)/html" - @echo " pdf - generate docs as PDF (via LaTeX) for paper format: $(SPHINXPAPER) in: $(SPHINXBUILDDIR)/pdf" - @echo " man - generate docs as manual pages in: $(SPHINXBUILDDIR)/man" - @echo " docchanges - generate an overview of all changed/added/deprecated items in docs" - @echo " doclinkcheck - check all external links in docs for integrity" - @echo " doccoverage - run coverage check of the documentation" - @echo " clobber - remove any build products" - @echo " build - build the package" - @echo " test - test from this directory using tox, including test coverage" - @echo " publish - upload to PyPI" - @echo " clean - remove any temporary build products" - @echo " dry-run - perform all action required for a release without actually releasing" - -.PHONY: release -release: test clean build publish - @echo "$@ done." - -.PHONY: test -test: - pip install 'tox>=1.7.2' - tox - @echo "$@ done." - -.PHONY: clean -clean: - rm -rf dist build $(PACKAGENAME).egg-info - @echo "$@ done." - -.PHONY: build -build: - python setup.py sdist bdist_wheel - -.PHONY: publish -publish: - twine upload -r pypi dist/$(PACKAGENAME)-* - @echo "$@ done." - -.PHONY: dry-run -dry-run: test clean build - @echo "$@ done." - -.PHONY: dev -dev: instdev test - @echo "$@ done." - -.PHONY: instdev -instdev: - pip install -r dev-requirements.txt - python setup.py develop - @echo "$@ done." - -.PHONY: install -install: - python setup.py install - @echo "$@ done." - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/html - @echo "$@ done; the HTML pages are in $(SPHINXBUILDDIR)/html." - -.PHONY: pdf -pdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/pdf - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(SPHINXBUILDDIR)/pdf all-pdf - @echo "$@ done; the PDF files are in $(SPHINXBUILDDIR)/pdf." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/man - @echo "$@ done; the manual pages are in $(SPHINXBUILDDIR)/man." - -.PHONY: docchanges -docchanges: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/changes - @echo - @echo "$@ done; the doc changes overview file is in $(SPHINXBUILDDIR)/changes." - -.PHONY: doclinkcheck -doclinkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/linkcheck - @echo - @echo "$@ done; look for any errors in the above output " \ - "or in $(SPHINXBUILDDIR)/linkcheck/output.txt." - -.PHONY: doccoverage -doccoverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(SPHINXBUILDDIR)/coverage - @echo "$@ done; the doc coverage results are in $(SPHINXBUILDDIR)/coverage/python.txt." - -.PHONY: clobber -clobber: clean - rm -rf $(SPHINXBUILDDIR) - @echo "$@ done." diff --git a/third_party/python/distro/PKG-INFO b/third_party/python/distro/PKG-INFO deleted file mode 100644 index eacc868d573f..000000000000 --- a/third_party/python/distro/PKG-INFO +++ /dev/null @@ -1,168 +0,0 @@ -Metadata-Version: 2.1 -Name: distro -Version: 1.4.0 -Summary: Distro - an OS platform information API -Home-page: https://github.com/nir0s/distro -Author: Nir Cohen -Author-email: nir36g@gmail.com -License: Apache License, Version 2.0 -Description: Distro - an OS platform information API - ======================================= - - [![Build Status](https://travis-ci.org/nir0s/distro.svg?branch=master)](https://travis-ci.org/nir0s/distro) - [![Build status](https://ci.appveyor.com/api/projects/status/e812qjk1gf0f74r5/branch/master?svg=true)](https://ci.appveyor.com/project/nir0s/distro/branch/master) - [![PyPI version](http://img.shields.io/pypi/v/distro.svg)](https://pypi.python.org/pypi/distro) - [![Supported Python Versions](https://img.shields.io/pypi/pyversions/distro.svg)](https://img.shields.io/pypi/pyversions/distro.svg) - [![Requirements Status](https://requires.io/github/nir0s/distro/requirements.svg?branch=master)](https://requires.io/github/nir0s/distro/requirements/?branch=master) - [![Code Coverage](https://codecov.io/github/nir0s/distro/coverage.svg?branch=master)](https://codecov.io/github/nir0s/distro?branch=master) - [![Code Quality](https://landscape.io/github/nir0s/distro/master/landscape.svg?style=flat)](https://landscape.io/github/nir0s/distro) - [![Is Wheel](https://img.shields.io/pypi/wheel/distro.svg?style=flat)](https://pypi.python.org/pypi/distro) - [![Latest Github Release](https://readthedocs.org/projects/distro/badge/?version=stable)](http://distro.readthedocs.io/en/latest/) - [![Join the chat at https://gitter.im/nir0s/distro](https://badges.gitter.im/nir0s/distro.svg)](https://gitter.im/nir0s/distro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - - `distro` provides information about the - OS distribution it runs on, such as a reliable machine-readable ID, or - version information. - - It is the recommended replacement for Python's original - [`platform.linux_distribution`](https://docs.python.org/3.7/library/platform.html#platform.linux_distribution) - function (which will be removed in Python 3.8). - It also provides much more functionality which isn't necessarily Python bound, - like a command-line interface. - - Distro currently supports Linux and BSD based systems but [Windows and OS X support](https://github.com/nir0s/distro/issues/177) is also planned. - - For Python 2.6 support, see https://github.com/nir0s/distro/tree/python2.6-support - - ## Installation - - Installation of the latest released version from PyPI: - - ```shell - pip install distro - ``` - - Installation of the latest development version: - - ```shell - pip install https://github.com/nir0s/distro/archive/master.tar.gz - ``` - - - ## Usage - - ```bash - $ distro - Name: Antergos Linux - Version: 2015.10 (ISO-Rolling) - Codename: ISO-Rolling - - $ distro -j - { - "codename": "ISO-Rolling", - "id": "antergos", - "like": "arch", - "version": "16.9", - "version_parts": { - "build_number": "", - "major": "16", - "minor": "9" - } - } - - - $ python - >>> import distro - >>> distro.linux_distribution(full_distribution_name=False) - ('centos', '7.1.1503', 'Core') - ``` - - - ## Documentation - - On top of the aforementioned API, several more functions are available. For a complete description of the - API, see the [latest API documentation](http://distro.readthedocs.org/en/latest/). - - ## Background - - An alternative implementation became necessary because Python 3.5 deprecated - this function, and Python 3.8 will remove it altogether. - Its predecessor function `platform.dist` was already deprecated since - Python 2.6 and will also be removed in Python 3.8. - Still, there are many cases in which access to that information is needed. - See [Python issue 1322](https://bugs.python.org/issue1322) for more - information. - - The `distro` package implements a robust and inclusive way of retrieving the - information about a distribution based on new standards and old methods, - namely from these data sources (from high to low precedence): - - * The os-release file `/etc/os-release`, if present. - * The output of the `lsb_release` command, if available. - * The distro release file (`/etc/*(-|_)(release|version)`), if present. - * The `uname` command for BSD based distrubtions. - - - ## Python and Distribution Support - - `distro` is supported and tested on Python 2.7, 3.4+ and PyPy and on - any distribution that provides one or more of the data sources - covered. - - This package is tested with test data that mimics the exact behavior of the data sources of [a number of Linux distributions](https://github.com/nir0s/distro/tree/master/tests/resources/distros). - - - ## Testing - - ```shell - git clone git@github.com:nir0s/distro.git - cd distro - pip install tox - tox - ``` - - - ## Contributions - - Pull requests are always welcome to deal with specific distributions or just - for general merriment. - - See [CONTRIBUTIONS](https://github.com/nir0s/distro/blob/master/CONTRIBUTING.md) for contribution info. - - Reference implementations for supporting additional distributions and file - formats can be found here: - - * https://github.com/saltstack/salt/blob/develop/salt/grains/core.py#L1172 - * https://github.com/chef/ohai/blob/master/lib/ohai/plugins/linux/platform.rb - * https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py - * https://github.com/puppetlabs/facter/blob/master/lib/src/facts/linux/os_linux.cc - - ## Package manager distributions - - * https://src.fedoraproject.org/rpms/python-distro - * https://www.archlinux.org/packages/community/any/python-distro/ - * https://launchpad.net/ubuntu/+source/python-distro - * https://packages.debian.org/sid/python-distro - * https://packages.gentoo.org/packages/dev-python/distro - * https://pkgs.org/download/python2-distro - * https://slackbuilds.org/repository/14.2/python/python-distro/ - -Platform: All -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: BSD :: FreeBSD -Classifier: Operating System :: POSIX :: BSD :: NetBSD -Classifier: Operating System :: POSIX :: BSD :: OpenBSD -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Operating System -Description-Content-Type: text/markdown diff --git a/third_party/python/distro/dev-requirements.txt b/third_party/python/distro/dev-requirements.txt deleted file mode 100644 index 738958e01fe9..000000000000 --- a/third_party/python/distro/dev-requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pytest -pytest-cov -sphinx>=1.1 \ No newline at end of file diff --git a/third_party/python/distro/LICENSE b/third_party/python/distro/distro-1.4.0.dist-info/LICENSE similarity index 100% rename from third_party/python/distro/LICENSE rename to third_party/python/distro/distro-1.4.0.dist-info/LICENSE diff --git a/third_party/python/distro/README.md b/third_party/python/distro/distro-1.4.0.dist-info/METADATA similarity index 82% rename from third_party/python/distro/README.md rename to third_party/python/distro/distro-1.4.0.dist-info/METADATA index 57d681c5c1c6..b34cf6205d1d 100644 --- a/third_party/python/distro/README.md +++ b/third_party/python/distro/distro-1.4.0.dist-info/METADATA @@ -1,3 +1,31 @@ +Metadata-Version: 2.1 +Name: distro +Version: 1.4.0 +Summary: Distro - an OS platform information API +Home-page: https://github.com/nir0s/distro +Author: Nir Cohen +Author-email: nir36g@gmail.com +License: Apache License, Version 2.0 +Platform: All +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: BSD :: FreeBSD +Classifier: Operating System :: POSIX :: BSD :: NetBSD +Classifier: Operating System :: POSIX :: BSD :: OpenBSD +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Operating System +Description-Content-Type: text/markdown + Distro - an OS platform information API ======================================= @@ -138,3 +166,5 @@ formats can be found here: * https://packages.gentoo.org/packages/dev-python/distro * https://pkgs.org/download/python2-distro * https://slackbuilds.org/repository/14.2/python/python-distro/ + + diff --git a/third_party/python/distro/distro-1.4.0.dist-info/RECORD b/third_party/python/distro/distro-1.4.0.dist-info/RECORD new file mode 100644 index 000000000000..ac0fb59ebed1 --- /dev/null +++ b/third_party/python/distro/distro-1.4.0.dist-info/RECORD @@ -0,0 +1,7 @@ +distro.py,sha256=X2So5kjrRKyMbQJ90Xgy93HU5eFtujCzKaYNeoy1k1c,43251 +distro-1.4.0.dist-info/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325 +distro-1.4.0.dist-info/METADATA,sha256=7u13dPkDA9zu5ahg3Ns-H2vfMpR6gBBS55EaBzlXIeg,6648 +distro-1.4.0.dist-info/WHEEL,sha256=_wJFdOYk7i3xxT8ElOkUJvOdOvfNGbR9g-bf6UQT6sU,110 +distro-1.4.0.dist-info/entry_points.txt,sha256=mDMyvS_AzB0WhRYe_6xrRkAAET1LwFiDTL5Sx57UFiY,40 +distro-1.4.0.dist-info/top_level.txt,sha256=ikde_V_XEdSBqaGd5tEriN_wzYHLgTX_zVtlsGLHvwQ,7 +distro-1.4.0.dist-info/RECORD,, diff --git a/third_party/python/distro/distro-1.4.0.dist-info/WHEEL b/third_party/python/distro/distro-1.4.0.dist-info/WHEEL new file mode 100644 index 000000000000..c4bde3037775 --- /dev/null +++ b/third_party/python/distro/distro-1.4.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.32.3) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/distro/distro-1.4.0.dist-info/entry_points.txt b/third_party/python/distro/distro-1.4.0.dist-info/entry_points.txt new file mode 100644 index 000000000000..dd4023997f5b --- /dev/null +++ b/third_party/python/distro/distro-1.4.0.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +distro = distro:main + diff --git a/third_party/python/distro/distro-1.4.0.dist-info/top_level.txt b/third_party/python/distro/distro-1.4.0.dist-info/top_level.txt new file mode 100644 index 000000000000..0e0933171d3e --- /dev/null +++ b/third_party/python/distro/distro-1.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +distro diff --git a/third_party/python/distro/distro.py b/third_party/python/distro/distro.py old mode 100755 new mode 100644 diff --git a/third_party/python/distro/query_local_distro.py b/third_party/python/distro/query_local_distro.py deleted file mode 100755 index 5c5ed9ef6f77..000000000000 --- a/third_party/python/distro/query_local_distro.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015,2016 Nir Cohen -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function - -from pprint import pformat - -import distro - - -def pprint(obj): - for line in pformat(obj).split('\n'): - print(4 * ' ' + line) - - -print('os_release_info:') -pprint(distro.os_release_info()) -print('lsb_release_info:') -pprint(distro.lsb_release_info()) -print('distro_release_info:') -pprint(distro.distro_release_info()) -print('id: {0}'.format(distro.id())) -print('name: {0}'.format(distro.name())) -print('name_pretty: {0}'.format(distro.name(True))) -print('version: {0}'.format(distro.version())) -print('version_pretty: {0}'.format(distro.version(True))) -print('like: {0}'.format(distro.like())) -print('codename: {0}'.format(distro.codename())) -print('linux_distribution_full: {0}'.format(distro.linux_distribution())) -print('linux_distribution: {0}'.format(distro.linux_distribution(False))) -print('major_version: {0}'.format(distro.major_version())) -print('minor_version: {0}'.format(distro.minor_version())) -print('build_number: {0}'.format(distro.build_number())) diff --git a/third_party/python/distro/setup.cfg b/third_party/python/distro/setup.cfg deleted file mode 100644 index 51b5f83b3da1..000000000000 --- a/third_party/python/distro/setup.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/distro/setup.py b/third_party/python/distro/setup.py deleted file mode 100644 index 0657449267bd..000000000000 --- a/third_party/python/distro/setup.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2015,2016 Nir Cohen -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import codecs -from setuptools import setup - -# The following version is parsed by other parts of this package. -# Don't change the format of the line, or the variable name. -package_version = "1.4.0" - -here = os.path.abspath(os.path.dirname(__file__)) - - -def read(*parts): - # intentionally *not* adding an encoding option to open - return codecs.open(os.path.join(here, *parts), 'r').read() - - -setup( - name='distro', - version=package_version, - url='https://github.com/nir0s/distro', - author='Nir Cohen', - author_email='nir36g@gmail.com', - license='Apache License, Version 2.0', - platforms='All', - description='Distro - an OS platform information API', - long_description=read('README.md'), - long_description_content_type='text/markdown', - py_modules=['distro'], - entry_points={ - 'console_scripts': [ - 'distro = distro:main', - ] - }, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: POSIX :: Linux', - 'Operating System :: POSIX :: BSD', - 'Operating System :: POSIX :: BSD :: FreeBSD', - 'Operating System :: POSIX :: BSD :: NetBSD', - 'Operating System :: POSIX :: BSD :: OpenBSD', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: System :: Operating System', - ] -) diff --git a/third_party/python/ecdsa/MANIFEST.in b/third_party/python/ecdsa/MANIFEST.in deleted file mode 100644 index a728ebd8f344..000000000000 --- a/third_party/python/ecdsa/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -# basic metadata -include MANIFEST.in LICENSE NEWS README.md versioneer.py -include src/ecdsa/_version.py diff --git a/third_party/python/ecdsa/NEWS b/third_party/python/ecdsa/NEWS deleted file mode 100644 index 682fd5f9de61..000000000000 --- a/third_party/python/ecdsa/NEWS +++ /dev/null @@ -1,213 +0,0 @@ -* Release 0.15 (02 Jan 2020) - -Bug fixes: -`from curves import *` will now correctly import `BRAINPOOLP256r1` and -`BRAINPOOLP320r1` curves. - -New features: -ECDH operations have a public explicit API. -Large hashes are now supported with small curves (e.g. SHA-256 can be used -with NIST192p). -`VerifyingKey` now supports the `precompute()` method to further speed up -signature verification with the given instance of the key. - -New API: -`VerifyingKey`, `SigningKey`, `Public_key`, `Private_key` and -`CurveFp` now have `__eq__` methods. -`ecdsa.ecdh` module and `ECDH` class. -`PointJacobi` added. -`VerifyingKey.verify_digest`, `SigningKey.sign_digest` and -`SigningKey.sign_digest_deterministic` methods now accept `allow_truncate` -argument to enable use of hashes larger than the curve order. -`VerifyingKey` `from_pem` and `from_der` now accept `hashfunc` parameter -like other `from*` methods. -`VerifyingKey` has `precompute` method now. -`VerifyingKey.from_public_point` may now not perform validation of public -point when `validate_point=False` argument is passed to method. -`CurveFp` constructor now accepts the `h` parameter - the cofactor of the -elliptic curve, it's used for selection of algorithm of public point -verification. - -Performance: -`randrange` now will now perform much fewer calls to system random number -generator. -`PointJacobi` introduced and used as the underlying implementation; speeds up -the library by a factor of about 20. -Library has now optional dependencies on `gmpy` and `gmpy2`. When they are -availbale, the elliptic curve calculations will be about 3 times faster. - -Maintenance: -expected minimum version of `six` module (1.9.0) is now specified explicitly -in `setup.py` and tested against. -Significantly faster test suite execution. - -* Release 0.14.1 (06 Nov 2019) - -Remove the obsolete `six.py` file from wheel - -* Release 0.14 (06 Nov 2019) - -Bug fixes: -Strict checking of DER requirements when parsing SEQUENCE, INTEGER, -OBJECT IDENTIFIER and BITSTRING objects. -DER parsers now consistently raise `UnexpectedDER` exception on malformed DER -encoded byte strings. -Make sure that both malformed and invalid signatures raise `BadSignatureError`. -Ensure that all `SigningKey` and `VerifyingKey` methods that should accept -bytes-like objects actually do accept them (also avoid copying input strings). -Make `SigningKey.sign_digest_deterministic` use default object hashfunc when -none was provided. -`encode_integer` now works for large integers. -Make `encode_oid` and `remove_object` correctly handle OBJECT IDENTIFIERs -with large second subidentifier and padding in encoded subidentifiers. - -New features: -Deterministic signature methods now accept `extra_entropy` parameter to further -randomise the selection of `k` (the nonce) for signature, as specified in -RFC6979. -Recovery of public key from signature is now supported. -Support for SEC1/X9.62 formatted keys, all three encodings are supported: -"uncompressed", "compressed" and "hybrid". Both string, and PEM/DER will -automatically accept them, if the size of the key matches the curve. -Benchmarking application now provides performance numbers that are easier to -compare against OpenSSL. -Support for all Brainpool curves (non-twisted). - -New API: -`CurveFp`: `__str__` is now supported. -`SigningKey.sign_deterministic`, `SigningKey.sign_digest_deterministic` and -`generate_k`: extra_entropy parameter was added -`Signature.recover_public_keys` was added -`VerifyingKey.from_public_key_recovery` and -`VerifyingKey.from_public_key_recovery_with_digest` were added -`VerifyingKey.to_string`: `encoding` parameter was added -`VerifyingKey.to_der` and `SigningKey.to_der`: `point_encoding` parameter was -added. -`encode_bitstring`: `unused` parameter was added -`remove_bitstring`: `expect_unused` parameter was added -`SECP256k1` is now part of `curves` `*` import -`Curves`: `__repr__` is now supported -`VerifyingKey`: `__repr__` is now supported - -Deprecations: -Python 2.5 is not supported any more - dead code removal. -`from ecdsa.keys import *` will now import only objects defined in that module. -Trying to decode a malformed point using `VerifyingKey.from_string` -will rise now the `MalformedPointError` exception (that inherits from -`AssertionError` but is not it). -Multiple functions in `numbertheory` are considered deprecated: `phi`, -`carmichael`, `carmichael_of_factorized`, `carmichael_of_ppower`, -`order_mod`, `largest_factor_relatively_prime`, `kinda_order_mod`. They will -now emit `DeprecationWarning` when used. Run the application or test suite -with `-Wd` option or with `PYTHONWARNINGS=default` environment variable to -verify if those methods are not used. They will be removed completely in a -future release. -`encode_bitstring` and `decode_bitstring` expect the number of unused -bits to be passed as an argument now. They will emit `DeprecationWarning` -if they are used in the deprecated way. -modular_exp: will emit `DeprecationWarning` - -Hardening: -Deterministic signatures now verify that the signature won't leak private -key through very unlikely selection of `k` value (the nonce). -Nonce bit size hiding was added (hardening against Minerva attack). Please -note that it DOES NOT make library secure against side channel attacks (timing -attacks). - -Performance: -The public key in key generation is not verified twice now, making key -generation and private key reading about 33% faster. -Microoptimisation to `inverse_mod` function, increasing performance by about -40% for all operations. - -Maintenance: -Extended test coverage to newer python versions. -Fixes to examples in README.md: correct commands, more correct code (now works -on Python 3). -Stopped bundling `six` -Moved sources into `src` subdirectory -Made benchmarking script standalone (runnable either with `tox -e speed`, or -after installation, with `python speed.py`) -Now test coverage reported to coveralls is branch coverage, not line coverage -Autodetection of curves supported by OpenSSL (test suite compatibility with -Fedora OpenSSL package). -More readable error messages (exceptions) in `der` module. -Documentation to `VerifyingKey`, `SigningKey` and signature encoder/decoder -functions added. -Added measuring and verifying condition coverage to Continuous Integration. -Big clean-up of the test suite, use pytest parametrisation and hypothesis -for better test coverage and more precise failure reporting. -Use platform-provided `math.gcd`, when provided. - -* Release 0.13.3 (07 Oct 2019) - -Fix CVE-2019-14853 - possible DoS caused by malformed signature decoding and -signature malleability. - -Also harden key decoding from string and DER encodings. - -* Release 0.13.2 (17 Apr 2019) - -Restore compatibility of setup.py with Python 2.6 and 2.7. - -* Release 0.13.1 (17 Apr 2019) - -Fix the PyPI wheel - the old version included .pyc files. - -* Release 0.13 (07 Feb 2015) - -Fix the argument order for Curve constructor (put openssl_name= at the end, -with a default value) to unbreak compatibility with external callers who used -the 0.11 convention. - -* Release 0.12 (06 Feb 2015) - -Switch to Versioneer for version-string management (fixing the broken -`ecdsa.__version__` attribute). Add Curve.openssl_name property. Mention -secp256k1 in README, test against OpenSSL. Produce "wheel" distributions. Add -py3.4 and pypy3 compatibility testing. Other minor fixes. - -* Release 0.11 (10 Mar 2014) - -Add signature-encoding functions "sigencode_{strings,string,der}_canonize" -which canonicalize the S value (using the smaller of the two possible -values). Add "validate_point=" argument to VerifyingKey.from_string() -constructor (defaults to True) which can be used to disable time-consuming -point validation when importing a pre-validated verifying key. Drop python2.5 -support (untested but not explicitly broken yet), update trove classifiers. - -* Release 0.10 (23 Oct 2013) - -Make the secp256k1 available in __init__.py too (thanks to Scott Bannert). - -* Release 0.9 (01 Oct 2013) - -Add secp256k1 curve (thanks to Benjamin Dauvergne). Add deterministic (no -entropy needed) signatures (thanks to slush). Added py3.2/py3.3 compatibility -(thanks to Elizabeth Myers). - -* Release 0.8 (04 Oct 2011) - -Small API addition: accept a hashfunc= argument in the constructors for -SigningKey and VerifyingKey. This makes it easier to write wrappers that e.g. -use NIST256p and SHA256 without their obligating callers to pass -hashfunc=sha256 in each time they call sign() or verify(). - -* Release 0.7 (28 Nov 2010) - -Fix test failure against OpenSSL-1.0.0 (previous versions only worked against -openssl-0.9.8 or earlier). Increase python requirement to py2.5 or later -(still no py3 compatibility, but work is underway). Replace use of obsolete -'sha' library with modern 'hashlib'. Clean up unit test runner (stop using -subprocesses). - -* Release 0.6 (15 Oct 2010) - -Small packaging changes: extract version number from git, add 'setup.py test' -command, set exit code correctly on test failure. Fix pyflakes warnings. - -* Release 0.5 (27 Apr 2010) - -Initial release. EC-DSA signature for five NIST "Suite B" GF(p) curves: -prime192v1, secp224r1, prime256v1, secp384r1, and secp521r1. DER/PEM -input/output functions, seed-to-randrange helper functions. diff --git a/third_party/python/ecdsa/PKG-INFO b/third_party/python/ecdsa/PKG-INFO deleted file mode 100644 index 06619f966322..000000000000 --- a/third_party/python/ecdsa/PKG-INFO +++ /dev/null @@ -1,620 +0,0 @@ -Metadata-Version: 2.1 -Name: ecdsa -Version: 0.15 -Summary: ECDSA cryptographic signature library (pure python) -Home-page: http://github.com/warner/python-ecdsa -Author: Brian Warner -Author-email: warner@lothar.com -License: MIT -Description: # Pure-Python ECDSA - - [![build status](https://travis-ci.org/warner/python-ecdsa.png)](http://travis-ci.org/warner/python-ecdsa) - [![Coverage Status](https://coveralls.io/repos/warner/python-ecdsa/badge.svg)](https://coveralls.io/r/warner/python-ecdsa) - [![condition coverage](https://img.shields.io/badge/condition%20coverage-81%25-yellow)](https://travis-ci.org/warner/python-ecdsa/jobs/626479178#L776) - [![Latest Version](https://img.shields.io/pypi/v/ecdsa.svg?style=flat)](https://pypi.python.org/pypi/ecdsa/) - - - This is an easy-to-use implementation of ECDSA cryptography (Elliptic Curve - Digital Signature Algorithm), implemented purely in Python, released under - the MIT license. With this library, you can quickly create keypairs (signing - key and verifying key), sign messages, and verify the signatures. The keys - and signatures are very short, making them easy to handle and incorporate - into other protocols. - - ## Features - - This library provides key generation, signing, and verifying, for five - popular NIST "Suite B" GF(p) (_prime field_) curves, with key lengths of 192, - 224, 256, 384, and 521 bits. The "short names" for these curves, as known by - the OpenSSL tool (`openssl ecparam -list_curves`), are: `prime192v1`, - `secp224r1`, `prime256v1`, `secp384r1`, and `secp521r1`. It includes the - 256-bit curve `secp256k1` used by Bitcoin. There is also support for the - regular (non-twisted) variants of Brainpool curves from 160 to 512 bits. The - "short names" of those curves are: `brainpoolP160r1`, `brainpoolP192r1`, - `brainpoolP224r1`, `brainpoolP256r1`, `brainpoolP320r1`, `brainpoolP384r1`, - `brainpoolP512r1`. - No other curves are included, but it is not too hard to add support for more - curves over prime fields. - - ## Dependencies - - This library uses only Python and the 'six' package. It is compatible with - Python 2.6, 2.7 and 3.3+. It also supports execution on the alternative - implementations like pypy and pypy3. - - If `gmpy2` or `gmpy` is installed, they will be used for faster arithmetic. - Either of them can be installed after this library is installed, - `python-ecdsa` will detect their presence on start-up and use them - automatically. - - To run the OpenSSL compatibility tests, the 'openssl' tool must be in your - `PATH`. This release has been tested successfully against OpenSSL 0.9.8o, - 1.0.0a, 1.0.2f and 1.1.1d (among others). - - - ## Installation - - This library is available on PyPI, it's recommended to install it using `pip`: - - ``` - pip install ecdsa - ``` - - In case higher performance is wanted and using native code is not a problem, - it's possible to specify installation together with `gmpy2`: - - ``` - pip install ecdsa[gmpy2] - ``` - - or (slower, legacy option): - ``` - pip install ecdsa[gmpy] - ``` - - ## Speed - - The following table shows how long this library takes to generate keypairs - (`keygen`), to sign data (`sign`), and to verify those signatures (`verify`). - All those values are in seconds. - For convenience, the inverses of those values are also provided: - how many keys per second can be generated (`keygen/s`), how many signatures - can be made per second (`sign/s`) and how many signatures can be verified - per second (`verify/s`). The size of raw signature (generally the smallest - way a signature can be encoded) is also provided in the `siglen` column. - Use `tox -e speed` to generate this table on your own computer. - On an Intel Core i7 4790K @ 4.0GHz I'm getting the following performance: - - ``` - siglen keygen keygen/s sign sign/s verify verify/s - NIST192p: 48 0.00035s 2893.02 0.00038s 2620.53 0.00069s 1458.92 - NIST224p: 56 0.00043s 2307.11 0.00048s 2092.00 0.00088s 1131.33 - NIST256p: 64 0.00056s 1793.70 0.00061s 1639.87 0.00113s 883.79 - NIST384p: 96 0.00116s 864.33 0.00124s 806.29 0.00233s 429.87 - NIST521p: 132 0.00221s 452.16 0.00234s 427.31 0.00460s 217.19 - SECP256k1: 64 0.00056s 1772.65 0.00061s 1628.73 0.00110s 912.13 - BRAINPOOLP160r1: 40 0.00026s 3801.86 0.00029s 3401.11 0.00052s 1930.47 - BRAINPOOLP192r1: 48 0.00034s 2925.73 0.00038s 2634.34 0.00070s 1438.06 - BRAINPOOLP224r1: 56 0.00044s 2287.98 0.00048s 2083.87 0.00088s 1137.52 - BRAINPOOLP256r1: 64 0.00056s 1774.11 0.00061s 1628.25 0.00112s 890.71 - BRAINPOOLP320r1: 80 0.00081s 1238.18 0.00087s 1146.71 0.00151s 661.95 - BRAINPOOLP384r1: 96 0.00117s 855.47 0.00124s 804.56 0.00241s 414.83 - BRAINPOOLP512r1: 128 0.00223s 447.99 0.00234s 427.49 0.00437s 229.09 - - ecdh ecdh/s - NIST192p: 0.00110s 910.70 - NIST224p: 0.00143s 701.17 - NIST256p: 0.00178s 560.44 - NIST384p: 0.00383s 261.03 - NIST521p: 0.00745s 134.23 - SECP256k1: 0.00168s 596.23 - BRAINPOOLP160r1: 0.00085s 1174.02 - BRAINPOOLP192r1: 0.00113s 883.47 - BRAINPOOLP224r1: 0.00145s 687.82 - BRAINPOOLP256r1: 0.00195s 514.03 - BRAINPOOLP320r1: 0.00277s 360.80 - BRAINPOOLP384r1: 0.00412s 242.58 - BRAINPOOLP512r1: 0.00787s 127.12 - ``` - - To test performance with `gmpy2` loaded, use `tox -e speedgmpy2`. - On the same machine I'm getting the following performance with `gmpy2`: - ``` - siglen keygen keygen/s sign sign/s verify verify/s - NIST192p: 48 0.00017s 5945.50 0.00018s 5544.66 0.00033s 3002.54 - NIST224p: 56 0.00021s 4742.14 0.00022s 4463.52 0.00044s 2248.59 - NIST256p: 64 0.00024s 4155.73 0.00025s 3994.28 0.00047s 2105.34 - NIST384p: 96 0.00041s 2415.06 0.00043s 2316.41 0.00085s 1177.18 - NIST521p: 132 0.00072s 1391.14 0.00074s 1359.63 0.00140s 716.31 - SECP256k1: 64 0.00024s 4216.50 0.00025s 3994.52 0.00047s 2120.57 - BRAINPOOLP160r1: 40 0.00014s 7038.99 0.00015s 6501.55 0.00029s 3397.79 - BRAINPOOLP192r1: 48 0.00017s 5983.18 0.00018s 5626.08 0.00035s 2843.62 - BRAINPOOLP224r1: 56 0.00021s 4727.54 0.00022s 4464.86 0.00043s 2326.84 - BRAINPOOLP256r1: 64 0.00024s 4221.00 0.00025s 4010.26 0.00049s 2046.40 - BRAINPOOLP320r1: 80 0.00032s 3142.14 0.00033s 3009.15 0.00061s 1652.88 - BRAINPOOLP384r1: 96 0.00041s 2415.98 0.00043s 2340.35 0.00083s 1198.77 - BRAINPOOLP512r1: 128 0.00064s 1567.27 0.00066s 1526.33 0.00127s 788.51 - - ecdh ecdh/s - NIST192p: 0.00051s 1960.26 - NIST224p: 0.00067s 1502.97 - NIST256p: 0.00073s 1376.12 - NIST384p: 0.00132s 758.68 - NIST521p: 0.00231s 433.23 - SECP256k1: 0.00072s 1387.18 - BRAINPOOLP160r1: 0.00042s 2366.60 - BRAINPOOLP192r1: 0.00049s 2026.80 - BRAINPOOLP224r1: 0.00067s 1486.52 - BRAINPOOLP256r1: 0.00076s 1310.31 - BRAINPOOLP320r1: 0.00101s 986.16 - BRAINPOOLP384r1: 0.00131s 761.35 - BRAINPOOLP512r1: 0.00211s 473.30 - ``` - - (there's also `gmpy` version, execute it using `tox -e speedgmpy`) - - For comparison, a highly optimised implementation (including curve-specific - assembly for some curves), like the one in OpenSSL 1.1.1d, provides following - performance numbers on the same machine. - Run `openssl speed ecdsa` and `openssl speed ecdh` to reproduce it: - ``` - sign verify sign/s verify/s - 192 bits ecdsa (nistp192) 0.0002s 0.0002s 4785.6 5380.7 - 224 bits ecdsa (nistp224) 0.0000s 0.0001s 22475.6 9822.0 - 256 bits ecdsa (nistp256) 0.0000s 0.0001s 45069.6 14166.6 - 384 bits ecdsa (nistp384) 0.0008s 0.0006s 1265.6 1648.1 - 521 bits ecdsa (nistp521) 0.0003s 0.0005s 3753.1 1819.5 - 256 bits ecdsa (brainpoolP256r1) 0.0003s 0.0003s 2983.5 3333.2 - 384 bits ecdsa (brainpoolP384r1) 0.0008s 0.0007s 1258.8 1528.1 - 512 bits ecdsa (brainpoolP512r1) 0.0015s 0.0012s 675.1 860.1 - - op op/s - 192 bits ecdh (nistp192) 0.0002s 4853.4 - 224 bits ecdh (nistp224) 0.0001s 15252.1 - 256 bits ecdh (nistp256) 0.0001s 18436.3 - 384 bits ecdh (nistp384) 0.0008s 1292.7 - 521 bits ecdh (nistp521) 0.0003s 2884.7 - 256 bits ecdh (brainpoolP256r1) 0.0003s 3066.5 - 384 bits ecdh (brainpoolP384r1) 0.0008s 1298.0 - 512 bits ecdh (brainpoolP512r1) 0.0014s 694.8 - ``` - - Keys and signature can be serialized in different ways (see Usage, below). - For a NIST192p key, the three basic representations require strings of the - following lengths (in bytes): - - to_string: signkey= 24, verifykey= 48, signature=48 - compressed: signkey=n/a, verifykey= 25, signature=n/a - DER: signkey=106, verifykey= 80, signature=55 - PEM: signkey=278, verifykey=162, (no support for PEM signatures) - - ## History - - In 2006, Peter Pearson announced his pure-python implementation of ECDSA in a - [message to sci.crypt][1], available from his [download site][2]. In 2010, - Brian Warner wrote a wrapper around this code, to make it a bit easier and - safer to use. Hubert Kario then included an implementation of elliptic curve - cryptography that uses Jacobian coordinates internally, improving performance - about 20-fold. You are looking at the README for this wrapper. - - [1]: http://www.derkeiler.com/Newsgroups/sci.crypt/2006-01/msg00651.html - [2]: http://webpages.charter.net/curryfans/peter/downloads.html - - ## Testing - - To run the full test suite, do this: - - tox -e coverage - - On an Intel Core i7 4790K @ 4.0GHz, the tests take about 16 seconds to execute. - The test suite uses - [`hypothesis`](https://github.com/HypothesisWorks/hypothesis) so there is some - inherent variability in the test suite execution time. - - One part of `test_pyecdsa.py` checks compatibility with OpenSSL, by - running the "openssl" CLI tool, make sure it's in your `PATH` if you want - to test compatibility with it. - - ## Security - - This library was not designed with security in mind. If you are processing - data that needs to be protected we suggest you use a quality wrapper around - OpenSSL. [pyca/cryptography](https://cryptography.io) is one example of such - a wrapper. The primary use-case of this library is as a portable library for - interoperability testing and as a teaching tool. - - **This library does not protect against side channel attacks.** - - Do not allow attackers to measure how long it takes you to generate a keypair - or sign a message. Do not allow attackers to run code on the same physical - machine when keypair generation or signing is taking place (this includes - virtual machines). Do not allow attackers to measure how much power your - computer uses while generating the keypair or signing a message. Do not allow - attackers to measure RF interference coming from your computer while generating - a keypair or signing a message. Note: just loading the private key will cause - keypair generation. Other operations or attack vectors may also be - vulnerable to attacks. **For a sophisticated attacker observing just one - operation with a private key will be sufficient to completely - reconstruct the private key**. - - Please also note that any Pure-python cryptographic library will be vulnerable - to the same side channel attacks. This is because Python does not provide - side-channel secure primitives (with the exception of - [`hmac.compare_digest()`][3]), making side-channel secure programming - impossible. - - This library depends upon a strong source of random numbers. Do not use it on - a system where `os.urandom()` does not provide cryptographically secure - random numbers. - - [3]: https://docs.python.org/3/library/hmac.html#hmac.compare_digest - - ## Usage - - You start by creating a `SigningKey`. You can use this to sign data, by passing - in data as a byte string and getting back the signature (also a byte string). - You can also ask a `SigningKey` to give you the corresponding `VerifyingKey`. - The `VerifyingKey` can be used to verify a signature, by passing it both the - data string and the signature byte string: it either returns True or raises - `BadSignatureError`. - - ```python - from ecdsa import SigningKey - sk = SigningKey.generate() # uses NIST192p - vk = sk.verifying_key - signature = sk.sign(b"message") - assert vk.verify(signature, b"message") - ``` - - Each `SigningKey`/`VerifyingKey` is associated with a specific curve, like - NIST192p (the default one). Longer curves are more secure, but take longer to - use, and result in longer keys and signatures. - - ```python - from ecdsa import SigningKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - vk = sk.verifying_key - signature = sk.sign(b"message") - assert vk.verify(signature, b"message") - ``` - - The `SigningKey` can be serialized into several different formats: the shortest - is to call `s=sk.to_string()`, and then re-create it with - `SigningKey.from_string(s, curve)` . This short form does not record the - curve, so you must be sure to pass to `from_string()` the same curve you used - for the original key. The short form of a NIST192p-based signing key is just 24 - bytes long. If a point encoding is invalid or it does not lie on the specified - curve, `from_string()` will raise `MalformedPointError`. - - ```python - from ecdsa import SigningKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - sk_string = sk.to_string() - sk2 = SigningKey.from_string(sk_string, curve=NIST384p) - print(sk_string.hex()) - print(sk2.to_string().hex()) - ``` - - Note: while the methods are called `to_string()` the type they return is - actually `bytes`, the "string" part is leftover from Python 2. - - `sk.to_pem()` and `sk.to_der()` will serialize the signing key into the same - formats that OpenSSL uses. The PEM file looks like the familiar ASCII-armored - `"-----BEGIN EC PRIVATE KEY-----"` base64-encoded format, and the DER format - is a shorter binary form of the same data. - `SigningKey.from_pem()/.from_der()` will undo this serialization. These - formats include the curve name, so you do not need to pass in a curve - identifier to the deserializer. In case the file is malformed `from_der()` - and `from_pem()` will raise `UnexpectedDER` or` MalformedPointError`. - - ```python - from ecdsa import SigningKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - sk_pem = sk.to_pem() - sk2 = SigningKey.from_pem(sk_pem) - # sk and sk2 are the same key - ``` - - Likewise, the `VerifyingKey` can be serialized in the same way: - `vk.to_string()/VerifyingKey.from_string()`, `to_pem()/from_pem()`, and - `to_der()/from_der()`. The same `curve=` argument is needed for - `VerifyingKey.from_string()`. - - ```python - from ecdsa import SigningKey, VerifyingKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - vk = sk.verifying_key - vk_string = vk.to_string() - vk2 = VerifyingKey.from_string(vk_string, curve=NIST384p) - # vk and vk2 are the same key - - from ecdsa import SigningKey, VerifyingKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - vk = sk.verifying_key - vk_pem = vk.to_pem() - vk2 = VerifyingKey.from_pem(vk_pem) - # vk and vk2 are the same key - ``` - - There are a couple of different ways to compute a signature. Fundamentally, - ECDSA takes a number that represents the data being signed, and returns a - pair of numbers that represent the signature. The `hashfunc=` argument to - `sk.sign()` and `vk.verify()` is used to turn an arbitrary string into - fixed-length digest, which is then turned into a number that ECDSA can sign, - and both sign and verify must use the same approach. The default value is - `hashlib.sha1`, but if you use NIST256p or a longer curve, you can use - `hashlib.sha256` instead. - - There are also multiple ways to represent a signature. The default - `sk.sign()` and `vk.verify()` methods present it as a short string, for - simplicity and minimal overhead. To use a different scheme, use the - `sk.sign(sigencode=)` and `vk.verify(sigdecode=)` arguments. There are helper - functions in the `ecdsa.util` module that can be useful here. - - It is also possible to create a `SigningKey` from a "seed", which is - deterministic. This can be used in protocols where you want to derive - consistent signing keys from some other secret, for example when you want - three separate keys and only want to store a single master secret. You should - start with a uniformly-distributed unguessable seed with about `curve.baselen` - bytes of entropy, and then use one of the helper functions in `ecdsa.util` to - convert it into an integer in the correct range, and then finally pass it - into `SigningKey.from_secret_exponent()`, like this: - - ```python - import os - from ecdsa import NIST384p, SigningKey - from ecdsa.util import randrange_from_seed__trytryagain - - def make_key(seed): - secexp = randrange_from_seed__trytryagain(seed, NIST384p.order) - return SigningKey.from_secret_exponent(secexp, curve=NIST384p) - - seed = os.urandom(NIST384p.baselen) # or other starting point - sk1a = make_key(seed) - sk1b = make_key(seed) - # note: sk1a and sk1b are the same key - assert sk1a.to_string() == sk1b.to_string() - sk2 = make_key(b"2-"+seed) # different key - assert sk1a.to_string() != sk2.to_string() - ``` - - In case the application will verify a lot of signatures made with a single - key, it's possible to precompute some of the internal values to make - signature verification significantly faster. The break-even point occurs at - about 100 signatures verified. - - To perform precomputation, you can call the `precompute()` method - on `VerifyingKey` instance: - ```python - from ecdsa import SigningKey, NIST384p - sk = SigningKey.generate(curve=NIST384p) - vk = sk.verifying_key - vk.precompute() - signature = sk.sign(b"message") - assert vk.verify(signature, b"message") - ``` - - Once `precompute()` was called, all signature verifications with this key will - be faster to execute. - - ## OpenSSL Compatibility - - To produce signatures that can be verified by OpenSSL tools, or to verify - signatures that were produced by those tools, use: - - ```python - # openssl ecparam -name prime256v1 -genkey -out sk.pem - # openssl ec -in sk.pem -pubout -out vk.pem - # echo "data for signing" > data - # openssl dgst -sha256 -sign sk.pem -out data.sig data - # openssl dgst -sha256 -verify vk.pem -signature data.sig data - # openssl dgst -sha256 -prverify sk.pem -signature data.sig data - - import hashlib - from ecdsa import SigningKey, VerifyingKey - from ecdsa.util import sigencode_der, sigdecode_der - - with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - - with open("data", "rb") as f: - data = f.read() - - with open("data.sig", "rb") as f: - signature = f.read() - - assert vk.verify(signature, data, hashlib.sha256, sigdecode=sigdecode_der) - - with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read(), hashlib.sha256) - - new_signature = sk.sign_deterministic(data, sigencode=sigencode_der) - - with open("data.sig2", "wb") as f: - f.write(new_signature) - - # openssl dgst -sha256 -verify vk.pem -signature data.sig2 data - ``` - - Note: if compatibility with OpenSSL 1.0.0 or earlier is necessary, the - `sigencode_string` and `sigdecode_string` from `ecdsa.util` can be used for - respectively writing and reading the signatures. - - The keys also can be written in format that openssl can handle: - - ```python - from ecdsa import SigningKey, VerifyingKey - - with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read()) - with open("sk.pem", "wb") as f: - f.write(sk.to_pem()) - - with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - with open("vk.pem", "wb") as f: - f.write(vk.to_pem()) - ``` - - ## Entropy - - Creating a signing key with `SigningKey.generate()` requires some form of - entropy (as opposed to - `from_secret_exponent`/`from_string`/`from_der`/`from_pem`, - which are deterministic and do not require an entropy source). The default - source is `os.urandom()`, but you can pass any other function that behaves - like `os.urandom` as the `entropy=` argument to do something different. This - may be useful in unit tests, where you want to achieve repeatable results. The - `ecdsa.util.PRNG` utility is handy here: it takes a seed and produces a strong - pseudo-random stream from it: - - ```python - from ecdsa.util import PRNG - from ecdsa import SigningKey - rng1 = PRNG(b"seed") - sk1 = SigningKey.generate(entropy=rng1) - rng2 = PRNG(b"seed") - sk2 = SigningKey.generate(entropy=rng2) - # sk1 and sk2 are the same key - ``` - - Likewise, ECDSA signature generation requires a random number, and each - signature must use a different one (using the same number twice will - immediately reveal the private signing key). The `sk.sign()` method takes an - `entropy=` argument which behaves the same as `SigningKey.generate(entropy=)`. - - ## Deterministic Signatures - - If you call `SigningKey.sign_deterministic(data)` instead of `.sign(data)`, - the code will generate a deterministic signature instead of a random one. - This uses the algorithm from RFC6979 to safely generate a unique `k` value, - derived from the private key and the message being signed. Each time you sign - the same message with the same key, you will get the same signature (using - the same `k`). - - This may become the default in a future version, as it is not vulnerable to - failures of the entropy source. - - ## Examples - - Create a NIST192p keypair and immediately save both to disk: - - ```python - from ecdsa import SigningKey - sk = SigningKey.generate() - vk = sk.verifying_key - with open("private.pem", "wb") as f: - f.write(sk.to_pem()) - with open("public.pem", "wb") as f: - f.write(vk.to_pem()) - ``` - - Load a signing key from disk, use it to sign a message (using SHA-1), and write - the signature to disk: - - ```python - from ecdsa import SigningKey - with open("private.pem") as f: - sk = SigningKey.from_pem(f.read()) - with open("message", "rb") as f: - message = f.read() - sig = sk.sign(message) - with open("signature", "wb") as f: - f.write(sig) - ``` - - Load the verifying key, message, and signature from disk, and verify the - signature (assume SHA-1 hash): - - ```python - from ecdsa import VerifyingKey, BadSignatureError - vk = VerifyingKey.from_pem(open("public.pem").read()) - with open("message", "rb") as f: - message = f.read() - with open("signature", "rb") as f: - sig = f.read() - try: - vk.verify(sig, message) - print "good signature" - except BadSignatureError: - print "BAD SIGNATURE" - ``` - - Create a NIST521p keypair: - - ```python - from ecdsa import SigningKey, NIST521p - sk = SigningKey.generate(curve=NIST521p) - vk = sk.verifying_key - ``` - - Create three independent signing keys from a master seed: - - ```python - from ecdsa import NIST192p, SigningKey - from ecdsa.util import randrange_from_seed__trytryagain - - def make_key_from_seed(seed, curve=NIST192p): - secexp = randrange_from_seed__trytryagain(seed, curve.order) - return SigningKey.from_secret_exponent(secexp, curve) - - sk1 = make_key_from_seed("1:%s" % seed) - sk2 = make_key_from_seed("2:%s" % seed) - sk3 = make_key_from_seed("3:%s" % seed) - ``` - - Load a verifying key from disk and print it using hex encoding in - uncompressed and compressed format (defined in X9.62 and SEC1 standards): - - ```python - from ecdsa import VerifyingKey - - with open("public.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - - print("uncompressed: {0}".format(vk.to_string("uncompressed").hex())) - print("compressed: {0}".format(vk.to_string("compressed").hex())) - ``` - - Load a verifying key from a hex string from compressed format, output - uncompressed: - - ```python - from ecdsa import VerifyingKey, NIST256p - - comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759' - vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p) - print(vk.to_string("uncompressed").hex()) - ``` - - ECDH key exchange with remote party - - ```python - from ecdsa import ECDH, NIST256p - - ecdh = ECDH(curve=NIST256p) - ecdh.generate_private_key() - local_public_key = ecdh.get_public_key() - #send `local_public_key` to remote party and receive `remote_public_key` from remote party - with open("remote_public_key.pem") as e: - remote_public_key = e.read() - ecdh.load_received_public_key_pem(remote_public_key) - secret = ecdh.generate_sharedsecret_bytes() - ``` - -Platform: UNKNOWN -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* -Description-Content-Type: text/markdown -Provides-Extra: gmpy2 -Provides-Extra: gmpy diff --git a/third_party/python/ecdsa/LICENSE b/third_party/python/ecdsa/ecdsa-0.15.dist-info/LICENSE similarity index 100% rename from third_party/python/ecdsa/LICENSE rename to third_party/python/ecdsa/ecdsa-0.15.dist-info/LICENSE diff --git a/third_party/python/ecdsa/README.md b/third_party/python/ecdsa/ecdsa-0.15.dist-info/METADATA similarity index 95% rename from third_party/python/ecdsa/README.md rename to third_party/python/ecdsa/ecdsa-0.15.dist-info/METADATA index 0d310b90a00d..6e8a2efe2988 100644 --- a/third_party/python/ecdsa/README.md +++ b/third_party/python/ecdsa/ecdsa-0.15.dist-info/METADATA @@ -1,3 +1,31 @@ +Metadata-Version: 2.1 +Name: ecdsa +Version: 0.15 +Summary: ECDSA cryptographic signature library (pure python) +Home-page: http://github.com/warner/python-ecdsa +Author: Brian Warner +Author-email: warner@lothar.com +License: MIT +Platform: UNKNOWN +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* +Description-Content-Type: text/markdown +Requires-Dist: six (>=1.9.0) +Provides-Extra: gmpy +Requires-Dist: gmpy ; extra == 'gmpy' +Provides-Extra: gmpy2 +Requires-Dist: gmpy2 ; extra == 'gmpy2' + # Pure-Python ECDSA [![build status](https://travis-ci.org/warner/python-ecdsa.png)](http://travis-ci.org/warner/python-ecdsa) @@ -593,3 +621,5 @@ with open("remote_public_key.pem") as e: ecdh.load_received_public_key_pem(remote_public_key) secret = ecdh.generate_sharedsecret_bytes() ``` + + diff --git a/third_party/python/ecdsa/ecdsa-0.15.dist-info/RECORD b/third_party/python/ecdsa/ecdsa-0.15.dist-info/RECORD new file mode 100644 index 000000000000..1a0163a7c072 --- /dev/null +++ b/third_party/python/ecdsa/ecdsa-0.15.dist-info/RECORD @@ -0,0 +1,28 @@ +ecdsa/__init__.py,sha256=3wbqSX9mkjn_sjkbx2vU-MJbKg0uz8DYLAZE5Jk4iyc,1219 +ecdsa/_compat.py,sha256=qmUf5lfl20-p8JleM4etlhplAEN37gbBqadBxXboomo,1108 +ecdsa/_rwlock.py,sha256=UVXDDwWF115oQroaHUtQo88uhhIoMLPIKfDQq3i7ETc,2848 +ecdsa/_version.py,sha256=J5ustrqphtIgbQXJKWGzATMRfq4koBTZ2UYvZuesnRw,496 +ecdsa/curves.py,sha256=Snq0JL6lydJunmSHeeycWvUQJ8Sj5N1tavcw6ZlZ4ik,4278 +ecdsa/der.py,sha256=rfV-KrVw10YAA2EWkVA4vZgbdeEhgsXaXfDd3S5qpp8,13864 +ecdsa/ecdh.py,sha256=qsUDPGMF9-tiqLaA9xUfhNBoUQ49gtMMFrc_O1YO_BQ,10459 +ecdsa/ecdsa.py,sha256=MB7v-2hUV982oOk-OzmKLtq-GXIPjNNK-Yd_dM4VcqU,17546 +ecdsa/ellipticcurve.py,sha256=wa3Om5WkW-HszXlBzyKdGaFfbQDsLABDCSXfrBzSMx0,24278 +ecdsa/keys.py,sha256=jeDeK5-G4C5jYebV0_sQGavRUQp5grNY7CV9eOH7o7I,52990 +ecdsa/numbertheory.py,sha256=FQiMnzY92Qi-Tt2z1czVd5MvaqqXzRgwlChZwPhwxEQ,15427 +ecdsa/rfc6979.py,sha256=7MR1nf19ZBD-EDgztlJ1SfSwLjlx3ePPb9BBFW7aEHo,2701 +ecdsa/test_der.py,sha256=XGZwUhZORvAZKEiWTLDDKlF_4JBplbUmTwkfdN-KGXU,12609 +ecdsa/test_ecdh.py,sha256=VlkuPt7fqwGh1nWwLVA-10Pguu5PYqWVaEOTDO7qlGM,13472 +ecdsa/test_ecdsa.py,sha256=zGC5L5vqc8nWNOKf0KOaUu3rJuLvpICioQ8tSypEjxs,18334 +ecdsa/test_ellipticcurve.py,sha256=odDCqwJm_sQgDFja9xSklpVskpXG5ebJ4xpBONU0duQ,6160 +ecdsa/test_jacobi.py,sha256=iGtWSMLpJ8HmJlrJkU7aiC5d50I8ahHKXFWfd0o_YP4,10778 +ecdsa/test_keys.py,sha256=NcnvEHsHJ0W-5T1F7M2RS9MzdR26ELlTv2LfAgMqEaU,12701 +ecdsa/test_malformed_sigs.py,sha256=6ow1rb-A-lbFD-TZjcl6a8VV9bwV2aL5Z0kwYJ4SJfk,10170 +ecdsa/test_numbertheory.py,sha256=KwC75hI2NfVPctlYki4JIUT8hUUcoK0x1AjcXDZQrow,9004 +ecdsa/test_pyecdsa.py,sha256=FqGtHsqwOpWz3Ne0Cmgib508pcEGv1b31eEBo-PQ5bE,64737 +ecdsa/test_rw_lock.py,sha256=5Gu_H73gU8Pb1_86X3AzkLMTYOtE4qdAwDOzBsEVbjk,6899 +ecdsa/util.py,sha256=CO6Jj3kUL28fIM3KnsevxYQJ1TCAAYDgCSacDAbSMu0,14007 +ecdsa-0.15.dist-info/LICENSE,sha256=PsqYRXc9LluMydjBGdNF8ApIBuS9Zg1KPWzfnA6di7I,1147 +ecdsa-0.15.dist-info/METADATA,sha256=Vipd5pI4sqqaWMjmDzRNRkZCQaq1YDHOHkAJPlI92tw,24899 +ecdsa-0.15.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +ecdsa-0.15.dist-info/top_level.txt,sha256=7ovPHfAPyTou19f8gOSbHm6B9dGjTibWolcCB7Zjovs,6 +ecdsa-0.15.dist-info/RECORD,, diff --git a/third_party/python/ecdsa/ecdsa-0.15.dist-info/WHEEL b/third_party/python/ecdsa/ecdsa-0.15.dist-info/WHEEL new file mode 100644 index 000000000000..8b701e93c231 --- /dev/null +++ b/third_party/python/ecdsa/ecdsa-0.15.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/ecdsa/ecdsa-0.15.dist-info/top_level.txt b/third_party/python/ecdsa/ecdsa-0.15.dist-info/top_level.txt new file mode 100644 index 000000000000..aa5efdb54777 --- /dev/null +++ b/third_party/python/ecdsa/ecdsa-0.15.dist-info/top_level.txt @@ -0,0 +1 @@ +ecdsa diff --git a/third_party/python/ecdsa/src/ecdsa/__init__.py b/third_party/python/ecdsa/ecdsa/__init__.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/__init__.py rename to third_party/python/ecdsa/ecdsa/__init__.py diff --git a/third_party/python/ecdsa/src/ecdsa/_compat.py b/third_party/python/ecdsa/ecdsa/_compat.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/_compat.py rename to third_party/python/ecdsa/ecdsa/_compat.py diff --git a/third_party/python/ecdsa/src/ecdsa/_rwlock.py b/third_party/python/ecdsa/ecdsa/_rwlock.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/_rwlock.py rename to third_party/python/ecdsa/ecdsa/_rwlock.py diff --git a/third_party/python/ecdsa/src/ecdsa/_version.py b/third_party/python/ecdsa/ecdsa/_version.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/_version.py rename to third_party/python/ecdsa/ecdsa/_version.py diff --git a/third_party/python/ecdsa/src/ecdsa/curves.py b/third_party/python/ecdsa/ecdsa/curves.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/curves.py rename to third_party/python/ecdsa/ecdsa/curves.py diff --git a/third_party/python/ecdsa/src/ecdsa/der.py b/third_party/python/ecdsa/ecdsa/der.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/der.py rename to third_party/python/ecdsa/ecdsa/der.py diff --git a/third_party/python/ecdsa/src/ecdsa/ecdh.py b/third_party/python/ecdsa/ecdsa/ecdh.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/ecdh.py rename to third_party/python/ecdsa/ecdsa/ecdh.py diff --git a/third_party/python/ecdsa/src/ecdsa/ecdsa.py b/third_party/python/ecdsa/ecdsa/ecdsa.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/ecdsa.py rename to third_party/python/ecdsa/ecdsa/ecdsa.py diff --git a/third_party/python/ecdsa/src/ecdsa/ellipticcurve.py b/third_party/python/ecdsa/ecdsa/ellipticcurve.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/ellipticcurve.py rename to third_party/python/ecdsa/ecdsa/ellipticcurve.py diff --git a/third_party/python/ecdsa/src/ecdsa/keys.py b/third_party/python/ecdsa/ecdsa/keys.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/keys.py rename to third_party/python/ecdsa/ecdsa/keys.py diff --git a/third_party/python/ecdsa/src/ecdsa/numbertheory.py b/third_party/python/ecdsa/ecdsa/numbertheory.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/numbertheory.py rename to third_party/python/ecdsa/ecdsa/numbertheory.py diff --git a/third_party/python/ecdsa/src/ecdsa/rfc6979.py b/third_party/python/ecdsa/ecdsa/rfc6979.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/rfc6979.py rename to third_party/python/ecdsa/ecdsa/rfc6979.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_der.py b/third_party/python/ecdsa/ecdsa/test_der.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_der.py rename to third_party/python/ecdsa/ecdsa/test_der.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_ecdh.py b/third_party/python/ecdsa/ecdsa/test_ecdh.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_ecdh.py rename to third_party/python/ecdsa/ecdsa/test_ecdh.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_ecdsa.py b/third_party/python/ecdsa/ecdsa/test_ecdsa.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_ecdsa.py rename to third_party/python/ecdsa/ecdsa/test_ecdsa.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_ellipticcurve.py b/third_party/python/ecdsa/ecdsa/test_ellipticcurve.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_ellipticcurve.py rename to third_party/python/ecdsa/ecdsa/test_ellipticcurve.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_jacobi.py b/third_party/python/ecdsa/ecdsa/test_jacobi.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_jacobi.py rename to third_party/python/ecdsa/ecdsa/test_jacobi.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_keys.py b/third_party/python/ecdsa/ecdsa/test_keys.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_keys.py rename to third_party/python/ecdsa/ecdsa/test_keys.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_malformed_sigs.py b/third_party/python/ecdsa/ecdsa/test_malformed_sigs.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_malformed_sigs.py rename to third_party/python/ecdsa/ecdsa/test_malformed_sigs.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_numbertheory.py b/third_party/python/ecdsa/ecdsa/test_numbertheory.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_numbertheory.py rename to third_party/python/ecdsa/ecdsa/test_numbertheory.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_pyecdsa.py b/third_party/python/ecdsa/ecdsa/test_pyecdsa.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_pyecdsa.py rename to third_party/python/ecdsa/ecdsa/test_pyecdsa.py diff --git a/third_party/python/ecdsa/src/ecdsa/test_rw_lock.py b/third_party/python/ecdsa/ecdsa/test_rw_lock.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/test_rw_lock.py rename to third_party/python/ecdsa/ecdsa/test_rw_lock.py diff --git a/third_party/python/ecdsa/src/ecdsa/util.py b/third_party/python/ecdsa/ecdsa/util.py similarity index 100% rename from third_party/python/ecdsa/src/ecdsa/util.py rename to third_party/python/ecdsa/ecdsa/util.py diff --git a/third_party/python/ecdsa/setup.cfg b/third_party/python/ecdsa/setup.cfg deleted file mode 100644 index 218838f637d6..000000000000 --- a/third_party/python/ecdsa/setup.cfg +++ /dev/null @@ -1,15 +0,0 @@ -[wheel] -universal = 1 - -[versioneer] -vcs = git -style = pep440 -versionfile_source = src/ecdsa/_version.py -versionfile_build = ecdsa/_version.py -tag_prefix = python-ecdsa- -parentdir_prefix = ecdsa- - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/ecdsa/setup.py b/third_party/python/ecdsa/setup.py deleted file mode 100755 index a6abc4ecc644..000000000000 --- a/third_party/python/ecdsa/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python - -import io -import os - -from setuptools import setup -import versioneer - -commands = versioneer.get_cmdclass().copy() - -# Use README.md to set markdown long_description -directory = os.path.abspath(os.path.dirname(__file__)) -readme_path = os.path.join(directory, "README.md") -with io.open(readme_path, encoding="utf-8") as read_file: - long_description = read_file.read() - -setup(name="ecdsa", - version=versioneer.get_version(), - description="ECDSA cryptographic signature library (pure python)", - long_description=long_description, - long_description_content_type='text/markdown', - author="Brian Warner", - author_email="warner@lothar.com", - url="http://github.com/warner/python-ecdsa", - packages=["ecdsa"], - package_dir={"": "src"}, - license="MIT", - cmdclass=commands, - python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*", - classifiers=[ - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - ], - install_requires=['six>=1.9.0'], - extras_require={ - 'gmpy2': 'gmpy2', - 'gmpy': 'gmpy', - }, - ) diff --git a/third_party/python/ecdsa/versioneer.py b/third_party/python/ecdsa/versioneer.py deleted file mode 100644 index f250cde55b8b..000000000000 --- a/third_party/python/ecdsa/versioneer.py +++ /dev/null @@ -1,1817 +0,0 @@ - -# Version: 0.17 - -"""The Versioneer - like a rocketeer, but for versions. - -The Versioneer -============== - -* like a rocketeer, but for versions! -* https://github.com/warner/python-versioneer -* Brian Warner -* License: Public Domain -* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, and pypy -* [![Latest Version] -(https://pypip.in/version/versioneer/badge.svg?style=flat) -](https://pypi.python.org/pypi/versioneer/) -* [![Build Status] -(https://travis-ci.org/warner/python-versioneer.png?branch=master) -](https://travis-ci.org/warner/python-versioneer) - -This is a tool for managing a recorded version number in distutils-based -python projects. The goal is to remove the tedious and error-prone "update -the embedded version string" step from your release process. Making a new -release should be as easy as recording a new tag in your version-control -system, and maybe making new tarballs. - - -## Quick Install - -* `pip install versioneer` to somewhere to your $PATH -* add a `[versioneer]` section to your setup.cfg (see below) -* run `versioneer install` in your source tree, commit the results - -## Version Identifiers - -Source trees come from a variety of places: - -* a version-control system checkout (mostly used by developers) -* a nightly tarball, produced by build automation -* a snapshot tarball, produced by a web-based VCS browser, like github's - "tarball from tag" feature -* a release tarball, produced by "setup.py sdist", distributed through PyPI - -Within each source tree, the version identifier (either a string or a number, -this tool is format-agnostic) can come from a variety of places: - -* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows - about recent "tags" and an absolute revision-id -* the name of the directory into which the tarball was unpacked -* an expanded VCS keyword ($Id$, etc) -* a `_version.py` created by some earlier build step - -For released software, the version identifier is closely related to a VCS -tag. Some projects use tag names that include more than just the version -string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool -needs to strip the tag prefix to extract the version identifier. For -unreleased software (between tags), the version identifier should provide -enough information to help developers recreate the same tree, while also -giving them an idea of roughly how old the tree is (after version 1.2, before -version 1.3). Many VCS systems can report a description that captures this, -for example `git describe --tags --dirty --always` reports things like -"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the -0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has -uncommitted changes. - -The version identifier is used for multiple purposes: - -* to allow the module to self-identify its version: `myproject.__version__` -* to choose a name and prefix for a 'setup.py sdist' tarball - -## Theory of Operation - -Versioneer works by adding a special `_version.py` file into your source -tree, where your `__init__.py` can import it. This `_version.py` knows how to -dynamically ask the VCS tool for version information at import time. - -`_version.py` also contains `$Revision$` markers, and the installation -process marks `_version.py` to have this marker rewritten with a tag name -during the `git archive` command. As a result, generated tarballs will -contain enough information to get the proper version. - -To allow `setup.py` to compute a version too, a `versioneer.py` is added to -the top level of your source tree, next to `setup.py` and the `setup.cfg` -that configures it. This overrides several distutils/setuptools commands to -compute the version when invoked, and changes `setup.py build` and `setup.py -sdist` to replace `_version.py` with a small static file that contains just -the generated version data. - -## Installation - -See [INSTALL.md](./INSTALL.md) for detailed installation instructions. - -## Version-String Flavors - -Code which uses Versioneer can learn about its version string at runtime by -importing `_version` from your main `__init__.py` file and running the -`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can -import the top-level `versioneer.py` and run `get_versions()`. - -Both functions return a dictionary with different flavors of version -information: - -* `['version']`: A condensed version string, rendered using the selected - style. This is the most commonly used value for the project's version - string. The default "pep440" style yields strings like `0.11`, - `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section - below for alternative styles. - -* `['full-revisionid']`: detailed revision identifier. For Git, this is the - full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". - -* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the - commit date in ISO 8601 format. This will be None if the date is not - available. - -* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that - this is only accurate if run in a VCS checkout, otherwise it is likely to - be False or None - -* `['error']`: if the version string could not be computed, this will be set - to a string describing the problem, otherwise it will be None. It may be - useful to throw an exception in setup.py if this is set, to avoid e.g. - creating tarballs with a version string of "unknown". - -Some variants are more useful than others. Including `full-revisionid` in a -bug report should allow developers to reconstruct the exact code being tested -(or indicate the presence of local changes that should be shared with the -developers). `version` is suitable for display in an "about" box or a CLI -`--version` output: it can be easily compared against release notes and lists -of bugs fixed in various releases. - -The installer adds the following text to your `__init__.py` to place a basic -version in `YOURPROJECT.__version__`: - - from ._version import get_versions - __version__ = get_versions()['version'] - del get_versions - -## Styles - -The setup.cfg `style=` configuration controls how the VCS information is -rendered into a version string. - -The default style, "pep440", produces a PEP440-compliant string, equal to the -un-prefixed tag name for actual releases, and containing an additional "local -version" section with more detail for in-between builds. For Git, this is -TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags ---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the -tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and -that this commit is two revisions ("+2") beyond the "0.11" tag. For released -software (exactly equal to a known tag), the identifier will only contain the -stripped tag, e.g. "0.11". - -Other styles are available. See details.md in the Versioneer source tree for -descriptions. - -## Debugging - -Versioneer tries to avoid fatal errors: if something goes wrong, it will tend -to return a version of "0+unknown". To investigate the problem, run `setup.py -version`, which will run the version-lookup code in a verbose mode, and will -display the full contents of `get_versions()` (including the `error` string, -which may help identify what went wrong). - -## Known Limitations - -Some situations are known to cause problems for Versioneer. This details the -most significant ones. More can be found on Github -[issues page](https://github.com/warner/python-versioneer/issues). - -### Subprojects - -Versioneer has limited support for source trees in which `setup.py` is not in -the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are -two common reasons why `setup.py` might not be in the root: - -* Source trees which contain multiple subprojects, such as - [Buildbot](https://github.com/buildbot/buildbot), which contains both - "master" and "slave" subprojects, each with their own `setup.py`, - `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI - distributions (and upload multiple independently-installable tarballs). -* Source trees whose main purpose is to contain a C library, but which also - provide bindings to Python (and perhaps other langauges) in subdirectories. - -Versioneer will look for `.git` in parent directories, and most operations -should get the right version string. However `pip` and `setuptools` have bugs -and implementation details which frequently cause `pip install .` from a -subproject directory to fail to find a correct version string (so it usually -defaults to `0+unknown`). - -`pip install --editable .` should work correctly. `setup.py install` might -work too. - -Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in -some later version. - -[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking -this issue. The discussion in -[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the -issue from the Versioneer side in more detail. -[pip PR#3176](https://github.com/pypa/pip/pull/3176) and -[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve -pip to let Versioneer work correctly. - -Versioneer-0.16 and earlier only looked for a `.git` directory next to the -`setup.cfg`, so subprojects were completely unsupported with those releases. - -### Editable installs with setuptools <= 18.5 - -`setup.py develop` and `pip install --editable .` allow you to install a -project into a virtualenv once, then continue editing the source code (and -test) without re-installing after every change. - -"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a -convenient way to specify executable scripts that should be installed along -with the python package. - -These both work as expected when using modern setuptools. When using -setuptools-18.5 or earlier, however, certain operations will cause -`pkg_resources.DistributionNotFound` errors when running the entrypoint -script, which must be resolved by re-installing the package. This happens -when the install happens with one version, then the egg_info data is -regenerated while a different version is checked out. Many setup.py commands -cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into -a different virtualenv), so this can be surprising. - -[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes -this one, but upgrading to a newer version of setuptools should probably -resolve it. - -### Unicode version strings - -While Versioneer works (and is continually tested) with both Python 2 and -Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. -Newer releases probably generate unicode version strings on py2. It's not -clear that this is wrong, but it may be surprising for applications when then -write these strings to a network connection or include them in bytes-oriented -APIs like cryptographic checksums. - -[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates -this question. - - -## Updating Versioneer - -To upgrade your project to a new release of Versioneer, do the following: - -* install the new Versioneer (`pip install -U versioneer` or equivalent) -* edit `setup.cfg`, if necessary, to include any new configuration settings - indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. -* re-run `versioneer install` in your source tree, to replace - `SRC/_version.py` -* commit any changed files - -## Future Directions - -This tool is designed to make it easily extended to other version-control -systems: all VCS-specific components are in separate directories like -src/git/ . The top-level `versioneer.py` script is assembled from these -components by running make-versioneer.py . In the future, make-versioneer.py -will take a VCS name as an argument, and will construct a version of -`versioneer.py` that is specific to the given VCS. It might also take the -configuration arguments that are currently provided manually during -installation by editing setup.py . Alternatively, it might go the other -direction and include code from all supported VCS systems, reducing the -number of intermediate scripts. - - -## License - -To make Versioneer easier to embed, all its code is dedicated to the public -domain. The `_version.py` that it creates is also in the public domain. -Specifically, both are released under the Creative Commons "Public Domain -Dedication" license (CC0-1.0), as described in -https://creativecommons.org/publicdomain/zero/1.0/ . - -""" - -from __future__ import print_function -try: - import configparser -except ImportError: - import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_root(): - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - me = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(me)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) - except NameError: - pass - return root - - -def get_config_from_root(root): - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise EnvironmentError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.SafeConfigParser() - with open(setup_cfg, "r") as f: - parser.readfp(f) - VCS = parser.get("versioneer", "VCS") # mandatory - - def get(parser, name): - if parser.has_option("versioneer", name): - return parser.get("versioneer", name) - return None - cfg = VersioneerConfig() - cfg.VCS = VCS - cfg.style = get(parser, "style") or "" - cfg.versionfile_source = get(parser, "versionfile_source") - cfg.versionfile_build = get(parser, "versionfile_build") - cfg.tag_prefix = get(parser, "tag_prefix") - if cfg.tag_prefix in ("''", '""'): - cfg.tag_prefix = "" - cfg.parentdir_prefix = get(parser, "parentdir_prefix") - cfg.verbose = get(parser, "verbose") - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.17 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%%s*" %% tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%%d" %% pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(manifest_in, versionfile_source, ipy): - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [manifest_in, versionfile_source] - if ipy: - files.append(ipy) - try: - me = __file__ - if me.endswith(".pyc") or me.endswith(".pyo"): - me = os.path.splitext(me)[0] + ".py" - versioneer_file = os.path.relpath(me) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - f = open(".gitattributes", "r") - for line in f.readlines(): - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - f.close() - except EnvironmentError: - pass - if not present: - f = open(".gitattributes", "a+") - f.write("%s export-subst\n" % versionfile_source) - f.close() - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.17) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) -""" - - -def versions_from_file(filename): - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except EnvironmentError: - raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename, versions): - """Write the given version number to the given _version.py file.""" - os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose=False): - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} - - -def get_version(): - """Get the short version string for this project.""" - return get_versions()["version"] - - -def get_cmdclass(): - """Get the custom setuptools/distutils subclasses used by Versioneer.""" - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/warner/python-versioneer/issues/52 - - cmds = {} - - # we add "version" to both distutils and setuptools - from distutils.core import Command - - class cmd_version(Command): - description = "report generated version string" - user_options = [] - boolean_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version - - # we override "build_py" in both distutils and setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - - # we override different "build_py" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.build_py import build_py as _build_py - else: - from distutils.command.build_py import build_py as _build_py - - class cmd_build_py(_build_py): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_py.run(self) - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py - - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if 'py2exe' in sys.modules: # py2exe enabled? - try: - from py2exe.distutils_buildexe import py2exe as _py2exe # py3 - except ImportError: - from py2exe.build_exe import py2exe as _py2exe # py2 - - class cmd_py2exe(_py2exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["py2exe"] = cmd_py2exe - - # we override different "sdist" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.sdist import sdist as _sdist - else: - from distutils.command.sdist import sdist as _sdist - - class cmd_sdist(_sdist): - def run(self): - versions = get_versions() - self._versioneer_generated_versions = versions - # unless we update this, the command will keep using the old - # version - self.distribution.metadata.version = versions["version"] - return _sdist.run(self) - - def make_release_tree(self, base_dir, files): - root = get_root() - cfg = get_config_from_root(root) - _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) - cmds["sdist"] = cmd_sdist - - return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -INIT_PY_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - - -def do_setup(): - """Main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: - if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except EnvironmentError: - old = "" - if INIT_PY_SNIPPET not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(INIT_PY_SNIPPET) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - ipy = None - - # Make sure both the top-level "versioneer.py" and versionfile_source - # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so - # they'll be copied into source distributions. Pip won't be able to - # install the package without this. - manifest_in = os.path.join(root, "MANIFEST.in") - simple_includes = set() - try: - with open(manifest_in, "r") as f: - for line in f: - if line.startswith("include "): - for include in line.split()[1:]: - simple_includes.add(include) - except EnvironmentError: - pass - # That doesn't cover everything MANIFEST.in can do - # (http://docs.python.org/2/distutils/sourcedist.html#commands), so - # it might give some false negatives. Appending redundant 'include' - # lines is safe, though. - if "versioneer.py" not in simple_includes: - print(" appending 'versioneer.py' to MANIFEST.in") - with open(manifest_in, "a") as f: - f.write("include versioneer.py\n") - else: - print(" 'versioneer.py' already in MANIFEST.in") - if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) - with open(manifest_in, "a") as f: - f.write("include %s\n" % cfg.versionfile_source) - else: - print(" versionfile_source already in MANIFEST.in") - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(manifest_in, cfg.versionfile_source, ipy) - return 0 - - -def scan_setup_py(): - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - errors = do_setup() - errors += scan_setup_py() - if errors: - sys.exit(1) diff --git a/third_party/python/fluent.syntax/PKG-INFO b/third_party/python/fluent.syntax/PKG-INFO deleted file mode 100644 index 7ce7dd4745a3..000000000000 --- a/third_party/python/fluent.syntax/PKG-INFO +++ /dev/null @@ -1,39 +0,0 @@ -Metadata-Version: 2.1 -Name: fluent.syntax -Version: 0.18.1 -Summary: Localization library for expressive translations. -Home-page: https://github.com/projectfluent/python-fluent -Author: Mozilla -Author-email: l10n-drivers@mozilla.org -License: APL 2 -Description: ``fluent.syntax`` |fluent.syntax| - --------------------------------- - - Read, write, and transform `Fluent`_ files. - - This package includes the parser, serializer, and traversal - utilities like Visitor and Transformer. You’re looking for this package - if you work on tooling for Fluent in Python. - - .. code-block:: python - - >>> from fluent.syntax import parse, ast, serialize - >>> resource = parse("a-key = String to localize") - >>> resource.body[0].value.elements[0].value = "Localized string" - >>> serialize(resource) - 'a-key = Localized string\n' - - - Find the full documentation on https://projectfluent.org/python-fluent/fluent.syntax/. - - .. _fluent: https://projectfluent.org/ - .. |fluent.syntax| image:: https://github.com/projectfluent/python-fluent/workflows/fluent.syntax/badge.svg - -Keywords: fluent,localization,l10n -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3.5 -Description-Content-Type: text/x-rst diff --git a/third_party/python/fluent.syntax/README.rst b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/DESCRIPTION.rst similarity index 99% rename from third_party/python/fluent.syntax/README.rst rename to third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/DESCRIPTION.rst index c847f5e6aa54..4f6444ed2561 100644 --- a/third_party/python/fluent.syntax/README.rst +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/DESCRIPTION.rst @@ -20,3 +20,5 @@ Find the full documentation on https://projectfluent.org/python-fluent/fluent.sy .. _fluent: https://projectfluent.org/ .. |fluent.syntax| image:: https://github.com/projectfluent/python-fluent/workflows/fluent.syntax/badge.svg + + diff --git a/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/METADATA b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/METADATA new file mode 100644 index 000000000000..3a803aec820e --- /dev/null +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/METADATA @@ -0,0 +1,41 @@ +Metadata-Version: 2.0 +Name: fluent.syntax +Version: 0.18.1 +Summary: Localization library for expressive translations. +Home-page: https://github.com/projectfluent/python-fluent +Author: Mozilla +Author-email: l10n-drivers@mozilla.org +License: APL 2 +Keywords: fluent,localization,l10n +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.5 +Description-Content-Type: text/x-rst + +``fluent.syntax`` |fluent.syntax| +--------------------------------- + +Read, write, and transform `Fluent`_ files. + +This package includes the parser, serializer, and traversal +utilities like Visitor and Transformer. You’re looking for this package +if you work on tooling for Fluent in Python. + +.. code-block:: python + + >>> from fluent.syntax import parse, ast, serialize + >>> resource = parse("a-key = String to localize") + >>> resource.body[0].value.elements[0].value = "Localized string" + >>> serialize(resource) + 'a-key = Localized string\n' + + +Find the full documentation on https://projectfluent.org/python-fluent/fluent.syntax/. + +.. _fluent: https://projectfluent.org/ +.. |fluent.syntax| image:: https://github.com/projectfluent/python-fluent/workflows/fluent.syntax/badge.svg + + diff --git a/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/RECORD b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/RECORD new file mode 100644 index 000000000000..3260cdd71cbb --- /dev/null +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/RECORD @@ -0,0 +1,14 @@ +fluent/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65 +fluent/syntax/__init__.py,sha256=ZRWtukW3DYmR3VkegVXxzKarqrx4Fv92iJO5W-evVB8,425 +fluent/syntax/ast.py,sha256=Jvd6PpR7u6E711jF1qZPRUulBqTRTtZRnRRADK1BRwI,10030 +fluent/syntax/errors.py,sha256=zena7CVTg8CvF52B4kadEuQUqQ3QSUyNm5lL3ynVxM0,2579 +fluent/syntax/parser.py,sha256=WVDbDiDwb1EJwlv_sgjH815tsvfnjpuyfL9lSlRWIIc,20194 +fluent/syntax/serializer.py,sha256=nERP9e_eMdfgx9B74tr2h05IO1lYFkRKZOeAtujpoz4,7606 +fluent/syntax/stream.py,sha256=Whap0UNpWo5-wOZBP3z34mRPMilWbsEPpxVFtAjcw1k,8015 +fluent/syntax/visitor.py,sha256=DISMs3y_rTaMZlaKylbxJ0rANmDzSbo22eZXcnb5TLA,2149 +fluent.syntax-0.18.1.dist-info/DESCRIPTION.rst,sha256=A33VWXJd9FFc9mg8QjsWPcprRJ7RazA0cYQyabC-A2M,794 +fluent.syntax-0.18.1.dist-info/METADATA,sha256=QptbKFmazXHoKtm4JWVb93AIh96sq5M2pF3D5qesZjU,1381 +fluent.syntax-0.18.1.dist-info/RECORD,, +fluent.syntax-0.18.1.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 +fluent.syntax-0.18.1.dist-info/metadata.json,sha256=5XyFJ0X2dc59aI7E3WrIFZ3aMs5Ir2K2n2IY3Z7wBrI,805 +fluent.syntax-0.18.1.dist-info/top_level.txt,sha256=E6y0EXb_8ntRq2470rEss448Ec6wP_-DI3zVECukrn0,7 diff --git a/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/WHEEL b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/WHEEL new file mode 100644 index 000000000000..7332a419cda6 --- /dev/null +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/metadata.json b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/metadata.json new file mode 100644 index 000000000000..7b4494d18d3f --- /dev/null +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5"], "description_content_type": "text/x-rst", "extensions": {"python.details": {"contacts": [{"email": "l10n-drivers@mozilla.org", "name": "Mozilla", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/projectfluent/python-fluent"}}}, "generator": "bdist_wheel (0.30.0)", "keywords": ["fluent", "localization", "l10n"], "license": "APL 2", "metadata_version": "2.0", "name": "fluent.syntax", "summary": "Localization library for expressive translations.", "test_requires": [{"requires": ["six"]}], "version": "0.18.1"} \ No newline at end of file diff --git a/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/top_level.txt b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/top_level.txt new file mode 100644 index 000000000000..a3582d405aef --- /dev/null +++ b/third_party/python/fluent.syntax/fluent.syntax-0.18.1.dist-info/top_level.txt @@ -0,0 +1 @@ +fluent diff --git a/third_party/python/fluent.syntax/setup.cfg b/third_party/python/fluent.syntax/setup.cfg deleted file mode 100644 index 4fb7b37a15a4..000000000000 --- a/third_party/python/fluent.syntax/setup.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[metadata] -version = 0.18.1 - -[bdist_wheel] -universal = 1 - -[flake8] -exclude = .tox -max-line-length = 120 - -[isort] -line_length = 120 -skip_glob = .tox -not_skip = __init__.py - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/fluent.syntax/setup.py b/third_party/python/fluent.syntax/setup.py deleted file mode 100755 index 411e912f527e..000000000000 --- a/third_party/python/fluent.syntax/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -from setuptools import setup -import os - -this_directory = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(this_directory, 'README.rst'), 'rb') as f: - long_description = f.read().decode('utf-8') - -setup(name='fluent.syntax', - description='Localization library for expressive translations.', - long_description=long_description, - long_description_content_type='text/x-rst', - author='Mozilla', - author_email='l10n-drivers@mozilla.org', - license='APL 2', - url='https://github.com/projectfluent/python-fluent', - keywords=['fluent', 'localization', 'l10n'], - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', - ], - packages=['fluent', 'fluent.syntax'], - # These should also be duplicated in tox.ini and /.github/workflow/fluent.syntax.yml - tests_require=['six'], - test_suite='tests.syntax' - ) diff --git a/third_party/python/glean_parser/.circleci/config.yml b/third_party/python/glean_parser/.circleci/config.yml deleted file mode 100644 index c0b6def0001b..000000000000 --- a/third_party/python/glean_parser/.circleci/config.yml +++ /dev/null @@ -1,212 +0,0 @@ -version: 2.1 - -commands: - test-start: - steps: - - checkout - - run: - name: environment - command: | - echo 'export PATH=.:$HOME/.local/bin:$PATH' >> $BASH_ENV - - run: - name: Upgrade pip - command: | - pip install --upgrade --user pip - - test-min-requirements: - steps: - - run: - name: install minimum requirements - command: | - # Use requirements-builder to determine the minimum versions of - # all requirements and test those - # We install requirements-builder itself into its own venv, since - # otherwise its dependencies might install newer versions of - # glean_parser's dependencies. - python3 -m venv .rb - .rb/bin/pip install requirements-builder - .rb/bin/requirements-builder --level=min setup.py > min_requirements.txt - - pip install --progress-bar off --user -U -r min_requirements.txt - - test-python-version: - parameters: - requirements-file: - type: string - default: "requirements_dev.txt" - steps: - - run: - name: install - command: | - pip install --progress-bar off --user -U -r <> - sudo apt update -q - sudo apt upgrade -q - sudo apt install openjdk-11-jdk-headless - make install-kotlin-linters - - run: - name: lint - command: make lint - - run: - name: install - # Set CC to something that isn't a working compiler so we - # can detect if any of the dependencies require a compiler - # to be installed. We can't count on a working compiler - # being available to pip on all of the platforms we need to - # support, so we need to make sure the dependencies are all - # pure Python or provide pre-built wheels. - command: CC=broken_compiler pip install . --user - - run: - name: test - command: make test - -jobs: - build-36: - docker: - - image: circleci/python:3.6.12 - steps: - - test-start - - test-python-version - - build-36-min: - docker: - - image: circleci/python:3.6.12 - steps: - - test-start - - test-min-requirements - - test-python-version - - build-37: - docker: - - image: circleci/python:3.7.9 - steps: - - test-start - - test-python-version - - run: - name: make-docs - command: | - make docs - touch docs/_build/html/.nojekyll - - persist_to_workspace: - root: docs/_build - paths: html - - build-38: - docker: - - image: circleci/python:3.8.5 - steps: - - test-start - - test-python-version - - build-38-min: - docker: - - image: circleci/python:3.8.5 - steps: - - test-start - - test-min-requirements - - test-python-version - - build-39: - docker: - - image: circleci/python:3.9.0 - steps: - - test-start - - test-python-version - - build-310: - docker: - - image: circleci/python:3.10-rc - steps: - - test-start - - test-python-version - - docs-deploy: - docker: - - image: node:8.10.0 - steps: - - checkout - - add_ssh_keys: - fingerprints: - - "9b:25:aa:bf:39:b6:4a:e7:c3:52:cf:ab:23:81:3d:52" - - attach_workspace: - at: docs/_build - - run: - name: install - command: | - npm install -g --silent gh-pages@2.0.1 - git config user.email "glean-ci@nowhere.com" - git config user.name "glean-ci" - - run: - name: deploy - command: | - gh-pages --dotfiles --message "[ci skip] updates" --dist docs/_build/html - - pypi-deploy: - docker: - - image: circleci/python:3.7.5 - steps: - - checkout - - run: - name: environment - command: | - echo 'export PATH=.:$HOME/.local/bin:$PATH' >> $BASH_ENV - - run: - name: Upgrade pip - command: | - pip install --upgrade --user pip - - run: - name: install - command: | - pip install --user -U -r requirements_dev.txt - - run: - name: deploy - # Requires that the TWINE_USERNAME and TWINE_PASSWORD environment - # variables are configured in CircleCI's environment variables. - command: | - make release - -workflows: - version: 2 - build: - jobs: - - build-36: - filters: - tags: - only: /.*/ - - build-36-min: - filters: - tags: - only: /.*/ - - build-37: - filters: - tags: - only: /.*/ - - build-38: - filters: - tags: - only: /.*/ - - build-38-min: - filters: - tags: - only: /.*/ - - build-39: - filters: - tags: - only: /.*/ - - build-310: - filters: - tags: - only: /.*/ - - docs-deploy: - requires: - - build-37 - filters: - branches: - only: main - - pypi-deploy: - requires: - - build-37 - filters: - branches: - ignore: /.*/ - tags: - only: /v[0-9]+(\.[0-9]+)*/ diff --git a/third_party/python/glean_parser/.editorconfig b/third_party/python/glean_parser/.editorconfig deleted file mode 100644 index d4a2c4405ec2..000000000000 --- a/third_party/python/glean_parser/.editorconfig +++ /dev/null @@ -1,21 +0,0 @@ -# http://editorconfig.org - -root = true - -[*] -indent_style = space -indent_size = 4 -trim_trailing_whitespace = true -insert_final_newline = true -charset = utf-8 -end_of_line = lf - -[*.bat] -indent_style = tab -end_of_line = crlf - -[LICENSE] -insert_final_newline = false - -[Makefile] -indent_style = tab diff --git a/third_party/python/glean_parser/.flake8 b/third_party/python/glean_parser/.flake8 deleted file mode 100644 index 2bcd70e390ce..000000000000 --- a/third_party/python/glean_parser/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 88 diff --git a/third_party/python/glean_parser/.github/ISSUE_TEMPLATE.md b/third_party/python/glean_parser/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index ac2c091d74e5..000000000000 --- a/third_party/python/glean_parser/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,15 +0,0 @@ -* Glean Parser version: -* Python version: -* Operating System: - -### Description - -Describe what you were trying to get done. -Tell us what happened, what went wrong, and what you expected to happen. - -### What I Did - -``` -Paste the command(s) you ran and the output. -If there was a crash, please include the traceback here. -``` diff --git a/third_party/python/glean_parser/.github/dependabot.yml b/third_party/python/glean_parser/.github/dependabot.yml deleted file mode 100644 index b38df29f46e1..000000000000 --- a/third_party/python/glean_parser/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "daily" diff --git a/third_party/python/glean_parser/.github/pull_request_template.md b/third_party/python/glean_parser/.github/pull_request_template.md deleted file mode 100644 index 8107945d6249..000000000000 --- a/third_party/python/glean_parser/.github/pull_request_template.md +++ /dev/null @@ -1,8 +0,0 @@ -### Pull Request checklist ### - -- [ ] **Quality**: This PR builds and tests run cleanly - - `make test` runs without emitting any warnings - - `make lint` runs without emitting any errors -- [ ] **Tests**: This PR includes thorough tests or an explanation of why it does not -- [ ] **Changelog**: This PR includes a changelog entry to `CHANGELOG.md` or an explanation of why it does not need one - - Any breaking changes to language binding APIs are noted explicitly diff --git a/third_party/python/glean_parser/.gitignore b/third_party/python/glean_parser/.gitignore deleted file mode 100644 index 120a8343f1e4..000000000000 --- a/third_party/python/glean_parser/.gitignore +++ /dev/null @@ -1,110 +0,0 @@ -docs/glean_parser.rst -docs/modules.rst - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# dotenv -.env - -# virtualenv -.venv -venv/ -ENV/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ - -.vscode/ - -detekt*.jar -ktlint diff --git a/third_party/python/glean_parser/.swiftlint.yml b/third_party/python/glean_parser/.swiftlint.yml deleted file mode 100644 index fa7b621a5db9..000000000000 --- a/third_party/python/glean_parser/.swiftlint.yml +++ /dev/null @@ -1,6 +0,0 @@ -identifier_name: - # Turn off it complaining about `id` or `let t = title`, etc, but keep - # warnings around e.g. enum names. - min_length: - warning: 0 - error: 0 diff --git a/third_party/python/glean_parser/CODE_OF_CONDUCT.md b/third_party/python/glean_parser/CODE_OF_CONDUCT.md deleted file mode 100644 index 498baa3fb0f0..000000000000 --- a/third_party/python/glean_parser/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,15 +0,0 @@ -# Community Participation Guidelines - -This repository is governed by Mozilla's code of conduct and etiquette guidelines. -For more details, please read the -[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). - -## How to Report -For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. - - diff --git a/third_party/python/glean_parser/CONTRIBUTING.md b/third_party/python/glean_parser/CONTRIBUTING.md deleted file mode 100644 index 9424603f6c6b..000000000000 --- a/third_party/python/glean_parser/CONTRIBUTING.md +++ /dev/null @@ -1,182 +0,0 @@ -# Contributing - -Contributions are welcome, and they are greatly appreciated! Every little bit -helps, and credit will always be given. - -You can contribute in many ways: - -## Types of Contributions - -### Report Bugs - -Report bugs at -[bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&cf_fission_milestone=---&cf_fx_iteration=---&cf_fx_points=---&cf_status_firefox65=---&cf_status_firefox66=---&cf_status_firefox67=---&cf_status_firefox_esr60=---&cf_status_thunderbird_esr60=---&cf_tracking_firefox65=---&cf_tracking_firefox66=---&cf_tracking_firefox67=---&cf_tracking_firefox_esr60=---&cf_tracking_firefox_relnote=---&cf_tracking_thunderbird_esr60=---&product=Data%20Platform%20and%20Tools&component=Glean%3A%20SDK&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&flag_type-203=X&flag_type-37=X&flag_type-41=X&flag_type-607=X&flag_type-721=X&flag_type-737=X&flag_type-787=X&flag_type-799=X&flag_type-800=X&flag_type-803=X&flag_type-835=X&flag_type-846=X&flag_type-855=X&flag_type-864=X&flag_type-916=X&flag_type-929=X&flag_type-930=X&flag_type-935=X&flag_type-936=X&flag_type-937=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=P3&&rep_platform=Unspecified&status_whiteboard=%5Btelemetry%3Aglean-rs%3Am%3F%5D&target_milestone=---&version=unspecified). - -If you are reporting a bug, please include: - -- Your operating system name and version. -- Any details about your local setup that might be helpful in troubleshooting. -- Detailed steps to reproduce the bug. - -### Fix Bugs - -Look through the GitHub issues for bugs. Anything tagged with "bug" and "help -wanted" is open to whoever wants to implement it. - -### Implement Features - -Look through the GitHub issues for features. Anything tagged with "enhancement" -and "help wanted" is open to whoever wants to implement it. - -### Write Documentation - -`glean_parser` could always use more documentation, whether as part of the -official `glean_parser` docs, in docstrings, or even on the web in blog posts, -articles, and such. - -### Submit Feedback - -The best way to send feedback is to file an issue at TODO - -If you are proposing a feature: - -- Explain in detail how it would work. -- Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions are - welcome :) - -## Get Started! - -Ready to contribute? Here's how to set up `glean_parser` for local -development. - -1. Fork the `glean_parser` repo on GitHub. - -2. Clone your fork locally: - - ```sh - $ git clone git@github.com:your_name_here/glean_parser.git - ``` - -3. Install your local copy into a virtualenv. Assuming you have - virtualenvwrapper installed, this is how you set up your fork for local - development: - - ```sh - $ mkvirtualenv glean_parser - $ cd glean_parser/ - $ pip install --editable . - ``` - -4. Create a branch for local development: - - ```sh - $ git checkout -b name-of-your-bugfix-or-feature - ``` - - Now you can make your changes locally. - -5. To test your changes to `glean_parser`: - - Install the testing dependencies: - - ```sh - $ pip install -r requirements_dev.txt - ``` - - Optionally, if you want to ensure that the generated Kotlin code lints - correctly, install a Java SDK, and then run: - - ```sh - $ make install-kotlin-linters - ``` - - Then make sure that all lints and tests are passing: - - ```sh - $ make lint - $ make test - ``` - -6. Commit your changes and push your branch to GitHub: - - ```sh - $ git add . - $ git commit -m "Your detailed description of your changes." - $ git push origin name-of-your-bugfix-or-feature - ``` - -7. Submit a pull request through the GitHub website. - -## Pull Request Guidelines - -Before you submit a pull request, check that it meets these guidelines: - -1. The pull request should include tests. -2. If the pull request adds functionality, the docs should be updated. Put your - new functionality into a function with a docstring, and describe - public-facing features in the docs. -3. The pull request should work for Python 3.6, 3.7, 3.8 and 3.9 (The CI system - will take care of testing all of these Python versions). -4. The pull request should update the changelog in `CHANGELOG.md`. - -## Tips - -To run a subset of tests: - -```sh -$ py.test tests.test_glean_parser -``` - -## Deploying - -A reminder for the maintainers on how to deploy. - -Get a clean main branch with all of the changes from `upstream`: - -```sh -$ git checkout main -$ git fetch upstream -$ git rebase upstream/main -``` - -- Update the header with the new version and date in `CHANGELOG.md`. - -- (By using the setuptools-scm package, there is no need to update the - version anywhere else). - -- Make sure all your changes are committed. - -- Push the changes upstream. (Normally pushing directly without review - is frowned upon, but the `main` branch is protected from force - pushes and release tagging requires the same permissions as pushing - to `main`): - - ```sh - $ git push upstream main - ``` - -- Wait for [continuous integration to - pass](https://circleci.com/gh/mozilla/glean_parser/tree/main) on main. - -- Make the release on GitHub using [this - link](https://github.com/mozilla/glean_parser/releases/new) - -- Both the tag and the release title should be in the form `vX.Y.Z`. - -- Copy and paste the relevant part of the `CHANGELOG.md` file into the - description. - -- Tagging the release will trigger a CI workflow which will build the - distribution of `glean_parser` and publish it to PyPI. - -The continuous integration system will then automatically deploy to -PyPI. - -See also: - -- The [instructions for updating the version of `glean_parser` -used by the Glean -SDK](https://mozilla.github.io/glean/dev/upgrading-glean-parser.html). -- The [instructions for updating the version of `glean_parser` -used by Glean.js](https://github.com/mozilla/glean.js/tree/main/docs/update_glean_parser.md). diff --git a/third_party/python/glean_parser/MANIFEST.in b/third_party/python/glean_parser/MANIFEST.in deleted file mode 100644 index f5f0349acea8..000000000000 --- a/third_party/python/glean_parser/MANIFEST.in +++ /dev/null @@ -1,14 +0,0 @@ -include AUTHORS.md -include CONTRIBUTING.md -include CHANGELOG.md -include LICENSE -include README.md - -recursive-include tests * -recursive-exclude * __pycache__ -recursive-exclude * *.py[co] - -recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif - -recursive-include glean_parser/schemas *.yaml -recursive-include glean_parser/templates * diff --git a/third_party/python/glean_parser/Makefile b/third_party/python/glean_parser/Makefile deleted file mode 100644 index 26041d565ca2..000000000000 --- a/third_party/python/glean_parser/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -.PHONY: clean clean-test clean-pyc clean-build docs help - -define PRINT_HELP_PYSCRIPT -import re, sys - -for line in sys.stdin: - match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) - if match: - target, help = match.groups() - print("%-20s %s" % (target, help)) -endef -export PRINT_HELP_PYSCRIPT - -help: - @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) - -clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts - -clean-build: ## remove build artifacts - rm -fr build/ - rm -fr dist/ - rm -fr .eggs/ - find . -name '*.egg-info' -exec rm -fr {} + - find . -name '*.egg' -exec rm -fr {} + - -clean-pyc: ## remove Python file artifacts - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - find . -name '__pycache__' -exec rm -fr {} + - -clean-test: ## remove test and coverage artifacts - rm -f .coverage - rm -fr htmlcov/ - rm -fr .pytest_cache - -lint: ## check style with flake8 - python3 -m flake8 glean_parser tests - python3 -m black --check glean_parser tests setup.py - python3 -m yamllint glean_parser tests - python3 -m mypy glean_parser - -test: ## run tests quickly with the default Python - py.test - -coverage: ## check code coverage quickly with the default Python - coverage run --source glean_parser -m pytest - coverage report -m - coverage html - -docs: ## generate Sphinx HTML documentation, including API docs - rm -f docs/glean_parser.rst - rm -f docs/modules.rst - sphinx-apidoc -o docs/ glean_parser - $(MAKE) -C docs clean - $(MAKE) -C docs html - -release: dist ## package and upload a release - twine upload dist/* - -dist: clean ## builds source and wheel package - python setup.py sdist - python setup.py bdist_wheel - ls -l dist - -install: clean ## install the package to the active Python's site-packages - pip install . - -install-kotlin-linters: ## install ktlint and detekt for linting Kotlin output - test -f ktlint || curl -sSLO https://github.com/shyiko/ktlint/releases/download/0.29.0/ktlint - echo "03c9f9f78f80bcdb44c292d95e4d9abf221daf5e377673c1b6675a8003eab94d *ktlint" | sha256sum -c - - chmod a+x ktlint - test -f detekt-cli.jar || curl -sSL --output "detekt-cli.jar" https://github.com/detekt/detekt/releases/download/v1.16.0/detekt-cli-1.16.0-all.jar - echo "dd63aae60cce4b0516ffc11d31b6280d4010ab481754c7e49b2c9e78db877ca4 *detekt-cli.jar" | sha256sum -c - diff --git a/third_party/python/glean_parser/PKG-INFO b/third_party/python/glean_parser/PKG-INFO deleted file mode 100644 index 87625e9b7ed2..000000000000 --- a/third_party/python/glean_parser/PKG-INFO +++ /dev/null @@ -1,565 +0,0 @@ -Metadata-Version: 2.1 -Name: glean_parser -Version: 3.6.0 -Summary: Parser tools for Mozilla's Glean telemetry -Home-page: https://github.com/mozilla/glean_parser -Author: Michael Droettboom -Author-email: mdroettboom@mozilla.com -License: UNKNOWN -Description: # Glean Parser - - Parser tools for Mozilla's Glean telemetry. - - ## Features - - Contains various utilities for handling `metrics.yaml` and `pings.yaml` for [the - Glean SDK](https://mozilla.github.io/glean). This includes producing generated - code for various integrations, linting and coverage testing. - - ## Documentation - - - [How to Contribute](https://github.com/mozilla/glean_parser/blob/main/CONTRIBUTING.md). Please file bugs in [bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&cf_fission_milestone=---&cf_fx_iteration=---&cf_fx_points=---&cf_status_firefox65=---&cf_status_firefox66=---&cf_status_firefox67=---&cf_status_firefox_esr60=---&cf_status_thunderbird_esr60=---&cf_tracking_firefox65=---&cf_tracking_firefox66=---&cf_tracking_firefox67=---&cf_tracking_firefox_esr60=---&cf_tracking_firefox_relnote=---&cf_tracking_thunderbird_esr60=---&product=Data%20Platform%20and%20Tools&component=Glean%3A%20SDK&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&flag_type-203=X&flag_type-37=X&flag_type-41=X&flag_type-607=X&flag_type-721=X&flag_type-737=X&flag_type-787=X&flag_type-799=X&flag_type-800=X&flag_type-803=X&flag_type-835=X&flag_type-846=X&flag_type-855=X&flag_type-864=X&flag_type-916=X&flag_type-929=X&flag_type-930=X&flag_type-935=X&flag_type-936=X&flag_type-937=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=P3&&rep_platform=Unspecified&status_whiteboard=%5Btelemetry%3Aglean-rs%3Am%3F%5D&target_milestone=---&version=unspecified). - - [User documentation for Glean](https://mozilla.github.io/glean/). - - [`glean_parser` developer documentation](https://mozilla.github.io/glean_parser/). - - ## Requirements - - - Python 3.6 (or later) - - The following library requirements are installed automatically when - `glean_parser` is installed by `pip`. - - - appdirs - - Click - - diskcache - - Jinja2 - - jsonschema - - PyYAML - - Additionally on Python 3.6: - - - iso8601 - - ## Usage - - ```sh - $ glean_parser --help - ``` - - Read in `metrics.yaml`, translate to Kotlin format, and - output to `output_dir`: - - ```sh - $ glean_parser translate -o output_dir -f kotlin metrics.yaml - ``` - - Check a Glean ping against the ping schema: - - ```sh - $ glean_parser check < ping.json - ``` - - - # Changelog - - ## Unreleased - - ## 3.6.0 (2021-06-11) - - - Add a command `data-review` to generate a skeleton Data Review Request for all metrics matching a supplied bug number. ([bug 1704541](https://bugzilla.mozilla.org/show_bug.cgi?id=1704541)) - - Enable custom distribution outside of GeckoView (`gecko_datapoint` becomes optional) - - ## 3.5.0 (2021-06-03) - - - Transform generated folder into QML Module when building Javascript templates for the Qt platform. ([bug 1707896](https://bugzilla.mozilla.org/show_bug.cgi?id=1707896) - - Import the Glean QML module from inside each generated file, removing the requirement to import Glean before importing any of the generated files; - - Prodive a `qmldir` file exposing all generated files; - - Drop the `namespace` option for Javascript templates; - - Add a new `version` option for Javascript templates, required when building for Qt, which expected the Glean QML module version. - - ## 3.4.0 (2021-05-28) - - - Add missing import for Kotlin code ([#339](https://github.com/mozilla/glean_parser/pull/341)) - - Use a plain Kotlin type in the generated interface implementation ([#339](https://github.com/mozilla/glean_parser/pull/341)) - - Generate additional generics for event metrics ([#339](https://github.com/mozilla/glean_parser/pull/341)) - - For Kotlin skip generating `GleanBuildInfo.kt` when requested (with `with_buildinfo=false`) ([#341](https://github.com/mozilla/glean_parser/pull/341)) - - ## 3.3.2 (2021-05-18) - - - Fix another bug in the Swift code generation when generating extra keys ([#334](https://github.com/mozilla/glean_parser/pull/334)) - - ## 3.3.1 (2021-05-18) - - - Fix Swift code generation bug for pings ([#333](https://github.com/mozilla/glean_parser/pull/333)) - - ## 3.3.0 (2021-05-18) - - - Generate new event API construct ([#321](https://github.com/mozilla/glean_parser/pull/321)) - - ## 3.2.0 (2021-04-28) - - - Add option to add extra introductory text to generated markdown ([#298](https://github.com/mozilla/glean_parser/pull/298)) - - Add support for Qt in Javascript templates ([bug 1706252](https://bugzilla.mozilla.org/show_bug.cgi?id=1706252)) - - Javascript templates will now accept the `platform` option. If this option is set to `qt` - the generated templates will be Qt compatible. Default value is `webext`. - - ## 3.1.2 (2021-04-21) - - - BUGFIX: Remove the "DO NOT COMMIT" notice from the documentation. - - ## 3.1.1 (2021-04-19) - - - Recommend to not commit as well as to not edit the generated files. ([bug 1706042](https://bugzilla.mozilla.org/show_bug.cgi?id=1706042)) - - BUGFIX: Include import statement for labeled metric subtypes in Javascript and Typescript templates. - - ## 3.1.0 (2021-04-16) - - - Add support for labeled metric types in Javascript and Typescript templates. - - ## 3.0.0 (2021-04-13) - - - Raise limit on number of statically-defined lables to 100. ([bug 1702263](https://bugzilla.mozilla.org/show_bug.cgi?id=1702263)) - - BUGFIX: Version 2.0.0 of the schema now allows the "special" `glean_.*` ping names for Glean-internal use again. - - Remove support for JWE metric types. - - ## 2.5.0 (2021-02-23) - - - Add parser and object model support for `rate` metric type. ([bug 1645166](https://bugzilla.mozilla.org/show_bug.cgi?id=1645166)) - - Add parser and object model support for telemetry_mirror property. ([bug 1685406](https://bugzilla.mozilla.org/show_bug.cgi?id=1685406)) - - Update the Javascript template to match Glean.js expectations. ([bug 1693516](https://bugzilla.mozilla.org/show_bug.cgi?id=1693516)) - - Glean.js has updated it's export strategy. It will now export each metric type as an independent module; - - Glean.js has dropped support for non ES6 modules. - - Add support for generating Typescript code. ([bug 1692157](https://bugzilla.mozilla.org/show_bug.cgi?id=1692157)) - - The templates added generate metrics and pings code for Glean.js. - - ## 2.4.0 (2021-02-18) - - - **Experimental:** `glean_parser` has a new subcommand `coverage` to convert raw coverage reports - into something consumable by coverage tools, such as codecov.io - - The path to the file that each metric is defined in is now stored on the - `Metric` object in `defined_in["filepath"]`. - - ## 2.3.0 (2021-02-17) - - - Leverage the `glean_namespace` to provide correct import when building for Javascript. - - ## 2.2.0 (2021-02-11) - - - The Kotlin generator now generates static build information that can be passed - into `Glean.initialize` to avoid calling the package manager at runtime. - - ## 2.1.0 (2021-02-10) - - - Add support for generating Javascript code. - - The templates added generate metrics and pings code for Glean.js. - - ## 2.0.0 (2021-02-05) - - - New versions 2.0.0 of the `metrics.yaml` and `pings.yaml` schemas now ship - with `glean_parser`. These schemas are different from version 1.0.0 in the - following ways: - - - Bugs must be specified as URLs. Bug numbers are disallowed. - - The legacy ping names containing underscores are no longer allowed. These - included `deletion_request`, `bookmarks_sync`, `history_sync`, - `session_end`, `all_pings`, `glean_*`). In these cases, the `_` should be - replaced with `-`. - - To upgrade your app or library to use the new schema, replace the version in - the `$schema` value with `2-0-0`. - - - **Breaking change:** It is now an error to use bug numbers (rather than URLs) - in ping definitions. - - - Add the line number that metrics and pings were originally defined in the yaml - files. - - ## 1.29.1 (2020-12-17) - - - BUGFIX: Linter output can now be redirected correctly (1675771). - - ## 1.29.0 (2020-10-07) - - - **Breaking change:** `glean_parser` will now return an error code when any of - the input files do not exist (unless the `--allow-missing-files` flag is - passed). - - Generated code now includes a comment next to each metric containing the name - of the metric in its original `snake_case` form. - - When metrics don't provide a `unit` parameter, it is not included in the - output (as provided by probe-scraper). - - ## 1.28.6 (2020-09-24) - - - BUGFIX: Ensure Kotlin arguments are deterministically ordered - - ## 1.28.5 (2020-09-14) - - - Fix deploy step to update pip before deploying to pypi. - - ## 1.28.4 (2020-09-14) - - - The `SUPERFLUOUS_NO_LINT` warning has been removed from the glinter. - It likely did more harm than good, and makes it hard to make - `metrics.yaml` files that pass across different versions of - `glean_parser`. - - Expired metrics will now produce a linter warning, `EXPIRED_METRIC`. - - Expiry dates that are more than 730 days (\~2 years) in the future - will produce a linter warning, `EXPIRATION_DATE_TOO_FAR`. - - Allow using the Quantity metric type outside of Gecko. - - New parser configs `custom_is_expired` and `custom_validate_expires` - added. These are both functions that take the `expires` value of the - metric and return a bool. (See `Metric.is_expired` and - `Metric.validate_expires`). These will allow FOG to provide custom - validation for its version-based `expires` values. - - ## 1.28.3 (2020-07-28) - - - BUGFIX: Support HashSet and Dictionary in the C\## generated code. - - ## 1.28.2 (2020-07-28) - - - BUGFIX: Generate valid C\## code when using Labeled metric types. - - ## 1.28.1 (2020-07-24) - - - BUGFIX: Add missing column to correctly render markdown tables in generated - documentation. - - ## 1.28.0 (2020-07-23) - - - **Breaking change:** The internal ping `deletion-request` was misnamed in - pings.py causing the linter to not allow use of the correctly named ping for - adding legacy ids to. Consuming apps will need to update their metrics.yaml if - they are using `deletion_request` in any `send_in_pings` to `deletion-request` - after updating. - - ## 1.27.0 (2020-07-21) - - - Rename the `data_category` field to `data_sensitivity` to be clearer. - - ## 1.26.0 (2020-07-21) - - - Add support for JWE metric types. - - Add a `data_sensitivity` field to all metrics for specifying the type of data - collected in the field. - - ## 1.25.0 (2020-07-17) - - - Add support for generating C\## code. - - BUGFIX: The memory unit is now correctly passed to the MemoryDistribution - metric type in Swift. - - ## 1.24.0 (2020-06-30) - - - BUGFIX: look for metrics in send\_if\_empty pings. Metrics for these kinds of - pings were being ignored. - - ## 1.23.0 (2020-06-27) - - - Support for Python 3.5 has been dropped. - - BUGFIX: The ordering of event extra keys will now match with their enum, - fixing a serious bug where keys of extras may not match the correct values in - the data payload. See . - - ## 1.22.0 (2020-05-28) - - - **Breaking change:** (Swift only) Combine all metrics and pings into a single - generated file `Metrics.swift`. - - ## 1.21.0 (2020-05-25) - - - `glinter` messages have been improved with more details and to be more - actionable. - - A maximum of 10 `extra_keys` is now enforced for `event` metric types. - - BUGFIX: the `Lifetime` enum values now match the values of the implementation - in mozilla/glean. - - ## 1.20.4 (2020-05-07) - - - BUGFIX: yamllint errors are now reported using the correct file name. - - ## 1.20.3 (2020-05-06) - - - Support for using `timing_distribution`'s `time_unit` parameter to control - the range of acceptable values is documented. The default unit for this use - case is `nanosecond` to avoid creating a breaking change. See [bug - 1630997](https://bugzilla.mozilla.org/show_bug.cgi?id=1630997) for more - information. - - ## 1.20.2 (2020-04-24) - - - Dependencies that depend on the version of Python being used are now specified - using the [Declaring platform specific dependencies syntax in - setuptools](https://setuptools.readthedocs.io/en/latest/setuptools.html##declaring-platform-specific-dependencies). - This means that more recent versions of dependencies are likely to be - installed on Python 3.6 and later, and unnecessary backport libraries won't - be installed on more recent Python versions. - - ## 1.20.1 (2020-04-21) - - - The minimum version of the runtime dependencies has been lowered to increase - compatibility with other tools. These minimum versions are now tested in CI, - in addition to testing the latest versions of the dependencies that was - already happening in CI. - - ## 1.20.0 (2020-04-15) - - - **Breaking change:** glinter errors found during the `translate` command will - now return an error code. glinter warnings will be displayed, but not return - an error code. - - `glean_parser` now produces a linter warning when `user` lifetime metrics are - set to expire. See [bug - 1604854](https://bugzilla.mozilla.org/show_bug.cgi?id=1604854) for additional - context. - - ## 1.19.0 (2020-03-18) - - - **Breaking change:** The regular expression used to validate labels is - stricter and more correct. - - Add more information about pings to markdown documentation: - - State whether the ping includes client id; - - Add list of data review links; - - Add list of related bugs links. - - `glean_parser` now makes it easier to write external translation - functions for different language targets. - - BUGFIX: `glean_parser` now works on 32-bit Windows. - - ## 1.18.3 (2020-02-24) - - - Dropped the `inflection` dependency. - - Constrained the `zipp` and `MarkupSafe` transitive dependencies to versions - that support Python 3.5. - - ## 1.18.2 (2020-02-14) - - - BUGFIX: Fix rendering of first element of reason list. - - ## 1.18.1 (2020-02-14) - - - BUGFIX: Reason codes are displayed in markdown output for built-in - pings as well. - - BUGFIX: Reason descriptions are indented correctly in markdown - output. - - BUGFIX: To avoid a compiler error, the `@JvmName` annotation isn't - added to private members. - - ## 1.18.0 (2020-02-13) - - - **Breaking Change (Java API)** Have the metrics names in Java match the names - in Kotlin. See [Bug - 1588060](https://bugzilla.mozilla.org/show_bug.cgi?id=1588060). - - The reasons a ping are sent are now included in the generated markdown - documentation. - - ## 1.17.3 (2020-02-05) - - - BUGFIX: The version of Jinja2 now specifies < 3.0, since that version no - longer supports Python 3.5. - - ## 1.17.2 (2020-02-05) - - - BUGFIX: Fixes an import error in generated Kotlin code. - - ## 1.17.1 (2020-02-05) - - - BUGFIX: Generated Swift code now includes `import Glean`, unless generating - for a Glean-internal build. - - ## 1.17.0 (2020-02-03) - - - Remove default schema URL from `validate_ping` - - Make `schema` argument required for CLI - - BUGFIX: Avoid default import in Swift code for Glean itself - - BUGFIX: Restore order of fields in generated Swift code - - ## 1.16.0 (2020-01-15) - - - Support for `reason` codes on pings was added. - - ## 1.15.6 (2020-02-06) - - - BUGFIX: The version of Jinja2 now specifies < 3.0, since that version no - longer supports Python 3.5 (backported from 1.17.3). - - ## 1.15.5 (2019-12-19) - - - BUGFIX: Also allow the legacy name `all_pings` for `send_in_pings` parameter - on metrics - - ## 1.15.4 (2019-12-19) - - - BUGFIX: Also allow the legacy name `all_pings` - - ## 1.15.3 (2019-12-13) - - - Add project title to markdown template. - - Remove "Sorry about that" from markdown template. - - BUGFIX: Replace dashes in variable names to force proper naming - - ## 1.15.2 (2019-12-12) - - - BUGFIX: Use a pure Python library for iso8601 so there is no compilation - required. - - ## 1.15.1 (2019-12-12) - - - BUGFIX: Add some additional ping names to the non-kebab-case allow list. - - ## 1.15.0 (2019-12-12) - - - Restrict new pings names to be kebab-case and change `all_pings` to - `all-pings` - - ## 1.14.0 (2019-12-06) - - - `glean_parser` now supports Python versions 3.5, 3.6, 3.7 and 3.8. - - ## 1.13.0 (2019-12-04) - - - The `translate` command will no longer clear extra files in the output - directory. - - BUGFIX: Ensure all newlines in comments are prefixed with comment markers - - BUGFIX: Escape Swift keywords in variable names in generated code - - Generate documentation for pings that are sent if empty - - ## 1.12.0 (2019-11-27) - - - Reserve the `deletion_request` ping name - - Added a new flag `send_if_empty` for pings - - ## 1.11.0 (2019-11-13) - - - The `glinter` command now performs `yamllint` validation on registry files. - - ## 1.10.0 (2019-11-11) - - - The Kotlin linter `detekt` is now run during CI, and for local - testing if installed. - - Python 3.8 is now tested in CI (in addition to Python 3.7). Using - `tox` for this doesn't work in modern versions of CircleCI, so the - `tox` configuration has been removed. - - `yamllint` has been added to test the YAML files on CI. - - ⚠ Metric types that don't yet have implementations in glean-core - have been removed. This includes `enumeration`, `rate`, `usage`, and - `use_counter`, as well as many labeled metrics that don't exist. - - ## 1.9.5 (2019-10-22) - - - Allow a Swift lint for generated code - - New lint: Restrict what metric can go into the `baseline` ping - - New lint: Warn for slight misspellings in ping names - - BUGFIX: change Labeled types labels from lists to sets. - - ## 1.9.4 (2019-10-16) - - - Use lists instead of sets in Labeled types labels to ensure that the order of - the labels passed to the `metrics.yaml` is kept. - - `glinter` will now check for duplicate labels and error if there are any. - - ## 1.9.3 (2019-10-09) - - - Add labels from Labeled types to the Extra column in the Markdown template. - - ## 1.9.2 (2019-10-08) - - - BUGFIX: Don't call `is_internal_metric` on `Ping` objects. - - ## 1.9.1 (2019-10-07) - - - Don't include Glean internal metrics in the generated markdown. - - ## 1.9.0 (2019-10-04) - - - Glinter now warns when bug numbers (rather than URLs) are used. - - BUGFIX: add `HistogramType` and `MemoryUnit` imports in Kotlin generated code. - - ## 1.8.4 (2019-10-02) - - - Removed unsupported labeled metric types. - - ## 1.8.3 (2019-10-02) - - - Fix indentation for generated Swift code - - ## 1.8.2 (2019-10-01) - - - Created labeled metrics and events in Swift code and wrap it in a - configured namespace - - ## 1.8.1 (2019-09-27) - - - BUGFIX: `memory_unit` is now passed to the Kotlin generator. - - ## 1.8.0 (2019-09-26) - - - A new parser config, `do_not_disable_expired`, was added to turn off the - feature that expired metrics are automatically disabled. This is useful if you - want to retain the disabled value that is explicitly in the `metrics.yaml` - file. - - `glinter` will now report about superfluous `no_lint` entries. - - ## 1.7.0 (2019-09-24) - - - A `glinter` tool is now included to find common mistakes in metric naming - and setup. This check is run during `translate` and warnings will be - displayed. ⚠ These warnings will be treated as errors in a future revision. - - ## 1.6.1 (2019-09-17) - - - BUGFIX: `GleanGeckoMetricsMapping` must include `LabeledMetricType` - and `CounterMetricType`. - - ## 1.6.0 (2019-09-17) - - - NEW: Support for outputting metrics in Swift. - - BUGFIX: Provides a helpful error message when `geckoview_datapoint` is used on - an metric type that doesn't support GeckoView exfiltration. - - Generate a lookup table for Gecko categorical histograms in - `GleanGeckoMetricsMapping`. - - Introduce a 'Swift' output generator. - - ## 1.4.1 (2019-08-28) - - - Documentation only. - - ## 1.4.0 (2019-08-27) - - - Added support for generating markdown documentation from `metrics.yaml` files. - - ## 1.3.0 (2019-08-22) - - - `quantity` metric type has been added. - - ## 1.2.1 (2019-08-13) - - - BUGFIX: `includeClientId` was not being output for PingType. - - ## 1.2.0 (2019-08-13) - - - `memory_distribution` metric type has been added. - - `custom_distribution` metric type has been added. - - `labeled_timespan` is no longer an allowed metric type. - - ## 1.1.0 (2019-08-05) - - - Add a special `all_pings` value to `send_in_pings`. - - ## 1.0.0 (2019-07-29) - - - First release to start following strict semver. - - ## 0.1.0 (2018-10-15) - - - First release on PyPI. - -Keywords: glean_parser -Platform: UNKNOWN -Classifier: Development Status :: 2 - Pre-Alpha -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Description-Content-Type: text/markdown diff --git a/third_party/python/glean_parser/README.md b/third_party/python/glean_parser/README.md deleted file mode 100644 index 7529f4b3c4e3..000000000000 --- a/third_party/python/glean_parser/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Glean Parser - -Parser tools for Mozilla's Glean telemetry. - -## Features - -Contains various utilities for handling `metrics.yaml` and `pings.yaml` for [the -Glean SDK](https://mozilla.github.io/glean). This includes producing generated -code for various integrations, linting and coverage testing. - -## Documentation - -- [How to Contribute](https://github.com/mozilla/glean_parser/blob/main/CONTRIBUTING.md). Please file bugs in [bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&cf_fission_milestone=---&cf_fx_iteration=---&cf_fx_points=---&cf_status_firefox65=---&cf_status_firefox66=---&cf_status_firefox67=---&cf_status_firefox_esr60=---&cf_status_thunderbird_esr60=---&cf_tracking_firefox65=---&cf_tracking_firefox66=---&cf_tracking_firefox67=---&cf_tracking_firefox_esr60=---&cf_tracking_firefox_relnote=---&cf_tracking_thunderbird_esr60=---&product=Data%20Platform%20and%20Tools&component=Glean%3A%20SDK&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&flag_type-203=X&flag_type-37=X&flag_type-41=X&flag_type-607=X&flag_type-721=X&flag_type-737=X&flag_type-787=X&flag_type-799=X&flag_type-800=X&flag_type-803=X&flag_type-835=X&flag_type-846=X&flag_type-855=X&flag_type-864=X&flag_type-916=X&flag_type-929=X&flag_type-930=X&flag_type-935=X&flag_type-936=X&flag_type-937=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=P3&&rep_platform=Unspecified&status_whiteboard=%5Btelemetry%3Aglean-rs%3Am%3F%5D&target_milestone=---&version=unspecified). -- [User documentation for Glean](https://mozilla.github.io/glean/). -- [`glean_parser` developer documentation](https://mozilla.github.io/glean_parser/). - -## Requirements - -- Python 3.6 (or later) - -The following library requirements are installed automatically when -`glean_parser` is installed by `pip`. - -- appdirs -- Click -- diskcache -- Jinja2 -- jsonschema -- PyYAML - -Additionally on Python 3.6: - -- iso8601 - -## Usage - -```sh -$ glean_parser --help -``` - -Read in `metrics.yaml`, translate to Kotlin format, and -output to `output_dir`: - -```sh -$ glean_parser translate -o output_dir -f kotlin metrics.yaml -``` - -Check a Glean ping against the ping schema: - -```sh -$ glean_parser check < ping.json -``` diff --git a/third_party/python/glean_parser/AUTHORS.md b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/AUTHORS.md similarity index 100% rename from third_party/python/glean_parser/AUTHORS.md rename to third_party/python/glean_parser/glean_parser-3.6.0.dist-info/AUTHORS.md diff --git a/third_party/python/glean_parser/LICENSE b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/LICENSE similarity index 100% rename from third_party/python/glean_parser/LICENSE rename to third_party/python/glean_parser/glean_parser-3.6.0.dist-info/LICENSE diff --git a/third_party/python/glean_parser/CHANGELOG.md b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/METADATA similarity index 84% rename from third_party/python/glean_parser/CHANGELOG.md rename to third_party/python/glean_parser/glean_parser-3.6.0.dist-info/METADATA index 8025160a5ed5..0245c48710d1 100644 --- a/third_party/python/glean_parser/CHANGELOG.md +++ b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/METADATA @@ -1,3 +1,85 @@ +Metadata-Version: 2.1 +Name: glean-parser +Version: 3.6.0 +Summary: Parser tools for Mozilla's Glean telemetry +Home-page: https://github.com/mozilla/glean_parser +Author: Michael Droettboom +Author-email: mdroettboom@mozilla.com +License: UNKNOWN +Keywords: glean_parser +Platform: UNKNOWN +Classifier: Development Status :: 2 - Pre-Alpha +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Description-Content-Type: text/markdown +Requires-Dist: appdirs (>=1.4) +Requires-Dist: Click (>=7) +Requires-Dist: diskcache (>=4) +Requires-Dist: Jinja2 (>=2.10.1) +Requires-Dist: jsonschema (<4,>=3.0.2) +Requires-Dist: PyYAML (>=5.3.1) +Requires-Dist: yamllint (>=1.18.0) +Requires-Dist: iso8601 (>=0.1.10) ; python_version <= "3.6" + +# Glean Parser + +Parser tools for Mozilla's Glean telemetry. + +## Features + +Contains various utilities for handling `metrics.yaml` and `pings.yaml` for [the +Glean SDK](https://mozilla.github.io/glean). This includes producing generated +code for various integrations, linting and coverage testing. + +## Documentation + +- [How to Contribute](https://github.com/mozilla/glean_parser/blob/main/CONTRIBUTING.md). Please file bugs in [bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&cf_fission_milestone=---&cf_fx_iteration=---&cf_fx_points=---&cf_status_firefox65=---&cf_status_firefox66=---&cf_status_firefox67=---&cf_status_firefox_esr60=---&cf_status_thunderbird_esr60=---&cf_tracking_firefox65=---&cf_tracking_firefox66=---&cf_tracking_firefox67=---&cf_tracking_firefox_esr60=---&cf_tracking_firefox_relnote=---&cf_tracking_thunderbird_esr60=---&product=Data%20Platform%20and%20Tools&component=Glean%3A%20SDK&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&flag_type-203=X&flag_type-37=X&flag_type-41=X&flag_type-607=X&flag_type-721=X&flag_type-737=X&flag_type-787=X&flag_type-799=X&flag_type-800=X&flag_type-803=X&flag_type-835=X&flag_type-846=X&flag_type-855=X&flag_type-864=X&flag_type-916=X&flag_type-929=X&flag_type-930=X&flag_type-935=X&flag_type-936=X&flag_type-937=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=P3&&rep_platform=Unspecified&status_whiteboard=%5Btelemetry%3Aglean-rs%3Am%3F%5D&target_milestone=---&version=unspecified). +- [User documentation for Glean](https://mozilla.github.io/glean/). +- [`glean_parser` developer documentation](https://mozilla.github.io/glean_parser/). + +## Requirements + +- Python 3.6 (or later) + +The following library requirements are installed automatically when +`glean_parser` is installed by `pip`. + +- appdirs +- Click +- diskcache +- Jinja2 +- jsonschema +- PyYAML + +Additionally on Python 3.6: + +- iso8601 + +## Usage + +```sh +$ glean_parser --help +``` + +Read in `metrics.yaml`, translate to Kotlin format, and +output to `output_dir`: + +```sh +$ glean_parser translate -o output_dir -f kotlin metrics.yaml +``` + +Check a Glean ping against the ping schema: + +```sh +$ glean_parser check < ping.json +``` + + # Changelog ## Unreleased @@ -489,3 +571,5 @@ ## 0.1.0 (2018-10-15) - First release on PyPI. + + diff --git a/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/RECORD b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/RECORD new file mode 100644 index 000000000000..61c013849c3e --- /dev/null +++ b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/RECORD @@ -0,0 +1,35 @@ +glean_parser/__init__.py,sha256=kaoYIRhwZiOE1d8TniW1SHSlEivLBXZQJJ3eiDcamvQ,538 +glean_parser/__main__.py,sha256=FGU4ETmwkPLtzUYOkqmAGElkDKFS98Q-WoXnpAFJH5M,6137 +glean_parser/coverage.py,sha256=2IwC4XMDtDamMkBFoYilmqJzW4gyypq65YVCur8SNas,4405 +glean_parser/csharp.py,sha256=tOrwOLjJCnfie0GvhWvg0Q3fnP4VFQM_4GRaaAqUh4I,5242 +glean_parser/data_review.py,sha256=ZwzL5SD-rC37OHDI9dCq7Z6-NUwARlRgBRb-kRsFGzA,4762 +glean_parser/javascript.py,sha256=U4QaG5DXfmpqEQoScyNSuoTCUJ-5CYts8jyC3o2bWZs,7849 +glean_parser/kotlin.py,sha256=204c61dRCCmnPRtPHzoCtLBwraG2Xs3_AF5HKbBuziI,11105 +glean_parser/lint.py,sha256=jwD0yZ99RZIrmzEBeC3BB9CPPBHcGHmn-oyUjoqNNyI,14470 +glean_parser/markdown.py,sha256=0auYAmzIrX0kqmQyq9DKkRRvTE66yAYdrU-YMgLhrpw,8996 +glean_parser/metrics.py,sha256=jUO4XwatfM4sJGVPcyfbUNb5aW4i9kVYp49OEBASvoM,11350 +glean_parser/parser.py,sha256=sO0kfhicG7xZOfYwNOt0rueBEVgK-YO9M6hVUqQKFP8,13286 +glean_parser/pings.py,sha256=_mrY0idUGMODEMG3fCMRgO8_B9CnXko_FbrOcUnezV0,2667 +glean_parser/swift.py,sha256=3pkl6u3JaQrT8Oz0HONoiq46DUdHCEUDcn_lmZXoCVM,6408 +glean_parser/translate.py,sha256=lnPT3wyzD_YO4Yj6qFAHkP8OZlvVymwK-06QgulnlIs,7394 +glean_parser/util.py,sha256=B7vX7fdmnP-L_yxiFk5csuN5yTOOJXTVR_zJoW13Snc,13701 +glean_parser/validate_ping.py,sha256=0TNvILH6dtzJDys3W8Kqorw6kk03me73OCUDtpoHcXU,2118 +glean_parser/schemas/metrics.1-0-0.schema.yaml,sha256=cND3cvi6iBfPUVmtfIBQfGJV9AALpbvN7nu8E33_J-o,19566 +glean_parser/schemas/metrics.2-0-0.schema.yaml,sha256=IHDSGcfcl9EstXXb7vn_d9x1wtjD_ANJn6ufpCiqBWY,20248 +glean_parser/schemas/pings.1-0-0.schema.yaml,sha256=hwCnsKpEysmrmVp-QHGBArEkVY3vaU1rVsxlTwhAzws,4315 +glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=xUNDwflVSmTcsZL_46uoAbBKROiIPFQRSBt12qiRMt4,3971 +glean_parser/templates/csharp.jinja2,sha256=tPj09JzgSK0YyNb53WkL8WFTA7fcVXyiJ7V-bARnfM0,4354 +glean_parser/templates/javascript.jinja2,sha256=osiIk9cZusDNDjW-ojwOGQulXkxPINmbgNOJx-h5iG8,1825 +glean_parser/templates/kotlin.buildinfo.jinja2,sha256=z9tPgvmNnf8E8gpx7FAWh35oXad8Dlv_UrpqN9CXetY,780 +glean_parser/templates/kotlin.geckoview.jinja2,sha256=K0c1BeKSXDVbshC3gpWALCQFp2JtsoqWhGyN1ScPhC0,5077 +glean_parser/templates/kotlin.jinja2,sha256=fsFXKI_fKwj5AEO4odJ5sRvoC5geW59_DhU6GATaA90,4475 +glean_parser/templates/markdown.jinja2,sha256=tOMN62xEGA1p8QoMKnpCVXUiK_jI5GwLuvCnuOROy8c,3381 +glean_parser/templates/qmldir.jinja2,sha256=m6IGsp-tgTiOfQ7VN8XW6GqX0gJqJkt3B6Pkaul6FVo,156 +glean_parser/templates/swift.jinja2,sha256=McprjDExS3Ao62_eTvEwl-ZHNIbYDOJe05gv1nd4trM,4791 +glean_parser-3.6.0.dist-info/AUTHORS.md,sha256=jBsSsn3EpmpLejgHMhzU1XTFwkCARqYeUs9iGLNgwkQ,432 +glean_parser-3.6.0.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725 +glean_parser-3.6.0.dist-info/METADATA,sha256=eQfxIRqcsGKQFWnaKB1WQ-XVUcu2cuO71ytkBf8MyGA,20755 +glean_parser-3.6.0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +glean_parser-3.6.0.dist-info/entry_points.txt,sha256=s-clJTIqp-PpJD-n3AnIQZFkTafIrzsTbAPX9vNY018,69 +glean_parser-3.6.0.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13 +glean_parser-3.6.0.dist-info/RECORD,, diff --git a/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/WHEEL b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/WHEEL new file mode 100644 index 000000000000..385faab0525c --- /dev/null +++ b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/entry_points.txt b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/entry_points.txt new file mode 100644 index 000000000000..2a22ca73211b --- /dev/null +++ b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +glean_parser = glean_parser.__main__:main_wrapper + diff --git a/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/top_level.txt b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/top_level.txt new file mode 100644 index 000000000000..a7f3a37918a2 --- /dev/null +++ b/third_party/python/glean_parser/glean_parser-3.6.0.dist-info/top_level.txt @@ -0,0 +1 @@ +glean_parser diff --git a/third_party/python/glean_parser/requirements_dev.txt b/third_party/python/glean_parser/requirements_dev.txt deleted file mode 100644 index ea96dfd66a89..000000000000 --- a/third_party/python/glean_parser/requirements_dev.txt +++ /dev/null @@ -1,15 +0,0 @@ -black==21.5b1 -coverage==5.5 -flake8==3.9.2 -flake8-bugbear==21.4.3 -m2r==0.2.1 -mypy==0.812 -pip -pytest-runner==5.3.1 -pytest==6.2.4 -recommonmark==0.7.1 -Sphinx==4.0.2 -twine==3.4.1 -watchdog==2.1.2 -wheel -yamllint==1.26.1 diff --git a/third_party/python/glean_parser/setup.cfg b/third_party/python/glean_parser/setup.cfg deleted file mode 100644 index b06262c0bfd6..000000000000 --- a/third_party/python/glean_parser/setup.cfg +++ /dev/null @@ -1,13 +0,0 @@ -[bdist_wheel] -python_tag = py3 - -[flake8] -exclude = docs - -[aliases] -test = pytest - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/glean_parser/setup.py b/third_party/python/glean_parser/setup.py deleted file mode 100755 index 0003fd411b56..000000000000 --- a/third_party/python/glean_parser/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -"""The setup script.""" - -import sys - -from setuptools import setup, find_packages - - -if sys.version_info < (3, 6): - print("glean_parser requires at least Python 3.6", file=sys.stderr) - sys.exit(1) - - -with open("README.md", encoding="utf-8") as readme_file: - readme = readme_file.read() - -with open("CHANGELOG.md", encoding="utf-8") as history_file: - history = history_file.read() - -requirements = [ - "appdirs>=1.4", - "Click>=7", - "diskcache>=4", - "iso8601>=0.1.10; python_version<='3.6'", - "Jinja2>=2.10.1", - "jsonschema>=3.0.2,<4", - "PyYAML>=5.3.1", - "yamllint>=1.18.0", -] - -setup_requirements = ["pytest-runner", "setuptools-scm"] - -test_requirements = [ - "pytest", -] - -setup( - author="Michael Droettboom", - author_email="mdroettboom@mozilla.com", - classifiers=[ - "Development Status :: 2 - Pre-Alpha", - "Intended Audience :: Developers", - "Natural Language :: English", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - ], - description="Parser tools for Mozilla's Glean telemetry", - entry_points={ - "console_scripts": [ - "glean_parser=glean_parser.__main__:main_wrapper", - ], - }, - install_requires=requirements, - long_description=readme + "\n\n" + history, - long_description_content_type="text/markdown", - include_package_data=True, - keywords="glean_parser", - name="glean_parser", - packages=find_packages(include=["glean_parser"]), - setup_requires=setup_requirements, - test_suite="tests", - tests_require=test_requirements, - url="https://github.com/mozilla/glean_parser", - zip_safe=False, - use_scm_version=True, -) diff --git a/third_party/python/glean_parser/tools/extract_data_categories.py b/third_party/python/glean_parser/tools/extract_data_categories.py deleted file mode 100755 index 9e7d9efcc623..000000000000 --- a/third_party/python/glean_parser/tools/extract_data_categories.py +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env python3 - -# -*- coding: utf-8 -*- - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -""" -Usage: - python extract_data_categories.py metrics.yaml - -Automatically extract the data collection categories for all the metrics in a -metrics.yaml file by consulting the linked data reviews. - -This script reads a metrics.yaml file, visits all of the associated data -reviews, trying to determine the associated data categories, and inserts them -(in place) to the original metrics.yaml file. - -A very simple heuristic is used: to look for the question about data categories -used in all data reviews, and then find any numbers between it and the next -question. When this simple heuristic fails, comments with "!!!" are inserted in -the output as a recommendation to manually investigate and enter the data -categories. - -Requirements from PyPI: BeautifulSoup4, PyYAML -""" - -import dbm -import functools -import re -import sys -import time -from typing import List, Set -from urllib.request import urlopen - - -from bs4 import BeautifulSoup -import yaml - - -cache = dbm.open("bugzilla-cache.db", "c") - - -QUESTION = "what collection type of data do the requested measurements fall under?" - - -CATEGORY_MAP = { - 1: "technical", - 2: "interaction", - 3: "web_activity", - 4: "highly_sensitive", -} - - -def fetch_url(url: str) -> str: - """ - Fetch a web page containing a data review, caching it to avoid - over-fetching. - """ - content = cache.get(url) - if content is not None: - return content - - print(f"Fetching {url}") - content = urlopen(url).read() - cache[url] = content - time.sleep(0.5) - return content - - -@functools.lru_cache(1000) -def parse_data_review(html: str) -> Set[int]: - """ - Parse a single data review. - """ - soup = BeautifulSoup(html, features="html.parser") - text = soup.get_text() - lines = iter(text.splitlines()) - for line in lines: - if QUESTION in line.strip(): - break - - categories: Set[int] = set() - for line in lines: - if "?" in line: - break - categories.update(int(x) for x in re.findall("[0-9]+", line)) - - return categories - - -def categories_as_strings(categories: Set[int]) -> List[str]: - """ - From a set of numeric categories, return the strings used in a metrics.yaml - file. This may contain strings representing errors. - """ - if len(categories): - return [ - CATEGORY_MAP.get(x, f"!!!UNKNOWN CATEGORY {x}") - for x in sorted(list(categories)) - ] - else: - return ["!!! NO DATA CATEGORIES FOUND"] - - -def update_lines( - lines: List[str], - category_name: str, - metric_name: str, - data_sensitivity_values: List[str], -) -> List[str]: - """ - Update the lines of a YAML file in place to include the data_sensitivity - for the given metric, returning the lines of the result. - """ - output = [] - lines_iter = iter(lines) - - for line in lines_iter: - output.append(line) - if line.startswith(f"{category_name}:"): - break - - for line in lines_iter: - output.append(line) - if line.startswith(f" {metric_name}:"): - break - - for line in lines_iter: - output.append(line) - if line.startswith(f" data_reviews:"): - break - - for line in lines_iter: - if not line.strip().startswith("- "): - output.append(" data_sensitivity:\n") - for data_sensitivity in data_sensitivity_values: - output.append(f" - {data_sensitivity}\n") - output.append(line) - break - else: - output.append(line) - - for line in lines_iter: - output.append(line) - - return output - - -def parse_yaml(yamlpath: str): - with open(yamlpath) as fd: - content = yaml.safe_load(fd) - - with open(yamlpath) as fd: - lines = list(fd.readlines()) - - for category_name, category in content.items(): - if category_name.startswith("$") or category_name == "no_lint": - continue - for metric_name, metric in category.items(): - categories = set() - for data_review_url in metric["data_reviews"]: - html = fetch_url(data_review_url) - categories.update(parse_data_review(html)) - lines = update_lines( - lines, category_name, metric_name, categories_as_strings(categories) - ) - - with open(yamlpath, "w") as fd: - for line in lines: - fd.write(line) - - -if __name__ == "__main__": - parse_yaml(sys.argv[-1]) diff --git a/third_party/python/idna/HISTORY.rst b/third_party/python/idna/HISTORY.rst deleted file mode 100644 index 6a2db7028ff0..000000000000 --- a/third_party/python/idna/HISTORY.rst +++ /dev/null @@ -1,162 +0,0 @@ -.. :changelog: - -History -------- - -2.10 (2020-06-27) -+++++++++++++++++ - -- Update to Unicode 13.0.0. -- Throws a more specific exception if "xn--" is provided as a label. -- This is expected to be the last version that supports Python 2. - -2.9 (2020-02-16) -++++++++++++++++ - -- Update to Unicode 12.1.0. -- Prohibit A-labels ending with a hyphen (Thanks, Julien Bernard!) -- Future-proofing: Test on Python 3.7 and 3.8, don't immediately - fail should Python 4 come along. -- Made BSD 3-clause license clearer - -2.8 (2018-12-04) -++++++++++++++++ - -- Update to Unicode 11.0.0. -- Provide more specific exceptions for some malformed labels. - -2.7 (2018-06-10) -++++++++++++++++ - -- Update to Unicode 10.0.0. -- No longer accepts dot-prefixed domains (e.g. ".example") as valid. - This is to be more conformant with the UTS 46 spec. Users should - strip dot prefixes from domains before processing. - -2.6 (2017-08-08) -++++++++++++++++ - -- Allows generation of IDNA and UTS 46 table data for different - versions of Unicode, by deriving properties directly from - Unicode data. -- Ability to generate RFC 5892/IANA-style table data -- Diagnostic output of IDNA-related Unicode properties and - derived calculations for a given codepoint -- Support for idna.__version__ to report version -- Support for idna.idnadata.__version__ and - idna.uts46data.__version__ to report Unicode version of - underlying IDNA and UTS 46 data respectively. - -2.5 (2017-03-07) -++++++++++++++++ - -- Fix bug with Katakana middle dot context-rule (Thanks, Greg - Shikhman.) - -2.4 (2017-03-01) -++++++++++++++++ - -- Restore IDNAError to be a subclass of UnicodeError, as some users of - this library are only looking for the latter to catch invalid strings. - -2.3 (2017-02-28) -++++++++++++++++ - -- Fix bugs relating to deriving IDNAError from UnicodeError. -- More memory footprint improvements (Thanks, Alex Gaynor) - -2.2 (2016-12-21) -++++++++++++++++ - -- Made some changes to the UTS 46 data that should allow Jython to get around - 64kb Java class limits. (Thanks, John A. Booth and Marcin Płonka.) -- In Python 2.6, skip two tests that rely on data not present in that - Python version's unicodedata module. -- Use relative imports to help downstream users. - -2.1 (2016-03-20) -++++++++++++++++ - -- Memory consumption optimizations. The library should consume significantly - less memory through smarter data structures being used to represent - relevant Unicode properties. Many thanks to Shivaram Lingamneni for this - patch. -- Patches to make library work better with Python 2.6. The core library - currently works however the unit testing does not. (Thanks, Robert - Buchholz) -- Better affix all Unicode codepoint properties to a specific version. - -2.0 (2015-05-18) -++++++++++++++++ - -- Added support for Unicode IDNA Compatibility Processing (aka Unicode - Technical Standard #46). Big thanks to Jon Ribbens who contributed this - functionality. - -1.1 (2015-01-27) -++++++++++++++++ - -- Use IDNA properties from Unicode 6.3.0. Internet Architecture Board (IAB) - issued statement recommending against the use of Unicode 7.0.0 until - issues relating to U+08A1 codepoint are resolved. See http://goo.gl/Ed1n0K -- Identify some cases when label would be too longer to be a legal DNS name - and raise an exception. (Thanks, Ed Lewis) - -1.0 (2014-10-12) -++++++++++++++++ - -- Update IDNA properties for Unicode 7.0.0. - -0.9 (2014-07-18) -++++++++++++++++ - -- Fix issue with non-UTF-8 environments reading the README file - now that it contains non-ASCII. (Thanks, Tom Prince) -- Codec functions are useful, so they are separated into their own - module, rather than just existing for compatibility reasons. -- Add LICENSE file. - -0.8 (2014-07-09) -++++++++++++++++ - -- Added MANIFEST.in for correct source distribution compilation. - -0.7 (2014-07-09) -++++++++++++++++ - -- Filled out missing tests for various functions. -- Fix bug in CONTEXTO validation for Greek lower numeral sign (U+0375) -- Fix bug in CONTEXTO validation for Japanese middle dot (U+30FB) -- Improved documentation -- Move designation to Stable - -0.6 (2014-04-29) -++++++++++++++++ - -- Minor improvements to Python 3 support, tests (Thanks, Derek Wilson) - -0.5 (2014-02-05) -++++++++++++++++ - -- Update IDNA properties for Unicode 6.3.0. - -0.4 (2014-01-07) -++++++++++++++++ - -- Fix trove classifier for Python 3. (Thanks, Hynek Schlawack) - -0.3 (2013-07-18) -++++++++++++++++ - -- Ported to Python 3. - -0.2 (2013-07-16) -++++++++++++++++ - -- Improve packaging. -- More conformant, passes all relevant tests in the Unicode TR46 test suite. - -0.1 (2013-05-27) -++++++++++++++++ - -- First proof-of-concept version. diff --git a/third_party/python/idna/MANIFEST.in b/third_party/python/idna/MANIFEST.in deleted file mode 100644 index 54873cb17904..000000000000 --- a/third_party/python/idna/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include *.rst -recursive-include tools * -recursive-exclude tools *.pyc -recursive-include tests * -recursive-exclude tests *.pyc - diff --git a/third_party/python/idna/PKG-INFO b/third_party/python/idna/PKG-INFO deleted file mode 100644 index 707c7b8b68ee..000000000000 --- a/third_party/python/idna/PKG-INFO +++ /dev/null @@ -1,241 +0,0 @@ -Metadata-Version: 1.2 -Name: idna -Version: 2.10 -Summary: Internationalized Domain Names in Applications (IDNA) -Home-page: https://github.com/kjd/idna -Author: Kim Davies -Author-email: kim@cynosure.com.au -License: BSD-like -Description: Internationalized Domain Names in Applications (IDNA) - ===================================================== - - Support for the Internationalised Domain Names in Applications - (IDNA) protocol as specified in `RFC 5891 `_. - This is the latest version of the protocol and is sometimes referred to as - “IDNA 2008”. - - This library also provides support for Unicode Technical Standard 46, - `Unicode IDNA Compatibility Processing `_. - - This acts as a suitable replacement for the “encodings.idna” module that - comes with the Python standard library, but only supports the - old, deprecated IDNA specification (`RFC 3490 `_). - - Basic functions are simply executed: - - .. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - - # Python 2 - >>> import idna - >>> idna.encode(u'ドメイン.テスト') - 'xn--eckwd4c7c.xn--zckzah' - >>> print idna.decode('xn--eckwd4c7c.xn--zckzah') - ドメイン.テスト - - Packages - -------- - - The latest tagged release version is published in the PyPI repository: - - .. image:: https://badge.fury.io/py/idna.svg - :target: http://badge.fury.io/py/idna - - - Installation - ------------ - - To install this library, you can use pip: - - .. code-block:: bash - - $ pip install idna - - Alternatively, you can install the package using the bundled setup script: - - .. code-block:: bash - - $ python setup.py install - - This library works with Python 2.7 and Python 3.4 or later. - - - Usage - ----- - - For typical usage, the ``encode`` and ``decode`` functions will take a domain - name argument and perform a conversion to A-labels or U-labels respectively. - - .. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - - You may use the codec encoding and decoding methods using the - ``idna.codec`` module: - - .. code-block:: pycon - - # Python 2 - >>> import idna.codec - >>> print u'домена.испытание'.encode('idna') - xn--80ahd1agd.xn--80akhbyknj4f - >>> print 'xn--80ahd1agd.xn--80akhbyknj4f'.decode('idna') - домена.испытание - - Conversions can be applied at a per-label basis using the ``ulabel`` or ``alabel`` - functions if necessary: - - .. code-block:: pycon - - # Python 2 - >>> idna.alabel(u'测试') - 'xn--0zwm56d' - - Compatibility Mapping (UTS #46) - +++++++++++++++++++++++++++++++ - - As described in `RFC 5895 `_, the IDNA - specification no longer normalizes input from different potential ways a user - may input a domain name. This functionality, known as a “mapping”, is now - considered by the specification to be a local user-interface issue distinct - from IDNA conversion functionality. - - This library provides one such mapping, that was developed by the Unicode - Consortium. Known as `Unicode IDNA Compatibility Processing `_, - it provides for both a regular mapping for typical applications, as well as - a transitional mapping to help migrate from older IDNA 2003 applications. - - For example, “Königsgäßchen” is not a permissible label as *LATIN CAPITAL - LETTER K* is not allowed (nor are capital letters in general). UTS 46 will - convert this into lower case prior to applying the IDNA conversion. - - .. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode(u'Königsgäßchen') - ... - idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed - >>> idna.encode('Königsgäßchen', uts46=True) - b'xn--knigsgchen-b4a3dun' - >>> print(idna.decode('xn--knigsgchen-b4a3dun')) - königsgäßchen - - Transitional processing provides conversions to help transition from the older - 2003 standard to the current standard. For example, in the original IDNA - specification, the *LATIN SMALL LETTER SHARP S* (ß) was converted into two - *LATIN SMALL LETTER S* (ss), whereas in the current IDNA specification this - conversion is not performed. - - .. code-block:: pycon - - # Python 2 - >>> idna.encode(u'Königsgäßchen', uts46=True, transitional=True) - 'xn--knigsgsschen-lcb0w' - - Implementors should use transitional processing with caution, only in rare - cases where conversion from legacy labels to current labels must be performed - (i.e. IDNA implementations that pre-date 2008). For typical applications - that just need to convert labels, transitional processing is unlikely to be - beneficial and could produce unexpected incompatible results. - - ``encodings.idna`` Compatibility - ++++++++++++++++++++++++++++++++ - - Function calls from the Python built-in ``encodings.idna`` module are - mapped to their IDNA 2008 equivalents using the ``idna.compat`` module. - Simply substitute the ``import`` clause in your code to refer to the - new module name. - - Exceptions - ---------- - - All errors raised during the conversion following the specification should - raise an exception derived from the ``idna.IDNAError`` base class. - - More specific exceptions that may be generated as ``idna.IDNABidiError`` - when the error reflects an illegal combination of left-to-right and right-to-left - characters in a label; ``idna.InvalidCodepoint`` when a specific codepoint is - an illegal character in an IDN label (i.e. INVALID); and ``idna.InvalidCodepointContext`` - when the codepoint is illegal based on its positional context (i.e. it is CONTEXTO - or CONTEXTJ but the contextual requirements are not satisfied.) - - Building and Diagnostics - ------------------------ - - The IDNA and UTS 46 functionality relies upon pre-calculated lookup tables for - performance. These tables are derived from computing against eligibility criteria - in the respective standards. These tables are computed using the command-line - script ``tools/idna-data``. - - This tool will fetch relevant tables from the Unicode Consortium and perform the - required calculations to identify eligibility. It has three main modes: - - * ``idna-data make-libdata``. Generates ``idnadata.py`` and ``uts46data.py``, - the pre-calculated lookup tables using for IDNA and UTS 46 conversions. Implementors - who wish to track this library against a different Unicode version may use this tool - to manually generate a different version of the ``idnadata.py`` and ``uts46data.py`` - files. - - * ``idna-data make-table``. Generate a table of the IDNA disposition - (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix B.1 of RFC - 5892 and the pre-computed tables published by `IANA `_. - - * ``idna-data U+0061``. Prints debugging output on the various properties - associated with an individual Unicode codepoint (in this case, U+0061), that are - used to assess the IDNA and UTS 46 status of a codepoint. This is helpful in debugging - or analysis. - - The tool accepts a number of arguments, described using ``idna-data -h``. Most notably, - the ``--version`` argument allows the specification of the version of Unicode to use - in computing the table data. For example, ``idna-data --version 9.0.0 make-libdata`` - will generate library data against Unicode 9.0.0. - - Note that this script requires Python 3, but all generated library data will work - in Python 2.7. - - - Testing - ------- - - The library has a test suite based on each rule of the IDNA specification, as - well as tests that are provided as part of the Unicode Technical Standard 46, - `Unicode IDNA Compatibility Processing `_. - - The tests are run automatically on each commit at Travis CI: - - .. image:: https://travis-ci.org/kjd/idna.svg?branch=master - :target: https://travis-ci.org/kjd/idna - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: Name Service (DNS) -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff --git a/third_party/python/idna/LICENSE.rst b/third_party/python/idna/idna-2.10.dist-info/LICENSE.rst similarity index 100% rename from third_party/python/idna/LICENSE.rst rename to third_party/python/idna/idna-2.10.dist-info/LICENSE.rst diff --git a/third_party/python/idna/README.rst b/third_party/python/idna/idna-2.10.dist-info/METADATA similarity index 85% rename from third_party/python/idna/README.rst rename to third_party/python/idna/idna-2.10.dist-info/METADATA index b115e83b45b5..f73c0ffefe83 100644 --- a/third_party/python/idna/README.rst +++ b/third_party/python/idna/idna-2.10.dist-info/METADATA @@ -1,3 +1,33 @@ +Metadata-Version: 2.1 +Name: idna +Version: 2.10 +Summary: Internationalized Domain Names in Applications (IDNA) +Home-page: https://github.com/kjd/idna +Author: Kim Davies +Author-email: kim@cynosure.com.au +License: BSD-like +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: Name Service (DNS) +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* + Internationalized Domain Names in Applications (IDNA) ===================================================== @@ -209,3 +239,5 @@ The tests are run automatically on each commit at Travis CI: .. image:: https://travis-ci.org/kjd/idna.svg?branch=master :target: https://travis-ci.org/kjd/idna + + diff --git a/third_party/python/idna/idna-2.10.dist-info/RECORD b/third_party/python/idna/idna-2.10.dist-info/RECORD new file mode 100644 index 000000000000..fd40d6538206 --- /dev/null +++ b/third_party/python/idna/idna-2.10.dist-info/RECORD @@ -0,0 +1,13 @@ +idna/__init__.py,sha256=9Nt7xpyet3DmOrPUGooDdAwmHZZu1qUAy2EaJ93kGiQ,58 +idna/codec.py,sha256=lvYb7yu7PhAqFaAIAdWcwgaWI2UmgseUua-1c0AsG0A,3299 +idna/compat.py,sha256=R-h29D-6mrnJzbXxymrWUW7iZUvy-26TQwZ0ij57i4U,232 +idna/core.py,sha256=jCoaLb3bA2tS_DDx9PpGuNTEZZN2jAzB369aP-IHYRE,11951 +idna/idnadata.py,sha256=gmzFwZWjdms3kKZ_M_vwz7-LP_SCgYfSeE03B21Qpsk,42350 +idna/intranges.py,sha256=TY1lpxZIQWEP6tNqjZkFA5hgoMWOj1OBmnUG8ihT87E,1749 +idna/package_data.py,sha256=bxBjpLnE06_1jSYKEy5svOMu1zM3OMztXVUb1tPlcp0,22 +idna/uts46data.py,sha256=lMdw2zdjkH1JUWXPPEfFUSYT3Fyj60bBmfLvvy5m7ko,202084 +idna-2.10.dist-info/LICENSE.rst,sha256=QSAUQg0kc9ugYRfD1Nng7sqm3eDKMM2VH07CvjlCbzI,1565 +idna-2.10.dist-info/METADATA,sha256=ZWCaQDBjdmSvx5EU7Cv6ORC-9NUQ6nXh1eXx38ySe40,9104 +idna-2.10.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +idna-2.10.dist-info/top_level.txt,sha256=jSag9sEDqvSPftxOQy-ABfGV_RSy7oFh4zZJpODV8k0,5 +idna-2.10.dist-info/RECORD,, diff --git a/third_party/python/idna/idna-2.10.dist-info/WHEEL b/third_party/python/idna/idna-2.10.dist-info/WHEEL new file mode 100644 index 000000000000..8b701e93c231 --- /dev/null +++ b/third_party/python/idna/idna-2.10.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/idna/idna-2.10.dist-info/top_level.txt b/third_party/python/idna/idna-2.10.dist-info/top_level.txt new file mode 100644 index 000000000000..c40472e6fc27 --- /dev/null +++ b/third_party/python/idna/idna-2.10.dist-info/top_level.txt @@ -0,0 +1 @@ +idna diff --git a/third_party/python/idna/setup.cfg b/third_party/python/idna/setup.cfg deleted file mode 100644 index adf5ed72aa40..000000000000 --- a/third_party/python/idna/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bdist_wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/idna/setup.py b/third_party/python/idna/setup.py deleted file mode 100644 index 208c063843f0..000000000000 --- a/third_party/python/idna/setup.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -A library to support the Internationalised Domain Names in Applications -(IDNA) protocol as specified in RFC 5890 et.al. This new methodology, -known as IDNA 2008, can generate materially different results to the -previous standard. The library can act as a drop-in replacement for -the "encodings.idna" module. -""" - -import io, sys -from setuptools import setup - - -def main(): - - python_version = sys.version_info[:2] - if python_version < (2,7): - raise SystemExit("Sorry, Python 2.7 or newer required") - - package_data = {} - exec(open('idna/package_data.py').read(), package_data) - - arguments = { - 'name': 'idna', - 'packages': ['idna'], - 'version': package_data['__version__'], - 'description': 'Internationalized Domain Names in Applications (IDNA)', - 'long_description': io.open("README.rst", encoding="UTF-8").read(), - 'author': 'Kim Davies', - 'author_email': 'kim@cynosure.com.au', - 'license': 'BSD-like', - 'url': 'https://github.com/kjd/idna', - 'classifiers': [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Internet :: Name Service (DNS)', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Utilities', - ], - 'python_requires': '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - } - - setup(**arguments) - -if __name__ == '__main__': - main() diff --git a/third_party/python/idna/tools/idna-data b/third_party/python/idna/tools/idna-data deleted file mode 100755 index 8f1695bd7a89..000000000000 --- a/third_party/python/idna/tools/idna-data +++ /dev/null @@ -1,670 +0,0 @@ -#!/usr/bin/env python3 - -import argparse, collections, datetime, os, re, sys, unicodedata -from urllib.request import urlopen -from intranges import intranges_from_list - -if sys.version_info[0] < 3: - print("Only Python 3 supported.") - sys.exit(2) - -PREFERRED_VERSION = '12.1.0' -UCD_URL = 'http://www.unicode.org/Public/{version}/ucd/{filename}' -UTS46_URL = 'http://www.unicode.org/Public/idna/{version}/{filename}' - -DEFAULT_CACHE_DIR = '~/.cache/unidata' - -# Scripts affected by IDNA contextual rules -SCRIPT_WHITELIST = sorted(['Greek', 'Han', 'Hebrew', 'Hiragana', 'Katakana']) - -# Used to piece apart UTS#46 data for Jython compatibility -UTS46_SEGMENT_SIZE = 100 - -UTS46_STATUSES = { - "valid": ("V", False), - "ignored": ("I", False), - "mapped": ("M", True), - "deviation": ("D", True), - "disallowed": ("X", False), - "disallowed_STD3_valid": ("3", False), - "disallowed_STD3_mapped": ("3", True) -} - -# Exceptions are manually assigned in Section 2.6 of RFC 5892. -exceptions = { - 0x00DF: 'PVALID', # LATIN SMALL LETTER SHARP S - 0x03C2: 'PVALID', # GREEK SMALL LETTER FINAL SIGMA - 0x06FD: 'PVALID', # ARABIC SIGN SINDHI AMPERSAND - 0x06FE: 'PVALID', # ARABIC SIGN SINDHI POSTPOSITION MEN - 0x0F0B: 'PVALID', # TIBETAN MARK INTERSYLLABIC TSHEG - 0x3007: 'PVALID', # IDEOGRAPHIC NUMBER ZERO - 0x00B7: 'CONTEXTO', # MIDDLE DOT - 0x0375: 'CONTEXTO', # GREEK LOWER NUMERAL SIGN (KERAIA) - 0x05F3: 'CONTEXTO', # HEBREW PUNCTUATION GERESH - 0x05F4: 'CONTEXTO', # HEBREW PUNCTUATION GERSHAYIM - 0x30FB: 'CONTEXTO', # KATAKANA MIDDLE DOT - 0x0660: 'CONTEXTO', # ARABIC-INDIC DIGIT ZERO - 0x0661: 'CONTEXTO', # ARABIC-INDIC DIGIT ONE - 0x0662: 'CONTEXTO', # ARABIC-INDIC DIGIT TWO - 0x0663: 'CONTEXTO', # ARABIC-INDIC DIGIT THREE - 0x0664: 'CONTEXTO', # ARABIC-INDIC DIGIT FOUR - 0x0665: 'CONTEXTO', # ARABIC-INDIC DIGIT FIVE - 0x0666: 'CONTEXTO', # ARABIC-INDIC DIGIT SIX - 0x0667: 'CONTEXTO', # ARABIC-INDIC DIGIT SEVEN - 0x0668: 'CONTEXTO', # ARABIC-INDIC DIGIT EIGHT - 0x0669: 'CONTEXTO', # ARABIC-INDIC DIGIT NINE - 0x06F0: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT ZERO - 0x06F1: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT ONE - 0x06F2: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT TWO - 0x06F3: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT THREE - 0x06F4: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT FOUR - 0x06F5: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT FIVE - 0x06F6: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT SIX - 0x06F7: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT SEVEN - 0x06F8: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT EIGHT - 0x06F9: 'CONTEXTO', # EXTENDED ARABIC-INDIC DIGIT NINE - 0x0640: 'DISALLOWED', # ARABIC TATWEEL - 0x07FA: 'DISALLOWED', # NKO LAJANYALAN - 0x302E: 'DISALLOWED', # HANGUL SINGLE DOT TONE MARK - 0x302F: 'DISALLOWED', # HANGUL DOUBLE DOT TONE MARK - 0x3031: 'DISALLOWED', # VERTICAL KANA REPEAT MARK - 0x3032: 'DISALLOWED', # VERTICAL KANA REPEAT WITH VOICED SOUND MARK - 0x3033: 'DISALLOWED', # VERTICAL KANA REPEAT MARK UPPER HALF - 0x3034: 'DISALLOWED', # VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HA - 0x3035: 'DISALLOWED', # VERTICAL KANA REPEAT MARK LOWER HALF - 0x303B: 'DISALLOWED', # VERTICAL IDEOGRAPHIC ITERATION MARK -} -backwardscompatible = {} - - -def hexrange(start, end): - return range(int(start, 16), int(end, 16) + 1) - -def hexvalue(value): - return int(value, 16) - - -class UnicodeVersion(object): - - def __init__(self, version): - result = re.match('^(?P\d+)\.(?P\d+)\.(?P\d+)$', version) - if result: - self.major = int(result.group('major')) - self.minor = int(result.group('minor')) - self.patch = int(result.group('patch')) - self.numerical = (self.major << 8) + (self.minor << 4) + self.patch - self.latest = False - elif version == 'latest': - self.latest = True - else: - raise ValueError('Unrecognized Unicode version') - - def __repr__(self, with_date=True): - if self.latest: - if with_date: - return 'latest@{}'.format(datetime.datetime.now().strftime('%Y-%m-%d')) - else: - return 'latest' - else: - return "{}.{}.{}".format(self.major, self.minor, self.patch) - - @property - def tag(self): - return self.__repr__(with_date=False) - - def __gt__(self, other): - if self.latest: - return True - return self.numerical > other.numerical - - def __eq__(self, other): - if self.latest: - return False - return self.numerical == other.numerical - - -class UnicodeData(object): - - def __init__(self, version, cache, args): - self.version = UnicodeVersion(version) - self.system_version = UnicodeVersion(unicodedata.unidata_version) - self.source = args.source - self.cache = cache - self.max = 0 - - if self.system_version < self.version: - print("Warning: Character stability not guaranteed as Python Unicode data {}" - " older than requested {}".format(self.system_version, self.version)) - - self._load_unicodedata() - self._load_proplist() - self._load_derivedcoreprops() - self._load_blocks() - self._load_casefolding() - self._load_hangulst() - self._load_arabicshaping() - self._load_scripts() - self._load_uts46mapping() - - def _load_unicodedata(self): - - f_ud = self._ucdfile('UnicodeData.txt') - self.ucd_data = {} - range_begin = None - for line in f_ud.splitlines(): - fields = line.split(';') - value = int(fields[0], 16) - start_marker = re.match('^<(?P.*?), First>$', fields[1]) - end_marker = re.match('^<(?P.*?), Last>$', fields[1]) - if start_marker: - range_begin = value - elif end_marker: - for i in range(range_begin, value+1): - fields[1] = '<{}>'.format(end_marker.group('name')) - self.ucd_data[i] = fields[1:] - range_begin = None - else: - self.ucd_data[value] = fields[1:] - - def _load_proplist(self): - - f_pl = self._ucdfile('PropList.txt') - self.ucd_props = collections.defaultdict(list) - for line in f_pl.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})(|\.\.(?P[0-9A-F]{4,6}))\s*;\s*(?P\S+)\s*(|\#.*)$', - line) - if result: - if result.group('end'): - for i in hexrange(result.group('start'), result.group('end')): - self.ucd_props[i].append(result.group('prop')) - else: - i = hexvalue(result.group('start')) - self.ucd_props[i].append(result.group('prop')) - - def _load_derivedcoreprops(self): - - f_dcp = self._ucdfile('DerivedCoreProperties.txt') - for line in f_dcp.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})(|\.\.(?P[0-9A-F]{4,6}))\s*;\s*(?P\S+)\s*(|\#.*)$', - line) - if result: - if result.group('end'): - for i in hexrange(result.group('start'), result.group('end')): - self.ucd_props[i].append(result.group('prop')) - else: - i = hexvalue(result.group('start')) - self.ucd_props[i].append(result.group('prop')) - - def _load_blocks(self): - - self.ucd_block = {} - f_b = self._ucdfile('Blocks.txt') - for line in f_b.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})\.\.(?P[0-9A-F]{4,6})\s*;\s*(?P.*)\s*$', - line) - if result: - for i in hexrange(result.group('start'), result.group('end')): - self.ucd_block[i] = result.group('block') - self.max = max(self.max, i) - - def _load_casefolding(self): - - self.ucd_cf = {} - f_cf = self._ucdfile('CaseFolding.txt') - for line in f_cf.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})\s*;\s*(?P\S+)\s*;\s*(?P[0-9A-F\s]+)\s*', - line) - if result: - if result.group('type') in ('C', 'F'): - self.ucd_cf[int(result.group('cp'), 16)] = \ - ''.join([chr(int(x, 16)) for x in result.group('subst').split(' ')]) - - def _load_hangulst(self): - - self.ucd_hst = {} - f_hst = self._ucdfile('HangulSyllableType.txt') - for line in f_hst.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})\.\.(?P[0-9A-F]{4,6})\s*;\s*(?P\S+)\s*(|\#.*)$', - line) - if result: - for i in hexrange(result.group('start'), result.group('end')): - self.ucd_hst[i] = result.group('type') - - def _load_arabicshaping(self): - - self.ucd_as = {} - f_as = self._ucdfile('ArabicShaping.txt') - for line in f_as.splitlines(): - result = re.match('^(?P[0-9A-F]{4,6})\s*;\s*.*?\s*;\s*(?P\S+)\s*;', line) - if result: - self.ucd_as[int(result.group('cp'), 16)] = result.group('jt') - - def _load_scripts(self): - - self.ucd_s = {} - f_s = self._ucdfile('Scripts.txt') - for line in f_s.splitlines(): - result = re.match( - '^(?P[0-9A-F]{4,6})(|\.\.(?P[0-9A-F]{4,6}))\s*;\s*(?P' - -def test_inline(): - h = html.div(html.span('foo'), html.span('bar')) - assert (h.unicode(indent=2) == - '
    foobar
    ') - -def test_object_tags(): - o = html.object(html.object()) - assert o.unicode(indent=0) == '' diff --git a/third_party/python/py/tox.ini b/third_party/python/py/tox.ini deleted file mode 100644 index f3203507fd9e..000000000000 --- a/third_party/python/py/tox.ini +++ /dev/null @@ -1,44 +0,0 @@ -[tox] -# Skip py37-pytest29 as such a combination does not work (#192) -envlist=py{27,35,36}-pytest{29,30,31},py37-pytest{30,31} - -[testenv] -commands= - pip install -U . # hande the install order fallout since pytest depends on pip - py.test --confcutdir=. --junitxml={envlogdir}/junit-{envname}.xml [] -deps= - attrs - pytest29: pytest~=2.9.0 - pytest30: pytest~=3.0.0 - pytest31: pytest~=3.1.0 - -[testenv:py27-xdist] -basepython=python2.7 -deps= - pytest~=2.9.0 - pytest-xdist<=1.16.0 -commands= - pip install -U .. # hande the install order fallout since pytest depends on pip - py.test -n3 --confcutdir=.. --runslowtests \ - --junitxml={envlogdir}/junit-{envname}.xml [] - -[testenv:jython] -changedir=testing -commands= - {envpython} -m pip install -U .. # hande the install order fallout since pytest depends on pip - {envpython} -m pytest --confcutdir=.. --junitxml={envlogdir}/junit-{envname}0.xml {posargs:io_ code} - -[pytest] -rsyncdirs = conftest.py py doc testing -addopts = -ra -testpaths = testing - -[coverage:run] -branch = 1 -source = . -parallel = 1 -[coverage:report] -include = py/*,testing/* -exclude_lines = - #\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER) - ^\s*raise NotImplementedError\b diff --git a/third_party/python/pyasn1/CHANGES.rst b/third_party/python/pyasn1/CHANGES.rst deleted file mode 100644 index 3ba82c06e3db..000000000000 --- a/third_party/python/pyasn1/CHANGES.rst +++ /dev/null @@ -1,716 +0,0 @@ - -Revision 0.4.8, released 16-11-2019 ------------------------------------ - -- Added ability of combining `SingleValueConstraint` and - `PermittedAlphabetConstraint` objects into one for proper modeling - `FROM ... EXCEPT ...` ASN.1 clause. - -Revision 0.4.7, released 01-09-2019 ------------------------------------ - -- Added `isInconsistent` property to all constructed types. This property - conceptually replaces `verifySizeSpec` method to serve a more general - purpose e.g. ensuring all required fields are in a good shape. By default - this check invokes subtype constraints verification and is run by codecs - on value de/serialisation. -- Deprecate `subtypeSpec` attributes and keyword argument. It is now - recommended to pass `ValueSizeConstraint`, as well as all other constraints, - to `subtypeSpec`. -- Fixed a design bug in a way of how the items assigned to constructed - types are verified. Now if `Asn1Type`-based object is assigned, its - compatibility is verified based on having all tags and constraint - objects as the type in field definition. When a bare Python value is - assigned, then field type object is cloned and initialized with the - bare value (constraints verificaton would run at this moment). -- Added `WithComponentsConstraint` along with related - `ComponentPresentConstraint` and `ComponentAbsentConstraint` classes - to be used with `Sequence`/`Set` types representing - `SET ... WITH COMPONENTS ...` like ASN.1 constructs. - -Revision 0.4.6, released 31-07-2019 ------------------------------------ - -- Added previously missing `SET OF ANY` construct encoding/decoding support. -- Added `omitEmptyOptionals` option which is respected by `Sequence` - and `Set` encoders. When `omitEmptyOptionals` is set to `True`, empty - initialized optional components are not encoded. Default is `False`. -- New elements to `SequenceOf`/`SetOf` objects can now be added at any - position - the requirement for the new elements to reside at the end - of the existing ones (i.e. s[len(s)] = 123) is removed. -- List-like slicing support added to `SequenceOf`/`SetOf` objects. -- Removed default initializer from `SequenceOf`/`SetOf` types to ensure - consistent behaviour with the rest of ASN.1 types. Before this change, - `SequenceOf`/`SetOf` instances immediately become value objects behaving - like an empty list. With this change, `SequenceOf`/`SetOf` objects - remain schema objects unless a component is added or `.clear()` is - called. - This change can potentially cause incompatibilities with existing - pyasn1 objects which assume `SequenceOf`/`SetOf` instances are value - objects right upon instantiation. - The behaviour of `Sequence`/`Set` types depends on the `componentType` - initializer: if on `componentType` is given, the behaviour is the - same as `SequenceOf`/`SetOf` have. IF `componentType` is given, but - neither optional nor defaulted components are present, the created - instance remains schema object, If, however, either optional or - defaulted component isi present, the created instance immediately - becomes a value object. -- Added `.reset()` method to all constructed types to turn value object - into a schema object. -- Added `PyAsn1UnicodeDecodeError`/`PyAsn1UnicodeDecodeError` exceptions - to help the caller treating unicode errors happening internally - to pyasn1 at the upper layers. -- Added support for subseconds CER/DER encoding edge cases in - `GeneralizedTime` codec. -- Fixed 3-digit fractional seconds value CER/DER encoding of - `GeneralizedTime`. -- Fixed `AnyDecoder` to accept possible `TagMap` as `asn1Spec` - to make dumping raw value operational - -Revision 0.4.5, released 29-12-2018 ------------------------------------ - -- Debug logging refactored for more efficiency when disabled and - for more functionality when in use. Specifically, the global - LOG object can easily be used from any function/method, not just - from codec main loop as it used to be. -- More debug logging added to BER family of codecs to ease encoding - problems troubleshooting. -- Copyright notice extended to the year 2019 -- Fixed defaulted constructed SEQUENCE component initialization. - -Revision 0.4.4, released 26-07-2018 ------------------------------------ - -- Fixed native encoder type map to include all ASN.1 types - rather than just ambiguous ones -- Fixed crash in `.prettyPrint` of `Sequence` and `Set` occurring - at OPTIONAL components - -Revision 0.4.3, released 23-05-2018 ------------------------------------ - -- Copyright notice extended to the year 2018 -- Fixed GeneralizedTime.asDateTime to perform milliseconds conversion - correctly - -Revision 0.4.2, released 23-11-2017 ------------------------------------ - -- Fixed explicit tag splitting in chunked encoding mode at - OctetString and BitString encoders - -Revision 0.4.1, released 23-11-2017 ------------------------------------ - -- ANY DEFINED BY clause support implemented -- Encoders refactored to take either a value (as ASN.1 object) - or a Python value plus ASN.1 schema -- BitString decoder optimised for better performance when running on - constructed encoding -- Constructed types' .getComponentBy*() methods accept the `default` - parameter to return instead if schema object is to be returned -- Constructed types' .getComponentBy*() methods accept the `instantiate` - parameter to disable automatic inner component instantiation -- The ASN.1 types' `__repr__` implementation reworked for better readability - at the cost of not being `eval`-compliant -- Most ASN.1 types' `__str__` magic methods (except for OctetString and - character types) reworked to call `.prettyPrint()` rather than - `.prettyPrint` calling `__str__` as it was before. The intention is - to eventually deprecate `.prettyPrint()` in favor of `str()`. - The other related change is that `str()` of enumerations and boolean - types will return string label instead of number. -- Fixed Choice.clear() to fully reset internal state of the object -- Sphinx documentation rearranged, simplified and reworded -- The `isValue` singleton is now the only way to indicate ASN.1 schema - as opposed to ASN.1 schema instance. The legacy `None` initializer - support has been removed. -- Changed `Null` object initialization behaviour: previous default - value (`''`) is not set anymore. Thus `Null()` call produces a - ASN.1 schema object, while `Null('')` - value object. -- Migrated all docs and references from SourceForge -- Imports PEP8'ed -- Fixed ASN.1 encoder not to omit empty substrate produced for inner - component if the inner component belongs to the simple class (as - opposed to constructed class) -- Fixed CER/DER encoders to respect tagged CHOICE when ordering - SET components -- Fixed ASN.1 types not to interfere with the Pickle protocol -- Fixed Sequence/SequenceOf types decoding heuristics in schema-less - decoding mode - -Revision 0.3.7, released 04-10-2017 ------------------------------------ - -- Fixed ASN.1 time types pickling/deepcopy'ing - -Revision 0.3.6, released 21-09-2017 ------------------------------------ - -- End-of-octets encoding optimized at ASN.1 encoders -- The __getitem__/__setitem__ behavior of Set/Sequence and SetOf/SequenceOf - objects aligned with the canonical Mapping and Sequence protocols in part -- Fixed crash in ASN.1 encoder when encoding an explicitly tagged - component of a Sequence - -Revision 0.3.5, released 16-09-2017 ------------------------------------ - -- Codecs signatures unified and pass the options kwargs through the - call chain -- Explicit tag encoding optimized to avoid unnecessary copying -- End-of-octets sentinel encoding optimized -- Refactored ASN.1 codecs properties to silently enforce proper - length and chunk size encoding modes -- Fixed DER encoder to always produce primitive encoding -- Fixed crash at SequenceOf native decoder -- Fixed Real.prettyPrint() to fail gracefully on overflow -- Fixed a couple of crashes when debug mode is enabled - -Revision 0.3.4, released 07-09-2017 ------------------------------------ - -- Fixed Native encoder to handle SEQUENCE/SET objects without - the componentType property -- Added missing component-less SEQUENCE/SET objects dict duck-typing support -- Fixed unnecessary duplicate tags detection at NamesType.tagMap -- Fixed crash at SEQUENCE and SEQUENCE OF CER encoder when running - in schemaless mode -- Fixed Character types instantiation from OctetString type -- double - unicode decoding may have scrambled the data - -Revision 0.3.3, released 27-08-2017 ------------------------------------ - -- Improved ASN.1 types instantiation performance -- Improved BER/CER/DER decoder performance by not unconditionally casting - substrate into str/bytes. -- Fixed exponential index size growth bug when building ambiguous - NamedTypes tree -- Fixed constructed types decoding failure at BER codec if running - in schema-less mode -- Fixed crash on prettyPrint'ing a SEQUENCE with no defined components -- Fixed SetOf ordering at CER/DER encoder -- Fixed crash on conditional binascii module import -- Fix to TagSet hash value build - -Revision 0.3.2, released 04-08-2017 ------------------------------------ - -- Fixed SequenceOf/SetOf types initialization syntax to remain - backward compatible with pyasn1 0.2.* -- Rectified thread safety issues by moving lazy, run-time computation - into object initializer. -- Fixed .isValue property to return True for empty SetOf/SequenceOf - objects -- Fixed GeneralizedTime/UTCTime CER/DER codecs to actually get invoked -- Fixed DER/CER encoders handling optional SEQUENCE/SET fields containing - nested SEQUENCE/SET with optional fields. -- Fixed crash in SequenceOf/SetOf pretty printing and decoding (in some - cases) -- Fixed documentation markup issues. - -Revision 0.3.1, released 26-07-2017 ------------------------------------ - -- ASN.1 types __init__(), .clone() and .subtype() signatures - refactored into keyword arguments to simplify their signatures. -- ASN.1 types initialization refactored to minimize the use of - relatively expensive isNoValue() call -- Lazily pre-populate list of values of Sequence/Set/Choice types -- NamedTypes comparison made more efficient -- More efficient constraints computation and code clean up -- The __getitem__() implementation of some ASN.1 types & tag object - refactored for better performance -- BER/CER/DER value encoders refactored to produce either tuple of - bytes or octet-stream depending on what is more optimal -- Reduced the frequency of expensive isinstance() calls -- Tag-related classes optimized, refactored into properties and - documented. -- The NamedValues implementation refactored to mimic Python dict, its use - in ASN.1 types refactored into properties and better documented. - WARNING: this change introduces a deviation from original API. -- NamedType family of classes overhauled, optimized and documented. -- The `componentType` attribute of constructed ASN.1 types turned - read-only on instances. -- Sequence/Set DER/CER/DER decoder optimized to skip the case of - reordered components handling when not necessary. -- Tags and constraints-related getter methods refactored into read-only - instance attributes. -- The .hasValue() method refactored into .isValue property. All ASN.1 - objects now support them, not just scalars. -- The Real.{isInfinity, isPlusInfinity, isMinusInfinity} methods - refactored into properties and renamed into IsInf, IsPlusInf and isMinusInf -- The end-of-octets type refactored to ensure it is a singleton. Codecs - changed to rely on that for better performance. -- Codecs lookup made more efficient at BER/CER/DER decoder main loop by - assigning `typeId` to every ASN.1 type, not just ambiguous ones. -- The .getComponent*() methods of constructed ASN.1 types changed - to lazily instantiate underlying type rather than return `None`. - This should simplify its API as initialization like `X[0][1] = 2` becomes - possible. - WARNING: this change introduces a deviation from the original API. -- The .setComponent*() methods of SetOf/SequenceOf types changed not - to allow uninitialized "holes" inside the sequences of their components. - They now behave similarly to Python lists. - WARNING: this change introduces a deviation from the original API. -- Default and optional components en/decoding of Constructed type - refactored towards better efficiency and more control. -- OctetsString and Any decoder optimized to avoid creating ASN.1 - objects for chunks of substrate. Instead they now join substrate - chunks together and create ASN.1 object from it just once. -- The GeneralizedTime and UTCTime types now support to/from Python - datetime object conversion. -- Unit tests added for the `compat` sub-package. -- Fixed BitString named bits initialization bug. -- Fixed non-functional tag cache (when running Python 2) at DER decoder. -- Fixed chunked encoding restriction on DER encoder. -- Fixed SET components ordering at DER encoder. -- Fixed BIT STRING & OCTET STRING encoding to be always non-chunked (e.g. - primitive) at DER encoder -- Fixed `compat.integer.from_bytes()` behaviour on empty input. - -Revision 0.2.3, released 25-02-2017 ------------------------------------ - -- Improved SEQUENCE/SET/CHOICE decoding performance by maintaining a single shared - NamedType object for all instances of SEQUENCE/SET object. -- Improved INTEGER encoding/decoding by switching to Python's built-in - integer serialisation functions. -- Improved BitString performance by rebasing it onto Python int type and leveraging - fast Integer serialisation functions. -- BitString type usability improved in many ways: for example bitshifting and - numeric operation on BitString is now possible. -- Minor ObjectIdentifier type performance optimization. -- ASN.1 character types refactored to keep unicode contents internally - (rather than serialised octet stream) and duck-type it directly. -- ASN.1 OctetString initialized from a Python object performs bytes() - on it when running on Python 3 (used to do str() which is probably - less logical). -- Missing support for NoValue.__sizeof__ added. -- Added checks to make sure SEQUENCE/SET components being assigned - match the prototypes. -- Setter methods for constructed types consistently accept matchTags - and matchConstraints flags to control the strictness of inner - components compatibility verification. Previously, these checks - were tied to verifyConstraints flag, now they are all independent. -- General documentation improvements here and there. -- Fix to __reversed__() magic to make it returning an iterator. -- Test suite simplified and unified. -- The __all__ variable added to most of the Python modules. -- The "test" directory renamed into "tests" not to collide with - the "test" module. - -Revision 0.2.2, released 07-02-2017 ------------------------------------ - -- FIX TO A SECURITY WEAKNESS: define length only decoders could have successfully - processed indefinite length serialisation. -- FIX TO A SECURITY WEAKNESS: canonical decoders (CER/DER) may have successfully - consumed non-canonical variations of (otherwise valid) serialisation. -- Broken Enumerated subtyping fixed. - -Revision 0.2.1, released 05-02-2017 ------------------------------------ - -- FIX TO A SECURITY WEAKNESS: BER decoder improperly cached long tags. -- New "native" codec implemented to transform pyasn1 types to Python built-in types and back. -- Switched to new-style classes. -- Sphinx documentation added. -- BitString improvements: - - * simple string of binary digits is now supported as initializer - * default str() yields string of binary digits (used to yield str(tuple()) - * binValue and hexValue initializers added - * .asNumbers(), .asOctets() and asInteger() representation added - -- Components of constructed ASN.1 types can now be populated with - uninitialized ASN.1 objects by assigning either noValue sentinel or - setupComponent() function return in addition to now-legacy None sentinel. - This should improve code readability. -- NoValue class improved to become a singleton and catch more kinds - of access to it. -- Compatibility wrappers str2octs() and oct2strs() fixed to run over - iso-8859-1 encoding. -- Integer changed to emit Real instance if division produces a float. -- True division operation now supported by Integer type. -- The __contains__(), __reverse__() methods implemented for container types -- Iterator protocol support implemented for all container types. - Warning, warning, warning: this change may potentially affect backward - compatibility when: - - * user class overrides __getitem__() without overriding __iter__() - * when user code iterates over SEQUENCE object to get its components (now keys will be yielded) - -- Almost complete Python list and dict protocols added to SequenceOf/SetOf and - Sequence/Set respectively -- Fix to divmod operation implementation in Integer type. -- Fix to IntegerDecoder's precomputed value map on Python 3. -- Fix to base ASN.1 types to run in "unicode_literals" mode. -- Fix to composite constraints "+" operands ordering (AbstractConstraintSet.__radd__) -- Fix to constraints merge in .subtype() -- on merge existing constraints are - expanded to accommodate new constraints, not the other way round. When existing - constraints are wrapped in ConstraintsIntersection composite, additional - constraints being added on subtyping effectively further narrow the set of - allowed values, which aligns well with the notion of subtyping. -- Fix to NamedTypes methods to handle .getTagMap() returning None -- Fix to Set/Sequence.setDefaultComponents() to return self -- Copyright notice added to non-trivial source code files. -- Author's email changed, copyright extended to 2017 - -Revision 0.1.9, released 28-09-2015 ------------------------------------ - -- Wheel distribution format now supported. -- Extensions added to text files, CVS attic flushed. -- Fix to make uninitialized pyasn1 objects failing properly on hash(). -- Fix to ObjectIdentifier initialization from unicode string. -- Fix to CER/DER Boolean decoder - fail on non single-octet payload. - -Revision 0.1.8, released 22-06-2015 ------------------------------------ - -- ObjectIdentifier codec fixed to work properly with arc 0 and arc 2 values. -- Explicit limit on ObjectIdentifier arc value size removed. -- Unicode initializer support added to OctetString type and derivatives. -- New prettyPrintType() abstract method implemented to base pyasn1 types - to facilitate encoding errors analysis. -- The __str__() method implemented to Tag, TagSet and TagMap classes to - ease encoding errors troubleshooting. - easing encoding errors -- Fix to SEQUENCE and SET types to give them their private componentTypes - collection (which is a NamedTypes object) so that they won't collide in - a MT execution environment. -- Missing T61String,ISO646String character types and ObjectDescriptor useful - type added. -- Distribute is gone, switched to setuptools completely. -- Missing NamedValues.__repr__() added. -- The base.NoValue() class, that indicates uninitialized ASN.1 object, - made public. -- The base.NoValue() class instances now support __repr__() what makes - possible to perform repr() on uninitialized pyasn1 types objects. -- When comparing ASN.1 types, by-tag and/or by-constraints matching - can now be performed with the isSuperTypeOf()/isSameTypeWith() optional - flags. -- Constructed types now verify their consistency by invoking - isSameTypeWith(matchTags=True, matchConstraints=False) and - isSuperTypeOf(matchTags=False, matchConstraints=True) for each of their - components rather than isSuperTypeOf() as it used to be. Constriants check - could be enforced to isSameTypeWith() with the strictConstraints=True - constructed classes attribute. -- Constructed types can now be initialized with new .setComponents() method - which accepts both var-args and keyword-args. Default repr() modified to - reflect this change. -- NamedTypes() and NamedValues() made comparable. -- Test coverage extended to cover pyasn1 types __repr__() function. -- The abs(Integer()) & abs(Real()) operation now returns respective pyasn1 - type, not a Python type. -- More Python magic methods implementations added to Integer & Real classes - (e.g. __pos__, __neg__, __round__, __floor__, __ceil__, __trunc__) -- The Integer.__invert__ Python magic method implemented. -- The OctetString.__int__() and .__float__() magic methods implemented. -- Handle the case of null writer at Debug printer. -- BitString encoder/decoder performance improved. -- Built-in debugging is now based on Python logging module. -- Fix to NamedType.__repr__() to work properly. -- Fixes to __repr__() implementation of many built-in ASN.1 types to take into - account all of their initializers such as tagSet, subtypeSpec etc. -- String typed float initializer to REAL type now supported. -- Float typed mantissa initializer to REAL type for base 2 added. -- Encoding bases 8 and 16 support for REAL type binary encoder added. -- More strict CER/DER encoders added for GeneralizedTime and UTCTime types. -- Asn1Item.hasValue() added to easily distinguish initalized ASN.1 objects - from uninitialized ones (e.g. pure types). -- Fix to REAL type binary decoder to handle different bases and scale factor. -- Fix to TagSet.repr() to include [obsolete] baseTag information. -- Fix to broken REAL type decoding handling. -- Fix to BitString and OctetString decoders dealing with constructed - encoding -- it used to be possible to embed other types in substrate. -- DER codec hardened not to tolerate indefinite length encoding/decoding. -- Fix to end-of-octest sentinel handling: - - + require strict two-zeros sentinel encoding - + recognize EOO sentinel only when explicitly requested by caller - of the decoder via allowEoo=True parameter (warning: API change) - -Revision 0.1.7 --------------- - -- License updated to vanilla BSD 2-Clause to ease package use - (https://opensource.org/licenses/BSD-2-Clause). -- Test suite made discoverable by unittest/unittest2 discovery feature. -- Fix to decoder working on indefinite length substrate -- end-of-octets - marker is now detected by both tag and value. Otherwise zero values may - interfere with end-of-octets marker. -- Fix to decoder to fail in cases where tagFormat indicates inappropriate - format for the type (e.g. BOOLEAN is always PRIMITIVE, SET is always - CONSTRUCTED and OCTET STRING is either of the two) -- Fix to REAL type encoder to force primitive encoding form encoding. -- Fix to CHOICE decoder to handle explicitly tagged, indefinite length - mode encoding -- Fix to REAL type decoder to handle negative REAL values correctly. Test - case added. - -Revision 0.1.6 --------------- - -- The compact (valueless) way of encoding zero INTEGERs introduced in - 0.1.5 seems to fail miserably as the world is filled with broken - BER decoders. So we had to back off the *encoder* for a while. - There's still the IntegerEncoder.supportCompactZero flag which - enables compact encoding form whenever it evaluates to True. -- Report package version on debugging code initialization. - -Revision 0.1.5 --------------- - -- Documentation updated and split into chapters to better match - web-site contents. -- Make prettyPrint() working for non-initialized pyasn1 data objects. It - used to throw an exception. -- Fix to encoder to produce empty-payload INTEGER values for zeros -- Fix to decoder to support empty-payload INTEGER and REAL values -- Fix to unit test suites imports to be able to run each from - their current directory - -Revision 0.1.4 --------------- - -- Built-in codec debugging facility added -- Added some more checks to ObjectIdentifier BER encoder catching - posible 2^8 overflow condition by two leading sub-OIDs -- Implementations overriding the AbstractDecoder.valueDecoder method - changed to return the rest of substrate behind the item being processed - rather than the unprocessed substrate within the item (which is usually - empty). -- Decoder's recursiveFlag feature generalized as a user callback function - which is passed an uninitialized object recovered from substrate and - its uninterpreted payload. -- Catch inappropriate substrate type passed to decoder. -- Expose tagMap/typeMap/Decoder objects at DER decoder to uniform API. -- Obsolete __init__.MajorVersionId replaced with __init__.__version__ - which is now in-sync with distutils. -- Package classifiers updated. -- The __init__.py's made non-empty (rumors are that they may be optimized - out by package managers). -- Bail out gracefully whenever Python version is older than 2.4. -- Fix to Real codec exponent encoding (should be in 2's complement form), - some more test cases added. -- Fix in Boolean truth testing built-in methods -- Fix to substrate underrun error handling at ObjectIdentifier BER decoder -- Fix to BER Boolean decoder that allows other pre-computed - values besides 0 and 1 -- Fix to leading 0x80 octet handling in DER/CER/DER ObjectIdentifier decoder. - See https://www.esat.kuleuven.be/cosic/publications/article-1432.pdf - -Revision 0.1.3 --------------- - -- Include class name into asn1 value constraint violation exception. -- Fix to OctetString.prettyOut() method that looses leading zero when - building hex string. - -Revision 0.1.2 --------------- - -- Fix to __long__() to actually return longs on py2k -- Fix to OctetString.__str__() workings of a non-initialized object. -- Fix to quote initializer of OctetString.__repr__() -- Minor fix towards ObjectIdentifier.prettyIn() reliability -- ObjectIdentifier.__str__() is aliased to prettyPrint() -- Exlicit repr() calls replaced with '%r' - -Revision 0.1.1 --------------- - -- Hex/bin string initializer to OctetString object reworked - (in a backward-incompatible manner) -- Fixed float() infinity compatibility issue (affects 2.5 and earlier) -- Fixed a bug/typo at Boolean CER encoder. -- Major overhawl for Python 2.4 -- 3.2 compatibility: - + get rid of old-style types - + drop string module usage - + switch to rich comparation - + drop explicit long integer type use - + map()/filter() replaced with list comprehension - + apply() replaced with \*/\*\*args - + switched to use 'key' sort() callback function - + support both __nonzero__() and __bool__() methods - + modified not to use py3k-incompatible exception syntax - + getslice() operator fully replaced with getitem() - + dictionary operations made 2K/3K compatible - + base type for encoding substrate and OctetString-based types - is now 'bytes' when running py3k and 'str' otherwise - + OctetString and derivatives now unicode compliant. - + OctetString now supports two python-neutral getters: asOcts() & asInts() - + print OctetString content in hex whenever it is not printable otherwise - + in test suite, implicit relative import replaced with the absolute one - + in test suite, string constants replaced with numerics - -Revision 0.0.13 ---------------- - -- Fix to base10 normalization function that loops on univ.Real(0) - -Revision 0.0.13b ----------------- - -- ASN.1 Real type is now supported properly. -- Objects of Constructed types now support __setitem__() -- Set/Sequence objects can now be addressed by their field names (string index) - and position (integer index). -- Typo fix to ber.SetDecoder code that prevented with schema decoding - operation. -- Fix to explicitly tagged items decoding support. -- Fix to OctetString.prettyPrint() to better handle non-printable content. -- Fix to repr() workings of Choice objects. - -Revision 0.0.13a ----------------- - -- Major codec re-design. -- Documentation significantly improved. -- ASN.1 Any type is now supported. -- All example ASN.1 modules moved to separate pyasn1-modules package. -- Fix to initial sub-OID overflow condition detection an encoder. -- BitString initialization value verification improved. -- The Set/Sequence.getNameByPosition() method implemented. -- Fix to proper behaviour of PermittedAlphabetConstraint object. -- Fix to improper Boolean substrate handling at CER/DER decoders. -- Changes towards performance improvement: - - + all dict.has_key() & dict.get() invocations replaced with modern syntax - (this breaks compatibility with Python 2.1 and older). - + tag and tagset caches introduced to decoder - + decoder code improved to prevent unnecessary pyasn1 objects creation - + allow disabling components verification when setting components to - structured types, this is used by decoder whilst running with schema - mode. - + BER decoder for integer values now looks up a small set of pre-computed - substrate values to save on decoding. - + a few pre-computed values configured to ObjectIdentifier BER encoder. - + ChoiceDecoder split-off SequenceOf one to save on unnecessary checks. - + replace slow hasattr()/getattr() calls with isinstance() introspection. - + track the number of initialized components of Constructed types to save - on default/optional components initialization. - + added a shortcut ObjectIdentifier.asTuple() to be used instead of - __getitem__() in hotspots. - + use Tag.asTuple() and pure integers at tag encoder. - + introduce and use in decoder the baseTagSet attribute of the built-in - ASN.1 types. - -Revision 0.0.12a ----------------- - -- The individual tag/length/value processing methods of - encoder.AbstractItemEncoder renamed (leading underscore stripped) - to promote overloading in cases where partial substrate processing - is required. -- The ocsp.py, ldap.py example scripts added. -- Fix to univ.ObjectIdentifier input value handler to disallow negative - sub-IDs. - -Revision 0.0.11a ----------------- - -- Decoder can now treat values of unknown types as opaque OctetString. -- Fix to Set/SetOf type decoder to handle uninitialized scalar SetOf - components correctly. - -Revision 0.0.10a ----------------- - -- API versioning mechanics retired (pyasn1.v1 -> pyasn1) what makes - it possible to zip-import pyasn1 sources (used by egg and py2exe). - -Revision 0.0.9a ---------------- - -- Allow any non-zero values in Boolean type BER decoder, as it's in - accordnance with the standard. - -Revision 0.0.8a ---------------- - -- Integer.__index__() now supported (for Python 2.5+). -- Fix to empty value encoding in BitString encoder, test case added. -- Fix to SequenceOf decoder that prevents it skipping possible Choice - typed inner component. -- Choice.getName() method added for getting currently set component - name. -- OctetsString.prettyPrint() does a single str() against its value - eliminating an extra quotes. - -Revision 0.0.7a ---------------- - -- Large tags (>31) now supported by codecs. -- Fix to encoder to properly handle explicitly tagged untagged items. -- All possible value lengths (up to 256^126) now supported by encoders. -- Fix to Tag class constructor to prevent negative IDs. - -Revision 0.0.6a ---------------- - -- Make use of setuptools. -- Constraints derivation verification (isSuperTypeOf()/isSubTypeOf()) fixed. -- Fix to constraints comparation logic -- can't cmp() hash values as it - may cause false positives due to hash conflicts. - -Revision 0.0.5a ---------------- - -- Integer BER codec reworked fixing negative values encoding bug. -- clone() and subtype() methods of Constructed ASN.1 classes now - accept optional cloneValueFlag flag which controls original value - inheritance. The default is *not* to inherit original value for - performance reasons (this may affect backward compatibility). - Performance penalty may be huge on deeply nested Constructed objects - re-creation. -- Base ASN.1 types (pyasn1.type.univ.*) do not have default values - anymore. They remain uninitialized acting as ASN.1 types. In - this model, initialized ASN.1 types represent either types with - default value installed or a type instance. -- Decoders' prototypes are now class instances rather than classes. - This is to simplify initial value installation to decoder's - prototype value. -- Bugfix to BitString BER decoder (trailing bits not regarded). -- Bugfix to Constraints use as mapping keys. -- Bugfix to Integer & BitString clone() methods -- Bugix to the way to distinguish Set from SetOf at CER/DER SetOfEncoder -- Adjustments to make it running on Python 1.5. -- In tests, substrate constants converted from hex escaped literals into - octals to overcome indefinite hex width issue occuring in young Python. -- Minor performance optimization of TagSet.isSuperTagSetOf() method -- examples/sshkey.py added - -Revision 0.0.4a ---------------- - -* Asn1Type.prettyPrinter() -> \*.prettyPrint() - -Revision 0.0.3a ---------------- - -* Simple ASN1 objects now hash to their Python value and don't - depend upon tag/constraints/etc. -* prettyIn & prettyOut methods of SimplleAsn1Object become public -* many syntax fixes - -Revision 0.0.2a ---------------- - -* ConstraintsIntersection.isSuperTypeOf() and - ConstraintsIntersection.hasConstraint() implemented -* Bugfix to NamedValues initialization code -* +/- operators added to NamedValues objects -* Integer.__abs__() & Integer.subtype() added -* ObjectIdentifier.prettyOut() fixes -* Allow subclass components at SequenceAndSetBase -* AbstractConstraint.__cmp__() dropped -* error.Asn1Error replaced with error.PyAsn1Error - -Revision 0.0.1a ---------------- - -* Initial public alpha release diff --git a/third_party/python/pyasn1/MANIFEST.in b/third_party/python/pyasn1/MANIFEST.in deleted file mode 100644 index c605b0eef094..000000000000 --- a/third_party/python/pyasn1/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include *.rst *.md -recursive-include tests *.py -recursive-include docs Makefile *.rst *.svg conf.py -prune docs/build -prune docs/source/.templates diff --git a/third_party/python/pyasn1/PKG-INFO b/third_party/python/pyasn1/PKG-INFO deleted file mode 100644 index 45d958b171d2..000000000000 --- a/third_party/python/pyasn1/PKG-INFO +++ /dev/null @@ -1,35 +0,0 @@ -Metadata-Version: 1.2 -Name: pyasn1 -Version: 0.4.8 -Summary: ASN.1 types and codecs -Home-page: https://github.com/etingof/pyasn1 -Author: Ilya Etingof -Author-email: etingof@gmail.com -Maintainer: Ilya Etingof -License: BSD -Description: Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208) -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Console -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: Intended Audience :: Telecommunications Industry -Classifier: License :: OSI Approved :: BSD License -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Topic :: Communications -Classifier: Topic :: Software Development :: Libraries :: Python Modules diff --git a/third_party/python/pyasn1/README.md b/third_party/python/pyasn1/README.md deleted file mode 100644 index e36324b0ded7..000000000000 --- a/third_party/python/pyasn1/README.md +++ /dev/null @@ -1,184 +0,0 @@ - -ASN.1 library for Python ------------------------- -[![PyPI](https://img.shields.io/pypi/v/pyasn1.svg?maxAge=2592000)](https://pypi.org/project/pyasn1) -[![Python Versions](https://img.shields.io/pypi/pyversions/pyasn1.svg)](https://pypi.org/project/pyasn1/) -[![Build status](https://travis-ci.org/etingof/pyasn1.svg?branch=master)](https://secure.travis-ci.org/etingof/pyasn1) -[![Coverage Status](https://img.shields.io/codecov/c/github/etingof/pyasn1.svg)](https://codecov.io/github/etingof/pyasn1) -[![GitHub license](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/etingof/pyasn1/master/LICENSE.txt) - -This is a free and open source implementation of ASN.1 types and codecs -as a Python package. It has been first written to support particular -protocol (SNMP) but then generalized to be suitable for a wide range -of protocols based on -[ASN.1 specification](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.208-198811-W!!PDF-E&type=items). - -Features --------- - -* Generic implementation of ASN.1 types (X.208) -* Standards compliant BER/CER/DER codecs -* Dumps/loads ASN.1 structures from Python types -* 100% Python, works with Python 2.4 up to Python 3.7 -* MT-safe -* Contributed ASN.1 compiler [Asn1ate](https://github.com/kimgr/asn1ate) - -Why using pyasn1 ----------------- - -ASN.1 solves the data serialisation problem. This solution was -designed long ago by the wise Ancients. Back then, they did not -have the luxury of wasting bits. That is why ASN.1 is designed -to serialise data structures of unbounded complexity into -something compact and efficient when it comes to processing -the data. - -That probably explains why many network protocols and file formats -still rely on the 30+ years old technology. Including a number of -high-profile Internet protocols and file formats. - -Quite a number of books cover the topic of ASN.1. -[Communication between heterogeneous systems](http://www.oss.com/asn1/dubuisson.html) -by Olivier Dubuisson is one of those high quality books freely -available on the Internet. - -The pyasn1 package is designed to help Python programmers tackling -network protocols and file formats at the comfort of their Python -prompt. The tool struggles to capture all aspects of a rather -complicated ASN.1 system and to represent it on the Python terms. - -How to use pyasn1 ------------------ - -With pyasn1 you can build Python objects from ASN.1 data structures. -For example, the following ASN.1 data structure: - -```bash -Record ::= SEQUENCE { - id INTEGER, - room [0] INTEGER OPTIONAL, - house [1] INTEGER DEFAULT 0 -} -``` - -Could be expressed in pyasn1 like this: - -```python -class Record(Sequence): - componentType = NamedTypes( - NamedType('id', Integer()), - OptionalNamedType( - 'room', Integer().subtype( - implicitTag=Tag(tagClassContext, tagFormatSimple, 0) - ) - ), - DefaultedNamedType( - 'house', Integer(0).subtype( - implicitTag=Tag(tagClassContext, tagFormatSimple, 1) - ) - ) - ) -``` - -It is in the spirit of ASN.1 to take abstract data description -and turn it into a programming language specific form. -Once you have your ASN.1 data structure expressed in Python, you -can use it along the lines of similar Python type (e.g. ASN.1 -`SET` is similar to Python `dict`, `SET OF` to `list`): - -```python ->>> record = Record() ->>> record['id'] = 123 ->>> record['room'] = 321 ->>> str(record) -Record: - id=123 - room=321 ->>> -``` - -Part of the power of ASN.1 comes from its serialisation features. You -can serialise your data structure and send it over the network. - -```python ->>> from pyasn1.codec.der.encoder import encode ->>> substrate = encode(record) ->>> hexdump(substrate) -00000: 30 07 02 01 7B 80 02 01 41 -``` - -Conversely, you can turn serialised ASN.1 content, as received from -network or read from a file, into a Python object which you can -introspect, modify, encode and send back. - -```python ->>> from pyasn1.codec.der.decoder import decode ->>> received_record, rest_of_substrate = decode(substrate, asn1Spec=Record()) ->>> ->>> for field in received_record: ->>> print('{} is {}'.format(field, received_record[field])) -id is 123 -room is 321 -house is 0 ->>> ->>> record == received_record -True ->>> received_record.update(room=123) ->>> substrate = encode(received_record) ->>> hexdump(substrate) -00000: 30 06 02 01 7B 80 01 7B -``` - -The pyasn1 classes struggle to emulate their Python prototypes (e.g. int, -list, dict etc.). But ASN.1 types exhibit more complicated behaviour. -To make life easier for a Pythonista, they can turn their pyasn1 -classes into Python built-ins: - -```python ->>> from pyasn1.codec.native.encoder import encode ->>> encode(record) -{'id': 123, 'room': 321, 'house': 0} -``` - -Or vice-versa -- you can initialize an ASN.1 structure from a tree of -Python objects: - -```python ->>> from pyasn1.codec.native.decoder import decode ->>> record = decode({'id': 123, 'room': 321, 'house': 0}, asn1Spec=Record()) ->>> str(record) -Record: - id=123 - room=321 ->>> -``` - -With ASN.1 design, serialisation codecs are decoupled from data objects, -so you could turn every single ASN.1 object into many different -serialised forms. As of this moment, pyasn1 supports BER, DER, CER and -Python built-ins codecs. The extremely compact PER encoding is expected -to be introduced in the upcoming pyasn1 release. - -More information on pyasn1 APIs can be found in the -[documentation](http://snmplabs.com/pyasn1/), -compiled ASN.1 modules for different protocols and file formats -could be found in the pyasn1-modules -[repo](https://github.com/etingof/pyasn1-modules). - -How to get pyasn1 ------------------ - -The pyasn1 package is distributed under terms and conditions of 2-clause -BSD [license](http://snmplabs.com/pyasn1/license.html). Source code is freely -available as a GitHub [repo](https://github.com/etingof/pyasn1). - -You could `pip install pyasn1` or download it from [PyPI](https://pypi.org/project/pyasn1). - -If something does not work as expected, -[open an issue](https://github.com/etingof/pyasn1/issues) at GitHub or -post your question [on Stack Overflow](https://stackoverflow.com/questions/ask) -or try browsing pyasn1 -[mailing list archives](https://sourceforge.net/p/pyasn1/mailman/pyasn1-users/). - -Copyright (c) 2005-2019, [Ilya Etingof](mailto:etingof@gmail.com). -All rights reserved. diff --git a/third_party/python/pyasn1/TODO.rst b/third_party/python/pyasn1/TODO.rst deleted file mode 100644 index 5c79ee7cdfdd..000000000000 --- a/third_party/python/pyasn1/TODO.rst +++ /dev/null @@ -1,92 +0,0 @@ - -Things to be done -================= - -Big things to tackle, anyone interested is welcome to fork pyasn1, work on -it and come up with a PR! - -New codecs ----------- - -* PER -* OER -* XER -* LWER -* JSON (alinged with existing experimental schemas) - -Lazy codecs ------------ - -Implement a thin layer over base types to cache pieces -of substrate being decoded till the very moment of ASN.1 -object access in the parse tree. - -Codecs generator interface --------------------------- - -For indefinite length or chunked encoding mode, make codecs -iterable producing/consuming substrate/objects. - -ASN.1 schema compiler ---------------------- - -Ideally, the compiler should parse modern schema files and be -designed to emit code for arbitrary languages (including SQL). - -Base types ----------- - -Implement X.680 constructs, including information schema. - -Examples --------- - -Add examples, including advanced/obscure use cases. - -Documentation -------------- - -Document more API, add notes and example snippets. - -More fresh modules ------------------- - -Compile and ship more Pythonized ASN.1 modules for -various ASN.1-based protocols (e.g. Kerberos etc). -Refresh outdated modules in pyasn1-packages. - -Minor, housekeeping things --------------------------- - -* more PEP8'ing at places -* consider simplifying repr(), otherwise it tend to be too hard to grasp -* Specialize ASN.1 character and useful types - -* ber.decoder: - - * suspend codec on underrun error ? - * present subtypes ? - * component presence check wont work at innertypeconst - * type vs value, defaultValue - -* ber.encoder: - - * Asn1Item.clone() / shallowcopy issue - * large length encoder? - * lookup type by tag first to allow custom codecs for non-base types - -* type.useful: - - * may need to implement prettyIn/Out - -* type.char: - - * may need to implement constraints - -* type.namedtypes - - * type vs tagset name convention - -* how untagged TagSet should be initialized? - -* type and codecs for Real needs refactoring diff --git a/third_party/python/pyasn1/LICENSE.rst b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/LICENSE.rst similarity index 100% rename from third_party/python/pyasn1/LICENSE.rst rename to third_party/python/pyasn1/pyasn1-0.4.8.dist-info/LICENSE.rst diff --git a/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/METADATA similarity index 92% rename from third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO rename to third_party/python/pyasn1/pyasn1-0.4.8.dist-info/METADATA index 45d958b171d2..d68429de7e93 100644 --- a/third_party/python/pyasn1/pyasn1.egg-info/PKG-INFO +++ b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/METADATA @@ -1,4 +1,4 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: pyasn1 Version: 0.4.8 Summary: ASN.1 types and codecs @@ -7,7 +7,6 @@ Author: Ilya Etingof Author-email: etingof@gmail.com Maintainer: Ilya Etingof License: BSD -Description: Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208) Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console @@ -33,3 +32,7 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications Classifier: Topic :: Software Development :: Libraries :: Python Modules + +Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208) + + diff --git a/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/RECORD b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/RECORD new file mode 100644 index 000000000000..54b2de2e86d9 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/RECORD @@ -0,0 +1,42 @@ +pyasn1/__init__.py,sha256=1Rn8wrJioqfDz7ORFwMehoT15xHOVeiiQD5pZW37D8s,175 +pyasn1/debug.py,sha256=HWGbLlEPLoCNyHqBd1Vd_KK91TppEn3CA4YgUxktT2k,3726 +pyasn1/error.py,sha256=DIn2FWY3ACYNbk_42b3ny2bevkehpK2lOqfAsfdkvBE,2257 +pyasn1/codec/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/codec/ber/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/codec/ber/decoder.py,sha256=7-WINr38zVEa3KUkmshh8FjK6QnFaA8Y7j7XaTgYfRk,59708 +pyasn1/codec/ber/encoder.py,sha256=xHl01PCIAiHZXev4x01sjbCgAUKcsTT6SzaLI3nt-9E,27741 +pyasn1/codec/ber/eoo.py,sha256=eZ6lEyHdayMcMmNqtceDIyzf7u5lOeZoRK-WEUxVThI,626 +pyasn1/codec/cer/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/codec/cer/decoder.py,sha256=ZYBqtDGNiYmKDpKDvioMDf-TYVWoJeZY3I8TEAKuk5s,3745 +pyasn1/codec/cer/encoder.py,sha256=PGtzcIelIHj5d5Yqc5FATMEIWCJybQYFlCaK1gy-NIA,9409 +pyasn1/codec/der/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/codec/der/decoder.py,sha256=kinXcogMDPGlR3f7hmAxRv2YbQyeP-UhuKM0r8gkbeA,2722 +pyasn1/codec/der/encoder.py,sha256=ZfRRxSCefQyLg0DLNb4zllaYf5_AWGIv3SPzB83Ln2I,3073 +pyasn1/codec/native/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/codec/native/decoder.py,sha256=4Q29tdKyytK3Oz-m94MSWxxPi_GhcBKvUfvPNKQcL0Y,7671 +pyasn1/codec/native/encoder.py,sha256=0eMLWR49dwMA1X4si0XswR1kX1aDAWyCeUNTpEbChag,8002 +pyasn1/compat/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/compat/binary.py,sha256=mgWqHmr_SMEdB2WVVr6jyYMnodSbPP6IByE5qKccWLM,698 +pyasn1/compat/calling.py,sha256=uTk3nJtGrElqJi8t34SoO8-eWFBG0gwNhXrlo1YmFEE,379 +pyasn1/compat/dateandtime.py,sha256=zHvXXBp4t3XJ6teg_tz6qgNDevzd93qnrLoEbNxZQ_E,482 +pyasn1/compat/integer.py,sha256=k6tqyxXMC0zJoU-Rz4oUPPoUpTmWXE6Prnzu0tkmmks,2988 +pyasn1/compat/octets.py,sha256=ICe-DVLBIOHmNSz-sp3ioMh--smodJ4VW3Ju0ogJMWA,1359 +pyasn1/compat/string.py,sha256=exqXJmPM6vYj4MjzsjciQdpUcJprRdgrLma8I4UcYHA,505 +pyasn1/type/__init__.py,sha256=EEDlJYS172EH39GUidN_8FbkNcWY9OVV8e30AV58pn0,59 +pyasn1/type/base.py,sha256=TX7qdOX3EPiY7-11MY4fwK2Hy6nQsrdQ_M41aUcApno,22386 +pyasn1/type/char.py,sha256=5HH8r1IqZMDCsfDlQHVCRphLlFuZ93bE2NW78CgeUTI,11397 +pyasn1/type/constraint.py,sha256=0Qsth_0JctnDMvOSe5R-vd9IosgjqkKZT_X9lBRXtuI,22132 +pyasn1/type/error.py,sha256=4_BHdjX-AL5WMTpU-tX1Nfo_P88c2z1sDvqPU-S9Bns,246 +pyasn1/type/namedtype.py,sha256=VIL3H3oPgA0zNrDSeAhKmi4CZGTb69uDBVNJzzRk3wM,16368 +pyasn1/type/namedval.py,sha256=dXYWiVTihvBy4RiebGY3AlIXsJvW78mJ1L7JSw-H7Qw,4886 +pyasn1/type/opentype.py,sha256=pUpnPqv8o4AFeIsmGHDTFfuxXAq7FvG3hrTEnoAgBO8,2848 +pyasn1/type/tag.py,sha256=nAK54C0_F_DL4_IaWRthIfIYBOTuXZoVVcbcbqgZiVA,9486 +pyasn1/type/tagmap.py,sha256=2bwm0hqxG2gvXYheOI_iasfl2Z_B93qU7y39EHteUvs,2998 +pyasn1/type/univ.py,sha256=FXc_VOStZfC-xIVTznpFO0qTq1aO4XyJFU0ayQWgPMY,108921 +pyasn1/type/useful.py,sha256=r_K6UhgcrJ0ej658X-s9522I9T7oYVdmEKcbXTkZMds,5368 +pyasn1-0.4.8.dist-info/LICENSE.rst,sha256=IsXMaSKrXWn7oy2MXuTN0UmBUIy1OvwOvYVZOEf9laU,1334 +pyasn1-0.4.8.dist-info/METADATA,sha256=Mx_DbLo2GA_t9nOIsqu-18vjHdTjMR1LtUzdcfLzE0Y,1521 +pyasn1-0.4.8.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +pyasn1-0.4.8.dist-info/top_level.txt,sha256=dnNEQt3nIDIO5mSCCOB5obQHrjDOUsRycdBujc2vrWE,7 +pyasn1-0.4.8.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +pyasn1-0.4.8.dist-info/RECORD,, diff --git a/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/WHEEL b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/WHEEL new file mode 100644 index 000000000000..8b701e93c231 --- /dev/null +++ b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/pyasn1/pyasn1.egg-info/top_level.txt b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/top_level.txt similarity index 100% rename from third_party/python/pyasn1/pyasn1.egg-info/top_level.txt rename to third_party/python/pyasn1/pyasn1-0.4.8.dist-info/top_level.txt diff --git a/third_party/python/pyasn1/pyasn1.egg-info/zip-safe b/third_party/python/pyasn1/pyasn1-0.4.8.dist-info/zip-safe similarity index 100% rename from third_party/python/pyasn1/pyasn1.egg-info/zip-safe rename to third_party/python/pyasn1/pyasn1-0.4.8.dist-info/zip-safe diff --git a/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt b/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt deleted file mode 100644 index 4877900b834a..000000000000 --- a/third_party/python/pyasn1/pyasn1.egg-info/SOURCES.txt +++ /dev/null @@ -1,161 +0,0 @@ -CHANGES.rst -LICENSE.rst -MANIFEST.in -README.md -TODO.rst -setup.cfg -setup.py -docs/Makefile -docs/tutorial.rst -docs/source/changelog.rst -docs/source/conf.py -docs/source/contents.rst -docs/source/download.rst -docs/source/example-use-case.rst -docs/source/license.rst -docs/source/.static/logo.svg -docs/source/pyasn1/contents.rst -docs/source/pyasn1/codec/ber/contents.rst -docs/source/pyasn1/codec/cer/contents.rst -docs/source/pyasn1/codec/der/contents.rst -docs/source/pyasn1/codec/native/contents.rst -docs/source/pyasn1/error/contents.rst -docs/source/pyasn1/type/base/asn1type.rst -docs/source/pyasn1/type/base/constructedasn1type.rst -docs/source/pyasn1/type/base/contents.rst -docs/source/pyasn1/type/base/novalue.rst -docs/source/pyasn1/type/base/simpleasn1type.rst -docs/source/pyasn1/type/char/bmpstring.rst -docs/source/pyasn1/type/char/contents.rst -docs/source/pyasn1/type/char/generalstring.rst -docs/source/pyasn1/type/char/graphicstring.rst -docs/source/pyasn1/type/char/ia5string.rst -docs/source/pyasn1/type/char/iso646string.rst -docs/source/pyasn1/type/char/numericstring.rst -docs/source/pyasn1/type/char/printablestring.rst -docs/source/pyasn1/type/char/t61string.rst -docs/source/pyasn1/type/char/teletexstring.rst -docs/source/pyasn1/type/char/universalstring.rst -docs/source/pyasn1/type/char/utf8string.rst -docs/source/pyasn1/type/char/videotexstring.rst -docs/source/pyasn1/type/char/visiblestring.rst -docs/source/pyasn1/type/constraint/constraintsexclusion.rst -docs/source/pyasn1/type/constraint/constraintsintersection.rst -docs/source/pyasn1/type/constraint/constraintsunion.rst -docs/source/pyasn1/type/constraint/containedsubtype.rst -docs/source/pyasn1/type/constraint/contents.rst -docs/source/pyasn1/type/constraint/permittedalphabet.rst -docs/source/pyasn1/type/constraint/singlevalue.rst -docs/source/pyasn1/type/constraint/valuerange.rst -docs/source/pyasn1/type/constraint/valuesize.rst -docs/source/pyasn1/type/constraint/withcomponents.rst -docs/source/pyasn1/type/namedtype/contents.rst -docs/source/pyasn1/type/namedtype/defaultednamedtype.rst -docs/source/pyasn1/type/namedtype/namedtype.rst -docs/source/pyasn1/type/namedtype/namedtypes.rst -docs/source/pyasn1/type/namedtype/optionalnamedtype.rst -docs/source/pyasn1/type/namedval/contents.rst -docs/source/pyasn1/type/namedval/namedval.rst -docs/source/pyasn1/type/opentype/contents.rst -docs/source/pyasn1/type/opentype/opentype.rst -docs/source/pyasn1/type/tag/contents.rst -docs/source/pyasn1/type/tag/tag.rst -docs/source/pyasn1/type/tag/tagmap.rst -docs/source/pyasn1/type/tag/tagset.rst -docs/source/pyasn1/type/univ/any.rst -docs/source/pyasn1/type/univ/bitstring.rst -docs/source/pyasn1/type/univ/boolean.rst -docs/source/pyasn1/type/univ/choice.rst -docs/source/pyasn1/type/univ/contents.rst -docs/source/pyasn1/type/univ/enumerated.rst -docs/source/pyasn1/type/univ/integer.rst -docs/source/pyasn1/type/univ/null.rst -docs/source/pyasn1/type/univ/objectidentifier.rst -docs/source/pyasn1/type/univ/octetstring.rst -docs/source/pyasn1/type/univ/real.rst -docs/source/pyasn1/type/univ/sequence.rst -docs/source/pyasn1/type/univ/sequenceof.rst -docs/source/pyasn1/type/univ/set.rst -docs/source/pyasn1/type/univ/setof.rst -docs/source/pyasn1/type/useful/contents.rst -docs/source/pyasn1/type/useful/generalizedtime.rst -docs/source/pyasn1/type/useful/objectdescriptor.rst -docs/source/pyasn1/type/useful/utctime.rst -pyasn1/__init__.py -pyasn1/debug.py -pyasn1/error.py -pyasn1.egg-info/PKG-INFO -pyasn1.egg-info/SOURCES.txt -pyasn1.egg-info/dependency_links.txt -pyasn1.egg-info/top_level.txt -pyasn1.egg-info/zip-safe -pyasn1/codec/__init__.py -pyasn1/codec/ber/__init__.py -pyasn1/codec/ber/decoder.py -pyasn1/codec/ber/encoder.py -pyasn1/codec/ber/eoo.py -pyasn1/codec/cer/__init__.py -pyasn1/codec/cer/decoder.py -pyasn1/codec/cer/encoder.py -pyasn1/codec/der/__init__.py -pyasn1/codec/der/decoder.py -pyasn1/codec/der/encoder.py -pyasn1/codec/native/__init__.py -pyasn1/codec/native/decoder.py -pyasn1/codec/native/encoder.py -pyasn1/compat/__init__.py -pyasn1/compat/binary.py -pyasn1/compat/calling.py -pyasn1/compat/dateandtime.py -pyasn1/compat/integer.py -pyasn1/compat/octets.py -pyasn1/compat/string.py -pyasn1/type/__init__.py -pyasn1/type/base.py -pyasn1/type/char.py -pyasn1/type/constraint.py -pyasn1/type/error.py -pyasn1/type/namedtype.py -pyasn1/type/namedval.py -pyasn1/type/opentype.py -pyasn1/type/tag.py -pyasn1/type/tagmap.py -pyasn1/type/univ.py -pyasn1/type/useful.py -tests/__init__.py -tests/__main__.py -tests/base.py -tests/test_debug.py -tests/codec/__init__.py -tests/codec/__main__.py -tests/codec/ber/__init__.py -tests/codec/ber/__main__.py -tests/codec/ber/test_decoder.py -tests/codec/ber/test_encoder.py -tests/codec/cer/__init__.py -tests/codec/cer/__main__.py -tests/codec/cer/test_decoder.py -tests/codec/cer/test_encoder.py -tests/codec/der/__init__.py -tests/codec/der/__main__.py -tests/codec/der/test_decoder.py -tests/codec/der/test_encoder.py -tests/codec/native/__init__.py -tests/codec/native/__main__.py -tests/codec/native/test_decoder.py -tests/codec/native/test_encoder.py -tests/compat/__init__.py -tests/compat/__main__.py -tests/compat/test_binary.py -tests/compat/test_integer.py -tests/compat/test_octets.py -tests/type/__init__.py -tests/type/__main__.py -tests/type/test_char.py -tests/type/test_constraint.py -tests/type/test_namedtype.py -tests/type/test_namedval.py -tests/type/test_opentype.py -tests/type/test_tag.py -tests/type/test_univ.py -tests/type/test_useful.py \ No newline at end of file diff --git a/third_party/python/pyasn1/pyasn1.egg-info/dependency_links.txt b/third_party/python/pyasn1/pyasn1.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/pyasn1/pyasn1.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/pyasn1/setup.cfg b/third_party/python/pyasn1/setup.cfg deleted file mode 100644 index b998b2a06f18..000000000000 --- a/third_party/python/pyasn1/setup.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE.rst - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/pyasn1/setup.py b/third_party/python/pyasn1/setup.py deleted file mode 100644 index fa0a876e78bf..000000000000 --- a/third_party/python/pyasn1/setup.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -# -# This file is part of pyasn1 software. -# -# Copyright (c) 2005-2019, Ilya Etingof -# License: http://snmplabs.com/pyasn1/license.html -# -import os -import sys - -classifiers = """\ -Development Status :: 5 - Production/Stable -Environment :: Console -Intended Audience :: Developers -Intended Audience :: Education -Intended Audience :: Information Technology -Intended Audience :: System Administrators -Intended Audience :: Telecommunications Industry -License :: OSI Approved :: BSD License -Natural Language :: English -Operating System :: OS Independent -Programming Language :: Python :: 2 -Programming Language :: Python :: 2.4 -Programming Language :: Python :: 2.5 -Programming Language :: Python :: 2.6 -Programming Language :: Python :: 2.7 -Programming Language :: Python :: 3 -Programming Language :: Python :: 3.2 -Programming Language :: Python :: 3.3 -Programming Language :: Python :: 3.4 -Programming Language :: Python :: 3.5 -Programming Language :: Python :: 3.6 -Programming Language :: Python :: 3.7 -Topic :: Communications -Topic :: Software Development :: Libraries :: Python Modules -""" - - -def howto_install_setuptools(): - print(""" - Error: You need setuptools Python package! - - It's very easy to install it, just type: - - wget https://bootstrap.pypa.io/ez_setup.py - python ez_setup.py - - Then you could make eggs from this package. -""") - - -if sys.version_info[:2] < (2, 4): - print("ERROR: this package requires Python 2.4 or later!") - sys.exit(1) - -try: - from setuptools import setup, Command - - params = { - 'zip_safe': True - } - -except ImportError: - for arg in sys.argv: - if 'egg' in arg: - howto_install_setuptools() - sys.exit(1) - from distutils.core import setup, Command - - params = {} - -params.update({ - 'name': 'pyasn1', - 'version': open(os.path.join('pyasn1', '__init__.py')).read().split('\'')[1], - 'description': 'ASN.1 types and codecs', - 'long_description': 'Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)', - 'maintainer': 'Ilya Etingof ', - 'author': 'Ilya Etingof', - 'author_email': 'etingof@gmail.com', - 'url': 'https://github.com/etingof/pyasn1', - 'platforms': ['any'], - 'classifiers': [x for x in classifiers.split('\n') if x], - 'license': 'BSD', - 'packages': ['pyasn1', - 'pyasn1.type', - 'pyasn1.compat', - 'pyasn1.codec', - 'pyasn1.codec.ber', - 'pyasn1.codec.cer', - 'pyasn1.codec.der', - 'pyasn1.codec.native']}) - -# handle unittest discovery feature -try: - import unittest2 as unittest -except ImportError: - import unittest - - -class PyTest(Command): - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - suite = unittest.TestLoader().loadTestsFromNames( - ['tests.__main__.suite'] - ) - - unittest.TextTestRunner(verbosity=2).run(suite) - -params['cmdclass'] = { - 'test': PyTest, - 'tests': PyTest, -} - -setup(**params) diff --git a/third_party/python/pytest/.coveragerc b/third_party/python/pytest/.coveragerc deleted file mode 100644 index 61ff66749dc8..000000000000 --- a/third_party/python/pytest/.coveragerc +++ /dev/null @@ -1,4 +0,0 @@ -[run] -omit = - # standlonetemplate is read dynamically and tested by test_genscript - *standalonetemplate.py diff --git a/third_party/python/pytest/.gitattributes b/third_party/python/pytest/.gitattributes deleted file mode 100644 index 242d3da0d74b..000000000000 --- a/third_party/python/pytest/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -CHANGELOG merge=union diff --git a/third_party/python/pytest/.github/ISSUE_TEMPLATE.md b/third_party/python/pytest/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index fbcbb16fc351..000000000000 --- a/third_party/python/pytest/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,8 +0,0 @@ -Thanks for submitting an issue! - -Here's a quick checklist in what to include: - -- [ ] Include a detailed description of the bug or suggestion -- [ ] `pip list` of the virtual environment you are using -- [ ] pytest and operating system versions -- [ ] Minimal example if possible diff --git a/third_party/python/pytest/.github/PULL_REQUEST_TEMPLATE.md b/third_party/python/pytest/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 23a9f8c56832..000000000000 --- a/third_party/python/pytest/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ -Thanks for submitting a PR, your contribution is really appreciated! - -Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is -just a guideline): - -- [ ] Create a new changelog file in the `changelog` folder, with a name like `..rst`. See [changelog/README.rst](/changelog/README.rst) for details. -- [ ] Target the `master` branch for bug fixes, documentation updates and trivial changes. -- [ ] Target the `features` branch for new features and removals/deprecations. -- [ ] Include documentation when adding new features. -- [ ] Include new tests or update existing tests when applicable. - -Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please: - -- [ ] Add yourself to `AUTHORS` in alphabetical order; diff --git a/third_party/python/pytest/.gitignore b/third_party/python/pytest/.gitignore deleted file mode 100644 index afb6bf9fd3f9..000000000000 --- a/third_party/python/pytest/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -# Automatically generated by `hgimportsvn` -.svn -.hgsvn - -# Ignore local virtualenvs -lib/ -bin/ -include/ -.Python/ - -# These lines are suggested according to the svn:ignore property -# Feel free to enable them by uncommenting them -*.pyc -*.pyo -*.swp -*.class -*.orig -*~ -.hypothesis/ - -# autogenerated -src/_pytest/_version.py -# setuptools -.eggs/ - -doc/*/_build -build/ -dist/ -*.egg-info -issue/ -env/ -.env/ -3rdparty/ -.tox -.cache -.pytest_cache -.coverage -.ropeproject -.idea -.hypothesis diff --git a/third_party/python/pytest/.pre-commit-config.yaml b/third_party/python/pytest/.pre-commit-config.yaml deleted file mode 100644 index e50891bbc1cb..000000000000 --- a/third_party/python/pytest/.pre-commit-config.yaml +++ /dev/null @@ -1,36 +0,0 @@ -exclude: doc/en/example/py2py3/test_py2.py -repos: -- repo: https://github.com/ambv/black - rev: 18.4a4 - hooks: - - id: black - args: [--safe, --quiet] - language_version: python3.6 -- repo: https://github.com/asottile/blacken-docs - rev: v0.1.1 - hooks: - - id: blacken-docs - additional_dependencies: [black==18.5b1] - language_version: python3.6 -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v1.2.3 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: debug-statements - exclude: _pytest/debugging.py - - id: flake8 -- repo: https://github.com/asottile/pyupgrade - rev: v1.2.0 - hooks: - - id: pyupgrade -- repo: local - hooks: - - id: rst - name: rst - entry: rst-lint --encoding utf-8 - files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|changelog/.*)$ - language: python - additional_dependencies: [pygments, restructuredtext_lint] - python_version: python3.6 diff --git a/third_party/python/pytest/.travis.yml b/third_party/python/pytest/.travis.yml deleted file mode 100644 index 1d092149b5d5..000000000000 --- a/third_party/python/pytest/.travis.yml +++ /dev/null @@ -1,83 +0,0 @@ -sudo: false -language: python -stages: -- linting -- test -- deploy -python: - - '3.6' -install: - - pip install --upgrade --pre tox -env: - matrix: - # coveralls is not listed in tox's envlist, but should run in travis - - TOXENV=coveralls - # note: please use "tox --listenvs" to populate the build matrix below - # please remove the linting env in all cases - - TOXENV=py27 - - TOXENV=py34 - - TOXENV=py36 - - TOXENV=py27-pexpect - - TOXENV=py27-xdist - - TOXENV=py27-trial - - TOXENV=py27-numpy - - TOXENV=py27-pluggymaster - - TOXENV=py36-pexpect - - TOXENV=py36-xdist - - TOXENV=py36-trial - - TOXENV=py36-numpy - - TOXENV=py36-pluggymaster - - TOXENV=py27-nobyte - - TOXENV=doctesting - - TOXENV=docs - -jobs: - include: - - env: TOXENV=pypy - python: 'pypy-5.4' - - env: TOXENV=py35 - python: '3.5' - - env: TOXENV=py35-freeze - python: '3.5' - - env: TOXENV=py37 - python: 'nightly' - - - stage: deploy - python: '3.6' - env: - install: pip install -U setuptools setuptools_scm - script: skip - deploy: - provider: pypi - user: nicoddemus - distributions: sdist bdist_wheel - skip_upload_docs: true - password: - secure: xanTgTUu6XDQVqB/0bwJQXoDMnU5tkwZc5koz6mBkkqZhKdNOi2CLoC1XhiSZ+ah24l4V1E0GAqY5kBBcy9d7NVe4WNg4tD095LsHw+CRU6/HCVIFfyk2IZ+FPAlguesCcUiJSXOrlBF+Wj68wEvLoK7EoRFbJeiZ/f91Ww1sbtDlqXABWGHrmhPJL5Wva7o7+wG7JwJowqdZg1pbQExsCc7b53w4v2RBu3D6TJaTAzHiVsW+nUSI67vKI/uf+cR/OixsTfy37wlHgSwihYmrYLFls3V0bSpahCim3bCgMaFZx8S8xrdgJ++PzBCof2HeflFKvW+VCkoYzGEG4NrTWJoNz6ni4red9GdvfjGH3YCjAKS56h9x58zp2E5rpsb/kVq5/45xzV+dq6JRuhQ1nJWjBC6fSKAc/bfwnuFK3EBxNLkvBssLHvsNjj5XG++cB8DdS9wVGUqjpoK4puaXUWFqy4q3S9F86HEsKNgExtieA9qNx+pCIZVs6JCXZNjr0I5eVNzqJIyggNgJG6RyravsU35t9Zd9doL5g4Y7UKmAGTn1Sz24HQ4sMQgXdm2SyD8gEK5je4tlhUvfGtDvMSlstq71kIn9nRpFnqB6MFlbYSEAZmo8dGbCquoUc++6Rum208wcVbrzzVtGlXB/Ow9AbFMYeAGA0+N/K1e59c= - on: - tags: true - repo: pytest-dev/pytest - - stage: linting - python: '3.6' - env: - install: - - pip install pre-commit - - pre-commit install-hooks - script: - - pre-commit run --all-files - -script: tox --recreate - -notifications: - irc: - channels: - - "chat.freenode.net#pytest" - on_success: change - on_failure: change - skip_join: true - email: - - pytest-commit@python.org -cache: - directories: - - $HOME/.cache/pip - - $HOME/.cache/pre-commit diff --git a/third_party/python/pytest/AUTHORS b/third_party/python/pytest/AUTHORS deleted file mode 100644 index 3edfdcf85ea6..000000000000 --- a/third_party/python/pytest/AUTHORS +++ /dev/null @@ -1,213 +0,0 @@ -Holger Krekel, holger at merlinux eu -merlinux GmbH, Germany, office at merlinux eu - -Contributors include:: - -Aaron Coleman -Abdeali JK -Abhijeet Kasurde -Ahn Ki-Wook -Alan Velasco -Alexander Johnson -Alexei Kozlenok -Anatoly Bubenkoff -Anders Hovmöller -Andras Tim -Andreas Zeidler -Andrzej Ostrowski -Andy Freeland -Anthon van der Neut -Anthony Shaw -Anthony Sottile -Antony Lee -Armin Rigo -Aron Coyle -Aron Curzon -Aviral Verma -Aviv Palivoda -Barney Gale -Ben Webb -Benjamin Peterson -Bernard Pratz -Bob Ippolito -Brian Dorsey -Brian Maissy -Brian Okken -Brianna Laugher -Bruno Oliveira -Cal Leeming -Carl Friedrich Bolz -Carlos Jenkins -Ceridwen -Charles Cloud -Charnjit SiNGH (CCSJ) -Chris Lamb -Christian Boelsen -Christian Theunert -Christian Tismer -Christopher Gilling -Cyrus Maden -Daniel Grana -Daniel Hahler -Daniel Nuri -Daniel Wandschneider -Danielle Jenkins -Dave Hunt -David Díaz-Barquero -David Mohr -David Vierra -Daw-Ran Liou -Denis Kirisov -Diego Russo -Dmitry Dygalo -Dmitry Pribysh -Duncan Betts -Edison Gustavo Muenz -Edoardo Batini -Eduardo Schettino -Eli Boyarski -Elizaveta Shashkova -Endre Galaczi -Eric Hunsberger -Eric Siegerman -Erik M. Bray -Feng Ma -Florian Bruhin -Floris Bruynooghe -Gabriel Reis -George Kussumoto -Georgy Dyuldin -Graham Horler -Greg Price -Grig Gheorghiu -Grigorii Eremeev (budulianin) -Guido Wesdorp -Guoqiang Zhang -Harald Armin Massa -Henk-Jaap Wagenaar -Hugo van Kemenade -Hui Wang (coldnight) -Ian Bicking -Ian Lesperance -Jaap Broekhuizen -Jan Balster -Janne Vanhala -Jason R. Coombs -Javier Domingo Cansino -Javier Romero -Jeff Rackauckas -Jeff Widman -John Eddie Ayson -John Towler -Jon Sonesen -Jonas Obrist -Jordan Guymon -Jordan Moldow -Jordan Speicher -Joshua Bronson -Jurko Gospodnetić -Justyna Janczyszyn -Kale Kundert -Katarzyna Jachim -Katerina Koukiou -Kevin Cox -Kodi B. Arfer -Kostis Anagnostopoulos -Lawrence Mitchell -Lee Kamentsky -Lev Maximov -Llandy Riveron Del Risco -Loic Esteve -Lukas Bednar -Luke Murphy -Maciek Fijalkowski -Maho -Maik Figura -Mandeep Bhutani -Manuel Krebber -Marc Schlaich -Marcin Bachry -Mark Abramowitz -Markus Unterwaditzer -Martijn Faassen -Martin Altmayer -Martin K. Scherer -Martin Prusse -Mathieu Clabaut -Matt Bachmann -Matt Duck -Matt Williams -Matthias Hafner -Maxim Filipenko -mbyt -Michael Aquilina -Michael Birtwell -Michael Droettboom -Michael Seifert -Michal Wajszczuk -Mihai Capotă -Mike Lundy -Miro Hrončok -Nathaniel Waisbrot -Ned Batchelder -Neven Mundar -Nicolas Delaby -Oleg Pidsadnyi -Oleg Sushchenko -Oliver Bestwalter -Omar Kohl -Omer Hadari -Patrick Hayes -Paweł Adamczak -Pedro Algarvio -Pieter Mulder -Piotr Banaszkiewicz -Punyashloka Biswal -Quentin Pradet -Ralf Schmitt -Ran Benita -Raphael Castaneda -Raphael Pierzina -Raquel Alegre -Ravi Chandra -Roberto Polli -Romain Dorgueil -Roman Bolshakov -Ronny Pfannschmidt -Ross Lawley -Russel Winder -Ryan Wooden -Samuel Dion-Girardeau -Samuele Pedroni -Segev Finer -Simon Gomizelj -Skylar Downes -Srinivas Reddy Thatiparthy -Stefan Farmbauer -Stefan Zimmermann -Stefano Taschini -Steffen Allner -Stephan Obermann -Tarcisio Fischer -Tareq Alayan -Ted Xiao -Thomas Grainger -Thomas Hisch -Tim Strazny -Tom Dalton -Tom Viner -Trevor Bekolay -Tyler Goodlet -Tzu-ping Chung -Vasily Kuznetsov -Victor Uriarte -Vidar T. Fauske -Vitaly Lashmanov -Vlad Dragos -William Lee -Wouter van Ackooy -Xuan Luong -Xuecong Liao -Zoltán Máté -Roland Puntaier -Allan Feldman diff --git a/third_party/python/pytest/CHANGELOG.rst b/third_party/python/pytest/CHANGELOG.rst deleted file mode 100644 index 21a090414a0d..000000000000 --- a/third_party/python/pytest/CHANGELOG.rst +++ /dev/null @@ -1,4883 +0,0 @@ -.. - You should *NOT* be adding new change log entries to this file, this - file is managed by towncrier. You *may* edit previous change logs to - fix problems like typo corrections or such. - To add a new change log entry, please see - https://pip.pypa.io/en/latest/development/#adding-a-news-entry - we named the news folder changelog - -.. towncrier release notes start - -Pytest 3.6.2 (2018-06-20) -========================= - -Bug Fixes ---------- - -- Fix regression in ``Node.add_marker`` by extracting the mark object of a - ``MarkDecorator``. (`#3555 - `_) - -- Warnings without ``location`` were reported as ``None``. This is corrected to - now report ````. (`#3563 - `_) - -- Continue to call finalizers in the stack when a finalizer in a former scope - raises an exception. (`#3569 - `_) - -- Fix encoding error with `print` statements in doctests (`#3583 - `_) - - -Improved Documentation ----------------------- - -- Add documentation for the ``--strict`` flag. (`#3549 - `_) - - -Trivial/Internal Changes ------------------------- - -- Update old quotation style to parens in fixture.rst documentation. (`#3525 - `_) - -- Improve display of hint about ``--fulltrace`` with ``KeyboardInterrupt``. - (`#3545 `_) - -- pytest's testsuite is no longer runnable through ``python setup.py test`` -- - instead invoke ``pytest`` or ``tox`` directly. (`#3552 - `_) - -- Fix typo in documentation (`#3567 - `_) - - -Pytest 3.6.1 (2018-06-05) -========================= - -Bug Fixes ---------- - -- Fixed a bug where stdout and stderr were logged twice by junitxml when a test - was marked xfail. (`#3491 - `_) - -- Fix ``usefixtures`` mark applyed to unittest tests by correctly instantiating - ``FixtureInfo``. (`#3498 - `_) - -- Fix assertion rewriter compatibility with libraries that monkey patch - ``file`` objects. (`#3503 - `_) - - -Improved Documentation ----------------------- - -- Added a section on how to use fixtures as factories to the fixture - documentation. (`#3461 `_) - - -Trivial/Internal Changes ------------------------- - -- Enable caching for pip/pre-commit in order to reduce build time on - travis/appveyor. (`#3502 - `_) - -- Switch pytest to the src/ layout as we already suggested it for good practice - - now we implement it as well. (`#3513 - `_) - -- Fix if in tests to support 3.7.0b5, where a docstring handling in AST got - reverted. (`#3530 `_) - -- Remove some python2.5 compatibility code. (`#3529 - `_) - - -Pytest 3.6.0 (2018-05-23) -========================= - -Features --------- - -- Revamp the internals of the ``pytest.mark`` implementation with correct per - node handling which fixes a number of long standing bugs caused by the old - design. This introduces new ``Node.iter_markers(name)`` and - ``Node.get_closest_mark(name)`` APIs. Users are **strongly encouraged** to - read the `reasons for the revamp in the docs - `_, - or jump over to details about `updating existing code to use the new APIs - `_. (`#3317 - `_) - -- Now when ``@pytest.fixture`` is applied more than once to the same function a - ``ValueError`` is raised. This buggy behavior would cause surprising problems - and if was working for a test suite it was mostly by accident. (`#2334 - `_) - -- Support for Python 3.7's builtin ``breakpoint()`` method, see `Using the - builtin breakpoint function - `_ for - details. (`#3180 `_) - -- ``monkeypatch`` now supports a ``context()`` function which acts as a context - manager which undoes all patching done within the ``with`` block. (`#3290 - `_) - -- The ``--pdb`` option now causes KeyboardInterrupt to enter the debugger, - instead of stopping the test session. On python 2.7, hitting CTRL+C again - exits the debugger. On python 3.2 and higher, use CTRL+D. (`#3299 - `_) - -- pytest not longer changes the log level of the root logger when the - ``log-level`` parameter has greater numeric value than that of the level of - the root logger, which makes it play better with custom logging configuration - in user code. (`#3307 `_) - - -Bug Fixes ---------- - -- A rare race-condition which might result in corrupted ``.pyc`` files on - Windows has been hopefully solved. (`#3008 - `_) - -- Also use iter_marker for discovering the marks applying for marker - expressions from the cli to avoid the bad data from the legacy mark storage. - (`#3441 `_) - -- When showing diffs of failed assertions where the contents contain only - whitespace, escape them using ``repr()`` first to make it easy to spot the - differences. (`#3443 `_) - - -Improved Documentation ----------------------- - -- Change documentation copyright year to a range which auto-updates itself each - time it is published. (`#3303 - `_) - - -Trivial/Internal Changes ------------------------- - -- ``pytest`` now depends on the `python-atomicwrites - `_ library. (`#3008 - `_) - -- Update all pypi.python.org URLs to pypi.org. (`#3431 - `_) - -- Detect `pytest_` prefixed hooks using the internal plugin manager since - ``pluggy`` is deprecating the ``implprefix`` argument to ``PluginManager``. - (`#3487 `_) - -- Import ``Mapping`` and ``Sequence`` from ``_pytest.compat`` instead of - directly from ``collections`` in ``python_api.py::approx``. Add ``Mapping`` - to ``_pytest.compat``, import it from ``collections`` on python 2, but from - ``collections.abc`` on Python 3 to avoid a ``DeprecationWarning`` on Python - 3.7 or newer. (`#3497 `_) - - -Pytest 3.5.1 (2018-04-23) -========================= - - -Bug Fixes ---------- - -- Reset ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback`` before - each test executes. Those attributes are added by pytest during the test run - to aid debugging, but were never reset so they would create a leaking - reference to the last failing test's frame which in turn could never be - reclaimed by the garbage collector. (`#2798 - `_) - -- ``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword - argument. (`#3348 `_) - -- ``pytest.raises`` now works with exception classes that look like iterables. - (`#3372 `_) - - -Improved Documentation ----------------------- - -- Fix typo in ``caplog`` fixture documentation, which incorrectly identified - certain attributes as methods. (`#3406 - `_) - - -Trivial/Internal Changes ------------------------- - -- Added a more indicative error message when parametrizing a function whose - argument takes a default value. (`#3221 - `_) - -- Remove internal ``_pytest.terminal.flatten`` function in favor of - ``more_itertools.collapse``. (`#3330 - `_) - -- Import some modules from ``collections.abc`` instead of ``collections`` as - the former modules trigger ``DeprecationWarning`` in Python 3.7. (`#3339 - `_) - -- record_property is no longer experimental, removing the warnings was - forgotten. (`#3360 `_) - -- Mention in documentation and CLI help that fixtures with leading ``_`` are - printed by ``pytest --fixtures`` only if the ``-v`` option is added. (`#3398 - `_) - - -Pytest 3.5.0 (2018-03-21) -========================= - -Deprecations and Removals -------------------------- - -- ``record_xml_property`` fixture is now deprecated in favor of the more - generic ``record_property``. (`#2770 - `_) - -- Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py - files, because they "leak" to the entire directory tree. (`#3084 - `_) - - -Features --------- - -- New ``--show-capture`` command-line option that allows to specify how to - display captured output when tests fail: ``no``, ``stdout``, ``stderr``, - ``log`` or ``all`` (the default). (`#1478 - `_) - -- New ``--rootdir`` command-line option to override the rules for discovering - the root directory. See `customize - `_ in the documentation for - details. (`#1642 `_) - -- Fixtures are now instantiated based on their scopes, with higher-scoped - fixtures (such as ``session``) being instantiated first than lower-scoped - fixtures (such as ``function``). The relative order of fixtures of the same - scope is kept unchanged, based in their declaration order and their - dependencies. (`#2405 `_) - -- ``record_xml_property`` renamed to ``record_property`` and is now compatible - with xdist, markers and any reporter. ``record_xml_property`` name is now - deprecated. (`#2770 `_) - -- New ``--nf``, ``--new-first`` options: run new tests first followed by the - rest of the tests, in both cases tests are also sorted by the file modified - time, with more recent files coming first. (`#3034 - `_) - -- New ``--last-failed-no-failures`` command-line option that allows to specify - the behavior of the cache plugin's ```--last-failed`` feature when no tests - failed in the last run (or no cache was found): ``none`` or ``all`` (the - default). (`#3139 `_) - -- New ``--doctest-continue-on-failure`` command-line option to enable doctests - to show multiple failures for each snippet, instead of stopping at the first - failure. (`#3149 `_) - -- Captured log messages are added to the ```` tag in the generated - junit xml file if the ``junit_logging`` ini option is set to ``system-out``. - If the value of this ini option is ``system-err``, the logs are written to - ````. The default value for ``junit_logging`` is ``no``, meaning - captured logs are not written to the output file. (`#3156 - `_) - -- Allow the logging plugin to handle ``pytest_runtest_logstart`` and - ``pytest_runtest_logfinish`` hooks when live logs are enabled. (`#3189 - `_) - -- Passing `--log-cli-level` in the command-line now automatically activates - live logging. (`#3190 `_) - -- Add command line option ``--deselect`` to allow deselection of individual - tests at collection time. (`#3198 - `_) - -- Captured logs are printed before entering pdb. (`#3204 - `_) - -- Deselected item count is now shown before tests are run, e.g. ``collected X - items / Y deselected``. (`#3213 - `_) - -- The builtin module ``platform`` is now available for use in expressions in - ``pytest.mark``. (`#3236 - `_) - -- The *short test summary info* section now is displayed after tracebacks and - warnings in the terminal. (`#3255 - `_) - -- New ``--verbosity`` flag to set verbosity level explicitly. (`#3296 - `_) - -- ``pytest.approx`` now accepts comparing a numpy array with a scalar. (`#3312 - `_) - - -Bug Fixes ---------- - -- Suppress ``IOError`` when closing the temporary file used for capturing - streams in Python 2.7. (`#2370 - `_) - -- Fixed ``clear()`` method on ``caplog`` fixture which cleared ``records``, but - not the ``text`` property. (`#3297 - `_) - -- During test collection, when stdin is not allowed to be read, the - ``DontReadFromStdin`` object still allow itself to be iterable and resolved - to an iterator without crashing. (`#3314 - `_) - - -Improved Documentation ----------------------- - -- Added a `reference `_ page - to the docs. (`#1713 `_) - - -Trivial/Internal Changes ------------------------- - -- Change minimum requirement of ``attrs`` to ``17.4.0``. (`#3228 - `_) - -- Renamed example directories so all tests pass when ran from the base - directory. (`#3245 `_) - -- Internal ``mark.py`` module has been turned into a package. (`#3250 - `_) - -- ``pytest`` now depends on the `more-itertools - `_ package. (`#3265 - `_) - -- Added warning when ``[pytest]`` section is used in a ``.cfg`` file passed - with ``-c`` (`#3268 `_) - -- ``nodeids`` can now be passed explicitly to ``FSCollector`` and ``Node`` - constructors. (`#3291 `_) - -- Internal refactoring of ``FormattedExcinfo`` to use ``attrs`` facilities and - remove old support code for legacy Python versions. (`#3292 - `_) - -- Refactoring to unify how verbosity is handled internally. (`#3296 - `_) - -- Internal refactoring to better integrate with argparse. (`#3304 - `_) - -- Fix a python example when calling a fixture in doc/en/usage.rst (`#3308 - `_) - - -Pytest 3.4.2 (2018-03-04) -========================= - -Bug Fixes ---------- - -- Removed progress information when capture option is ``no``. (`#3203 - `_) - -- Refactor check of bindir from ``exists`` to ``isdir``. (`#3241 - `_) - -- Fix ``TypeError`` issue when using ``approx`` with a ``Decimal`` value. - (`#3247 `_) - -- Fix reference cycle generated when using the ``request`` fixture. (`#3249 - `_) - -- ``[tool:pytest]`` sections in ``*.cfg`` files passed by the ``-c`` option are - now properly recognized. (`#3260 - `_) - - -Improved Documentation ----------------------- - -- Add logging plugin to plugins list. (`#3209 - `_) - - -Trivial/Internal Changes ------------------------- - -- Fix minor typo in fixture.rst (`#3259 - `_) - - -Pytest 3.4.1 (2018-02-20) -========================= - -Bug Fixes ---------- - -- Move import of ``doctest.UnexpectedException`` to top-level to avoid possible - errors when using ``--pdb``. (`#1810 - `_) - -- Added printing of captured stdout/stderr before entering pdb, and improved a - test which was giving false negatives about output capturing. (`#3052 - `_) - -- Fix ordering of tests using parametrized fixtures which can lead to fixtures - being created more than necessary. (`#3161 - `_) - -- Fix bug where logging happening at hooks outside of "test run" hooks would - cause an internal error. (`#3184 - `_) - -- Detect arguments injected by ``unittest.mock.patch`` decorator correctly when - pypi ``mock.patch`` is installed and imported. (`#3206 - `_) - -- Errors shown when a ``pytest.raises()`` with ``match=`` fails are now cleaner - on what happened: When no exception was raised, the "matching '...'" part got - removed as it falsely implies that an exception was raised but it didn't - match. When a wrong exception was raised, it's now thrown (like - ``pytest.raised()`` without ``match=`` would) instead of complaining about - the unmatched text. (`#3222 - `_) - -- Fixed output capture handling in doctests on macOS. (`#985 - `_) - - -Improved Documentation ----------------------- - -- Add Sphinx parameter docs for ``match`` and ``message`` args to - ``pytest.raises``. (`#3202 - `_) - - -Trivial/Internal Changes ------------------------- - -- pytest has changed the publication procedure and is now being published to - PyPI directly from Travis. (`#3060 - `_) - -- Rename ``ParameterSet._for_parameterize()`` to ``_for_parametrize()`` in - order to comply with the naming convention. (`#3166 - `_) - -- Skip failing pdb/doctest test on mac. (`#985 - `_) - - -Pytest 3.4.0 (2018-01-30) -========================= - -Deprecations and Removals -------------------------- - -- All pytest classes now subclass ``object`` for better Python 2/3 compatibility. - This should not affect user code except in very rare edge cases. (`#2147 - `_) - - -Features --------- - -- Introduce ``empty_parameter_set_mark`` ini option to select which mark to - apply when ``@pytest.mark.parametrize`` is given an empty set of parameters. - Valid options are ``skip`` (default) and ``xfail``. Note that it is planned - to change the default to ``xfail`` in future releases as this is considered - less error prone. (`#2527 - `_) - -- **Incompatible change**: after community feedback the `logging - `_ functionality has - undergone some changes. Please consult the `logging documentation - `_ - for details. (`#3013 `_) - -- Console output falls back to "classic" mode when capturing is disabled (``-s``), - otherwise the output gets garbled to the point of being useless. (`#3038 - `_) - -- New `pytest_runtest_logfinish - `_ - hook which is called when a test item has finished executing, analogous to - `pytest_runtest_logstart - `_. - (`#3101 `_) - -- Improve performance when collecting tests using many fixtures. (`#3107 - `_) - -- New ``caplog.get_records(when)`` method which provides access to the captured - records for the ``"setup"``, ``"call"`` and ``"teardown"`` - testing stages. (`#3117 `_) - -- New fixture ``record_xml_attribute`` that allows modifying and inserting - attributes on the ```` xml node in JUnit reports. (`#3130 - `_) - -- The default cache directory has been renamed from ``.cache`` to - ``.pytest_cache`` after community feedback that the name ``.cache`` did not - make it clear that it was used by pytest. (`#3138 - `_) - -- Colorize the levelname column in the live-log output. (`#3142 - `_) - - -Bug Fixes ---------- - -- Fix hanging pexpect test on MacOS by using flush() instead of wait(). - (`#2022 `_) - -- Fix restoring Python state after in-process pytest runs with the - ``pytester`` plugin; this may break tests using multiple inprocess - pytest runs if later ones depend on earlier ones leaking global interpreter - changes. (`#3016 `_) - -- Fix skipping plugin reporting hook when test aborted before plugin setup - hook. (`#3074 `_) - -- Fix progress percentage reported when tests fail during teardown. (`#3088 - `_) - -- **Incompatible change**: ``-o/--override`` option no longer eats all the - remaining options, which can lead to surprising behavior: for example, - ``pytest -o foo=1 /path/to/test.py`` would fail because ``/path/to/test.py`` - would be considered as part of the ``-o`` command-line argument. One - consequence of this is that now multiple configuration overrides need - multiple ``-o`` flags: ``pytest -o foo=1 -o bar=2``. (`#3103 - `_) - - -Improved Documentation ----------------------- - -- Document hooks (defined with ``historic=True``) which cannot be used with - ``hookwrapper=True``. (`#2423 - `_) - -- Clarify that warning capturing doesn't change the warning filter by default. - (`#2457 `_) - -- Clarify a possible confusion when using pytest_fixture_setup with fixture - functions that return None. (`#2698 - `_) - -- Fix the wording of a sentence on doctest flags used in pytest. (`#3076 - `_) - -- Prefer ``https://*.readthedocs.io`` over ``http://*.rtfd.org`` for links in - the documentation. (`#3092 - `_) - -- Improve readability (wording, grammar) of Getting Started guide (`#3131 - `_) - -- Added note that calling pytest.main multiple times from the same process is - not recommended because of import caching. (`#3143 - `_) - - -Trivial/Internal Changes ------------------------- - -- Show a simple and easy error when keyword expressions trigger a syntax error - (for example, ``"-k foo and import"`` will show an error that you can not use - the ``import`` keyword in expressions). (`#2953 - `_) - -- Change parametrized automatic test id generation to use the ``__name__`` - attribute of functions instead of the fallback argument name plus counter. - (`#2976 `_) - -- Replace py.std with stdlib imports. (`#3067 - `_) - -- Corrected 'you' to 'your' in logging docs. (`#3129 - `_) - - -Pytest 3.3.2 (2017-12-25) -========================= - -Bug Fixes ---------- - -- pytester: ignore files used to obtain current user metadata in the fd leak - detector. (`#2784 `_) - -- Fix **memory leak** where objects returned by fixtures were never destructed - by the garbage collector. (`#2981 - `_) - -- Fix conversion of pyargs to filename to not convert symlinks on Python 2. (`#2985 - `_) - -- ``PYTEST_DONT_REWRITE`` is now checked for plugins too rather than only for - test modules. (`#2995 `_) - - -Improved Documentation ----------------------- - -- Add clarifying note about behavior of multiple parametrized arguments (`#3001 - `_) - - -Trivial/Internal Changes ------------------------- - -- Code cleanup. (`#3015 `_, - `#3021 `_) - -- Clean up code by replacing imports and references of `_ast` to `ast`. (`#3018 - `_) - - -Pytest 3.3.1 (2017-12-05) -========================= - -Bug Fixes ---------- - -- Fix issue about ``-p no:`` having no effect. (`#2920 - `_) - -- Fix regression with warnings that contained non-strings in their arguments in - Python 2. (`#2956 `_) - -- Always escape null bytes when setting ``PYTEST_CURRENT_TEST``. (`#2957 - `_) - -- Fix ``ZeroDivisionError`` when using the ``testmon`` plugin when no tests - were actually collected. (`#2971 - `_) - -- Bring back ``TerminalReporter.writer`` as an alias to - ``TerminalReporter._tw``. This alias was removed by accident in the ``3.3.0`` - release. (`#2984 `_) - -- The ``pytest-capturelog`` plugin is now also blacklisted, avoiding errors when - running pytest with it still installed. (`#3004 - `_) - - -Improved Documentation ----------------------- - -- Fix broken link to plugin ``pytest-localserver``. (`#2963 - `_) - - -Trivial/Internal Changes ------------------------- - -- Update github "bugs" link in ``CONTRIBUTING.rst`` (`#2949 - `_) - - -Pytest 3.3.0 (2017-11-23) -========================= - -Deprecations and Removals -------------------------- - -- Pytest no longer supports Python **2.6** and **3.3**. Those Python versions - are EOL for some time now and incur maintenance and compatibility costs on - the pytest core team, and following up with the rest of the community we - decided that they will no longer be supported starting on this version. Users - which still require those versions should pin pytest to ``<3.3``. (`#2812 - `_) - -- Remove internal ``_preloadplugins()`` function. This removal is part of the - ``pytest_namespace()`` hook deprecation. (`#2636 - `_) - -- Internally change ``CallSpec2`` to have a list of marks instead of a broken - mapping of keywords. This removes the keywords attribute of the internal - ``CallSpec2`` class. (`#2672 - `_) - -- Remove ParameterSet.deprecated_arg_dict - its not a public api and the lack - of the underscore was a naming error. (`#2675 - `_) - -- Remove the internal multi-typed attribute ``Node._evalskip`` and replace it - with the boolean ``Node._skipped_by_mark``. (`#2767 - `_) - -- The ``params`` list passed to ``pytest.fixture`` is now for - all effects considered immutable and frozen at the moment of the ``pytest.fixture`` - call. Previously the list could be changed before the first invocation of the fixture - allowing for a form of dynamic parametrization (for example, updated from command-line options), - but this was an unwanted implementation detail which complicated the internals and prevented - some internal cleanup. See issue `#2959 `_ - for details and a recommended workaround. - -Features --------- - -- ``pytest_fixture_post_finalizer`` hook can now receive a ``request`` - argument. (`#2124 `_) - -- Replace the old introspection code in compat.py that determines the available - arguments of fixtures with inspect.signature on Python 3 and - funcsigs.signature on Python 2. This should respect ``__signature__`` - declarations on functions. (`#2267 - `_) - -- Report tests with global ``pytestmark`` variable only once. (`#2549 - `_) - -- Now pytest displays the total progress percentage while running tests. The - previous output style can be set by configuring the ``console_output_style`` - setting to ``classic``. (`#2657 `_) - -- Match ``warns`` signature to ``raises`` by adding ``match`` keyword. (`#2708 - `_) - -- Pytest now captures and displays output from the standard ``logging`` module. - The user can control the logging level to be captured by specifying options - in ``pytest.ini``, the command line and also during individual tests using - markers. Also, a ``caplog`` fixture is available that enables users to test - the captured log during specific tests (similar to ``capsys`` for example). - For more information, please see the `logging docs - `_. This feature was - introduced by merging the popular `pytest-catchlog - `_ plugin, thanks to `Thomas Hisch - `_. Be advised that during the merging the - backward compatibility interface with the defunct ``pytest-capturelog`` has - been dropped. (`#2794 `_) - -- Add ``allow_module_level`` kwarg to ``pytest.skip()``, enabling to skip the - whole module. (`#2808 `_) - -- Allow setting ``file_or_dir``, ``-c``, and ``-o`` in PYTEST_ADDOPTS. (`#2824 - `_) - -- Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and - ``err`` can be accessed by attribute. (`#2879 - `_) - -- Add ``capfdbinary``, a version of ``capfd`` which returns bytes from - ``readouterr()``. (`#2923 - `_) - -- Add ``capsysbinary`` a version of ``capsys`` which returns bytes from - ``readouterr()``. (`#2934 - `_) - -- Implement feature to skip ``setup.py`` files when run with - ``--doctest-modules``. (`#502 - `_) - - -Bug Fixes ---------- - -- Resume output capturing after ``capsys/capfd.disabled()`` context manager. - (`#1993 `_) - -- ``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now - called for all ``conftest.py`` files. (`#2124 - `_) - -- If an exception happens while loading a plugin, pytest no longer hides the - original traceback. In Python 2 it will show the original traceback with a new - message that explains in which plugin. In Python 3 it will show 2 canonized - exceptions, the original exception while loading the plugin in addition to an - exception that pytest throws about loading a plugin. (`#2491 - `_) - -- ``capsys`` and ``capfd`` can now be used by other fixtures. (`#2709 - `_) - -- Internal ``pytester`` plugin properly encodes ``bytes`` arguments to - ``utf-8``. (`#2738 `_) - -- ``testdir`` now uses use the same method used by ``tmpdir`` to create its - temporary directory. This changes the final structure of the ``testdir`` - directory slightly, but should not affect usage in normal scenarios and - avoids a number of potential problems. (`#2751 - `_) - -- Pytest no longer complains about warnings with unicode messages being - non-ascii compatible even for ascii-compatible messages. As a result of this, - warnings with unicode messages are converted first to an ascii representation - for safety. (`#2809 `_) - -- Change return value of pytest command when ``--maxfail`` is reached from - ``2`` (interrupted) to ``1`` (failed). (`#2845 - `_) - -- Fix issue in assertion rewriting which could lead it to rewrite modules which - should not be rewritten. (`#2939 - `_) - -- Handle marks without description in ``pytest.ini``. (`#2942 - `_) - - -Trivial/Internal Changes ------------------------- - -- pytest now depends on `attrs `_ for internal - structures to ease code maintainability. (`#2641 - `_) - -- Refactored internal Python 2/3 compatibility code to use ``six``. (`#2642 - `_) - -- Stop vendoring ``pluggy`` - we're missing out on its latest changes for not - much benefit (`#2719 `_) - -- Internal refactor: simplify ascii string escaping by using the - backslashreplace error handler in newer Python 3 versions. (`#2734 - `_) - -- Remove unnecessary mark evaluator in unittest plugin (`#2767 - `_) - -- Calls to ``Metafunc.addcall`` now emit a deprecation warning. This function - is scheduled to be removed in ``pytest-4.0``. (`#2876 - `_) - -- Internal move of the parameterset extraction to a more maintainable place. - (`#2877 `_) - -- Internal refactoring to simplify scope node lookup. (`#2910 - `_) - -- Configure ``pytest`` to prevent pip from installing pytest in unsupported - Python versions. (`#2922 - `_) - - -Pytest 3.2.5 (2017-11-15) -========================= - -Bug Fixes ---------- - -- Remove ``py<1.5`` restriction from ``pytest`` as this can cause version - conflicts in some installations. (`#2926 - `_) - - -Pytest 3.2.4 (2017-11-13) -========================= - -Bug Fixes ---------- - -- Fix the bug where running with ``--pyargs`` will result in items with - empty ``parent.nodeid`` if run from a different root directory. (`#2775 - `_) - -- Fix issue with ``@pytest.parametrize`` if argnames was specified as keyword arguments. - (`#2819 `_) - -- Strip whitespace from marker names when reading them from INI config. (`#2856 - `_) - -- Show full context of doctest source in the pytest output, if the line number of - failed example in the docstring is < 9. (`#2882 - `_) - -- Match fixture paths against actual path segments in order to avoid matching folders which share a prefix. - (`#2836 `_) - -Improved Documentation ----------------------- - -- Introduce a dedicated section about conftest.py. (`#1505 - `_) - -- Explicitly mention ``xpass`` in the documentation of ``xfail``. (`#1997 - `_) - -- Append example for pytest.param in the example/parametrize document. (`#2658 - `_) - -- Clarify language of proposal for fixtures parameters (`#2893 - `_) - -- List python 3.6 in the documented supported versions in the getting started - document. (`#2903 `_) - -- Clarify the documentation of available fixture scopes. (`#538 - `_) - -- Add documentation about the ``python -m pytest`` invocation adding the - current directory to sys.path. (`#911 - `_) - - -Pytest 3.2.3 (2017-10-03) -========================= - -Bug Fixes ---------- - -- Fix crash in tab completion when no prefix is given. (`#2748 - `_) - -- The equality checking function (``__eq__``) of ``MarkDecorator`` returns - ``False`` if one object is not an instance of ``MarkDecorator``. (`#2758 - `_) - -- When running ``pytest --fixtures-per-test``: don't crash if an item has no - _fixtureinfo attribute (e.g. doctests) (`#2788 - `_) - - -Improved Documentation ----------------------- - -- In help text of ``-k`` option, add example of using ``not`` to not select - certain tests whose names match the provided expression. (`#1442 - `_) - -- Add note in ``parametrize.rst`` about calling ``metafunc.parametrize`` - multiple times. (`#1548 `_) - - -Trivial/Internal Changes ------------------------- - -- Set ``xfail_strict=True`` in pytest's own test suite to catch expected - failures as soon as they start to pass. (`#2722 - `_) - -- Fix typo in example of passing a callable to markers (in example/markers.rst) - (`#2765 `_) - - -Pytest 3.2.2 (2017-09-06) -========================= - -Bug Fixes ---------- - -- Calling the deprecated `request.getfuncargvalue()` now shows the source of - the call. (`#2681 `_) - -- Allow tests declared as ``@staticmethod`` to use fixtures. (`#2699 - `_) - -- Fixed edge-case during collection: attributes which raised ``pytest.fail`` - when accessed would abort the entire collection. (`#2707 - `_) - -- Fix ``ReprFuncArgs`` with mixed unicode and UTF-8 args. (`#2731 - `_) - - -Improved Documentation ----------------------- - -- In examples on working with custom markers, add examples demonstrating the - usage of ``pytest.mark.MARKER_NAME.with_args`` in comparison with - ``pytest.mark.MARKER_NAME.__call__`` (`#2604 - `_) - -- In one of the simple examples, use `pytest_collection_modifyitems()` to skip - tests based on a command-line option, allowing its sharing while preventing a - user error when acessing `pytest.config` before the argument parsing. (`#2653 - `_) - - -Trivial/Internal Changes ------------------------- - -- Fixed minor error in 'Good Practices/Manual Integration' code snippet. - (`#2691 `_) - -- Fixed typo in goodpractices.rst. (`#2721 - `_) - -- Improve user guidance regarding ``--resultlog`` deprecation. (`#2739 - `_) - - -Pytest 3.2.1 (2017-08-08) -========================= - -Bug Fixes ---------- - -- Fixed small terminal glitch when collecting a single test item. (`#2579 - `_) - -- Correctly consider ``/`` as the file separator to automatically mark plugin - files for rewrite on Windows. (`#2591 `_) - -- Properly escape test names when setting ``PYTEST_CURRENT_TEST`` environment - variable. (`#2644 `_) - -- Fix error on Windows and Python 3.6+ when ``sys.stdout`` has been replaced - with a stream-like object which does not implement the full ``io`` module - buffer protocol. In particular this affects ``pytest-xdist`` users on the - aforementioned platform. (`#2666 `_) - - -Improved Documentation ----------------------- - -- Explicitly document which pytest features work with ``unittest``. (`#2626 - `_) - - -Pytest 3.2.0 (2017-07-30) -========================= - -Deprecations and Removals -------------------------- - -- ``pytest.approx`` no longer supports ``>``, ``>=``, ``<`` and ``<=`` - operators to avoid surprising/inconsistent behavior. See `the approx docs - `_ for more - information. (`#2003 `_) - -- All old-style specific behavior in current classes in the pytest's API is - considered deprecated at this point and will be removed in a future release. - This affects Python 2 users only and in rare situations. (`#2147 - `_) - -- A deprecation warning is now raised when using marks for parameters - in ``pytest.mark.parametrize``. Use ``pytest.param`` to apply marks to - parameters instead. (`#2427 `_) - - -Features --------- - -- Add support for numpy arrays (and dicts) to approx. (`#1994 - `_) - -- Now test function objects have a ``pytestmark`` attribute containing a list - of marks applied directly to the test function, as opposed to marks inherited - from parent classes or modules. (`#2516 `_) - -- Collection ignores local virtualenvs by default; `--collect-in-virtualenv` - overrides this behavior. (`#2518 `_) - -- Allow class methods decorated as ``@staticmethod`` to be candidates for - collection as a test function. (Only for Python 2.7 and above. Python 2.6 - will still ignore static methods.) (`#2528 `_) - -- Introduce ``mark.with_args`` in order to allow passing functions/classes as - sole argument to marks. (`#2540 `_) - -- New ``cache_dir`` ini option: sets the directory where the contents of the - cache plugin are stored. Directory may be relative or absolute path: if relative path, then - directory is created relative to ``rootdir``, otherwise it is used as is. - Additionally path may contain environment variables which are expanded during - runtime. (`#2543 `_) - -- Introduce the ``PYTEST_CURRENT_TEST`` environment variable that is set with - the ``nodeid`` and stage (``setup``, ``call`` and ``teardown``) of the test - being currently executed. See the `documentation - `_ for more info. (`#2583 `_) - -- Introduced ``@pytest.mark.filterwarnings`` mark which allows overwriting the - warnings filter on a per test, class or module level. See the `docs - `_ for more information. (`#2598 `_) - -- ``--last-failed`` now remembers forever when a test has failed and only - forgets it if it passes again. This makes it easy to fix a test suite by - selectively running files and fixing tests incrementally. (`#2621 - `_) - -- New ``pytest_report_collectionfinish`` hook which allows plugins to add - messages to the terminal reporting after collection has been finished - successfully. (`#2622 `_) - -- Added support for `PEP-415's `_ - ``Exception.__suppress_context__``. Now if a ``raise exception from None`` is - caught by pytest, pytest will no longer chain the context in the test report. - The behavior now matches Python's traceback behavior. (`#2631 - `_) - -- Exceptions raised by ``pytest.fail``, ``pytest.skip`` and ``pytest.xfail`` - now subclass BaseException, making them harder to be caught unintentionally - by normal code. (`#580 `_) - - -Bug Fixes ---------- - -- Set ``stdin`` to a closed ``PIPE`` in ``pytester.py.Testdir.popen()`` for - avoid unwanted interactive ``pdb`` (`#2023 `_) - -- Add missing ``encoding`` attribute to ``sys.std*`` streams when using - ``capsys`` capture mode. (`#2375 `_) - -- Fix terminal color changing to black on Windows if ``colorama`` is imported - in a ``conftest.py`` file. (`#2510 `_) - -- Fix line number when reporting summary of skipped tests. (`#2548 - `_) - -- capture: ensure that EncodedFile.name is a string. (`#2555 - `_) - -- The options ``--fixtures`` and ``--fixtures-per-test`` will now keep - indentation within docstrings. (`#2574 `_) - -- doctests line numbers are now reported correctly, fixing `pytest-sugar#122 - `_. (`#2610 - `_) - -- Fix non-determinism in order of fixture collection. Adds new dependency - (ordereddict) for Python 2.6. (`#920 `_) - - -Improved Documentation ----------------------- - -- Clarify ``pytest_configure`` hook call order. (`#2539 - `_) - -- Extend documentation for testing plugin code with the ``pytester`` plugin. - (`#971 `_) - - -Trivial/Internal Changes ------------------------- - -- Update help message for ``--strict`` to make it clear it only deals with - unregistered markers, not warnings. (`#2444 `_) - -- Internal code move: move code for pytest.approx/pytest.raises to own files in - order to cut down the size of python.py (`#2489 `_) - -- Renamed the utility function ``_pytest.compat._escape_strings`` to - ``_ascii_escaped`` to better communicate the function's purpose. (`#2533 - `_) - -- Improve error message for CollectError with skip/skipif. (`#2546 - `_) - -- Emit warning about ``yield`` tests being deprecated only once per generator. - (`#2562 `_) - -- Ensure final collected line doesn't include artifacts of previous write. - (`#2571 `_) - -- Fixed all flake8 errors and warnings. (`#2581 `_) - -- Added ``fix-lint`` tox environment to run automatic pep8 fixes on the code. - (`#2582 `_) - -- Turn warnings into errors in pytest's own test suite in order to catch - regressions due to deprecations more promptly. (`#2588 - `_) - -- Show multiple issue links in CHANGELOG entries. (`#2620 - `_) - - -Pytest 3.1.3 (2017-07-03) -========================= - -Bug Fixes ---------- - -- Fix decode error in Python 2 for doctests in docstrings. (`#2434 - `_) - -- Exceptions raised during teardown by finalizers are now suppressed until all - finalizers are called, with the initial exception reraised. (`#2440 - `_) - -- Fix incorrect "collected items" report when specifying tests on the command- - line. (`#2464 `_) - -- ``deprecated_call`` in context-manager form now captures deprecation warnings - even if the same warning has already been raised. Also, ``deprecated_call`` - will always produce the same error message (previously it would produce - different messages in context-manager vs. function-call mode). (`#2469 - `_) - -- Fix issue where paths collected by pytest could have triple leading ``/`` - characters. (`#2475 `_) - -- Fix internal error when trying to detect the start of a recursive traceback. - (`#2486 `_) - - -Improved Documentation ----------------------- - -- Explicitly state for which hooks the calls stop after the first non-None - result. (`#2493 `_) - - -Trivial/Internal Changes ------------------------- - -- Create invoke tasks for updating the vendored packages. (`#2474 - `_) - -- Update copyright dates in LICENSE, README.rst and in the documentation. - (`#2499 `_) - - -Pytest 3.1.2 (2017-06-08) -========================= - -Bug Fixes ---------- - -- Required options added via ``pytest_addoption`` will no longer prevent using - --help without passing them. (#1999) - -- Respect ``python_files`` in assertion rewriting. (#2121) - -- Fix recursion error detection when frames in the traceback contain objects - that can't be compared (like ``numpy`` arrays). (#2459) - -- ``UnicodeWarning`` is issued from the internal pytest warnings plugin only - when the message contains non-ascii unicode (Python 2 only). (#2463) - -- Added a workaround for Python 3.6 ``WindowsConsoleIO`` breaking due to Pytests's - ``FDCapture``. Other code using console handles might still be affected by the - very same issue and might require further workarounds/fixes, i.e. ``colorama``. - (#2467) - - -Improved Documentation ----------------------- - -- Fix internal API links to ``pluggy`` objects. (#2331) - -- Make it clear that ``pytest.xfail`` stops test execution at the calling point - and improve overall flow of the ``skipping`` docs. (#810) - - -Pytest 3.1.1 (2017-05-30) -========================= - -Bug Fixes ---------- - -- pytest warning capture no longer overrides existing warning filters. The - previous behaviour would override all filters and caused regressions in test - suites which configure warning filters to match their needs. Note that as a - side-effect of this is that ``DeprecationWarning`` and - ``PendingDeprecationWarning`` are no longer shown by default. (#2430) - -- Fix issue with non-ascii contents in doctest text files. (#2434) - -- Fix encoding errors for unicode warnings in Python 2. (#2436) - -- ``pytest.deprecated_call`` now captures ``PendingDeprecationWarning`` in - context manager form. (#2441) - - -Improved Documentation ----------------------- - -- Addition of towncrier for changelog management. (#2390) - - -3.1.0 (2017-05-22) -================== - - -New Features ------------- - -* The ``pytest-warnings`` plugin has been integrated into the core and now ``pytest`` automatically - captures and displays warnings at the end of the test session. - - .. warning:: - - This feature may disrupt test suites which apply and treat warnings themselves, and can be - disabled in your ``pytest.ini``: - - .. code-block:: ini - - [pytest] - addopts = -p no:warnings - - See the `warnings documentation page `_ for more - information. - - Thanks `@nicoddemus`_ for the PR. - -* Added ``junit_suite_name`` ini option to specify root ```` name for JUnit XML reports (`#533`_). - -* Added an ini option ``doctest_encoding`` to specify which encoding to use for doctest files. - Thanks `@wheerd`_ for the PR (`#2101`_). - -* ``pytest.warns`` now checks for subclass relationship rather than - class equality. Thanks `@lesteve`_ for the PR (`#2166`_) - -* ``pytest.raises`` now asserts that the error message matches a text or regex - with the ``match`` keyword argument. Thanks `@Kriechi`_ for the PR. - -* ``pytest.param`` can be used to declare test parameter sets with marks and test ids. - Thanks `@RonnyPfannschmidt`_ for the PR. - - -Changes -------- - -* remove all internal uses of pytest_namespace hooks, - this is to prepare the removal of preloadconfig in pytest 4.0 - Thanks to `@RonnyPfannschmidt`_ for the PR. - -* pytest now warns when a callable ids raises in a parametrized test. Thanks `@fogo`_ for the PR. - -* It is now possible to skip test classes from being collected by setting a - ``__test__`` attribute to ``False`` in the class body (`#2007`_). Thanks - to `@syre`_ for the report and `@lwm`_ for the PR. - -* Change junitxml.py to produce reports that comply with Junitxml schema. - If the same test fails with failure in call and then errors in teardown - we split testcase element into two, one containing the error and the other - the failure. (`#2228`_) Thanks to `@kkoukiou`_ for the PR. - -* Testcase reports with a ``url`` attribute will now properly write this to junitxml. - Thanks `@fushi`_ for the PR (`#1874`_). - -* Remove common items from dict comparison output when verbosity=1. Also update - the truncation message to make it clearer that pytest truncates all - assertion messages if verbosity < 2 (`#1512`_). - Thanks `@mattduck`_ for the PR - -* ``--pdbcls`` no longer implies ``--pdb``. This makes it possible to use - ``addopts=--pdbcls=module.SomeClass`` on ``pytest.ini``. Thanks `@davidszotten`_ for - the PR (`#1952`_). - -* fix `#2013`_: turn RecordedWarning into ``namedtuple``, - to give it a comprehensible repr while preventing unwarranted modification. - -* fix `#2208`_: ensure an iteration limit for _pytest.compat.get_real_func. - Thanks `@RonnyPfannschmidt`_ for the report and PR. - -* Hooks are now verified after collection is complete, rather than right after loading installed plugins. This - makes it easy to write hooks for plugins which will be loaded during collection, for example using the - ``pytest_plugins`` special variable (`#1821`_). - Thanks `@nicoddemus`_ for the PR. - -* Modify ``pytest_make_parametrize_id()`` hook to accept ``argname`` as an - additional parameter. - Thanks `@unsignedint`_ for the PR. - -* Add ``venv`` to the default ``norecursedirs`` setting. - Thanks `@The-Compiler`_ for the PR. - -* ``PluginManager.import_plugin`` now accepts unicode plugin names in Python 2. - Thanks `@reutsharabani`_ for the PR. - -* fix `#2308`_: When using both ``--lf`` and ``--ff``, only the last failed tests are run. - Thanks `@ojii`_ for the PR. - -* Replace minor/patch level version numbers in the documentation with placeholders. - This significantly reduces change-noise as different contributors regnerate - the documentation on different platforms. - Thanks `@RonnyPfannschmidt`_ for the PR. - -* fix `#2391`_: consider pytest_plugins on all plugin modules - Thanks `@RonnyPfannschmidt`_ for the PR. - - -Bug Fixes ---------- - -* Fix ``AttributeError`` on ``sys.stdout.buffer`` / ``sys.stderr.buffer`` - while using ``capsys`` fixture in python 3. (`#1407`_). - Thanks to `@asottile`_. - -* Change capture.py's ``DontReadFromInput`` class to throw ``io.UnsupportedOperation`` errors rather - than ValueErrors in the ``fileno`` method (`#2276`_). - Thanks `@metasyn`_ and `@vlad-dragos`_ for the PR. - -* Fix exception formatting while importing modules when the exception message - contains non-ascii characters (`#2336`_). - Thanks `@fabioz`_ for the report and `@nicoddemus`_ for the PR. - -* Added documentation related to issue (`#1937`_) - Thanks `@skylarjhdownes`_ for the PR. - -* Allow collecting files with any file extension as Python modules (`#2369`_). - Thanks `@Kodiologist`_ for the PR. - -* Show the correct error message when collect "parametrize" func with wrong args (`#2383`_). - Thanks `@The-Compiler`_ for the report and `@robin0371`_ for the PR. - - -.. _@davidszotten: https://github.com/davidszotten -.. _@fabioz: https://github.com/fabioz -.. _@fogo: https://github.com/fogo -.. _@fushi: https://github.com/fushi -.. _@Kodiologist: https://github.com/Kodiologist -.. _@Kriechi: https://github.com/Kriechi -.. _@mandeep: https://github.com/mandeep -.. _@mattduck: https://github.com/mattduck -.. _@metasyn: https://github.com/metasyn -.. _@MichalTHEDUDE: https://github.com/MichalTHEDUDE -.. _@ojii: https://github.com/ojii -.. _@reutsharabani: https://github.com/reutsharabani -.. _@robin0371: https://github.com/robin0371 -.. _@skylarjhdownes: https://github.com/skylarjhdownes -.. _@unsignedint: https://github.com/unsignedint -.. _@wheerd: https://github.com/wheerd - - -.. _#1407: https://github.com/pytest-dev/pytest/issues/1407 -.. _#1512: https://github.com/pytest-dev/pytest/issues/1512 -.. _#1821: https://github.com/pytest-dev/pytest/issues/1821 -.. _#1874: https://github.com/pytest-dev/pytest/pull/1874 -.. _#1937: https://github.com/pytest-dev/pytest/issues/1937 -.. _#1952: https://github.com/pytest-dev/pytest/pull/1952 -.. _#2007: https://github.com/pytest-dev/pytest/issues/2007 -.. _#2013: https://github.com/pytest-dev/pytest/issues/2013 -.. _#2101: https://github.com/pytest-dev/pytest/pull/2101 -.. _#2166: https://github.com/pytest-dev/pytest/pull/2166 -.. _#2208: https://github.com/pytest-dev/pytest/issues/2208 -.. _#2228: https://github.com/pytest-dev/pytest/issues/2228 -.. _#2276: https://github.com/pytest-dev/pytest/issues/2276 -.. _#2308: https://github.com/pytest-dev/pytest/issues/2308 -.. _#2336: https://github.com/pytest-dev/pytest/issues/2336 -.. _#2369: https://github.com/pytest-dev/pytest/issues/2369 -.. _#2383: https://github.com/pytest-dev/pytest/issues/2383 -.. _#2391: https://github.com/pytest-dev/pytest/issues/2391 -.. _#533: https://github.com/pytest-dev/pytest/issues/533 - - - -3.0.7 (2017-03-14) -================== - - -* Fix issue in assertion rewriting breaking due to modules silently discarding - other modules when importing fails - Notably, importing the ``anydbm`` module is fixed. (`#2248`_). - Thanks `@pfhayes`_ for the PR. - -* junitxml: Fix problematic case where system-out tag occurred twice per testcase - element in the XML report. Thanks `@kkoukiou`_ for the PR. - -* Fix regression, pytest now skips unittest correctly if run with ``--pdb`` - (`#2137`_). Thanks to `@gst`_ for the report and `@mbyt`_ for the PR. - -* Ignore exceptions raised from descriptors (e.g. properties) during Python test collection (`#2234`_). - Thanks to `@bluetech`_. - -* ``--override-ini`` now correctly overrides some fundamental options like ``python_files`` (`#2238`_). - Thanks `@sirex`_ for the report and `@nicoddemus`_ for the PR. - -* Replace ``raise StopIteration`` usages in the code by simple ``returns`` to finish generators, in accordance to `PEP-479`_ (`#2160`_). - Thanks `@tgoodlet`_ for the report and `@nicoddemus`_ for the PR. - -* Fix internal errors when an unprintable ``AssertionError`` is raised inside a test. - Thanks `@omerhadari`_ for the PR. - -* Skipping plugin now also works with test items generated by custom collectors (`#2231`_). - Thanks to `@vidartf`_. - -* Fix trailing whitespace in console output if no .ini file presented (`#2281`_). Thanks `@fbjorn`_ for the PR. - -* Conditionless ``xfail`` markers no longer rely on the underlying test item - being an instance of ``PyobjMixin``, and can therefore apply to tests not - collected by the built-in python test collector. Thanks `@barneygale`_ for the - PR. - - -.. _@pfhayes: https://github.com/pfhayes -.. _@bluetech: https://github.com/bluetech -.. _@gst: https://github.com/gst -.. _@sirex: https://github.com/sirex -.. _@vidartf: https://github.com/vidartf -.. _@kkoukiou: https://github.com/KKoukiou -.. _@omerhadari: https://github.com/omerhadari -.. _@fbjorn: https://github.com/fbjorn - -.. _#2248: https://github.com/pytest-dev/pytest/issues/2248 -.. _#2137: https://github.com/pytest-dev/pytest/issues/2137 -.. _#2160: https://github.com/pytest-dev/pytest/issues/2160 -.. _#2231: https://github.com/pytest-dev/pytest/issues/2231 -.. _#2234: https://github.com/pytest-dev/pytest/issues/2234 -.. _#2238: https://github.com/pytest-dev/pytest/issues/2238 -.. _#2281: https://github.com/pytest-dev/pytest/issues/2281 - -.. _PEP-479: https://www.python.org/dev/peps/pep-0479/ - - -3.0.6 (2017-01-22) -================== - -* pytest no longer generates ``PendingDeprecationWarning`` from its own operations, which was introduced by mistake in version ``3.0.5`` (`#2118`_). - Thanks to `@nicoddemus`_ for the report and `@RonnyPfannschmidt`_ for the PR. - - -* pytest no longer recognizes coroutine functions as yield tests (`#2129`_). - Thanks to `@malinoff`_ for the PR. - -* Plugins loaded by the ``PYTEST_PLUGINS`` environment variable are now automatically - considered for assertion rewriting (`#2185`_). - Thanks `@nicoddemus`_ for the PR. - -* Improve error message when pytest.warns fails (`#2150`_). The type(s) of the - expected warnings and the list of caught warnings is added to the - error message. Thanks `@lesteve`_ for the PR. - -* Fix ``pytester`` internal plugin to work correctly with latest versions of - ``zope.interface`` (`#1989`_). Thanks `@nicoddemus`_ for the PR. - -* Assert statements of the ``pytester`` plugin again benefit from assertion rewriting (`#1920`_). - Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. - -* Specifying tests with colons like ``test_foo.py::test_bar`` for tests in - subdirectories with ini configuration files now uses the correct ini file - (`#2148`_). Thanks `@pelme`_. - -* Fail ``testdir.runpytest().assert_outcomes()`` explicitly if the pytest - terminal output it relies on is missing. Thanks to `@eli-b`_ for the PR. - - -.. _@barneygale: https://github.com/barneygale -.. _@lesteve: https://github.com/lesteve -.. _@malinoff: https://github.com/malinoff -.. _@pelme: https://github.com/pelme -.. _@eli-b: https://github.com/eli-b - -.. _#2118: https://github.com/pytest-dev/pytest/issues/2118 - -.. _#1989: https://github.com/pytest-dev/pytest/issues/1989 -.. _#1920: https://github.com/pytest-dev/pytest/issues/1920 -.. _#2129: https://github.com/pytest-dev/pytest/issues/2129 -.. _#2148: https://github.com/pytest-dev/pytest/issues/2148 -.. _#2150: https://github.com/pytest-dev/pytest/issues/2150 -.. _#2185: https://github.com/pytest-dev/pytest/issues/2185 - - -3.0.5 (2016-12-05) -================== - -* Add warning when not passing ``option=value`` correctly to ``-o/--override-ini`` (`#2105`_). - Also improved the help documentation. Thanks to `@mbukatov`_ for the report and - `@lwm`_ for the PR. - -* Now ``--confcutdir`` and ``--junit-xml`` are properly validated if they are directories - and filenames, respectively (`#2089`_ and `#2078`_). Thanks to `@lwm`_ for the PR. - -* Add hint to error message hinting possible missing ``__init__.py`` (`#478`_). Thanks `@DuncanBetts`_. - -* More accurately describe when fixture finalization occurs in documentation (`#687`_). Thanks `@DuncanBetts`_. - -* Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing. - Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR. - -* In Python 2, use a simple ``+-`` ASCII string in the string representation of ``pytest.approx`` (for example ``"4 +- 4.0e-06"``) - because it is brittle to handle that in different contexts and representations internally in pytest - which can result in bugs such as `#2111`_. In Python 3, the representation still uses ``±`` (for example ``4 ± 4.0e-06``). - Thanks `@kerrick-lyft`_ for the report and `@nicoddemus`_ for the PR. - -* Using ``item.Function``, ``item.Module``, etc., is now issuing deprecation warnings, prefer - ``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_). - Thanks `@nmundar`_ for the PR. - -* Fix error message using ``approx`` with complex numbers (`#2082`_). - Thanks `@adler-j`_ for the report and `@nicoddemus`_ for the PR. - -* Fixed false-positives warnings from assertion rewrite hook for modules imported more than - once by the ``pytest_plugins`` mechanism. - Thanks `@nicoddemus`_ for the PR. - -* Remove an internal cache which could cause hooks from ``conftest.py`` files in - sub-directories to be called in other directories incorrectly (`#2016`_). - Thanks `@d-b-w`_ for the report and `@nicoddemus`_ for the PR. - -* Remove internal code meant to support earlier Python 3 versions that produced the side effect - of leaving ``None`` in ``sys.modules`` when expressions were evaluated by pytest (for example passing a condition - as a string to ``pytest.mark.skipif``)(`#2103`_). - Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR. - -* Cope gracefully with a .pyc file with no matching .py file (`#2038`_). Thanks - `@nedbat`_. - -.. _@syre: https://github.com/syre -.. _@adler-j: https://github.com/adler-j -.. _@d-b-w: https://bitbucket.org/d-b-w/ -.. _@DuncanBetts: https://github.com/DuncanBetts -.. _@dupuy: https://bitbucket.org/dupuy/ -.. _@kerrick-lyft: https://github.com/kerrick-lyft -.. _@lwm: https://github.com/lwm -.. _@mbukatov: https://github.com/mbukatov -.. _@nedbat: https://github.com/nedbat -.. _@nmundar: https://github.com/nmundar - -.. _#2016: https://github.com/pytest-dev/pytest/issues/2016 -.. _#2034: https://github.com/pytest-dev/pytest/issues/2034 -.. _#2038: https://github.com/pytest-dev/pytest/issues/2038 -.. _#2078: https://github.com/pytest-dev/pytest/issues/2078 -.. _#2082: https://github.com/pytest-dev/pytest/issues/2082 -.. _#2089: https://github.com/pytest-dev/pytest/issues/2089 -.. _#2103: https://github.com/pytest-dev/pytest/issues/2103 -.. _#2105: https://github.com/pytest-dev/pytest/issues/2105 -.. _#2111: https://github.com/pytest-dev/pytest/issues/2111 -.. _#478: https://github.com/pytest-dev/pytest/issues/478 -.. _#687: https://github.com/pytest-dev/pytest/issues/687 - - -3.0.4 (2016-11-09) -================== - -* Import errors when collecting test modules now display the full traceback (`#1976`_). - Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR. - -* Fix confusing command-line help message for custom options with two or more ``metavar`` properties (`#2004`_). - Thanks `@okulynyak`_ and `@davehunt`_ for the report and `@nicoddemus`_ for the PR. - -* When loading plugins, import errors which contain non-ascii messages are now properly handled in Python 2 (`#1998`_). - Thanks `@nicoddemus`_ for the PR. - -* Fixed cyclic reference when ``pytest.raises`` is used in context-manager form (`#1965`_). Also as a - result of this fix, ``sys.exc_info()`` is left empty in both context-manager and function call usages. - Previously, ``sys.exc_info`` would contain the exception caught by the context manager, - even when the expected exception occurred. - Thanks `@MSeifert04`_ for the report and the PR. - -* Fixed false-positives warnings from assertion rewrite hook for modules that were rewritten but - were later marked explicitly by ``pytest.register_assert_rewrite`` - or implicitly as a plugin (`#2005`_). - Thanks `@RonnyPfannschmidt`_ for the report and `@nicoddemus`_ for the PR. - -* Report teardown output on test failure (`#442`_). - Thanks `@matclab`_ for the PR. - -* Fix teardown error message in generated xUnit XML. - Thanks `@gdyuldin`_ for the PR. - -* Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). - Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. - -* Clean up unittest TestCase objects after tests are complete (`#1649`_). - Thanks `@d_b_w`_ for the report and PR. - - -.. _@adborden: https://github.com/adborden -.. _@cwitty: https://github.com/cwitty -.. _@d_b_w: https://github.com/d_b_w -.. _@gdyuldin: https://github.com/gdyuldin -.. _@matclab: https://github.com/matclab -.. _@MSeifert04: https://github.com/MSeifert04 -.. _@okulynyak: https://github.com/okulynyak - -.. _#442: https://github.com/pytest-dev/pytest/issues/442 -.. _#1965: https://github.com/pytest-dev/pytest/issues/1965 -.. _#1976: https://github.com/pytest-dev/pytest/issues/1976 -.. _#1984: https://github.com/pytest-dev/pytest/issues/1984 -.. _#1998: https://github.com/pytest-dev/pytest/issues/1998 -.. _#2004: https://github.com/pytest-dev/pytest/issues/2004 -.. _#2005: https://github.com/pytest-dev/pytest/issues/2005 -.. _#1649: https://github.com/pytest-dev/pytest/issues/1649 - - -3.0.3 (2016-09-28) -================== - -* The ``ids`` argument to ``parametrize`` again accepts ``unicode`` strings - in Python 2 (`#1905`_). - Thanks `@philpep`_ for the report and `@nicoddemus`_ for the PR. - -* Assertions are now being rewritten for plugins in development mode - (``pip install -e``) (`#1934`_). - Thanks `@nicoddemus`_ for the PR. - -* Fix pkg_resources import error in Jython projects (`#1853`_). - Thanks `@raquel-ucl`_ for the PR. - -* Got rid of ``AttributeError: 'Module' object has no attribute '_obj'`` exception - in Python 3 (`#1944`_). - Thanks `@axil`_ for the PR. - -* Explain a bad scope value passed to ``@fixture`` declarations or - a ``MetaFunc.parametrize()`` call. Thanks `@tgoodlet`_ for the PR. - -* This version includes ``pluggy-0.4.0``, which correctly handles - ``VersionConflict`` errors in plugins (`#704`_). - Thanks `@nicoddemus`_ for the PR. - - -.. _@philpep: https://github.com/philpep -.. _@raquel-ucl: https://github.com/raquel-ucl -.. _@axil: https://github.com/axil -.. _@tgoodlet: https://github.com/tgoodlet -.. _@vlad-dragos: https://github.com/vlad-dragos - -.. _#1853: https://github.com/pytest-dev/pytest/issues/1853 -.. _#1905: https://github.com/pytest-dev/pytest/issues/1905 -.. _#1934: https://github.com/pytest-dev/pytest/issues/1934 -.. _#1944: https://github.com/pytest-dev/pytest/issues/1944 -.. _#704: https://github.com/pytest-dev/pytest/issues/704 - - - - -3.0.2 (2016-09-01) -================== - -* Improve error message when passing non-string ids to ``pytest.mark.parametrize`` (`#1857`_). - Thanks `@okken`_ for the report and `@nicoddemus`_ for the PR. - -* Add ``buffer`` attribute to stdin stub class ``pytest.capture.DontReadFromInput`` - Thanks `@joguSD`_ for the PR. - -* Fix ``UnicodeEncodeError`` when string comparison with unicode has failed. (`#1864`_) - Thanks `@AiOO`_ for the PR. - -* ``pytest_plugins`` is now handled correctly if defined as a string (as opposed as - a sequence of strings) when modules are considered for assertion rewriting. - Due to this bug, much more modules were being rewritten than necessary - if a test suite uses ``pytest_plugins`` to load internal plugins (`#1888`_). - Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR (`#1891`_). - -* Do not call tearDown and cleanups when running tests from - ``unittest.TestCase`` subclasses with ``--pdb`` - enabled. This allows proper post mortem debugging for all applications - which have significant logic in their tearDown machinery (`#1890`_). Thanks - `@mbyt`_ for the PR. - -* Fix use of deprecated ``getfuncargvalue`` method in the internal doctest plugin. - Thanks `@ViviCoder`_ for the report (`#1898`_). - -.. _@joguSD: https://github.com/joguSD -.. _@AiOO: https://github.com/AiOO -.. _@mbyt: https://github.com/mbyt -.. _@ViviCoder: https://github.com/ViviCoder - -.. _#1857: https://github.com/pytest-dev/pytest/issues/1857 -.. _#1864: https://github.com/pytest-dev/pytest/issues/1864 -.. _#1888: https://github.com/pytest-dev/pytest/issues/1888 -.. _#1891: https://github.com/pytest-dev/pytest/pull/1891 -.. _#1890: https://github.com/pytest-dev/pytest/issues/1890 -.. _#1898: https://github.com/pytest-dev/pytest/issues/1898 - - -3.0.1 (2016-08-23) -================== - -* Fix regression when ``importorskip`` is used at module level (`#1822`_). - Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR. - -* Fix parametrization scope when session fixtures are used in conjunction - with normal parameters in the same call (`#1832`_). - Thanks `@The-Compiler`_ for the report, `@Kingdread`_ and `@nicoddemus`_ for the PR. - -* Fix internal error when parametrizing tests or fixtures using an empty ``ids`` argument (`#1849`_). - Thanks `@OPpuolitaival`_ for the report and `@nicoddemus`_ for the PR. - -* Fix loader error when running ``pytest`` embedded in a zipfile. - Thanks `@mbachry`_ for the PR. - - -.. _@Kingdread: https://github.com/Kingdread -.. _@mbachry: https://github.com/mbachry -.. _@OPpuolitaival: https://github.com/OPpuolitaival - -.. _#1822: https://github.com/pytest-dev/pytest/issues/1822 -.. _#1832: https://github.com/pytest-dev/pytest/issues/1832 -.. _#1849: https://github.com/pytest-dev/pytest/issues/1849 - - -3.0.0 (2016-08-18) -================== - -**Incompatible changes** - - -A number of incompatible changes were made in this release, with the intent of removing features deprecated for a long -time or change existing behaviors in order to make them less surprising/more useful. - -* Reinterpretation mode has now been removed. Only plain and rewrite - mode are available, consequently the ``--assert=reinterp`` option is - no longer available. This also means files imported from plugins or - ``conftest.py`` will not benefit from improved assertions by - default, you should use ``pytest.register_assert_rewrite()`` to - explicitly turn on assertion rewriting for those files. Thanks - `@flub`_ for the PR. - -* The following deprecated commandline options were removed: - - * ``--genscript``: no longer supported; - * ``--no-assert``: use ``--assert=plain`` instead; - * ``--nomagic``: use ``--assert=plain`` instead; - * ``--report``: use ``-r`` instead; - - Thanks to `@RedBeardCode`_ for the PR (`#1664`_). - -* ImportErrors in plugins now are a fatal error instead of issuing a - pytest warning (`#1479`_). Thanks to `@The-Compiler`_ for the PR. - -* Removed support code for Python 3 versions < 3.3 (`#1627`_). - -* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points - were never documented and a leftover from a pre-virtualenv era. These entry - points also created broken entry points in wheels, so removing them also - removes a source of confusion for users (`#1632`_). - Thanks `@obestwalter`_ for the PR. - -* ``pytest.skip()`` now raises an error when used to decorate a test function, - as opposed to its original intent (to imperatively skip a test inside a test function). Previously - this usage would cause the entire module to be skipped (`#607`_). - Thanks `@omarkohl`_ for the complete PR (`#1519`_). - -* Exit tests if a collection error occurs. A poll indicated most users will hit CTRL-C - anyway as soon as they see collection errors, so pytest might as well make that the default behavior (`#1421`_). - A ``--continue-on-collection-errors`` option has been added to restore the previous behaviour. - Thanks `@olegpidsadnyi`_ and `@omarkohl`_ for the complete PR (`#1628`_). - -* Renamed the pytest ``pdb`` module (plugin) into ``debugging`` to avoid clashes with the builtin ``pdb`` module. - -* Raise a helpful failure message when requesting a parametrized fixture at runtime, - e.g. with ``request.getfixturevalue``. Previously these parameters were simply - never defined, so a fixture decorated like ``@pytest.fixture(params=[0, 1, 2])`` - only ran once (`#460`_). - Thanks to `@nikratio`_ for the bug report, `@RedBeardCode`_ and `@tomviner`_ for the PR. - -* ``_pytest.monkeypatch.monkeypatch`` class has been renamed to ``_pytest.monkeypatch.MonkeyPatch`` - so it doesn't conflict with the ``monkeypatch`` fixture. - -* ``--exitfirst / -x`` can now be overridden by a following ``--maxfail=N`` - and is just a synonym for ``--maxfail=1``. - - -**New Features** - -* Support nose-style ``__test__`` attribute on methods of classes, - including unittest-style Classes. If set to ``False``, the test will not be - collected. - -* New ``doctest_namespace`` fixture for injecting names into the - namespace in which doctests run. - Thanks `@milliams`_ for the complete PR (`#1428`_). - -* New ``--doctest-report`` option available to change the output format of diffs - when running (failing) doctests (implements `#1749`_). - Thanks `@hartym`_ for the PR. - -* New ``name`` argument to ``pytest.fixture`` decorator which allows a custom name - for a fixture (to solve the funcarg-shadowing-fixture problem). - Thanks `@novas0x2a`_ for the complete PR (`#1444`_). - -* New ``approx()`` function for easily comparing floating-point numbers in - tests. - Thanks `@kalekundert`_ for the complete PR (`#1441`_). - -* Ability to add global properties in the final xunit output file by accessing - the internal ``junitxml`` plugin (experimental). - Thanks `@tareqalayan`_ for the complete PR `#1454`_). - -* New ``ExceptionInfo.match()`` method to match a regular expression on the - string representation of an exception (`#372`_). - Thanks `@omarkohl`_ for the complete PR (`#1502`_). - -* ``__tracebackhide__`` can now also be set to a callable which then can decide - whether to filter the traceback based on the ``ExceptionInfo`` object passed - to it. Thanks `@The-Compiler`_ for the complete PR (`#1526`_). - -* New ``pytest_make_parametrize_id(config, val)`` hook which can be used by plugins to provide - friendly strings for custom types. - Thanks `@palaviv`_ for the PR. - -* ``capsys`` and ``capfd`` now have a ``disabled()`` context-manager method, which - can be used to temporarily disable capture within a test. - Thanks `@nicoddemus`_ for the PR. - -* New cli flag ``--fixtures-per-test``: shows which fixtures are being used - for each selected test item. Features doc strings of fixtures by default. - Can also show where fixtures are defined if combined with ``-v``. - Thanks `@hackebrot`_ for the PR. - -* Introduce ``pytest`` command as recommended entry point. Note that ``py.test`` - still works and is not scheduled for removal. Closes proposal - `#1629`_. Thanks `@obestwalter`_ and `@davehunt`_ for the complete PR - (`#1633`_). - -* New cli flags: - - + ``--setup-plan``: performs normal collection and reports - the potential setup and teardown and does not execute any fixtures and tests; - + ``--setup-only``: performs normal collection, executes setup and teardown of - fixtures and reports them; - + ``--setup-show``: performs normal test execution and additionally shows - setup and teardown of fixtures; - + ``--keep-duplicates``: py.test now ignores duplicated paths given in the command - line. To retain the previous behavior where the same test could be run multiple - times by specifying it in the command-line multiple times, pass the ``--keep-duplicates`` - argument (`#1609`_); - - Thanks `@d6e`_, `@kvas-it`_, `@sallner`_, `@ioggstream`_ and `@omarkohl`_ for the PRs. - -* New CLI flag ``--override-ini``/``-o``: overrides values from the ini file. - For example: ``"-o xfail_strict=True"``'. - Thanks `@blueyed`_ and `@fengxx`_ for the PR. - -* New hooks: - - + ``pytest_fixture_setup(fixturedef, request)``: executes fixture setup; - + ``pytest_fixture_post_finalizer(fixturedef)``: called after the fixture's - finalizer and has access to the fixture's result cache. - - Thanks `@d6e`_, `@sallner`_. - -* Issue warnings for asserts whose test is a tuple literal. Such asserts will - never fail because tuples are always truthy and are usually a mistake - (see `#1562`_). Thanks `@kvas-it`_, for the PR. - -* Allow passing a custom debugger class (e.g. ``--pdbcls=IPython.core.debugger:Pdb``). - Thanks to `@anntzer`_ for the PR. - - -**Changes** - -* Plugins now benefit from assertion rewriting. Thanks - `@sober7`_, `@nicoddemus`_ and `@flub`_ for the PR. - -* Change ``report.outcome`` for ``xpassed`` tests to ``"passed"`` in non-strict - mode and ``"failed"`` in strict mode. Thanks to `@hackebrot`_ for the PR - (`#1795`_) and `@gprasad84`_ for report (`#1546`_). - -* Tests marked with ``xfail(strict=False)`` (the default) now appear in - JUnitXML reports as passing tests instead of skipped. - Thanks to `@hackebrot`_ for the PR (`#1795`_). - -* Highlight path of the file location in the error report to make it easier to copy/paste. - Thanks `@suzaku`_ for the PR (`#1778`_). - -* Fixtures marked with ``@pytest.fixture`` can now use ``yield`` statements exactly like - those marked with the ``@pytest.yield_fixture`` decorator. This change renders - ``@pytest.yield_fixture`` deprecated and makes ``@pytest.fixture`` with ``yield`` statements - the preferred way to write teardown code (`#1461`_). - Thanks `@csaftoiu`_ for bringing this to attention and `@nicoddemus`_ for the PR. - -* Explicitly passed parametrize ids do not get escaped to ascii (`#1351`_). - Thanks `@ceridwen`_ for the PR. - -* Fixtures are now sorted in the error message displayed when an unknown - fixture is declared in a test function. - Thanks `@nicoddemus`_ for the PR. - -* ``pytest_terminal_summary`` hook now receives the ``exitstatus`` - of the test session as argument. Thanks `@blueyed`_ for the PR (`#1809`_). - -* Parametrize ids can accept ``None`` as specific test id, in which case the - automatically generated id for that argument will be used. - Thanks `@palaviv`_ for the complete PR (`#1468`_). - -* The parameter to xunit-style setup/teardown methods (``setup_method``, - ``setup_module``, etc.) is now optional and may be omitted. - Thanks `@okken`_ for bringing this to attention and `@nicoddemus`_ for the PR. - -* Improved automatic id generation selection in case of duplicate ids in - parametrize. - Thanks `@palaviv`_ for the complete PR (`#1474`_). - -* Now pytest warnings summary is shown up by default. Added a new flag - ``--disable-pytest-warnings`` to explicitly disable the warnings summary (`#1668`_). - -* Make ImportError during collection more explicit by reminding - the user to check the name of the test module/package(s) (`#1426`_). - Thanks `@omarkohl`_ for the complete PR (`#1520`_). - -* Add ``build/`` and ``dist/`` to the default ``--norecursedirs`` list. Thanks - `@mikofski`_ for the report and `@tomviner`_ for the PR (`#1544`_). - -* ``pytest.raises`` in the context manager form accepts a custom - ``message`` to raise when no exception occurred. - Thanks `@palaviv`_ for the complete PR (`#1616`_). - -* ``conftest.py`` files now benefit from assertion rewriting; previously it - was only available for test modules. Thanks `@flub`_, `@sober7`_ and - `@nicoddemus`_ for the PR (`#1619`_). - -* Text documents without any doctests no longer appear as "skipped". - Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_). - -* Ensure that a module within a namespace package can be found when it - is specified on the command line together with the ``--pyargs`` - option. Thanks to `@taschini`_ for the PR (`#1597`_). - -* Always include full assertion explanation during assertion rewriting. The previous behaviour was hiding - sub-expressions that happened to be ``False``, assuming this was redundant information. - Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and - `@tomviner`_ for the PR. - -* ``OptionGroup.addoption()`` now checks if option names were already - added before, to make it easier to track down issues like `#1618`_. - Before, you only got exceptions later from ``argparse`` library, - giving no clue about the actual reason for double-added options. - -* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0. - Thanks `@nicoddemus`_ for the PR. - -* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]`` - to avoid conflicts with other distutils commands (see `#567`_). ``[pytest]`` sections in - ``pytest.ini`` or ``tox.ini`` files are supported and unchanged. - Thanks `@nicoddemus`_ for the PR. - -* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be - removed in pytest-4.0 (`#1684`_). - Thanks `@nicoddemus`_ for the PR. - -* Passing a command-line string to ``pytest.main()`` is considered deprecated and scheduled - for removal in pytest-4.0. It is recommended to pass a list of arguments instead (`#1723`_). - -* Rename ``getfuncargvalue`` to ``getfixturevalue``. ``getfuncargvalue`` is - still present but is now considered deprecated. Thanks to `@RedBeardCode`_ and `@tomviner`_ - for the PR (`#1626`_). - -* ``optparse`` type usage now triggers DeprecationWarnings (`#1740`_). - - -* ``optparse`` backward compatibility supports float/complex types (`#457`_). - -* Refined logic for determining the ``rootdir``, considering only valid - paths which fixes a number of issues: `#1594`_, `#1435`_ and `#1471`_. - Updated the documentation according to current behavior. Thanks to - `@blueyed`_, `@davehunt`_ and `@matthiasha`_ for the PR. - -* Always include full assertion explanation. The previous behaviour was hiding - sub-expressions that happened to be False, assuming this was redundant information. - Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and - `@tomviner`_ for PR. - -* Better message in case of not using parametrized variable (see `#1539`_). - Thanks to `@tramwaj29`_ for the PR. - -* Updated docstrings with a more uniform style. - -* Add stderr write for ``pytest.exit(msg)`` during startup. Previously the message was never shown. - Thanks `@BeyondEvil`_ for reporting `#1210`_. Thanks to `@JonathonSonesen`_ and - `@tomviner`_ for the PR. - -* No longer display the incorrect test deselection reason (`#1372`_). - Thanks `@ronnypfannschmidt`_ for the PR. - -* The ``--resultlog`` command line option has been deprecated: it is little used - and there are more modern and better alternatives (see `#830`_). - Thanks `@nicoddemus`_ for the PR. - -* Improve error message with fixture lookup errors: add an 'E' to the first - line and '>' to the rest. Fixes `#717`_. Thanks `@blueyed`_ for reporting and - a PR, `@eolo999`_ for the initial PR and `@tomviner`_ for his guidance during - EuroPython2016 sprint. - - -**Bug Fixes** - -* Parametrize now correctly handles duplicated test ids. - -* Fix internal error issue when the ``method`` argument is missing for - ``teardown_method()`` (`#1605`_). - -* Fix exception visualization in case the current working directory (CWD) gets - deleted during testing (`#1235`_). Thanks `@bukzor`_ for reporting. PR by - `@marscher`_. - -* Improve test output for logical expression with brackets (`#925`_). - Thanks `@DRMacIver`_ for reporting and `@RedBeardCode`_ for the PR. - -* Create correct diff for strings ending with newlines (`#1553`_). - Thanks `@Vogtinator`_ for reporting and `@RedBeardCode`_ and - `@tomviner`_ for the PR. - -* ``ConftestImportFailure`` now shows the traceback making it easier to - identify bugs in ``conftest.py`` files (`#1516`_). Thanks `@txomon`_ for - the PR. - -* Text documents without any doctests no longer appear as "skipped". - Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_). - -* Fixed collection of classes with custom ``__new__`` method. - Fixes `#1579`_. Thanks to `@Stranger6667`_ for the PR. - -* Fixed scope overriding inside metafunc.parametrize (`#634`_). - Thanks to `@Stranger6667`_ for the PR. - -* Fixed the total tests tally in junit xml output (`#1798`_). - Thanks to `@cryporchild`_ for the PR. - -* Fixed off-by-one error with lines from ``request.node.warn``. - Thanks to `@blueyed`_ for the PR. - - -.. _#1210: https://github.com/pytest-dev/pytest/issues/1210 -.. _#1235: https://github.com/pytest-dev/pytest/issues/1235 -.. _#1351: https://github.com/pytest-dev/pytest/issues/1351 -.. _#1372: https://github.com/pytest-dev/pytest/issues/1372 -.. _#1421: https://github.com/pytest-dev/pytest/issues/1421 -.. _#1426: https://github.com/pytest-dev/pytest/issues/1426 -.. _#1428: https://github.com/pytest-dev/pytest/pull/1428 -.. _#1435: https://github.com/pytest-dev/pytest/issues/1435 -.. _#1441: https://github.com/pytest-dev/pytest/pull/1441 -.. _#1444: https://github.com/pytest-dev/pytest/pull/1444 -.. _#1454: https://github.com/pytest-dev/pytest/pull/1454 -.. _#1461: https://github.com/pytest-dev/pytest/pull/1461 -.. _#1468: https://github.com/pytest-dev/pytest/pull/1468 -.. _#1471: https://github.com/pytest-dev/pytest/issues/1471 -.. _#1474: https://github.com/pytest-dev/pytest/pull/1474 -.. _#1479: https://github.com/pytest-dev/pytest/issues/1479 -.. _#1502: https://github.com/pytest-dev/pytest/pull/1502 -.. _#1503: https://github.com/pytest-dev/pytest/issues/1503 -.. _#1516: https://github.com/pytest-dev/pytest/pull/1516 -.. _#1519: https://github.com/pytest-dev/pytest/pull/1519 -.. _#1520: https://github.com/pytest-dev/pytest/pull/1520 -.. _#1526: https://github.com/pytest-dev/pytest/pull/1526 -.. _#1539: https://github.com/pytest-dev/pytest/issues/1539 -.. _#1544: https://github.com/pytest-dev/pytest/issues/1544 -.. _#1546: https://github.com/pytest-dev/pytest/issues/1546 -.. _#1553: https://github.com/pytest-dev/pytest/issues/1553 -.. _#1562: https://github.com/pytest-dev/pytest/issues/1562 -.. _#1579: https://github.com/pytest-dev/pytest/issues/1579 -.. _#1580: https://github.com/pytest-dev/pytest/pull/1580 -.. _#1594: https://github.com/pytest-dev/pytest/issues/1594 -.. _#1597: https://github.com/pytest-dev/pytest/pull/1597 -.. _#1605: https://github.com/pytest-dev/pytest/issues/1605 -.. _#1616: https://github.com/pytest-dev/pytest/pull/1616 -.. _#1618: https://github.com/pytest-dev/pytest/issues/1618 -.. _#1619: https://github.com/pytest-dev/pytest/issues/1619 -.. _#1626: https://github.com/pytest-dev/pytest/pull/1626 -.. _#1627: https://github.com/pytest-dev/pytest/pull/1627 -.. _#1628: https://github.com/pytest-dev/pytest/pull/1628 -.. _#1629: https://github.com/pytest-dev/pytest/issues/1629 -.. _#1632: https://github.com/pytest-dev/pytest/issues/1632 -.. _#1633: https://github.com/pytest-dev/pytest/pull/1633 -.. _#1664: https://github.com/pytest-dev/pytest/pull/1664 -.. _#1668: https://github.com/pytest-dev/pytest/issues/1668 -.. _#1684: https://github.com/pytest-dev/pytest/pull/1684 -.. _#1723: https://github.com/pytest-dev/pytest/pull/1723 -.. _#1740: https://github.com/pytest-dev/pytest/issues/1740 -.. _#1749: https://github.com/pytest-dev/pytest/issues/1749 -.. _#1778: https://github.com/pytest-dev/pytest/pull/1778 -.. _#1795: https://github.com/pytest-dev/pytest/pull/1795 -.. _#1798: https://github.com/pytest-dev/pytest/pull/1798 -.. _#1809: https://github.com/pytest-dev/pytest/pull/1809 -.. _#372: https://github.com/pytest-dev/pytest/issues/372 -.. _#457: https://github.com/pytest-dev/pytest/issues/457 -.. _#460: https://github.com/pytest-dev/pytest/pull/460 -.. _#567: https://github.com/pytest-dev/pytest/pull/567 -.. _#607: https://github.com/pytest-dev/pytest/issues/607 -.. _#634: https://github.com/pytest-dev/pytest/issues/634 -.. _#717: https://github.com/pytest-dev/pytest/issues/717 -.. _#830: https://github.com/pytest-dev/pytest/issues/830 -.. _#925: https://github.com/pytest-dev/pytest/issues/925 - - -.. _@anntzer: https://github.com/anntzer -.. _@bagerard: https://github.com/bagerard -.. _@BeyondEvil: https://github.com/BeyondEvil -.. _@blueyed: https://github.com/blueyed -.. _@ceridwen: https://github.com/ceridwen -.. _@cryporchild: https://github.com/cryporchild -.. _@csaftoiu: https://github.com/csaftoiu -.. _@d6e: https://github.com/d6e -.. _@davehunt: https://github.com/davehunt -.. _@DRMacIver: https://github.com/DRMacIver -.. _@eolo999: https://github.com/eolo999 -.. _@fengxx: https://github.com/fengxx -.. _@flub: https://github.com/flub -.. _@gprasad84: https://github.com/gprasad84 -.. _@graingert: https://github.com/graingert -.. _@hartym: https://github.com/hartym -.. _@JonathonSonesen: https://github.com/JonathonSonesen -.. _@kalekundert: https://github.com/kalekundert -.. _@kvas-it: https://github.com/kvas-it -.. _@marscher: https://github.com/marscher -.. _@mikofski: https://github.com/mikofski -.. _@milliams: https://github.com/milliams -.. _@nikratio: https://github.com/nikratio -.. _@novas0x2a: https://github.com/novas0x2a -.. _@obestwalter: https://github.com/obestwalter -.. _@okken: https://github.com/okken -.. _@olegpidsadnyi: https://github.com/olegpidsadnyi -.. _@omarkohl: https://github.com/omarkohl -.. _@palaviv: https://github.com/palaviv -.. _@RedBeardCode: https://github.com/RedBeardCode -.. _@sallner: https://github.com/sallner -.. _@sober7: https://github.com/sober7 -.. _@Stranger6667: https://github.com/Stranger6667 -.. _@suzaku: https://github.com/suzaku -.. _@tareqalayan: https://github.com/tareqalayan -.. _@taschini: https://github.com/taschini -.. _@tramwaj29: https://github.com/tramwaj29 -.. _@txomon: https://github.com/txomon -.. _@Vogtinator: https://github.com/Vogtinator -.. _@matthiasha: https://github.com/matthiasha - - -2.9.2 (2016-05-31) -================== - -**Bug Fixes** - -* fix `#510`_: skip tests where one parameterize dimension was empty - thanks Alex Stapleton for the Report and `@RonnyPfannschmidt`_ for the PR - -* Fix Xfail does not work with condition keyword argument. - Thanks `@astraw38`_ for reporting the issue (`#1496`_) and `@tomviner`_ - for PR the (`#1524`_). - -* Fix win32 path issue when putting custom config file with absolute path - in ``pytest.main("-c your_absolute_path")``. - -* Fix maximum recursion depth detection when raised error class is not aware - of unicode/encoded bytes. - Thanks `@prusse-martin`_ for the PR (`#1506`_). - -* Fix ``pytest.mark.skip`` mark when used in strict mode. - Thanks `@pquentin`_ for the PR and `@RonnyPfannschmidt`_ for - showing how to fix the bug. - -* Minor improvements and fixes to the documentation. - Thanks `@omarkohl`_ for the PR. - -* Fix ``--fixtures`` to show all fixture definitions as opposed to just - one per fixture name. - Thanks to `@hackebrot`_ for the PR. - -.. _#510: https://github.com/pytest-dev/pytest/issues/510 -.. _#1506: https://github.com/pytest-dev/pytest/pull/1506 -.. _#1496: https://github.com/pytest-dev/pytest/issues/1496 -.. _#1524: https://github.com/pytest-dev/pytest/pull/1524 - -.. _@prusse-martin: https://github.com/prusse-martin -.. _@astraw38: https://github.com/astraw38 - - -2.9.1 (2016-03-17) -================== - -**Bug Fixes** - -* Improve error message when a plugin fails to load. - Thanks `@nicoddemus`_ for the PR. - -* Fix (`#1178 `_): - ``pytest.fail`` with non-ascii characters raises an internal pytest error. - Thanks `@nicoddemus`_ for the PR. - -* Fix (`#469`_): junit parses report.nodeid incorrectly, when params IDs - contain ``::``. Thanks `@tomviner`_ for the PR (`#1431`_). - -* Fix (`#578 `_): SyntaxErrors - containing non-ascii lines at the point of failure generated an internal - py.test error. - Thanks `@asottile`_ for the report and `@nicoddemus`_ for the PR. - -* Fix (`#1437`_): When passing in a bytestring regex pattern to parameterize - attempt to decode it as utf-8 ignoring errors. - -* Fix (`#649`_): parametrized test nodes cannot be specified to run on the command line. - -* Fix (`#138`_): better reporting for python 3.3+ chained exceptions - -.. _#1437: https://github.com/pytest-dev/pytest/issues/1437 -.. _#469: https://github.com/pytest-dev/pytest/issues/469 -.. _#1431: https://github.com/pytest-dev/pytest/pull/1431 -.. _#649: https://github.com/pytest-dev/pytest/issues/649 -.. _#138: https://github.com/pytest-dev/pytest/issues/138 - -.. _@asottile: https://github.com/asottile - - -2.9.0 (2016-02-29) -================== - -**New Features** - -* New ``pytest.mark.skip`` mark, which unconditionally skips marked tests. - Thanks `@MichaelAquilina`_ for the complete PR (`#1040`_). - -* ``--doctest-glob`` may now be passed multiple times in the command-line. - Thanks `@jab`_ and `@nicoddemus`_ for the PR. - -* New ``-rp`` and ``-rP`` reporting options give the summary and full output - of passing tests, respectively. Thanks to `@codewarrior0`_ for the PR. - -* ``pytest.mark.xfail`` now has a ``strict`` option, which makes ``XPASS`` - tests to fail the test suite (defaulting to ``False``). There's also a - ``xfail_strict`` ini option that can be used to configure it project-wise. - Thanks `@rabbbit`_ for the request and `@nicoddemus`_ for the PR (`#1355`_). - -* ``Parser.addini`` now supports options of type ``bool``. - Thanks `@nicoddemus`_ for the PR. - -* New ``ALLOW_BYTES`` doctest option. This strips ``b`` prefixes from byte strings - in doctest output (similar to ``ALLOW_UNICODE``). - Thanks `@jaraco`_ for the request and `@nicoddemus`_ for the PR (`#1287`_). - -* Give a hint on ``KeyboardInterrupt`` to use the ``--fulltrace`` option to show the errors. - Fixes `#1366`_. - Thanks to `@hpk42`_ for the report and `@RonnyPfannschmidt`_ for the PR. - -* Catch ``IndexError`` exceptions when getting exception source location. - Fixes a pytest internal error for dynamically generated code (fixtures and tests) - where source lines are fake by intention. - -**Changes** - -* **Important**: `py.code `_ has been - merged into the ``pytest`` repository as ``pytest._code``. This decision - was made because ``py.code`` had very few uses outside ``pytest`` and the - fact that it was in a different repository made it difficult to fix bugs on - its code in a timely manner. The team hopes with this to be able to better - refactor out and improve that code. - This change shouldn't affect users, but it is useful to let users aware - if they encounter any strange behavior. - - Keep in mind that the code for ``pytest._code`` is **private** and - **experimental**, so you definitely should not import it explicitly! - - Please note that the original ``py.code`` is still available in - `pylib `_. - -* ``pytest_enter_pdb`` now optionally receives the pytest config object. - Thanks `@nicoddemus`_ for the PR. - -* Removed code and documentation for Python 2.5 or lower versions, - including removal of the obsolete ``_pytest.assertion.oldinterpret`` module. - Thanks `@nicoddemus`_ for the PR (`#1226`_). - -* Comparisons now always show up in full when ``CI`` or ``BUILD_NUMBER`` is - found in the environment, even when ``-vv`` isn't used. - Thanks `@The-Compiler`_ for the PR. - -* ``--lf`` and ``--ff`` now support long names: ``--last-failed`` and - ``--failed-first`` respectively. - Thanks `@MichaelAquilina`_ for the PR. - -* Added expected exceptions to ``pytest.raises`` fail message. - -* Collection only displays progress ("collecting X items") when in a terminal. - This avoids cluttering the output when using ``--color=yes`` to obtain - colors in CI integrations systems (`#1397`_). - -**Bug Fixes** - -* The ``-s`` and ``-c`` options should now work under ``xdist``; - ``Config.fromdictargs`` now represents its input much more faithfully. - Thanks to `@bukzor`_ for the complete PR (`#680`_). - -* Fix (`#1290`_): support Python 3.5's ``@`` operator in assertion rewriting. - Thanks `@Shinkenjoe`_ for report with test case and `@tomviner`_ for the PR. - -* Fix formatting utf-8 explanation messages (`#1379`_). - Thanks `@biern`_ for the PR. - -* Fix `traceback style docs`_ to describe all of the available options - (auto/long/short/line/native/no), with ``auto`` being the default since v2.6. - Thanks `@hackebrot`_ for the PR. - -* Fix (`#1422`_): junit record_xml_property doesn't allow multiple records - with same name. - -.. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing - -.. _#1609: https://github.com/pytest-dev/pytest/issues/1609 -.. _#1422: https://github.com/pytest-dev/pytest/issues/1422 -.. _#1379: https://github.com/pytest-dev/pytest/issues/1379 -.. _#1366: https://github.com/pytest-dev/pytest/issues/1366 -.. _#1040: https://github.com/pytest-dev/pytest/pull/1040 -.. _#680: https://github.com/pytest-dev/pytest/issues/680 -.. _#1287: https://github.com/pytest-dev/pytest/pull/1287 -.. _#1226: https://github.com/pytest-dev/pytest/pull/1226 -.. _#1290: https://github.com/pytest-dev/pytest/pull/1290 -.. _#1355: https://github.com/pytest-dev/pytest/pull/1355 -.. _#1397: https://github.com/pytest-dev/pytest/issues/1397 -.. _@biern: https://github.com/biern -.. _@MichaelAquilina: https://github.com/MichaelAquilina -.. _@bukzor: https://github.com/bukzor -.. _@hpk42: https://github.com/hpk42 -.. _@nicoddemus: https://github.com/nicoddemus -.. _@jab: https://github.com/jab -.. _@codewarrior0: https://github.com/codewarrior0 -.. _@jaraco: https://github.com/jaraco -.. _@The-Compiler: https://github.com/The-Compiler -.. _@Shinkenjoe: https://github.com/Shinkenjoe -.. _@tomviner: https://github.com/tomviner -.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt -.. _@rabbbit: https://github.com/rabbbit -.. _@hackebrot: https://github.com/hackebrot -.. _@pquentin: https://github.com/pquentin -.. _@ioggstream: https://github.com/ioggstream - -2.8.7 (2016-01-24) -================== - -- fix #1338: use predictable object resolution for monkeypatch - -2.8.6 (2016-01-21) -================== - -- fix #1259: allow for double nodeids in junitxml, - this was a regression failing plugins combinations - like pytest-pep8 + pytest-flakes - -- Workaround for exception that occurs in pyreadline when using - ``--pdb`` with standard I/O capture enabled. - Thanks Erik M. Bray for the PR. - -- fix #900: Better error message in case the target of a ``monkeypatch`` call - raises an ``ImportError``. - -- fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1). - Thanks David R. MacIver for the report and Bruno Oliveira for the PR. - -- fix #1223: captured stdout and stderr are now properly displayed before - entering pdb when ``--pdb`` is used instead of being thrown away. - Thanks Cal Leeming for the PR. - -- fix #1305: pytest warnings emitted during ``pytest_terminal_summary`` are now - properly displayed. - Thanks Ionel Maries Cristian for the report and Bruno Oliveira for the PR. - -- fix #628: fixed internal UnicodeDecodeError when doctests contain unicode. - Thanks Jason R. Coombs for the report and Bruno Oliveira for the PR. - -- fix #1334: Add captured stdout to jUnit XML report on setup error. - Thanks Georgy Dyuldin for the PR. - - -2.8.5 (2015-12-11) -================== - -- fix #1243: fixed issue where class attributes injected during collection could break pytest. - PR by Alexei Kozlenok, thanks Ronny Pfannschmidt and Bruno Oliveira for the review and help. - -- fix #1074: precompute junitxml chunks instead of storing the whole tree in objects - Thanks Bruno Oliveira for the report and Ronny Pfannschmidt for the PR - -- fix #1238: fix ``pytest.deprecated_call()`` receiving multiple arguments - (Regression introduced in 2.8.4). Thanks Alex Gaynor for the report and - Bruno Oliveira for the PR. - - -2.8.4 (2015-12-06) -================== - -- fix #1190: ``deprecated_call()`` now works when the deprecated - function has been already called by another test in the same - module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the - PR. - -- fix #1198: ``--pastebin`` option now works on Python 3. Thanks - Mehdy Khoshnoody for the PR. - -- fix #1219: ``--pastebin`` now works correctly when captured output contains - non-ascii characters. Thanks Bruno Oliveira for the PR. - -- fix #1204: another error when collecting with a nasty __getattr__(). - Thanks Florian Bruhin for the PR. - -- fix the summary printed when no tests did run. - Thanks Florian Bruhin for the PR. -- fix #1185 - ensure MANIFEST.in exactly matches what should go to a sdist - -- a number of documentation modernizations wrt good practices. - Thanks Bruno Oliveira for the PR. - -2.8.3 (2015-11-18) -================== - -- fix #1169: add __name__ attribute to testcases in TestCaseFunction to - support the @unittest.skip decorator on functions and methods. - Thanks Lee Kamentsky for the PR. - -- fix #1035: collecting tests if test module level obj has __getattr__(). - Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR. - -- fix #331: don't collect tests if their failure cannot be reported correctly - e.g. they are a callable instance of a class. - -- fix #1133: fixed internal error when filtering tracebacks where one entry - belongs to a file which is no longer available. - Thanks Bruno Oliveira for the PR. - -- enhancement made to highlight in red the name of the failing tests so - they stand out in the output. - Thanks Gabriel Reis for the PR. - -- add more talks to the documentation -- extend documentation on the --ignore cli option -- use pytest-runner for setuptools integration -- minor fixes for interaction with OS X El Capitan - system integrity protection (thanks Florian) - - -2.8.2 (2015-10-07) -================== - -- fix #1085: proper handling of encoding errors when passing encoded byte - strings to pytest.parametrize in Python 2. - Thanks Themanwithoutaplan for the report and Bruno Oliveira for the PR. - -- fix #1087: handling SystemError when passing empty byte strings to - pytest.parametrize in Python 3. - Thanks Paul Kehrer for the report and Bruno Oliveira for the PR. - -- fix #995: fixed internal error when filtering tracebacks where one entry - was generated by an exec() statement. - Thanks Daniel Hahler, Ashley C Straw, Philippe Gauthier and Pavel Savchenko - for contributing and Bruno Oliveira for the PR. - -- fix #1100 and #1057: errors when using autouse fixtures and doctest modules. - Thanks Sergey B Kirpichev and Vital Kudzelka for contributing and Bruno - Oliveira for the PR. - -2.8.1 (2015-09-29) -================== - -- fix #1034: Add missing nodeid on pytest_logwarning call in - addhook. Thanks Simon Gomizelj for the PR. - -- 'deprecated_call' is now only satisfied with a DeprecationWarning or - PendingDeprecationWarning. Before 2.8.0, it accepted any warning, and 2.8.0 - made it accept only DeprecationWarning (but not PendingDeprecationWarning). - Thanks Alex Gaynor for the issue and Eric Hunsberger for the PR. - -- fix issue #1073: avoid calling __getattr__ on potential plugin objects. - This fixes an incompatibility with pytest-django. Thanks Andreas Pelme, - Bruno Oliveira and Ronny Pfannschmidt for contributing and Holger Krekel - for the fix. - -- Fix issue #704: handle versionconflict during plugin loading more - gracefully. Thanks Bruno Oliveira for the PR. - -- Fix issue #1064: ""--junitxml" regression when used with the - "pytest-xdist" plugin, with test reports being assigned to the wrong tests. - Thanks Daniel Grunwald for the report and Bruno Oliveira for the PR. - -- (experimental) adapt more SEMVER style versioning and change meaning of - master branch in git repo: "master" branch now keeps the bugfixes, changes - aimed for micro releases. "features" branch will only be released - with minor or major pytest releases. - -- Fix issue #766 by removing documentation references to distutils. - Thanks Russel Winder. - -- Fix issue #1030: now byte-strings are escaped to produce item node ids - to make them always serializable. - Thanks Andy Freeland for the report and Bruno Oliveira for the PR. - -- Python 2: if unicode parametrized values are convertible to ascii, their - ascii representation is used for the node id. - -- Fix issue #411: Add __eq__ method to assertion comparison example. - Thanks Ben Webb. -- Fix issue #653: deprecated_call can be used as context manager. - -- fix issue 877: properly handle assertion explanations with non-ascii repr - Thanks Mathieu Agopian for the report and Ronny Pfannschmidt for the PR. - -- fix issue 1029: transform errors when writing cache values into pytest-warnings - -2.8.0 (2015-09-18) -================== - -- new ``--lf`` and ``-ff`` options to run only the last failing tests or - "failing tests first" from the last run. This functionality is provided - through porting the formerly external pytest-cache plugin into pytest core. - BACKWARD INCOMPAT: if you used pytest-cache's functionality to persist - data between test runs be aware that we don't serialize sets anymore. - Thanks Ronny Pfannschmidt for most of the merging work. - -- "-r" option now accepts "a" to include all possible reports, similar - to passing "fEsxXw" explicitly (isse960). - Thanks Abhijeet Kasurde for the PR. - -- avoid python3.5 deprecation warnings by introducing version - specific inspection helpers, thanks Michael Droettboom. - -- fix issue562: @nose.tools.istest now fully respected. - -- fix issue934: when string comparison fails and a diff is too large to display - without passing -vv, still show a few lines of the diff. - Thanks Florian Bruhin for the report and Bruno Oliveira for the PR. - -- fix issue736: Fix a bug where fixture params would be discarded when combined - with parametrization markers. - Thanks to Markus Unterwaditzer for the PR. - -- fix issue710: introduce ALLOW_UNICODE doctest option: when enabled, the - ``u`` prefix is stripped from unicode strings in expected doctest output. This - allows doctests which use unicode to run in Python 2 and 3 unchanged. - Thanks Jason R. Coombs for the report and Bruno Oliveira for the PR. - -- parametrize now also generates meaningful test IDs for enum, regex and class - objects (as opposed to class instances). - Thanks to Florian Bruhin for the PR. - -- Add 'warns' to assert that warnings are thrown (like 'raises'). - Thanks to Eric Hunsberger for the PR. - -- Fix issue683: Do not apply an already applied mark. Thanks ojake for the PR. - -- Deal with capturing failures better so fewer exceptions get lost to - /dev/null. Thanks David Szotten for the PR. - -- fix issue730: deprecate and warn about the --genscript option. - Thanks Ronny Pfannschmidt for the report and Christian Pommranz for the PR. - -- fix issue751: multiple parametrize with ids bug if it parametrizes class with - two or more test methods. Thanks Sergey Chipiga for reporting and Jan - Bednarik for PR. - -- fix issue82: avoid loading conftest files from setup.cfg/pytest.ini/tox.ini - files and upwards by default (--confcutdir can still be set to override this). - Thanks Bruno Oliveira for the PR. - -- fix issue768: docstrings found in python modules were not setting up session - fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR. - -- added ``tmpdir_factory``, a session-scoped fixture that can be used to create - directories under the base temporary directory. Previously this object was - installed as a ``_tmpdirhandler`` attribute of the ``config`` object, but now it - is part of the official API and using ``config._tmpdirhandler`` is - deprecated. - Thanks Bruno Oliveira for the PR. - -- fix issue808: pytest's internal assertion rewrite hook now implements the - optional PEP302 get_data API so tests can access data files next to them. - Thanks xmo-odoo for request and example and Bruno Oliveira for - the PR. - -- rootdir and inifile are now displayed during usage errors to help - users diagnose problems such as unexpected ini files which add - unknown options being picked up by pytest. Thanks to Pavel Savchenko for - bringing the problem to attention in #821 and Bruno Oliveira for the PR. - -- Summary bar now is colored yellow for warning - situations such as: all tests either were skipped or xpass/xfailed, - or no tests were run at all (this is a partial fix for issue500). - -- fix issue812: pytest now exits with status code 5 in situations where no - tests were run at all, such as the directory given in the command line does - not contain any tests or as result of a command line option filters - all out all tests (-k for example). - Thanks Eric Siegerman (issue812) and Bruno Oliveira for the PR. - -- Summary bar now is colored yellow for warning - situations such as: all tests either were skipped or xpass/xfailed, - or no tests were run at all (related to issue500). - Thanks Eric Siegerman. - -- New ``testpaths`` ini option: list of directories to search for tests - when executing pytest from the root directory. This can be used - to speed up test collection when a project has well specified directories - for tests, being usually more practical than configuring norecursedirs for - all directories that do not contain tests. - Thanks to Adrian for idea (#694) and Bruno Oliveira for the PR. - -- fix issue713: JUnit XML reports for doctest failures. - Thanks Punyashloka Biswal. - -- fix issue970: internal pytest warnings now appear as "pytest-warnings" in - the terminal instead of "warnings", so it is clear for users that those - warnings are from pytest and not from the builtin "warnings" module. - Thanks Bruno Oliveira. - -- Include setup and teardown in junitxml test durations. - Thanks Janne Vanhala. - -- fix issue735: assertion failures on debug versions of Python 3.4+ - -- new option ``--import-mode`` to allow to change test module importing - behaviour to append to sys.path instead of prepending. This better allows - to run test modules against installed versions of a package even if the - package under test has the same import root. In this example:: - - testing/__init__.py - testing/test_pkg_under_test.py - pkg_under_test/ - - the tests will run against the installed version - of pkg_under_test when ``--import-mode=append`` is used whereas - by default they would always pick up the local version. Thanks Holger Krekel. - -- pytester: add method ``TmpTestdir.delete_loaded_modules()``, and call it - from ``inline_run()`` to allow temporary modules to be reloaded. - Thanks Eduardo Schettino. - -- internally refactor pluginmanager API and code so that there - is a clear distinction between a pytest-agnostic rather simple - pluginmanager and the PytestPluginManager which adds a lot of - behaviour, among it handling of the local conftest files. - In terms of documented methods this is a backward compatible - change but it might still break 3rd party plugins which relied on - details like especially the pluginmanager.add_shutdown() API. - Thanks Holger Krekel. - -- pluginmanagement: introduce ``pytest.hookimpl`` and - ``pytest.hookspec`` decorators for setting impl/spec - specific parameters. This substitutes the previous - now deprecated use of ``pytest.mark`` which is meant to - contain markers for test functions only. - -- write/refine docs for "writing plugins" which now have their - own page and are separate from the "using/installing plugins`` page. - -- fix issue732: properly unregister plugins from any hook calling - sites allowing to have temporary plugins during test execution. - -- deprecate and warn about ``__multicall__`` argument in hook - implementations. Use the ``hookwrapper`` mechanism instead already - introduced with pytest-2.7. - -- speed up pytest's own test suite considerably by using inprocess - tests by default (testrun can be modified with --runpytest=subprocess - to create subprocesses in many places instead). The main - APIs to run pytest in a test is "runpytest()" or "runpytest_subprocess" - and "runpytest_inprocess" if you need a particular way of running - the test. In all cases you get back a RunResult but the inprocess - one will also have a "reprec" attribute with the recorded events/reports. - -- fix monkeypatch.setattr("x.y", raising=False) to actually not raise - if "y" is not a pre-existing attribute. Thanks Florian Bruhin. - -- fix issue741: make running output from testdir.run copy/pasteable - Thanks Bruno Oliveira. - -- add a new ``--noconftest`` argument which ignores all ``conftest.py`` files. - -- add ``file`` and ``line`` attributes to JUnit-XML output. - -- fix issue890: changed extension of all documentation files from ``txt`` to - ``rst``. Thanks to Abhijeet for the PR. - -- fix issue714: add ability to apply indirect=True parameter on particular argnames. - Thanks Elizaveta239. - -- fix issue890: changed extension of all documentation files from ``txt`` to - ``rst``. Thanks to Abhijeet for the PR. - -- fix issue957: "# doctest: SKIP" option will now register doctests as SKIPPED - rather than PASSED. - Thanks Thomas Grainger for the report and Bruno Oliveira for the PR. - -- issue951: add new record_xml_property fixture, that supports logging - additional information on xml output. Thanks David Diaz for the PR. - -- issue949: paths after normal options (for example ``-s``, ``-v``, etc) are now - properly used to discover ``rootdir`` and ``ini`` files. - Thanks Peter Lauri for the report and Bruno Oliveira for the PR. - -2.7.3 (2015-09-15) -================== - -- Allow 'dev', 'rc', or other non-integer version strings in ``importorskip``. - Thanks to Eric Hunsberger for the PR. - -- fix issue856: consider --color parameter in all outputs (for example - --fixtures). Thanks Barney Gale for the report and Bruno Oliveira for the PR. - -- fix issue855: passing str objects as ``plugins`` argument to pytest.main - is now interpreted as a module name to be imported and registered as a - plugin, instead of silently having no effect. - Thanks xmo-odoo for the report and Bruno Oliveira for the PR. - -- fix issue744: fix for ast.Call changes in Python 3.5+. Thanks - Guido van Rossum, Matthias Bussonnier, Stefan Zimmermann and - Thomas Kluyver. - -- fix issue842: applying markers in classes no longer propagate this markers - to superclasses which also have markers. - Thanks xmo-odoo for the report and Bruno Oliveira for the PR. - -- preserve warning functions after call to pytest.deprecated_call. Thanks - Pieter Mulder for PR. - -- fix issue854: autouse yield_fixtures defined as class members of - unittest.TestCase subclasses now work as expected. - Thannks xmo-odoo for the report and Bruno Oliveira for the PR. - -- fix issue833: --fixtures now shows all fixtures of collected test files, instead of just the - fixtures declared on the first one. - Thanks Florian Bruhin for reporting and Bruno Oliveira for the PR. - -- fix issue863: skipped tests now report the correct reason when a skip/xfail - condition is met when using multiple markers. - Thanks Raphael Pierzina for reporting and Bruno Oliveira for the PR. - -- optimized tmpdir fixture initialization, which should make test sessions - faster (specially when using pytest-xdist). The only visible effect - is that now pytest uses a subdirectory in the $TEMP directory for all - directories created by this fixture (defaults to $TEMP/pytest-$USER). - Thanks Bruno Oliveira for the PR. - -2.7.2 (2015-06-23) -================== - -- fix issue767: pytest.raises value attribute does not contain the exception - instance on Python 2.6. Thanks Eric Siegerman for providing the test - case and Bruno Oliveira for PR. - -- Automatically create directory for junitxml and results log. - Thanks Aron Curzon. - -- fix issue713: JUnit XML reports for doctest failures. - Thanks Punyashloka Biswal. - -- fix issue735: assertion failures on debug versions of Python 3.4+ - Thanks Benjamin Peterson. - -- fix issue114: skipif marker reports to internal skipping plugin; - Thanks Floris Bruynooghe for reporting and Bruno Oliveira for the PR. - -- fix issue748: unittest.SkipTest reports to internal pytest unittest plugin. - Thanks Thomas De Schampheleire for reporting and Bruno Oliveira for the PR. - -- fix issue718: failed to create representation of sets containing unsortable - elements in python 2. Thanks Edison Gustavo Muenz. - -- fix issue756, fix issue752 (and similar issues): depend on py-1.4.29 - which has a refined algorithm for traceback generation. - - -2.7.1 (2015-05-19) -================== - -- fix issue731: do not get confused by the braces which may be present - and unbalanced in an object's repr while collapsing False - explanations. Thanks Carl Meyer for the report and test case. - -- fix issue553: properly handling inspect.getsourcelines failures in - FixtureLookupError which would lead to an internal error, - obfuscating the original problem. Thanks talljosh for initial - diagnose/patch and Bruno Oliveira for final patch. - -- fix issue660: properly report scope-mismatch-access errors - independently from ordering of fixture arguments. Also - avoid the pytest internal traceback which does not provide - information to the user. Thanks Holger Krekel. - -- streamlined and documented release process. Also all versions - (in setup.py and documentation generation) are now read - from _pytest/__init__.py. Thanks Holger Krekel. - -- fixed docs to remove the notion that yield-fixtures are experimental. - They are here to stay :) Thanks Bruno Oliveira. - -- Support building wheels by using environment markers for the - requirements. Thanks Ionel Maries Cristian. - -- fixed regression to 2.6.4 which surfaced e.g. in lost stdout capture printing - when tests raised SystemExit. Thanks Holger Krekel. - -- reintroduced _pytest fixture of the pytester plugin which is used - at least by pytest-xdist. - -2.7.0 (2015-03-26) -================== - -- fix issue435: make reload() work when assert rewriting is active. - Thanks Daniel Hahler. - -- fix issue616: conftest.py files and their contained fixutres are now - properly considered for visibility, independently from the exact - current working directory and test arguments that are used. - Many thanks to Eric Siegerman and his PR235 which contains - systematic tests for conftest visibility and now passes. - This change also introduces the concept of a ``rootdir`` which - is printed as a new pytest header and documented in the pytest - customize web page. - -- change reporting of "diverted" tests, i.e. tests that are collected - in one file but actually come from another (e.g. when tests in a test class - come from a base class in a different file). We now show the nodeid - and indicate via a postfix the other file. - -- add ability to set command line options by environment variable PYTEST_ADDOPTS. - -- added documentation on the new pytest-dev teams on bitbucket and - github. See https://pytest.org/latest/contributing.html . - Thanks to Anatoly for pushing and initial work on this. - -- fix issue650: new option ``--docttest-ignore-import-errors`` which - will turn import errors in doctests into skips. Thanks Charles Cloud - for the complete PR. - -- fix issue655: work around different ways that cause python2/3 - to leak sys.exc_info into fixtures/tests causing failures in 3rd party code - -- fix issue615: assertion rewriting did not correctly escape % signs - when formatting boolean operations, which tripped over mixing - booleans with modulo operators. Thanks to Tom Viner for the report, - triaging and fix. - -- implement issue351: add ability to specify parametrize ids as a callable - to generate custom test ids. Thanks Brianna Laugher for the idea and - implementation. - -- introduce and document new hookwrapper mechanism useful for plugins - which want to wrap the execution of certain hooks for their purposes. - This supersedes the undocumented ``__multicall__`` protocol which - pytest itself and some external plugins use. Note that pytest-2.8 - is scheduled to drop supporting the old ``__multicall__`` - and only support the hookwrapper protocol. - -- majorly speed up invocation of plugin hooks - -- use hookwrapper mechanism in builtin pytest plugins. - -- add a doctest ini option for doctest flags, thanks Holger Peters. - -- add note to docs that if you want to mark a parameter and the - parameter is a callable, you also need to pass in a reason to disambiguate - it from the "decorator" case. Thanks Tom Viner. - -- "python_classes" and "python_functions" options now support glob-patterns - for test discovery, as discussed in issue600. Thanks Ldiary Translations. - -- allow to override parametrized fixtures with non-parametrized ones and vice versa (bubenkoff). - -- fix issue463: raise specific error for 'parameterize' misspelling (pfctdayelise). - -- On failure, the ``sys.last_value``, ``sys.last_type`` and - ``sys.last_traceback`` are set, so that a user can inspect the error - via postmortem debugging (almarklein). - -2.6.4 (2014-10-24) -================== - -- Improve assertion failure reporting on iterables, by using ndiff and - pprint. - -- removed outdated japanese docs from source tree. - -- docs for "pytest_addhooks" hook. Thanks Bruno Oliveira. - -- updated plugin index docs. Thanks Bruno Oliveira. - -- fix issue557: with "-k" we only allow the old style "-" for negation - at the beginning of strings and even that is deprecated. Use "not" instead. - This should allow to pick parametrized tests where "-" appeared in the parameter. - -- fix issue604: Escape % character in the assertion message. - -- fix issue620: add explanation in the --genscript target about what - the binary blob means. Thanks Dinu Gherman. - -- fix issue614: fixed pastebin support. - - -- fix issue620: add explanation in the --genscript target about what - the binary blob means. Thanks Dinu Gherman. - -- fix issue614: fixed pastebin support. - -2.6.3 (2014-09-24) -================== - -- fix issue575: xunit-xml was reporting collection errors as failures - instead of errors, thanks Oleg Sinyavskiy. - -- fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny - Pfannschmidt. - -- Fix infinite recursion bug when pickling capture.EncodedFile, thanks - Uwe Schmitt. - -- fix issue589: fix bad interaction with numpy and others when showing - exceptions. Check for precise "maximum recursion depth exceed" exception - instead of presuming any RuntimeError is that one (implemented in py - dep). Thanks Charles Cloud for analysing the issue. - -- fix conftest related fixture visibility issue: when running with a - CWD outside of a test package pytest would get fixture discovery wrong. - Thanks to Wolfgang Schnerring for figuring out a reproducible example. - -- Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the - timeout when interactively entering pdb). Thanks Wolfgang Schnerring. - -- check xfail/skip also with non-python function test items. Thanks - Floris Bruynooghe. - -2.6.2 (2014-09-05) -================== - -- Added function pytest.freeze_includes(), which makes it easy to embed - pytest into executables using tools like cx_freeze. - See docs for examples and rationale. Thanks Bruno Oliveira. - -- Improve assertion rewriting cache invalidation precision. - -- fixed issue561: adapt autouse fixture example for python3. - -- fixed issue453: assertion rewriting issue with __repr__ containing - "\n{", "\n}" and "\n~". - -- fix issue560: correctly display code if an "else:" or "finally:" is - followed by statements on the same line. - -- Fix example in monkeypatch documentation, thanks t-8ch. - -- fix issue572: correct tmpdir doc example for python3. - -- Do not mark as universal wheel because Python 2.6 is different from - other builds due to the extra argparse dependency. Fixes issue566. - Thanks sontek. - -- Implement issue549: user-provided assertion messages now no longer - replace the py.test introspection message but are shown in addition - to them. - -2.6.1 (2014-08-07) -================== - -- No longer show line numbers in the --verbose output, the output is now - purely the nodeid. The line number is still shown in failure reports. - Thanks Floris Bruynooghe. - -- fix issue437 where assertion rewriting could cause pytest-xdist slaves - to collect different tests. Thanks Bruno Oliveira. - -- fix issue555: add "errors" attribute to capture-streams to satisfy - some distutils and possibly other code accessing sys.stdout.errors. - -- fix issue547 capsys/capfd also work when output capturing ("-s") is disabled. - -- address issue170: allow pytest.mark.xfail(...) to specify expected exceptions via - an optional "raises=EXC" argument where EXC can be a single exception - or a tuple of exception classes. Thanks David Mohr for the complete - PR. - -- fix integration of pytest with unittest.mock.patch decorator when - it uses the "new" argument. Thanks Nicolas Delaby for test and PR. - -- fix issue with detecting conftest files if the arguments contain - "::" node id specifications (copy pasted from "-v" output) - -- fix issue544 by only removing "@NUM" at the end of "::" separated parts - and if the part has a ".py" extension - -- don't use py.std import helper, rather import things directly. - Thanks Bruno Oliveira. - -2.6 -=== - -- Cache exceptions from fixtures according to their scope (issue 467). - -- fix issue537: Avoid importing old assertion reinterpretation code by default. - -- fix issue364: shorten and enhance tracebacks representation by default. - The new "--tb=auto" option (default) will only display long tracebacks - for the first and last entry. You can get the old behaviour of printing - all entries as long entries with "--tb=long". Also short entries by - default are now printed very similarly to "--tb=native" ones. - -- fix issue514: teach assertion reinterpretation about private class attributes - -- change -v output to include full node IDs of tests. Users can copy - a node ID from a test run, including line number, and use it as a - positional argument in order to run only a single test. - -- fix issue 475: fail early and comprehensible if calling - pytest.raises with wrong exception type. - -- fix issue516: tell in getting-started about current dependencies. - -- cleanup setup.py a bit and specify supported versions. Thanks Jurko - Gospodnetic for the PR. - -- change XPASS colour to yellow rather then red when tests are run - with -v. - -- fix issue473: work around mock putting an unbound method into a class - dict when double-patching. - -- fix issue498: if a fixture finalizer fails, make sure that - the fixture is still invalidated. - -- fix issue453: the result of the pytest_assertrepr_compare hook now gets - it's newlines escaped so that format_exception does not blow up. - -- internal new warning system: pytest will now produce warnings when - it detects oddities in your test collection or execution. - Warnings are ultimately sent to a new pytest_logwarning hook which is - currently only implemented by the terminal plugin which displays - warnings in the summary line and shows more details when -rw (report on - warnings) is specified. - -- change skips into warnings for test classes with an __init__ and - callables in test modules which look like a test but are not functions. - -- fix issue436: improved finding of initial conftest files from command - line arguments by using the result of parse_known_args rather than - the previous flaky heuristics. Thanks Marc Abramowitz for tests - and initial fixing approaches in this area. - -- fix issue #479: properly handle nose/unittest(2) SkipTest exceptions - during collection/loading of test modules. Thanks to Marc Schlaich - for the complete PR. - -- fix issue490: include pytest_load_initial_conftests in documentation - and improve docstring. - -- fix issue472: clarify that ``pytest.config.getvalue()`` cannot work - if it's triggered ahead of command line parsing. - -- merge PR123: improved integration with mock.patch decorator on tests. - -- fix issue412: messing with stdout/stderr FD-level streams is now - captured without crashes. - -- fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR. - -- improve example for pytest integration with "python setup.py test" - which now has a generic "-a" or "--pytest-args" option where you - can pass additional options as a quoted string. Thanks Trevor Bekolay. - -- simplified internal capturing mechanism and made it more robust - against tests or setups changing FD1/FD2, also better integrated - now with pytest.pdb() in single tests. - -- improvements to pytest's own test-suite leakage detection, courtesy of PRs - from Marc Abramowitz - -- fix issue492: avoid leak in test_writeorg. Thanks Marc Abramowitz. - -- fix issue493: don't run tests in doc directory with ``python setup.py test`` - (use tox -e doctesting for that) - -- fix issue486: better reporting and handling of early conftest loading failures - -- some cleanup and simplification of internal conftest handling. - -- work a bit harder to break reference cycles when catching exceptions. - Thanks Jurko Gospodnetic. - -- fix issue443: fix skip examples to use proper comparison. Thanks Alex - Groenholm. - -- support nose-style ``__test__`` attribute on modules, classes and - functions, including unittest-style Classes. If set to False, the - test will not be collected. - -- fix issue512: show "" for arguments which might not be set - in monkeypatch plugin. Improves output in documentation. - - -2.5.2 (2014-01-29) -================== - -- fix issue409 -- better interoperate with cx_freeze by not - trying to import from collections.abc which causes problems - for py27/cx_freeze. Thanks Wolfgang L. for reporting and tracking it down. - -- fixed docs and code to use "pytest" instead of "py.test" almost everywhere. - Thanks Jurko Gospodnetic for the complete PR. - -- fix issue425: mention at end of "py.test -h" that --markers - and --fixtures work according to specified test path (or current dir) - -- fix issue413: exceptions with unicode attributes are now printed - correctly also on python2 and with pytest-xdist runs. (the fix - requires py-1.4.20) - -- copy, cleanup and integrate py.io capture - from pylib 1.4.20.dev2 (rev 13d9af95547e) - -- address issue416: clarify docs as to conftest.py loading semantics - -- fix issue429: comparing byte strings with non-ascii chars in assert - expressions now work better. Thanks Floris Bruynooghe. - -- make capfd/capsys.capture private, its unused and shouldn't be exposed - - -2.5.1 (2013-12-17) -================== - -- merge new documentation styling PR from Tobias Bieniek. - -- fix issue403: allow parametrize of multiple same-name functions within - a collection node. Thanks Andreas Kloeckner and Alex Gaynor for reporting - and analysis. - -- Allow parameterized fixtures to specify the ID of the parameters by - adding an ids argument to pytest.fixture() and pytest.yield_fixture(). - Thanks Floris Bruynooghe. - -- fix issue404 by always using the binary xml escape in the junitxml - plugin. Thanks Ronny Pfannschmidt. - -- fix issue407: fix addoption docstring to point to argparse instead of - optparse. Thanks Daniel D. Wright. - - - -2.5.0 (2013-12-12) -================== - -- dropped python2.5 from automated release testing of pytest itself - which means it's probably going to break soon (but still works - with this release we believe). - -- simplified and fixed implementation for calling finalizers when - parametrized fixtures or function arguments are involved. finalization - is now performed lazily at setup time instead of in the "teardown phase". - While this might sound odd at first, it helps to ensure that we are - correctly handling setup/teardown even in complex code. User-level code - should not be affected unless it's implementing the pytest_runtest_teardown - hook and expecting certain fixture instances are torn down within (very - unlikely and would have been unreliable anyway). - -- PR90: add --color=yes|no|auto option to force terminal coloring - mode ("auto" is default). Thanks Marc Abramowitz. - -- fix issue319 - correctly show unicode in assertion errors. Many - thanks to Floris Bruynooghe for the complete PR. Also means - we depend on py>=1.4.19 now. - -- fix issue396 - correctly sort and finalize class-scoped parametrized - tests independently from number of methods on the class. - -- refix issue323 in a better way -- parametrization should now never - cause Runtime Recursion errors because the underlying algorithm - for re-ordering tests per-scope/per-fixture is not recursive - anymore (it was tail-call recursive before which could lead - to problems for more than >966 non-function scoped parameters). - -- fix issue290 - there is preliminary support now for parametrizing - with repeated same values (sometimes useful to test if calling - a second time works as with the first time). - -- close issue240 - document precisely how pytest module importing - works, discuss the two common test directory layouts, and how it - interacts with PEP420-namespace packages. - -- fix issue246 fix finalizer order to be LIFO on independent fixtures - depending on a parametrized higher-than-function scoped fixture. - (was quite some effort so please bear with the complexity of this sentence :) - Thanks Ralph Schmitt for the precise failure example. - -- fix issue244 by implementing special index for parameters to only use - indices for paramentrized test ids - -- fix issue287 by running all finalizers but saving the exception - from the first failing finalizer and re-raising it so teardown will - still have failed. We reraise the first failing exception because - it might be the cause for other finalizers to fail. - -- fix ordering when mock.patch or other standard decorator-wrappings - are used with test methods. This fixues issue346 and should - help with random "xdist" collection failures. Thanks to - Ronny Pfannschmidt and Donald Stufft for helping to isolate it. - -- fix issue357 - special case "-k" expressions to allow for - filtering with simple strings that are not valid python expressions. - Examples: "-k 1.3" matches all tests parametrized with 1.3. - "-k None" filters all tests that have "None" in their name - and conversely "-k 'not None'". - Previously these examples would raise syntax errors. - -- fix issue384 by removing the trial support code - since the unittest compat enhancements allow - trial to handle it on its own - -- don't hide an ImportError when importing a plugin produces one. - fixes issue375. - -- fix issue275 - allow usefixtures and autouse fixtures - for running doctest text files. - -- fix issue380 by making --resultlog only rely on longrepr instead - of the "reprcrash" attribute which only exists sometimes. - -- address issue122: allow @pytest.fixture(params=iterator) by exploding - into a list early on. - -- fix pexpect-3.0 compatibility for pytest's own tests. - (fixes issue386) - -- allow nested parametrize-value markers, thanks James Lan for the PR. - -- fix unicode handling with new monkeypatch.setattr(import_path, value) - API. Thanks Rob Dennis. Fixes issue371. - -- fix unicode handling with junitxml, fixes issue368. - -- In assertion rewriting mode on Python 2, fix the detection of coding - cookies. See issue #330. - -- make "--runxfail" turn imperative pytest.xfail calls into no ops - (it already did neutralize pytest.mark.xfail markers) - -- refine pytest / pkg_resources interactions: The AssertionRewritingHook - PEP302 compliant loader now registers itself with setuptools/pkg_resources - properly so that the pkg_resources.resource_stream method works properly. - Fixes issue366. Thanks for the investigations and full PR to Jason R. Coombs. - -- pytestconfig fixture is now session-scoped as it is the same object during the - whole test run. Fixes issue370. - -- avoid one surprising case of marker malfunction/confusion:: - - @pytest.mark.some(lambda arg: ...) - def test_function(): - - would not work correctly because pytest assumes @pytest.mark.some - gets a function to be decorated already. We now at least detect if this - arg is a lambda and thus the example will work. Thanks Alex Gaynor - for bringing it up. - -- xfail a test on pypy that checks wrong encoding/ascii (pypy does - not error out). fixes issue385. - -- internally make varnames() deal with classes's __init__, - although it's not needed by pytest itself atm. Also - fix caching. Fixes issue376. - -- fix issue221 - handle importing of namespace-package with no - __init__.py properly. - -- refactor internal FixtureRequest handling to avoid monkeypatching. - One of the positive user-facing effects is that the "request" object - can now be used in closures. - -- fixed version comparison in pytest.importskip(modname, minverstring) - -- fix issue377 by clarifying in the nose-compat docs that pytest - does not duplicate the unittest-API into the "plain" namespace. - -- fix verbose reporting for @mock'd test functions - -2.4.2 (2013-10-04) -================== - -- on Windows require colorama and a newer py lib so that py.io.TerminalWriter() - now uses colorama instead of its own ctypes hacks. (fixes issue365) - thanks Paul Moore for bringing it up. - -- fix "-k" matching of tests where "repr" and "attr" and other names would - cause wrong matches because of an internal implementation quirk - (don't ask) which is now properly implemented. fixes issue345. - -- avoid tmpdir fixture to create too long filenames especially - when parametrization is used (issue354) - -- fix pytest-pep8 and pytest-flakes / pytest interactions - (collection names in mark plugin was assuming an item always - has a function which is not true for those plugins etc.) - Thanks Andi Zeidler. - -- introduce node.get_marker/node.add_marker API for plugins - like pytest-pep8 and pytest-flakes to avoid the messy - details of the node.keywords pseudo-dicts. Adapted - docs. - -- remove attempt to "dup" stdout at startup as it's icky. - the normal capturing should catch enough possibilities - of tests messing up standard FDs. - -- add pluginmanager.do_configure(config) as a link to - config.do_configure() for plugin-compatibility - -2.4.1 (2013-10-02) -================== - -- When using parser.addoption() unicode arguments to the - "type" keyword should also be converted to the respective types. - thanks Floris Bruynooghe, @dnozay. (fixes issue360 and issue362) - -- fix dotted filename completion when using argcomplete - thanks Anthon van der Neuth. (fixes issue361) - -- fix regression when a 1-tuple ("arg",) is used for specifying - parametrization (the values of the parametrization were passed - nested in a tuple). Thanks Donald Stufft. - -- merge doc typo fixes, thanks Andy Dirnberger - -2.4 -=== - -known incompatibilities: - -- if calling --genscript from python2.7 or above, you only get a - standalone script which works on python2.7 or above. Use Python2.6 - to also get a python2.5 compatible version. - -- all xunit-style teardown methods (nose-style, pytest-style, - unittest-style) will not be called if the corresponding setup method failed, - see issue322 below. - -- the pytest_plugin_unregister hook wasn't ever properly called - and there is no known implementation of the hook - so it got removed. - -- pytest.fixture-decorated functions cannot be generators (i.e. use - yield) anymore. This change might be reversed in 2.4.1 if it causes - unforeseen real-life issues. However, you can always write and return - an inner function/generator and change the fixture consumer to iterate - over the returned generator. This change was done in lieu of the new - ``pytest.yield_fixture`` decorator, see below. - -new features: - -- experimentally introduce a new ``pytest.yield_fixture`` decorator - which accepts exactly the same parameters as pytest.fixture but - mandates a ``yield`` statement instead of a ``return statement`` from - fixture functions. This allows direct integration with "with-style" - context managers in fixture functions and generally avoids registering - of finalization callbacks in favour of treating the "after-yield" as - teardown code. Thanks Andreas Pelme, Vladimir Keleshev, Floris - Bruynooghe, Ronny Pfannschmidt and many others for discussions. - -- allow boolean expression directly with skipif/xfail - if a "reason" is also specified. Rework skipping documentation - to recommend "condition as booleans" because it prevents surprises - when importing markers between modules. Specifying conditions - as strings will remain fully supported. - -- reporting: color the last line red or green depending if - failures/errors occurred or everything passed. thanks Christian - Theunert. - -- make "import pdb ; pdb.set_trace()" work natively wrt capturing (no - "-s" needed anymore), making ``pytest.set_trace()`` a mere shortcut. - -- fix issue181: --pdb now also works on collect errors (and - on internal errors) . This was implemented by a slight internal - refactoring and the introduction of a new hook - ``pytest_exception_interact`` hook (see next item). - -- fix issue341: introduce new experimental hook for IDEs/terminals to - intercept debugging: ``pytest_exception_interact(node, call, report)``. - -- new monkeypatch.setattr() variant to provide a shorter - invocation for patching out classes/functions from modules: - - monkeypatch.setattr("requests.get", myfunc) - - will replace the "get" function of the "requests" module with ``myfunc``. - -- fix issue322: tearDownClass is not run if setUpClass failed. Thanks - Mathieu Agopian for the initial fix. Also make all of pytest/nose - finalizer mimic the same generic behaviour: if a setupX exists and - fails, don't run teardownX. This internally introduces a new method - "node.addfinalizer()" helper which can only be called during the setup - phase of a node. - -- simplify pytest.mark.parametrize() signature: allow to pass a - CSV-separated string to specify argnames. For example: - ``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])`` - works as well as the previous: - ``pytest.mark.parametrize(("input", "expected"), ...)``. - -- add support for setUpModule/tearDownModule detection, thanks Brian Okken. - -- integrate tab-completion on options through use of "argcomplete". - Thanks Anthon van der Neut for the PR. - -- change option names to be hyphen-separated long options but keep the - old spelling backward compatible. py.test -h will only show the - hyphenated version, for example "--collect-only" but "--collectonly" - will remain valid as well (for backward-compat reasons). Many thanks to - Anthon van der Neut for the implementation and to Hynek Schlawack for - pushing us. - -- fix issue 308 - allow to mark/xfail/skip individual parameter sets - when parametrizing. Thanks Brianna Laugher. - -- call new experimental pytest_load_initial_conftests hook to allow - 3rd party plugins to do something before a conftest is loaded. - -Bug fixes: - -- fix issue358 - capturing options are now parsed more properly - by using a new parser.parse_known_args method. - -- pytest now uses argparse instead of optparse (thanks Anthon) which - means that "argparse" is added as a dependency if installing into python2.6 - environments or below. - -- fix issue333: fix a case of bad unittest/pytest hook interaction. - -- PR27: correctly handle nose.SkipTest during collection. Thanks - Antonio Cuni, Ronny Pfannschmidt. - -- fix issue355: junitxml puts name="pytest" attribute to testsuite tag. - -- fix issue336: autouse fixture in plugins should work again. - -- fix issue279: improve object comparisons on assertion failure - for standard datatypes and recognise collections.abc. Thanks to - Brianna Laugher and Mathieu Agopian. - -- fix issue317: assertion rewriter support for the is_package method - -- fix issue335: document py.code.ExceptionInfo() object returned - from pytest.raises(), thanks Mathieu Agopian. - -- remove implicit distribute_setup support from setup.py. - -- fix issue305: ignore any problems when writing pyc files. - -- SO-17664702: call fixture finalizers even if the fixture function - partially failed (finalizers would not always be called before) - -- fix issue320 - fix class scope for fixtures when mixed with - module-level functions. Thanks Anatloy Bubenkoff. - -- you can specify "-q" or "-qq" to get different levels of "quieter" - reporting (thanks Katarzyna Jachim) - -- fix issue300 - Fix order of conftest loading when starting py.test - in a subdirectory. - -- fix issue323 - sorting of many module-scoped arg parametrizations - -- make sessionfinish hooks execute with the same cwd-context as at - session start (helps fix plugin behaviour which write output files - with relative path such as pytest-cov) - -- fix issue316 - properly reference collection hooks in docs - -- fix issue 306 - cleanup of -k/-m options to only match markers/test - names/keywords respectively. Thanks Wouter van Ackooy. - -- improved doctest counting for doctests in python modules -- - files without any doctest items will not show up anymore - and doctest examples are counted as separate test items. - thanks Danilo Bellini. - -- fix issue245 by depending on the released py-1.4.14 - which fixes py.io.dupfile to work with files with no - mode. Thanks Jason R. Coombs. - -- fix junitxml generation when test output contains control characters, - addressing issue267, thanks Jaap Broekhuizen - -- fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. - -- fix issue307 - use yaml.safe_load in example, thanks Mark Eichin. - -- better parametrize error messages, thanks Brianna Laugher - -- pytest_terminal_summary(terminalreporter) hooks can now use - ".section(title)" and ".line(msg)" methods to print extra - information at the end of a test run. - -2.3.5 (2013-04-30) -================== - -- fix issue169: respect --tb=style with setup/teardown errors as well. - -- never consider a fixture function for test function collection - -- allow re-running of test items / helps to fix pytest-reruntests plugin - and also help to keep less fixture/resource references alive - -- put captured stdout/stderr into junitxml output even for passing tests - (thanks Adam Goucher) - -- Issue 265 - integrate nose setup/teardown with setupstate - so it doesn't try to teardown if it did not setup - -- issue 271 - don't write junitxml on slave nodes - -- Issue 274 - don't try to show full doctest example - when doctest does not know the example location - -- issue 280 - disable assertion rewriting on buggy CPython 2.6.0 - -- inject "getfixture()" helper to retrieve fixtures from doctests, - thanks Andreas Zeidler - -- issue 259 - when assertion rewriting, be consistent with the default - source encoding of ASCII on Python 2 - -- issue 251 - report a skip instead of ignoring classes with init - -- issue250 unicode/str mixes in parametrization names and values now works - -- issue257, assertion-triggered compilation of source ending in a - comment line doesn't blow up in python2.5 (fixed through py>=1.4.13.dev6) - -- fix --genscript option to generate standalone scripts that also - work with python3.3 (importer ordering) - -- issue171 - in assertion rewriting, show the repr of some - global variables - -- fix option help for "-k" - -- move long description of distribution into README.rst - -- improve docstring for metafunc.parametrize() - -- fix bug where using capsys with pytest.set_trace() in a test - function would break when looking at capsys.readouterr() - -- allow to specify prefixes starting with "_" when - customizing python_functions test discovery. (thanks Graham Horler) - -- improve PYTEST_DEBUG tracing output by putting - extra data on a new lines with additional indent - -- ensure OutcomeExceptions like skip/fail have initialized exception attributes - -- issue 260 - don't use nose special setup on plain unittest cases - -- fix issue134 - print the collect errors that prevent running specified test items - -- fix issue266 - accept unicode in MarkEvaluator expressions - -2.3.4 (2012-11-20) -================== - -- yielded test functions will now have autouse-fixtures active but - cannot accept fixtures as funcargs - it's anyway recommended to - rather use the post-2.0 parametrize features instead of yield, see: - http://pytest.org/latest/example/parametrize.html -- fix autouse-issue where autouse-fixtures would not be discovered - if defined in an a/conftest.py file and tests in a/tests/test_some.py -- fix issue226 - LIFO ordering for fixture teardowns -- fix issue224 - invocations with >256 char arguments now work -- fix issue91 - add/discuss package/directory level setups in example -- allow to dynamically define markers via - item.keywords[...]=assignment integrating with "-m" option -- make "-k" accept an expressions the same as with "-m" so that one - can write: -k "name1 or name2" etc. This is a slight incompatibility - if you used special syntax like "TestClass.test_method" which you now - need to write as -k "TestClass and test_method" to match a certain - method in a certain test class. - -2.3.3 (2012-11-06) -================== - -- fix issue214 - parse modules that contain special objects like e. g. - flask's request object which blows up on getattr access if no request - is active. thanks Thomas Waldmann. - -- fix issue213 - allow to parametrize with values like numpy arrays that - do not support an __eq__ operator - -- fix issue215 - split test_python.org into multiple files - -- fix issue148 - @unittest.skip on classes is now recognized and avoids - calling setUpClass/tearDownClass, thanks Pavel Repin - -- fix issue209 - reintroduce python2.4 support by depending on newer - pylib which re-introduced statement-finding for pre-AST interpreters - -- nose support: only call setup if it's a callable, thanks Andrew - Taumoefolau - -- fix issue219 - add py2.4-3.3 classifiers to TROVE list - -- in tracebacks *,** arg values are now shown next to normal arguments - (thanks Manuel Jacob) - -- fix issue217 - support mock.patch with pytest's fixtures - note that - you need either mock-1.0.1 or the python3.3 builtin unittest.mock. - -- fix issue127 - improve documentation for pytest_addoption() and - add a ``config.getoption(name)`` helper function for consistency. - -2.3.2 (2012-10-25) -================== - -- fix issue208 and fix issue29 use new py version to avoid long pauses - when printing tracebacks in long modules - -- fix issue205 - conftests in subdirs customizing - pytest_pycollect_makemodule and pytest_pycollect_makeitem - now work properly - -- fix teardown-ordering for parametrized setups - -- fix issue127 - better documentation for pytest_addoption - and related objects. - -- fix unittest behaviour: TestCase.runtest only called if there are - test methods defined - -- improve trial support: don't collect its empty - unittest.TestCase.runTest() method - -- "python setup.py test" now works with pytest itself - -- fix/improve internal/packaging related bits: - - - exception message check of test_nose.py now passes on python33 as well - - - issue206 - fix test_assertrewrite.py to work when a global - PYTHONDONTWRITEBYTECODE=1 is present - - - add tox.ini to pytest distribution so that ignore-dirs and others config - bits are properly distributed for maintainers who run pytest-own tests - -2.3.1 (2012-10-20) -================== - -- fix issue202 - fix regression: using "self" from fixture functions now - works as expected (it's the same "self" instance that a test method - which uses the fixture sees) - -- skip pexpect using tests (test_pdb.py mostly) on freebsd* systems - due to pexpect not supporting it properly (hanging) - -- link to web pages from --markers output which provides help for - pytest.mark.* usage. - -2.3.0 (2012-10-19) -================== - -- fix issue202 - better automatic names for parametrized test functions -- fix issue139 - introduce @pytest.fixture which allows direct scoping - and parametrization of funcarg factories. -- fix issue198 - conftest fixtures were not found on windows32 in some - circumstances with nested directory structures due to path manipulation issues -- fix issue193 skip test functions with were parametrized with empty - parameter sets -- fix python3.3 compat, mostly reporting bits that previously depended - on dict ordering -- introduce re-ordering of tests by resource and parametrization setup - which takes precedence to the usual file-ordering -- fix issue185 monkeypatching time.time does not cause pytest to fail -- fix issue172 duplicate call of pytest.fixture decoratored setup_module - functions -- fix junitxml=path construction so that if tests change the - current working directory and the path is a relative path - it is constructed correctly from the original current working dir. -- fix "python setup.py test" example to cause a proper "errno" return -- fix issue165 - fix broken doc links and mention stackoverflow for FAQ -- catch unicode-issues when writing failure representations - to terminal to prevent the whole session from crashing -- fix xfail/skip confusion: a skip-mark or an imperative pytest.skip - will now take precedence before xfail-markers because we - can't determine xfail/xpass status in case of a skip. see also: - http://stackoverflow.com/questions/11105828/in-py-test-when-i-explicitly-skip-a-test-that-is-marked-as-xfail-how-can-i-get - -- always report installed 3rd party plugins in the header of a test run - -- fix issue160: a failing setup of an xfail-marked tests should - be reported as xfail (not xpass) - -- fix issue128: show captured output when capsys/capfd are used - -- fix issue179: properly show the dependency chain of factories - -- pluginmanager.register(...) now raises ValueError if the - plugin has been already registered or the name is taken - -- fix issue159: improve http://pytest.org/latest/faq.html - especially with respect to the "magic" history, also mention - pytest-django, trial and unittest integration. - -- make request.keywords and node.keywords writable. All descendant - collection nodes will see keyword values. Keywords are dictionaries - containing markers and other info. - -- fix issue 178: xml binary escapes are now wrapped in py.xml.raw - -- fix issue 176: correctly catch the builtin AssertionError - even when we replaced AssertionError with a subclass on the - python level - -- factory discovery no longer fails with magic global callables - that provide no sane __code__ object (mock.call for example) - -- fix issue 182: testdir.inprocess_run now considers passed plugins - -- fix issue 188: ensure sys.exc_info is clear on python2 - before calling into a test - -- fix issue 191: add unittest TestCase runTest method support -- fix issue 156: monkeypatch correctly handles class level descriptors - -- reporting refinements: - - - pytest_report_header now receives a "startdir" so that - you can use startdir.bestrelpath(yourpath) to show - nice relative path - - - allow plugins to implement both pytest_report_header and - pytest_sessionstart (sessionstart is invoked first). - - - don't show deselected reason line if there is none - - - py.test -vv will show all of assert comparisons instead of truncating - -2.2.4 (2012-05-22) -================== - -- fix error message for rewritten assertions involving the % operator -- fix issue 126: correctly match all invalid xml characters for junitxml - binary escape -- fix issue with unittest: now @unittest.expectedFailure markers should - be processed correctly (you can also use @pytest.mark markers) -- document integration with the extended distribute/setuptools test commands -- fix issue 140: properly get the real functions - of bound classmethods for setup/teardown_class -- fix issue #141: switch from the deceased paste.pocoo.org to bpaste.net -- fix issue #143: call unconfigure/sessionfinish always when - configure/sessionstart where called -- fix issue #144: better mangle test ids to junitxml classnames -- upgrade distribute_setup.py to 0.6.27 - -2.2.3 (2012-02-05) -================== - -- fix uploaded package to only include necessary files - -2.2.2 (2012-02-05) -================== - -- fix issue101: wrong args to unittest.TestCase test function now - produce better output -- fix issue102: report more useful errors and hints for when a - test directory was renamed and some pyc/__pycache__ remain -- fix issue106: allow parametrize to be applied multiple times - e.g. from module, class and at function level. -- fix issue107: actually perform session scope finalization -- don't check in parametrize if indirect parameters are funcarg names -- add chdir method to monkeypatch funcarg -- fix crash resulting from calling monkeypatch undo a second time -- fix issue115: make --collectonly robust against early failure - (missing files/directories) -- "-qq --collectonly" now shows only files and the number of tests in them -- "-q --collectonly" now shows test ids -- allow adding of attributes to test reports such that it also works - with distributed testing (no upgrade of pytest-xdist needed) - -2.2.1 (2011-12-16) -================== - -- fix issue99 (in pytest and py) internallerrors with resultlog now - produce better output - fixed by normalizing pytest_internalerror - input arguments. -- fix issue97 / traceback issues (in pytest and py) improve traceback output - in conjunction with jinja2 and cython which hack tracebacks -- fix issue93 (in pytest and pytest-xdist) avoid "delayed teardowns": - the final test in a test node will now run its teardown directly - instead of waiting for the end of the session. Thanks Dave Hunt for - the good reporting and feedback. The pytest_runtest_protocol as well - as the pytest_runtest_teardown hooks now have "nextitem" available - which will be None indicating the end of the test run. -- fix collection crash due to unknown-source collected items, thanks - to Ralf Schmitt (fixed by depending on a more recent pylib) - -2.2.0 (2011-11-18) -================== - -- fix issue90: introduce eager tearing down of test items so that - teardown function are called earlier. -- add an all-powerful metafunc.parametrize function which allows to - parametrize test function arguments in multiple steps and therefore - from independent plugins and places. -- add a @pytest.mark.parametrize helper which allows to easily - call a test function with different argument values -- Add examples to the "parametrize" example page, including a quick port - of Test scenarios and the new parametrize function and decorator. -- introduce registration for "pytest.mark.*" helpers via ini-files - or through plugin hooks. Also introduce a "--strict" option which - will treat unregistered markers as errors - allowing to avoid typos and maintain a well described set of markers - for your test suite. See exaples at http://pytest.org/latest/mark.html - and its links. -- issue50: introduce "-m marker" option to select tests based on markers - (this is a stricter and more predictable version of '-k' in that "-m" - only matches complete markers and has more obvious rules for and/or - semantics. -- new feature to help optimizing the speed of your tests: - --durations=N option for displaying N slowest test calls - and setup/teardown methods. -- fix issue87: --pastebin now works with python3 -- fix issue89: --pdb with unexpected exceptions in doctest work more sensibly -- fix and cleanup pytest's own test suite to not leak FDs -- fix issue83: link to generated funcarg list -- fix issue74: pyarg module names are now checked against imp.find_module false positives -- fix compatibility with twisted/trial-11.1.0 use cases -- simplify Node.listchain -- simplify junitxml output code by relying on py.xml -- add support for skip properties on unittest classes and functions - -2.1.3 (2011-10-18) -================== - -- fix issue79: assertion rewriting failed on some comparisons in boolops -- correctly handle zero length arguments (a la pytest '') -- fix issue67 / junitxml now contains correct test durations, thanks ronny -- fix issue75 / skipping test failure on jython -- fix issue77 / Allow assertrepr_compare hook to apply to a subset of tests - -2.1.2 (2011-09-24) -================== - -- fix assertion rewriting on files with windows newlines on some Python versions -- refine test discovery by package/module name (--pyargs), thanks Florian Mayer -- fix issue69 / assertion rewriting fixed on some boolean operations -- fix issue68 / packages now work with assertion rewriting -- fix issue66: use different assertion rewriting caches when the -O option is passed -- don't try assertion rewriting on Jython, use reinterp - -2.1.1 -===== - -- fix issue64 / pytest.set_trace now works within pytest_generate_tests hooks -- fix issue60 / fix error conditions involving the creation of __pycache__ -- fix issue63 / assertion rewriting on inserts involving strings containing '%' -- fix assertion rewriting on calls with a ** arg -- don't cache rewritten modules if bytecode generation is disabled -- fix assertion rewriting in read-only directories -- fix issue59: provide system-out/err tags for junitxml output -- fix issue61: assertion rewriting on boolean operations with 3 or more operands -- you can now build a man page with "cd doc ; make man" - -2.1.0 (2011-07-09) -================== - -- fix issue53 call nosestyle setup functions with correct ordering -- fix issue58 and issue59: new assertion code fixes -- merge Benjamin's assertionrewrite branch: now assertions - for test modules on python 2.6 and above are done by rewriting - the AST and saving the pyc file before the test module is imported. - see doc/assert.txt for more info. -- fix issue43: improve doctests with better traceback reporting on - unexpected exceptions -- fix issue47: timing output in junitxml for test cases is now correct -- fix issue48: typo in MarkInfo repr leading to exception -- fix issue49: avoid confusing error when initizaliation partially fails -- fix issue44: env/username expansion for junitxml file path -- show releaselevel information in test runs for pypy -- reworked doc pages for better navigation and PDF generation -- report KeyboardInterrupt even if interrupted during session startup -- fix issue 35 - provide PDF doc version and download link from index page - -2.0.3 (2011-05-11) -================== - -- fix issue38: nicer tracebacks on calls to hooks, particularly early - configure/sessionstart ones - -- fix missing skip reason/meta information in junitxml files, reported - via http://lists.idyll.org/pipermail/testing-in-python/2011-March/003928.html - -- fix issue34: avoid collection failure with "test" prefixed classes - deriving from object. - -- don't require zlib (and other libs) for genscript plugin without - --genscript actually being used. - -- speed up skips (by not doing a full traceback representation - internally) - -- fix issue37: avoid invalid characters in junitxml's output - -2.0.2 (2011-03-09) -================== - -- tackle issue32 - speed up test runs of very quick test functions - by reducing the relative overhead - -- fix issue30 - extended xfail/skipif handling and improved reporting. - If you have a syntax error in your skip/xfail - expressions you now get nice error reports. - - Also you can now access module globals from xfail/skipif - expressions so that this for example works now:: - - import pytest - import mymodule - @pytest.mark.skipif("mymodule.__version__[0] == "1") - def test_function(): - pass - - This will not run the test function if the module's version string - does not start with a "1". Note that specifying a string instead - of a boolean expressions allows py.test to report meaningful information - when summarizing a test run as to what conditions lead to skipping - (or xfail-ing) tests. - -- fix issue28 - setup_method and pytest_generate_tests work together - The setup_method fixture method now gets called also for - test function invocations generated from the pytest_generate_tests - hook. - -- fix issue27 - collectonly and keyword-selection (-k) now work together - Also, if you do "py.test --collectonly -q" you now get a flat list - of test ids that you can use to paste to the py.test commandline - in order to execute a particular test. - -- fix issue25 avoid reported problems with --pdb and python3.2/encodings output - -- fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP - Starting with Python3.2 os.symlink may be supported. By requiring - a newer py lib version the py.path.local() implementation acknowledges - this. - -- fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular - thanks to Laura Creighton who also reviewed parts of the documentation. - -- fix slightly wrong output of verbose progress reporting for classes - (thanks Amaury) - -- more precise (avoiding of) deprecation warnings for node.Class|Function accesses - -- avoid std unittest assertion helper code in tracebacks (thanks Ronny) - -2.0.1 (2011-02-07) -================== - -- refine and unify initial capturing so that it works nicely - even if the logging module is used on an early-loaded conftest.py - file or plugin. -- allow to omit "()" in test ids to allow for uniform test ids - as produced by Alfredo's nice pytest.vim plugin. -- fix issue12 - show plugin versions with "--version" and - "--traceconfig" and also document how to add extra information - to reporting test header -- fix issue17 (import-* reporting issue on python3) by - requiring py>1.4.0 (1.4.1 is going to include it) -- fix issue10 (numpy arrays truth checking) by refining - assertion interpretation in py lib -- fix issue15: make nose compatibility tests compatible - with python3 (now that nose-1.0 supports python3) -- remove somewhat surprising "same-conftest" detection because - it ignores conftest.py when they appear in several subdirs. -- improve assertions ("not in"), thanks Floris Bruynooghe -- improve behaviour/warnings when running on top of "python -OO" - (assertions and docstrings are turned off, leading to potential - false positives) -- introduce a pytest_cmdline_processargs(args) hook - to allow dynamic computation of command line arguments. - This fixes a regression because py.test prior to 2.0 - allowed to set command line options from conftest.py - files which so far pytest-2.0 only allowed from ini-files now. -- fix issue7: assert failures in doctest modules. - unexpected failures in doctests will not generally - show nicer, i.e. within the doctest failing context. -- fix issue9: setup/teardown functions for an xfail-marked - test will report as xfail if they fail but report as normally - passing (not xpassing) if they succeed. This only is true - for "direct" setup/teardown invocations because teardown_class/ - teardown_module cannot closely relate to a single test. -- fix issue14: no logging errors at process exit -- refinements to "collecting" output on non-ttys -- refine internal plugin registration and --traceconfig output -- introduce a mechanism to prevent/unregister plugins from the - command line, see http://pytest.org/plugins.html#cmdunregister -- activate resultlog plugin by default -- fix regression wrt yielded tests which due to the - collection-before-running semantics were not - setup as with pytest 1.3.4. Note, however, that - the recommended and much cleaner way to do test - parametraization remains the "pytest_generate_tests" - mechanism, see the docs. - -2.0.0 (2010-11-25) -================== - -- pytest-2.0 is now its own package and depends on pylib-2.0 -- new ability: python -m pytest / python -m pytest.main ability -- new python invocation: pytest.main(args, plugins) to load - some custom plugins early. -- try harder to run unittest test suites in a more compatible manner - by deferring setup/teardown semantics to the unittest package. - also work harder to run twisted/trial and Django tests which - should now basically work by default. -- introduce a new way to set config options via ini-style files, - by default setup.cfg and tox.ini files are searched. The old - ways (certain environment variables, dynamic conftest.py reading - is removed). -- add a new "-q" option which decreases verbosity and prints a more - nose/unittest-style "dot" output. -- fix issue135 - marks now work with unittest test cases as well -- fix issue126 - introduce py.test.set_trace() to trace execution via - PDB during the running of tests even if capturing is ongoing. -- fix issue123 - new "python -m py.test" invocation for py.test - (requires Python 2.5 or above) -- fix issue124 - make reporting more resilient against tests opening - files on filedescriptor 1 (stdout). -- fix issue109 - sibling conftest.py files will not be loaded. - (and Directory collectors cannot be customized anymore from a Directory's - conftest.py - this needs to happen at least one level up). -- introduce (customizable) assertion failure representations and enhance - output on assertion failures for comparisons and other cases (Floris Bruynooghe) -- nose-plugin: pass through type-signature failures in setup/teardown - functions instead of not calling them (Ed Singleton) -- remove py.test.collect.Directory (follows from a major refactoring - and simplification of the collection process) -- majorly reduce py.test core code, shift function/python testing to own plugin -- fix issue88 (finding custom test nodes from command line arg) -- refine 'tmpdir' creation, will now create basenames better associated - with test names (thanks Ronny) -- "xpass" (unexpected pass) tests don't cause exitcode!=0 -- fix issue131 / issue60 - importing doctests in __init__ files used as namespace packages -- fix issue93 stdout/stderr is captured while importing conftest.py -- fix bug: unittest collected functions now also can have "pytestmark" - applied at class/module level -- add ability to use "class" level for cached_setup helper -- fix strangeness: mark.* objects are now immutable, create new instances - -1.3.4 (2010-09-14) -================== - -- fix issue111: improve install documentation for windows -- fix issue119: fix custom collectability of __init__.py as a module -- fix issue116: --doctestmodules work with __init__.py files as well -- fix issue115: unify internal exception passthrough/catching/GeneratorExit -- fix issue118: new --tb=native for presenting cpython-standard exceptions - -1.3.3 (2010-07-30) -================== - -- fix issue113: assertion representation problem with triple-quoted strings - (and possibly other cases) -- make conftest loading detect that a conftest file with the same - content was already loaded, avoids surprises in nested directory structures - which can be produced e.g. by Hudson. It probably removes the need to use - --confcutdir in most cases. -- fix terminal coloring for win32 - (thanks Michael Foord for reporting) -- fix weirdness: make terminal width detection work on stdout instead of stdin - (thanks Armin Ronacher for reporting) -- remove trailing whitespace in all py/text distribution files - -1.3.2 (2010-07-08) -================== - -**New features** - -- fix issue103: introduce py.test.raises as context manager, examples:: - - with py.test.raises(ZeroDivisionError): - x = 0 - 1 / x - - with py.test.raises(RuntimeError) as excinfo: - call_something() - - # you may do extra checks on excinfo.value|type|traceback here - - (thanks Ronny Pfannschmidt) - -- Funcarg factories can now dynamically apply a marker to a - test invocation. This is for example useful if a factory - provides parameters to a test which are expected-to-fail:: - - def pytest_funcarg__arg(request): - request.applymarker(py.test.mark.xfail(reason="flaky config")) - ... - - def test_function(arg): - ... - -- improved error reporting on collection and import errors. This makes - use of a more general mechanism, namely that for custom test item/collect - nodes ``node.repr_failure(excinfo)`` is now uniformly called so that you can - override it to return a string error representation of your choice - which is going to be reported as a (red) string. - -- introduce '--junitprefix=STR' option to prepend a prefix - to all reports in the junitxml file. - -**Bug fixes** - -- make tests and the ``pytest_recwarn`` plugin in particular fully compatible - to Python2.7 (if you use the ``recwarn`` funcarg warnings will be enabled so that - you can properly check for their existence in a cross-python manner). -- refine --pdb: ignore xfailed tests, unify its TB-reporting and - don't display failures again at the end. -- fix assertion interpretation with the ** operator (thanks Benjamin Peterson) -- fix issue105 assignment on the same line as a failing assertion (thanks Benjamin Peterson) -- fix issue104 proper escaping for test names in junitxml plugin (thanks anonymous) -- fix issue57 -f|--looponfail to work with xpassing tests (thanks Ronny) -- fix issue92 collectonly reporter and --pastebin (thanks Benjamin Peterson) -- fix py.code.compile(source) to generate unique filenames -- fix assertion re-interp problems on PyPy, by defering code - compilation to the (overridable) Frame.eval class. (thanks Amaury Forgeot) -- fix py.path.local.pyimport() to work with directories -- streamline py.path.local.mkdtemp implementation and usage -- don't print empty lines when showing junitxml-filename -- add optional boolean ignore_errors parameter to py.path.local.remove -- fix terminal writing on win32/python2.4 -- py.process.cmdexec() now tries harder to return properly encoded unicode objects - on all python versions -- install plain py.test/py.which scripts also for Jython, this helps to - get canonical script paths in virtualenv situations -- make path.bestrelpath(path) return ".", note that when calling - X.bestrelpath the assumption is that X is a directory. -- make initial conftest discovery ignore "--" prefixed arguments -- fix resultlog plugin when used in a multicpu/multihost xdist situation - (thanks Jakub Gustak) -- perform distributed testing related reporting in the xdist-plugin - rather than having dist-related code in the generic py.test - distribution -- fix homedir detection on Windows -- ship distribute_setup.py version 0.6.13 - -1.3.1 (2010-05-25) -================== - -**New features** - -- issue91: introduce new py.test.xfail(reason) helper - to imperatively mark a test as expected to fail. Can - be used from within setup and test functions. This is - useful especially for parametrized tests when certain - configurations are expected-to-fail. In this case the - declarative approach with the @py.test.mark.xfail cannot - be used as it would mark all configurations as xfail. - -- issue102: introduce new --maxfail=NUM option to stop - test runs after NUM failures. This is a generalization - of the '-x' or '--exitfirst' option which is now equivalent - to '--maxfail=1'. Both '-x' and '--maxfail' will - now also print a line near the end indicating the Interruption. - -- issue89: allow py.test.mark decorators to be used on classes - (class decorators were introduced with python2.6) and - also allow to have multiple markers applied at class/module level - by specifying a list. - -- improve and refine letter reporting in the progress bar: - . pass - f failed test - s skipped tests (reminder: use for dependency/platform mismatch only) - x xfailed test (test that was expected to fail) - X xpassed test (test that was expected to fail but passed) - - You can use any combination of 'fsxX' with the '-r' extended - reporting option. The xfail/xpass results will show up as - skipped tests in the junitxml output - which also fixes - issue99. - -- make py.test.cmdline.main() return the exitstatus instead of raising - SystemExit and also allow it to be called multiple times. This of - course requires that your application and tests are properly teared - down and don't have global state. - -**Bug Fixes** - -- improved traceback presentation: - - improved and unified reporting for "--tb=short" option - - Errors during test module imports are much shorter, (using --tb=short style) - - raises shows shorter more relevant tracebacks - - --fulltrace now more systematically makes traces longer / inhibits cutting - -- improve support for raises and other dynamically compiled code by - manipulating python's linecache.cache instead of the previous - rather hacky way of creating custom code objects. This makes - it seemlessly work on Jython and PyPy where it previously didn't. - -- fix issue96: make capturing more resilient against Control-C - interruptions (involved somewhat substantial refactoring - to the underlying capturing functionality to avoid race - conditions). - -- fix chaining of conditional skipif/xfail decorators - so it works now - as expected to use multiple @py.test.mark.skipif(condition) decorators, - including specific reporting which of the conditions lead to skipping. - -- fix issue95: late-import zlib so that it's not required - for general py.test startup. - -- fix issue94: make reporting more robust against bogus source code - (and internally be more careful when presenting unexpected byte sequences) - - -1.3.0 (2010-05-05) -================== - -- deprecate --report option in favour of a new shorter and easier to - remember -r option: it takes a string argument consisting of any - combination of 'xfsX' characters. They relate to the single chars - you see during the dotted progress printing and will print an extra line - per test at the end of the test run. This extra line indicates the exact - position or test ID that you directly paste to the py.test cmdline in order - to re-run a particular test. - -- allow external plugins to register new hooks via the new - pytest_addhooks(pluginmanager) hook. The new release of - the pytest-xdist plugin for distributed and looponfailing - testing requires this feature. - -- add a new pytest_ignore_collect(path, config) hook to allow projects and - plugins to define exclusion behaviour for their directory structure - - for example you may define in a conftest.py this method:: - - def pytest_ignore_collect(path): - return path.check(link=1) - - to prevent even a collection try of any tests in symlinked dirs. - -- new pytest_pycollect_makemodule(path, parent) hook for - allowing customization of the Module collection object for a - matching test module. - -- extend and refine xfail mechanism: - ``@py.test.mark.xfail(run=False)`` do not run the decorated test - ``@py.test.mark.xfail(reason="...")`` prints the reason string in xfail summaries - specifying ``--runxfail`` on command line virtually ignores xfail markers - -- expose (previously internal) commonly useful methods: - py.io.get_terminal_with() -> return terminal width - py.io.ansi_print(...) -> print colored/bold text on linux/win32 - py.io.saferepr(obj) -> return limited representation string - -- expose test outcome related exceptions as py.test.skip.Exception, - py.test.raises.Exception etc., useful mostly for plugins - doing special outcome interpretation/tweaking - -- (issue85) fix junitxml plugin to handle tests with non-ascii output - -- fix/refine python3 compatibility (thanks Benjamin Peterson) - -- fixes for making the jython/win32 combination work, note however: - jython2.5.1/win32 does not provide a command line launcher, see - http://bugs.jython.org/issue1491 . See pylib install documentation - for how to work around. - -- fixes for handling of unicode exception values and unprintable objects - -- (issue87) fix unboundlocal error in assertionold code - -- (issue86) improve documentation for looponfailing - -- refine IO capturing: stdin-redirect pseudo-file now has a NOP close() method - -- ship distribute_setup.py version 0.6.10 - -- added links to the new capturelog and coverage plugins - - -1.2.0 (2010-01-18) -================== - -- refined usage and options for "py.cleanup":: - - py.cleanup # remove "*.pyc" and "*$py.class" (jython) files - py.cleanup -e .swp -e .cache # also remove files with these extensions - py.cleanup -s # remove "build" and "dist" directory next to setup.py files - py.cleanup -d # also remove empty directories - py.cleanup -a # synonym for "-s -d -e 'pip-log.txt'" - py.cleanup -n # dry run, only show what would be removed - -- add a new option "py.test --funcargs" which shows available funcargs - and their help strings (docstrings on their respective factory function) - for a given test path - -- display a short and concise traceback if a funcarg lookup fails - -- early-load "conftest.py" files in non-dot first-level sub directories. - allows to conveniently keep and access test-related options in a ``test`` - subdir and still add command line options. - -- fix issue67: new super-short traceback-printing option: "--tb=line" will print a single line for each failing (python) test indicating its filename, lineno and the failure value - -- fix issue78: always call python-level teardown functions even if the - according setup failed. This includes refinements for calling setup_module/class functions - which will now only be called once instead of the previous behaviour where they'd be called - multiple times if they raise an exception (including a Skipped exception). Any exception - will be re-corded and associated with all tests in the according module/class scope. - -- fix issue63: assume <40 columns to be a bogus terminal width, default to 80 - -- fix pdb debugging to be in the correct frame on raises-related errors - -- update apipkg.py to fix an issue where recursive imports might - unnecessarily break importing - -- fix plugin links - -1.1.1 (2009-11-24) -================== - -- moved dist/looponfailing from py.test core into a new - separately released pytest-xdist plugin. - -- new junitxml plugin: --junitxml=path will generate a junit style xml file - which is processable e.g. by the Hudson CI system. - -- new option: --genscript=path will generate a standalone py.test script - which will not need any libraries installed. thanks to Ralf Schmitt. - -- new option: --ignore will prevent specified path from collection. - Can be specified multiple times. - -- new option: --confcutdir=dir will make py.test only consider conftest - files that are relative to the specified dir. - -- new funcarg: "pytestconfig" is the pytest config object for access - to command line args and can now be easily used in a test. - -- install ``py.test`` and ``py.which`` with a ``-$VERSION`` suffix to - disambiguate between Python3, python2.X, Jython and PyPy installed versions. - -- new "pytestconfig" funcarg allows access to test config object - -- new "pytest_report_header" hook can return additional lines - to be displayed at the header of a test run. - -- (experimental) allow "py.test path::name1::name2::..." for pointing - to a test within a test collection directly. This might eventually - evolve as a full substitute to "-k" specifications. - -- streamlined plugin loading: order is now as documented in - customize.html: setuptools, ENV, commandline, conftest. - also setuptools entry point names are turned to canonical namees ("pytest_*") - -- automatically skip tests that need 'capfd' but have no os.dup - -- allow pytest_generate_tests to be defined in classes as well - -- deprecate usage of 'disabled' attribute in favour of pytestmark -- deprecate definition of Directory, Module, Class and Function nodes - in conftest.py files. Use pytest collect hooks instead. - -- collection/item node specific runtest/collect hooks are only called exactly - on matching conftest.py files, i.e. ones which are exactly below - the filesystem path of an item - -- change: the first pytest_collect_directory hook to return something - will now prevent further hooks to be called. - -- change: figleaf plugin now requires --figleaf to run. Also - change its long command line options to be a bit shorter (see py.test -h). - -- change: pytest doctest plugin is now enabled by default and has a - new option --doctest-glob to set a pattern for file matches. - -- change: remove internal py._* helper vars, only keep py._pydir - -- robustify capturing to survive if custom pytest_runtest_setup - code failed and prevented the capturing setup code from running. - -- make py.test.* helpers provided by default plugins visible early - - works transparently both for pydoc and for interactive sessions - which will regularly see e.g. py.test.mark and py.test.importorskip. - -- simplify internal plugin manager machinery -- simplify internal collection tree by introducing a RootCollector node - -- fix assert reinterpreation that sees a call containing "keyword=..." - -- fix issue66: invoke pytest_sessionstart and pytest_sessionfinish - hooks on slaves during dist-testing, report module/session teardown - hooks correctly. - -- fix issue65: properly handle dist-testing if no - execnet/py lib installed remotely. - -- skip some install-tests if no execnet is available - -- fix docs, fix internal bin/ script generation - - -1.1.0 (2009-11-05) -================== - -- introduce automatic plugin registration via 'pytest11' - entrypoints via setuptools' pkg_resources.iter_entry_points - -- fix py.test dist-testing to work with execnet >= 1.0.0b4 - -- re-introduce py.test.cmdline.main() for better backward compatibility - -- svn paths: fix a bug with path.check(versioned=True) for svn paths, - allow '%' in svn paths, make svnwc.update() default to interactive mode - like in 1.0.x and add svnwc.update(interactive=False) to inhibit interaction. - -- refine distributed tarball to contain test and no pyc files - -- try harder to have deprecation warnings for py.compat.* accesses - report a correct location - -1.0.3 -===== - -* adjust and improve docs - -* remove py.rest tool and internal namespace - it was - never really advertised and can still be used with - the old release if needed. If there is interest - it could be revived into its own tool i guess. - -* fix issue48 and issue59: raise an Error if the module - from an imported test file does not seem to come from - the filepath - avoids "same-name" confusion that has - been reported repeatedly - -* merged Ronny's nose-compatibility hacks: now - nose-style setup_module() and setup() functions are - supported - -* introduce generalized py.test.mark function marking - -* reshuffle / refine command line grouping - -* deprecate parser.addgroup in favour of getgroup which creates option group - -* add --report command line option that allows to control showing of skipped/xfailed sections - -* generalized skipping: a new way to mark python functions with skipif or xfail - at function, class and modules level based on platform or sys-module attributes. - -* extend py.test.mark decorator to allow for positional args - -* introduce and test "py.cleanup -d" to remove empty directories - -* fix issue #59 - robustify unittest test collection - -* make bpython/help interaction work by adding an __all__ attribute - to ApiModule, cleanup initpkg - -* use MIT license for pylib, add some contributors - -* remove py.execnet code and substitute all usages with 'execnet' proper - -* fix issue50 - cached_setup now caches more to expectations - for test functions with multiple arguments. - -* merge Jarko's fixes, issue #45 and #46 - -* add the ability to specify a path for py.lookup to search in - -* fix a funcarg cached_setup bug probably only occurring - in distributed testing and "module" scope with teardown. - -* many fixes and changes for making the code base python3 compatible, - many thanks to Benjamin Peterson for helping with this. - -* consolidate builtins implementation to be compatible with >=2.3, - add helpers to ease keeping 2 and 3k compatible code - -* deprecate py.compat.doctest|subprocess|textwrap|optparse - -* deprecate py.magic.autopath, remove py/magic directory - -* move pytest assertion handling to py/code and a pytest_assertion - plugin, add "--no-assert" option, deprecate py.magic namespaces - in favour of (less) py.code ones. - -* consolidate and cleanup py/code classes and files - -* cleanup py/misc, move tests to bin-for-dist - -* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg - -* consolidate py.log implementation, remove old approach. - -* introduce py.io.TextIO and py.io.BytesIO for distinguishing between - text/unicode and byte-streams (uses underlying standard lib io.* - if available) - -* make py.unittest_convert helper script available which converts "unittest.py" - style files into the simpler assert/direct-test-classes py.test/nosetests - style. The script was written by Laura Creighton. - -* simplified internal localpath implementation - -1.0.2 (2009-08-27) -================== - -* fixing packaging issues, triggered by fedora redhat packaging, - also added doc, examples and contrib dirs to the tarball. - -* added a documentation link to the new django plugin. - -1.0.1 (2009-08-19) -================== - -* added a 'pytest_nose' plugin which handles nose.SkipTest, - nose-style function/method/generator setup/teardown and - tries to report functions correctly. - -* capturing of unicode writes or encoded strings to sys.stdout/err - work better, also terminalwriting was adapted and somewhat - unified between windows and linux. - -* improved documentation layout and content a lot - -* added a "--help-config" option to show conftest.py / ENV-var names for - all longopt cmdline options, and some special conftest.py variables. - renamed 'conf_capture' conftest setting to 'option_capture' accordingly. - -* fix issue #27: better reporting on non-collectable items given on commandline - (e.g. pyc files) - -* fix issue #33: added --version flag (thanks Benjamin Peterson) - -* fix issue #32: adding support for "incomplete" paths to wcpath.status() - -* "Test" prefixed classes are *not* collected by default anymore if they - have an __init__ method - -* monkeypatch setenv() now accepts a "prepend" parameter - -* improved reporting of collection error tracebacks - -* simplified multicall mechanism and plugin architecture, - renamed some internal methods and argnames - -1.0.0 (2009-08-04) -================== - -* more terse reporting try to show filesystem path relatively to current dir -* improve xfail output a bit - -1.0.0b9 (2009-07-31) -==================== - -* cleanly handle and report final teardown of test setup - -* fix svn-1.6 compat issue with py.path.svnwc().versioned() - (thanks Wouter Vanden Hove) - -* setup/teardown or collection problems now show as ERRORs - or with big "E"'s in the progress lines. they are reported - and counted separately. - -* dist-testing: properly handle test items that get locally - collected but cannot be collected on the remote side - often - due to platform/dependency reasons - -* simplified py.test.mark API - see keyword plugin documentation - -* integrate better with logging: capturing now by default captures - test functions and their immediate setup/teardown in a single stream - -* capsys and capfd funcargs now have a readouterr() and a close() method - (underlyingly py.io.StdCapture/FD objects are used which grew a - readouterr() method as well to return snapshots of captured out/err) - -* make assert-reinterpretation work better with comparisons not - returning bools (reported with numpy from thanks maciej fijalkowski) - -* reworked per-test output capturing into the pytest_iocapture.py plugin - and thus removed capturing code from config object - -* item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) - - -1.0.0b8 (2009-07-22) -==================== - -* pytest_unittest-plugin is now enabled by default - -* introduced pytest_keyboardinterrupt hook and - refined pytest_sessionfinish hooked, added tests. - -* workaround a buggy logging module interaction ("closing already closed - files"). Thanks to Sridhar Ratnakumar for triggering. - -* if plugins use "py.test.importorskip" for importing - a dependency only a warning will be issued instead - of exiting the testing process. - -* many improvements to docs: - - refined funcargs doc , use the term "factory" instead of "provider" - - added a new talk/tutorial doc page - - better download page - - better plugin docstrings - - added new plugins page and automatic doc generation script - -* fixed teardown problem related to partially failing funcarg setups - (thanks MrTopf for reporting), "pytest_runtest_teardown" is now - always invoked even if the "pytest_runtest_setup" failed. - -* tweaked doctest output for docstrings in py modules, - thanks Radomir. - -1.0.0b7 -======= - -* renamed py.test.xfail back to py.test.mark.xfail to avoid - two ways to decorate for xfail - -* re-added py.test.mark decorator for setting keywords on functions - (it was actually documented so removing it was not nice) - -* remove scope-argument from request.addfinalizer() because - request.cached_setup has the scope arg. TOOWTDI. - -* perform setup finalization before reporting failures - -* apply modified patches from Andreas Kloeckner to allow - test functions to have no func_code (#22) and to make - "-k" and function keywords work (#20) - -* apply patch from Daniel Peolzleithner (issue #23) - -* resolve issue #18, multiprocessing.Manager() and - redirection clash - -* make __name__ == "__channelexec__" for remote_exec code - -1.0.0b3 (2009-06-19) -==================== - -* plugin classes are removed: one now defines - hooks directly in conftest.py or global pytest_*.py - files. - -* added new pytest_namespace(config) hook that allows - to inject helpers directly to the py.test.* namespace. - -* documented and refined many hooks - -* added new style of generative tests via - pytest_generate_tests hook that integrates - well with function arguments. - - -1.0.0b1 -======= - -* introduced new "funcarg" setup method, - see doc/test/funcarg.txt - -* introduced plugin architecture and many - new py.test plugins, see - doc/test/plugins.txt - -* teardown_method is now guaranteed to get - called after a test method has run. - -* new method: py.test.importorskip(mod,minversion) - will either import or call py.test.skip() - -* completely revised internal py.test architecture - -* new py.process.ForkedFunc object allowing to - fork execution of a function to a sub process - and getting a result back. - -XXX lots of things missing here XXX - -0.9.2 -===== - -* refined installation and metadata, created new setup.py, - now based on setuptools/ez_setup (thanks to Ralf Schmitt - for his support). - -* improved the way of making py.* scripts available in - windows environments, they are now added to the - Scripts directory as ".cmd" files. - -* py.path.svnwc.status() now is more complete and - uses xml output from the 'svn' command if available - (Guido Wesdorp) - -* fix for py.path.svn* to work with svn 1.5 - (Chris Lamb) - -* fix path.relto(otherpath) method on windows to - use normcase for checking if a path is relative. - -* py.test's traceback is better parseable from editors - (follows the filenames:LINENO: MSG convention) - (thanks to Osmo Salomaa) - -* fix to javascript-generation, "py.test --runbrowser" - should work more reliably now - -* removed previously accidentally added - py.test.broken and py.test.notimplemented helpers. - -* there now is a py.__version__ attribute - -0.9.1 -===== - -This is a fairly complete list of v0.9.1, which can -serve as a reference for developers. - -* allowing + signs in py.path.svn urls [39106] -* fixed support for Failed exceptions without excinfo in py.test [39340] -* added support for killing processes for Windows (as well as platforms that - support os.kill) in py.misc.killproc [39655] -* added setup/teardown for generative tests to py.test [40702] -* added detection of FAILED TO LOAD MODULE to py.test [40703, 40738, 40739] -* fixed problem with calling .remove() on wcpaths of non-versioned files in - py.path [44248] -* fixed some import and inheritance issues in py.test [41480, 44648, 44655] -* fail to run greenlet tests when pypy is available, but without stackless - [45294] -* small fixes in rsession tests [45295] -* fixed issue with 2.5 type representations in py.test [45483, 45484] -* made that internal reporting issues displaying is done atomically in py.test - [45518] -* made that non-existing files are ignored by the py.lookup script [45519] -* improved exception name creation in py.test [45535] -* made that less threads are used in execnet [merge in 45539] -* removed lock required for atomic reporting issue displaying in py.test - [45545] -* removed globals from execnet [45541, 45547] -* refactored cleanup mechanics, made that setDaemon is set to 1 to make atexit - get called in 2.5 (py.execnet) [45548] -* fixed bug in joining threads in py.execnet's servemain [45549] -* refactored py.test.rsession tests to not rely on exact output format anymore - [45646] -* using repr() on test outcome [45647] -* added 'Reason' classes for py.test.skip() [45648, 45649] -* killed some unnecessary sanity check in py.test.collect [45655] -* avoid using os.tmpfile() in py.io.fdcapture because on Windows it's only - usable by Administrators [45901] -* added support for locking and non-recursive commits to py.path.svnwc [45994] -* locking files in py.execnet to prevent CPython from segfaulting [46010] -* added export() method to py.path.svnurl -* fixed -d -x in py.test [47277] -* fixed argument concatenation problem in py.path.svnwc [49423] -* restore py.test behaviour that it exits with code 1 when there are failures - [49974] -* don't fail on html files that don't have an accompanying .txt file [50606] -* fixed 'utestconvert.py < input' [50645] -* small fix for code indentation in py.code.source [50755] -* fix _docgen.py documentation building [51285] -* improved checks for source representation of code blocks in py.test [51292] -* added support for passing authentication to py.path.svn* objects [52000, - 52001] -* removed sorted() call for py.apigen tests in favour of [].sort() to support - Python 2.3 [52481] diff --git a/third_party/python/pytest/CONTRIBUTING.rst b/third_party/python/pytest/CONTRIBUTING.rst deleted file mode 100644 index c005c2fb2545..000000000000 --- a/third_party/python/pytest/CONTRIBUTING.rst +++ /dev/null @@ -1,294 +0,0 @@ -============================ -Contribution getting started -============================ - -Contributions are highly welcomed and appreciated. Every little help counts, -so do not hesitate! - -.. contents:: Contribution links - :depth: 2 - - -.. _submitfeedback: - -Feature requests and feedback ------------------------------ - -Do you like pytest? Share some love on Twitter or in your blog posts! - -We'd also like to hear about your propositions and suggestions. Feel free to -`submit them as issues `_ and: - -* Explain in detail how they should work. -* Keep the scope as narrow as possible. This will make it easier to implement. - - -.. _reportbugs: - -Report bugs ------------ - -Report bugs for pytest in the `issue tracker `_. - -If you are reporting a bug, please include: - -* Your operating system name and version. -* Any details about your local setup that might be helpful in troubleshooting, - specifically the Python interpreter version, installed libraries, and pytest - version. -* Detailed steps to reproduce the bug. - -If you can write a demonstration test that currently fails but should pass -(xfail), that is a very useful commit to make as well, even if you cannot -fix the bug itself. - - -.. _fixbugs: - -Fix bugs --------- - -Look through the `GitHub issues for bugs `_. - -:ref:`Talk ` to developers to find out how you can fix specific bugs. - -Don't forget to check the issue trackers of your favourite plugins, too! - -.. _writeplugins: - -Implement features ------------------- - -Look through the `GitHub issues for enhancements `_. - -:ref:`Talk ` to developers to find out how you can implement specific -features. - -Write documentation -------------------- - -Pytest could always use more documentation. What exactly is needed? - -* More complementary documentation. Have you perhaps found something unclear? -* Documentation translations. We currently have only English. -* Docstrings. There can never be too many of them. -* Blog posts, articles and such -- they're all very appreciated. - -You can also edit documentation files directly in the GitHub web interface, -without using a local copy. This can be convenient for small fixes. - -.. note:: - Build the documentation locally with the following command: - - .. code:: bash - - $ tox -e docs - - The built documentation should be available in the ``doc/en/_build/``. - - Where 'en' refers to the documentation language. - -.. _submitplugin: - -Submitting Plugins to pytest-dev --------------------------------- - -Pytest development of the core, some plugins and support code happens -in repositories living under the ``pytest-dev`` organisations: - -- `pytest-dev on GitHub `_ - -- `pytest-dev on Bitbucket `_ - -All pytest-dev Contributors team members have write access to all contained -repositories. Pytest core and plugins are generally developed -using `pull requests`_ to respective repositories. - -The objectives of the ``pytest-dev`` organisation are: - -* Having a central location for popular pytest plugins -* Sharing some of the maintenance responsibility (in case a maintainer no - longer wishes to maintain a plugin) - -You can submit your plugin by subscribing to the `pytest-dev mail list -`_ and writing a -mail pointing to your existing pytest plugin repository which must have -the following: - -- PyPI presence with a ``setup.py`` that contains a license, ``pytest-`` - prefixed name, version number, authors, short and long description. - -- a ``tox.ini`` for running tests using `tox `_. - -- a ``README.txt`` describing how to use the plugin and on which - platforms it runs. - -- a ``LICENSE.txt`` file or equivalent containing the licensing - information, with matching info in ``setup.py``. - -- an issue tracker for bug reports and enhancement requests. - -- a `changelog `_ - -If no contributor strongly objects and two agree, the repository can then be -transferred to the ``pytest-dev`` organisation. - -Here's a rundown of how a repository transfer usually proceeds -(using a repository named ``joedoe/pytest-xyz`` as example): - -* ``joedoe`` transfers repository ownership to ``pytest-dev`` administrator ``calvin``. -* ``calvin`` creates ``pytest-xyz-admin`` and ``pytest-xyz-developers`` teams, inviting ``joedoe`` to both as **maintainer**. -* ``calvin`` transfers repository to ``pytest-dev`` and configures team access: - - - ``pytest-xyz-admin`` **admin** access; - - ``pytest-xyz-developers`` **write** access; - -The ``pytest-dev/Contributors`` team has write access to all projects, and -every project administrator is in it. We recommend that each plugin has at least three -people who have the right to release to PyPI. - -Repository owners can rest assured that no ``pytest-dev`` administrator will ever make -releases of your repository or take ownership in any way, except in rare cases -where someone becomes unresponsive after months of contact attempts. -As stated, the objective is to share maintenance and avoid "plugin-abandon". - - -.. _`pull requests`: -.. _pull-requests: - -Preparing Pull Requests ------------------------ - -Short version -~~~~~~~~~~~~~ - -#. Fork the repository. -#. Enable and install `pre-commit `_ to ensure style-guides and code checks are followed. -#. Target ``master`` for bugfixes and doc changes. -#. Target ``features`` for new features or functionality changes. -#. Follow **PEP-8** for naming and `black `_ for formatting. -#. Tests are run using ``tox``:: - - tox -e linting,py27,py36 - - The test environments above are usually enough to cover most cases locally. - -#. Write a ``changelog`` entry: ``changelog/2574.bugfix``, use issue id number - and one of ``bugfix``, ``removal``, ``feature``, ``vendor``, ``doc`` or - ``trivial`` for the issue type. -#. Unless your change is a trivial or a documentation fix (e.g., a typo or reword of a small section) please - add yourself to the ``AUTHORS`` file, in alphabetical order. - - -Long version -~~~~~~~~~~~~ - -What is a "pull request"? It informs the project's core developers about the -changes you want to review and merge. Pull requests are stored on -`GitHub servers `_. -Once you send a pull request, we can discuss its potential modifications and -even add more commits to it later on. There's an excellent tutorial on how Pull -Requests work in the -`GitHub Help Center `_. - -Here is a simple overview, with pytest-specific bits: - -#. Fork the - `pytest GitHub repository `__. It's - fine to use ``pytest`` as your fork repository name because it will live - under your user. - -#. Clone your fork locally using `git `_ and create a branch:: - - $ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git - $ cd pytest - # now, to fix a bug create your own branch off "master": - - $ git checkout -b your-bugfix-branch-name master - - # or to instead add a feature create your own branch off "features": - - $ git checkout -b your-feature-branch-name features - - Given we have "major.minor.micro" version numbers, bugfixes will usually - be released in micro releases whereas features will be released in - minor releases and incompatible changes in major releases. - - If you need some help with Git, follow this quick start - guide: https://git.wiki.kernel.org/index.php/QuickStart - -#. Install `pre-commit `_ and its hook on the pytest repo:: - - $ pip install --user pre-commit - $ pre-commit install - - Afterwards ``pre-commit`` will run whenever you commit. - - https://pre-commit.com/ is a framework for managing and maintaining multi-language pre-commit hooks - to ensure code-style and code formatting is consistent. - -#. Install tox - - Tox is used to run all the tests and will automatically setup virtualenvs - to run the tests in. - (will implicitly use http://www.virtualenv.org/en/latest/):: - - $ pip install tox - -#. Run all the tests - - You need to have Python 2.7 and 3.6 available in your system. Now - running tests is as simple as issuing this command:: - - $ tox -e linting,py27,py36 - - This command will run tests via the "tox" tool against Python 2.7 and 3.6 - and also perform "lint" coding-style checks. - -#. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming. - - You can pass different options to ``tox``. For example, to run tests on Python 2.7 and pass options to pytest - (e.g. enter pdb on failure) to pytest you can do:: - - $ tox -e py27 -- --pdb - - Or to only run tests in a particular test module on Python 3.6:: - - $ tox -e py36 -- testing/test_config.py - - - When committing, ``pre-commit`` will re-format the files if necessary. - -#. Commit and push once your tests pass and you are happy with your change(s):: - - $ git commit -a -m "" - $ git push -u - -#. Create a new changelog entry in ``changelog``. The file should be named ``.``, - where *issueid* is the number of the issue related to the change and *type* is one of - ``bugfix``, ``removal``, ``feature``, ``vendor``, ``doc`` or ``trivial``. - -#. Add yourself to ``AUTHORS`` file if not there yet, in alphabetical order. - -#. Finally, submit a pull request through the GitHub website using this data:: - - head-fork: YOUR_GITHUB_USERNAME/pytest - compare: your-branch-name - - base-fork: pytest-dev/pytest - base: master # if it's a bugfix - base: features # if it's a feature - - -Joining the Development Team ----------------------------- - -Anyone who has successfully seen through a pull request which did not -require any extra work from the development team to merge will -themselves gain commit access if they so wish (if we forget to ask please send a friendly -reminder). This does not mean your workflow to contribute changes, -everyone goes through the same pull-request-and-review process and -no-one merges their own pull requests unless already approved. It does however mean you can -participate in the development process more fully since you can merge -pull requests from other contributors yourself after having reviewed -them. diff --git a/third_party/python/pytest/HOWTORELEASE.rst b/third_party/python/pytest/HOWTORELEASE.rst deleted file mode 100644 index 97bddf7202b1..000000000000 --- a/third_party/python/pytest/HOWTORELEASE.rst +++ /dev/null @@ -1,49 +0,0 @@ -Release Procedure ------------------ - -Our current policy for releasing is to aim for a bugfix every few weeks and a minor release every 2-3 months. The idea -is to get fixes and new features out instead of trying to cram a ton of features into a release and by consequence -taking a lot of time to make a new one. - -.. important:: - - pytest releases must be prepared on **Linux** because the docs and examples expect - to be executed in that platform. - -#. Install development dependencies in a virtual environment with:: - - pip3 install -U -r tasks/requirements.txt - -#. Create a branch ``release-X.Y.Z`` with the version for the release. - - * **patch releases**: from the latest ``master``; - - * **minor releases**: from the latest ``features``; then merge with the latest ``master``; - - Ensure your are in a clean work tree. - -#. Generate docs, changelog, announcements and a **local** tag:: - - invoke generate.pre-release - -#. Open a PR for this branch targeting ``master``. - -#. After all tests pass and the PR has been approved, publish to PyPI by pushing the tag:: - - git push git@github.com:pytest-dev/pytest.git - - Wait for the deploy to complete, then make sure it is `available on PyPI `_. - -#. Send an email announcement with the contents from:: - - doc/en/announce/release-.rst - - To the following mailing lists: - - * pytest-dev@python.org (all releases) - * python-announce-list@python.org (all releases) - * testing-in-python@lists.idyll.org (only major/minor releases) - - And announce it on `Twitter `_ with the ``#pytest`` hashtag. - -#. After a minor/major release, merge ``release-X.Y.Z`` into ``master`` and push (or open a PR). diff --git a/third_party/python/pytest/PKG-INFO b/third_party/python/pytest/PKG-INFO deleted file mode 100644 index 1c50ee34dfa3..000000000000 --- a/third_party/python/pytest/PKG-INFO +++ /dev/null @@ -1,149 +0,0 @@ -Metadata-Version: 1.2 -Name: pytest -Version: 3.6.2 -Summary: pytest: simple powerful testing with Python -Home-page: http://pytest.org -Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others -License: MIT license -Project-URL: Source, https://github.com/pytest-dev/pytest -Project-URL: Tracker, https://github.com/pytest-dev/pytest/issues -Description: .. image:: http://docs.pytest.org/en/latest/_static/pytest1.png - :target: http://docs.pytest.org - :align: center - :alt: pytest - - ------ - - .. image:: https://img.shields.io/pypi/v/pytest.svg - :target: https://pypi.org/project/pytest/ - - .. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg - :target: https://anaconda.org/conda-forge/pytest - - .. image:: https://img.shields.io/pypi/pyversions/pytest.svg - :target: https://pypi.org/project/pytest/ - - .. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg - :target: https://coveralls.io/r/pytest-dev/pytest - - .. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master - :target: https://travis-ci.org/pytest-dev/pytest - - .. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true - :target: https://ci.appveyor.com/project/pytestbot/pytest - - .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/ambv/black - - .. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg - :target: https://www.codetriage.com/pytest-dev/pytest - - The ``pytest`` framework makes it easy to write small tests, yet - scales to support complex functional testing for applications and libraries. - - An example of a simple test: - - .. code-block:: python - - # content of test_sample.py - def inc(x): - return x + 1 - - - def test_answer(): - assert inc(3) == 5 - - - To execute it:: - - $ pytest - ============================= test session starts ============================= - collected 1 items - - test_sample.py F - - ================================== FAILURES =================================== - _________________________________ test_answer _________________________________ - - def test_answer(): - > assert inc(3) == 5 - E assert 4 == 5 - E + where 4 = inc(3) - - test_sample.py:5: AssertionError - ========================== 1 failed in 0.04 seconds =========================== - - - Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started `_ for more examples. - - - Features - -------- - - - Detailed info on failing `assert statements `_ (no need to remember ``self.assert*`` names); - - - `Auto-discovery - `_ - of test modules and functions; - - - `Modular fixtures `_ for - managing small or parametrized long-lived test resources; - - - Can run `unittest `_ (or trial), - `nose `_ test suites out of the box; - - - Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested); - - - Rich plugin architecture, with over 315+ `external plugins `_ and thriving community; - - - Documentation - ------------- - - For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org. - - - Bugs/Requests - ------------- - - Please use the `GitHub issue tracker `_ to submit bugs or request features. - - - Changelog - --------- - - Consult the `Changelog `__ page for fixes and enhancements of each version. - - - License - ------- - - Copyright Holger Krekel and others, 2004-2017. - - Distributed under the terms of the `MIT`_ license, pytest is free and open source software. - - .. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE - -Keywords: test unittest -Platform: unix -Platform: linux -Platform: osx -Platform: cygwin -Platform: win32 -Classifier: Development Status :: 6 - Mature -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Topic :: Software Development :: Testing -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* diff --git a/third_party/python/pytest/src/_pytest/__init__.py b/third_party/python/pytest/_pytest/__init__.py similarity index 100% rename from third_party/python/pytest/src/_pytest/__init__.py rename to third_party/python/pytest/_pytest/__init__.py diff --git a/third_party/python/pytest/src/_pytest/_argcomplete.py b/third_party/python/pytest/_pytest/_argcomplete.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_argcomplete.py rename to third_party/python/pytest/_pytest/_argcomplete.py diff --git a/third_party/python/pytest/src/_pytest/_code/__init__.py b/third_party/python/pytest/_pytest/_code/__init__.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_code/__init__.py rename to third_party/python/pytest/_pytest/_code/__init__.py diff --git a/third_party/python/pytest/src/_pytest/_code/_py2traceback.py b/third_party/python/pytest/_pytest/_code/_py2traceback.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_code/_py2traceback.py rename to third_party/python/pytest/_pytest/_code/_py2traceback.py diff --git a/third_party/python/pytest/src/_pytest/_code/code.py b/third_party/python/pytest/_pytest/_code/code.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_code/code.py rename to third_party/python/pytest/_pytest/_code/code.py diff --git a/third_party/python/pytest/src/_pytest/_code/source.py b/third_party/python/pytest/_pytest/_code/source.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_code/source.py rename to third_party/python/pytest/_pytest/_code/source.py diff --git a/third_party/python/pytest/src/_pytest/_version.py b/third_party/python/pytest/_pytest/_version.py similarity index 100% rename from third_party/python/pytest/src/_pytest/_version.py rename to third_party/python/pytest/_pytest/_version.py diff --git a/third_party/python/pytest/src/_pytest/assertion/__init__.py b/third_party/python/pytest/_pytest/assertion/__init__.py similarity index 100% rename from third_party/python/pytest/src/_pytest/assertion/__init__.py rename to third_party/python/pytest/_pytest/assertion/__init__.py diff --git a/third_party/python/pytest/src/_pytest/assertion/rewrite.py b/third_party/python/pytest/_pytest/assertion/rewrite.py similarity index 100% rename from third_party/python/pytest/src/_pytest/assertion/rewrite.py rename to third_party/python/pytest/_pytest/assertion/rewrite.py diff --git a/third_party/python/pytest/src/_pytest/assertion/truncate.py b/third_party/python/pytest/_pytest/assertion/truncate.py similarity index 100% rename from third_party/python/pytest/src/_pytest/assertion/truncate.py rename to third_party/python/pytest/_pytest/assertion/truncate.py diff --git a/third_party/python/pytest/src/_pytest/assertion/util.py b/third_party/python/pytest/_pytest/assertion/util.py similarity index 100% rename from third_party/python/pytest/src/_pytest/assertion/util.py rename to third_party/python/pytest/_pytest/assertion/util.py diff --git a/third_party/python/pytest/src/_pytest/cacheprovider.py b/third_party/python/pytest/_pytest/cacheprovider.py old mode 100755 new mode 100644 similarity index 100% rename from third_party/python/pytest/src/_pytest/cacheprovider.py rename to third_party/python/pytest/_pytest/cacheprovider.py diff --git a/third_party/python/pytest/src/_pytest/capture.py b/third_party/python/pytest/_pytest/capture.py similarity index 100% rename from third_party/python/pytest/src/_pytest/capture.py rename to third_party/python/pytest/_pytest/capture.py diff --git a/third_party/python/pytest/src/_pytest/compat.py b/third_party/python/pytest/_pytest/compat.py similarity index 100% rename from third_party/python/pytest/src/_pytest/compat.py rename to third_party/python/pytest/_pytest/compat.py diff --git a/third_party/python/pytest/src/_pytest/config/__init__.py b/third_party/python/pytest/_pytest/config/__init__.py similarity index 100% rename from third_party/python/pytest/src/_pytest/config/__init__.py rename to third_party/python/pytest/_pytest/config/__init__.py diff --git a/third_party/python/pytest/src/_pytest/config/argparsing.py b/third_party/python/pytest/_pytest/config/argparsing.py similarity index 100% rename from third_party/python/pytest/src/_pytest/config/argparsing.py rename to third_party/python/pytest/_pytest/config/argparsing.py diff --git a/third_party/python/pytest/src/_pytest/config/exceptions.py b/third_party/python/pytest/_pytest/config/exceptions.py similarity index 100% rename from third_party/python/pytest/src/_pytest/config/exceptions.py rename to third_party/python/pytest/_pytest/config/exceptions.py diff --git a/third_party/python/pytest/src/_pytest/config/findpaths.py b/third_party/python/pytest/_pytest/config/findpaths.py similarity index 100% rename from third_party/python/pytest/src/_pytest/config/findpaths.py rename to third_party/python/pytest/_pytest/config/findpaths.py diff --git a/third_party/python/pytest/src/_pytest/debugging.py b/third_party/python/pytest/_pytest/debugging.py similarity index 100% rename from third_party/python/pytest/src/_pytest/debugging.py rename to third_party/python/pytest/_pytest/debugging.py diff --git a/third_party/python/pytest/src/_pytest/deprecated.py b/third_party/python/pytest/_pytest/deprecated.py similarity index 100% rename from third_party/python/pytest/src/_pytest/deprecated.py rename to third_party/python/pytest/_pytest/deprecated.py diff --git a/third_party/python/pytest/src/_pytest/doctest.py b/third_party/python/pytest/_pytest/doctest.py similarity index 100% rename from third_party/python/pytest/src/_pytest/doctest.py rename to third_party/python/pytest/_pytest/doctest.py diff --git a/third_party/python/pytest/src/_pytest/fixtures.py b/third_party/python/pytest/_pytest/fixtures.py similarity index 100% rename from third_party/python/pytest/src/_pytest/fixtures.py rename to third_party/python/pytest/_pytest/fixtures.py diff --git a/third_party/python/pytest/src/_pytest/freeze_support.py b/third_party/python/pytest/_pytest/freeze_support.py similarity index 100% rename from third_party/python/pytest/src/_pytest/freeze_support.py rename to third_party/python/pytest/_pytest/freeze_support.py diff --git a/third_party/python/pytest/src/_pytest/helpconfig.py b/third_party/python/pytest/_pytest/helpconfig.py similarity index 100% rename from third_party/python/pytest/src/_pytest/helpconfig.py rename to third_party/python/pytest/_pytest/helpconfig.py diff --git a/third_party/python/pytest/src/_pytest/hookspec.py b/third_party/python/pytest/_pytest/hookspec.py similarity index 100% rename from third_party/python/pytest/src/_pytest/hookspec.py rename to third_party/python/pytest/_pytest/hookspec.py diff --git a/third_party/python/pytest/src/_pytest/junitxml.py b/third_party/python/pytest/_pytest/junitxml.py similarity index 100% rename from third_party/python/pytest/src/_pytest/junitxml.py rename to third_party/python/pytest/_pytest/junitxml.py diff --git a/third_party/python/pytest/src/_pytest/logging.py b/third_party/python/pytest/_pytest/logging.py similarity index 100% rename from third_party/python/pytest/src/_pytest/logging.py rename to third_party/python/pytest/_pytest/logging.py diff --git a/third_party/python/pytest/src/_pytest/main.py b/third_party/python/pytest/_pytest/main.py similarity index 100% rename from third_party/python/pytest/src/_pytest/main.py rename to third_party/python/pytest/_pytest/main.py diff --git a/third_party/python/pytest/src/_pytest/mark/__init__.py b/third_party/python/pytest/_pytest/mark/__init__.py similarity index 100% rename from third_party/python/pytest/src/_pytest/mark/__init__.py rename to third_party/python/pytest/_pytest/mark/__init__.py diff --git a/third_party/python/pytest/src/_pytest/mark/evaluate.py b/third_party/python/pytest/_pytest/mark/evaluate.py similarity index 100% rename from third_party/python/pytest/src/_pytest/mark/evaluate.py rename to third_party/python/pytest/_pytest/mark/evaluate.py diff --git a/third_party/python/pytest/src/_pytest/mark/legacy.py b/third_party/python/pytest/_pytest/mark/legacy.py similarity index 100% rename from third_party/python/pytest/src/_pytest/mark/legacy.py rename to third_party/python/pytest/_pytest/mark/legacy.py diff --git a/third_party/python/pytest/src/_pytest/mark/structures.py b/third_party/python/pytest/_pytest/mark/structures.py similarity index 100% rename from third_party/python/pytest/src/_pytest/mark/structures.py rename to third_party/python/pytest/_pytest/mark/structures.py diff --git a/third_party/python/pytest/src/_pytest/monkeypatch.py b/third_party/python/pytest/_pytest/monkeypatch.py similarity index 100% rename from third_party/python/pytest/src/_pytest/monkeypatch.py rename to third_party/python/pytest/_pytest/monkeypatch.py diff --git a/third_party/python/pytest/src/_pytest/nodes.py b/third_party/python/pytest/_pytest/nodes.py similarity index 100% rename from third_party/python/pytest/src/_pytest/nodes.py rename to third_party/python/pytest/_pytest/nodes.py diff --git a/third_party/python/pytest/src/_pytest/nose.py b/third_party/python/pytest/_pytest/nose.py similarity index 100% rename from third_party/python/pytest/src/_pytest/nose.py rename to third_party/python/pytest/_pytest/nose.py diff --git a/third_party/python/pytest/src/_pytest/outcomes.py b/third_party/python/pytest/_pytest/outcomes.py similarity index 100% rename from third_party/python/pytest/src/_pytest/outcomes.py rename to third_party/python/pytest/_pytest/outcomes.py diff --git a/third_party/python/pytest/src/_pytest/pastebin.py b/third_party/python/pytest/_pytest/pastebin.py similarity index 100% rename from third_party/python/pytest/src/_pytest/pastebin.py rename to third_party/python/pytest/_pytest/pastebin.py diff --git a/third_party/python/pytest/src/_pytest/pytester.py b/third_party/python/pytest/_pytest/pytester.py similarity index 100% rename from third_party/python/pytest/src/_pytest/pytester.py rename to third_party/python/pytest/_pytest/pytester.py diff --git a/third_party/python/pytest/src/_pytest/python.py b/third_party/python/pytest/_pytest/python.py similarity index 100% rename from third_party/python/pytest/src/_pytest/python.py rename to third_party/python/pytest/_pytest/python.py diff --git a/third_party/python/pytest/src/_pytest/python_api.py b/third_party/python/pytest/_pytest/python_api.py similarity index 100% rename from third_party/python/pytest/src/_pytest/python_api.py rename to third_party/python/pytest/_pytest/python_api.py diff --git a/third_party/python/pytest/src/_pytest/recwarn.py b/third_party/python/pytest/_pytest/recwarn.py similarity index 100% rename from third_party/python/pytest/src/_pytest/recwarn.py rename to third_party/python/pytest/_pytest/recwarn.py diff --git a/third_party/python/pytest/src/_pytest/resultlog.py b/third_party/python/pytest/_pytest/resultlog.py similarity index 100% rename from third_party/python/pytest/src/_pytest/resultlog.py rename to third_party/python/pytest/_pytest/resultlog.py diff --git a/third_party/python/pytest/src/_pytest/runner.py b/third_party/python/pytest/_pytest/runner.py similarity index 100% rename from third_party/python/pytest/src/_pytest/runner.py rename to third_party/python/pytest/_pytest/runner.py diff --git a/third_party/python/pytest/src/_pytest/setuponly.py b/third_party/python/pytest/_pytest/setuponly.py similarity index 100% rename from third_party/python/pytest/src/_pytest/setuponly.py rename to third_party/python/pytest/_pytest/setuponly.py diff --git a/third_party/python/pytest/src/_pytest/setupplan.py b/third_party/python/pytest/_pytest/setupplan.py similarity index 100% rename from third_party/python/pytest/src/_pytest/setupplan.py rename to third_party/python/pytest/_pytest/setupplan.py diff --git a/third_party/python/pytest/src/_pytest/skipping.py b/third_party/python/pytest/_pytest/skipping.py similarity index 100% rename from third_party/python/pytest/src/_pytest/skipping.py rename to third_party/python/pytest/_pytest/skipping.py diff --git a/third_party/python/pytest/src/_pytest/terminal.py b/third_party/python/pytest/_pytest/terminal.py similarity index 100% rename from third_party/python/pytest/src/_pytest/terminal.py rename to third_party/python/pytest/_pytest/terminal.py diff --git a/third_party/python/pytest/src/_pytest/tmpdir.py b/third_party/python/pytest/_pytest/tmpdir.py similarity index 100% rename from third_party/python/pytest/src/_pytest/tmpdir.py rename to third_party/python/pytest/_pytest/tmpdir.py diff --git a/third_party/python/pytest/src/_pytest/unittest.py b/third_party/python/pytest/_pytest/unittest.py similarity index 100% rename from third_party/python/pytest/src/_pytest/unittest.py rename to third_party/python/pytest/_pytest/unittest.py diff --git a/third_party/python/pytest/src/_pytest/warnings.py b/third_party/python/pytest/_pytest/warnings.py similarity index 100% rename from third_party/python/pytest/src/_pytest/warnings.py rename to third_party/python/pytest/_pytest/warnings.py diff --git a/third_party/python/pytest/appveyor.yml b/third_party/python/pytest/appveyor.yml deleted file mode 100644 index b808fa6d91a9..000000000000 --- a/third_party/python/pytest/appveyor.yml +++ /dev/null @@ -1,48 +0,0 @@ -environment: - COVERALLS_REPO_TOKEN: - secure: 2NJ5Ct55cHJ9WEg3xbSqCuv0rdgzzb6pnzOIG5OkMbTndw3wOBrXntWFoQrXiMFi - # this is pytest's token in coveralls.io, encrypted - # using pytestbot account as detailed here: - # https://www.appveyor.com/docs/build-configuration#secure-variables - - matrix: - # coveralls is not in the default env list - - TOXENV: "coveralls" - # note: please use "tox --listenvs" to populate the build matrix below - - TOXENV: "linting" - - TOXENV: "py27" - - TOXENV: "py34" - - TOXENV: "py35" - - TOXENV: "py36" - - TOXENV: "pypy" - - TOXENV: "py27-pexpect" - - TOXENV: "py27-xdist" - - TOXENV: "py27-trial" - - TOXENV: "py27-numpy" - - TOXENV: "py27-pluggymaster" - - TOXENV: "py36-pexpect" - - TOXENV: "py36-xdist" - - TOXENV: "py36-trial" - - TOXENV: "py36-numpy" - - TOXENV: "py36-pluggymaster" - - TOXENV: "py27-nobyte" - - TOXENV: "doctesting" - - TOXENV: "py35-freeze" - - TOXENV: "docs" - -install: - - echo Installed Pythons - - dir c:\Python* - - - if "%TOXENV%" == "pypy" call scripts\install-pypy.bat - - - C:\Python36\python -m pip install --upgrade --pre tox - -build: false # Not a C# project, build stuff at the test step instead. - -test_script: - - call scripts\call-tox.bat - -cache: - - '%LOCALAPPDATA%\pip\cache' - - '%USERPROFILE%\.cache\pre-commit' diff --git a/third_party/python/pytest/bench/bench.py b/third_party/python/pytest/bench/bench.py deleted file mode 100644 index 4e72444e7d7a..000000000000 --- a/third_party/python/pytest/bench/bench.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys - -if __name__ == "__main__": - import cProfile - import pytest # NOQA - import pstats - - script = sys.argv[1:] if len(sys.argv) > 1 else "empty.py" - stats = cProfile.run("pytest.cmdline.main(%r)" % script, "prof") - p = pstats.Stats("prof") - p.strip_dirs() - p.sort_stats("cumulative") - print(p.print_stats(500)) diff --git a/third_party/python/pytest/bench/bench_argcomplete.py b/third_party/python/pytest/bench/bench_argcomplete.py deleted file mode 100644 index 495e2c4ed3b1..000000000000 --- a/third_party/python/pytest/bench/bench_argcomplete.py +++ /dev/null @@ -1,22 +0,0 @@ - - -# 10000 iterations, just for relative comparison -# 2.7.5 3.3.2 -# FilesCompleter 75.1109 69.2116 -# FastFilesCompleter 0.7383 1.0760 - -import timeit - -imports = [ - "from argcomplete.completers import FilesCompleter as completer", - "from _pytest._argcomplete import FastFilesCompleter as completer", -] - -count = 1000 # only a few seconds -setup = "%s\nfc = completer()" -run = 'fc("/d")' - - -if __name__ == "__main__": - print(timeit.timeit(run, setup=setup % imports[0], number=count)) - print((timeit.timeit(run, setup=setup % imports[1], number=count))) diff --git a/third_party/python/pytest/bench/empty.py b/third_party/python/pytest/bench/empty.py deleted file mode 100644 index b90319936b3e..000000000000 --- a/third_party/python/pytest/bench/empty.py +++ /dev/null @@ -1,4 +0,0 @@ -import py - -for i in range(1000): - py.builtin.exec_("def test_func_%d(): pass" % i) diff --git a/third_party/python/pytest/bench/manyparam.py b/third_party/python/pytest/bench/manyparam.py deleted file mode 100644 index a25b098de868..000000000000 --- a/third_party/python/pytest/bench/manyparam.py +++ /dev/null @@ -1,15 +0,0 @@ - -import pytest - - -@pytest.fixture(scope="module", params=range(966)) -def foo(request): - return request.param - - -def test_it(foo): - pass - - -def test_it2(foo): - pass diff --git a/third_party/python/pytest/bench/skip.py b/third_party/python/pytest/bench/skip.py deleted file mode 100644 index b105e79f82eb..000000000000 --- a/third_party/python/pytest/bench/skip.py +++ /dev/null @@ -1,11 +0,0 @@ -from six.moves import range -import pytest - - -SKIP = True - - -@pytest.mark.parametrize("x", range(5000)) -def test_foo(x): - if SKIP: - pytest.skip("heh") diff --git a/third_party/python/pytest/changelog/README.rst b/third_party/python/pytest/changelog/README.rst deleted file mode 100644 index e34bd4da267c..000000000000 --- a/third_party/python/pytest/changelog/README.rst +++ /dev/null @@ -1,32 +0,0 @@ -This directory contains "newsfragments" which are short files that contain a small **ReST**-formatted -text that will be added to the next ``CHANGELOG``. - -The ``CHANGELOG`` will be read by users, so this description should be aimed to pytest users -instead of describing internal changes which are only relevant to the developers. - -Make sure to use full sentences with correct case and punctuation, for example:: - - Fix issue with non-ascii messages from the ``warnings`` module. - -Each file should be named like ``..rst``, where -```` is an issue number, and ```` is one of: - -* ``feature``: new user facing features, like new command-line options and new behavior. -* ``bugfix``: fixes a reported bug. -* ``doc``: documentation improvement, like rewording an entire session or adding missing docs. -* ``removal``: feature deprecation or removal. -* ``vendor``: changes in packages vendored in pytest. -* ``trivial``: fixing a small typo or internal change that might be noteworthy. - -So for example: ``123.feature.rst``, ``456.bugfix.rst``. - -If your PR fixes an issue, use that number here. If there is no issue, -then after you submit the PR and get the PR number you can add a -changelog using that instead. - -If you are not sure what issue type to use, don't hesitate to ask in your PR. - -Note that the ``towncrier`` tool will automatically -reflow your text, so it will work best if you stick to a single paragraph, but multiple sentences and links are OK -and encouraged. You can install ``towncrier`` and then run ``towncrier --draft`` -if you want to get a preview of how your change will look in the final release notes. diff --git a/third_party/python/pytest/changelog/_template.rst b/third_party/python/pytest/changelog/_template.rst deleted file mode 100644 index a898abc15af1..000000000000 --- a/third_party/python/pytest/changelog/_template.rst +++ /dev/null @@ -1,40 +0,0 @@ -{% for section in sections %} -{% set underline = "-" %} -{% if section %} -{{section}} -{{ underline * section|length }}{% set underline = "~" %} - -{% endif %} -{% if sections[section] %} -{% for category, val in definitions.items() if category in sections[section] %} - -{{ definitions[category]['name'] }} -{{ underline * definitions[category]['name']|length }} - -{% if definitions[category]['showcontent'] %} -{% for text, values in sections[section][category]|dictsort(by='value') %} -{% set issue_joiner = joiner(', ') %} -- {{ text }}{% if category != 'vendor' %} ({% for value in values|sort %}{{ issue_joiner() }}`{{ value }} `_{% endfor %}){% endif %} - - -{% endfor %} -{% else %} -- {{ sections[section][category]['']|sort|join(', ') }} - - -{% endif %} -{% if sections[section][category]|length == 0 %} - -No significant changes. - - -{% else %} -{% endif %} -{% endfor %} -{% else %} - -No significant changes. - - -{% endif %} -{% endfor %} diff --git a/third_party/python/pytest/extra/get_issues.py b/third_party/python/pytest/extra/get_issues.py deleted file mode 100644 index c026972b145d..000000000000 --- a/third_party/python/pytest/extra/get_issues.py +++ /dev/null @@ -1,84 +0,0 @@ -import json -import py -import requests - -issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues" - - -def get_issues(): - issues = [] - url = issues_url - while 1: - get_data = {"state": "all"} - r = requests.get(url, params=get_data) - data = r.json() - if r.status_code == 403: - # API request limit exceeded - print(data["message"]) - exit(1) - issues.extend(data) - - # Look for next page - links = requests.utils.parse_header_links(r.headers["Link"]) - another_page = False - for link in links: - if link["rel"] == "next": - url = link["url"] - another_page = True - if not another_page: - return issues - - -def main(args): - cachefile = py.path.local(args.cache) - if not cachefile.exists() or args.refresh: - issues = get_issues() - cachefile.write(json.dumps(issues)) - else: - issues = json.loads(cachefile.read()) - - open_issues = [x for x in issues if x["state"] == "open"] - - open_issues.sort(key=lambda x: x["number"]) - report(open_issues) - - -def _get_kind(issue): - labels = [l["name"] for l in issue["labels"]] - for key in ("bug", "enhancement", "proposal"): - if key in labels: - return key - return "issue" - - -def report(issues): - for issue in issues: - title = issue["title"] - # body = issue["body"] - kind = _get_kind(issue) - status = issue["state"] - number = issue["number"] - link = "https://github.com/pytest-dev/pytest/issues/%s/" % number - print("----") - print(status, kind, link) - print(title) - # print() - # lines = body.split("\n") - # print ("\n".join(lines[:3])) - # if len(lines) > 3 or len(body) > 240: - # print ("...") - print("\n\nFound %s open issues" % len(issues)) - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser("process bitbucket issues") - parser.add_argument( - "--refresh", action="store_true", help="invalidate cache, refresh issues" - ) - parser.add_argument( - "--cache", action="store", default="issues.json", help="cache file" - ) - args = parser.parse_args() - main(args) diff --git a/third_party/python/pytest/extra/setup-py.test/setup.py b/third_party/python/pytest/extra/setup-py.test/setup.py deleted file mode 100644 index d0560ce1f5f4..000000000000 --- a/third_party/python/pytest/extra/setup-py.test/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys -from distutils.core import setup - -if __name__ == "__main__": - if "sdist" not in sys.argv[1:]: - raise ValueError("please use 'pytest' pypi package instead of 'py.test'") - setup( - name="py.test", - version="0.0", - description="please use 'pytest' for installation", - ) diff --git a/third_party/python/pytest/pyproject.toml b/third_party/python/pytest/pyproject.toml deleted file mode 100644 index 65e6bf59bf1c..000000000000 --- a/third_party/python/pytest/pyproject.toml +++ /dev/null @@ -1,43 +0,0 @@ -[build-system] -requires = [ - "setuptools", - "setuptools-scm", - "wheel", -] - -[tool.towncrier] -package = "pytest" -package_dir = "src" -filename = "CHANGELOG.rst" -directory = "changelog/" -template = "changelog/_template.rst" - - [[tool.towncrier.type]] - directory = "removal" - name = "Deprecations and Removals" - showcontent = true - - [[tool.towncrier.type]] - directory = "feature" - name = "Features" - showcontent = true - - [[tool.towncrier.type]] - directory = "bugfix" - name = "Bug Fixes" - showcontent = true - - [[tool.towncrier.type]] - directory = "vendor" - name = "Vendored Libraries" - showcontent = true - - [[tool.towncrier.type]] - directory = "doc" - name = "Improved Documentation" - showcontent = true - - [[tool.towncrier.type]] - directory = "trivial" - name = "Trivial/Internal Changes" - showcontent = true diff --git a/third_party/python/pytest/LICENSE b/third_party/python/pytest/pytest-3.6.2.dist-info/LICENSE.txt similarity index 100% rename from third_party/python/pytest/LICENSE rename to third_party/python/pytest/pytest-3.6.2.dist-info/LICENSE.txt diff --git a/third_party/python/pytest/README.rst b/third_party/python/pytest/pytest-3.6.2.dist-info/METADATA similarity index 68% rename from third_party/python/pytest/README.rst rename to third_party/python/pytest/pytest-3.6.2.dist-info/METADATA index 564ffff6c91e..1ee092eee089 100644 --- a/third_party/python/pytest/README.rst +++ b/third_party/python/pytest/pytest-3.6.2.dist-info/METADATA @@ -1,3 +1,45 @@ +Metadata-Version: 2.1 +Name: pytest +Version: 3.6.2 +Summary: pytest: simple powerful testing with Python +Home-page: http://pytest.org +Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others +License: MIT license +Project-URL: Source, https://github.com/pytest-dev/pytest +Project-URL: Tracker, https://github.com/pytest-dev/pytest/issues +Keywords: test unittest +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: py (>=1.5.0) +Requires-Dist: six (>=1.10.0) +Requires-Dist: setuptools +Requires-Dist: attrs (>=17.4.0) +Requires-Dist: more-itertools (>=4.0.0) +Requires-Dist: atomicwrites (>=1.0) +Requires-Dist: pluggy (<0.7,>=0.5) +Requires-Dist: funcsigs; python_version < "3.0" +Requires-Dist: colorama; sys_platform == "win32" + .. image:: http://docs.pytest.org/en/latest/_static/pytest1.png :target: http://docs.pytest.org :align: center @@ -114,3 +156,5 @@ Copyright Holger Krekel and others, 2004-2017. Distributed under the terms of the `MIT`_ license, pytest is free and open source software. .. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE + + diff --git a/third_party/python/pytest/pytest-3.6.2.dist-info/RECORD b/third_party/python/pytest/pytest-3.6.2.dist-info/RECORD new file mode 100644 index 000000000000..42e3075a5a99 --- /dev/null +++ b/third_party/python/pytest/pytest-3.6.2.dist-info/RECORD @@ -0,0 +1,57 @@ +pytest.py,sha256=YBrSVQt3T_bFrRtbffILY-SfCMWKlw-3OfmYG__tVFw,1712 +_pytest/__init__.py,sha256=6Ff5v_9CZKpy1l87AT5cIHOfMA9kdTtzhl2G3QjYC9Q,239 +_pytest/_argcomplete.py,sha256=CJBB2CZEqv_inTyr3g1oMyxXQfLIxoPnUatOqKBrIqw,3680 +_pytest/_version.py,sha256=DfJn09gV_fhIsyix22gb8OZwiBxNIC8d8mw0a2gXs8Y,116 +_pytest/cacheprovider.py,sha256=DtZkuqXACcgD2FUXCEU-KRWOKRh35nsHajthvWDLKcg,12002 +_pytest/capture.py,sha256=hLarnC5RP_gd9Sjviofiz8Lv2FmHkIsydLuKtYAs7Z0,23624 +_pytest/compat.py,sha256=8KBifrhG1fCP1i_rrpkyOFfhvZPFqxDptXzRM_MFabI,10851 +_pytest/debugging.py,sha256=PymqXO0ijvOCnmHV7eVEJaGS1YWcMH7yItnKeh_k-Mc,5038 +_pytest/deprecated.py,sha256=0nyCEVEz73lcQ80Qr6MgWT4TEpqNLeZtkeYolXouEYM,2604 +_pytest/doctest.py,sha256=qfl2mVBh_FWmsLJWKkRlGSgFNsyda4wrVjl7DEkUcrw,17010 +_pytest/fixtures.py,sha256=LEgEqSe80mzsozWHkUTOBqWWuN_qF_eBhy3Zbhzrvz4,46907 +_pytest/freeze_support.py,sha256=a_KBi4RpqWc7TmAiidK0PkGkwYL2XJjXbVd2TkbSK24,1195 +_pytest/helpconfig.py,sha256=K7eG4T4Sqvu4vJEDmDa55xVzxguvXWWjtbGETrCwWnY,6694 +_pytest/hookspec.py,sha256=nXT3RdhpjbSr3tFQw7AAZD8XYdDnnheAlew3ulyBFMA,18334 +_pytest/junitxml.py,sha256=0uSRC_nrNPOdkTaYcQYFg91I1foiT0qcB8LDK1iMicQ,19055 +_pytest/logging.py,sha256=nNd2WKqmdZcY6KyDr9_RbNMj61nSX4u8VCa953XCWuk,19604 +_pytest/main.py,sha256=tPFInF1LgdQXwgSeoh8W3nkB6tyv7XL0c85BlPoaAhA,20405 +_pytest/monkeypatch.py,sha256=hC8RnW4CKvjFVgYbwrsU-5Tj-QR2waBCrA8AiUVwHlE,9814 +_pytest/nodes.py,sha256=-ZfG9iin1Sm1F9DOzRGDnutAwslNHItE9qNOVmYqE8A,13926 +_pytest/nose.py,sha256=VY0r1CgEevAVwcWybQPjlG7w7ut0FukGTaPNBAxYFUk,2589 +_pytest/outcomes.py,sha256=2B-I2c1UUFGvcmtp_MRP8skKc4-ys7VDfxTcvf-G2DM,4808 +_pytest/pastebin.py,sha256=rGpJbZOlMUT9Edx2x856qKviuwiMaa1F0uC026raXbE,3631 +_pytest/pytester.py,sha256=HOqRhMXTO3lqHlj-976_RX2Jl5Lj02mFB467T11jvqw,42622 +_pytest/python.py,sha256=4d7_3aRaoLVQ9UM5UI3FTsIL2_DfzQ4ML77_9_FoGQg,47552 +_pytest/python_api.py,sha256=50XZUpLmM1Z9auYAWoOPUq3vu9ti0klMEUWJGrZya28,24587 +_pytest/recwarn.py,sha256=VbwFSUt4cSqIILTMPrTPOLDnhVoInmI5LHIrC5xNJBw,8634 +_pytest/resultlog.py,sha256=HT6BFiW3Ye4aLBLhh4kbTM9TysuEuEGkBpjxypMPlq8,3725 +_pytest/runner.py,sha256=qRX4eOehQgy3RYoypCcpXC7J0XHSZBUXJU7gao8UEYU,17438 +_pytest/setuponly.py,sha256=nRqc_nSiuEbgk5gBR2LZE8aO9t9Ku8Dn6xd0STRM2Aw,2623 +_pytest/setupplan.py,sha256=UGXXmoK26N0mcTmImB8pBNvpvkZNJbUau-kncnDhlcw,823 +_pytest/skipping.py,sha256=B6s_ZMmMxtUJkyAmi1LttWGnSM5B4SCQ4XEUPPSO_oI,10063 +_pytest/terminal.py,sha256=56ScwcB4s9YddbuIet9saWkFifC2RP_-xnKZZQFMIMo,28715 +_pytest/tmpdir.py,sha256=H0Q8UylCgAahCR0YOzJGxEPPtD5mKT1zU-FDTxqwH0I,4266 +_pytest/unittest.py,sha256=i4hc6OTdNTqKSINwcGCTH6mrSrJPZr-8nCV5oEtk8RE,8605 +_pytest/warnings.py,sha256=497RsSxi70za9cbJVYax94u_c8MBV4Ys4kq9Jdy8NS8,3348 +_pytest/_code/__init__.py,sha256=xc4AtbMH64T0uj93rM06vh-wVInRayAbXpmamDyWWiQ,410 +_pytest/_code/_py2traceback.py,sha256=iizm_cST-lSuMls8-LSnPaNIY7QCQ85htO-X1TfMSCk,3005 +_pytest/_code/code.py,sha256=nZjRJ477VjTdvDs4Ub6gGQOrm2SP6BvDRd0xNEaUOKM,32343 +_pytest/_code/source.py,sha256=0FHKagM-luZB02Baep4Ap3Em6gV9FL6ipLhX2BXCzYs,12165 +_pytest/assertion/__init__.py,sha256=whd3-W2bghH1iUjKNwyXJ2SI4JgOwPxEyZt9Z7wGsH8,5125 +_pytest/assertion/rewrite.py,sha256=lW8Qf4lomseoyMasil5l_ixyv8KjLLH77h3UIsUjsjk,35779 +_pytest/assertion/truncate.py,sha256=4AEAgi_CrxA__AwDTBZsBthVQXTuBmZowt4IES9_OaI,3331 +_pytest/assertion/util.py,sha256=p5N8w4uVDKQfjasYnY1AUeNToA4jphnS08szXkotWig,11492 +_pytest/config/__init__.py,sha256=AO-2uTePLDzE5E3zsqrYplY1u5FJiNaw9RHpbUTitm8,34116 +_pytest/config/argparsing.py,sha256=-1PQgLAn_Qvd-QNBzL-BR4ii9A0vXbqX5m2_fi96ZJE,15141 +_pytest/config/exceptions.py,sha256=yoOMMMqagB6CNNHD8P4FxKPHqAIMV80fJ8aBLCIlIVs,228 +_pytest/config/findpaths.py,sha256=_0G9yTbZfVBwpfRf9fE9V8cIwBTOq8n7wrxZgLFZyrY,5010 +_pytest/mark/__init__.py,sha256=WxGz2ObFuHvGrab3eMRcLwVQ7xYZNztC5_Z46PvTxsk,5165 +_pytest/mark/evaluate.py,sha256=OnAMeEKQ0xd40nLpCtNT0plnmt-iJHdIIkr5iUn17_0,3771 +_pytest/mark/legacy.py,sha256=EQ5GUOi-ZUwJ3nporDfQN07iUY2SlAzYXUFlehoeEVc,3046 +_pytest/mark/structures.py,sha256=oZa1pNZ6UGble4icXvweJ7DGA202V2OAoKqdPrjHT68,13195 +pytest-3.6.2.dist-info/LICENSE.txt,sha256=oevOFa_Htc-Yx8beUS0ZWdS_YduMa_LxEShtSDtAqZc,1096 +pytest-3.6.2.dist-info/METADATA,sha256=PNGlCITpmB2LtGQtuG2jrtDCryfYefNGl3Lsi8RI7AI,5314 +pytest-3.6.2.dist-info/RECORD,, +pytest-3.6.2.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110 +pytest-3.6.2.dist-info/entry_points.txt,sha256=axdK_VT5P2oD8QJv5r7o8lo9DC45aJ2uvB3vpTP-qSE,62 +pytest-3.6.2.dist-info/top_level.txt,sha256=ENE0IeZV1I1R61DOt8gs5KmSXwitaq2zstF0az5f9PA,15 diff --git a/third_party/python/pytest/pytest-3.6.2.dist-info/WHEEL b/third_party/python/pytest/pytest-3.6.2.dist-info/WHEEL new file mode 100644 index 000000000000..1316c41d0706 --- /dev/null +++ b/third_party/python/pytest/pytest-3.6.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/pytest/pytest-3.6.2.dist-info/entry_points.txt b/third_party/python/pytest/pytest-3.6.2.dist-info/entry_points.txt new file mode 100644 index 000000000000..d8e4fd298fe6 --- /dev/null +++ b/third_party/python/pytest/pytest-3.6.2.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +py.test = pytest:main +pytest = pytest:main + diff --git a/third_party/python/pytest/pytest-3.6.2.dist-info/top_level.txt b/third_party/python/pytest/pytest-3.6.2.dist-info/top_level.txt new file mode 100644 index 000000000000..e94857af9646 --- /dev/null +++ b/third_party/python/pytest/pytest-3.6.2.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_pytest +pytest diff --git a/third_party/python/pytest/src/pytest.py b/third_party/python/pytest/pytest.py similarity index 100% rename from third_party/python/pytest/src/pytest.py rename to third_party/python/pytest/pytest.py diff --git a/third_party/python/pytest/scripts/call-tox.bat b/third_party/python/pytest/scripts/call-tox.bat deleted file mode 100644 index 86fb25c1df1d..000000000000 --- a/third_party/python/pytest/scripts/call-tox.bat +++ /dev/null @@ -1,8 +0,0 @@ -REM skip "coveralls" run in PRs or forks -if "%TOXENV%" == "coveralls" ( - if not defined COVERALLS_REPO_TOKEN ( - echo skipping coveralls run because COVERALLS_REPO_TOKEN is not defined - exit /b 0 - ) -) -C:\Python36\python -m tox diff --git a/third_party/python/pytest/scripts/install-pypy.bat b/third_party/python/pytest/scripts/install-pypy.bat deleted file mode 100644 index 8012ea46aca4..000000000000 --- a/third_party/python/pytest/scripts/install-pypy.bat +++ /dev/null @@ -1,6 +0,0 @@ -REM install pypy using choco -REM redirect to a file because choco install python.pypy is too noisy. If the command fails, write output to console -choco install python.pypy > pypy-inst.log 2>&1 || (type pypy-inst.log & exit /b 1) -set PATH=C:\tools\pypy\pypy;%PATH% # so tox can find pypy -echo PyPy installed -pypy --version diff --git a/third_party/python/pytest/setup.cfg b/third_party/python/pytest/setup.cfg deleted file mode 100644 index e52a837592bc..000000000000 --- a/third_party/python/pytest/setup.cfg +++ /dev/null @@ -1,25 +0,0 @@ -[build_sphinx] -source-dir = doc/en/ -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/en/build/html - -[bdist_wheel] -universal = 1 - -[check-manifest] -ignore = - _pytest/_version.py - -[metadata] -license_file = LICENSE - -[devpi:upload] -formats = sdist.tgz,bdist_wheel - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/pytest/setup.py b/third_party/python/pytest/setup.py deleted file mode 100644 index 3d60d6becf84..000000000000 --- a/third_party/python/pytest/setup.py +++ /dev/null @@ -1,124 +0,0 @@ -import os -import sys -import setuptools -import pkg_resources -from setuptools import setup - -classifiers = [ - "Development Status :: 6 - Mature", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: POSIX", - "Operating System :: Microsoft :: Windows", - "Operating System :: MacOS :: MacOS X", - "Topic :: Software Development :: Testing", - "Topic :: Software Development :: Libraries", - "Topic :: Utilities", -] + [ - ("Programming Language :: Python :: %s" % x) - for x in "2 2.7 3 3.4 3.5 3.6 3.7".split() -] - -with open("README.rst") as fd: - long_description = fd.read() - - -def get_environment_marker_support_level(): - """ - Tests how well setuptools supports PEP-426 environment marker. - - The first known release to support it is 0.7 (and the earliest on PyPI seems to be 0.7.2 - so we're using that), see: https://setuptools.readthedocs.io/en/latest/history.html#id350 - - The support is later enhanced to allow direct conditional inclusions inside install_requires, - which is now recommended by setuptools. It first appeared in 36.2.0, went broken with 36.2.1, and - again worked since 36.2.2, so we're using that. See: - https://setuptools.readthedocs.io/en/latest/history.html#v36-2-2 - https://github.com/pypa/setuptools/issues/1099 - - References: - - * https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies - * https://www.python.org/dev/peps/pep-0426/#environment-markers - * https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies - """ - try: - version = pkg_resources.parse_version(setuptools.__version__) - if version >= pkg_resources.parse_version("36.2.2"): - return 2 - if version >= pkg_resources.parse_version("0.7.2"): - return 1 - except Exception as exc: - sys.stderr.write("Could not test setuptool's version: %s\n" % exc) - - # as of testing on 2018-05-26 fedora was on version 37* and debian was on version 33+ - # we should consider erroring on those - return 0 - - -def main(): - extras_require = {} - install_requires = [ - "py>=1.5.0", - "six>=1.10.0", - "setuptools", - "attrs>=17.4.0", - "more-itertools>=4.0.0", - "atomicwrites>=1.0", - ] - # if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy; - # used by tox.ini to test with pluggy master - if "_PYTEST_SETUP_SKIP_PLUGGY_DEP" not in os.environ: - install_requires.append("pluggy>=0.5,<0.7") - environment_marker_support_level = get_environment_marker_support_level() - if environment_marker_support_level >= 2: - install_requires.append('funcsigs;python_version<"3.0"') - install_requires.append('colorama;sys_platform=="win32"') - elif environment_marker_support_level == 1: - extras_require[':python_version<"3.0"'] = ["funcsigs"] - extras_require[':sys_platform=="win32"'] = ["colorama"] - else: - if sys.platform == "win32": - install_requires.append("colorama") - if sys.version_info < (3, 0): - install_requires.append("funcsigs") - - setup( - name="pytest", - description="pytest: simple powerful testing with Python", - long_description=long_description, - use_scm_version={"write_to": "src/_pytest/_version.py"}, - url="http://pytest.org", - project_urls={ - "Source": "https://github.com/pytest-dev/pytest", - "Tracker": "https://github.com/pytest-dev/pytest/issues", - }, - license="MIT license", - platforms=["unix", "linux", "osx", "cygwin", "win32"], - author=( - "Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, " - "Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others" - ), - entry_points={"console_scripts": ["pytest=pytest:main", "py.test=pytest:main"]}, - classifiers=classifiers, - keywords="test unittest", - # the following should be enabled for release - setup_requires=["setuptools-scm"], - package_dir={"": "src"}, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", - install_requires=install_requires, - extras_require=extras_require, - packages=[ - "_pytest", - "_pytest.assertion", - "_pytest._code", - "_pytest.mark", - "_pytest.config", - ], - py_modules=["pytest"], - zip_safe=False, - ) - - -if __name__ == "__main__": - main() diff --git a/third_party/python/pytest/tasks/__init__.py b/third_party/python/pytest/tasks/__init__.py deleted file mode 100644 index ea5b1293e33e..000000000000 --- a/third_party/python/pytest/tasks/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -Invoke tasks to help with pytest development and release process. -""" - -import invoke - -from . import generate - - -ns = invoke.Collection(generate) diff --git a/third_party/python/pytest/tasks/generate.py b/third_party/python/pytest/tasks/generate.py deleted file mode 100644 index 398af70c9427..000000000000 --- a/third_party/python/pytest/tasks/generate.py +++ /dev/null @@ -1,118 +0,0 @@ -""" -Invoke development tasks. -""" -from pathlib import Path -from subprocess import check_output, check_call - -import invoke - - -@invoke.task(help={"version": "version being released"}) -def announce(ctx, version): - """Generates a new release announcement entry in the docs.""" - # Get our list of authors - stdout = check_output(["git", "describe", "--abbrev=0", "--tags"]) - stdout = stdout.decode("utf-8") - last_version = stdout.strip() - - stdout = check_output( - ["git", "log", "{}..HEAD".format(last_version), "--format=%aN"] - ) - stdout = stdout.decode("utf-8") - - contributors = set(stdout.splitlines()) - - template_name = "release.minor.rst" if version.endswith( - ".0" - ) else "release.patch.rst" - template_text = Path(__file__).parent.joinpath(template_name).read_text( - encoding="UTF-8" - ) - - contributors_text = "\n".join( - "* {}".format(name) for name in sorted(contributors) - ) + "\n" - text = template_text.format(version=version, contributors=contributors_text) - - target = Path(__file__).parent.joinpath( - "../doc/en/announce/release-{}.rst".format(version) - ) - target.write_text(text, encoding="UTF-8") - print("[generate.announce] Generated {}".format(target.name)) - - # Update index with the new release entry - index_path = Path(__file__).parent.joinpath("../doc/en/announce/index.rst") - lines = index_path.read_text(encoding="UTF-8").splitlines() - indent = " " - for index, line in enumerate(lines): - if line.startswith("{}release-".format(indent)): - new_line = indent + target.stem - if line != new_line: - lines.insert(index, new_line) - index_path.write_text("\n".join(lines) + "\n", encoding="UTF-8") - print("[generate.announce] Updated {}".format(index_path.name)) - else: - print( - "[generate.announce] Skip {} (already contains release)".format( - index_path.name - ) - ) - break - - check_call(["git", "add", str(target)]) - - -@invoke.task() -def regen(ctx): - """Call regendoc tool to update examples and pytest output in the docs.""" - print("[generate.regen] Updating docs") - check_call(["tox", "-e", "regen"]) - - -@invoke.task() -def make_tag(ctx, version): - """Create a new, local tag for the release, only if the repository is clean.""" - from git import Repo - - repo = Repo(".") - if repo.is_dirty(): - print("Current repository is dirty. Please commit any changes and try again.") - raise invoke.Exit(code=2) - - tag_names = [x.name for x in repo.tags] - if version in tag_names: - print("[generate.make_tag] Delete existing tag {}".format(version)) - repo.delete_tag(version) - - print("[generate.make_tag] Create tag {}".format(version)) - repo.create_tag(version) - - -@invoke.task(help={"version": "version being released"}) -def pre_release(ctx, version): - """Generates new docs, release announcements and creates a local tag.""" - announce(ctx, version) - regen(ctx) - changelog(ctx, version, write_out=True) - - msg = "Preparing release version {}".format(version) - check_call(["git", "commit", "-a", "-m", msg]) - - make_tag(ctx, version) - - print() - print("[generate.pre_release] Please push your branch and open a PR.") - - -@invoke.task( - help={ - "version": "version being released", - "write_out": "write changes to the actual changelog", - } -) -def changelog(ctx, version, write_out=False): - if write_out: - addopts = [] - else: - addopts = ["--draft"] - check_call(["towncrier", "--yes", "--version", version] + addopts) diff --git a/third_party/python/pytest/tasks/release.minor.rst b/third_party/python/pytest/tasks/release.minor.rst deleted file mode 100644 index bdd8282cfad9..000000000000 --- a/third_party/python/pytest/tasks/release.minor.rst +++ /dev/null @@ -1,27 +0,0 @@ -pytest-{version} -======================================= - -The pytest team is proud to announce the {version} release! - -pytest is a mature Python testing tool with more than a 2000 tests -against itself, passing on many different interpreters and platforms. - -This release contains a number of bugs fixes and improvements, so users are encouraged -to take a look at the CHANGELOG: - - http://doc.pytest.org/en/latest/changelog.html - -For complete documentation, please visit: - - http://docs.pytest.org - -As usual, you can upgrade from pypi via: - - pip install -U pytest - -Thanks to all who contributed to this release, among them: - -{contributors} - -Happy testing, -The Pytest Development Team diff --git a/third_party/python/pytest/tasks/release.patch.rst b/third_party/python/pytest/tasks/release.patch.rst deleted file mode 100644 index 1982dc353c4b..000000000000 --- a/third_party/python/pytest/tasks/release.patch.rst +++ /dev/null @@ -1,17 +0,0 @@ -pytest-{version} -======================================= - -pytest {version} has just been released to PyPI. - -This is a bug-fix release, being a drop-in replacement. To upgrade:: - - pip install --upgrade pytest - -The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. - -Thanks to all who contributed to this release, among them: - -{contributors} - -Happy testing, -The pytest Development Team diff --git a/third_party/python/pytest/tasks/requirements.txt b/third_party/python/pytest/tasks/requirements.txt deleted file mode 100644 index db54e76e85c8..000000000000 --- a/third_party/python/pytest/tasks/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ --e . -gitpython -invoke -towncrier -tox -wheel diff --git a/third_party/python/pytest/testing/acceptance_test.py b/third_party/python/pytest/testing/acceptance_test.py deleted file mode 100644 index c2eed419c9cb..000000000000 --- a/third_party/python/pytest/testing/acceptance_test.py +++ /dev/null @@ -1,1066 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function -import os -import sys -import types - -import six - -import _pytest._code -import py -import pytest -from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR - - -class TestGeneralUsage(object): - - def test_config_error(self, testdir): - testdir.makeconftest( - """ - def pytest_configure(config): - import pytest - raise pytest.UsageError("hello") - """ - ) - result = testdir.runpytest(testdir.tmpdir) - assert result.ret != 0 - result.stderr.fnmatch_lines(["*ERROR: hello"]) - - def test_root_conftest_syntax_error(self, testdir): - testdir.makepyfile(conftest="raise SyntaxError\n") - result = testdir.runpytest() - result.stderr.fnmatch_lines(["*raise SyntaxError*"]) - assert result.ret != 0 - - def test_early_hook_error_issue38_1(self, testdir): - testdir.makeconftest( - """ - def pytest_sessionstart(): - 0 / 0 - """ - ) - result = testdir.runpytest(testdir.tmpdir) - assert result.ret != 0 - # tracestyle is native by default for hook failures - result.stdout.fnmatch_lines( - ["*INTERNALERROR*File*conftest.py*line 2*", "*0 / 0*"] - ) - result = testdir.runpytest(testdir.tmpdir, "--fulltrace") - assert result.ret != 0 - # tracestyle is native by default for hook failures - result.stdout.fnmatch_lines( - ["*INTERNALERROR*def pytest_sessionstart():*", "*INTERNALERROR*0 / 0*"] - ) - - def test_early_hook_configure_error_issue38(self, testdir): - testdir.makeconftest( - """ - def pytest_configure(): - 0 / 0 - """ - ) - result = testdir.runpytest(testdir.tmpdir) - assert result.ret != 0 - # here we get it on stderr - result.stderr.fnmatch_lines( - ["*INTERNALERROR*File*conftest.py*line 2*", "*0 / 0*"] - ) - - def test_file_not_found(self, testdir): - result = testdir.runpytest("asd") - assert result.ret != 0 - result.stderr.fnmatch_lines(["ERROR: file not found*asd"]) - - def test_file_not_found_unconfigure_issue143(self, testdir): - testdir.makeconftest( - """ - def pytest_configure(): - print("---configure") - def pytest_unconfigure(): - print("---unconfigure") - """ - ) - result = testdir.runpytest("-s", "asd") - assert result.ret == 4 # EXIT_USAGEERROR - result.stderr.fnmatch_lines(["ERROR: file not found*asd"]) - result.stdout.fnmatch_lines(["*---configure", "*---unconfigure"]) - - def test_config_preparse_plugin_option(self, testdir): - testdir.makepyfile( - pytest_xyz=""" - def pytest_addoption(parser): - parser.addoption("--xyz", dest="xyz", action="store") - """ - ) - testdir.makepyfile( - test_one=""" - def test_option(pytestconfig): - assert pytestconfig.option.xyz == "123" - """ - ) - result = testdir.runpytest("-p", "pytest_xyz", "--xyz=123", syspathinsert=True) - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_assertion_magic(self, testdir): - p = testdir.makepyfile( - """ - def test_this(): - x = 0 - assert x - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["> assert x", "E assert 0"]) - assert result.ret == 1 - - def test_nested_import_error(self, testdir): - p = testdir.makepyfile( - """ - import import_fails - def test_this(): - assert import_fails.a == 1 - """ - ) - testdir.makepyfile(import_fails="import does_not_work") - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - # XXX on jython this fails: "> import import_fails", - "ImportError while importing test module*", - "*No module named *does_not_work*", - ] - ) - assert result.ret == 2 - - def test_not_collectable_arguments(self, testdir): - p1 = testdir.makepyfile("") - p2 = testdir.makefile(".pyc", "123") - result = testdir.runpytest(p1, p2) - assert result.ret - result.stderr.fnmatch_lines(["*ERROR: not found:*%s" % (p2.basename,)]) - - def test_issue486_better_reporting_on_conftest_load_failure(self, testdir): - testdir.makepyfile("") - testdir.makeconftest("import qwerty") - result = testdir.runpytest("--help") - result.stdout.fnmatch_lines( - """ - *--version* - *warning*conftest.py* - """ - ) - result = testdir.runpytest() - result.stderr.fnmatch_lines( - """ - *ERROR*could not load*conftest.py* - """ - ) - - def test_early_skip(self, testdir): - testdir.mkdir("xyz") - testdir.makeconftest( - """ - import pytest - def pytest_collect_directory(): - pytest.skip("early") - """ - ) - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stdout.fnmatch_lines(["*1 skip*"]) - - def test_issue88_initial_file_multinodes(self, testdir): - testdir.makeconftest( - """ - import pytest - class MyFile(pytest.File): - def collect(self): - return [MyItem("hello", parent=self)] - def pytest_collect_file(path, parent): - return MyFile(path, parent) - class MyItem(pytest.Item): - pass - """ - ) - p = testdir.makepyfile("def test_hello(): pass") - result = testdir.runpytest(p, "--collect-only") - result.stdout.fnmatch_lines(["*MyFile*test_issue88*", "*Module*test_issue88*"]) - - def test_issue93_initialnode_importing_capturing(self, testdir): - testdir.makeconftest( - """ - import sys - print ("should not be seen") - sys.stderr.write("stder42\\n") - """ - ) - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - assert "should not be seen" not in result.stdout.str() - assert "stderr42" not in result.stderr.str() - - def test_conftest_printing_shows_if_error(self, testdir): - testdir.makeconftest( - """ - print ("should be seen") - assert 0 - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - assert "should be seen" in result.stdout.str() - - @pytest.mark.skipif( - not hasattr(py.path.local, "mksymlinkto"), - reason="symlink not available on this platform", - ) - def test_chdir(self, testdir): - testdir.tmpdir.join("py").mksymlinkto(py._pydir) - p = testdir.tmpdir.join("main.py") - p.write( - _pytest._code.Source( - """ - import sys, os - sys.path.insert(0, '') - import py - print (py.__file__) - print (py.__path__) - os.chdir(os.path.dirname(os.getcwd())) - print (py.log) - """ - ) - ) - result = testdir.runpython(p) - assert not result.ret - - def test_issue109_sibling_conftests_not_loaded(self, testdir): - sub1 = testdir.mkdir("sub1") - sub2 = testdir.mkdir("sub2") - sub1.join("conftest.py").write("assert 0") - result = testdir.runpytest(sub2) - assert result.ret == EXIT_NOTESTSCOLLECTED - sub2.ensure("__init__.py") - p = sub2.ensure("test_hello.py") - result = testdir.runpytest(p) - assert result.ret == EXIT_NOTESTSCOLLECTED - result = testdir.runpytest(sub1) - assert result.ret == EXIT_USAGEERROR - - def test_directory_skipped(self, testdir): - testdir.makeconftest( - """ - import pytest - def pytest_ignore_collect(): - pytest.skip("intentional") - """ - ) - testdir.makepyfile("def test_hello(): pass") - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stdout.fnmatch_lines(["*1 skipped*"]) - - def test_multiple_items_per_collector_byid(self, testdir): - c = testdir.makeconftest( - """ - import pytest - class MyItem(pytest.Item): - def runtest(self): - pass - class MyCollector(pytest.File): - def collect(self): - return [MyItem(name="xyz", parent=self)] - def pytest_collect_file(path, parent): - if path.basename.startswith("conftest"): - return MyCollector(path, parent) - """ - ) - result = testdir.runpytest(c.basename + "::" + "xyz") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 pass*"]) - - def test_skip_on_generated_funcarg_id(self, testdir): - testdir.makeconftest( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.addcall({'x': 3}, id='hello-123') - def pytest_runtest_setup(item): - print (item.keywords) - if 'hello-123' in item.keywords: - pytest.skip("hello") - assert 0 - """ - ) - p = testdir.makepyfile("""def test_func(x): pass""") - res = testdir.runpytest(p) - assert res.ret == 0 - res.stdout.fnmatch_lines(["*1 skipped*"]) - - def test_direct_addressing_selects(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall({'i': 1}, id="1") - metafunc.addcall({'i': 2}, id="2") - def test_func(i): - pass - """ - ) - res = testdir.runpytest(p.basename + "::" + "test_func[1]") - assert res.ret == 0 - res.stdout.fnmatch_lines(["*1 passed*"]) - - def test_direct_addressing_notfound(self, testdir): - p = testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - res = testdir.runpytest(p.basename + "::" + "test_notfound") - assert res.ret - res.stderr.fnmatch_lines(["*ERROR*not found*"]) - - def test_docstring_on_hookspec(self): - from _pytest import hookspec - - for name, value in vars(hookspec).items(): - if name.startswith("pytest_"): - assert value.__doc__, "no docstring for %s" % name - - def test_initialization_error_issue49(self, testdir): - testdir.makeconftest( - """ - def pytest_configure(): - x - """ - ) - result = testdir.runpytest() - assert result.ret == 3 # internal error - result.stderr.fnmatch_lines(["INTERNAL*pytest_configure*", "INTERNAL*x*"]) - assert "sessionstarttime" not in result.stderr.str() - - @pytest.mark.parametrize("lookfor", ["test_fun.py::test_a"]) - def test_issue134_report_error_when_collecting_member(self, testdir, lookfor): - testdir.makepyfile( - test_fun=""" - def test_a(): - pass - def""" - ) - result = testdir.runpytest(lookfor) - result.stdout.fnmatch_lines(["*SyntaxError*"]) - if "::" in lookfor: - result.stderr.fnmatch_lines(["*ERROR*"]) - assert result.ret == 4 # usage error only if item not found - - def test_report_all_failed_collections_initargs(self, testdir): - testdir.makepyfile(test_a="def", test_b="def") - result = testdir.runpytest("test_a.py::a", "test_b.py::b") - result.stderr.fnmatch_lines(["*ERROR*test_a.py::a*", "*ERROR*test_b.py::b*"]) - - @pytest.mark.usefixtures("recwarn") - def test_namespace_import_doesnt_confuse_import_hook(self, testdir): - """ - Ref #383. Python 3.3's namespace package messed with our import hooks - Importing a module that didn't exist, even if the ImportError was - gracefully handled, would make our test crash. - - Use recwarn here to silence this warning in Python 2.7: - ImportWarning: Not importing directory '...\not_a_package': missing __init__.py - """ - testdir.mkdir("not_a_package") - p = testdir.makepyfile( - """ - try: - from not_a_package import doesnt_exist - except ImportError: - # We handle the import error gracefully here - pass - - def test_whatever(): - pass - """ - ) - res = testdir.runpytest(p.basename) - assert res.ret == 0 - - def test_unknown_option(self, testdir): - result = testdir.runpytest("--qwlkej") - result.stderr.fnmatch_lines( - """ - *unrecognized* - """ - ) - - def test_getsourcelines_error_issue553(self, testdir, monkeypatch): - monkeypatch.setattr("inspect.getsourcelines", None) - p = testdir.makepyfile( - """ - def raise_error(obj): - raise IOError('source code not available') - - import inspect - inspect.getsourcelines = raise_error - - def test_foo(invalid_fixture): - pass - """ - ) - res = testdir.runpytest(p) - res.stdout.fnmatch_lines( - ["*source code not available*", "E*fixture 'invalid_fixture' not found"] - ) - - def test_plugins_given_as_strings(self, tmpdir, monkeypatch): - """test that str values passed to main() as `plugins` arg - are interpreted as module names to be imported and registered. - #855. - """ - with pytest.raises(ImportError) as excinfo: - pytest.main([str(tmpdir)], plugins=["invalid.module"]) - assert "invalid" in str(excinfo.value) - - p = tmpdir.join("test_test_plugins_given_as_strings.py") - p.write("def test_foo(): pass") - mod = types.ModuleType("myplugin") - monkeypatch.setitem(sys.modules, "myplugin", mod) - assert pytest.main(args=[str(tmpdir)], plugins=["myplugin"]) == 0 - - def test_parametrized_with_bytes_regex(self, testdir): - p = testdir.makepyfile( - """ - import re - import pytest - @pytest.mark.parametrize('r', [re.compile(b'foo')]) - def test_stuff(r): - pass - """ - ) - res = testdir.runpytest(p) - res.stdout.fnmatch_lines(["*1 passed*"]) - - def test_parametrized_with_null_bytes(self, testdir): - """Test parametrization with values that contain null bytes and unicode characters (#2644, #2957)""" - p = testdir.makepyfile( - u""" - # encoding: UTF-8 - import pytest - - @pytest.mark.parametrize("data", [b"\\x00", "\\x00", u'ação']) - def test_foo(data): - assert data - """ - ) - res = testdir.runpytest(p) - res.assert_outcomes(passed=3) - - -class TestInvocationVariants(object): - - def test_earlyinit(self, testdir): - p = testdir.makepyfile( - """ - import pytest - assert hasattr(pytest, 'mark') - """ - ) - result = testdir.runpython(p) - assert result.ret == 0 - - @pytest.mark.xfail("sys.platform.startswith('java')") - def test_pydoc(self, testdir): - for name in ("py.test", "pytest"): - result = testdir.runpython_c("import %s;help(%s)" % (name, name)) - assert result.ret == 0 - s = result.stdout.str() - assert "MarkGenerator" in s - - def test_import_star_py_dot_test(self, testdir): - p = testdir.makepyfile( - """ - from py.test import * - #collect - #cmdline - #Item - # assert collect.Item is Item - # assert collect.Collector is Collector - main - skip - xfail - """ - ) - result = testdir.runpython(p) - assert result.ret == 0 - - def test_import_star_pytest(self, testdir): - p = testdir.makepyfile( - """ - from pytest import * - #Item - #File - main - skip - xfail - """ - ) - result = testdir.runpython(p) - assert result.ret == 0 - - def test_double_pytestcmdline(self, testdir): - p = testdir.makepyfile( - run=""" - import pytest - pytest.main() - pytest.main() - """ - ) - testdir.makepyfile( - """ - def test_hello(): - pass - """ - ) - result = testdir.runpython(p) - result.stdout.fnmatch_lines(["*1 passed*", "*1 passed*"]) - - def test_python_minus_m_invocation_ok(self, testdir): - p1 = testdir.makepyfile("def test_hello(): pass") - res = testdir.run(sys.executable, "-m", "pytest", str(p1)) - assert res.ret == 0 - - def test_python_minus_m_invocation_fail(self, testdir): - p1 = testdir.makepyfile("def test_fail(): 0/0") - res = testdir.run(sys.executable, "-m", "pytest", str(p1)) - assert res.ret == 1 - - def test_python_pytest_package(self, testdir): - p1 = testdir.makepyfile("def test_pass(): pass") - res = testdir.run(sys.executable, "-m", "pytest", str(p1)) - assert res.ret == 0 - res.stdout.fnmatch_lines(["*1 passed*"]) - - def test_equivalence_pytest_pytest(self): - assert pytest.main == py.test.cmdline.main - - def test_invoke_with_string(self, capsys): - retcode = pytest.main("-h") - assert not retcode - out, err = capsys.readouterr() - assert "--help" in out - pytest.raises(ValueError, lambda: pytest.main(0)) - - def test_invoke_with_path(self, tmpdir, capsys): - retcode = pytest.main(tmpdir) - assert retcode == EXIT_NOTESTSCOLLECTED - out, err = capsys.readouterr() - - def test_invoke_plugin_api(self, testdir, capsys): - - class MyPlugin(object): - - def pytest_addoption(self, parser): - parser.addoption("--myopt") - - pytest.main(["-h"], plugins=[MyPlugin()]) - out, err = capsys.readouterr() - assert "--myopt" in out - - def test_pyargs_importerror(self, testdir, monkeypatch): - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", False) - path = testdir.mkpydir("tpkg") - path.join("test_hello.py").write("raise ImportError") - - result = testdir.runpytest("--pyargs", "tpkg.test_hello", syspathinsert=True) - assert result.ret != 0 - - result.stdout.fnmatch_lines(["collected*0*items*/*1*errors"]) - - def test_cmdline_python_package(self, testdir, monkeypatch): - import warnings - - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", False) - path = testdir.mkpydir("tpkg") - path.join("test_hello.py").write("def test_hello(): pass") - path.join("test_world.py").write("def test_world(): pass") - result = testdir.runpytest("--pyargs", "tpkg") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*2 passed*"]) - result = testdir.runpytest("--pyargs", "tpkg.test_hello", syspathinsert=True) - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def join_pythonpath(what): - cur = os.environ.get("PYTHONPATH") - if cur: - return str(what) + os.pathsep + cur - return what - - empty_package = testdir.mkpydir("empty_package") - monkeypatch.setenv("PYTHONPATH", join_pythonpath(empty_package)) - # the path which is not a package raises a warning on pypy; - # no idea why only pypy and not normal python warn about it here - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - result = testdir.runpytest("--pyargs", ".") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*2 passed*"]) - - monkeypatch.setenv("PYTHONPATH", join_pythonpath(testdir)) - result = testdir.runpytest("--pyargs", "tpkg.test_missing", syspathinsert=True) - assert result.ret != 0 - result.stderr.fnmatch_lines(["*not*found*test_missing*"]) - - def test_cmdline_python_namespace_package(self, testdir, monkeypatch): - """ - test --pyargs option with namespace packages (#1567) - """ - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) - - search_path = [] - for dirname in "hello", "world": - d = testdir.mkdir(dirname) - search_path.append(d) - ns = d.mkdir("ns_pkg") - ns.join("__init__.py").write( - "__import__('pkg_resources').declare_namespace(__name__)" - ) - lib = ns.mkdir(dirname) - lib.ensure("__init__.py") - lib.join("test_{}.py".format(dirname)).write( - "def test_{}(): pass\n" "def test_other():pass".format(dirname) - ) - - # The structure of the test directory is now: - # . - # ├── hello - # │ └── ns_pkg - # │ ├── __init__.py - # │ └── hello - # │ ├── __init__.py - # │ └── test_hello.py - # └── world - # └── ns_pkg - # ├── __init__.py - # └── world - # ├── __init__.py - # └── test_world.py - - def join_pythonpath(*dirs): - cur = os.environ.get("PYTHONPATH") - if cur: - dirs += (cur,) - return os.pathsep.join(str(p) for p in dirs) - - monkeypatch.setenv("PYTHONPATH", join_pythonpath(*search_path)) - for p in search_path: - monkeypatch.syspath_prepend(p) - - # mixed module and filenames: - os.chdir("world") - result = testdir.runpytest("--pyargs", "-v", "ns_pkg.hello", "ns_pkg/world") - assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*test_hello.py::test_hello*PASSED*", - "*test_hello.py::test_other*PASSED*", - "*test_world.py::test_world*PASSED*", - "*test_world.py::test_other*PASSED*", - "*4 passed*", - ] - ) - - # specify tests within a module - testdir.chdir() - result = testdir.runpytest( - "--pyargs", "-v", "ns_pkg.world.test_world::test_other" - ) - assert result.ret == 0 - result.stdout.fnmatch_lines( - ["*test_world.py::test_other*PASSED*", "*1 passed*"] - ) - - @pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires symlinks") - def test_cmdline_python_package_symlink(self, testdir, monkeypatch): - """ - test --pyargs option with packages with path containing symlink can - have conftest.py in their package (#2985) - """ - # dummy check that we can actually create symlinks: on Windows `os.symlink` is available, - # but normal users require special admin privileges to create symlinks. - if sys.platform == "win32": - try: - os.symlink( - str(testdir.tmpdir.ensure("tmpfile")), - str(testdir.tmpdir.join("tmpfile2")), - ) - except OSError as e: - pytest.skip(six.text_type(e.args[0])) - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) - - search_path = ["lib", os.path.join("local", "lib")] - - dirname = "lib" - d = testdir.mkdir(dirname) - foo = d.mkdir("foo") - foo.ensure("__init__.py") - lib = foo.mkdir("bar") - lib.ensure("__init__.py") - lib.join("test_bar.py").write( - "def test_bar(): pass\n" "def test_other(a_fixture):pass" - ) - lib.join("conftest.py").write( - "import pytest\n" "@pytest.fixture\n" "def a_fixture():pass" - ) - - d_local = testdir.mkdir("local") - symlink_location = os.path.join(str(d_local), "lib") - if six.PY2: - os.symlink(str(d), symlink_location) - else: - os.symlink(str(d), symlink_location, target_is_directory=True) - - # The structure of the test directory is now: - # . - # ├── local - # │ └── lib -> ../lib - # └── lib - # └── foo - # ├── __init__.py - # └── bar - # ├── __init__.py - # ├── conftest.py - # └── test_bar.py - - def join_pythonpath(*dirs): - cur = os.getenv("PYTHONPATH") - if cur: - dirs += (cur,) - return os.pathsep.join(str(p) for p in dirs) - - monkeypatch.setenv("PYTHONPATH", join_pythonpath(*search_path)) - for p in search_path: - monkeypatch.syspath_prepend(p) - - # module picked up in symlink-ed directory: - result = testdir.runpytest("--pyargs", "-v", "foo.bar") - testdir.chdir() - assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*lib/foo/bar/test_bar.py::test_bar*PASSED*", - "*lib/foo/bar/test_bar.py::test_other*PASSED*", - "*2 passed*", - ] - ) - - def test_cmdline_python_package_not_exists(self, testdir): - result = testdir.runpytest("--pyargs", "tpkgwhatv") - assert result.ret - result.stderr.fnmatch_lines(["ERROR*file*or*package*not*found*"]) - - @pytest.mark.xfail(reason="decide: feature or bug") - def test_noclass_discovery_if_not_testcase(self, testdir): - testpath = testdir.makepyfile( - """ - import unittest - class TestHello(object): - def test_hello(self): - assert self.attr - - class RealTest(unittest.TestCase, TestHello): - attr = 42 - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=1) - - def test_doctest_id(self, testdir): - testdir.makefile( - ".txt", - """ - >>> x=3 - >>> x - 4 - """, - ) - result = testdir.runpytest("-rf") - lines = result.stdout.str().splitlines() - for line in lines: - if line.startswith("FAIL "): - testid = line[5:].strip() - break - result = testdir.runpytest(testid, "-rf") - result.stdout.fnmatch_lines([line, "*1 failed*"]) - - def test_core_backward_compatibility(self): - """Test backward compatibility for get_plugin_manager function. See #787.""" - import _pytest.config - - assert type( - _pytest.config.get_plugin_manager() - ) is _pytest.config.PytestPluginManager - - def test_has_plugin(self, request): - """Test hasplugin function of the plugin manager (#932).""" - assert request.config.pluginmanager.hasplugin("python") - - -class TestDurations(object): - source = """ - import time - frag = 0.002 - def test_something(): - pass - def test_2(): - time.sleep(frag*5) - def test_1(): - time.sleep(frag) - def test_3(): - time.sleep(frag*10) - """ - - def test_calls(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("--durations=10") - assert result.ret == 0 - result.stdout.fnmatch_lines_random( - ["*durations*", "*call*test_3*", "*call*test_2*", "*call*test_1*"] - ) - - def test_calls_show_2(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("--durations=2") - assert result.ret == 0 - lines = result.stdout.get_lines_after("*slowest*durations*") - assert "4 passed" in lines[2] - - def test_calls_showall(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("--durations=0") - assert result.ret == 0 - for x in "123": - for y in ("call",): # 'setup', 'call', 'teardown': - for line in result.stdout.lines: - if ("test_%s" % x) in line and y in line: - break - else: - raise AssertionError("not found %s %s" % (x, y)) - - def test_with_deselected(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("--durations=2", "-k test_1") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*durations*", "*call*test_1*"]) - - def test_with_failing_collection(self, testdir): - testdir.makepyfile(self.source) - testdir.makepyfile(test_collecterror="""xyz""") - result = testdir.runpytest("--durations=2", "-k test_1") - assert result.ret == 2 - result.stdout.fnmatch_lines(["*Interrupted: 1 errors during collection*"]) - # Collection errors abort test execution, therefore no duration is - # output - assert "duration" not in result.stdout.str() - - def test_with_not(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("-k not 1") - assert result.ret == 0 - - -class TestDurationWithFixture(object): - source = """ - import time - frag = 0.001 - def setup_function(func): - time.sleep(frag * 3) - def test_1(): - time.sleep(frag*2) - def test_2(): - time.sleep(frag) - """ - - def test_setup_function(self, testdir): - testdir.makepyfile(self.source) - result = testdir.runpytest("--durations=10") - assert result.ret == 0 - - result.stdout.fnmatch_lines_random( - """ - *durations* - * setup *test_1* - * call *test_1* - """ - ) - - -def test_zipimport_hook(testdir, tmpdir): - """Test package loader is being used correctly (see #1837).""" - zipapp = pytest.importorskip("zipapp") - testdir.tmpdir.join("app").ensure(dir=1) - testdir.makepyfile( - **{ - "app/foo.py": """ - import pytest - def main(): - pytest.main(['--pyarg', 'foo']) - """ - } - ) - target = tmpdir.join("foo.zip") - zipapp.create_archive(str(testdir.tmpdir.join("app")), str(target), main="foo:main") - result = testdir.runpython(target) - assert result.ret == 0 - result.stderr.fnmatch_lines(["*not found*foo*"]) - assert "INTERNALERROR>" not in result.stdout.str() - - -def test_import_plugin_unicode_name(testdir): - testdir.makepyfile(myplugin="") - testdir.makepyfile( - """ - def test(): pass - """ - ) - testdir.makeconftest( - """ - pytest_plugins = [u'myplugin'] - """ - ) - r = testdir.runpytest() - assert r.ret == 0 - - -def test_deferred_hook_checking(testdir): - """ - Check hooks as late as possible (#1821). - """ - testdir.syspathinsert() - testdir.makepyfile( - **{ - "plugin.py": """ - class Hooks(object): - def pytest_my_hook(self, config): - pass - - def pytest_configure(config): - config.pluginmanager.add_hookspecs(Hooks) - """, - "conftest.py": """ - pytest_plugins = ['plugin'] - def pytest_my_hook(config): - return 40 - """, - "test_foo.py": """ - def test(request): - assert request.config.hook.pytest_my_hook(config=request.config) == [40] - """, - } - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 1 passed *"]) - - -def test_fixture_values_leak(testdir): - """Ensure that fixture objects are properly destroyed by the garbage collector at the end of their expected - life-times (#2981). - """ - testdir.makepyfile( - """ - import attr - import gc - import pytest - import weakref - - @attr.s - class SomeObj(object): - name = attr.ib() - - fix_of_test1_ref = None - session_ref = None - - @pytest.fixture(scope='session') - def session_fix(): - global session_ref - obj = SomeObj(name='session-fixture') - session_ref = weakref.ref(obj) - return obj - - @pytest.fixture - def fix(session_fix): - global fix_of_test1_ref - obj = SomeObj(name='local-fixture') - fix_of_test1_ref = weakref.ref(obj) - return obj - - def test1(fix): - assert fix_of_test1_ref() is fix - - def test2(): - gc.collect() - # fixture "fix" created during test1 must have been destroyed by now - assert fix_of_test1_ref() is None - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 2 passed *"]) - - -def test_fixture_order_respects_scope(testdir): - """Ensure that fixtures are created according to scope order, regression test for #2405 - """ - testdir.makepyfile( - """ - import pytest - - data = {} - - @pytest.fixture(scope='module') - def clean_data(): - data.clear() - - @pytest.fixture(autouse=True) - def add_data(): - data.update(value=True) - - @pytest.mark.usefixtures('clean_data') - def test_value(): - assert data.get('value') - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - - -def test_frame_leak_on_failing_test(testdir): - """pytest would leak garbage referencing the frames of tests that failed that could never be reclaimed (#2798) - - Unfortunately it was not possible to remove the actual circles because most of them - are made of traceback objects which cannot be weakly referenced. Those objects at least - can be eventually claimed by the garbage collector. - """ - testdir.makepyfile( - """ - import gc - import weakref - - class Obj: - pass - - ref = None - - def test1(): - obj = Obj() - global ref - ref = weakref.ref(obj) - assert 0 - - def test2(): - gc.collect() - assert ref() is None - """ - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*1 failed, 1 passed in*"]) diff --git a/third_party/python/pytest/testing/code/test_code.py b/third_party/python/pytest/testing/code/test_code.py deleted file mode 100644 index bfae3691882e..000000000000 --- a/third_party/python/pytest/testing/code/test_code.py +++ /dev/null @@ -1,210 +0,0 @@ -# coding: utf-8 -from __future__ import absolute_import, division, print_function -import sys - -import _pytest._code -import py -import pytest -from test_excinfo import TWMock -from six import text_type - - -def test_ne(): - code1 = _pytest._code.Code(compile('foo = "bar"', "", "exec")) - assert code1 == code1 - code2 = _pytest._code.Code(compile('foo = "baz"', "", "exec")) - assert code2 != code1 - - -def test_code_gives_back_name_for_not_existing_file(): - name = "abc-123" - co_code = compile("pass\n", name, "exec") - assert co_code.co_filename == name - code = _pytest._code.Code(co_code) - assert str(code.path) == name - assert code.fullsource is None - - -def test_code_with_class(): - - class A(object): - pass - - pytest.raises(TypeError, "_pytest._code.Code(A)") - - -if True: - - def x(): - pass - - -def test_code_fullsource(): - code = _pytest._code.Code(x) - full = code.fullsource - assert "test_code_fullsource()" in str(full) - - -def test_code_source(): - code = _pytest._code.Code(x) - src = code.source() - expected = """def x(): - pass""" - assert str(src) == expected - - -def test_frame_getsourcelineno_myself(): - - def func(): - return sys._getframe(0) - - f = func() - f = _pytest._code.Frame(f) - source, lineno = f.code.fullsource, f.lineno - assert source[lineno].startswith(" return sys._getframe(0)") - - -def test_getstatement_empty_fullsource(): - - def func(): - return sys._getframe(0) - - f = func() - f = _pytest._code.Frame(f) - prop = f.code.__class__.fullsource - try: - f.code.__class__.fullsource = None - assert f.statement == _pytest._code.Source("") - finally: - f.code.__class__.fullsource = prop - - -def test_code_from_func(): - co = _pytest._code.Code(test_frame_getsourcelineno_myself) - assert co.firstlineno - assert co.path - - -def test_unicode_handling(): - value = py.builtin._totext("\xc4\x85\xc4\x87\n", "utf-8").encode("utf8") - - def f(): - raise Exception(value) - - excinfo = pytest.raises(Exception, f) - str(excinfo) - if sys.version_info[0] < 3: - text_type(excinfo) - - -@pytest.mark.skipif(sys.version_info[0] >= 3, reason="python 2 only issue") -def test_unicode_handling_syntax_error(): - value = py.builtin._totext("\xc4\x85\xc4\x87\n", "utf-8").encode("utf8") - - def f(): - raise SyntaxError("invalid syntax", (None, 1, 3, value)) - - excinfo = pytest.raises(Exception, f) - str(excinfo) - if sys.version_info[0] < 3: - text_type(excinfo) - - -def test_code_getargs(): - - def f1(x): - pass - - c1 = _pytest._code.Code(f1) - assert c1.getargs(var=True) == ("x",) - - def f2(x, *y): - pass - - c2 = _pytest._code.Code(f2) - assert c2.getargs(var=True) == ("x", "y") - - def f3(x, **z): - pass - - c3 = _pytest._code.Code(f3) - assert c3.getargs(var=True) == ("x", "z") - - def f4(x, *y, **z): - pass - - c4 = _pytest._code.Code(f4) - assert c4.getargs(var=True) == ("x", "y", "z") - - -def test_frame_getargs(): - - def f1(x): - return sys._getframe(0) - - fr1 = _pytest._code.Frame(f1("a")) - assert fr1.getargs(var=True) == [("x", "a")] - - def f2(x, *y): - return sys._getframe(0) - - fr2 = _pytest._code.Frame(f2("a", "b", "c")) - assert fr2.getargs(var=True) == [("x", "a"), ("y", ("b", "c"))] - - def f3(x, **z): - return sys._getframe(0) - - fr3 = _pytest._code.Frame(f3("a", b="c")) - assert fr3.getargs(var=True) == [("x", "a"), ("z", {"b": "c"})] - - def f4(x, *y, **z): - return sys._getframe(0) - - fr4 = _pytest._code.Frame(f4("a", "b", c="d")) - assert fr4.getargs(var=True) == [("x", "a"), ("y", ("b",)), ("z", {"c": "d"})] - - -class TestExceptionInfo(object): - - def test_bad_getsource(self): - try: - if False: - pass - else: - assert False - except AssertionError: - exci = _pytest._code.ExceptionInfo() - assert exci.getrepr() - - -class TestTracebackEntry(object): - - def test_getsource(self): - try: - if False: - pass - else: - assert False - except AssertionError: - exci = _pytest._code.ExceptionInfo() - entry = exci.traceback[0] - source = entry.getsource() - assert len(source) == 6 - assert "assert False" in source[5] - - -class TestReprFuncArgs(object): - - def test_not_raise_exception_with_mixed_encoding(self): - from _pytest._code.code import ReprFuncArgs - - tw = TWMock() - - args = [("unicode_string", u"São Paulo"), ("utf8_string", "S\xc3\xa3o Paulo")] - - r = ReprFuncArgs(args) - r.toterminal(tw) - if sys.version_info[0] >= 3: - assert tw.lines[0] == "unicode_string = São Paulo, utf8_string = São Paulo" - else: - assert tw.lines[0] == "unicode_string = São Paulo, utf8_string = São Paulo" diff --git a/third_party/python/pytest/testing/code/test_excinfo.py b/third_party/python/pytest/testing/code/test_excinfo.py deleted file mode 100644 index f4044b6ecc44..000000000000 --- a/third_party/python/pytest/testing/code/test_excinfo.py +++ /dev/null @@ -1,1357 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function - -import operator -import os -import sys -import _pytest -import py -import pytest -from _pytest._code.code import ( - ExceptionInfo, - FormattedExcinfo, - ReprExceptionInfo, - ExceptionChainRepr, -) -from six.moves import queue - -from test_source import astonly - -try: - import importlib -except ImportError: - invalidate_import_caches = None -else: - invalidate_import_caches = getattr(importlib, "invalidate_caches", None) - -failsonjython = pytest.mark.xfail("sys.platform.startswith('java')") - -pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3])) - - -class TWMock(object): - WRITE = object() - - def __init__(self): - self.lines = [] - self.is_writing = False - - def sep(self, sep, line=None): - self.lines.append((sep, line)) - - def write(self, msg, **kw): - self.lines.append((TWMock.WRITE, msg)) - - def line(self, line, **kw): - self.lines.append(line) - - def markup(self, text, **kw): - return text - - def get_write_msg(self, idx): - flag, msg = self.lines[idx] - assert flag == TWMock.WRITE - return msg - - fullwidth = 80 - - -def test_excinfo_simple(): - try: - raise ValueError - except ValueError: - info = _pytest._code.ExceptionInfo() - assert info.type == ValueError - - -def test_excinfo_getstatement(): - - def g(): - raise ValueError - - def f(): - g() - - try: - f() - except ValueError: - excinfo = _pytest._code.ExceptionInfo() - linenumbers = [ - _pytest._code.getrawcode(f).co_firstlineno - 1 + 4, - _pytest._code.getrawcode(f).co_firstlineno - 1 + 1, - _pytest._code.getrawcode(g).co_firstlineno - 1 + 1, - ] - values = list(excinfo.traceback) - foundlinenumbers = [x.lineno for x in values] - assert foundlinenumbers == linenumbers - # for x in info: - # print "%s:%d %s" %(x.path.relto(root), x.lineno, x.statement) - # xxx - - -# testchain for getentries test below - - -def f(): - # - raise ValueError - # - - -def g(): - # - __tracebackhide__ = True - f() - # - - -def h(): - # - g() - # - - -class TestTraceback_f_g_h(object): - - def setup_method(self, method): - try: - h() - except ValueError: - self.excinfo = _pytest._code.ExceptionInfo() - - def test_traceback_entries(self): - tb = self.excinfo.traceback - entries = list(tb) - assert len(tb) == 4 # maybe fragile test - assert len(entries) == 4 # maybe fragile test - names = ["f", "g", "h"] - for entry in entries: - try: - names.remove(entry.frame.code.name) - except ValueError: - pass - assert not names - - def test_traceback_entry_getsource(self): - tb = self.excinfo.traceback - s = str(tb[-1].getsource()) - assert s.startswith("def f():") - assert s.endswith("raise ValueError") - - @astonly - @failsonjython - def test_traceback_entry_getsource_in_construct(self): - source = _pytest._code.Source( - """\ - def xyz(): - try: - raise ValueError - except somenoname: - pass - xyz() - """ - ) - try: - exec(source.compile()) - except NameError: - tb = _pytest._code.ExceptionInfo().traceback - print(tb[-1].getsource()) - s = str(tb[-1].getsource()) - assert s.startswith("def xyz():\n try:") - assert s.strip().endswith("except somenoname:") - - def test_traceback_cut(self): - co = _pytest._code.Code(f) - path, firstlineno = co.path, co.firstlineno - traceback = self.excinfo.traceback - newtraceback = traceback.cut(path=path, firstlineno=firstlineno) - assert len(newtraceback) == 1 - newtraceback = traceback.cut(path=path, lineno=firstlineno + 2) - assert len(newtraceback) == 1 - - def test_traceback_cut_excludepath(self, testdir): - p = testdir.makepyfile("def f(): raise ValueError") - excinfo = pytest.raises(ValueError, "p.pyimport().f()") - basedir = py.path.local(pytest.__file__).dirpath() - newtraceback = excinfo.traceback.cut(excludepath=basedir) - for x in newtraceback: - if hasattr(x, "path"): - assert not py.path.local(x.path).relto(basedir) - assert newtraceback[-1].frame.code.path == p - - def test_traceback_filter(self): - traceback = self.excinfo.traceback - ntraceback = traceback.filter() - assert len(ntraceback) == len(traceback) - 1 - - @pytest.mark.parametrize( - "tracebackhide, matching", - [ - (lambda info: True, True), - (lambda info: False, False), - (operator.methodcaller("errisinstance", ValueError), True), - (operator.methodcaller("errisinstance", IndexError), False), - ], - ) - def test_traceback_filter_selective(self, tracebackhide, matching): - - def f(): - # - raise ValueError - # - - def g(): - # - __tracebackhide__ = tracebackhide - f() - # - - def h(): - # - g() - # - - excinfo = pytest.raises(ValueError, h) - traceback = excinfo.traceback - ntraceback = traceback.filter() - print("old: {!r}".format(traceback)) - print("new: {!r}".format(ntraceback)) - - if matching: - assert len(ntraceback) == len(traceback) - 2 - else: - # -1 because of the __tracebackhide__ in pytest.raises - assert len(ntraceback) == len(traceback) - 1 - - def test_traceback_recursion_index(self): - - def f(n): - if n < 10: - n += 1 - f(n) - - excinfo = pytest.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() - assert recindex == 3 - - def test_traceback_only_specific_recursion_errors(self, monkeypatch): - - def f(n): - if n == 0: - raise RuntimeError("hello") - f(n - 1) - - excinfo = pytest.raises(RuntimeError, f, 100) - monkeypatch.delattr(excinfo.traceback.__class__, "recursionindex") - repr = excinfo.getrepr() - assert "RuntimeError: hello" in str(repr.reprcrash) - - def test_traceback_no_recursion_index(self): - - def do_stuff(): - raise RuntimeError - - def reraise_me(): - import sys - - exc, val, tb = sys.exc_info() - py.builtin._reraise(exc, val, tb) - - def f(n): - try: - do_stuff() - except: # noqa - reraise_me() - - excinfo = pytest.raises(RuntimeError, f, 8) - traceback = excinfo.traceback - recindex = traceback.recursionindex() - assert recindex is None - - def test_traceback_messy_recursion(self): - # XXX: simplified locally testable version - decorator = pytest.importorskip("decorator").decorator - - def log(f, *k, **kw): - print("%s %s" % (k, kw)) - f(*k, **kw) - - log = decorator(log) - - def fail(): - raise ValueError("") - - fail = log(log(fail)) - - excinfo = pytest.raises(ValueError, fail) - assert excinfo.traceback.recursionindex() is None - - def test_traceback_getcrashentry(self): - - def i(): - __tracebackhide__ = True - raise ValueError - - def h(): - i() - - def g(): - __tracebackhide__ = True - h() - - def f(): - g() - - excinfo = pytest.raises(ValueError, f) - tb = excinfo.traceback - entry = tb.getcrashentry() - co = _pytest._code.Code(h) - assert entry.frame.code.path == co.path - assert entry.lineno == co.firstlineno + 1 - assert entry.frame.code.name == "h" - - def test_traceback_getcrashentry_empty(self): - - def g(): - __tracebackhide__ = True - raise ValueError - - def f(): - __tracebackhide__ = True - g() - - excinfo = pytest.raises(ValueError, f) - tb = excinfo.traceback - entry = tb.getcrashentry() - co = _pytest._code.Code(g) - assert entry.frame.code.path == co.path - assert entry.lineno == co.firstlineno + 2 - assert entry.frame.code.name == "g" - - -def test_excinfo_exconly(): - excinfo = pytest.raises(ValueError, h) - assert excinfo.exconly().startswith("ValueError") - excinfo = pytest.raises(ValueError, "raise ValueError('hello\\nworld')") - msg = excinfo.exconly(tryshort=True) - assert msg.startswith("ValueError") - assert msg.endswith("world") - - -def test_excinfo_repr(): - excinfo = pytest.raises(ValueError, h) - s = repr(excinfo) - assert s == "" - - -def test_excinfo_str(): - excinfo = pytest.raises(ValueError, h) - s = str(excinfo) - assert s.startswith(__file__[:-9]) # pyc file and $py.class - assert s.endswith("ValueError") - assert len(s.split(":")) >= 3 # on windows it's 4 - - -def test_excinfo_errisinstance(): - excinfo = pytest.raises(ValueError, h) - assert excinfo.errisinstance(ValueError) - - -def test_excinfo_no_sourcecode(): - try: - exec("raise ValueError()") - except ValueError: - excinfo = _pytest._code.ExceptionInfo() - s = str(excinfo.traceback[-1]) - assert s == " File '':1 in \n ???\n" - - -def test_excinfo_no_python_sourcecode(tmpdir): - # XXX: simplified locally testable version - tmpdir.join("test.txt").write("{{ h()}}:") - - jinja2 = pytest.importorskip("jinja2") - loader = jinja2.FileSystemLoader(str(tmpdir)) - env = jinja2.Environment(loader=loader) - template = env.get_template("test.txt") - excinfo = pytest.raises(ValueError, template.render, h=h) - for item in excinfo.traceback: - print(item) # XXX: for some reason jinja.Template.render is printed in full - item.source # shouldnt fail - if item.path.basename == "test.txt": - assert str(item.source) == "{{ h()}}:" - - -def test_entrysource_Queue_example(): - try: - queue.Queue().get(timeout=0.001) - except queue.Empty: - excinfo = _pytest._code.ExceptionInfo() - entry = excinfo.traceback[-1] - source = entry.getsource() - assert source is not None - s = str(source).strip() - assert s.startswith("def get") - - -def test_codepath_Queue_example(): - try: - queue.Queue().get(timeout=0.001) - except queue.Empty: - excinfo = _pytest._code.ExceptionInfo() - entry = excinfo.traceback[-1] - path = entry.path - assert isinstance(path, py.path.local) - assert path.basename.lower() == "queue.py" - assert path.check() - - -def test_match_succeeds(): - with pytest.raises(ZeroDivisionError) as excinfo: - 0 // 0 - excinfo.match(r".*zero.*") - - -def test_match_raises_error(testdir): - testdir.makepyfile( - """ - import pytest - def test_division_zero(): - with pytest.raises(ZeroDivisionError) as excinfo: - 0 / 0 - excinfo.match(r'[123]+') - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines(["*AssertionError*Pattern*[123]*not found*"]) - - -class TestFormattedExcinfo(object): - - @pytest.fixture - def importasmod(self, request): - - def importasmod(source): - source = _pytest._code.Source(source) - tmpdir = request.getfixturevalue("tmpdir") - modpath = tmpdir.join("mod.py") - tmpdir.ensure("__init__.py") - modpath.write(source) - if invalidate_import_caches is not None: - invalidate_import_caches() - return modpath.pyimport() - - return importasmod - - def excinfo_from_exec(self, source): - source = _pytest._code.Source(source).strip() - try: - exec(source.compile()) - except KeyboardInterrupt: - raise - except: # noqa - return _pytest._code.ExceptionInfo() - assert 0, "did not raise" - - def test_repr_source(self): - pr = FormattedExcinfo() - source = _pytest._code.Source( - """ - def f(x): - pass - """ - ).strip() - pr.flow_marker = "|" - lines = pr.get_source(source, 0) - assert len(lines) == 2 - assert lines[0] == "| def f(x):" - assert lines[1] == " pass" - - def test_repr_source_excinfo(self): - """ check if indentation is right """ - pr = FormattedExcinfo() - excinfo = self.excinfo_from_exec( - """ - def f(): - assert 0 - f() - """ - ) - pr = FormattedExcinfo() - source = pr._getentrysource(excinfo.traceback[-1]) - lines = pr.get_source(source, 1, excinfo) - assert lines == [" def f():", "> assert 0", "E AssertionError"] - - def test_repr_source_not_existing(self): - pr = FormattedExcinfo() - co = compile("raise ValueError()", "", "exec") - try: - exec(co) - except ValueError: - excinfo = _pytest._code.ExceptionInfo() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" - if sys.version_info[0] >= 3: - assert repr.chain[0][0].reprentries[1].lines[0] == "> ???" - - def test_repr_many_line_source_not_existing(self): - pr = FormattedExcinfo() - co = compile( - """ -a = 1 -raise ValueError() -""", - "", - "exec", - ) - try: - exec(co) - except ValueError: - excinfo = _pytest._code.ExceptionInfo() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[1].lines[0] == "> ???" - if sys.version_info[0] >= 3: - assert repr.chain[0][0].reprentries[1].lines[0] == "> ???" - - def test_repr_source_failing_fullsource(self): - pr = FormattedExcinfo() - - class FakeCode(object): - - class raw(object): - co_filename = "?" - - path = "?" - firstlineno = 5 - - def fullsource(self): - return None - - fullsource = property(fullsource) - - class FakeFrame(object): - code = FakeCode() - f_locals = {} - f_globals = {} - - class FakeTracebackEntry(_pytest._code.Traceback.Entry): - - def __init__(self, tb, excinfo=None): - self.lineno = 5 + 3 - - @property - def frame(self): - return FakeFrame() - - class Traceback(_pytest._code.Traceback): - Entry = FakeTracebackEntry - - class FakeExcinfo(_pytest._code.ExceptionInfo): - typename = "Foo" - value = Exception() - - def __init__(self): - pass - - def exconly(self, tryshort): - return "EXC" - - def errisinstance(self, cls): - return False - - excinfo = FakeExcinfo() - - class FakeRawTB(object): - tb_next = None - - tb = FakeRawTB() - excinfo.traceback = Traceback(tb) - - fail = IOError() - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - if sys.version_info[0] >= 3: - assert repr.chain[0][0].reprentries[0].lines[0] == "> ???" - - fail = py.error.ENOENT # noqa - repr = pr.repr_excinfo(excinfo) - assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" - if sys.version_info[0] >= 3: - assert repr.chain[0][0].reprentries[0].lines[0] == "> ???" - - def test_repr_local(self): - p = FormattedExcinfo(showlocals=True) - loc = {"y": 5, "z": 7, "x": 3, "@x": 2, "__builtins__": {}} - reprlocals = p.repr_locals(loc) - assert reprlocals.lines - assert reprlocals.lines[0] == "__builtins__ = " - assert reprlocals.lines[1] == "x = 3" - assert reprlocals.lines[2] == "y = 5" - assert reprlocals.lines[3] == "z = 7" - - def test_repr_tracebackentry_lines(self, importasmod): - mod = importasmod( - """ - def func1(): - raise ValueError("hello\\nworld") - """ - ) - excinfo = pytest.raises(ValueError, mod.func1) - excinfo.traceback = excinfo.traceback.filter() - p = FormattedExcinfo() - reprtb = p.repr_traceback_entry(excinfo.traceback[-1]) - - # test as intermittent entry - lines = reprtb.lines - assert lines[0] == " def func1():" - assert lines[1] == '> raise ValueError("hello\\nworld")' - - # test as last entry - p = FormattedExcinfo(showlocals=True) - repr_entry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = repr_entry.lines - assert lines[0] == " def func1():" - assert lines[1] == '> raise ValueError("hello\\nworld")' - assert lines[2] == "E ValueError: hello" - assert lines[3] == "E world" - assert not lines[4:] - - loc = repr_entry.reprlocals is not None - loc = repr_entry.reprfileloc - assert loc.path == mod.__file__ - assert loc.lineno == 3 - # assert loc.message == "ValueError: hello" - - def test_repr_tracebackentry_lines2(self, importasmod): - mod = importasmod( - """ - def func1(m, x, y, z): - raise ValueError("hello\\nworld") - """ - ) - excinfo = pytest.raises(ValueError, mod.func1, "m" * 90, 5, 13, "z" * 120) - excinfo.traceback = excinfo.traceback.filter() - entry = excinfo.traceback[-1] - p = FormattedExcinfo(funcargs=True) - reprfuncargs = p.repr_args(entry) - assert reprfuncargs.args[0] == ("m", repr("m" * 90)) - assert reprfuncargs.args[1] == ("x", "5") - assert reprfuncargs.args[2] == ("y", "13") - assert reprfuncargs.args[3] == ("z", repr("z" * 120)) - - p = FormattedExcinfo(funcargs=True) - repr_entry = p.repr_traceback_entry(entry) - assert repr_entry.reprfuncargs.args == reprfuncargs.args - tw = TWMock() - repr_entry.toterminal(tw) - assert tw.lines[0] == "m = " + repr("m" * 90) - assert tw.lines[1] == "x = 5, y = 13" - assert tw.lines[2] == "z = " + repr("z" * 120) - - def test_repr_tracebackentry_lines_var_kw_args(self, importasmod): - mod = importasmod( - """ - def func1(x, *y, **z): - raise ValueError("hello\\nworld") - """ - ) - excinfo = pytest.raises(ValueError, mod.func1, "a", "b", c="d") - excinfo.traceback = excinfo.traceback.filter() - entry = excinfo.traceback[-1] - p = FormattedExcinfo(funcargs=True) - reprfuncargs = p.repr_args(entry) - assert reprfuncargs.args[0] == ("x", repr("a")) - assert reprfuncargs.args[1] == ("y", repr(("b",))) - assert reprfuncargs.args[2] == ("z", repr({"c": "d"})) - - p = FormattedExcinfo(funcargs=True) - repr_entry = p.repr_traceback_entry(entry) - assert repr_entry.reprfuncargs.args == reprfuncargs.args - tw = TWMock() - repr_entry.toterminal(tw) - assert tw.lines[0] == "x = 'a', y = ('b',), z = {'c': 'd'}" - - def test_repr_tracebackentry_short(self, importasmod): - mod = importasmod( - """ - def func1(): - raise ValueError("hello") - def entry(): - func1() - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback_entry(excinfo.traceback[-2]) - lines = reprtb.lines - basename = py.path.local(mod.__file__).basename - assert lines[0] == " func1()" - assert basename in str(reprtb.reprfileloc.path) - assert reprtb.reprfileloc.lineno == 5 - - # test last entry - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprtb.lines - assert lines[0] == ' raise ValueError("hello")' - assert lines[1] == "E ValueError: hello" - assert basename in str(reprtb.reprfileloc.path) - assert reprtb.reprfileloc.lineno == 3 - - def test_repr_tracebackentry_no(self, importasmod): - mod = importasmod( - """ - def func1(): - raise ValueError("hello") - def entry(): - func1() - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - p = FormattedExcinfo(style="no") - p.repr_traceback_entry(excinfo.traceback[-2]) - - p = FormattedExcinfo(style="no") - reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - lines = reprentry.lines - assert lines[0] == "E ValueError: hello" - assert not lines[1:] - - def test_repr_traceback_tbfilter(self, importasmod): - mod = importasmod( - """ - def f(x): - raise ValueError(x) - def entry(): - f(0) - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - p = FormattedExcinfo(tbfilter=True) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 2 - p = FormattedExcinfo(tbfilter=False) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 3 - - def test_traceback_short_no_source(self, importasmod, monkeypatch): - mod = importasmod( - """ - def func1(): - raise ValueError("hello") - def entry(): - func1() - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - from _pytest._code.code import Code - - monkeypatch.setattr(Code, "path", "bogus") - excinfo.traceback[0].frame.code.path = "bogus" - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback_entry(excinfo.traceback[-2]) - lines = reprtb.lines - last_p = FormattedExcinfo(style="short") - last_reprtb = last_p.repr_traceback_entry(excinfo.traceback[-1], excinfo) - last_lines = last_reprtb.lines - monkeypatch.undo() - assert lines[0] == " func1()" - - assert last_lines[0] == ' raise ValueError("hello")' - assert last_lines[1] == "E ValueError: hello" - - def test_repr_traceback_and_excinfo(self, importasmod): - mod = importasmod( - """ - def f(x): - raise ValueError(x) - def entry(): - f(0) - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - - for style in ("long", "short"): - p = FormattedExcinfo(style=style) - reprtb = p.repr_traceback(excinfo) - assert len(reprtb.reprentries) == 2 - assert reprtb.style == style - assert not reprtb.extraline - repr = p.repr_excinfo(excinfo) - assert repr.reprtraceback - assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries) - if sys.version_info[0] >= 3: - assert repr.chain[0][0] - assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries) - assert repr.reprcrash.path.endswith("mod.py") - assert repr.reprcrash.message == "ValueError: 0" - - def test_repr_traceback_with_invalid_cwd(self, importasmod, monkeypatch): - mod = importasmod( - """ - def f(x): - raise ValueError(x) - def entry(): - f(0) - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - - p = FormattedExcinfo() - - def raiseos(): - raise OSError(2) - - monkeypatch.setattr(os, "getcwd", raiseos) - assert p._makepath(__file__) == __file__ - p.repr_traceback(excinfo) - - def test_repr_excinfo_addouterr(self, importasmod): - mod = importasmod( - """ - def entry(): - raise ValueError() - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - repr = excinfo.getrepr() - repr.addsection("title", "content") - twmock = TWMock() - repr.toterminal(twmock) - assert twmock.lines[-1] == "content" - assert twmock.lines[-2] == ("-", "title") - - def test_repr_excinfo_reprcrash(self, importasmod): - mod = importasmod( - """ - def entry(): - raise ValueError() - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - repr = excinfo.getrepr() - assert repr.reprcrash.path.endswith("mod.py") - assert repr.reprcrash.lineno == 3 - assert repr.reprcrash.message == "ValueError" - assert str(repr.reprcrash).endswith("mod.py:3: ValueError") - - def test_repr_traceback_recursion(self, importasmod): - mod = importasmod( - """ - def rec2(x): - return rec1(x+1) - def rec1(x): - return rec2(x-1) - def entry(): - rec1(42) - """ - ) - excinfo = pytest.raises(RuntimeError, mod.entry) - - for style in ("short", "long", "no"): - p = FormattedExcinfo(style="short") - reprtb = p.repr_traceback(excinfo) - assert reprtb.extraline == "!!! Recursion detected (same locals & position)" - assert str(reprtb) - - def test_reprexcinfo_getrepr(self, importasmod): - mod = importasmod( - """ - def f(x): - raise ValueError(x) - def entry(): - f(0) - """ - ) - excinfo = pytest.raises(ValueError, mod.entry) - - for style in ("short", "long", "no"): - for showlocals in (True, False): - repr = excinfo.getrepr(style=style, showlocals=showlocals) - if sys.version_info[0] < 3: - assert isinstance(repr, ReprExceptionInfo) - assert repr.reprtraceback.style == style - if sys.version_info[0] >= 3: - assert isinstance(repr, ExceptionChainRepr) - for repr in repr.chain: - assert repr[0].style == style - - def test_reprexcinfo_unicode(self): - from _pytest._code.code import TerminalRepr - - class MyRepr(TerminalRepr): - - def toterminal(self, tw): - tw.line(py.builtin._totext("я", "utf-8")) - - x = py.builtin._totext(MyRepr()) - assert x == py.builtin._totext("я", "utf-8") - - def test_toterminal_long(self, importasmod): - mod = importasmod( - """ - def g(x): - raise ValueError(x) - def f(): - g(3) - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - excinfo.traceback = excinfo.traceback.filter() - repr = excinfo.getrepr() - tw = TWMock() - repr.toterminal(tw) - assert tw.lines[0] == "" - tw.lines.pop(0) - assert tw.lines[0] == " def f():" - assert tw.lines[1] == "> g(3)" - assert tw.lines[2] == "" - line = tw.get_write_msg(3) - assert line.endswith("mod.py") - assert tw.lines[4] == (":5: ") - assert tw.lines[5] == ("_ ", None) - assert tw.lines[6] == "" - assert tw.lines[7] == " def g(x):" - assert tw.lines[8] == "> raise ValueError(x)" - assert tw.lines[9] == "E ValueError: 3" - assert tw.lines[10] == "" - line = tw.get_write_msg(11) - assert line.endswith("mod.py") - assert tw.lines[12] == ":3: ValueError" - - def test_toterminal_long_missing_source(self, importasmod, tmpdir): - mod = importasmod( - """ - def g(x): - raise ValueError(x) - def f(): - g(3) - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - tmpdir.join("mod.py").remove() - excinfo.traceback = excinfo.traceback.filter() - repr = excinfo.getrepr() - tw = TWMock() - repr.toterminal(tw) - assert tw.lines[0] == "" - tw.lines.pop(0) - assert tw.lines[0] == "> ???" - assert tw.lines[1] == "" - line = tw.get_write_msg(2) - assert line.endswith("mod.py") - assert tw.lines[3] == ":5: " - assert tw.lines[4] == ("_ ", None) - assert tw.lines[5] == "" - assert tw.lines[6] == "> ???" - assert tw.lines[7] == "E ValueError: 3" - assert tw.lines[8] == "" - line = tw.get_write_msg(9) - assert line.endswith("mod.py") - assert tw.lines[10] == ":3: ValueError" - - def test_toterminal_long_incomplete_source(self, importasmod, tmpdir): - mod = importasmod( - """ - def g(x): - raise ValueError(x) - def f(): - g(3) - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - tmpdir.join("mod.py").write("asdf") - excinfo.traceback = excinfo.traceback.filter() - repr = excinfo.getrepr() - tw = TWMock() - repr.toterminal(tw) - assert tw.lines[0] == "" - tw.lines.pop(0) - assert tw.lines[0] == "> ???" - assert tw.lines[1] == "" - line = tw.get_write_msg(2) - assert line.endswith("mod.py") - assert tw.lines[3] == ":5: " - assert tw.lines[4] == ("_ ", None) - assert tw.lines[5] == "" - assert tw.lines[6] == "> ???" - assert tw.lines[7] == "E ValueError: 3" - assert tw.lines[8] == "" - line = tw.get_write_msg(9) - assert line.endswith("mod.py") - assert tw.lines[10] == ":3: ValueError" - - def test_toterminal_long_filenames(self, importasmod): - mod = importasmod( - """ - def f(): - raise ValueError() - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - tw = TWMock() - path = py.path.local(mod.__file__) - old = path.dirpath().chdir() - try: - repr = excinfo.getrepr(abspath=False) - repr.toterminal(tw) - x = py.path.local().bestrelpath(path) - if len(x) < len(str(path)): - msg = tw.get_write_msg(-2) - assert msg == "mod.py" - assert tw.lines[-1] == ":3: ValueError" - - repr = excinfo.getrepr(abspath=True) - repr.toterminal(tw) - msg = tw.get_write_msg(-2) - assert msg == path - line = tw.lines[-1] - assert line == ":3: ValueError" - finally: - old.chdir() - - @pytest.mark.parametrize( - "reproptions", - [ - { - "style": style, - "showlocals": showlocals, - "funcargs": funcargs, - "tbfilter": tbfilter, - } - for style in ("long", "short", "no") - for showlocals in (True, False) - for tbfilter in (True, False) - for funcargs in (True, False) - ], - ) - def test_format_excinfo(self, importasmod, reproptions): - mod = importasmod( - """ - def g(x): - raise ValueError(x) - def f(): - g(3) - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - tw = py.io.TerminalWriter(stringio=True) - repr = excinfo.getrepr(**reproptions) - repr.toterminal(tw) - assert tw.stringio.getvalue() - - def test_traceback_repr_style(self, importasmod): - mod = importasmod( - """ - def f(): - g() - def g(): - h() - def h(): - i() - def i(): - raise ValueError() - """ - ) - excinfo = pytest.raises(ValueError, mod.f) - excinfo.traceback = excinfo.traceback.filter() - excinfo.traceback[1].set_repr_style("short") - excinfo.traceback[2].set_repr_style("short") - r = excinfo.getrepr(style="long") - tw = TWMock() - r.toterminal(tw) - for line in tw.lines: - print(line) - assert tw.lines[0] == "" - assert tw.lines[1] == " def f():" - assert tw.lines[2] == "> g()" - assert tw.lines[3] == "" - msg = tw.get_write_msg(4) - assert msg.endswith("mod.py") - assert tw.lines[5] == ":3: " - assert tw.lines[6] == ("_ ", None) - tw.get_write_msg(7) - assert tw.lines[8].endswith("in g") - assert tw.lines[9] == " h()" - tw.get_write_msg(10) - assert tw.lines[11].endswith("in h") - assert tw.lines[12] == " i()" - assert tw.lines[13] == ("_ ", None) - assert tw.lines[14] == "" - assert tw.lines[15] == " def i():" - assert tw.lines[16] == "> raise ValueError()" - assert tw.lines[17] == "E ValueError" - assert tw.lines[18] == "" - msg = tw.get_write_msg(19) - msg.endswith("mod.py") - assert tw.lines[20] == ":9: ValueError" - - @pytest.mark.skipif("sys.version_info[0] < 3") - def test_exc_chain_repr(self, importasmod): - mod = importasmod( - """ - class Err(Exception): - pass - def f(): - try: - g() - except Exception as e: - raise Err() from e - finally: - h() - def g(): - raise ValueError() - - def h(): - raise AttributeError() - """ - ) - excinfo = pytest.raises(AttributeError, mod.f) - r = excinfo.getrepr(style="long") - tw = TWMock() - r.toterminal(tw) - for line in tw.lines: - print(line) - assert tw.lines[0] == "" - assert tw.lines[1] == " def f():" - assert tw.lines[2] == " try:" - assert tw.lines[3] == "> g()" - assert tw.lines[4] == "" - line = tw.get_write_msg(5) - assert line.endswith("mod.py") - assert tw.lines[6] == ":6: " - assert tw.lines[7] == ("_ ", None) - assert tw.lines[8] == "" - assert tw.lines[9] == " def g():" - assert tw.lines[10] == "> raise ValueError()" - assert tw.lines[11] == "E ValueError" - assert tw.lines[12] == "" - line = tw.get_write_msg(13) - assert line.endswith("mod.py") - assert tw.lines[14] == ":12: ValueError" - assert tw.lines[15] == "" - assert ( - tw.lines[16] - == "The above exception was the direct cause of the following exception:" - ) - assert tw.lines[17] == "" - assert tw.lines[18] == " def f():" - assert tw.lines[19] == " try:" - assert tw.lines[20] == " g()" - assert tw.lines[21] == " except Exception as e:" - assert tw.lines[22] == "> raise Err() from e" - assert tw.lines[23] == "E test_exc_chain_repr0.mod.Err" - assert tw.lines[24] == "" - line = tw.get_write_msg(25) - assert line.endswith("mod.py") - assert tw.lines[26] == ":8: Err" - assert tw.lines[27] == "" - assert ( - tw.lines[28] - == "During handling of the above exception, another exception occurred:" - ) - assert tw.lines[29] == "" - assert tw.lines[30] == " def f():" - assert tw.lines[31] == " try:" - assert tw.lines[32] == " g()" - assert tw.lines[33] == " except Exception as e:" - assert tw.lines[34] == " raise Err() from e" - assert tw.lines[35] == " finally:" - assert tw.lines[36] == "> h()" - assert tw.lines[37] == "" - line = tw.get_write_msg(38) - assert line.endswith("mod.py") - assert tw.lines[39] == ":10: " - assert tw.lines[40] == ("_ ", None) - assert tw.lines[41] == "" - assert tw.lines[42] == " def h():" - assert tw.lines[43] == "> raise AttributeError()" - assert tw.lines[44] == "E AttributeError" - assert tw.lines[45] == "" - line = tw.get_write_msg(46) - assert line.endswith("mod.py") - assert tw.lines[47] == ":15: AttributeError" - - @pytest.mark.skipif("sys.version_info[0] < 3") - def test_exc_repr_with_raise_from_none_chain_suppression(self, importasmod): - mod = importasmod( - """ - def f(): - try: - g() - except Exception: - raise AttributeError() from None - def g(): - raise ValueError() - """ - ) - excinfo = pytest.raises(AttributeError, mod.f) - r = excinfo.getrepr(style="long") - tw = TWMock() - r.toterminal(tw) - for line in tw.lines: - print(line) - assert tw.lines[0] == "" - assert tw.lines[1] == " def f():" - assert tw.lines[2] == " try:" - assert tw.lines[3] == " g()" - assert tw.lines[4] == " except Exception:" - assert tw.lines[5] == "> raise AttributeError() from None" - assert tw.lines[6] == "E AttributeError" - assert tw.lines[7] == "" - line = tw.get_write_msg(8) - assert line.endswith("mod.py") - assert tw.lines[9] == ":6: AttributeError" - assert len(tw.lines) == 10 - - @pytest.mark.skipif("sys.version_info[0] < 3") - @pytest.mark.parametrize( - "reason, description", - [ - ( - "cause", - "The above exception was the direct cause of the following exception:", - ), - ( - "context", - "During handling of the above exception, another exception occurred:", - ), - ], - ) - def test_exc_chain_repr_without_traceback(self, importasmod, reason, description): - """ - Handle representation of exception chains where one of the exceptions doesn't have a - real traceback, such as those raised in a subprocess submitted by the multiprocessing - module (#1984). - """ - from _pytest.pytester import LineMatcher - - exc_handling_code = " from e" if reason == "cause" else "" - mod = importasmod( - """ - def f(): - try: - g() - except Exception as e: - raise RuntimeError('runtime problem'){exc_handling_code} - def g(): - raise ValueError('invalid value') - """.format( - exc_handling_code=exc_handling_code - ) - ) - - with pytest.raises(RuntimeError) as excinfo: - mod.f() - - # emulate the issue described in #1984 - attr = "__%s__" % reason - getattr(excinfo.value, attr).__traceback__ = None - - r = excinfo.getrepr() - tw = py.io.TerminalWriter(stringio=True) - tw.hasmarkup = False - r.toterminal(tw) - - matcher = LineMatcher(tw.stringio.getvalue().splitlines()) - matcher.fnmatch_lines( - [ - "ValueError: invalid value", - description, - "* except Exception as e:", - "> * raise RuntimeError('runtime problem')" + exc_handling_code, - "E *RuntimeError: runtime problem", - ] - ) - - -@pytest.mark.parametrize("style", ["short", "long"]) -@pytest.mark.parametrize("encoding", [None, "utf8", "utf16"]) -def test_repr_traceback_with_unicode(style, encoding): - msg = u"☹" - if encoding is not None: - msg = msg.encode(encoding) - try: - raise RuntimeError(msg) - except RuntimeError: - e_info = ExceptionInfo() - formatter = FormattedExcinfo(style=style) - repr_traceback = formatter.repr_traceback(e_info) - assert repr_traceback is not None - - -def test_cwd_deleted(testdir): - testdir.makepyfile( - """ - def test(tmpdir): - tmpdir.chdir() - tmpdir.remove() - assert False - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 1 failed in *"]) - assert "INTERNALERROR" not in result.stdout.str() + result.stderr.str() - - -def test_exception_repr_extraction_error_on_recursion(): - """ - Ensure we can properly detect a recursion error even - if some locals raise error on comparison (#2459). - """ - - class numpy_like(object): - - def __eq__(self, other): - if type(other) is numpy_like: - raise ValueError( - "The truth value of an array " - "with more than one element is ambiguous." - ) - - def a(x): - return b(numpy_like()) - - def b(x): - return a(numpy_like()) - - try: - a(numpy_like()) - except: # noqa - from _pytest._code.code import ExceptionInfo - from _pytest.pytester import LineMatcher - - exc_info = ExceptionInfo() - - matcher = LineMatcher(str(exc_info.getrepr()).splitlines()) - matcher.fnmatch_lines( - [ - "!!! Recursion error detected, but an error occurred locating the origin of recursion.", - "*The following exception happened*", - "*ValueError: The truth value of an array*", - ] - ) - - -def test_no_recursion_index_on_recursion_error(): - """ - Ensure that we don't break in case we can't find the recursion index - during a recursion error (#2486). - """ - try: - - class RecursionDepthError(object): - - def __getattr__(self, attr): - return getattr(self, "_" + attr) - - RecursionDepthError().trigger - except: # noqa - from _pytest._code.code import ExceptionInfo - - exc_info = ExceptionInfo() - assert "maximum recursion" in str(exc_info.getrepr()) - else: - assert 0 diff --git a/third_party/python/pytest/testing/code/test_source.py b/third_party/python/pytest/testing/code/test_source.py deleted file mode 100644 index 56dad75671fa..000000000000 --- a/third_party/python/pytest/testing/code/test_source.py +++ /dev/null @@ -1,758 +0,0 @@ -# flake8: noqa -# disable flake check on this file because some constructs are strange -# or redundant on purpose and can't be disable on a line-by-line basis -from __future__ import absolute_import, division, print_function -import inspect -import sys - -import _pytest._code -import py -import pytest -from _pytest._code import Source -from _pytest._code.source import ast - - -astonly = pytest.mark.nothing -failsonjython = pytest.mark.xfail("sys.platform.startswith('java')") - - -def test_source_str_function(): - x = Source("3") - assert str(x) == "3" - - x = Source(" 3") - assert str(x) == "3" - - x = Source( - """ - 3 - """, - rstrip=False, - ) - assert str(x) == "\n3\n " - - x = Source( - """ - 3 - """, - rstrip=True, - ) - assert str(x) == "\n3" - - -def test_unicode(): - try: - unicode - except NameError: - return - x = Source(unicode("4")) - assert str(x) == "4" - co = _pytest._code.compile(unicode('u"\xc3\xa5"', "utf8"), mode="eval") - val = eval(co) - assert isinstance(val, unicode) - - -def test_source_from_function(): - source = _pytest._code.Source(test_source_str_function) - assert str(source).startswith("def test_source_str_function():") - - -def test_source_from_method(): - - class TestClass(object): - - def test_method(self): - pass - - source = _pytest._code.Source(TestClass().test_method) - assert source.lines == ["def test_method(self):", " pass"] - - -def test_source_from_lines(): - lines = ["a \n", "b\n", "c"] - source = _pytest._code.Source(lines) - assert source.lines == ["a ", "b", "c"] - - -def test_source_from_inner_function(): - - def f(): - pass - - source = _pytest._code.Source(f, deindent=False) - assert str(source).startswith(" def f():") - source = _pytest._code.Source(f) - assert str(source).startswith("def f():") - - -def test_source_putaround_simple(): - source = Source("raise ValueError") - source = source.putaround( - "try:", - """\ - except ValueError: - x = 42 - else: - x = 23""", - ) - assert ( - str(source) - == """\ -try: - raise ValueError -except ValueError: - x = 42 -else: - x = 23""" - ) - - -def test_source_putaround(): - source = Source() - source = source.putaround( - """ - if 1: - x=1 - """ - ) - assert str(source).strip() == "if 1:\n x=1" - - -def test_source_strips(): - source = Source("") - assert source == Source() - assert str(source) == "" - assert source.strip() == source - - -def test_source_strip_multiline(): - source = Source() - source.lines = ["", " hello", " "] - source2 = source.strip() - assert source2.lines == [" hello"] - - -def test_syntaxerror_rerepresentation(): - ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz") - assert ex.value.lineno == 1 - assert ex.value.offset in (4, 7) # XXX pypy/jython versus cpython? - assert ex.value.text.strip(), "x x" - - -def test_isparseable(): - assert Source("hello").isparseable() - assert Source("if 1:\n pass").isparseable() - assert Source(" \nif 1:\n pass").isparseable() - assert not Source("if 1:\n").isparseable() - assert not Source(" \nif 1:\npass").isparseable() - assert not Source(chr(0)).isparseable() - - -class TestAccesses(object): - source = Source( - """\ - def f(x): - pass - def g(x): - pass - """ - ) - - def test_getrange(self): - x = self.source[0:2] - assert x.isparseable() - assert len(x.lines) == 2 - assert str(x) == "def f(x):\n pass" - - def test_getline(self): - x = self.source[0] - assert x == "def f(x):" - - def test_len(self): - assert len(self.source) == 4 - - def test_iter(self): - values = [x for x in self.source] - assert len(values) == 4 - - -class TestSourceParsingAndCompiling(object): - source = Source( - """\ - def f(x): - assert (x == - 3 + - 4) - """ - ).strip() - - def test_compile(self): - co = _pytest._code.compile("x=3") - d = {} - exec(co, d) - assert d["x"] == 3 - - def test_compile_and_getsource_simple(self): - co = _pytest._code.compile("x=3") - exec(co) - source = _pytest._code.Source(co) - assert str(source) == "x=3" - - def test_compile_and_getsource_through_same_function(self): - - def gensource(source): - return _pytest._code.compile(source) - - co1 = gensource( - """ - def f(): - raise KeyError() - """ - ) - co2 = gensource( - """ - def f(): - raise ValueError() - """ - ) - source1 = inspect.getsource(co1) - assert "KeyError" in source1 - source2 = inspect.getsource(co2) - assert "ValueError" in source2 - - def test_getstatement(self): - # print str(self.source) - ass = str(self.source[1:]) - for i in range(1, 4): - # print "trying start in line %r" % self.source[i] - s = self.source.getstatement(i) - # x = s.deindent() - assert str(s) == ass - - def test_getstatementrange_triple_quoted(self): - # print str(self.source) - source = Source( - """hello(''' - ''')""" - ) - s = source.getstatement(0) - assert s == str(source) - s = source.getstatement(1) - assert s == str(source) - - @astonly - def test_getstatementrange_within_constructs(self): - source = Source( - """\ - try: - try: - raise ValueError - except SomeThing: - pass - finally: - 42 - """ - ) - assert len(source) == 7 - # check all lineno's that could occur in a traceback - # assert source.getstatementrange(0) == (0, 7) - # assert source.getstatementrange(1) == (1, 5) - assert source.getstatementrange(2) == (2, 3) - assert source.getstatementrange(3) == (3, 4) - assert source.getstatementrange(4) == (4, 5) - # assert source.getstatementrange(5) == (0, 7) - assert source.getstatementrange(6) == (6, 7) - - def test_getstatementrange_bug(self): - source = Source( - """\ - try: - x = ( - y + - z) - except: - pass - """ - ) - assert len(source) == 6 - assert source.getstatementrange(2) == (1, 4) - - def test_getstatementrange_bug2(self): - source = Source( - """\ - assert ( - 33 - == - [ - X(3, - b=1, c=2 - ), - ] - ) - """ - ) - assert len(source) == 9 - assert source.getstatementrange(5) == (0, 9) - - def test_getstatementrange_ast_issue58(self): - source = Source( - """\ - - def test_some(): - for a in [a for a in - CAUSE_ERROR]: pass - - x = 3 - """ - ) - assert getstatement(2, source).lines == source.lines[2:3] - assert getstatement(3, source).lines == source.lines[3:4] - - def test_getstatementrange_out_of_bounds_py3(self): - source = Source("if xxx:\n from .collections import something") - r = source.getstatementrange(1) - assert r == (1, 2) - - def test_getstatementrange_with_syntaxerror_issue7(self): - source = Source(":") - pytest.raises(SyntaxError, lambda: source.getstatementrange(0)) - - def test_compile_to_ast(self): - import ast - - source = Source("x = 4") - mod = source.compile(flag=ast.PyCF_ONLY_AST) - assert isinstance(mod, ast.Module) - compile(mod, "", "exec") - - def test_compile_and_getsource(self): - co = self.source.compile() - py.builtin.exec_(co, globals()) - f(7) - excinfo = pytest.raises(AssertionError, "f(6)") - frame = excinfo.traceback[-1].frame - stmt = frame.code.fullsource.getstatement(frame.lineno) - # print "block", str(block) - assert str(stmt).strip().startswith("assert") - - @pytest.mark.parametrize("name", ["", None, "my"]) - def test_compilefuncs_and_path_sanity(self, name): - - def check(comp, name): - co = comp(self.source, name) - if not name: - expected = "codegen %s:%d>" % (mypath, mylineno + 2 + 3) - else: - expected = "codegen %r %s:%d>" % (name, mypath, mylineno + 2 + 3) - fn = co.co_filename - assert fn.endswith(expected) - - mycode = _pytest._code.Code(self.test_compilefuncs_and_path_sanity) - mylineno = mycode.firstlineno - mypath = mycode.path - - for comp in _pytest._code.compile, _pytest._code.Source.compile: - check(comp, name) - - def test_offsetless_synerr(self): - pytest.raises(SyntaxError, _pytest._code.compile, "lambda a,a: 0", mode="eval") - - -def test_getstartingblock_singleline(): - - class A(object): - - def __init__(self, *args): - frame = sys._getframe(1) - self.source = _pytest._code.Frame(frame).statement - - x = A("x", "y") - - values = [i for i in x.source.lines if i.strip()] - assert len(values) == 1 - - -def test_getline_finally(): - - def c(): - pass - - excinfo = pytest.raises( - TypeError, - """ - teardown = None - try: - c(1) - finally: - if teardown: - teardown() - """, - ) - source = excinfo.traceback[-1].statement - assert str(source).strip() == "c(1)" - - -def test_getfuncsource_dynamic(): - source = """ - def f(): - raise ValueError - - def g(): pass - """ - co = _pytest._code.compile(source) - py.builtin.exec_(co, globals()) - assert str(_pytest._code.Source(f)).strip() == "def f():\n raise ValueError" - assert str(_pytest._code.Source(g)).strip() == "def g(): pass" - - -def test_getfuncsource_with_multine_string(): - - def f(): - c = """while True: - pass -""" - - assert ( - str(_pytest._code.Source(f)).strip() - == 'def f():\n c = """while True:\n pass\n"""' - ) - - -def test_deindent(): - from _pytest._code.source import deindent as deindent - - assert deindent(["\tfoo", "\tbar"]) == ["foo", "bar"] - - def f(): - c = """while True: - pass -""" - - lines = deindent(inspect.getsource(f).splitlines()) - assert lines == ["def f():", ' c = """while True:', " pass", '"""'] - - source = """ - def f(): - def g(): - pass - """ - lines = deindent(source.splitlines()) - assert lines == ["", "def f():", " def g():", " pass", " "] - - -def test_source_of_class_at_eof_without_newline(tmpdir): - # this test fails because the implicit inspect.getsource(A) below - # does not return the "x = 1" last line. - source = _pytest._code.Source( - """ - class A(object): - def method(self): - x = 1 - """ - ) - path = tmpdir.join("a.py") - path.write(source) - s2 = _pytest._code.Source(tmpdir.join("a.py").pyimport().A) - assert str(source).strip() == str(s2).strip() - - -if True: - - def x(): - pass - - -def test_getsource_fallback(): - from _pytest._code.source import getsource - - expected = """def x(): - pass""" - src = getsource(x) - assert src == expected - - -def test_idem_compile_and_getsource(): - from _pytest._code.source import getsource - - expected = "def x(): pass" - co = _pytest._code.compile(expected) - src = getsource(co) - assert src == expected - - -def test_findsource_fallback(): - from _pytest._code.source import findsource - - src, lineno = findsource(x) - assert "test_findsource_simple" in str(src) - assert src[lineno] == " def x():" - - -def test_findsource(): - from _pytest._code.source import findsource - - co = _pytest._code.compile( - """if 1: - def x(): - pass -""" - ) - - src, lineno = findsource(co) - assert "if 1:" in str(src) - - d = {} - eval(co, d) - src, lineno = findsource(d["x"]) - assert "if 1:" in str(src) - assert src[lineno] == " def x():" - - -def test_getfslineno(): - from _pytest._code import getfslineno - - def f(x): - pass - - fspath, lineno = getfslineno(f) - - assert fspath.basename == "test_source.py" - assert lineno == _pytest._code.getrawcode(f).co_firstlineno - 1 # see findsource - - class A(object): - pass - - fspath, lineno = getfslineno(A) - - _, A_lineno = inspect.findsource(A) - assert fspath.basename == "test_source.py" - assert lineno == A_lineno - - assert getfslineno(3) == ("", -1) - - class B(object): - pass - - B.__name__ = "B2" - assert getfslineno(B)[1] == -1 - - -def test_code_of_object_instance_with_call(): - - class A(object): - pass - - pytest.raises(TypeError, lambda: _pytest._code.Source(A())) - - class WithCall(object): - - def __call__(self): - pass - - code = _pytest._code.Code(WithCall()) - assert "pass" in str(code.source()) - - class Hello(object): - - def __call__(self): - pass - - pytest.raises(TypeError, lambda: _pytest._code.Code(Hello)) - - -def getstatement(lineno, source): - from _pytest._code.source import getstatementrange_ast - - source = _pytest._code.Source(source, deindent=False) - ast, start, end = getstatementrange_ast(lineno, source) - return source[start:end] - - -def test_oneline(): - source = getstatement(0, "raise ValueError") - assert str(source) == "raise ValueError" - - -def test_comment_and_no_newline_at_end(): - from _pytest._code.source import getstatementrange_ast - - source = Source( - [ - "def test_basic_complex():", - " assert 1 == 2", - "# vim: filetype=pyopencl:fdm=marker", - ] - ) - ast, start, end = getstatementrange_ast(1, source) - assert end == 2 - - -def test_oneline_and_comment(): - source = getstatement(0, "raise ValueError\n#hello") - assert str(source) == "raise ValueError" - - -@pytest.mark.xfail(hasattr(sys, "pypy_version_info"), reason="does not work on pypy") -def test_comments(): - source = '''def test(): - "comment 1" - x = 1 - # comment 2 - # comment 3 - - assert False - -""" -comment 4 -""" -''' - for line in range(2, 6): - assert str(getstatement(line, source)) == " x = 1" - for line in range(6, 10): - assert str(getstatement(line, source)) == " assert False" - assert str(getstatement(10, source)) == '"""' - - -def test_comment_in_statement(): - source = """test(foo=1, - # comment 1 - bar=2) -""" - for line in range(1, 3): - assert ( - str(getstatement(line, source)) - == "test(foo=1,\n # comment 1\n bar=2)" - ) - - -def test_single_line_else(): - source = getstatement(1, "if False: 2\nelse: 3") - assert str(source) == "else: 3" - - -def test_single_line_finally(): - source = getstatement(1, "try: 1\nfinally: 3") - assert str(source) == "finally: 3" - - -def test_issue55(): - source = ( - "def round_trip(dinp):\n assert 1 == dinp\n" - 'def test_rt():\n round_trip("""\n""")\n' - ) - s = getstatement(3, source) - assert str(s) == ' round_trip("""\n""")' - - -def XXXtest_multiline(): - source = getstatement( - 0, - """\ -raise ValueError( - 23 -) -x = 3 -""", - ) - assert str(source) == "raise ValueError(\n 23\n)" - - -class TestTry(object): - pytestmark = astonly - source = """\ -try: - raise ValueError -except Something: - raise IndexError(1) -else: - raise KeyError() -""" - - def test_body(self): - source = getstatement(1, self.source) - assert str(source) == " raise ValueError" - - def test_except_line(self): - source = getstatement(2, self.source) - assert str(source) == "except Something:" - - def test_except_body(self): - source = getstatement(3, self.source) - assert str(source) == " raise IndexError(1)" - - def test_else(self): - source = getstatement(5, self.source) - assert str(source) == " raise KeyError()" - - -class TestTryFinally(object): - source = """\ -try: - raise ValueError -finally: - raise IndexError(1) -""" - - def test_body(self): - source = getstatement(1, self.source) - assert str(source) == " raise ValueError" - - def test_finally(self): - source = getstatement(3, self.source) - assert str(source) == " raise IndexError(1)" - - -class TestIf(object): - pytestmark = astonly - source = """\ -if 1: - y = 3 -elif False: - y = 5 -else: - y = 7 -""" - - def test_body(self): - source = getstatement(1, self.source) - assert str(source) == " y = 3" - - def test_elif_clause(self): - source = getstatement(2, self.source) - assert str(source) == "elif False:" - - def test_elif(self): - source = getstatement(3, self.source) - assert str(source) == " y = 5" - - def test_else(self): - source = getstatement(5, self.source) - assert str(source) == " y = 7" - - -def test_semicolon(): - s = """\ -hello ; pytest.skip() -""" - source = getstatement(0, s) - assert str(source) == s.strip() - - -def test_def_online(): - s = """\ -def func(): raise ValueError(42) - -def something(): - pass -""" - source = getstatement(0, s) - assert str(source) == "def func(): raise ValueError(42)" - - -def XXX_test_expression_multiline(): - source = """\ -something -''' -'''""" - result = getstatement(1, source) - assert str(result) == "'''\n'''" diff --git a/third_party/python/pytest/testing/code/test_source_multiline_block.py b/third_party/python/pytest/testing/code/test_source_multiline_block.py deleted file mode 100644 index 92f7412eb8cf..000000000000 --- a/third_party/python/pytest/testing/code/test_source_multiline_block.py +++ /dev/null @@ -1,29 +0,0 @@ -# flake8: noqa -import sys - -import _pytest._code - - -def test_getstartingblock_multiline(): - """ - This test was originally found in test_source.py, but it depends on the weird - formatting of the ``x = A`` construct seen here and our autopep8 tool can only exclude entire - files (it does not support excluding lines/blocks using the traditional #noqa comment yet, - see hhatto/autopep8#307). It was considered better to just move this single test to its own - file and exclude it from autopep8 than try to complicate things. - """ - - class A(object): - - def __init__(self, *args): - frame = sys._getframe(1) - self.source = _pytest._code.Frame(frame).statement - - # fmt: off - x = A('x', - 'y' - , - 'z') - # fmt: on - values = [i for i in x.source.lines if i.strip()] - assert len(values) == 4 diff --git a/third_party/python/pytest/testing/deprecated_test.py b/third_party/python/pytest/testing/deprecated_test.py deleted file mode 100644 index 39ff1f1fc385..000000000000 --- a/third_party/python/pytest/testing/deprecated_test.py +++ /dev/null @@ -1,265 +0,0 @@ -from __future__ import absolute_import, division, print_function -import pytest - - -def test_yield_tests_deprecation(testdir): - testdir.makepyfile( - """ - def func1(arg, arg2): - assert arg == arg2 - def test_gen(): - yield "m1", func1, 15, 3*5 - yield "m2", func1, 42, 6*7 - def test_gen2(): - for k in range(10): - yield func1, 1, 1 - """ - ) - result = testdir.runpytest("-ra") - result.stdout.fnmatch_lines( - [ - "*yield tests are deprecated, and scheduled to be removed in pytest 4.0*", - "*2 passed*", - ] - ) - assert result.stdout.str().count("yield tests are deprecated") == 2 - - -def test_funcarg_prefix_deprecation(testdir): - testdir.makepyfile( - """ - def pytest_funcarg__value(): - return 10 - - def test_funcarg_prefix(value): - assert value == 10 - """ - ) - result = testdir.runpytest("-ra") - result.stdout.fnmatch_lines( - [ - ( - "*pytest_funcarg__value: " - 'declaring fixtures using "pytest_funcarg__" prefix is deprecated ' - "and scheduled to be removed in pytest 4.0. " - "Please remove the prefix and use the @pytest.fixture decorator instead." - ), - "*1 passed*", - ] - ) - - -def test_pytest_setup_cfg_deprecated(testdir): - testdir.makefile( - ".cfg", - setup=""" - [pytest] - addopts = --verbose - """, - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*pytest*section in setup.cfg files is deprecated*use*tool:pytest*instead*"] - ) - - -def test_pytest_custom_cfg_deprecated(testdir): - testdir.makefile( - ".cfg", - custom=""" - [pytest] - addopts = --verbose - """, - ) - result = testdir.runpytest("-c", "custom.cfg") - result.stdout.fnmatch_lines( - ["*pytest*section in custom.cfg files is deprecated*use*tool:pytest*instead*"] - ) - - -def test_str_args_deprecated(tmpdir, testdir): - """Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0.""" - from _pytest.main import EXIT_NOTESTSCOLLECTED - - warnings = [] - - class Collect(object): - - def pytest_logwarning(self, message): - warnings.append(message) - - ret = pytest.main("%s -x" % tmpdir, plugins=[Collect()]) - msg = ( - "passing a string to pytest.main() is deprecated, " - "pass a list of arguments instead." - ) - assert msg in warnings - assert ret == EXIT_NOTESTSCOLLECTED - - -def test_getfuncargvalue_is_deprecated(request): - pytest.deprecated_call(request.getfuncargvalue, "tmpdir") - - -def test_resultlog_is_deprecated(testdir): - result = testdir.runpytest("--help") - result.stdout.fnmatch_lines(["*DEPRECATED path for machine-readable result log*"]) - - testdir.makepyfile( - """ - def test(): - pass - """ - ) - result = testdir.runpytest("--result-log=%s" % testdir.tmpdir.join("result.log")) - result.stdout.fnmatch_lines( - [ - "*--result-log is deprecated and scheduled for removal in pytest 4.0*", - "*See https://docs.pytest.org/*/usage.html#creating-resultlog-format-files for more information*", - ] - ) - - -@pytest.mark.filterwarnings("always:Metafunc.addcall is deprecated") -def test_metafunc_addcall_deprecated(testdir): - testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall({'i': 1}) - metafunc.addcall({'i': 2}) - def test_func(i): - pass - """ - ) - res = testdir.runpytest("-s") - assert res.ret == 0 - res.stdout.fnmatch_lines( - ["*Metafunc.addcall is deprecated*", "*2 passed, 2 warnings*"] - ) - - -def test_terminal_reporter_writer_attr(pytestconfig): - """Check that TerminalReporter._tw is also available as 'writer' (#2984) - This attribute is planned to be deprecated in 3.4. - """ - try: - import xdist # noqa - - pytest.skip("xdist workers disable the terminal reporter plugin") - except ImportError: - pass - terminal_reporter = pytestconfig.pluginmanager.get_plugin("terminalreporter") - assert terminal_reporter.writer is terminal_reporter._tw - - -@pytest.mark.parametrize("plugin", ["catchlog", "capturelog"]) -def test_pytest_catchlog_deprecated(testdir, plugin): - testdir.makepyfile( - """ - def test_func(pytestconfig): - pytestconfig.pluginmanager.register(None, 'pytest_{}') - """.format( - plugin - ) - ) - res = testdir.runpytest() - assert res.ret == 0 - res.stdout.fnmatch_lines( - ["*pytest-*log plugin has been merged into the core*", "*1 passed, 1 warnings*"] - ) - - -def test_pytest_plugins_in_non_top_level_conftest_deprecated(testdir): - from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST - - subdirectory = testdir.tmpdir.join("subdirectory") - subdirectory.mkdir() - # create the inner conftest with makeconftest and then move it to the subdirectory - testdir.makeconftest( - """ - pytest_plugins=['capture'] - """ - ) - testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py")) - # make the top level conftest - testdir.makeconftest( - """ - import warnings - warnings.filterwarnings('always', category=DeprecationWarning) - """ - ) - testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - res = testdir.runpytest_subprocess() - assert res.ret == 0 - res.stderr.fnmatch_lines( - "*" + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] - ) - - -def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_top_level_conftest( - testdir -): - from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST - - subdirectory = testdir.tmpdir.join("subdirectory") - subdirectory.mkdir() - testdir.makeconftest( - """ - import warnings - warnings.filterwarnings('always', category=DeprecationWarning) - pytest_plugins=['capture'] - """ - ) - testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py")) - - testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - - res = testdir.runpytest_subprocess() - assert res.ret == 0 - res.stderr.fnmatch_lines( - "*" + str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0] - ) - - -def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_false_positives( - testdir -): - from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST - - subdirectory = testdir.tmpdir.join("subdirectory") - subdirectory.mkdir() - testdir.makeconftest( - """ - pass - """ - ) - testdir.tmpdir.join("conftest.py").move(subdirectory.join("conftest.py")) - - testdir.makeconftest( - """ - import warnings - warnings.filterwarnings('always', category=DeprecationWarning) - pytest_plugins=['capture'] - """ - ) - testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - res = testdir.runpytest_subprocess() - assert res.ret == 0 - assert str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[ - 0 - ] not in res.stderr.str() diff --git a/third_party/python/pytest/testing/freeze/.gitignore b/third_party/python/pytest/testing/freeze/.gitignore deleted file mode 100644 index b53319087248..000000000000 --- a/third_party/python/pytest/testing/freeze/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -*.spec diff --git a/third_party/python/pytest/testing/freeze/create_executable.py b/third_party/python/pytest/testing/freeze/create_executable.py deleted file mode 100644 index 98aa2034c9d7..000000000000 --- a/third_party/python/pytest/testing/freeze/create_executable.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Generates an executable with pytest runner embedded using PyInstaller. -""" -if __name__ == "__main__": - import pytest - import subprocess - - hidden = [] - for x in pytest.freeze_includes(): - hidden.extend(["--hidden-import", x]) - args = ["pyinstaller", "--noconfirm"] + hidden + ["runtests_script.py"] - subprocess.check_call(" ".join(args), shell=True) diff --git a/third_party/python/pytest/testing/freeze/runtests_script.py b/third_party/python/pytest/testing/freeze/runtests_script.py deleted file mode 100644 index d03bca8406de..000000000000 --- a/third_party/python/pytest/testing/freeze/runtests_script.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -This is the script that is actually frozen into an executable: simply executes -py.test main(). -""" - -if __name__ == "__main__": - import sys - import pytest - - sys.exit(pytest.main()) diff --git a/third_party/python/pytest/testing/freeze/tests/test_doctest.txt b/third_party/python/pytest/testing/freeze/tests/test_doctest.txt deleted file mode 100644 index e18a4b68cc96..000000000000 --- a/third_party/python/pytest/testing/freeze/tests/test_doctest.txt +++ /dev/null @@ -1,6 +0,0 @@ - - -Testing doctest:: - - >>> 1 + 1 - 2 diff --git a/third_party/python/pytest/testing/freeze/tests/test_trivial.py b/third_party/python/pytest/testing/freeze/tests/test_trivial.py deleted file mode 100644 index 08a55552abbf..000000000000 --- a/third_party/python/pytest/testing/freeze/tests/test_trivial.py +++ /dev/null @@ -1,6 +0,0 @@ -def test_upper(): - assert "foo".upper() == "FOO" - - -def test_lower(): - assert "FOO".lower() == "foo" diff --git a/third_party/python/pytest/testing/freeze/tox_run.py b/third_party/python/pytest/testing/freeze/tox_run.py deleted file mode 100644 index 678a69c858a2..000000000000 --- a/third_party/python/pytest/testing/freeze/tox_run.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Called by tox.ini: uses the generated executable to run the tests in ./tests/ -directory. -""" -if __name__ == "__main__": - import os - import sys - - executable = os.path.join(os.getcwd(), "dist", "runtests_script", "runtests_script") - if sys.platform.startswith("win"): - executable += ".exe" - sys.exit(os.system("%s tests" % executable)) diff --git a/third_party/python/pytest/testing/logging/test_fixture.py b/third_party/python/pytest/testing/logging/test_fixture.py deleted file mode 100644 index 8d9ae6b518da..000000000000 --- a/third_party/python/pytest/testing/logging/test_fixture.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -import logging - -import pytest - -logger = logging.getLogger(__name__) -sublogger = logging.getLogger(__name__ + ".baz") - - -def test_fixture_help(testdir): - result = testdir.runpytest("--fixtures") - result.stdout.fnmatch_lines(["*caplog*"]) - - -def test_change_level(caplog): - caplog.set_level(logging.INFO) - logger.debug("handler DEBUG level") - logger.info("handler INFO level") - - caplog.set_level(logging.CRITICAL, logger=sublogger.name) - sublogger.warning("logger WARNING level") - sublogger.critical("logger CRITICAL level") - - assert "DEBUG" not in caplog.text - assert "INFO" in caplog.text - assert "WARNING" not in caplog.text - assert "CRITICAL" in caplog.text - - -def test_change_level_undo(testdir): - """Ensure that 'set_level' is undone after the end of the test""" - testdir.makepyfile( - """ - import logging - - def test1(caplog): - caplog.set_level(logging.INFO) - # using + operator here so fnmatch_lines doesn't match the code in the traceback - logging.info('log from ' + 'test1') - assert 0 - - def test2(caplog): - # using + operator here so fnmatch_lines doesn't match the code in the traceback - logging.info('log from ' + 'test2') - assert 0 - """ - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*log from test1*", "*2 failed in *"]) - assert "log from test2" not in result.stdout.str() - - -def test_with_statement(caplog): - with caplog.at_level(logging.INFO): - logger.debug("handler DEBUG level") - logger.info("handler INFO level") - - with caplog.at_level(logging.CRITICAL, logger=sublogger.name): - sublogger.warning("logger WARNING level") - sublogger.critical("logger CRITICAL level") - - assert "DEBUG" not in caplog.text - assert "INFO" in caplog.text - assert "WARNING" not in caplog.text - assert "CRITICAL" in caplog.text - - -def test_log_access(caplog): - caplog.set_level(logging.INFO) - logger.info("boo %s", "arg") - assert caplog.records[0].levelname == "INFO" - assert caplog.records[0].msg == "boo %s" - assert "boo arg" in caplog.text - - -def test_record_tuples(caplog): - caplog.set_level(logging.INFO) - logger.info("boo %s", "arg") - - assert caplog.record_tuples == [(__name__, logging.INFO, "boo arg")] - - -def test_unicode(caplog): - caplog.set_level(logging.INFO) - logger.info(u"bū") - assert caplog.records[0].levelname == "INFO" - assert caplog.records[0].msg == u"bū" - assert u"bū" in caplog.text - - -def test_clear(caplog): - caplog.set_level(logging.INFO) - logger.info(u"bū") - assert len(caplog.records) - assert caplog.text - caplog.clear() - assert not len(caplog.records) - assert not caplog.text - - -@pytest.fixture -def logging_during_setup_and_teardown(caplog): - caplog.set_level("INFO") - logger.info("a_setup_log") - yield - logger.info("a_teardown_log") - assert [x.message for x in caplog.get_records("teardown")] == ["a_teardown_log"] - - -def test_caplog_captures_for_all_stages(caplog, logging_during_setup_and_teardown): - assert not caplog.records - assert not caplog.get_records("call") - logger.info("a_call_log") - assert [x.message for x in caplog.get_records("call")] == ["a_call_log"] - - assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"] - - # This reachers into private API, don't use this type of thing in real tests! - assert set(caplog._item.catch_log_handlers.keys()) == {"setup", "call"} diff --git a/third_party/python/pytest/testing/logging/test_formatter.py b/third_party/python/pytest/testing/logging/test_formatter.py deleted file mode 100644 index ca2a41065376..000000000000 --- a/third_party/python/pytest/testing/logging/test_formatter.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging - -import py.io -from _pytest.logging import ColoredLevelFormatter - - -def test_coloredlogformatter(): - logfmt = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s" - - record = logging.LogRecord( - name="dummy", - level=logging.INFO, - pathname="dummypath", - lineno=10, - msg="Test Message", - args=(), - exc_info=False, - ) - - class ColorConfig(object): - - class option(object): - pass - - tw = py.io.TerminalWriter() - tw.hasmarkup = True - formatter = ColoredLevelFormatter(tw, logfmt) - output = formatter.format(record) - assert ( - output - == ("dummypath 10 " "\x1b[32mINFO \x1b[0m Test Message") - ) - - tw.hasmarkup = False - formatter = ColoredLevelFormatter(tw, logfmt) - output = formatter.format(record) - assert output == ("dummypath 10 " "INFO Test Message") diff --git a/third_party/python/pytest/testing/logging/test_reporting.py b/third_party/python/pytest/testing/logging/test_reporting.py deleted file mode 100644 index 91ed2e4758cb..000000000000 --- a/third_party/python/pytest/testing/logging/test_reporting.py +++ /dev/null @@ -1,874 +0,0 @@ -# -*- coding: utf-8 -*- -import re -import os - -import six - -import pytest - - -def test_nothing_logged(testdir): - testdir.makepyfile( - """ - import sys - - def test_foo(): - sys.stdout.write('text going to stdout') - sys.stderr.write('text going to stderr') - assert False - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"]) - result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"]) - with pytest.raises(pytest.fail.Exception): - result.stdout.fnmatch_lines(["*- Captured *log call -*"]) - - -def test_messages_logged(testdir): - testdir.makepyfile( - """ - import sys - import logging - - logger = logging.getLogger(__name__) - - def test_foo(): - sys.stdout.write('text going to stdout') - sys.stderr.write('text going to stderr') - logger.info('text going to logger') - assert False - """ - ) - result = testdir.runpytest("--log-level=INFO") - assert result.ret == 1 - result.stdout.fnmatch_lines(["*- Captured *log call -*", "*text going to logger*"]) - result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"]) - result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"]) - - -def test_root_logger_affected(testdir): - testdir.makepyfile( - """ - import logging - logger = logging.getLogger() - def test_foo(): - logger.info('info text ' + 'going to logger') - logger.warning('warning text ' + 'going to logger') - logger.error('error text ' + 'going to logger') - - assert 0 - """ - ) - log_file = testdir.tmpdir.join("pytest.log").strpath - result = testdir.runpytest("--log-level=ERROR", "--log-file=pytest.log") - assert result.ret == 1 - - # the capture log calls in the stdout section only contain the - # logger.error msg, because --log-level=ERROR - result.stdout.fnmatch_lines(["*error text going to logger*"]) - with pytest.raises(pytest.fail.Exception): - result.stdout.fnmatch_lines(["*warning text going to logger*"]) - with pytest.raises(pytest.fail.Exception): - result.stdout.fnmatch_lines(["*info text going to logger*"]) - - # the log file should contain the warning and the error log messages and - # not the info one, because the default level of the root logger is - # WARNING. - assert os.path.isfile(log_file) - with open(log_file) as rfh: - contents = rfh.read() - assert "info text going to logger" not in contents - assert "warning text going to logger" in contents - assert "error text going to logger" in contents - - -def test_log_cli_level_log_level_interaction(testdir): - testdir.makepyfile( - """ - import logging - logger = logging.getLogger() - - def test_foo(): - logger.debug('debug text ' + 'going to logger') - logger.info('info text ' + 'going to logger') - logger.warning('warning text ' + 'going to logger') - logger.error('error text ' + 'going to logger') - assert 0 - """ - ) - - result = testdir.runpytest("--log-cli-level=INFO", "--log-level=ERROR") - assert result.ret == 1 - - result.stdout.fnmatch_lines( - [ - "*-- live log call --*", - "*INFO*info text going to logger", - "*WARNING*warning text going to logger", - "*ERROR*error text going to logger", - "=* 1 failed in *=", - ] - ) - assert "DEBUG" not in result.stdout.str() - - -def test_setup_logging(testdir): - testdir.makepyfile( - """ - import logging - - logger = logging.getLogger(__name__) - - def setup_function(function): - logger.info('text going to logger from setup') - - def test_foo(): - logger.info('text going to logger from call') - assert False - """ - ) - result = testdir.runpytest("--log-level=INFO") - assert result.ret == 1 - result.stdout.fnmatch_lines( - [ - "*- Captured *log setup -*", - "*text going to logger from setup*", - "*- Captured *log call -*", - "*text going to logger from call*", - ] - ) - - -def test_teardown_logging(testdir): - testdir.makepyfile( - """ - import logging - - logger = logging.getLogger(__name__) - - def test_foo(): - logger.info('text going to logger from call') - - def teardown_function(function): - logger.info('text going to logger from teardown') - assert False - """ - ) - result = testdir.runpytest("--log-level=INFO") - assert result.ret == 1 - result.stdout.fnmatch_lines( - [ - "*- Captured *log call -*", - "*text going to logger from call*", - "*- Captured *log teardown -*", - "*text going to logger from teardown*", - ] - ) - - -def test_disable_log_capturing(testdir): - testdir.makepyfile( - """ - import sys - import logging - - logger = logging.getLogger(__name__) - - def test_foo(): - sys.stdout.write('text going to stdout') - logger.warning('catch me if you can!') - sys.stderr.write('text going to stderr') - assert False - """ - ) - result = testdir.runpytest("--no-print-logs") - print(result.stdout) - assert result.ret == 1 - result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"]) - result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"]) - with pytest.raises(pytest.fail.Exception): - result.stdout.fnmatch_lines(["*- Captured *log call -*"]) - - -def test_disable_log_capturing_ini(testdir): - testdir.makeini( - """ - [pytest] - log_print=False - """ - ) - testdir.makepyfile( - """ - import sys - import logging - - logger = logging.getLogger(__name__) - - def test_foo(): - sys.stdout.write('text going to stdout') - logger.warning('catch me if you can!') - sys.stderr.write('text going to stderr') - assert False - """ - ) - result = testdir.runpytest() - print(result.stdout) - assert result.ret == 1 - result.stdout.fnmatch_lines(["*- Captured stdout call -*", "text going to stdout"]) - result.stdout.fnmatch_lines(["*- Captured stderr call -*", "text going to stderr"]) - with pytest.raises(pytest.fail.Exception): - result.stdout.fnmatch_lines(["*- Captured *log call -*"]) - - -@pytest.mark.parametrize("enabled", [True, False]) -def test_log_cli_enabled_disabled(testdir, enabled): - msg = "critical message logged by test" - testdir.makepyfile( - """ - import logging - def test_log_cli(): - logging.critical("{}") - """.format( - msg - ) - ) - if enabled: - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - result = testdir.runpytest() - if enabled: - result.stdout.fnmatch_lines( - [ - "test_log_cli_enabled_disabled.py::test_log_cli ", - "*-- live log call --*", - "test_log_cli_enabled_disabled.py* CRITICAL critical message logged by test", - "PASSED*", - ] - ) - else: - assert msg not in result.stdout.str() - - -def test_log_cli_default_level(testdir): - # Default log file level - testdir.makepyfile( - """ - import pytest - import logging - def test_log_cli(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_cli_handler.level == logging.NOTSET - logging.getLogger('catchlog').info("INFO message won't be shown") - logging.getLogger('catchlog').warning("WARNING message will be shown") - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest() - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines( - [ - "test_log_cli_default_level.py::test_log_cli ", - "test_log_cli_default_level.py*WARNING message will be shown*", - ] - ) - assert "INFO message won't be shown" not in result.stdout.str() - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - - -def test_log_cli_default_level_multiple_tests(testdir, request): - """Ensure we reset the first newline added by the live logger between tests""" - filename = request.node.name + ".py" - testdir.makepyfile( - """ - import logging - - def test_log_1(): - logging.warning("log message from test_log_1") - - def test_log_2(): - logging.warning("log message from test_log_2") - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "{}::test_log_1 ".format(filename), - "*WARNING*log message from test_log_1*", - "PASSED *50%*", - "{}::test_log_2 ".format(filename), - "*WARNING*log message from test_log_2*", - "PASSED *100%*", - "=* 2 passed in *=", - ] - ) - - -def test_log_cli_default_level_sections(testdir, request): - """Check that with live logging enable we are printing the correct headers during - start/setup/call/teardown/finish.""" - filename = request.node.name + ".py" - testdir.makeconftest( - """ - import pytest - import logging - - def pytest_runtest_logstart(): - logging.warning('>>>>> START >>>>>') - - def pytest_runtest_logfinish(): - logging.warning('<<<<< END <<<<<<<') - """ - ) - - testdir.makepyfile( - """ - import pytest - import logging - - @pytest.fixture - def fix(request): - logging.warning("log message from setup of {}".format(request.node.name)) - yield - logging.warning("log message from teardown of {}".format(request.node.name)) - - def test_log_1(fix): - logging.warning("log message from test_log_1") - - def test_log_2(fix): - logging.warning("log message from test_log_2") - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "{}::test_log_1 ".format(filename), - "*-- live log start --*", - "*WARNING* >>>>> START >>>>>*", - "*-- live log setup --*", - "*WARNING*log message from setup of test_log_1*", - "*-- live log call --*", - "*WARNING*log message from test_log_1*", - "PASSED *50%*", - "*-- live log teardown --*", - "*WARNING*log message from teardown of test_log_1*", - "*-- live log finish --*", - "*WARNING* <<<<< END <<<<<<<*", - "{}::test_log_2 ".format(filename), - "*-- live log start --*", - "*WARNING* >>>>> START >>>>>*", - "*-- live log setup --*", - "*WARNING*log message from setup of test_log_2*", - "*-- live log call --*", - "*WARNING*log message from test_log_2*", - "PASSED *100%*", - "*-- live log teardown --*", - "*WARNING*log message from teardown of test_log_2*", - "*-- live log finish --*", - "*WARNING* <<<<< END <<<<<<<*", - "=* 2 passed in *=", - ] - ) - - -def test_live_logs_unknown_sections(testdir, request): - """Check that with live logging enable we are printing the correct headers during - start/setup/call/teardown/finish.""" - filename = request.node.name + ".py" - testdir.makeconftest( - """ - import pytest - import logging - - def pytest_runtest_protocol(item, nextitem): - logging.warning('Unknown Section!') - - def pytest_runtest_logstart(): - logging.warning('>>>>> START >>>>>') - - def pytest_runtest_logfinish(): - logging.warning('<<<<< END <<<<<<<') - """ - ) - - testdir.makepyfile( - """ - import pytest - import logging - - @pytest.fixture - def fix(request): - logging.warning("log message from setup of {}".format(request.node.name)) - yield - logging.warning("log message from teardown of {}".format(request.node.name)) - - def test_log_1(fix): - logging.warning("log message from test_log_1") - - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*WARNING*Unknown Section*", - "{}::test_log_1 ".format(filename), - "*WARNING* >>>>> START >>>>>*", - "*-- live log setup --*", - "*WARNING*log message from setup of test_log_1*", - "*-- live log call --*", - "*WARNING*log message from test_log_1*", - "PASSED *100%*", - "*-- live log teardown --*", - "*WARNING*log message from teardown of test_log_1*", - "*WARNING* <<<<< END <<<<<<<*", - "=* 1 passed in *=", - ] - ) - - -def test_sections_single_new_line_after_test_outcome(testdir, request): - """Check that only a single new line is written between log messages during - teardown/finish.""" - filename = request.node.name + ".py" - testdir.makeconftest( - """ - import pytest - import logging - - def pytest_runtest_logstart(): - logging.warning('>>>>> START >>>>>') - - def pytest_runtest_logfinish(): - logging.warning('<<<<< END <<<<<<<') - logging.warning('<<<<< END <<<<<<<') - """ - ) - - testdir.makepyfile( - """ - import pytest - import logging - - @pytest.fixture - def fix(request): - logging.warning("log message from setup of {}".format(request.node.name)) - yield - logging.warning("log message from teardown of {}".format(request.node.name)) - logging.warning("log message from teardown of {}".format(request.node.name)) - - def test_log_1(fix): - logging.warning("log message from test_log_1") - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "{}::test_log_1 ".format(filename), - "*-- live log start --*", - "*WARNING* >>>>> START >>>>>*", - "*-- live log setup --*", - "*WARNING*log message from setup of test_log_1*", - "*-- live log call --*", - "*WARNING*log message from test_log_1*", - "PASSED *100%*", - "*-- live log teardown --*", - "*WARNING*log message from teardown of test_log_1*", - "*-- live log finish --*", - "*WARNING* <<<<< END <<<<<<<*", - "*WARNING* <<<<< END <<<<<<<*", - "=* 1 passed in *=", - ] - ) - assert re.search( - r"(.+)live log teardown(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)", - result.stdout.str(), - re.MULTILINE, - ) is not None - assert re.search( - r"(.+)live log finish(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)", - result.stdout.str(), - re.MULTILINE, - ) is not None - - -def test_log_cli_level(testdir): - # Default log file level - testdir.makepyfile( - """ - import pytest - import logging - def test_log_cli(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_cli_handler.level == logging.INFO - logging.getLogger('catchlog').debug("This log message won't be shown") - logging.getLogger('catchlog').info("This log message will be shown") - print('PASSED') - """ - ) - testdir.makeini( - """ - [pytest] - log_cli=true - """ - ) - - result = testdir.runpytest("-s", "--log-cli-level=INFO") - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines( - [ - "test_log_cli_level.py*This log message will be shown", - "PASSED", # 'PASSED' on its own line because the log message prints a new line - ] - ) - assert "This log message won't be shown" not in result.stdout.str() - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - - result = testdir.runpytest("-s", "--log-level=INFO") - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines( - [ - "test_log_cli_level.py* This log message will be shown", - "PASSED", # 'PASSED' on its own line because the log message prints a new line - ] - ) - assert "This log message won't be shown" not in result.stdout.str() - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - - -def test_log_cli_ini_level(testdir): - testdir.makeini( - """ - [pytest] - log_cli=true - log_cli_level = INFO - """ - ) - testdir.makepyfile( - """ - import pytest - import logging - def test_log_cli(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_cli_handler.level == logging.INFO - logging.getLogger('catchlog').debug("This log message won't be shown") - logging.getLogger('catchlog').info("This log message will be shown") - print('PASSED') - """ - ) - - result = testdir.runpytest("-s") - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines( - [ - "test_log_cli_ini_level.py* This log message will be shown", - "PASSED", # 'PASSED' on its own line because the log message prints a new line - ] - ) - assert "This log message won't be shown" not in result.stdout.str() - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - - -@pytest.mark.parametrize( - "cli_args", - ["", "--log-level=WARNING", "--log-file-level=WARNING", "--log-cli-level=WARNING"], -) -def test_log_cli_auto_enable(testdir, request, cli_args): - """Check that live logs are enabled if --log-level or --log-cli-level is passed on the CLI. - It should not be auto enabled if the same configs are set on the INI file. - """ - testdir.makepyfile( - """ - import pytest - import logging - - def test_log_1(): - logging.info("log message from test_log_1 not to be shown") - logging.warning("log message from test_log_1") - - """ - ) - testdir.makeini( - """ - [pytest] - log_level=INFO - log_cli_level=INFO - """ - ) - - result = testdir.runpytest(cli_args) - if cli_args == "--log-cli-level=WARNING": - result.stdout.fnmatch_lines( - [ - "*::test_log_1 ", - "*-- live log call --*", - "*WARNING*log message from test_log_1*", - "PASSED *100%*", - "=* 1 passed in *=", - ] - ) - assert "INFO" not in result.stdout.str() - else: - result.stdout.fnmatch_lines( - ["*test_log_cli_auto_enable*100%*", "=* 1 passed in *="] - ) - assert "INFO" not in result.stdout.str() - assert "WARNING" not in result.stdout.str() - - -def test_log_file_cli(testdir): - # Default log file level - testdir.makepyfile( - """ - import pytest - import logging - def test_log_file(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_file_handler.level == logging.WARNING - logging.getLogger('catchlog').info("This log message won't be shown") - logging.getLogger('catchlog').warning("This log message will be shown") - print('PASSED') - """ - ) - - log_file = testdir.tmpdir.join("pytest.log").strpath - - result = testdir.runpytest( - "-s", "--log-file={}".format(log_file), "--log-file-level=WARNING" - ) - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines(["test_log_file_cli.py PASSED"]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - assert os.path.isfile(log_file) - with open(log_file) as rfh: - contents = rfh.read() - assert "This log message will be shown" in contents - assert "This log message won't be shown" not in contents - - -def test_log_file_cli_level(testdir): - # Default log file level - testdir.makepyfile( - """ - import pytest - import logging - def test_log_file(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_file_handler.level == logging.INFO - logging.getLogger('catchlog').debug("This log message won't be shown") - logging.getLogger('catchlog').info("This log message will be shown") - print('PASSED') - """ - ) - - log_file = testdir.tmpdir.join("pytest.log").strpath - - result = testdir.runpytest( - "-s", "--log-file={}".format(log_file), "--log-file-level=INFO" - ) - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines(["test_log_file_cli_level.py PASSED"]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - assert os.path.isfile(log_file) - with open(log_file) as rfh: - contents = rfh.read() - assert "This log message will be shown" in contents - assert "This log message won't be shown" not in contents - - -def test_log_level_not_changed_by_default(testdir): - testdir.makepyfile( - """ - import logging - def test_log_file(): - assert logging.getLogger().level == logging.WARNING - """ - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines("* 1 passed in *") - - -def test_log_file_ini(testdir): - log_file = testdir.tmpdir.join("pytest.log").strpath - - testdir.makeini( - """ - [pytest] - log_file={} - log_file_level=WARNING - """.format( - log_file - ) - ) - testdir.makepyfile( - """ - import pytest - import logging - def test_log_file(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_file_handler.level == logging.WARNING - logging.getLogger('catchlog').info("This log message won't be shown") - logging.getLogger('catchlog').warning("This log message will be shown") - print('PASSED') - """ - ) - - result = testdir.runpytest("-s") - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines(["test_log_file_ini.py PASSED"]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - assert os.path.isfile(log_file) - with open(log_file) as rfh: - contents = rfh.read() - assert "This log message will be shown" in contents - assert "This log message won't be shown" not in contents - - -def test_log_file_ini_level(testdir): - log_file = testdir.tmpdir.join("pytest.log").strpath - - testdir.makeini( - """ - [pytest] - log_file={} - log_file_level = INFO - """.format( - log_file - ) - ) - testdir.makepyfile( - """ - import pytest - import logging - def test_log_file(request): - plugin = request.config.pluginmanager.getplugin('logging-plugin') - assert plugin.log_file_handler.level == logging.INFO - logging.getLogger('catchlog').debug("This log message won't be shown") - logging.getLogger('catchlog').info("This log message will be shown") - print('PASSED') - """ - ) - - result = testdir.runpytest("-s") - - # fnmatch_lines does an assertion internally - result.stdout.fnmatch_lines(["test_log_file_ini_level.py PASSED"]) - - # make sure that that we get a '0' exit code for the testsuite - assert result.ret == 0 - assert os.path.isfile(log_file) - with open(log_file) as rfh: - contents = rfh.read() - assert "This log message will be shown" in contents - assert "This log message won't be shown" not in contents - - -@pytest.mark.parametrize("has_capture_manager", [True, False]) -def test_live_logging_suspends_capture(has_capture_manager, request): - """Test that capture manager is suspended when we emitting messages for live logging. - - This tests the implementation calls instead of behavior because it is difficult/impossible to do it using - ``testdir`` facilities because they do their own capturing. - - We parametrize the test to also make sure _LiveLoggingStreamHandler works correctly if no capture manager plugin - is installed. - """ - import logging - from functools import partial - from _pytest.capture import CaptureManager - from _pytest.logging import _LiveLoggingStreamHandler - - class MockCaptureManager: - calls = [] - - def suspend_global_capture(self): - self.calls.append("suspend_global_capture") - - def resume_global_capture(self): - self.calls.append("resume_global_capture") - - # sanity check - assert CaptureManager.suspend_capture_item - assert CaptureManager.resume_global_capture - - class DummyTerminal(six.StringIO): - - def section(self, *args, **kwargs): - pass - - out_file = DummyTerminal() - capture_manager = MockCaptureManager() if has_capture_manager else None - handler = _LiveLoggingStreamHandler(out_file, capture_manager) - handler.set_when("call") - - logger = logging.getLogger(__name__ + ".test_live_logging_suspends_capture") - logger.addHandler(handler) - request.addfinalizer(partial(logger.removeHandler, handler)) - - logger.critical("some message") - if has_capture_manager: - assert ( - MockCaptureManager.calls - == ["suspend_global_capture", "resume_global_capture"] - ) - else: - assert MockCaptureManager.calls == [] - assert out_file.getvalue() == "\nsome message\n" diff --git a/third_party/python/pytest/testing/python/approx.py b/third_party/python/pytest/testing/python/approx.py deleted file mode 100644 index 9e25feb0b4d6..000000000000 --- a/third_party/python/pytest/testing/python/approx.py +++ /dev/null @@ -1,406 +0,0 @@ -# encoding: utf-8 -import operator -import sys -import pytest -import doctest - -from pytest import approx -from operator import eq, ne -from decimal import Decimal -from fractions import Fraction - -inf, nan = float("inf"), float("nan") - - -class MyDocTestRunner(doctest.DocTestRunner): - - def __init__(self): - doctest.DocTestRunner.__init__(self) - - def report_failure(self, out, test, example, got): - raise AssertionError( - "'{}' evaluates to '{}', not '{}'".format( - example.source.strip(), got.strip(), example.want.strip() - ) - ) - - -class TestApprox(object): - - def test_repr_string(self): - plus_minus = u"\u00b1" if sys.version_info[0] > 2 else u"+-" - tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf" - assert repr(approx(1.0)) == "1.0 {pm} {tol1}".format(pm=plus_minus, tol1=tol1) - assert ( - repr(approx([1.0, 2.0])) - == "approx([1.0 {pm} {tol1}, 2.0 {pm} {tol2}])".format( - pm=plus_minus, tol1=tol1, tol2=tol2 - ) - ) - assert ( - repr(approx((1.0, 2.0))) - == "approx((1.0 {pm} {tol1}, 2.0 {pm} {tol2}))".format( - pm=plus_minus, tol1=tol1, tol2=tol2 - ) - ) - assert repr(approx(inf)) == "inf" - assert repr(approx(1.0, rel=nan)) == "1.0 {pm} ???".format(pm=plus_minus) - assert ( - repr(approx(1.0, rel=inf)) - == "1.0 {pm} {infr}".format(pm=plus_minus, infr=infr) - ) - assert repr(approx(1.0j, rel=inf)) == "1j" - - # Dictionaries aren't ordered, so we need to check both orders. - assert repr(approx({"a": 1.0, "b": 2.0})) in ( - "approx({{'a': 1.0 {pm} {tol1}, 'b': 2.0 {pm} {tol2}}})".format( - pm=plus_minus, tol1=tol1, tol2=tol2 - ), - "approx({{'b': 2.0 {pm} {tol2}, 'a': 1.0 {pm} {tol1}}})".format( - pm=plus_minus, tol1=tol1, tol2=tol2 - ), - ) - - def test_operator_overloading(self): - assert 1 == approx(1, rel=1e-6, abs=1e-12) - assert not (1 != approx(1, rel=1e-6, abs=1e-12)) - assert 10 != approx(1, rel=1e-6, abs=1e-12) - assert not (10 == approx(1, rel=1e-6, abs=1e-12)) - - def test_exactly_equal(self): - examples = [ - (2.0, 2.0), - (0.1e200, 0.1e200), - (1.123e-300, 1.123e-300), - (12345, 12345.0), - (0.0, -0.0), - (345678, 345678), - (Decimal("1.0001"), Decimal("1.0001")), - (Fraction(1, 3), Fraction(-1, -3)), - ] - for a, x in examples: - assert a == approx(x) - - def test_opposite_sign(self): - examples = [(eq, 1e-100, -1e-100), (ne, 1e100, -1e100)] - for op, a, x in examples: - assert op(a, approx(x)) - - def test_zero_tolerance(self): - within_1e10 = [(1.1e-100, 1e-100), (-1.1e-100, -1e-100)] - for a, x in within_1e10: - assert x == approx(x, rel=0.0, abs=0.0) - assert a != approx(x, rel=0.0, abs=0.0) - assert a == approx(x, rel=0.0, abs=5e-101) - assert a != approx(x, rel=0.0, abs=5e-102) - assert a == approx(x, rel=5e-1, abs=0.0) - assert a != approx(x, rel=5e-2, abs=0.0) - - def test_negative_tolerance(self): - # Negative tolerances are not allowed. - illegal_kwargs = [ - dict(rel=-1e100), - dict(abs=-1e100), - dict(rel=1e100, abs=-1e100), - dict(rel=-1e100, abs=1e100), - dict(rel=-1e100, abs=-1e100), - ] - for kwargs in illegal_kwargs: - with pytest.raises(ValueError): - 1.1 == approx(1, **kwargs) - - def test_inf_tolerance(self): - # Everything should be equal if the tolerance is infinite. - large_diffs = [(1, 1000), (1e-50, 1e50), (-1.0, -1e300), (0.0, 10)] - for a, x in large_diffs: - assert a != approx(x, rel=0.0, abs=0.0) - assert a == approx(x, rel=inf, abs=0.0) - assert a == approx(x, rel=0.0, abs=inf) - assert a == approx(x, rel=inf, abs=inf) - - def test_inf_tolerance_expecting_zero(self): - # If the relative tolerance is zero but the expected value is infinite, - # the actual tolerance is a NaN, which should be an error. - illegal_kwargs = [dict(rel=inf, abs=0.0), dict(rel=inf, abs=inf)] - for kwargs in illegal_kwargs: - with pytest.raises(ValueError): - 1 == approx(0, **kwargs) - - def test_nan_tolerance(self): - illegal_kwargs = [dict(rel=nan), dict(abs=nan), dict(rel=nan, abs=nan)] - for kwargs in illegal_kwargs: - with pytest.raises(ValueError): - 1.1 == approx(1, **kwargs) - - def test_reasonable_defaults(self): - # Whatever the defaults are, they should work for numbers close to 1 - # than have a small amount of floating-point error. - assert 0.1 + 0.2 == approx(0.3) - - def test_default_tolerances(self): - # This tests the defaults as they are currently set. If you change the - # defaults, this test will fail but you should feel free to change it. - # None of the other tests (except the doctests) should be affected by - # the choice of defaults. - examples = [ - # Relative tolerance used. - (eq, 1e100 + 1e94, 1e100), - (ne, 1e100 + 2e94, 1e100), - (eq, 1e0 + 1e-6, 1e0), - (ne, 1e0 + 2e-6, 1e0), - # Absolute tolerance used. - (eq, 1e-100, +1e-106), - (eq, 1e-100, +2e-106), - (eq, 1e-100, 0), - ] - for op, a, x in examples: - assert op(a, approx(x)) - - def test_custom_tolerances(self): - assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e0) - assert 1e8 + 1e0 == approx(1e8, rel=5e-9, abs=5e0) - assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e-1) - assert 1e8 + 1e0 != approx(1e8, rel=5e-9, abs=5e-1) - - assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-8) - assert 1e0 + 1e-8 == approx(1e0, rel=5e-9, abs=5e-8) - assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-9) - assert 1e0 + 1e-8 != approx(1e0, rel=5e-9, abs=5e-9) - - assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-16) - assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-9, abs=5e-16) - assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-17) - assert 1e-8 + 1e-16 != approx(1e-8, rel=5e-9, abs=5e-17) - - def test_relative_tolerance(self): - within_1e8_rel = [(1e8 + 1e0, 1e8), (1e0 + 1e-8, 1e0), (1e-8 + 1e-16, 1e-8)] - for a, x in within_1e8_rel: - assert a == approx(x, rel=5e-8, abs=0.0) - assert a != approx(x, rel=5e-9, abs=0.0) - - def test_absolute_tolerance(self): - within_1e8_abs = [(1e8 + 9e-9, 1e8), (1e0 + 9e-9, 1e0), (1e-8 + 9e-9, 1e-8)] - for a, x in within_1e8_abs: - assert a == approx(x, rel=0, abs=5e-8) - assert a != approx(x, rel=0, abs=5e-9) - - def test_expecting_zero(self): - examples = [ - (ne, 1e-6, 0.0), - (ne, -1e-6, 0.0), - (eq, 1e-12, 0.0), - (eq, -1e-12, 0.0), - (ne, 2e-12, 0.0), - (ne, -2e-12, 0.0), - (ne, inf, 0.0), - (ne, nan, 0.0), - ] - for op, a, x in examples: - assert op(a, approx(x, rel=0.0, abs=1e-12)) - assert op(a, approx(x, rel=1e-6, abs=1e-12)) - - def test_expecting_inf(self): - examples = [ - (eq, inf, inf), - (eq, -inf, -inf), - (ne, inf, -inf), - (ne, 0.0, inf), - (ne, nan, inf), - ] - for op, a, x in examples: - assert op(a, approx(x)) - - def test_expecting_nan(self): - examples = [ - (eq, nan, nan), - (eq, -nan, -nan), - (eq, nan, -nan), - (ne, 0.0, nan), - (ne, inf, nan), - ] - for op, a, x in examples: - # Nothing is equal to NaN by default. - assert a != approx(x) - - # If ``nan_ok=True``, then NaN is equal to NaN. - assert op(a, approx(x, nan_ok=True)) - - def test_int(self): - within_1e6 = [(1000001, 1000000), (-1000001, -1000000)] - for a, x in within_1e6: - assert a == approx(x, rel=5e-6, abs=0) - assert a != approx(x, rel=5e-7, abs=0) - assert approx(x, rel=5e-6, abs=0) == a - assert approx(x, rel=5e-7, abs=0) != a - - def test_decimal(self): - within_1e6 = [ - (Decimal("1.000001"), Decimal("1.0")), - (Decimal("-1.000001"), Decimal("-1.0")), - ] - for a, x in within_1e6: - assert a == approx(x) - assert a == approx(x, rel=Decimal("5e-6"), abs=0) - assert a != approx(x, rel=Decimal("5e-7"), abs=0) - assert approx(x, rel=Decimal("5e-6"), abs=0) == a - assert approx(x, rel=Decimal("5e-7"), abs=0) != a - - def test_fraction(self): - within_1e6 = [ - (1 + Fraction(1, 1000000), Fraction(1)), - (-1 - Fraction(-1, 1000000), Fraction(-1)), - ] - for a, x in within_1e6: - assert a == approx(x, rel=5e-6, abs=0) - assert a != approx(x, rel=5e-7, abs=0) - assert approx(x, rel=5e-6, abs=0) == a - assert approx(x, rel=5e-7, abs=0) != a - - def test_complex(self): - within_1e6 = [ - (1.000001 + 1.0j, 1.0 + 1.0j), - (1.0 + 1.000001j, 1.0 + 1.0j), - (-1.000001 + 1.0j, -1.0 + 1.0j), - (1.0 - 1.000001j, 1.0 - 1.0j), - ] - for a, x in within_1e6: - assert a == approx(x, rel=5e-6, abs=0) - assert a != approx(x, rel=5e-7, abs=0) - assert approx(x, rel=5e-6, abs=0) == a - assert approx(x, rel=5e-7, abs=0) != a - - def test_list(self): - actual = [1 + 1e-7, 2 + 1e-8] - expected = [1, 2] - - # Return false if any element is outside the tolerance. - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == actual - assert approx(expected, rel=5e-8, abs=0) != actual - - def test_list_wrong_len(self): - assert [1, 2] != approx([1]) - assert [1, 2] != approx([1, 2, 3]) - - def test_tuple(self): - actual = (1 + 1e-7, 2 + 1e-8) - expected = (1, 2) - - # Return false if any element is outside the tolerance. - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == actual - assert approx(expected, rel=5e-8, abs=0) != actual - - def test_tuple_wrong_len(self): - assert (1, 2) != approx((1,)) - assert (1, 2) != approx((1, 2, 3)) - - def test_dict(self): - actual = {"a": 1 + 1e-7, "b": 2 + 1e-8} - # Dictionaries became ordered in python3.6, so switch up the order here - # to make sure it doesn't matter. - expected = {"b": 2, "a": 1} - - # Return false if any element is outside the tolerance. - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == actual - assert approx(expected, rel=5e-8, abs=0) != actual - - def test_dict_wrong_len(self): - assert {"a": 1, "b": 2} != approx({"a": 1}) - assert {"a": 1, "b": 2} != approx({"a": 1, "c": 2}) - assert {"a": 1, "b": 2} != approx({"a": 1, "b": 2, "c": 3}) - - def test_numpy_array(self): - np = pytest.importorskip("numpy") - - actual = np.array([1 + 1e-7, 2 + 1e-8]) - expected = np.array([1, 2]) - - # Return false if any element is outside the tolerance. - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == expected - assert approx(expected, rel=5e-8, abs=0) != actual - - # Should be able to compare lists with numpy arrays. - assert list(actual) == approx(expected, rel=5e-7, abs=0) - assert list(actual) != approx(expected, rel=5e-8, abs=0) - assert actual == approx(list(expected), rel=5e-7, abs=0) - assert actual != approx(list(expected), rel=5e-8, abs=0) - - def test_numpy_array_wrong_shape(self): - np = pytest.importorskip("numpy") - - a12 = np.array([[1, 2]]) - a21 = np.array([[1], [2]]) - - assert a12 != approx(a21) - assert a21 != approx(a12) - - def test_doctests(self): - parser = doctest.DocTestParser() - test = parser.get_doctest( - approx.__doc__, {"approx": approx}, approx.__name__, None, None - ) - runner = MyDocTestRunner() - runner.run(test) - - def test_unicode_plus_minus(self, testdir): - """ - Comparing approx instances inside lists should not produce an error in the detailed diff. - Integration test for issue #2111. - """ - testdir.makepyfile( - """ - import pytest - def test_foo(): - assert [3] == [pytest.approx(4)] - """ - ) - expected = "4.0e-06" - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*At index 0 diff: 3 != 4 * {}".format(expected), "=* 1 failed in *="] - ) - - @pytest.mark.parametrize( - "op", - [ - pytest.param(operator.le, id="<="), - pytest.param(operator.lt, id="<"), - pytest.param(operator.ge, id=">="), - pytest.param(operator.gt, id=">"), - ], - ) - def test_comparison_operator_type_error(self, op): - """ - pytest.approx should raise TypeError for operators other than == and != (#2003). - """ - with pytest.raises(TypeError): - op(1, approx(1, rel=1e-6, abs=1e-12)) - - def test_numpy_array_with_scalar(self): - np = pytest.importorskip("numpy") - - actual = np.array([1 + 1e-7, 1 - 1e-8]) - expected = 1.0 - - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == actual - assert approx(expected, rel=5e-8, abs=0) != actual - - def test_numpy_scalar_with_array(self): - np = pytest.importorskip("numpy") - - actual = 1.0 - expected = np.array([1 + 1e-7, 1 - 1e-8]) - - assert actual == approx(expected, rel=5e-7, abs=0) - assert actual != approx(expected, rel=5e-8, abs=0) - assert approx(expected, rel=5e-7, abs=0) == actual - assert approx(expected, rel=5e-8, abs=0) != actual diff --git a/third_party/python/pytest/testing/python/collect.py b/third_party/python/pytest/testing/python/collect.py deleted file mode 100644 index 724504b1af70..000000000000 --- a/third_party/python/pytest/testing/python/collect.py +++ /dev/null @@ -1,1555 +0,0 @@ -# -*- coding: utf-8 -*- -import os -import sys -from textwrap import dedent - -import _pytest._code -import pytest -from _pytest.main import EXIT_NOTESTSCOLLECTED -from _pytest.nodes import Collector - -ignore_parametrized_marks = pytest.mark.filterwarnings( - "ignore:Applying marks directly to parameters" -) - - -class TestModule(object): - - def test_failing_import(self, testdir): - modcol = testdir.getmodulecol("import alksdjalskdjalkjals") - pytest.raises(Collector.CollectError, modcol.collect) - - def test_import_duplicate(self, testdir): - a = testdir.mkdir("a") - b = testdir.mkdir("b") - p = a.ensure("test_whatever.py") - p.pyimport() - del sys.modules["test_whatever"] - b.ensure("test_whatever.py") - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*import*mismatch*", - "*imported*test_whatever*", - "*%s*" % a.join("test_whatever.py"), - "*not the same*", - "*%s*" % b.join("test_whatever.py"), - "*HINT*", - ] - ) - - def test_import_prepend_append(self, testdir, monkeypatch): - syspath = list(sys.path) - monkeypatch.setattr(sys, "path", syspath) - root1 = testdir.mkdir("root1") - root2 = testdir.mkdir("root2") - root1.ensure("x456.py") - root2.ensure("x456.py") - p = root2.join("test_x456.py") - monkeypatch.syspath_prepend(str(root1)) - p.write( - dedent( - """\ - import x456 - def test(): - assert x456.__file__.startswith(%r) - """ - % str(root2) - ) - ) - with root2.as_cwd(): - reprec = testdir.inline_run("--import-mode=append") - reprec.assertoutcome(passed=0, failed=1) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_syntax_error_in_module(self, testdir): - modcol = testdir.getmodulecol("this is a syntax error") - pytest.raises(modcol.CollectError, modcol.collect) - pytest.raises(modcol.CollectError, modcol.collect) - - def test_module_considers_pluginmanager_at_import(self, testdir): - modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") - pytest.raises(ImportError, lambda: modcol.obj) - - def test_invalid_test_module_name(self, testdir): - a = testdir.mkdir("a") - a.ensure("test_one.part1.py") - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - [ - "ImportError while importing test module*test_one.part1*", - "Hint: make sure your test modules/packages have valid Python names.", - ] - ) - - @pytest.mark.parametrize("verbose", [0, 1, 2]) - def test_show_traceback_import_error(self, testdir, verbose): - """Import errors when collecting modules should display the traceback (#1976). - - With low verbosity we omit pytest and internal modules, otherwise show all traceback entries. - """ - testdir.makepyfile( - foo_traceback_import_error=""" - from bar_traceback_import_error import NOT_AVAILABLE - """, - bar_traceback_import_error="", - ) - testdir.makepyfile( - """ - import foo_traceback_import_error - """ - ) - args = ("-v",) * verbose - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines( - [ - "ImportError while importing test module*", - "Traceback:", - "*from bar_traceback_import_error import NOT_AVAILABLE", - "*cannot import name *NOT_AVAILABLE*", - ] - ) - assert result.ret == 2 - - stdout = result.stdout.str() - for name in ("_pytest", os.path.join("py", "_path")): - if verbose == 2: - assert name in stdout - else: - assert name not in stdout - - def test_show_traceback_import_error_unicode(self, testdir): - """Check test modules collected which raise ImportError with unicode messages - are handled properly (#2336). - """ - testdir.makepyfile( - u""" - # -*- coding: utf-8 -*- - raise ImportError(u'Something bad happened ☺') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "ImportError while importing test module*", - "Traceback:", - "*raise ImportError*Something bad happened*", - ] - ) - assert result.ret == 2 - - -class TestClass(object): - - def test_class_with_init_warning(self, testdir): - testdir.makepyfile( - """ - class TestClass1(object): - def __init__(self): - pass - """ - ) - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - [ - "*cannot collect test class 'TestClass1' because it has a __init__ constructor" - ] - ) - - def test_class_subclassobject(self, testdir): - testdir.getmodulecol( - """ - class test(object): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*collected 0*"]) - - def test_static_method(self, testdir): - """Support for collecting staticmethod tests (#2528, #2699)""" - testdir.getmodulecol( - """ - import pytest - class Test(object): - @staticmethod - def test_something(): - pass - - @pytest.fixture - def fix(self): - return 1 - - @staticmethod - def test_fix(fix): - assert fix == 1 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*collected 2 items*", "*2 passed in*"]) - - def test_setup_teardown_class_as_classmethod(self, testdir): - testdir.makepyfile( - test_mod1=""" - class TestClassMethod(object): - @classmethod - def setup_class(cls): - pass - def test_1(self): - pass - @classmethod - def teardown_class(cls): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_issue1035_obj_has_getattr(self, testdir): - modcol = testdir.getmodulecol( - """ - class Chameleon(object): - def __getattr__(self, name): - return True - chameleon = Chameleon() - """ - ) - colitems = modcol.collect() - assert len(colitems) == 0 - - def test_issue1579_namedtuple(self, testdir): - testdir.makepyfile( - """ - import collections - - TestCase = collections.namedtuple('TestCase', ['a']) - """ - ) - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - "*cannot collect test class 'TestCase' " - "because it has a __new__ constructor*" - ) - - def test_issue2234_property(self, testdir): - testdir.makepyfile( - """ - class TestCase(object): - @property - def prop(self): - raise NotImplementedError() - """ - ) - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - - -class TestGenerator(object): - - def test_generative_functions(self, testdir): - modcol = testdir.getmodulecol( - """ - def func1(arg, arg2): - assert arg == arg2 - - def test_gen(): - yield func1, 17, 3*5 - yield func1, 42, 6*7 - """ - ) - colitems = modcol.collect() - assert len(colitems) == 1 - gencol = colitems[0] - assert isinstance(gencol, pytest.Generator) - gencolitems = gencol.collect() - assert len(gencolitems) == 2 - assert isinstance(gencolitems[0], pytest.Function) - assert isinstance(gencolitems[1], pytest.Function) - assert gencolitems[0].name == "[0]" - assert gencolitems[0].obj.__name__ == "func1" - - def test_generative_methods(self, testdir): - modcol = testdir.getmodulecol( - """ - def func1(arg, arg2): - assert arg == arg2 - class TestGenMethods(object): - def test_gen(self): - yield func1, 17, 3*5 - yield func1, 42, 6*7 - """ - ) - gencol = modcol.collect()[0].collect()[0].collect()[0] - assert isinstance(gencol, pytest.Generator) - gencolitems = gencol.collect() - assert len(gencolitems) == 2 - assert isinstance(gencolitems[0], pytest.Function) - assert isinstance(gencolitems[1], pytest.Function) - assert gencolitems[0].name == "[0]" - assert gencolitems[0].obj.__name__ == "func1" - - def test_generative_functions_with_explicit_names(self, testdir): - modcol = testdir.getmodulecol( - """ - def func1(arg, arg2): - assert arg == arg2 - - def test_gen(): - yield "seventeen", func1, 17, 3*5 - yield "fortytwo", func1, 42, 6*7 - """ - ) - colitems = modcol.collect() - assert len(colitems) == 1 - gencol = colitems[0] - assert isinstance(gencol, pytest.Generator) - gencolitems = gencol.collect() - assert len(gencolitems) == 2 - assert isinstance(gencolitems[0], pytest.Function) - assert isinstance(gencolitems[1], pytest.Function) - assert gencolitems[0].name == "['seventeen']" - assert gencolitems[0].obj.__name__ == "func1" - assert gencolitems[1].name == "['fortytwo']" - assert gencolitems[1].obj.__name__ == "func1" - - def test_generative_functions_unique_explicit_names(self, testdir): - # generative - modcol = testdir.getmodulecol( - """ - def func(): pass - def test_gen(): - yield "name", func - yield "name", func - """ - ) - colitems = modcol.collect() - assert len(colitems) == 1 - gencol = colitems[0] - assert isinstance(gencol, pytest.Generator) - pytest.raises(ValueError, "gencol.collect()") - - def test_generative_methods_with_explicit_names(self, testdir): - modcol = testdir.getmodulecol( - """ - def func1(arg, arg2): - assert arg == arg2 - class TestGenMethods(object): - def test_gen(self): - yield "m1", func1, 17, 3*5 - yield "m2", func1, 42, 6*7 - """ - ) - gencol = modcol.collect()[0].collect()[0].collect()[0] - assert isinstance(gencol, pytest.Generator) - gencolitems = gencol.collect() - assert len(gencolitems) == 2 - assert isinstance(gencolitems[0], pytest.Function) - assert isinstance(gencolitems[1], pytest.Function) - assert gencolitems[0].name == "['m1']" - assert gencolitems[0].obj.__name__ == "func1" - assert gencolitems[1].name == "['m2']" - assert gencolitems[1].obj.__name__ == "func1" - - def test_order_of_execution_generator_same_codeline(self, testdir, tmpdir): - o = testdir.makepyfile( - """ - from __future__ import print_function - def test_generative_order_of_execution(): - import py, pytest - test_list = [] - expected_list = list(range(6)) - - def list_append(item): - test_list.append(item) - - def assert_order_of_execution(): - print('expected order', expected_list) - print('but got ', test_list) - assert test_list == expected_list - - for i in expected_list: - yield list_append, i - yield assert_order_of_execution - """ - ) - reprec = testdir.inline_run(o) - passed, skipped, failed = reprec.countoutcomes() - assert passed == 7 - assert not skipped and not failed - - def test_order_of_execution_generator_different_codeline(self, testdir): - o = testdir.makepyfile( - """ - from __future__ import print_function - def test_generative_tests_different_codeline(): - import py, pytest - test_list = [] - expected_list = list(range(3)) - - def list_append_2(): - test_list.append(2) - - def list_append_1(): - test_list.append(1) - - def list_append_0(): - test_list.append(0) - - def assert_order_of_execution(): - print('expected order', expected_list) - print('but got ', test_list) - assert test_list == expected_list - - yield list_append_0 - yield list_append_1 - yield list_append_2 - yield assert_order_of_execution - """ - ) - reprec = testdir.inline_run(o) - passed, skipped, failed = reprec.countoutcomes() - assert passed == 4 - assert not skipped and not failed - - def test_setupstate_is_preserved_134(self, testdir): - # yield-based tests are messy wrt to setupstate because - # during collection they already invoke setup functions - # and then again when they are run. For now, we want to make sure - # that the old 1.3.4 behaviour is preserved such that all - # yielded functions all share the same "self" instance that - # has been used during collection. - o = testdir.makepyfile( - """ - setuplist = [] - class TestClass(object): - def setup_method(self, func): - #print "setup_method", self, func - setuplist.append(self) - self.init = 42 - - def teardown_method(self, func): - self.init = None - - def test_func1(self): - pass - - def test_func2(self): - yield self.func2 - yield self.func2 - - def func2(self): - assert self.init - - def test_setuplist(): - # once for test_func2 during collection - # once for test_func1 during test run - # once for test_func2 during test run - #print setuplist - assert len(setuplist) == 3, len(setuplist) - assert setuplist[0] == setuplist[2], setuplist - assert setuplist[1] != setuplist[2], setuplist - """ - ) - reprec = testdir.inline_run(o, "-v") - passed, skipped, failed = reprec.countoutcomes() - assert passed == 4 - assert not skipped and not failed - - -class TestFunction(object): - - def test_getmodulecollector(self, testdir): - item = testdir.getitem("def test_func(): pass") - modcol = item.getparent(pytest.Module) - assert isinstance(modcol, pytest.Module) - assert hasattr(modcol.obj, "test_func") - - def test_function_as_object_instance_ignored(self, testdir): - testdir.makepyfile( - """ - class A(object): - def __call__(self, tmpdir): - 0/0 - - test_a = A() - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome() - - def test_function_equality(self, testdir, tmpdir): - from _pytest.fixtures import FixtureManager - - config = testdir.parseconfigure() - session = testdir.Session(config) - session._fixturemanager = FixtureManager(session) - - def func1(): - pass - - def func2(): - pass - - f1 = pytest.Function( - name="name", parent=session, config=config, args=(1,), callobj=func1 - ) - assert f1 == f1 - f2 = pytest.Function(name="name", config=config, callobj=func2, parent=session) - assert f1 != f2 - - def test_issue197_parametrize_emptyset(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('arg', []) - def test_function(arg): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=1) - - def test_single_tuple_unwraps_values(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize(('arg',), [(1,)]) - def test_function(arg): - assert arg == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_issue213_parametrize_value_no_equal(self, testdir): - testdir.makepyfile( - """ - import pytest - class A(object): - def __eq__(self, other): - raise ValueError("not possible") - @pytest.mark.parametrize('arg', [A()]) - def test_function(arg): - assert arg.__class__.__name__ == "A" - """ - ) - reprec = testdir.inline_run("--fulltrace") - reprec.assertoutcome(passed=1) - - def test_parametrize_with_non_hashable_values(self, testdir): - """Test parametrization with non-hashable values.""" - testdir.makepyfile( - """ - archival_mapping = { - '1.0': {'tag': '1.0'}, - '1.2.2a1': {'tag': 'release-1.2.2a1'}, - } - - import pytest - @pytest.mark.parametrize('key value'.split(), - archival_mapping.items()) - def test_archival_to_version(key, value): - assert key in archival_mapping - assert value == archival_mapping[key] - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(passed=2) - - def test_parametrize_with_non_hashable_values_indirect(self, testdir): - """Test parametrization with non-hashable values with indirect parametrization.""" - testdir.makepyfile( - """ - archival_mapping = { - '1.0': {'tag': '1.0'}, - '1.2.2a1': {'tag': 'release-1.2.2a1'}, - } - - import pytest - - @pytest.fixture - def key(request): - return request.param - - @pytest.fixture - def value(request): - return request.param - - @pytest.mark.parametrize('key value'.split(), - archival_mapping.items(), indirect=True) - def test_archival_to_version(key, value): - assert key in archival_mapping - assert value == archival_mapping[key] - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(passed=2) - - def test_parametrize_overrides_fixture(self, testdir): - """Test parametrization when parameter overrides existing fixture with same name.""" - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def value(): - return 'value' - - @pytest.mark.parametrize('value', - ['overridden']) - def test_overridden_via_param(value): - assert value == 'overridden' - - @pytest.mark.parametrize('somevalue', ['overridden']) - def test_not_overridden(value, somevalue): - assert value == 'value' - assert somevalue == 'overridden' - - @pytest.mark.parametrize('other,value', [('foo', 'overridden')]) - def test_overridden_via_multiparam(other, value): - assert other == 'foo' - assert value == 'overridden' - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(passed=3) - - def test_parametrize_overrides_parametrized_fixture(self, testdir): - """Test parametrization when parameter overrides existing parametrized fixture with same name.""" - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[1, 2]) - def value(request): - return request.param - - @pytest.mark.parametrize('value', - ['overridden']) - def test_overridden_via_param(value): - assert value == 'overridden' - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(passed=1) - - @ignore_parametrized_marks - def test_parametrize_with_mark(self, testdir): - items = testdir.getitems( - """ - import pytest - @pytest.mark.foo - @pytest.mark.parametrize('arg', [ - 1, - pytest.mark.bar(pytest.mark.baz(2)) - ]) - def test_function(arg): - pass - """ - ) - keywords = [item.keywords for item in items] - assert ( - "foo" in keywords[0] - and "bar" not in keywords[0] - and "baz" not in keywords[0] - ) - assert "foo" in keywords[1] and "bar" in keywords[1] and "baz" in keywords[1] - - def test_function_equality_with_callspec(self, testdir, tmpdir): - items = testdir.getitems( - """ - import pytest - @pytest.mark.parametrize('arg', [1,2]) - def test_function(arg): - pass - """ - ) - assert items[0] != items[1] - assert not (items[0] == items[1]) - - def test_pyfunc_call(self, testdir): - item = testdir.getitem("def test_func(): raise ValueError") - config = item.config - - class MyPlugin1(object): - - def pytest_pyfunc_call(self, pyfuncitem): - raise ValueError - - class MyPlugin2(object): - - def pytest_pyfunc_call(self, pyfuncitem): - return True - - config.pluginmanager.register(MyPlugin1()) - config.pluginmanager.register(MyPlugin2()) - config.hook.pytest_runtest_setup(item=item) - config.hook.pytest_pyfunc_call(pyfuncitem=item) - - def test_multiple_parametrize(self, testdir): - modcol = testdir.getmodulecol( - """ - import pytest - @pytest.mark.parametrize('x', [0, 1]) - @pytest.mark.parametrize('y', [2, 3]) - def test1(x, y): - pass - """ - ) - colitems = modcol.collect() - assert colitems[0].name == "test1[2-0]" - assert colitems[1].name == "test1[2-1]" - assert colitems[2].name == "test1[3-0]" - assert colitems[3].name == "test1[3-1]" - - def test_issue751_multiple_parametrize_with_ids(self, testdir): - modcol = testdir.getmodulecol( - """ - import pytest - @pytest.mark.parametrize('x', [0], ids=['c']) - @pytest.mark.parametrize('y', [0, 1], ids=['a', 'b']) - class Test(object): - def test1(self, x, y): - pass - def test2(self, x, y): - pass - """ - ) - colitems = modcol.collect()[0].collect()[0].collect() - assert colitems[0].name == "test1[a-c]" - assert colitems[1].name == "test1[b-c]" - assert colitems[2].name == "test2[a-c]" - assert colitems[3].name == "test2[b-c]" - - @ignore_parametrized_marks - def test_parametrize_skipif(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.skipif('True') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_skip_if(x): - assert x < 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 2 passed, 1 skipped in *") - - @ignore_parametrized_marks - def test_parametrize_skip(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.skip('') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_skip(x): - assert x < 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 2 passed, 1 skipped in *") - - @ignore_parametrized_marks - def test_parametrize_skipif_no_skip(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.skipif('False') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_skipif_no_skip(x): - assert x < 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 1 failed, 2 passed in *") - - @ignore_parametrized_marks - def test_parametrize_xfail(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.xfail('True') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_xfail(x): - assert x < 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 2 passed, 1 xfailed in *") - - @ignore_parametrized_marks - def test_parametrize_passed(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.xfail('True') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_xfail(x): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 2 passed, 1 xpassed in *") - - @ignore_parametrized_marks - def test_parametrize_xfail_passed(self, testdir): - testdir.makepyfile( - """ - import pytest - - m = pytest.mark.xfail('False') - - @pytest.mark.parametrize('x', [0, 1, m(2)]) - def test_passed(x): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("* 3 passed in *") - - def test_function_original_name(self, testdir): - items = testdir.getitems( - """ - import pytest - @pytest.mark.parametrize('arg', [1,2]) - def test_func(arg): - pass - """ - ) - assert [x.originalname for x in items] == ["test_func", "test_func"] - - -class TestSorting(object): - - def test_check_equality(self, testdir): - modcol = testdir.getmodulecol( - """ - def test_pass(): pass - def test_fail(): assert 0 - """ - ) - fn1 = testdir.collect_by_name(modcol, "test_pass") - assert isinstance(fn1, pytest.Function) - fn2 = testdir.collect_by_name(modcol, "test_pass") - assert isinstance(fn2, pytest.Function) - - assert fn1 == fn2 - assert fn1 != modcol - if sys.version_info < (3, 0): - assert cmp(fn1, fn2) == 0 # NOQA - assert hash(fn1) == hash(fn2) - - fn3 = testdir.collect_by_name(modcol, "test_fail") - assert isinstance(fn3, pytest.Function) - assert not (fn1 == fn3) - assert fn1 != fn3 - - for fn in fn1, fn2, fn3: - assert fn != 3 - assert fn != modcol - assert fn != [1, 2, 3] - assert [1, 2, 3] != fn - assert modcol != fn - - def test_allow_sane_sorting_for_decorators(self, testdir): - modcol = testdir.getmodulecol( - """ - def dec(f): - g = lambda: f(2) - g.place_as = f - return g - - - def test_b(y): - pass - test_b = dec(test_b) - - def test_a(y): - pass - test_a = dec(test_a) - """ - ) - colitems = modcol.collect() - assert len(colitems) == 2 - assert [item.name for item in colitems] == ["test_b", "test_a"] - - -class TestConftestCustomization(object): - - def test_pytest_pycollect_module(self, testdir): - testdir.makeconftest( - """ - import pytest - class MyModule(pytest.Module): - pass - def pytest_pycollect_makemodule(path, parent): - if path.basename == "test_xyz.py": - return MyModule(path, parent) - """ - ) - testdir.makepyfile("def test_some(): pass") - testdir.makepyfile(test_xyz="def test_func(): pass") - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["* 3 - - def test_traceback_error_during_import(self, testdir): - testdir.makepyfile( - """ - x = 1 - x = 2 - x = 17 - asd - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - out = result.stdout.str() - assert "x = 1" not in out - assert "x = 2" not in out - result.stdout.fnmatch_lines([" *asd*", "E*NameError*"]) - result = testdir.runpytest("--fulltrace") - out = result.stdout.str() - assert "x = 1" in out - assert "x = 2" in out - result.stdout.fnmatch_lines([">*asd*", "E*NameError*"]) - - def test_traceback_filter_error_during_fixture_collection(self, testdir): - """integration test for issue #995. - """ - testdir.makepyfile( - """ - import pytest - - def fail_me(func): - ns = {} - exec('def w(): raise ValueError("fail me")', ns) - return ns['w'] - - @pytest.fixture(scope='class') - @fail_me - def fail_fixture(): - pass - - def test_failing_fixture(fail_fixture): - pass - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - out = result.stdout.str() - assert "INTERNALERROR>" not in out - result.stdout.fnmatch_lines(["*ValueError: fail me*", "* 1 error in *"]) - - def test_filter_traceback_generated_code(self): - """test that filter_traceback() works with the fact that - py.code.Code.path attribute might return an str object. - In this case, one of the entries on the traceback was produced by - dynamically generated code. - See: https://bitbucket.org/pytest-dev/py/issues/71 - This fixes #995. - """ - from _pytest.python import filter_traceback - - try: - ns = {} - exec("def foo(): raise ValueError", ns) - ns["foo"]() - except ValueError: - _, _, tb = sys.exc_info() - - tb = _pytest._code.Traceback(tb) - assert isinstance(tb[-1].path, str) - assert not filter_traceback(tb[-1]) - - def test_filter_traceback_path_no_longer_valid(self, testdir): - """test that filter_traceback() works with the fact that - py.code.Code.path attribute might return an str object. - In this case, one of the files in the traceback no longer exists. - This fixes #1133. - """ - from _pytest.python import filter_traceback - - testdir.syspathinsert() - testdir.makepyfile( - filter_traceback_entry_as_str=""" - def foo(): - raise ValueError - """ - ) - try: - import filter_traceback_entry_as_str - - filter_traceback_entry_as_str.foo() - except ValueError: - _, _, tb = sys.exc_info() - - testdir.tmpdir.join("filter_traceback_entry_as_str.py").remove() - tb = _pytest._code.Traceback(tb) - assert isinstance(tb[-1].path, str) - assert filter_traceback(tb[-1]) - - -class TestReportInfo(object): - - def test_itemreport_reportinfo(self, testdir, linecomp): - testdir.makeconftest( - """ - import pytest - class MyFunction(pytest.Function): - def reportinfo(self): - return "ABCDE", 42, "custom" - def pytest_pycollect_makeitem(collector, name, obj): - if name == "test_func": - return MyFunction(name, parent=collector) - """ - ) - item = testdir.getitem("def test_func(): pass") - item.config.pluginmanager.getplugin("runner") - assert item.location == ("ABCDE", 42, "custom") - - def test_func_reportinfo(self, testdir): - item = testdir.getitem("def test_func(): pass") - fspath, lineno, modpath = item.reportinfo() - assert fspath == item.fspath - assert lineno == 0 - assert modpath == "test_func" - - def test_class_reportinfo(self, testdir): - modcol = testdir.getmodulecol( - """ - # lineno 0 - class TestClass(object): - def test_hello(self): pass - """ - ) - classcol = testdir.collect_by_name(modcol, "TestClass") - fspath, lineno, msg = classcol.reportinfo() - assert fspath == modcol.fspath - assert lineno == 1 - assert msg == "TestClass" - - def test_generator_reportinfo(self, testdir): - modcol = testdir.getmodulecol( - """ - # lineno 0 - def test_gen(): - def check(x): - assert x - yield check, 3 - """ - ) - gencol = testdir.collect_by_name(modcol, "test_gen") - fspath, lineno, modpath = gencol.reportinfo() - assert fspath == modcol.fspath - assert lineno == 1 - assert modpath == "test_gen" - - genitem = gencol.collect()[0] - fspath, lineno, modpath = genitem.reportinfo() - assert fspath == modcol.fspath - assert lineno == 2 - assert modpath == "test_gen[0]" - """ - def test_func(): - pass - def test_genfunc(): - def check(x): - pass - yield check, 3 - class TestClass(object): - def test_method(self): - pass - """ - - def test_reportinfo_with_nasty_getattr(self, testdir): - # https://github.com/pytest-dev/pytest/issues/1204 - modcol = testdir.getmodulecol( - """ - # lineno 0 - class TestClass(object): - def __getattr__(self, name): - return "this is not an int" - - def test_foo(self): - pass - """ - ) - classcol = testdir.collect_by_name(modcol, "TestClass") - instance = classcol.collect()[0] - fspath, lineno, msg = instance.reportinfo() - - -def test_customized_python_discovery(testdir): - testdir.makeini( - """ - [pytest] - python_files=check_*.py - python_classes=Check - python_functions=check - """ - ) - p = testdir.makepyfile( - """ - def check_simple(): - pass - class CheckMyApp(object): - def check_meth(self): - pass - """ - ) - p2 = p.new(basename=p.basename.replace("test", "check")) - p.move(p2) - result = testdir.runpytest("--collect-only", "-s") - result.stdout.fnmatch_lines( - ["*check_customized*", "*check_simple*", "*CheckMyApp*", "*check_meth*"] - ) - - result = testdir.runpytest() - assert result.ret == 0 - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_customized_python_discovery_functions(testdir): - testdir.makeini( - """ - [pytest] - python_functions=_test - """ - ) - testdir.makepyfile( - """ - def _test_underscore(): - pass - """ - ) - result = testdir.runpytest("--collect-only", "-s") - result.stdout.fnmatch_lines(["*_test_underscore*"]) - - result = testdir.runpytest() - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_collector_attributes(testdir): - testdir.makeconftest( - """ - import pytest - def pytest_pycollect_makeitem(collector): - assert collector.Function == pytest.Function - assert collector.Class == pytest.Class - assert collector.Instance == pytest.Instance - assert collector.Module == pytest.Module - """ - ) - testdir.makepyfile( - """ - def test_hello(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_customize_through_attributes(testdir): - testdir.makeconftest( - """ - import pytest - class MyFunction(pytest.Function): - pass - class MyInstance(pytest.Instance): - Function = MyFunction - class MyClass(pytest.Class): - Instance = MyInstance - - def pytest_pycollect_makeitem(collector, name, obj): - if name.startswith("MyTestClass"): - return MyClass(name, parent=collector) - """ - ) - testdir.makepyfile( - """ - class MyTestClass(object): - def test_hello(self): - pass - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines( - ["*MyClass*", "*MyInstance*", "*MyFunction*test_hello*"] - ) - - -def test_unorderable_types(testdir): - testdir.makepyfile( - """ - class TestJoinEmpty(object): - pass - - def make_test(): - class Test(object): - pass - Test.__name__ = "TestFoo" - return Test - TestFoo = make_test() - """ - ) - result = testdir.runpytest() - assert "TypeError" not in result.stdout.str() - assert result.ret == EXIT_NOTESTSCOLLECTED - - -def test_collect_functools_partial(testdir): - """ - Test that collection of functools.partial object works, and arguments - to the wrapped functions are dealt correctly (see #811). - """ - testdir.makepyfile( - """ - import functools - import pytest - - @pytest.fixture - def fix1(): - return 'fix1' - - @pytest.fixture - def fix2(): - return 'fix2' - - def check1(i, fix1): - assert i == 2 - assert fix1 == 'fix1' - - def check2(fix1, i): - assert i == 2 - assert fix1 == 'fix1' - - def check3(fix1, i, fix2): - assert i == 2 - assert fix1 == 'fix1' - assert fix2 == 'fix2' - - test_ok_1 = functools.partial(check1, i=2) - test_ok_2 = functools.partial(check1, i=2, fix1='fix1') - test_ok_3 = functools.partial(check1, 2) - test_ok_4 = functools.partial(check2, i=2) - test_ok_5 = functools.partial(check3, i=2) - test_ok_6 = functools.partial(check3, i=2, fix1='fix1') - - test_fail_1 = functools.partial(check2, 2) - test_fail_2 = functools.partial(check3, 2) - """ - ) - result = testdir.inline_run() - result.assertoutcome(passed=6, failed=2) - - -def test_dont_collect_non_function_callable(testdir): - """Test for issue https://github.com/pytest-dev/pytest/issues/331 - - In this case an INTERNALERROR occurred trying to report the failure of - a test like this one because py test failed to get the source lines. - """ - testdir.makepyfile( - """ - class Oh(object): - def __call__(self): - pass - - test_a = Oh() - - def test_real(): - pass - """ - ) - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - [ - "*collected 1 item*", - "*cannot collect 'test_a' because it is not a function*", - "*1 passed, 1 warnings in *", - ] - ) - - -def test_class_injection_does_not_break_collection(testdir): - """Tests whether injection during collection time will terminate testing. - - In this case the error should not occur if the TestClass itself - is modified during collection time, and the original method list - is still used for collection. - """ - testdir.makeconftest( - """ - from test_inject import TestClass - def pytest_generate_tests(metafunc): - TestClass.changed_var = {} - """ - ) - testdir.makepyfile( - test_inject=''' - class TestClass(object): - def test_injection(self): - """Test being parametrized.""" - pass - ''' - ) - result = testdir.runpytest() - assert "RuntimeError: dictionary changed size during iteration" not in result.stdout.str() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_syntax_error_with_non_ascii_chars(testdir): - """Fix decoding issue while formatting SyntaxErrors during collection (#578) - """ - testdir.makepyfile( - u""" - # -*- coding: UTF-8 -*- - - ☃ - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*ERROR collecting*", "*SyntaxError*", "*1 error in*"]) - - -def test_skip_duplicates_by_default(testdir): - """Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609) - - Ignore duplicate directories. - """ - a = testdir.mkdir("a") - fh = a.join("test_a.py") - fh.write( - _pytest._code.Source( - """ - import pytest - def test_real(): - pass - """ - ) - ) - result = testdir.runpytest(a.strpath, a.strpath) - result.stdout.fnmatch_lines(["*collected 1 item*"]) - - -def test_keep_duplicates(testdir): - """Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609) - - Use --keep-duplicates to collect tests from duplicate directories. - """ - a = testdir.mkdir("a") - fh = a.join("test_a.py") - fh.write( - _pytest._code.Source( - """ - import pytest - def test_real(): - pass - """ - ) - ) - result = testdir.runpytest("--keep-duplicates", a.strpath, a.strpath) - result.stdout.fnmatch_lines(["*collected 2 item*"]) diff --git a/third_party/python/pytest/testing/python/fixture.py b/third_party/python/pytest/testing/python/fixture.py deleted file mode 100644 index 6d2bb663b6cd..000000000000 --- a/third_party/python/pytest/testing/python/fixture.py +++ /dev/null @@ -1,4011 +0,0 @@ -from textwrap import dedent - -import _pytest._code -import pytest -from _pytest.pytester import get_public_names -from _pytest.fixtures import FixtureLookupError, FixtureRequest -from _pytest import fixtures - - -def test_getfuncargnames(): - - def f(): - pass - - assert not fixtures.getfuncargnames(f) - - def g(arg): - pass - - assert fixtures.getfuncargnames(g) == ("arg",) - - def h(arg1, arg2="hello"): - pass - - assert fixtures.getfuncargnames(h) == ("arg1",) - - def h(arg1, arg2, arg3="hello"): - pass - - assert fixtures.getfuncargnames(h) == ("arg1", "arg2") - - class A(object): - - def f(self, arg1, arg2="hello"): - pass - - @staticmethod - def static(arg1, arg2): - pass - - assert fixtures.getfuncargnames(A().f) == ("arg1",) - assert fixtures.getfuncargnames(A.static, cls=A) == ("arg1", "arg2") - - -class TestFillFixtures(object): - - def test_fillfuncargs_exposed(self): - # used by oejskit, kept for compatibility - assert pytest._fillfuncargs == fixtures.fillfixtures - - def test_funcarg_lookupfails(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def xyzsomething(request): - return 42 - - def test_func(some): - pass - """ - ) - result = testdir.runpytest() # "--collect-only") - assert result.ret != 0 - result.stdout.fnmatch_lines( - ["*def test_func(some)*", "*fixture*some*not found*", "*xyzsomething*"] - ) - - def test_funcarg_basic(self, testdir): - item = testdir.getitem( - """ - import pytest - - @pytest.fixture - def some(request): - return request.function.__name__ - @pytest.fixture - def other(request): - return 42 - def test_func(some, other): - pass - """ - ) - fixtures.fillfixtures(item) - del item.funcargs["request"] - assert len(get_public_names(item.funcargs)) == 2 - assert item.funcargs["some"] == "test_func" - assert item.funcargs["other"] == 42 - - def test_funcarg_lookup_modulelevel(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def something(request): - return request.function.__name__ - - class TestClass(object): - def test_method(self, something): - assert something == "test_method" - def test_func(something): - assert something == "test_func" - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_funcarg_lookup_classlevel(self, testdir): - p = testdir.makepyfile( - """ - import pytest - class TestClass(object): - - @pytest.fixture - def something(self, request): - return request.instance - - def test_method(self, something): - assert something is self - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_conftest_funcargs_only_available_in_subdir(self, testdir): - sub1 = testdir.mkpydir("sub1") - sub2 = testdir.mkpydir("sub2") - sub1.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def arg1(request): - pytest.raises(Exception, "request.getfixturevalue('arg2')") - """ - ) - ) - sub2.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def arg2(request): - pytest.raises(Exception, "request.getfixturevalue('arg1')") - """ - ) - ) - - sub1.join("test_in_sub1.py").write("def test_1(arg1): pass") - sub2.join("test_in_sub2.py").write("def test_2(arg2): pass") - result = testdir.runpytest("-v") - result.assert_outcomes(passed=2) - - def test_extend_fixture_module_class(self, testdir): - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - - class TestSpam(object): - - @pytest.fixture - def spam(self, spam): - return spam * 2 - - def test_spam(self, spam): - assert spam == 'spamspam' - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_extend_fixture_conftest_module(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - """ - ) - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def spam(spam): - return spam * 2 - - def test_spam(spam): - assert spam == 'spamspam' - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_extend_fixture_conftest_conftest(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - """ - ) - pkg = testdir.mkpydir("pkg") - pkg.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - - @pytest.fixture - def spam(spam): - return spam * 2 - """ - ) - ) - testfile = pkg.join("test_spam.py") - testfile.write( - _pytest._code.Source( - """ - def test_spam(spam): - assert spam == "spamspam" - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_extend_fixture_conftest_plugin(self, testdir): - testdir.makepyfile( - testplugin=""" - import pytest - - @pytest.fixture - def foo(): - return 7 - """ - ) - testdir.syspathinsert() - testdir.makeconftest( - """ - import pytest - - pytest_plugins = 'testplugin' - - @pytest.fixture - def foo(foo): - return foo + 7 - """ - ) - testdir.makepyfile( - """ - def test_foo(foo): - assert foo == 14 - """ - ) - result = testdir.runpytest("-s") - assert result.ret == 0 - - def test_extend_fixture_plugin_plugin(self, testdir): - # Two plugins should extend each order in loading order - testdir.makepyfile( - testplugin0=""" - import pytest - - @pytest.fixture - def foo(): - return 7 - """ - ) - testdir.makepyfile( - testplugin1=""" - import pytest - - @pytest.fixture - def foo(foo): - return foo + 7 - """ - ) - testdir.syspathinsert() - testdir.makepyfile( - """ - pytest_plugins = ['testplugin0', 'testplugin1'] - - def test_foo(foo): - assert foo == 14 - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - - def test_override_parametrized_fixture_conftest_module(self, testdir): - """Test override of the parametrized fixture with non-parametrized one on the test module level.""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(params=[1, 2, 3]) - def spam(request): - return request.param - """ - ) - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - - def test_spam(spam): - assert spam == 'spam' - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_override_parametrized_fixture_conftest_conftest(self, testdir): - """Test override of the parametrized fixture with non-parametrized one on the conftest level.""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(params=[1, 2, 3]) - def spam(request): - return request.param - """ - ) - subdir = testdir.mkpydir("subdir") - subdir.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - """ - ) - ) - testfile = subdir.join("test_spam.py") - testfile.write( - _pytest._code.Source( - """ - def test_spam(spam): - assert spam == "spam" - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_override_non_parametrized_fixture_conftest_module(self, testdir): - """Test override of the non-parametrized fixture with parametrized one on the test module level.""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - """ - ) - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[1, 2, 3]) - def spam(request): - return request.param - - params = {'spam': 1} - - def test_spam(spam): - assert spam == params['spam'] - params['spam'] += 1 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*3 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*3 passed*"]) - - def test_override_non_parametrized_fixture_conftest_conftest(self, testdir): - """Test override of the non-parametrized fixture with parametrized one on the conftest level.""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def spam(): - return 'spam' - """ - ) - subdir = testdir.mkpydir("subdir") - subdir.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - - @pytest.fixture(params=[1, 2, 3]) - def spam(request): - return request.param - """ - ) - ) - testfile = subdir.join("test_spam.py") - testfile.write( - _pytest._code.Source( - """ - params = {'spam': 1} - - def test_spam(spam): - assert spam == params['spam'] - params['spam'] += 1 - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*3 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*3 passed*"]) - - def test_override_autouse_fixture_with_parametrized_fixture_conftest_conftest( - self, testdir - ): - """Test override of the autouse fixture with parametrized one on the conftest level. - This test covers the issue explained in issue 1601 - """ - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(autouse=True) - def spam(): - return 'spam' - """ - ) - subdir = testdir.mkpydir("subdir") - subdir.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - - @pytest.fixture(params=[1, 2, 3]) - def spam(request): - return request.param - """ - ) - ) - testfile = subdir.join("test_spam.py") - testfile.write( - _pytest._code.Source( - """ - params = {'spam': 1} - - def test_spam(spam): - assert spam == params['spam'] - params['spam'] += 1 - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*3 passed*"]) - result = testdir.runpytest(testfile) - result.stdout.fnmatch_lines(["*3 passed*"]) - - def test_autouse_fixture_plugin(self, testdir): - # A fixture from a plugin has no baseid set, which screwed up - # the autouse fixture handling. - testdir.makepyfile( - testplugin=""" - import pytest - - @pytest.fixture(autouse=True) - def foo(request): - request.function.foo = 7 - """ - ) - testdir.syspathinsert() - testdir.makepyfile( - """ - pytest_plugins = 'testplugin' - - def test_foo(request): - assert request.function.foo == 7 - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - - def test_funcarg_lookup_error(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def a_fixture(): pass - - @pytest.fixture - def b_fixture(): pass - - @pytest.fixture - def c_fixture(): pass - - @pytest.fixture - def d_fixture(): pass - """ - ) - testdir.makepyfile( - """ - def test_lookup_error(unknown): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ERROR at setup of test_lookup_error*", - " def test_lookup_error(unknown):*", - "E fixture 'unknown' not found", - "> available fixtures:*a_fixture,*b_fixture,*c_fixture,*d_fixture*monkeypatch,*", # sorted - "> use 'py*test --fixtures *' for help on them.", - "*1 error*", - ] - ) - assert "INTERNAL" not in result.stdout.str() - - def test_fixture_excinfo_leak(self, testdir): - # on python2 sys.excinfo would leak into fixture executions - testdir.makepyfile( - """ - import sys - import traceback - import pytest - - @pytest.fixture - def leak(): - if sys.exc_info()[0]: # python3 bug :) - traceback.print_exc() - #fails - assert sys.exc_info() == (None, None, None) - - def test_leak(leak): - if sys.exc_info()[0]: # python3 bug :) - traceback.print_exc() - assert sys.exc_info() == (None, None, None) - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - - -class TestRequestBasic(object): - - def test_request_attributes(self, testdir): - item = testdir.getitem( - """ - import pytest - - @pytest.fixture - def something(request): pass - def test_func(something): pass - """ - ) - req = fixtures.FixtureRequest(item) - assert req.function == item.obj - assert req.keywords == item.keywords - assert hasattr(req.module, "test_func") - assert req.cls is None - assert req.function.__name__ == "test_func" - assert req.config == item.config - assert repr(req).find(req.function.__name__) != -1 - - def test_request_attributes_method(self, testdir): - item, = testdir.getitems( - """ - import pytest - class TestB(object): - - @pytest.fixture - def something(self, request): - return 1 - def test_func(self, something): - pass - """ - ) - req = item._request - assert req.cls.__name__ == "TestB" - assert req.instance.__class__ == req.cls - - def test_request_contains_funcarg_arg2fixturedefs(self, testdir): - modcol = testdir.getmodulecol( - """ - import pytest - @pytest.fixture - def something(request): - pass - class TestClass(object): - def test_method(self, something): - pass - """ - ) - item1, = testdir.genitems([modcol]) - assert item1.name == "test_method" - arg2fixturedefs = fixtures.FixtureRequest(item1)._arg2fixturedefs - assert len(arg2fixturedefs) == 1 - assert arg2fixturedefs["something"][0].argname == "something" - - def test_request_garbage(self, testdir): - testdir.makepyfile( - """ - import sys - import pytest - from _pytest.fixtures import PseudoFixtureDef - import gc - - @pytest.fixture(autouse=True) - def something(request): - # this method of test doesn't work on pypy - if hasattr(sys, "pypy_version_info"): - yield - else: - original = gc.get_debug() - gc.set_debug(gc.DEBUG_SAVEALL) - gc.collect() - - yield - - gc.collect() - leaked_types = sum(1 for _ in gc.garbage - if isinstance(_, PseudoFixtureDef)) - - gc.garbage[:] = [] - - try: - assert leaked_types == 0 - finally: - gc.set_debug(original) - - def test_func(): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_getfixturevalue_recursive(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def something(request): - return 1 - """ - ) - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def something(request): - return request.getfixturevalue("something") + 1 - def test_func(something): - assert something == 2 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - @pytest.mark.parametrize("getfixmethod", ("getfixturevalue", "getfuncargvalue")) - def test_getfixturevalue(self, testdir, getfixmethod): - item = testdir.getitem( - """ - import pytest - values = [2] - @pytest.fixture - def something(request): return 1 - @pytest.fixture - def other(request): - return values.pop() - def test_func(something): pass - """ - ) - import contextlib - - if getfixmethod == "getfuncargvalue": - warning_expectation = pytest.warns(DeprecationWarning) - else: - # see #1830 for a cleaner way to accomplish this - @contextlib.contextmanager - def expecting_no_warning(): - yield - - warning_expectation = expecting_no_warning() - - req = item._request - with warning_expectation: - fixture_fetcher = getattr(req, getfixmethod) - with pytest.raises(FixtureLookupError): - fixture_fetcher("notexists") - val = fixture_fetcher("something") - assert val == 1 - val = fixture_fetcher("something") - assert val == 1 - val2 = fixture_fetcher("other") - assert val2 == 2 - val2 = fixture_fetcher("other") # see about caching - assert val2 == 2 - pytest._fillfuncargs(item) - assert item.funcargs["something"] == 1 - assert len(get_public_names(item.funcargs)) == 2 - assert "request" in item.funcargs - - def test_request_addfinalizer(self, testdir): - item = testdir.getitem( - """ - import pytest - teardownlist = [] - @pytest.fixture - def something(request): - request.addfinalizer(lambda: teardownlist.append(1)) - def test_func(something): pass - """ - ) - item.session._setupstate.prepare(item) - pytest._fillfuncargs(item) - # successively check finalization calls - teardownlist = item.getparent(pytest.Module).obj.teardownlist - ss = item.session._setupstate - assert not teardownlist - ss.teardown_exact(item, None) - print(ss.stack) - assert teardownlist == [1] - - def test_mark_as_fixture_with_prefix_and_decorator_fails(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def pytest_funcarg__marked_with_prefix_and_decorator(): - pass - """ - ) - result = testdir.runpytest_subprocess() - assert result.ret != 0 - result.stdout.fnmatch_lines( - [ - "*AssertionError: fixtures cannot have*@pytest.fixture*", - "*pytest_funcarg__marked_with_prefix_and_decorator*", - ] - ) - - def test_request_addfinalizer_failing_setup(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [1] - @pytest.fixture - def myfix(request): - request.addfinalizer(values.pop) - assert 0 - def test_fix(myfix): - pass - def test_finalizer_ran(): - assert not values - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(failed=1, passed=1) - - def test_request_addfinalizer_failing_setup_module(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [1, 2] - @pytest.fixture(scope="module") - def myfix(request): - request.addfinalizer(values.pop) - request.addfinalizer(values.pop) - assert 0 - def test_fix(myfix): - pass - """ - ) - reprec = testdir.inline_run("-s") - mod = reprec.getcalls("pytest_runtest_setup")[0].item.module - assert not mod.values - - def test_request_addfinalizer_partial_setup_failure(self, testdir): - p = testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture - def something(request): - request.addfinalizer(lambda: values.append(None)) - def test_func(something, missingarg): - pass - def test_second(): - assert len(values) == 1 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - ["*1 error*"] # XXX the whole module collection fails - ) - - def test_request_subrequest_addfinalizer_exceptions(self, testdir): - """ - Ensure exceptions raised during teardown by a finalizer are suppressed - until all finalizers are called, re-raising the first exception (#2440) - """ - testdir.makepyfile( - """ - import pytest - values = [] - def _excepts(where): - raise Exception('Error in %s fixture' % where) - @pytest.fixture - def subrequest(request): - return request - @pytest.fixture - def something(subrequest): - subrequest.addfinalizer(lambda: values.append(1)) - subrequest.addfinalizer(lambda: values.append(2)) - subrequest.addfinalizer(lambda: _excepts('something')) - @pytest.fixture - def excepts(subrequest): - subrequest.addfinalizer(lambda: _excepts('excepts')) - subrequest.addfinalizer(lambda: values.append(3)) - def test_first(something, excepts): - pass - def test_second(): - assert values == [3, 2, 1] - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*Exception: Error in excepts fixture", "* 2 passed, 1 error in *"] - ) - - def test_request_getmodulepath(self, testdir): - modcol = testdir.getmodulecol("def test_somefunc(): pass") - item, = testdir.genitems([modcol]) - req = fixtures.FixtureRequest(item) - assert req.fspath == modcol.fspath - - def test_request_fixturenames(self, testdir): - testdir.makepyfile( - """ - import pytest - from _pytest.pytester import get_public_names - @pytest.fixture() - def arg1(): - pass - @pytest.fixture() - def farg(arg1): - pass - @pytest.fixture(autouse=True) - def sarg(tmpdir): - pass - def test_function(request, farg): - assert set(get_public_names(request.fixturenames)) == \ - set(["tmpdir", "sarg", "arg1", "request", "farg", - "tmpdir_factory"]) - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_funcargnames_compatattr(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - assert metafunc.funcargnames == metafunc.fixturenames - @pytest.fixture - def fn(request): - assert request._pyfuncitem.funcargnames == \ - request._pyfuncitem.fixturenames - return request.funcargnames, request.fixturenames - - def test_hello(fn): - assert fn[0] == fn[1] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_setupdecorator_and_xunit(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope='module', autouse=True) - def setup_module(): - values.append("module") - @pytest.fixture(autouse=True) - def setup_function(): - values.append("function") - - def test_func(): - pass - - class TestClass(object): - @pytest.fixture(scope="class", autouse=True) - def setup_class(self): - values.append("class") - @pytest.fixture(autouse=True) - def setup_method(self): - values.append("method") - def test_method(self): - pass - def test_all(): - assert values == ["module", "function", "class", - "function", "method", "function"] - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=3) - - def test_fixtures_sub_subdir_normalize_sep(self, testdir): - # this tests that normalization of nodeids takes place - b = testdir.mkdir("tests").mkdir("unit") - b.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def arg1(): - pass - """ - ) - ) - p = b.join("test_module.py") - p.write("def test_func(arg1): pass") - result = testdir.runpytest(p, "--fixtures") - assert result.ret == 0 - result.stdout.fnmatch_lines( - """ - *fixtures defined*conftest* - *arg1* - """ - ) - - def test_show_fixtures_color_yes(self, testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("--color=yes", "--fixtures") - assert "\x1b[32mtmpdir" in result.stdout.str() - - def test_newstyle_with_request(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def arg(request): - pass - def test_1(arg): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_setupcontext_no_param(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(params=[1,2]) - def arg(request): - return request.param - - @pytest.fixture(autouse=True) - def mysetup(request, arg): - assert not hasattr(request, "param") - def test_1(arg): - assert arg in (1,2) - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - -class TestRequestMarking(object): - - def test_applymarker(self, testdir): - item1, item2 = testdir.getitems( - """ - import pytest - - @pytest.fixture - def something(request): - pass - class TestClass(object): - def test_func1(self, something): - pass - def test_func2(self, something): - pass - """ - ) - req1 = fixtures.FixtureRequest(item1) - assert "xfail" not in item1.keywords - req1.applymarker(pytest.mark.xfail) - assert "xfail" in item1.keywords - assert "skipif" not in item1.keywords - req1.applymarker(pytest.mark.skipif) - assert "skipif" in item1.keywords - pytest.raises(ValueError, "req1.applymarker(42)") - - def test_accesskeywords(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def keywords(request): - return request.keywords - @pytest.mark.XYZ - def test_function(keywords): - assert keywords["XYZ"] - assert "abc" not in keywords - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_accessmarker_dynamic(self, testdir): - testdir.makeconftest( - """ - import pytest - @pytest.fixture() - def keywords(request): - return request.keywords - - @pytest.fixture(scope="class", autouse=True) - def marking(request): - request.applymarker(pytest.mark.XYZ("hello")) - """ - ) - testdir.makepyfile( - """ - import pytest - def test_fun1(keywords): - assert keywords["XYZ"] is not None - assert "abc" not in keywords - def test_fun2(keywords): - assert keywords["XYZ"] is not None - assert "abc" not in keywords - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - -class TestRequestCachedSetup(object): - - def test_request_cachedsetup_defaultmodule(self, testdir): - reprec = testdir.inline_runsource( - """ - mysetup = ["hello",].pop - - import pytest - - @pytest.fixture - def something(request): - return request.cached_setup(mysetup, scope="module") - - def test_func1(something): - assert something == "hello" - class TestClass(object): - def test_func1a(self, something): - assert something == "hello" - """ - ) - reprec.assertoutcome(passed=2) - - def test_request_cachedsetup_class(self, testdir): - reprec = testdir.inline_runsource( - """ - mysetup = ["hello", "hello2", "hello3"].pop - - import pytest - @pytest.fixture - def something(request): - return request.cached_setup(mysetup, scope="class") - def test_func1(something): - assert something == "hello3" - def test_func2(something): - assert something == "hello2" - class TestClass(object): - def test_func1a(self, something): - assert something == "hello" - def test_func2b(self, something): - assert something == "hello" - """ - ) - reprec.assertoutcome(passed=4) - - def test_request_cachedsetup_extrakey(self, testdir): - item1 = testdir.getitem("def test_func(): pass") - req1 = fixtures.FixtureRequest(item1) - values = ["hello", "world"] - - def setup(): - return values.pop() - - ret1 = req1.cached_setup(setup, extrakey=1) - ret2 = req1.cached_setup(setup, extrakey=2) - assert ret2 == "hello" - assert ret1 == "world" - ret1b = req1.cached_setup(setup, extrakey=1) - ret2b = req1.cached_setup(setup, extrakey=2) - assert ret1 == ret1b - assert ret2 == ret2b - - def test_request_cachedsetup_cache_deletion(self, testdir): - item1 = testdir.getitem("def test_func(): pass") - req1 = fixtures.FixtureRequest(item1) - values = [] - - def setup(): - values.append("setup") - - def teardown(val): - values.append("teardown") - - req1.cached_setup(setup, teardown, scope="function") - assert values == ["setup"] - # artificial call of finalizer - setupstate = req1._pyfuncitem.session._setupstate - setupstate._callfinalizers(item1) - assert values == ["setup", "teardown"] - req1.cached_setup(setup, teardown, scope="function") - assert values == ["setup", "teardown", "setup"] - setupstate._callfinalizers(item1) - assert values == ["setup", "teardown", "setup", "teardown"] - - def test_request_cached_setup_two_args(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg1(request): - return request.cached_setup(lambda: 42) - @pytest.fixture - def arg2(request): - return request.cached_setup(lambda: 17) - def test_two_different_setups(arg1, arg2): - assert arg1 != arg2 - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_request_cached_setup_getfixturevalue(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg1(request): - arg1 = request.getfixturevalue("arg2") - return request.cached_setup(lambda: arg1 + 1) - @pytest.fixture - def arg2(request): - return request.cached_setup(lambda: 10) - def test_two_funcarg(arg1): - assert arg1 == 11 - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_request_cached_setup_functional(self, testdir): - testdir.makepyfile( - test_0=""" - import pytest - values = [] - @pytest.fixture - def something(request): - val = request.cached_setup(fsetup, fteardown) - return val - def fsetup(mycache=[1]): - values.append(mycache.pop()) - return values - def fteardown(something): - values.remove(something[0]) - values.append(2) - def test_list_once(something): - assert something == [1] - def test_list_twice(something): - assert something == [1] - """ - ) - testdir.makepyfile( - test_1=""" - import test_0 # should have run already - def test_check_test0_has_teardown_correct(): - assert test_0.values == [2] - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*3 passed*"]) - - def test_issue117_sessionscopeteardown(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def app(request): - app = request.cached_setup( - scope='session', - setup=lambda: 0, - teardown=lambda x: 3/x) - return app - def test_func(app): - pass - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines(["*3/x*", "*ZeroDivisionError*"]) - - -class TestFixtureUsages(object): - - def test_noargfixturedec(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture - def arg1(): - return 1 - - def test_func(arg1): - assert arg1 == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_receives_funcargs(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def arg1(): - return 1 - - @pytest.fixture() - def arg2(arg1): - return arg1 + 1 - - def test_add(arg2): - assert arg2 == 2 - def test_all(arg1, arg2): - assert arg1 == 1 - assert arg2 == 2 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_receives_funcargs_scope_mismatch(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="function") - def arg1(): - return 1 - - @pytest.fixture(scope="module") - def arg2(arg1): - return arg1 + 1 - - def test_add(arg2): - assert arg2 == 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ScopeMismatch*involved factories*", - "* def arg2*", - "* def arg1*", - "*1 error*", - ] - ) - - def test_receives_funcargs_scope_mismatch_issue660(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="function") - def arg1(): - return 1 - - @pytest.fixture(scope="module") - def arg2(arg1): - return arg1 + 1 - - def test_add(arg1, arg2): - assert arg2 == 2 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*ScopeMismatch*involved factories*", "* def arg2*", "*1 error*"] - ) - - def test_invalid_scope(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="functions") - def badscope(): - pass - - def test_nothing(badscope): - pass - """ - ) - result = testdir.runpytest_inprocess() - result.stdout.fnmatch_lines( - ( - "*ValueError: fixture badscope from test_invalid_scope.py has an unsupported" - " scope value 'functions'" - ) - ) - - def test_funcarg_parametrized_and_used_twice(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(params=[1,2]) - def arg1(request): - values.append(1) - return request.param - - @pytest.fixture() - def arg2(arg1): - return arg1 + 1 - - def test_add(arg1, arg2): - assert arg2 == arg1 + 1 - assert len(values) == arg1 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 passed*"]) - - def test_factory_uses_unknown_funcarg_as_dependency_error(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture() - def fail(missing): - return - - @pytest.fixture() - def call_fail(fail): - return - - def test_missing(call_fail): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *pytest.fixture()* - *def call_fail(fail)* - *pytest.fixture()* - *def fail* - *fixture*'missing'*not found* - """ - ) - - def test_factory_setup_as_classes_fails(self, testdir): - testdir.makepyfile( - """ - import pytest - class arg1(object): - def __init__(self, request): - self.x = 1 - arg1 = pytest.fixture()(arg1) - - """ - ) - reprec = testdir.inline_run() - values = reprec.getfailedcollections() - assert len(values) == 1 - - def test_request_can_be_overridden(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def request(request): - request.a = 1 - return request - def test_request(request): - assert request.a == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_usefixtures_marker(self, testdir): - testdir.makepyfile( - """ - import pytest - - values = [] - - @pytest.fixture(scope="class") - def myfix(request): - request.cls.hello = "world" - values.append(1) - - class TestClass(object): - def test_one(self): - assert self.hello == "world" - assert len(values) == 1 - def test_two(self): - assert self.hello == "world" - assert len(values) == 1 - pytest.mark.usefixtures("myfix")(TestClass) - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_usefixtures_ini(self, testdir): - testdir.makeini( - """ - [pytest] - usefixtures = myfix - """ - ) - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(scope="class") - def myfix(request): - request.cls.hello = "world" - - """ - ) - testdir.makepyfile( - """ - class TestClass(object): - def test_one(self): - assert self.hello == "world" - def test_two(self): - assert self.hello == "world" - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_usefixtures_seen_in_showmarkers(self, testdir): - result = testdir.runpytest("--markers") - result.stdout.fnmatch_lines( - """ - *usefixtures(fixturename1*mark tests*fixtures* - """ - ) - - def test_request_instance_issue203(self, testdir): - testdir.makepyfile( - """ - import pytest - - class TestClass(object): - @pytest.fixture - def setup1(self, request): - assert self == request.instance - self.arg1 = 1 - def test_hello(self, setup1): - assert self.arg1 == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_fixture_parametrized_with_iterator(self, testdir): - testdir.makepyfile( - """ - import pytest - - values = [] - def f(): - yield 1 - yield 2 - dec = pytest.fixture(scope="module", params=f()) - - @dec - def arg(request): - return request.param - @dec - def arg2(request): - return request.param - - def test_1(arg): - values.append(arg) - def test_2(arg2): - values.append(arg2*10) - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=4) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - assert values == [1, 2, 10, 20] - - -class TestFixtureManagerParseFactories(object): - - @pytest.fixture - def testdir(self, request): - testdir = request.getfixturevalue("testdir") - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def hello(request): - return "conftest" - - @pytest.fixture - def fm(request): - return request._fixturemanager - - @pytest.fixture - def item(request): - return request._pyfuncitem - """ - ) - return testdir - - def test_parsefactories_evil_objects_issue214(self, testdir): - testdir.makepyfile( - """ - class A(object): - def __call__(self): - pass - def __getattr__(self, name): - raise RuntimeError() - a = A() - def test_hello(): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1, failed=0) - - def test_parsefactories_conftest(self, testdir): - testdir.makepyfile( - """ - def test_hello(item, fm): - for name in ("fm", "hello", "item"): - faclist = fm.getfixturedefs(name, item.nodeid) - assert len(faclist) == 1 - fac = faclist[0] - assert fac.func.__name__ == name - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=1) - - def test_parsefactories_conftest_and_module_and_class(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def hello(request): - return "module" - class TestClass(object): - @pytest.fixture - def hello(self, request): - return "class" - def test_hello(self, item, fm): - faclist = fm.getfixturedefs("hello", item.nodeid) - print (faclist) - assert len(faclist) == 3 - assert faclist[0].func(item._request) == "conftest" - assert faclist[1].func(item._request) == "module" - assert faclist[2].func(item._request) == "class" - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=1) - - def test_parsefactories_relative_node_ids(self, testdir): - # example mostly taken from: - # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html - runner = testdir.mkdir("runner") - package = testdir.mkdir("package") - package.join("conftest.py").write( - dedent( - """\ - import pytest - @pytest.fixture - def one(): - return 1 - """ - ) - ) - package.join("test_x.py").write( - dedent( - """\ - def test_x(one): - assert one == 1 - """ - ) - ) - sub = package.mkdir("sub") - sub.join("__init__.py").ensure() - sub.join("conftest.py").write( - dedent( - """\ - import pytest - @pytest.fixture - def one(): - return 2 - """ - ) - ) - sub.join("test_y.py").write( - dedent( - """\ - def test_x(one): - assert one == 2 - """ - ) - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - with runner.as_cwd(): - reprec = testdir.inline_run("..") - reprec.assertoutcome(passed=2) - - -class TestAutouseDiscovery(object): - - @pytest.fixture - def testdir(self, testdir): - testdir.makeconftest( - """ - import pytest - @pytest.fixture(autouse=True) - def perfunction(request, tmpdir): - pass - - @pytest.fixture() - def arg1(tmpdir): - pass - @pytest.fixture(autouse=True) - def perfunction2(arg1): - pass - - @pytest.fixture - def fm(request): - return request._fixturemanager - - @pytest.fixture - def item(request): - return request._pyfuncitem - """ - ) - return testdir - - def test_parsefactories_conftest(self, testdir): - testdir.makepyfile( - """ - from _pytest.pytester import get_public_names - def test_check_setup(item, fm): - autousenames = fm._getautousenames(item.nodeid) - assert len(get_public_names(autousenames)) == 2 - assert "perfunction2" in autousenames - assert "perfunction" in autousenames - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=1) - - def test_two_classes_separated_autouse(self, testdir): - testdir.makepyfile( - """ - import pytest - class TestA(object): - values = [] - @pytest.fixture(autouse=True) - def setup1(self): - self.values.append(1) - def test_setup1(self): - assert self.values == [1] - class TestB(object): - values = [] - @pytest.fixture(autouse=True) - def setup2(self): - self.values.append(1) - def test_setup2(self): - assert self.values == [1] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_setup_at_classlevel(self, testdir): - testdir.makepyfile( - """ - import pytest - class TestClass(object): - @pytest.fixture(autouse=True) - def permethod(self, request): - request.instance.funcname = request.function.__name__ - def test_method1(self): - assert self.funcname == "test_method1" - def test_method2(self): - assert self.funcname == "test_method2" - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=2) - - @pytest.mark.xfail(reason="'enabled' feature not implemented") - def test_setup_enabled_functionnode(self, testdir): - testdir.makepyfile( - """ - import pytest - - def enabled(parentnode, markers): - return "needsdb" in markers - - @pytest.fixture(params=[1,2]) - def db(request): - return request.param - - @pytest.fixture(enabled=enabled, autouse=True) - def createdb(db): - pass - - def test_func1(request): - assert "db" not in request.fixturenames - - @pytest.mark.needsdb - def test_func2(request): - assert "db" in request.fixturenames - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=2) - - def test_callables_nocode(self, testdir): - """ - an imported mock.call would break setup/factory discovery - due to it being callable and __code__ not being a code object - """ - testdir.makepyfile( - """ - class _call(tuple): - def __call__(self, *k, **kw): - pass - def __getattr__(self, k): - return self - - call = _call() - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(failed=0, passed=0) - - def test_autouse_in_conftests(self, testdir): - a = testdir.mkdir("a") - b = testdir.mkdir("a1") - conftest = testdir.makeconftest( - """ - import pytest - @pytest.fixture(autouse=True) - def hello(): - xxx - """ - ) - conftest.move(a.join(conftest.basename)) - a.join("test_something.py").write("def test_func(): pass") - b.join("test_otherthing.py").write("def test_func(): pass") - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *1 passed*1 error* - """ - ) - - def test_autouse_in_module_and_two_classes(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(autouse=True) - def append1(): - values.append("module") - def test_x(): - assert values == ["module"] - - class TestA(object): - @pytest.fixture(autouse=True) - def append2(self): - values.append("A") - def test_hello(self): - assert values == ["module", "module", "A"], values - class TestA2(object): - def test_world(self): - assert values == ["module", "module", "A", "module"], values - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=3) - - -class TestAutouseManagement(object): - - def test_autouse_conftest_mid_directory(self, testdir): - pkgdir = testdir.mkpydir("xyz123") - pkgdir.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture(autouse=True) - def app(): - import sys - sys._myapp = "hello" - """ - ) - ) - t = pkgdir.ensure("tests", "test_app.py") - t.write( - _pytest._code.Source( - """ - import sys - def test_app(): - assert sys._myapp == "hello" - """ - ) - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=1) - - def test_autouse_honored_for_yield(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(autouse=True) - def tst(): - global x - x = 3 - def test_gen(): - def f(hello): - assert x == abs(hello) - yield f, 3 - yield f, -3 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_funcarg_and_setup(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope="module") - def arg(): - values.append(1) - return 0 - @pytest.fixture(scope="module", autouse=True) - def something(arg): - values.append(2) - - def test_hello(arg): - assert len(values) == 2 - assert values == [1,2] - assert arg == 0 - - def test_hello2(arg): - assert len(values) == 2 - assert values == [1,2] - assert arg == 0 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_uses_parametrized_resource(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(params=[1,2]) - def arg(request): - return request.param - - @pytest.fixture(autouse=True) - def something(arg): - values.append(arg) - - def test_hello(): - if len(values) == 1: - assert values == [1] - elif len(values) == 2: - assert values == [1, 2] - else: - 0/0 - - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=2) - - def test_session_parametrized_function(self, testdir): - testdir.makepyfile( - """ - import pytest - - values = [] - - @pytest.fixture(scope="session", params=[1,2]) - def arg(request): - return request.param - - @pytest.fixture(scope="function", autouse=True) - def append(request, arg): - if request.function.__name__ == "test_some": - values.append(arg) - - def test_some(): - pass - - def test_result(arg): - assert len(values) == arg - assert values[:arg] == [1,2][:arg] - """ - ) - reprec = testdir.inline_run("-v", "-s") - reprec.assertoutcome(passed=4) - - def test_class_function_parametrization_finalization(self, testdir): - p = testdir.makeconftest( - """ - import pytest - import pprint - - values = [] - - @pytest.fixture(scope="function", params=[1,2]) - def farg(request): - return request.param - - @pytest.fixture(scope="class", params=list("ab")) - def carg(request): - return request.param - - @pytest.fixture(scope="function", autouse=True) - def append(request, farg, carg): - def fin(): - values.append("fin_%s%s" % (carg, farg)) - request.addfinalizer(fin) - """ - ) - testdir.makepyfile( - """ - import pytest - - class TestClass(object): - def test_1(self): - pass - class TestClass2(object): - def test_2(self): - pass - """ - ) - confcut = "--confcutdir={}".format(testdir.tmpdir) - reprec = testdir.inline_run("-v", "-s", confcut) - reprec.assertoutcome(passed=8) - config = reprec.getcalls("pytest_unconfigure")[0].config - values = config.pluginmanager._getconftestmodules(p)[0].values - assert values == ["fin_a1", "fin_a2", "fin_b1", "fin_b2"] * 2 - - def test_scope_ordering(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope="function", autouse=True) - def fappend2(): - values.append(2) - @pytest.fixture(scope="class", autouse=True) - def classappend3(): - values.append(3) - @pytest.fixture(scope="module", autouse=True) - def mappend(): - values.append(1) - - class TestHallo(object): - def test_method(self): - assert values == [1,3,2] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_parametrization_setup_teardown_ordering(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - def pytest_generate_tests(metafunc): - if metafunc.cls is None: - assert metafunc.function is test_finish - if metafunc.cls is not None: - metafunc.parametrize("item", [1,2], scope="class") - class TestClass(object): - @pytest.fixture(scope="class", autouse=True) - def addteardown(self, item, request): - values.append("setup-%d" % item) - request.addfinalizer(lambda: values.append("teardown-%d" % item)) - def test_step1(self, item): - values.append("step1-%d" % item) - def test_step2(self, item): - values.append("step2-%d" % item) - - def test_finish(): - print (values) - assert values == ["setup-1", "step1-1", "step2-1", "teardown-1", - "setup-2", "step1-2", "step2-2", "teardown-2",] - """ - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=5) - - def test_ordering_autouse_before_explicit(self, testdir): - testdir.makepyfile( - """ - import pytest - - values = [] - @pytest.fixture(autouse=True) - def fix1(): - values.append(1) - @pytest.fixture() - def arg1(): - values.append(2) - def test_hello(arg1): - assert values == [1,2] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - @pytest.mark.issue226 - @pytest.mark.parametrize("param1", ["", "params=[1]"], ids=["p00", "p01"]) - @pytest.mark.parametrize("param2", ["", "params=[1]"], ids=["p10", "p11"]) - def test_ordering_dependencies_torndown_first(self, testdir, param1, param2): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(%(param1)s) - def arg1(request): - request.addfinalizer(lambda: values.append("fin1")) - values.append("new1") - @pytest.fixture(%(param2)s) - def arg2(request, arg1): - request.addfinalizer(lambda: values.append("fin2")) - values.append("new2") - - def test_arg(arg2): - pass - def test_check(): - assert values == ["new1", "new2", "fin2", "fin1"] - """ - % locals() - ) - reprec = testdir.inline_run("-s") - reprec.assertoutcome(passed=2) - - -class TestFixtureMarker(object): - - def test_parametrize(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(params=["a", "b", "c"]) - def arg(request): - return request.param - values = [] - def test_param(arg): - values.append(arg) - def test_result(): - assert values == list("abc") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=4) - - def test_multiple_parametrization_issue_736(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[1,2,3]) - def foo(request): - return request.param - - @pytest.mark.parametrize('foobar', [4,5,6]) - def test_issue(foo, foobar): - assert foo in [1,2,3] - assert foobar in [4,5,6] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=9) - - @pytest.mark.parametrize( - "param_args", - ["'fixt, val'", "'fixt,val'", "['fixt', 'val']", "('fixt', 'val')"], - ) - def test_override_parametrized_fixture_issue_979(self, testdir, param_args): - """Make sure a parametrized argument can override a parametrized fixture. - - This was a regression introduced in the fix for #736. - """ - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[1, 2]) - def fixt(request): - return request.param - - @pytest.mark.parametrize(%s, [(3, 'x'), (4, 'x')]) - def test_foo(fixt, val): - pass - """ - % param_args - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_scope_session(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope="module") - def arg(): - values.append(1) - return 1 - - def test_1(arg): - assert arg == 1 - def test_2(arg): - assert arg == 1 - assert len(values) == 1 - class TestClass(object): - def test3(self, arg): - assert arg == 1 - assert len(values) == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=3) - - def test_scope_session_exc(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope="session") - def fix(): - values.append(1) - pytest.skip('skipping') - - def test_1(fix): - pass - def test_2(fix): - pass - def test_last(): - assert values == [1] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=2, passed=1) - - def test_scope_session_exc_two_fix(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - m = [] - @pytest.fixture(scope="session") - def a(): - values.append(1) - pytest.skip('skipping') - @pytest.fixture(scope="session") - def b(a): - m.append(1) - - def test_1(b): - pass - def test_2(b): - pass - def test_last(): - assert values == [1] - assert m == [] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=2, passed=1) - - def test_scope_exc(self, testdir): - testdir.makepyfile( - test_foo=""" - def test_foo(fix): - pass - """, - test_bar=""" - def test_bar(fix): - pass - """, - conftest=""" - import pytest - reqs = [] - @pytest.fixture(scope="session") - def fix(request): - reqs.append(1) - pytest.skip() - @pytest.fixture - def req_list(): - return reqs - """, - test_real=""" - def test_last(req_list): - assert req_list == [1] - """, - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=2, passed=1) - - def test_scope_module_uses_session(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(scope="module") - def arg(): - values.append(1) - return 1 - - def test_1(arg): - assert arg == 1 - def test_2(arg): - assert arg == 1 - assert len(values) == 1 - class TestClass(object): - def test3(self, arg): - assert arg == 1 - assert len(values) == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=3) - - def test_scope_module_and_finalizer(self, testdir): - testdir.makeconftest( - """ - import pytest - finalized_list = [] - created_list = [] - @pytest.fixture(scope="module") - def arg(request): - created_list.append(1) - assert request.scope == "module" - request.addfinalizer(lambda: finalized_list.append(1)) - @pytest.fixture - def created(request): - return len(created_list) - @pytest.fixture - def finalized(request): - return len(finalized_list) - """ - ) - testdir.makepyfile( - test_mod1=""" - def test_1(arg, created, finalized): - assert created == 1 - assert finalized == 0 - def test_2(arg, created, finalized): - assert created == 1 - assert finalized == 0""", - test_mod2=""" - def test_3(arg, created, finalized): - assert created == 2 - assert finalized == 1""", - test_mode3=""" - def test_4(arg, created, finalized): - assert created == 3 - assert finalized == 2 - """, - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=4) - - @pytest.mark.parametrize( - "method", - [ - 'request.getfixturevalue("arg")', - 'request.cached_setup(lambda: None, scope="function")', - ], - ids=["getfixturevalue", "cached_setup"], - ) - def test_scope_mismatch_various(self, testdir, method): - testdir.makeconftest( - """ - import pytest - finalized = [] - created = [] - @pytest.fixture(scope="function") - def arg(request): - pass - """ - ) - testdir.makepyfile( - test_mod1=""" - import pytest - @pytest.fixture(scope="session") - def arg(request): - %s - def test_1(arg): - pass - """ - % method - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines( - ["*ScopeMismatch*You tried*function*session*request*"] - ) - - def test_register_only_with_mark(self, testdir): - testdir.makeconftest( - """ - import pytest - @pytest.fixture() - def arg(): - return 1 - """ - ) - testdir.makepyfile( - test_mod1=""" - import pytest - @pytest.fixture() - def arg(arg): - return arg + 1 - def test_1(arg): - assert arg == 2 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_parametrize_and_scope(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="module", params=["a", "b", "c"]) - def arg(request): - return request.param - values = [] - def test_param(arg): - values.append(arg) - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=3) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - assert len(values) == 3 - assert "a" in values - assert "b" in values - assert "c" in values - - def test_scope_mismatch(self, testdir): - testdir.makeconftest( - """ - import pytest - @pytest.fixture(scope="function") - def arg(request): - pass - """ - ) - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="session") - def arg(arg): - pass - def test_mismatch(arg): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*ScopeMismatch*", "*1 error*"]) - - def test_parametrize_separated_order(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module", params=[1, 2]) - def arg(request): - return request.param - - values = [] - def test_1(arg): - values.append(arg) - def test_2(arg): - values.append(arg) - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=4) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - assert values == [1, 1, 2, 2] - - def test_module_parametrized_ordering(self, testdir): - testdir.makeini( - """ - [pytest] - console_output_style=classic - """ - ) - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(scope="session", params="s1 s2".split()) - def sarg(): - pass - @pytest.fixture(scope="module", params="m1 m2".split()) - def marg(): - pass - """ - ) - testdir.makepyfile( - test_mod1=""" - def test_func(sarg): - pass - def test_func1(marg): - pass - """, - test_mod2=""" - def test_func2(sarg): - pass - def test_func3(sarg, marg): - pass - def test_func3b(sarg, marg): - pass - def test_func4(marg): - pass - """, - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - """ - test_mod1.py::test_func[s1] PASSED - test_mod2.py::test_func2[s1] PASSED - test_mod2.py::test_func3[s1-m1] PASSED - test_mod2.py::test_func3b[s1-m1] PASSED - test_mod2.py::test_func3[s1-m2] PASSED - test_mod2.py::test_func3b[s1-m2] PASSED - test_mod1.py::test_func[s2] PASSED - test_mod2.py::test_func2[s2] PASSED - test_mod2.py::test_func3[s2-m1] PASSED - test_mod2.py::test_func3b[s2-m1] PASSED - test_mod2.py::test_func4[m1] PASSED - test_mod2.py::test_func3[s2-m2] PASSED - test_mod2.py::test_func3b[s2-m2] PASSED - test_mod2.py::test_func4[m2] PASSED - test_mod1.py::test_func1[m1] PASSED - test_mod1.py::test_func1[m2] PASSED - """ - ) - - def test_dynamic_parametrized_ordering(self, testdir): - testdir.makeini( - """ - [pytest] - console_output_style=classic - """ - ) - testdir.makeconftest( - """ - import pytest - - def pytest_configure(config): - class DynamicFixturePlugin(object): - @pytest.fixture(scope='session', params=['flavor1', 'flavor2']) - def flavor(self, request): - return request.param - config.pluginmanager.register(DynamicFixturePlugin(), 'flavor-fixture') - - @pytest.fixture(scope='session', params=['vxlan', 'vlan']) - def encap(request): - return request.param - - @pytest.fixture(scope='session', autouse='True') - def reprovision(request, flavor, encap): - pass - """ - ) - testdir.makepyfile( - """ - def test(reprovision): - pass - def test2(reprovision): - pass - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - """ - test_dynamic_parametrized_ordering.py::test[flavor1-vxlan] PASSED - test_dynamic_parametrized_ordering.py::test2[flavor1-vxlan] PASSED - test_dynamic_parametrized_ordering.py::test[flavor2-vxlan] PASSED - test_dynamic_parametrized_ordering.py::test2[flavor2-vxlan] PASSED - test_dynamic_parametrized_ordering.py::test[flavor2-vlan] PASSED - test_dynamic_parametrized_ordering.py::test2[flavor2-vlan] PASSED - test_dynamic_parametrized_ordering.py::test[flavor1-vlan] PASSED - test_dynamic_parametrized_ordering.py::test2[flavor1-vlan] PASSED - """ - ) - - def test_class_ordering(self, testdir): - testdir.makeini( - """ - [pytest] - console_output_style=classic - """ - ) - testdir.makeconftest( - """ - import pytest - - values = [] - - @pytest.fixture(scope="function", params=[1,2]) - def farg(request): - return request.param - - @pytest.fixture(scope="class", params=list("ab")) - def carg(request): - return request.param - - @pytest.fixture(scope="function", autouse=True) - def append(request, farg, carg): - def fin(): - values.append("fin_%s%s" % (carg, farg)) - request.addfinalizer(fin) - """ - ) - testdir.makepyfile( - """ - import pytest - - class TestClass2(object): - def test_1(self): - pass - def test_2(self): - pass - class TestClass(object): - def test_3(self): - pass - """ - ) - result = testdir.runpytest("-vs") - result.stdout.re_match_lines( - r""" - test_class_ordering.py::TestClass2::test_1\[a-1\] PASSED - test_class_ordering.py::TestClass2::test_1\[a-2\] PASSED - test_class_ordering.py::TestClass2::test_2\[a-1\] PASSED - test_class_ordering.py::TestClass2::test_2\[a-2\] PASSED - test_class_ordering.py::TestClass2::test_1\[b-1\] PASSED - test_class_ordering.py::TestClass2::test_1\[b-2\] PASSED - test_class_ordering.py::TestClass2::test_2\[b-1\] PASSED - test_class_ordering.py::TestClass2::test_2\[b-2\] PASSED - test_class_ordering.py::TestClass::test_3\[a-1\] PASSED - test_class_ordering.py::TestClass::test_3\[a-2\] PASSED - test_class_ordering.py::TestClass::test_3\[b-1\] PASSED - test_class_ordering.py::TestClass::test_3\[b-2\] PASSED - """ - ) - - def test_parametrize_separated_order_higher_scope_first(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="function", params=[1, 2]) - def arg(request): - param = request.param - request.addfinalizer(lambda: values.append("fin:%s" % param)) - values.append("create:%s" % param) - return request.param - - @pytest.fixture(scope="module", params=["mod1", "mod2"]) - def modarg(request): - param = request.param - request.addfinalizer(lambda: values.append("fin:%s" % param)) - values.append("create:%s" % param) - return request.param - - values = [] - def test_1(arg): - values.append("test1") - def test_2(modarg): - values.append("test2") - def test_3(arg, modarg): - values.append("test3") - def test_4(modarg, arg): - values.append("test4") - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=12) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - expected = [ - "create:1", - "test1", - "fin:1", - "create:2", - "test1", - "fin:2", - "create:mod1", - "test2", - "create:1", - "test3", - "fin:1", - "create:2", - "test3", - "fin:2", - "create:1", - "test4", - "fin:1", - "create:2", - "test4", - "fin:2", - "fin:mod1", - "create:mod2", - "test2", - "create:1", - "test3", - "fin:1", - "create:2", - "test3", - "fin:2", - "create:1", - "test4", - "fin:1", - "create:2", - "test4", - "fin:2", - "fin:mod2", - ] - import pprint - - pprint.pprint(list(zip(values, expected))) - assert values == expected - - def test_parametrized_fixture_teardown_order(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(params=[1,2], scope="class") - def param1(request): - return request.param - - values = [] - - class TestClass(object): - @classmethod - @pytest.fixture(scope="class", autouse=True) - def setup1(self, request, param1): - values.append(1) - request.addfinalizer(self.teardown1) - @classmethod - def teardown1(self): - assert values.pop() == 1 - @pytest.fixture(scope="class", autouse=True) - def setup2(self, request, param1): - values.append(2) - request.addfinalizer(self.teardown2) - @classmethod - def teardown2(self): - assert values.pop() == 2 - def test(self): - pass - - def test_finish(): - assert not values - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - """ - *3 passed* - """ - ) - assert "error" not in result.stdout.str() - - def test_fixture_finalizer(self, testdir): - testdir.makeconftest( - """ - import pytest - import sys - - @pytest.fixture - def browser(request): - - def finalize(): - sys.stdout.write('Finalized') - request.addfinalizer(finalize) - return {} - """ - ) - b = testdir.mkdir("subdir") - b.join("test_overridden_fixture_finalizer.py").write( - dedent( - """ - import pytest - @pytest.fixture - def browser(browser): - browser['visited'] = True - return browser - - def test_browser(browser): - assert browser['visited'] is True - """ - ) - ) - reprec = testdir.runpytest("-s") - for test in ["test_browser"]: - reprec.stdout.fnmatch_lines("*Finalized*") - - def test_class_scope_with_normal_tests(self, testdir): - testpath = testdir.makepyfile( - """ - import pytest - - class Box(object): - value = 0 - - @pytest.fixture(scope='class') - def a(request): - Box.value += 1 - return Box.value - - def test_a(a): - assert a == 1 - - class Test1(object): - def test_b(self, a): - assert a == 2 - - class Test2(object): - def test_c(self, a): - assert a == 3""" - ) - reprec = testdir.inline_run(testpath) - for test in ["test_a", "test_b", "test_c"]: - assert reprec.matchreport(test).passed - - def test_request_is_clean(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(params=[1, 2]) - def fix(request): - request.addfinalizer(lambda: values.append(request.param)) - def test_fix(fix): - pass - """ - ) - reprec = testdir.inline_run("-s") - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - assert values == [1, 2] - - def test_parametrize_separated_lifecycle(self, testdir): - testdir.makepyfile( - """ - import pytest - - values = [] - @pytest.fixture(scope="module", params=[1, 2]) - def arg(request): - x = request.param - request.addfinalizer(lambda: values.append("fin%s" % x)) - return request.param - def test_1(arg): - values.append(arg) - def test_2(arg): - values.append(arg) - """ - ) - reprec = testdir.inline_run("-vs") - reprec.assertoutcome(passed=4) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - import pprint - - pprint.pprint(values) - # assert len(values) == 6 - assert values[0] == values[1] == 1 - assert values[2] == "fin1" - assert values[3] == values[4] == 2 - assert values[5] == "fin2" - - def test_parametrize_function_scoped_finalizers_called(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="function", params=[1, 2]) - def arg(request): - x = request.param - request.addfinalizer(lambda: values.append("fin%s" % x)) - return request.param - - values = [] - def test_1(arg): - values.append(arg) - def test_2(arg): - values.append(arg) - def test_3(): - assert len(values) == 8 - assert values == [1, "fin1", 2, "fin2", 1, "fin1", 2, "fin2"] - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=5) - - @pytest.mark.issue246 - @pytest.mark.parametrize("scope", ["session", "function", "module"]) - def test_finalizer_order_on_parametrization(self, scope, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - - @pytest.fixture(scope=%(scope)r, params=["1"]) - def fix1(request): - return request.param - - @pytest.fixture(scope=%(scope)r) - def fix2(request, base): - def cleanup_fix2(): - assert not values, "base should not have been finalized" - request.addfinalizer(cleanup_fix2) - - @pytest.fixture(scope=%(scope)r) - def base(request, fix1): - def cleanup_base(): - values.append("fin_base") - print ("finalizing base") - request.addfinalizer(cleanup_base) - - def test_begin(): - pass - def test_baz(base, fix2): - pass - def test_other(): - pass - """ - % {"scope": scope} - ) - reprec = testdir.inline_run("-lvs") - reprec.assertoutcome(passed=3) - - @pytest.mark.issue396 - def test_class_scope_parametrization_ordering(self, testdir): - testdir.makepyfile( - """ - import pytest - values = [] - @pytest.fixture(params=["John", "Doe"], scope="class") - def human(request): - request.addfinalizer(lambda: values.append("fin %s" % request.param)) - return request.param - - class TestGreetings(object): - def test_hello(self, human): - values.append("test_hello") - - class TestMetrics(object): - def test_name(self, human): - values.append("test_name") - - def test_population(self, human): - values.append("test_population") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=6) - values = reprec.getcalls("pytest_runtest_call")[0].item.module.values - assert ( - values - == [ - "test_hello", - "fin John", - "test_hello", - "fin Doe", - "test_name", - "test_population", - "fin John", - "test_name", - "test_population", - "fin Doe", - ] - ) - - def test_parametrize_setup_function(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module", params=[1, 2]) - def arg(request): - return request.param - - @pytest.fixture(scope="module", autouse=True) - def mysetup(request, arg): - request.addfinalizer(lambda: values.append("fin%s" % arg)) - values.append("setup%s" % arg) - - values = [] - def test_1(arg): - values.append(arg) - def test_2(arg): - values.append(arg) - def test_3(): - import pprint - pprint.pprint(values) - if arg == 1: - assert values == ["setup1", 1, 1, ] - elif arg == 2: - assert values == ["setup1", 1, 1, "fin1", - "setup2", 2, 2, ] - - """ - ) - reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=6) - - def test_fixture_marked_function_not_collected_as_test(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture - def test_app(): - return 1 - - def test_something(test_app): - assert test_app == 1 - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_params_and_ids(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[object(), object()], - ids=['alpha', 'beta']) - def fix(request): - return request.param - - def test_foo(fix): - assert 1 - """ - ) - res = testdir.runpytest("-v") - res.stdout.fnmatch_lines(["*test_foo*alpha*", "*test_foo*beta*"]) - - def test_params_and_ids_yieldfixture(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.yield_fixture(params=[object(), object()], - ids=['alpha', 'beta']) - def fix(request): - yield request.param - - def test_foo(fix): - assert 1 - """ - ) - res = testdir.runpytest("-v") - res.stdout.fnmatch_lines(["*test_foo*alpha*", "*test_foo*beta*"]) - - @pytest.mark.issue920 - def test_deterministic_fixture_collection(self, testdir, monkeypatch): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module", - params=["A", - "B", - "C"]) - def A(request): - return request.param - - @pytest.fixture(scope="module", - params=["DDDDDDDDD", "EEEEEEEEEEEE", "FFFFFFFFFFF", "banansda"]) - def B(request, A): - return request.param - - def test_foo(B): - # Something funky is going on here. - # Despite specified seeds, on what is collected, - # sometimes we get unexpected passes. hashing B seems - # to help? - assert hash(B) or True - """ - ) - monkeypatch.setenv("PYTHONHASHSEED", "1") - out1 = testdir.runpytest_subprocess("-v") - monkeypatch.setenv("PYTHONHASHSEED", "2") - out2 = testdir.runpytest_subprocess("-v") - out1 = [ - line - for line in out1.outlines - if line.startswith("test_deterministic_fixture_collection.py::test_foo") - ] - out2 = [ - line - for line in out2.outlines - if line.startswith("test_deterministic_fixture_collection.py::test_foo") - ] - assert len(out1) == 12 - assert out1 == out2 - - -class TestRequestScopeAccess(object): - pytestmark = pytest.mark.parametrize( - ("scope", "ok", "error"), - [ - ["session", "", "fspath class function module"], - ["module", "module fspath", "cls function"], - ["class", "module fspath cls", "function"], - ["function", "module fspath cls function", ""], - ], - ) - - def test_setup(self, testdir, scope, ok, error): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope=%r, autouse=True) - def myscoped(request): - for x in %r: - assert hasattr(request, x) - for x in %r: - pytest.raises(AttributeError, lambda: - getattr(request, x)) - assert request.session - assert request.config - def test_func(): - pass - """ - % (scope, ok.split(), error.split()) - ) - reprec = testdir.inline_run("-l") - reprec.assertoutcome(passed=1) - - def test_funcarg(self, testdir, scope, ok, error): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope=%r) - def arg(request): - for x in %r: - assert hasattr(request, x) - for x in %r: - pytest.raises(AttributeError, lambda: - getattr(request, x)) - assert request.session - assert request.config - def test_func(arg): - pass - """ - % (scope, ok.split(), error.split()) - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -class TestErrors(object): - - def test_subfactory_missing_funcarg(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def gen(qwe123): - return 1 - def test_something(gen): - pass - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines( - ["*def gen(qwe123):*", "*fixture*qwe123*not found*", "*1 error*"] - ) - - def test_issue498_fixture_finalizer_failing(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture - def fix1(request): - def f(): - raise KeyError - request.addfinalizer(f) - return object() - - values = [] - def test_1(fix1): - values.append(fix1) - def test_2(fix1): - values.append(fix1) - def test_3(): - assert values[0] != values[1] - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *ERROR*teardown*test_1* - *KeyError* - *ERROR*teardown*test_2* - *KeyError* - *3 pass*2 error* - """ - ) - - def test_setupfunc_missing_funcarg(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(autouse=True) - def gen(qwe123): - return 1 - def test_something(): - pass - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines( - ["*def gen(qwe123):*", "*fixture*qwe123*not found*", "*1 error*"] - ) - - -class TestShowFixtures(object): - - def test_funcarg_compat(self, testdir): - config = testdir.parseconfigure("--funcargs") - assert config.option.showfixtures - - def test_show_fixtures(self, testdir): - result = testdir.runpytest("--fixtures") - result.stdout.fnmatch_lines(["*tmpdir*", "*temporary directory*"]) - - def test_show_fixtures_verbose(self, testdir): - result = testdir.runpytest("--fixtures", "-v") - result.stdout.fnmatch_lines(["*tmpdir*--*tmpdir.py*", "*temporary directory*"]) - - def test_show_fixtures_testmodule(self, testdir): - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def _arg0(): - """ hidden """ - @pytest.fixture - def arg1(): - """ hello world """ - ''' - ) - result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines( - """ - *tmpdir - *fixtures defined from* - *arg1* - *hello world* - """ - ) - assert "arg0" not in result.stdout.str() - - @pytest.mark.parametrize("testmod", [True, False]) - def test_show_fixtures_conftest(self, testdir, testmod): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture - def arg1(): - """ hello world """ - ''' - ) - if testmod: - testdir.makepyfile( - """ - def test_hello(): - pass - """ - ) - result = testdir.runpytest("--fixtures") - result.stdout.fnmatch_lines( - """ - *tmpdir* - *fixtures defined from*conftest* - *arg1* - *hello world* - """ - ) - - def test_show_fixtures_trimmed_doc(self, testdir): - p = testdir.makepyfile( - dedent( - ''' - import pytest - @pytest.fixture - def arg1(): - """ - line1 - line2 - - """ - @pytest.fixture - def arg2(): - """ - line1 - line2 - - """ - ''' - ) - ) - result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines( - dedent( - """ - * fixtures defined from test_show_fixtures_trimmed_doc * - arg2 - line1 - line2 - arg1 - line1 - line2 - - """ - ) - ) - - def test_show_fixtures_indented_doc(self, testdir): - p = testdir.makepyfile( - dedent( - ''' - import pytest - @pytest.fixture - def fixture1(): - """ - line1 - indented line - """ - ''' - ) - ) - result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines( - dedent( - """ - * fixtures defined from test_show_fixtures_indented_doc * - fixture1 - line1 - indented line - """ - ) - ) - - def test_show_fixtures_indented_doc_first_line_unindented(self, testdir): - p = testdir.makepyfile( - dedent( - ''' - import pytest - @pytest.fixture - def fixture1(): - """line1 - line2 - indented line - """ - ''' - ) - ) - result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines( - dedent( - """ - * fixtures defined from test_show_fixtures_indented_doc_first_line_unindented * - fixture1 - line1 - line2 - indented line - """ - ) - ) - - def test_show_fixtures_indented_in_class(self, testdir): - p = testdir.makepyfile( - dedent( - ''' - import pytest - class TestClass(object): - @pytest.fixture - def fixture1(self): - """line1 - line2 - indented line - """ - ''' - ) - ) - result = testdir.runpytest("--fixtures", p) - result.stdout.fnmatch_lines( - dedent( - """ - * fixtures defined from test_show_fixtures_indented_in_class * - fixture1 - line1 - line2 - indented line - """ - ) - ) - - def test_show_fixtures_different_files(self, testdir): - """ - #833: --fixtures only shows fixtures from first file - """ - testdir.makepyfile( - test_a=''' - import pytest - - @pytest.fixture - def fix_a(): - """Fixture A""" - pass - - def test_a(fix_a): - pass - ''' - ) - testdir.makepyfile( - test_b=''' - import pytest - - @pytest.fixture - def fix_b(): - """Fixture B""" - pass - - def test_b(fix_b): - pass - ''' - ) - result = testdir.runpytest("--fixtures") - result.stdout.fnmatch_lines( - """ - * fixtures defined from test_a * - fix_a - Fixture A - - * fixtures defined from test_b * - fix_b - Fixture B - """ - ) - - def test_show_fixtures_with_same_name(self, testdir): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture - def arg1(): - """Hello World in conftest.py""" - return "Hello World" - ''' - ) - testdir.makepyfile( - """ - def test_foo(arg1): - assert arg1 == "Hello World" - """ - ) - testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def arg1(): - """Hi from test module""" - return "Hi" - def test_bar(arg1): - assert arg1 == "Hi" - ''' - ) - result = testdir.runpytest("--fixtures") - result.stdout.fnmatch_lines( - """ - * fixtures defined from conftest * - arg1 - Hello World in conftest.py - - * fixtures defined from test_show_fixtures_with_same_name * - arg1 - Hi from test module - """ - ) - - def test_fixture_disallow_twice(self): - """Test that applying @pytest.fixture twice generates an error (#2334).""" - with pytest.raises(ValueError): - - @pytest.fixture - @pytest.fixture - def foo(): - pass - - -@pytest.mark.parametrize("flavor", ["fixture", "yield_fixture"]) -class TestContextManagerFixtureFuncs(object): - - def test_simple(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor} - def arg1(): - print ("setup") - yield 1 - print ("teardown") - def test_1(arg1): - print ("test1 %s" % arg1) - def test_2(arg1): - print ("test2 %s" % arg1) - assert 0 - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *setup* - *test1 1* - *teardown* - *setup* - *test2 1* - *teardown* - """ - ) - - def test_scoped(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor}(scope="module") - def arg1(): - print ("setup") - yield 1 - print ("teardown") - def test_1(arg1): - print ("test1 %s" % arg1) - def test_2(arg1): - print ("test2 %s" % arg1) - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *setup* - *test1 1* - *test2 1* - *teardown* - """ - ) - - def test_setup_exception(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor}(scope="module") - def arg1(): - pytest.fail("setup") - yield 1 - def test_1(arg1): - pass - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *pytest.fail*setup* - *1 error* - """ - ) - - def test_teardown_exception(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor}(scope="module") - def arg1(): - yield 1 - pytest.fail("teardown") - def test_1(arg1): - pass - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *pytest.fail*teardown* - *1 passed*1 error* - """ - ) - - def test_yields_more_than_one(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor}(scope="module") - def arg1(): - yield 1 - yield 2 - def test_1(arg1): - pass - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *fixture function* - *test_yields*:2* - """ - ) - - def test_custom_name(self, testdir, flavor): - testdir.makepyfile( - """ - import pytest - @pytest.{flavor}(name='meow') - def arg1(): - return 'mew' - def test_1(meow): - print(meow) - """.format( - flavor=flavor - ) - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines("*mew*") - - -class TestParameterizedSubRequest(object): - - def test_call_from_fixture(self, testdir): - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[0, 1, 2]) - def fix_with_param(request): - return request.param - - @pytest.fixture - def get_named_fixture(request): - return request.getfixturevalue('fix_with_param') - - def test_foo(request, get_named_fixture): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - E*Failed: The requested fixture has no parameter defined for the current test. - E* - E*Requested fixture 'fix_with_param' defined in: - E*{}:4 - E*Requested here: - E*{}:9 - *1 error* - """.format( - testfile.basename, testfile.basename - ) - ) - - def test_call_from_test(self, testdir): - testfile = testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[0, 1, 2]) - def fix_with_param(request): - return request.param - - def test_foo(request): - request.getfixturevalue('fix_with_param') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - E*Failed: The requested fixture has no parameter defined for the current test. - E* - E*Requested fixture 'fix_with_param' defined in: - E*{}:4 - E*Requested here: - E*{}:8 - *1 failed* - """.format( - testfile.basename, testfile.basename - ) - ) - - def test_external_fixture(self, testdir): - conffile = testdir.makeconftest( - """ - import pytest - - @pytest.fixture(params=[0, 1, 2]) - def fix_with_param(request): - return request.param - """ - ) - - testfile = testdir.makepyfile( - """ - def test_foo(request): - request.getfixturevalue('fix_with_param') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - E*Failed: The requested fixture has no parameter defined for the current test. - E* - E*Requested fixture 'fix_with_param' defined in: - E*{}:4 - E*Requested here: - E*{}:2 - *1 failed* - """.format( - conffile.basename, testfile.basename - ) - ) - - def test_non_relative_path(self, testdir): - tests_dir = testdir.mkdir("tests") - fixdir = testdir.mkdir("fixtures") - fixfile = fixdir.join("fix.py") - fixfile.write( - _pytest._code.Source( - """ - import pytest - - @pytest.fixture(params=[0, 1, 2]) - def fix_with_param(request): - return request.param - """ - ) - ) - - testfile = tests_dir.join("test_foos.py") - testfile.write( - _pytest._code.Source( - """ - from fix import fix_with_param - - def test_foo(request): - request.getfixturevalue('fix_with_param') - """ - ) - ) - - tests_dir.chdir() - testdir.syspathinsert(fixdir) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - E*Failed: The requested fixture has no parameter defined for the current test. - E* - E*Requested fixture 'fix_with_param' defined in: - E*{}:5 - E*Requested here: - E*{}:5 - *1 failed* - """.format( - fixfile.strpath, testfile.basename - ) - ) - - -def test_pytest_fixture_setup_and_post_finalizer_hook(testdir): - testdir.makeconftest( - """ - from __future__ import print_function - def pytest_fixture_setup(fixturedef, request): - print('ROOT setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) - def pytest_fixture_post_finalizer(fixturedef, request): - print('ROOT finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) - """ - ) - testdir.makepyfile( - **{ - "tests/conftest.py": """ - from __future__ import print_function - def pytest_fixture_setup(fixturedef, request): - print('TESTS setup hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) - def pytest_fixture_post_finalizer(fixturedef, request): - print('TESTS finalizer hook called for {0} from {1}'.format(fixturedef.argname, request.node.name)) - """, - "tests/test_hooks.py": """ - from __future__ import print_function - import pytest - - @pytest.fixture() - def my_fixture(): - return 'some' - - def test_func(my_fixture): - print('TEST test_func') - assert my_fixture == 'some' - """, - } - ) - result = testdir.runpytest("-s") - assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*TESTS setup hook called for my_fixture from test_func*", - "*ROOT setup hook called for my_fixture from test_func*", - "*TEST test_func*", - "*TESTS finalizer hook called for my_fixture from test_func*", - "*ROOT finalizer hook called for my_fixture from test_func*", - ] - ) - - -class TestScopeOrdering(object): - """Class of tests that ensure fixtures are ordered based on their scopes (#2405)""" - - @pytest.mark.parametrize("use_mark", [True, False]) - def test_func_closure_module_auto(self, testdir, use_mark): - """Semantically identical to the example posted in #2405 when ``use_mark=True``""" - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='module', autouse={autouse}) - def m1(): pass - - if {use_mark}: - pytestmark = pytest.mark.usefixtures('m1') - - @pytest.fixture(scope='function', autouse=True) - def f1(): pass - - def test_func(m1): - pass - """.format( - autouse=not use_mark, use_mark=use_mark - ) - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - assert request.fixturenames == "m1 f1".split() - - def test_func_closure_with_native_fixtures(self, testdir, monkeypatch): - """Sanity check that verifies the order returned by the closures and the actual fixture execution order: - The execution order may differ because of fixture inter-dependencies. - """ - monkeypatch.setattr(pytest, "FIXTURE_ORDER", [], raising=False) - testdir.makepyfile( - """ - import pytest - - FIXTURE_ORDER = pytest.FIXTURE_ORDER - - @pytest.fixture(scope="session") - def s1(): - FIXTURE_ORDER.append('s1') - - @pytest.fixture(scope="module") - def m1(): - FIXTURE_ORDER.append('m1') - - @pytest.fixture(scope='session') - def my_tmpdir_factory(): - FIXTURE_ORDER.append('my_tmpdir_factory') - - @pytest.fixture - def my_tmpdir(my_tmpdir_factory): - FIXTURE_ORDER.append('my_tmpdir') - - @pytest.fixture - def f1(my_tmpdir): - FIXTURE_ORDER.append('f1') - - @pytest.fixture - def f2(): - FIXTURE_ORDER.append('f2') - - def test_foo(f1, m1, f2, s1): pass - """ - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - # order of fixtures based on their scope and position in the parameter list - assert request.fixturenames == "s1 my_tmpdir_factory m1 f1 f2 my_tmpdir".split() - testdir.runpytest() - # actual fixture execution differs: dependent fixtures must be created first ("my_tmpdir") - assert pytest.FIXTURE_ORDER == "s1 my_tmpdir_factory m1 my_tmpdir f1 f2".split() - - def test_func_closure_module(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='module') - def m1(): pass - - @pytest.fixture(scope='function') - def f1(): pass - - def test_func(f1, m1): - pass - """ - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - assert request.fixturenames == "m1 f1".split() - - def test_func_closure_scopes_reordered(self, testdir): - """Test ensures that fixtures are ordered by scope regardless of the order of the parameters, although - fixtures of same scope keep the declared order - """ - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='session') - def s1(): pass - - @pytest.fixture(scope='module') - def m1(): pass - - @pytest.fixture(scope='function') - def f1(): pass - - @pytest.fixture(scope='function') - def f2(): pass - - class Test: - - @pytest.fixture(scope='class') - def c1(cls): pass - - def test_func(self, f2, f1, c1, m1, s1): - pass - """ - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - assert request.fixturenames == "s1 m1 c1 f2 f1".split() - - def test_func_closure_same_scope_closer_root_first(self, testdir): - """Auto-use fixtures of same scope are ordered by closer-to-root first""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(scope='module', autouse=True) - def m_conf(): pass - """ - ) - testdir.makepyfile( - **{ - "sub/conftest.py": """ - import pytest - - @pytest.fixture(scope='module', autouse=True) - def m_sub(): pass - """, - "sub/test_func.py": """ - import pytest - - @pytest.fixture(scope='module', autouse=True) - def m_test(): pass - - @pytest.fixture(scope='function') - def f1(): pass - - def test_func(m_test, f1): - pass - """, - } - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - assert request.fixturenames == "m_conf m_sub m_test f1".split() - - def test_func_closure_all_scopes_complex(self, testdir): - """Complex test involving all scopes and mixing autouse with normal fixtures""" - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(scope='session') - def s1(): pass - """ - ) - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='module', autouse=True) - def m1(): pass - - @pytest.fixture(scope='module') - def m2(s1): pass - - @pytest.fixture(scope='function') - def f1(): pass - - @pytest.fixture(scope='function') - def f2(): pass - - class Test: - - @pytest.fixture(scope='class', autouse=True) - def c1(self): - pass - - def test_func(self, f2, f1, m2): - pass - """ - ) - items, _ = testdir.inline_genitems() - request = FixtureRequest(items[0]) - assert request.fixturenames == "s1 m1 m2 c1 f2 f1".split() diff --git a/third_party/python/pytest/testing/python/integration.py b/third_party/python/pytest/testing/python/integration.py deleted file mode 100644 index f348fdc29fd2..000000000000 --- a/third_party/python/pytest/testing/python/integration.py +++ /dev/null @@ -1,453 +0,0 @@ -import pytest -from _pytest import python -from _pytest import runner - - -class TestOEJSKITSpecials(object): - - def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage - testdir.makeconftest( - """ - import pytest - def pytest_pycollect_makeitem(collector, name, obj): - if name == "MyClass": - return MyCollector(name, parent=collector) - class MyCollector(pytest.Collector): - def reportinfo(self): - return self.fspath, 3, "xyz" - """ - ) - modcol = testdir.getmodulecol( - """ - import pytest - @pytest.fixture - def arg1(request): - return 42 - class MyClass(object): - pass - """ - ) - # this hook finds funcarg factories - rep = runner.collect_one_node(collector=modcol) - clscol = rep.result[0] - clscol.obj = lambda arg1: None - clscol.funcargs = {} - pytest._fillfuncargs(clscol) - assert clscol.funcargs["arg1"] == 42 - - def test_autouse_fixture(self, testdir): # rough jstests usage - testdir.makeconftest( - """ - import pytest - def pytest_pycollect_makeitem(collector, name, obj): - if name == "MyClass": - return MyCollector(name, parent=collector) - class MyCollector(pytest.Collector): - def reportinfo(self): - return self.fspath, 3, "xyz" - """ - ) - modcol = testdir.getmodulecol( - """ - import pytest - @pytest.fixture(autouse=True) - def hello(): - pass - @pytest.fixture - def arg1(request): - return 42 - class MyClass(object): - pass - """ - ) - # this hook finds funcarg factories - rep = runner.collect_one_node(modcol) - clscol = rep.result[0] - clscol.obj = lambda: None - clscol.funcargs = {} - pytest._fillfuncargs(clscol) - assert not clscol.funcargs - - -def test_wrapped_getfslineno(): - - def func(): - pass - - def wrap(f): - func.__wrapped__ = f - func.patchings = ["qwe"] - return func - - @wrap - def wrapped_func(x, y, z): - pass - - fs, lineno = python.getfslineno(wrapped_func) - fs2, lineno2 = python.getfslineno(wrap) - assert lineno > lineno2, "getfslineno does not unwrap correctly" - - -class TestMockDecoration(object): - - def test_wrapped_getfuncargnames(self): - from _pytest.compat import getfuncargnames - - def wrap(f): - - def func(): - pass - - func.__wrapped__ = f - return func - - @wrap - def f(x): - pass - - values = getfuncargnames(f) - assert values == ("x",) - - @pytest.mark.xfail( - strict=False, reason="getfuncargnames breaks if mock is imported" - ) - def test_wrapped_getfuncargnames_patching(self): - from _pytest.compat import getfuncargnames - - def wrap(f): - - def func(): - pass - - func.__wrapped__ = f - func.patchings = ["qwe"] - return func - - @wrap - def f(x, y, z): - pass - - values = getfuncargnames(f) - assert values == ("y", "z") - - def test_unittest_mock(self, testdir): - pytest.importorskip("unittest.mock") - testdir.makepyfile( - """ - import unittest.mock - class T(unittest.TestCase): - @unittest.mock.patch("os.path.abspath") - def test_hello(self, abspath): - import os - os.path.abspath("hello") - abspath.assert_any_call("hello") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_unittest_mock_and_fixture(self, testdir): - pytest.importorskip("unittest.mock") - testdir.makepyfile( - """ - import os.path - import unittest.mock - import pytest - - @pytest.fixture - def inject_me(): - pass - - @unittest.mock.patch.object(os.path, "abspath", - new=unittest.mock.MagicMock) - def test_hello(inject_me): - import os - os.path.abspath("hello") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_unittest_mock_and_pypi_mock(self, testdir): - pytest.importorskip("unittest.mock") - pytest.importorskip("mock", "1.0.1") - testdir.makepyfile( - """ - import mock - import unittest.mock - class TestBoth(object): - @unittest.mock.patch("os.path.abspath") - def test_hello(self, abspath): - import os - os.path.abspath("hello") - abspath.assert_any_call("hello") - - @mock.patch("os.path.abspath") - def test_hello_mock(self, abspath): - import os - os.path.abspath("hello") - abspath.assert_any_call("hello") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_mock(self, testdir): - pytest.importorskip("mock", "1.0.1") - testdir.makepyfile( - """ - import os - import unittest - import mock - - class T(unittest.TestCase): - @mock.patch("os.path.abspath") - def test_hello(self, abspath): - os.path.abspath("hello") - abspath.assert_any_call("hello") - def mock_basename(path): - return "mock_basename" - @mock.patch("os.path.abspath") - @mock.patch("os.path.normpath") - @mock.patch("os.path.basename", new=mock_basename) - def test_someting(normpath, abspath, tmpdir): - abspath.return_value = "this" - os.path.normpath(os.path.abspath("hello")) - normpath.assert_any_call("this") - assert os.path.basename("123") == "mock_basename" - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - calls = reprec.getcalls("pytest_runtest_logreport") - funcnames = [ - call.report.location[2] for call in calls if call.report.when == "call" - ] - assert funcnames == ["T.test_hello", "test_someting"] - - def test_mock_sorting(self, testdir): - pytest.importorskip("mock", "1.0.1") - testdir.makepyfile( - """ - import os - import mock - - @mock.patch("os.path.abspath") - def test_one(abspath): - pass - @mock.patch("os.path.abspath") - def test_two(abspath): - pass - @mock.patch("os.path.abspath") - def test_three(abspath): - pass - """ - ) - reprec = testdir.inline_run() - calls = reprec.getreports("pytest_runtest_logreport") - calls = [x for x in calls if x.when == "call"] - names = [x.nodeid.split("::")[-1] for x in calls] - assert names == ["test_one", "test_two", "test_three"] - - def test_mock_double_patch_issue473(self, testdir): - pytest.importorskip("mock", "1.0.1") - testdir.makepyfile( - """ - from mock import patch - from pytest import mark - - @patch('os.getcwd') - @patch('os.path') - @mark.slow - class TestSimple(object): - def test_simple_thing(self, mock_path, mock_getcwd): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -class TestReRunTests(object): - - def test_rerun(self, testdir): - testdir.makeconftest( - """ - from _pytest.runner import runtestprotocol - def pytest_runtest_protocol(item, nextitem): - runtestprotocol(item, log=False, nextitem=nextitem) - runtestprotocol(item, log=True, nextitem=nextitem) - """ - ) - testdir.makepyfile( - """ - import pytest - count = 0 - req = None - @pytest.fixture - def fix(request): - global count, req - assert request != req - req = request - print ("fix count %s" % count) - count += 1 - def test_fix(fix): - pass - """ - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines( - """ - *fix count 0* - *fix count 1* - """ - ) - result.stdout.fnmatch_lines( - """ - *2 passed* - """ - ) - - -def test_pytestconfig_is_session_scoped(): - from _pytest.fixtures import pytestconfig - - assert pytestconfig._pytestfixturefunction.scope == "session" - - -class TestNoselikeTestAttribute(object): - - def test_module_with_global_test(self, testdir): - testdir.makepyfile( - """ - __test__ = False - def test_hello(): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - calls = reprec.getreports("pytest_runtest_logreport") - assert not calls - - def test_class_and_method(self, testdir): - testdir.makepyfile( - """ - __test__ = True - def test_func(): - pass - test_func.__test__ = False - - class TestSome(object): - __test__ = False - def test_method(self): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - calls = reprec.getreports("pytest_runtest_logreport") - assert not calls - - def test_unittest_class(self, testdir): - testdir.makepyfile( - """ - import unittest - class TC(unittest.TestCase): - def test_1(self): - pass - class TC2(unittest.TestCase): - __test__ = False - def test_2(self): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - call = reprec.getcalls("pytest_collection_modifyitems")[0] - assert len(call.items) == 1 - assert call.items[0].cls.__name__ == "TC" - - def test_class_with_nasty_getattr(self, testdir): - """Make sure we handle classes with a custom nasty __getattr__ right. - - With a custom __getattr__ which e.g. returns a function (like with a - RPC wrapper), we shouldn't assume this meant "__test__ = True". - """ - # https://github.com/pytest-dev/pytest/issues/1204 - testdir.makepyfile( - """ - class MetaModel(type): - - def __getattr__(cls, key): - return lambda: None - - - BaseModel = MetaModel('Model', (), {}) - - - class Model(BaseModel): - - __metaclass__ = MetaModel - - def test_blah(self): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - call = reprec.getcalls("pytest_collection_modifyitems")[0] - assert not call.items - - -@pytest.mark.issue351 -class TestParameterize(object): - - def test_idfn_marker(self, testdir): - testdir.makepyfile( - """ - import pytest - - def idfn(param): - if param == 0: - return 'spam' - elif param == 1: - return 'ham' - else: - return None - - @pytest.mark.parametrize('a,b', [(0, 2), (1, 2)], ids=idfn) - def test_params(a, b): - pass - """ - ) - res = testdir.runpytest("--collect-only") - res.stdout.fnmatch_lines(["*spam-2*", "*ham-2*"]) - - def test_idfn_fixture(self, testdir): - testdir.makepyfile( - """ - import pytest - - def idfn(param): - if param == 0: - return 'spam' - elif param == 1: - return 'ham' - else: - return None - - @pytest.fixture(params=[0, 1], ids=idfn) - def a(request): - return request.param - - @pytest.fixture(params=[1, 2], ids=idfn) - def b(request): - return request.param - - def test_params(a, b): - pass - """ - ) - res = testdir.runpytest("--collect-only") - res.stdout.fnmatch_lines(["*spam-2*", "*ham-2*"]) diff --git a/third_party/python/pytest/testing/python/metafunc.py b/third_party/python/pytest/testing/python/metafunc.py deleted file mode 100644 index e181d3131f57..000000000000 --- a/third_party/python/pytest/testing/python/metafunc.py +++ /dev/null @@ -1,1768 +0,0 @@ -# -*- coding: utf-8 -*- -import re -import sys -import attr -import _pytest._code -import py -import pytest -from _pytest import python, fixtures - -import hypothesis -from hypothesis import strategies - -PY3 = sys.version_info >= (3, 0) - - -class TestMetafunc(object): - - def Metafunc(self, func, config=None): - # the unit tests of this class check if things work correctly - # on the funcarg level, so we don't need a full blown - # initiliazation - class FixtureInfo(object): - name2fixturedefs = None - - def __init__(self, names): - self.names_closure = names - - @attr.s - class DefinitionMock(object): - obj = attr.ib() - - names = fixtures.getfuncargnames(func) - fixtureinfo = FixtureInfo(names) - definition = DefinitionMock(func) - return python.Metafunc(definition, fixtureinfo, config) - - def test_no_funcargs(self, testdir): - - def function(): - pass - - metafunc = self.Metafunc(function) - assert not metafunc.fixturenames - repr(metafunc._calls) - - def test_function_basic(self): - - def func(arg1, arg2="qwe"): - pass - - metafunc = self.Metafunc(func) - assert len(metafunc.fixturenames) == 1 - assert "arg1" in metafunc.fixturenames - assert metafunc.function is func - assert metafunc.cls is None - - def test_addcall_no_args(self): - - def func(arg1): - pass - - metafunc = self.Metafunc(func) - metafunc.addcall() - assert len(metafunc._calls) == 1 - call = metafunc._calls[0] - assert call.id == "0" - assert not hasattr(call, "param") - - def test_addcall_id(self): - - def func(arg1): - pass - - metafunc = self.Metafunc(func) - pytest.raises(ValueError, "metafunc.addcall(id=None)") - - metafunc.addcall(id=1) - pytest.raises(ValueError, "metafunc.addcall(id=1)") - pytest.raises(ValueError, "metafunc.addcall(id='1')") - metafunc.addcall(id=2) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].id == "1" - assert metafunc._calls[1].id == "2" - - def test_addcall_param(self): - - def func(arg1): - pass - - metafunc = self.Metafunc(func) - - class obj(object): - pass - - metafunc.addcall(param=obj) - metafunc.addcall(param=obj) - metafunc.addcall(param=1) - assert len(metafunc._calls) == 3 - assert metafunc._calls[0].getparam("arg1") == obj - assert metafunc._calls[1].getparam("arg1") == obj - assert metafunc._calls[2].getparam("arg1") == 1 - - def test_addcall_funcargs(self): - - def func(x): - pass - - metafunc = self.Metafunc(func) - - class obj(object): - pass - - metafunc.addcall(funcargs={"x": 2}) - metafunc.addcall(funcargs={"x": 3}) - pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})") - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == {"x": 2} - assert metafunc._calls[1].funcargs == {"x": 3} - assert not hasattr(metafunc._calls[1], "param") - - def test_parametrize_error(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x", [1, 2]) - pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5, 6])) - pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5, 6])) - metafunc.parametrize("y", [1, 2]) - pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) - pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) - - def test_parametrize_bad_scope(self, testdir): - - def func(x): - pass - - metafunc = self.Metafunc(func) - try: - metafunc.parametrize("x", [1], scope="doggy") - except ValueError as ve: - assert "has an unsupported scope value 'doggy'" in str(ve) - - def test_parametrize_and_id(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - - metafunc.parametrize("x", [1, 2], ids=["basic", "advanced"]) - metafunc.parametrize("y", ["abc", "def"]) - ids = [x.id for x in metafunc._calls] - assert ids == ["basic-abc", "basic-def", "advanced-abc", "advanced-def"] - - def test_parametrize_and_id_unicode(self): - """Allow unicode strings for "ids" parameter in Python 2 (##1905)""" - - def func(x): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x", [1, 2], ids=[u"basic", u"advanced"]) - ids = [x.id for x in metafunc._calls] - assert ids == [u"basic", u"advanced"] - - def test_parametrize_with_wrong_number_of_ids(self, testdir): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - - pytest.raises( - ValueError, lambda: metafunc.parametrize("x", [1, 2], ids=["basic"]) - ) - - pytest.raises( - ValueError, - lambda: metafunc.parametrize( - ("x", "y"), [("abc", "def"), ("ghi", "jkl")], ids=["one"] - ), - ) - - @pytest.mark.issue510 - def test_parametrize_empty_list(self): - - def func(y): - pass - - class MockConfig(object): - - def getini(self, name): - return "" - - @property - def hook(self): - return self - - def pytest_make_parametrize_id(self, **kw): - pass - - metafunc = self.Metafunc(func, MockConfig()) - metafunc.parametrize("y", []) - assert "skip" == metafunc._calls[0].marks[0].name - - def test_parametrize_with_userobjects(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - - class A(object): - pass - - metafunc.parametrize("x", [A(), A()]) - metafunc.parametrize("y", list("ab")) - assert metafunc._calls[0].id == "x0-a" - assert metafunc._calls[1].id == "x0-b" - assert metafunc._calls[2].id == "x1-a" - assert metafunc._calls[3].id == "x1-b" - - @hypothesis.given(strategies.text() | strategies.binary()) - @hypothesis.settings( - deadline=400.0 - ) # very close to std deadline and CI boxes are not reliable in CPU power - def test_idval_hypothesis(self, value): - from _pytest.python import _idval - - escaped = _idval(value, "a", 6, None) - assert isinstance(escaped, str) - if PY3: - escaped.encode("ascii") - else: - escaped.decode("ascii") - - def test_unicode_idval(self): - """This tests that Unicode strings outside the ASCII character set get - escaped, using byte escapes if they're in that range or unicode - escapes if they're not. - - """ - from _pytest.python import _idval - - values = [ - (u"", ""), - (u"ascii", "ascii"), - (u"ação", "a\\xe7\\xe3o"), - (u"josé@blah.com", "jos\\xe9@blah.com"), - ( - u"δοκ.ιμή@παράδειγμα.δοκιμή", - "\\u03b4\\u03bf\\u03ba.\\u03b9\\u03bc\\u03ae@\\u03c0\\u03b1\\u03c1\\u03ac\\u03b4\\u03b5\\u03b9\\u03b3" - "\\u03bc\\u03b1.\\u03b4\\u03bf\\u03ba\\u03b9\\u03bc\\u03ae", - ), - ] - for val, expected in values: - assert _idval(val, "a", 6, None) == expected - - def test_bytes_idval(self): - """unittest for the expected behavior to obtain ids for parametrized - bytes values: - - python2: non-ascii strings are considered bytes and formatted using - "binary escape", where any byte < 127 is escaped into its hex form. - - python3: bytes objects are always escaped using "binary escape". - """ - from _pytest.python import _idval - - values = [ - (b"", ""), - (b"\xc3\xb4\xff\xe4", "\\xc3\\xb4\\xff\\xe4"), - (b"ascii", "ascii"), - (u"αρά".encode("utf-8"), "\\xce\\xb1\\xcf\\x81\\xce\\xac"), - ] - for val, expected in values: - assert _idval(val, "a", 6, None) == expected - - def test_class_or_function_idval(self): - """unittest for the expected behavior to obtain ids for parametrized - values that are classes or functions: their __name__. - """ - from _pytest.python import _idval - - class TestClass(object): - pass - - def test_function(): - pass - - values = [(TestClass, "TestClass"), (test_function, "test_function")] - for val, expected in values: - assert _idval(val, "a", 6, None) == expected - - @pytest.mark.issue250 - def test_idmaker_autoname(self): - from _pytest.python import idmaker - - result = idmaker( - ("a", "b"), [pytest.param("string", 1.0), pytest.param("st-ring", 2.0)] - ) - assert result == ["string-1.0", "st-ring-2.0"] - - result = idmaker( - ("a", "b"), [pytest.param(object(), 1.0), pytest.param(object(), object())] - ) - assert result == ["a0-1.0", "a1-b1"] - # unicode mixing, issue250 - result = idmaker( - (py.builtin._totext("a"), "b"), [pytest.param({}, b"\xc3\xb4")] - ) - assert result == ["a0-\\xc3\\xb4"] - - def test_idmaker_with_bytes_regex(self): - from _pytest.python import idmaker - - result = idmaker(("a"), [pytest.param(re.compile(b"foo"), 1.0)]) - assert result == ["foo"] - - def test_idmaker_native_strings(self): - from _pytest.python import idmaker - - totext = py.builtin._totext - result = idmaker( - ("a", "b"), - [ - pytest.param(1.0, -1.1), - pytest.param(2, -202), - pytest.param("three", "three hundred"), - pytest.param(True, False), - pytest.param(None, None), - pytest.param(re.compile("foo"), re.compile("bar")), - pytest.param(str, int), - pytest.param(list("six"), [66, 66]), - pytest.param({7}, set("seven")), - pytest.param(tuple("eight"), (8, -8, 8)), - pytest.param(b"\xc3\xb4", b"name"), - pytest.param(b"\xc3\xb4", totext("other")), - ], - ) - assert ( - result - == [ - "1.0--1.1", - "2--202", - "three-three hundred", - "True-False", - "None-None", - "foo-bar", - "str-int", - "a7-b7", - "a8-b8", - "a9-b9", - "\\xc3\\xb4-name", - "\\xc3\\xb4-other", - ] - ) - - def test_idmaker_enum(self): - from _pytest.python import idmaker - - enum = pytest.importorskip("enum") - e = enum.Enum("Foo", "one, two") - result = idmaker(("a", "b"), [pytest.param(e.one, e.two)]) - assert result == ["Foo.one-Foo.two"] - - @pytest.mark.issue351 - def test_idmaker_idfn(self): - from _pytest.python import idmaker - - def ids(val): - if isinstance(val, Exception): - return repr(val) - - result = idmaker( - ("a", "b"), - [ - pytest.param(10.0, IndexError()), - pytest.param(20, KeyError()), - pytest.param("three", [1, 2, 3]), - ], - idfn=ids, - ) - assert result == ["10.0-IndexError()", "20-KeyError()", "three-b2"] - - @pytest.mark.issue351 - def test_idmaker_idfn_unique_names(self): - from _pytest.python import idmaker - - def ids(val): - return "a" - - result = idmaker( - ("a", "b"), - [ - pytest.param(10.0, IndexError()), - pytest.param(20, KeyError()), - pytest.param("three", [1, 2, 3]), - ], - idfn=ids, - ) - assert result == ["a-a0", "a-a1", "a-a2"] - - @pytest.mark.issue351 - def test_idmaker_idfn_exception(self): - from _pytest.python import idmaker - from _pytest.recwarn import WarningsRecorder - - class BadIdsException(Exception): - pass - - def ids(val): - raise BadIdsException("ids raised") - - rec = WarningsRecorder() - with rec: - idmaker( - ("a", "b"), - [ - pytest.param(10.0, IndexError()), - pytest.param(20, KeyError()), - pytest.param("three", [1, 2, 3]), - ], - idfn=ids, - ) - - assert ( - [str(i.message) for i in rec.list] - == [ - "Raised while trying to determine id of parameter a at position 0." - "\nUpdate your code as this will raise an error in pytest-4.0.", - "Raised while trying to determine id of parameter b at position 0." - "\nUpdate your code as this will raise an error in pytest-4.0.", - "Raised while trying to determine id of parameter a at position 1." - "\nUpdate your code as this will raise an error in pytest-4.0.", - "Raised while trying to determine id of parameter b at position 1." - "\nUpdate your code as this will raise an error in pytest-4.0.", - "Raised while trying to determine id of parameter a at position 2." - "\nUpdate your code as this will raise an error in pytest-4.0.", - "Raised while trying to determine id of parameter b at position 2." - "\nUpdate your code as this will raise an error in pytest-4.0.", - ] - ) - - def test_parametrize_ids_exception(self, testdir): - """ - :param testdir: the instance of Testdir class, a temporary - test directory. - """ - testdir.makepyfile( - """ - import pytest - - def ids(arg): - raise Exception("bad ids") - - @pytest.mark.parametrize("arg", ["a", "b"], ids=ids) - def test_foo(arg): - pass - """ - ) - with pytest.warns(DeprecationWarning): - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines( - [ - "", - " ", - " ", - ] - ) - - def test_idmaker_with_ids(self): - from _pytest.python import idmaker - - result = idmaker( - ("a", "b"), [pytest.param(1, 2), pytest.param(3, 4)], ids=["a", None] - ) - assert result == ["a", "3-4"] - - def test_idmaker_with_paramset_id(self): - from _pytest.python import idmaker - - result = idmaker( - ("a", "b"), - [pytest.param(1, 2, id="me"), pytest.param(3, 4, id="you")], - ids=["a", None], - ) - assert result == ["me", "you"] - - def test_idmaker_with_ids_unique_names(self): - from _pytest.python import idmaker - - result = idmaker( - ("a"), map(pytest.param, [1, 2, 3, 4, 5]), ids=["a", "a", "b", "c", "b"] - ) - assert result == ["a0", "a1", "b0", "c", "b1"] - - def test_addcall_and_parametrize(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.addcall({"x": 1}) - metafunc.parametrize("y", [2, 3]) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == {"x": 1, "y": 2} - assert metafunc._calls[1].funcargs == {"x": 1, "y": 3} - assert metafunc._calls[0].id == "0-2" - assert metafunc._calls[1].id == "0-3" - - @pytest.mark.issue714 - def test_parametrize_indirect(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x", [1], indirect=True) - metafunc.parametrize("y", [2, 3], indirect=True) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == {} - assert metafunc._calls[1].funcargs == {} - assert metafunc._calls[0].params == dict(x=1, y=2) - assert metafunc._calls[1].params == dict(x=1, y=3) - - @pytest.mark.issue714 - def test_parametrize_indirect_list(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x, y", [("a", "b")], indirect=["x"]) - assert metafunc._calls[0].funcargs == dict(y="b") - assert metafunc._calls[0].params == dict(x="a") - - @pytest.mark.issue714 - def test_parametrize_indirect_list_all(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x, y", [("a", "b")], indirect=["x", "y"]) - assert metafunc._calls[0].funcargs == {} - assert metafunc._calls[0].params == dict(x="a", y="b") - - @pytest.mark.issue714 - def test_parametrize_indirect_list_empty(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.parametrize("x, y", [("a", "b")], indirect=[]) - assert metafunc._calls[0].funcargs == dict(x="a", y="b") - assert metafunc._calls[0].params == {} - - @pytest.mark.issue714 - def test_parametrize_indirect_list_functional(self, testdir): - """ - Test parametrization with 'indirect' parameter applied on - particular arguments. As y is is direct, its value should - be used directly rather than being passed to the fixture - y. - - :param testdir: the instance of Testdir class, a temporary - test directory. - """ - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='function') - def x(request): - return request.param * 3 - @pytest.fixture(scope='function') - def y(request): - return request.param * 2 - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['x']) - def test_simple(x,y): - assert len(x) == 3 - assert len(y) == 1 - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*test_simple*a-b*", "*1 passed*"]) - - @pytest.mark.issue714 - def test_parametrize_indirect_list_error(self, testdir): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - with pytest.raises(ValueError): - metafunc.parametrize("x, y", [("a", "b")], indirect=["x", "z"]) - - @pytest.mark.issue714 - def test_parametrize_uses_no_fixture_error_indirect_false(self, testdir): - """The 'uses no fixture' error tells the user at collection time - that the parametrize data they've set up doesn't correspond to the - fixtures in their test function, rather than silently ignoring this - and letting the test potentially pass. - """ - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=False) - def test_simple(x): - assert len(x) == 3 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*uses no argument 'y'*"]) - - @pytest.mark.issue714 - def test_parametrize_uses_no_fixture_error_indirect_true(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='function') - def x(request): - return request.param * 3 - @pytest.fixture(scope='function') - def y(request): - return request.param * 2 - - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=True) - def test_simple(x): - assert len(x) == 3 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) - - @pytest.mark.issue714 - def test_parametrize_indirect_uses_no_fixture_error_indirect_string(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='function') - def x(request): - return request.param * 3 - - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect='y') - def test_simple(x): - assert len(x) == 3 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) - - @pytest.mark.issue714 - def test_parametrize_indirect_uses_no_fixture_error_indirect_list(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='function') - def x(request): - return request.param * 3 - - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['y']) - def test_simple(x): - assert len(x) == 3 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*uses no fixture 'y'*"]) - - @pytest.mark.issue714 - def test_parametrize_argument_not_in_indirect_list(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='function') - def x(request): - return request.param * 3 - - @pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['x']) - def test_simple(x): - assert len(x) == 3 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*uses no argument 'y'*"]) - - def test_parametrize_gives_indicative_error_on_function_with_default_argument( - self, testdir - ): - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize('x, y', [('a', 'b')]) - def test_simple(x, y=1): - assert len(x) == 1 - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines( - ["*already takes an argument 'y' with a default value"] - ) - - def test_addcalls_and_parametrize_indirect(self): - - def func(x, y): - pass - - metafunc = self.Metafunc(func) - metafunc.addcall(param="123") - metafunc.parametrize("x", [1], indirect=True) - metafunc.parametrize("y", [2, 3], indirect=True) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == {} - assert metafunc._calls[1].funcargs == {} - assert metafunc._calls[0].params == dict(x=1, y=2) - assert metafunc._calls[1].params == dict(x=1, y=3) - - def test_parametrize_functional(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.parametrize('x', [1,2], indirect=True) - metafunc.parametrize('y', [2]) - @pytest.fixture - def x(request): - return request.param * 10 - - def test_simple(x,y): - assert x in (10,20) - assert y == 2 - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - ["*test_simple*1-2*", "*test_simple*2-2*", "*2 passed*"] - ) - - def test_parametrize_onearg(self): - metafunc = self.Metafunc(lambda x: None) - metafunc.parametrize("x", [1, 2]) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == dict(x=1) - assert metafunc._calls[0].id == "1" - assert metafunc._calls[1].funcargs == dict(x=2) - assert metafunc._calls[1].id == "2" - - def test_parametrize_onearg_indirect(self): - metafunc = self.Metafunc(lambda x: None) - metafunc.parametrize("x", [1, 2], indirect=True) - assert metafunc._calls[0].params == dict(x=1) - assert metafunc._calls[0].id == "1" - assert metafunc._calls[1].params == dict(x=2) - assert metafunc._calls[1].id == "2" - - def test_parametrize_twoargs(self): - metafunc = self.Metafunc(lambda x, y: None) - metafunc.parametrize(("x", "y"), [(1, 2), (3, 4)]) - assert len(metafunc._calls) == 2 - assert metafunc._calls[0].funcargs == dict(x=1, y=2) - assert metafunc._calls[0].id == "1-2" - assert metafunc._calls[1].funcargs == dict(x=3, y=4) - assert metafunc._calls[1].id == "3-4" - - def test_parametrize_multiple_times(self, testdir): - testdir.makepyfile( - """ - import pytest - pytestmark = pytest.mark.parametrize("x", [1,2]) - def test_func(x): - assert 0, x - class TestClass(object): - pytestmark = pytest.mark.parametrize("y", [3,4]) - def test_meth(self, x, y): - assert 0, x - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.assert_outcomes(failed=6) - - def test_parametrize_CSV(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize("x, y,", [(1,2), (2,3)]) - def test_func(x, y): - assert x+1 == y - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - def test_parametrize_class_scenarios(self, testdir): - testdir.makepyfile( - """ - # same as doc/en/example/parametrize scenario example - def pytest_generate_tests(metafunc): - idlist = [] - argvalues = [] - for scenario in metafunc.cls.scenarios: - idlist.append(scenario[0]) - items = scenario[1].items() - argnames = [x[0] for x in items] - argvalues.append(([x[1] for x in items])) - metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") - - class Test(object): - scenarios = [['1', {'arg': {1: 2}, "arg2": "value2"}], - ['2', {'arg':'value2', "arg2": "value2"}]] - - def test_1(self, arg, arg2): - pass - - def test_2(self, arg2, arg): - pass - - def test_3(self, arg, arg2): - pass - """ - ) - result = testdir.runpytest("-v") - assert result.ret == 0 - result.stdout.fnmatch_lines( - """ - *test_1*1* - *test_2*1* - *test_3*1* - *test_1*2* - *test_2*2* - *test_3*2* - *6 passed* - """ - ) - - def test_format_args(self): - - def function1(): - pass - - assert fixtures._format_args(function1) == "()" - - def function2(arg1): - pass - - assert fixtures._format_args(function2) == "(arg1)" - - def function3(arg1, arg2="qwe"): - pass - - assert fixtures._format_args(function3) == "(arg1, arg2='qwe')" - - def function4(arg1, *args, **kwargs): - pass - - assert fixtures._format_args(function4) == "(arg1, *args, **kwargs)" - - -class TestMetafuncFunctional(object): - - def test_attributes(self, testdir): - p = testdir.makepyfile( - """ - # assumes that generate/provide runs in the same process - import sys, pytest - def pytest_generate_tests(metafunc): - metafunc.addcall(param=metafunc) - - @pytest.fixture - def metafunc(request): - assert request._pyfuncitem._genid == "0" - return request.param - - def test_function(metafunc, pytestconfig): - assert metafunc.config == pytestconfig - assert metafunc.module.__name__ == __name__ - assert metafunc.function == test_function - assert metafunc.cls is None - - class TestClass(object): - def test_method(self, metafunc, pytestconfig): - assert metafunc.config == pytestconfig - assert metafunc.module.__name__ == __name__ - if sys.version_info > (3, 0): - unbound = TestClass.test_method - else: - unbound = TestClass.test_method.im_func - # XXX actually have an unbound test function here? - assert metafunc.function == unbound - assert metafunc.cls == TestClass - """ - ) - result = testdir.runpytest(p, "-v") - result.assert_outcomes(passed=2) - - def test_addcall_with_two_funcargs_generators(self, testdir): - testdir.makeconftest( - """ - def pytest_generate_tests(metafunc): - assert "arg1" in metafunc.fixturenames - metafunc.addcall(funcargs=dict(arg1=1, arg2=2)) - """ - ) - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall(funcargs=dict(arg1=1, arg2=1)) - - class TestClass(object): - def test_myfunc(self, arg1, arg2): - assert arg1 == arg2 - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines( - ["*test_myfunc*0*PASS*", "*test_myfunc*1*FAIL*", "*1 failed, 1 passed*"] - ) - - def test_two_functions(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall(param=10) - metafunc.addcall(param=20) - - import pytest - @pytest.fixture - def arg1(request): - return request.param - - def test_func1(arg1): - assert arg1 == 10 - def test_func2(arg1): - assert arg1 in (10, 20) - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines( - [ - "*test_func1*0*PASS*", - "*test_func1*1*FAIL*", - "*test_func2*PASS*", - "*1 failed, 3 passed*", - ] - ) - - def test_noself_in_method(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - assert 'xyz' not in metafunc.fixturenames - - class TestHello(object): - def test_hello(xyz): - pass - """ - ) - result = testdir.runpytest(p) - result.assert_outcomes(passed=1) - - def test_generate_plugin_and_module(self, testdir): - testdir.makeconftest( - """ - def pytest_generate_tests(metafunc): - assert "arg1" in metafunc.fixturenames - metafunc.addcall(id="world", param=(2,100)) - """ - ) - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall(param=(1,1), id="hello") - - import pytest - @pytest.fixture - def arg1(request): - return request.param[0] - @pytest.fixture - def arg2(request): - return request.param[1] - - class TestClass(object): - def test_myfunc(self, arg1, arg2): - assert arg1 == arg2 - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines( - [ - "*test_myfunc*hello*PASS*", - "*test_myfunc*world*FAIL*", - "*1 failed, 1 passed*", - ] - ) - - def test_generate_tests_in_class(self, testdir): - p = testdir.makepyfile( - """ - class TestClass(object): - def pytest_generate_tests(self, metafunc): - metafunc.addcall(funcargs={'hello': 'world'}, id="hello") - - def test_myfunc(self, hello): - assert hello == "world" - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines(["*test_myfunc*hello*PASS*", "*1 passed*"]) - - def test_two_functions_not_same_instance(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall({'arg1': 10}) - metafunc.addcall({'arg1': 20}) - - class TestClass(object): - def test_func(self, arg1): - assert not hasattr(self, 'x') - self.x = 1 - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines( - ["*test_func*0*PASS*", "*test_func*1*PASS*", "*2 pass*"] - ) - - def test_issue28_setup_method_in_generate_tests(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall({'arg1': 1}) - - class TestClass(object): - def test_method(self, arg1): - assert arg1 == self.val - def setup_method(self, func): - self.val = 1 - """ - ) - result = testdir.runpytest(p) - result.assert_outcomes(passed=1) - - def test_parametrize_functional2(self, testdir): - testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.parametrize("arg1", [1,2]) - metafunc.parametrize("arg2", [4,5]) - def test_hello(arg1, arg2): - assert 0, (arg1, arg2) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*(1, 4)*", "*(1, 5)*", "*(2, 4)*", "*(2, 5)*", "*4 failed*"] - ) - - def test_parametrize_and_inner_getfixturevalue(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.parametrize("arg1", [1], indirect=True) - metafunc.parametrize("arg2", [10], indirect=True) - - import pytest - @pytest.fixture - def arg1(request): - x = request.getfixturevalue("arg2") - return x + request.param - - @pytest.fixture - def arg2(request): - return request.param - - def test_func1(arg1, arg2): - assert arg1 == 11 - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines(["*test_func1*1*PASS*", "*1 passed*"]) - - def test_parametrize_on_setup_arg(self, testdir): - p = testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - assert "arg1" in metafunc.fixturenames - metafunc.parametrize("arg1", [1], indirect=True) - - import pytest - @pytest.fixture - def arg1(request): - return request.param - - @pytest.fixture - def arg2(request, arg1): - return 10 * arg1 - - def test_func(arg2): - assert arg2 == 10 - """ - ) - result = testdir.runpytest("-v", p) - result.stdout.fnmatch_lines(["*test_func*1*PASS*", "*1 passed*"]) - - def test_parametrize_with_ids(self, testdir): - testdir.makeini( - """ - [pytest] - console_output_style=classic - """ - ) - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.parametrize(("a", "b"), [(1,1), (1,2)], - ids=["basic", "advanced"]) - - def test_function(a, b): - assert a == b - """ - ) - result = testdir.runpytest("-v") - assert result.ret == 1 - result.stdout.fnmatch_lines_random( - ["*test_function*basic*PASSED", "*test_function*advanced*FAILED"] - ) - - def test_parametrize_without_ids(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.parametrize(("a", "b"), - [(1,object()), (1.3,object())]) - - def test_function(a, b): - assert 1 - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - """ - *test_function*1-b0* - *test_function*1.3-b1* - """ - ) - - def test_parametrize_with_None_in_ids(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.parametrize(("a", "b"), [(1,1), (1,1), (1,2)], - ids=["basic", None, "advanced"]) - - def test_function(a, b): - assert a == b - """ - ) - result = testdir.runpytest("-v") - assert result.ret == 1 - result.stdout.fnmatch_lines_random( - [ - "*test_function*basic*PASSED*", - "*test_function*1-1*PASSED*", - "*test_function*advanced*FAILED*", - ] - ) - - def test_fixture_parametrized_empty_ids(self, testdir): - """Fixtures parametrized with empty ids cause an internal error (#1849).""" - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope="module", ids=[], params=[]) - def temp(request): - return request.param - - def test_temp(temp): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 1 skipped *"]) - - def test_parametrized_empty_ids(self, testdir): - """Tests parametrized with empty ids cause an internal error (#1849).""" - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize('temp', [], ids=list()) - def test_temp(temp): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 1 skipped *"]) - - def test_parametrized_ids_invalid_type(self, testdir): - """Tests parametrized with ids as non-strings (#1857).""" - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize("x, expected", [(10, 20), (40, 80)], ids=(None, 2)) - def test_ids_numbers(x,expected): - assert x * 2 == expected - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*ids must be list of strings, found: 2 (type: int)*"] - ) - - def test_parametrize_with_identical_ids_get_unique_names(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - metafunc.parametrize(("a", "b"), [(1,1), (1,2)], - ids=["a", "a"]) - - def test_function(a, b): - assert a == b - """ - ) - result = testdir.runpytest("-v") - assert result.ret == 1 - result.stdout.fnmatch_lines_random( - ["*test_function*a0*PASSED*", "*test_function*a1*FAILED*"] - ) - - @pytest.mark.parametrize(("scope", "length"), [("module", 2), ("function", 4)]) - def test_parametrize_scope_overrides(self, testdir, scope, length): - testdir.makepyfile( - """ - import pytest - values = [] - def pytest_generate_tests(metafunc): - if "arg" in metafunc.funcargnames: - metafunc.parametrize("arg", [1,2], indirect=True, - scope=%r) - @pytest.fixture - def arg(request): - values.append(request.param) - return request.param - def test_hello(arg): - assert arg in (1,2) - def test_world(arg): - assert arg in (1,2) - def test_checklength(): - assert len(values) == %d - """ - % (scope, length) - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=5) - - def test_parametrize_issue323(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='module', params=range(966)) - def foo(request): - return request.param - - def test_it(foo): - pass - def test_it2(foo): - pass - """ - ) - reprec = testdir.inline_run("--collect-only") - assert not reprec.getcalls("pytest_internalerror") - - def test_usefixtures_seen_in_generate_tests(self, testdir): - testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - assert "abc" in metafunc.fixturenames - metafunc.parametrize("abc", [1]) - - @pytest.mark.usefixtures("abc") - def test_function(): - pass - """ - ) - reprec = testdir.runpytest() - reprec.assert_outcomes(passed=1) - - def test_generate_tests_only_done_in_subdir(self, testdir): - sub1 = testdir.mkpydir("sub1") - sub2 = testdir.mkpydir("sub2") - sub1.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_generate_tests(metafunc): - assert metafunc.function.__name__ == "test_1" - """ - ) - ) - sub2.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_generate_tests(metafunc): - assert metafunc.function.__name__ == "test_2" - """ - ) - ) - sub1.join("test_in_sub1.py").write("def test_1(): pass") - sub2.join("test_in_sub2.py").write("def test_2(): pass") - result = testdir.runpytest("--keep-duplicates", "-v", "-s", sub1, sub2, sub1) - result.assert_outcomes(passed=3) - - def test_generate_same_function_names_issue403(self, testdir): - testdir.makepyfile( - """ - import pytest - - def make_tests(): - @pytest.mark.parametrize("x", range(2)) - def test_foo(x): - pass - return test_foo - - test_x = make_tests() - test_y = make_tests() - """ - ) - reprec = testdir.runpytest() - reprec.assert_outcomes(passed=4) - - @pytest.mark.issue463 - @pytest.mark.parametrize("attr", ["parametrise", "parameterize", "parameterise"]) - def test_parametrize_misspelling(self, testdir, attr): - testdir.makepyfile( - """ - import pytest - - @pytest.mark.{}("x", range(2)) - def test_foo(x): - pass - """.format( - attr - ) - ) - reprec = testdir.inline_run("--collectonly") - failures = reprec.getfailures() - assert len(failures) == 1 - expectederror = "MarkerError: test_foo has '{}', spelling should be 'parametrize'".format( - attr - ) - assert expectederror in failures[0].longrepr.reprcrash.message - - -class TestMetafuncFunctionalAuto(object): - """ - Tests related to automatically find out the correct scope for parametrized tests (#1832). - """ - - def test_parametrize_auto_scope(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='session', autouse=True) - def fixture(): - return 1 - - @pytest.mark.parametrize('animal', ["dog", "cat"]) - def test_1(animal): - assert animal in ('dog', 'cat') - - @pytest.mark.parametrize('animal', ['fish']) - def test_2(animal): - assert animal == 'fish' - - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 3 passed *"]) - - def test_parametrize_auto_scope_indirect(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='session') - def echo(request): - return request.param - - @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=['echo']) - def test_1(animal, echo): - assert animal in ('dog', 'cat') - assert echo in (1, 2, 3) - - @pytest.mark.parametrize('animal, echo', [('fish', 3)], indirect=['echo']) - def test_2(animal, echo): - assert animal == 'fish' - assert echo in (1, 2, 3) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 3 passed *"]) - - def test_parametrize_auto_scope_override_fixture(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='session', autouse=True) - def animal(): - return 'fox' - - @pytest.mark.parametrize('animal', ["dog", "cat"]) - def test_1(animal): - assert animal in ('dog', 'cat') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 2 passed *"]) - - def test_parametrize_all_indirects(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture() - def animal(request): - return request.param - - @pytest.fixture(scope='session') - def echo(request): - return request.param - - @pytest.mark.parametrize('animal, echo', [("dog", 1), ("cat", 2)], indirect=True) - def test_1(animal, echo): - assert animal in ('dog', 'cat') - assert echo in (1, 2, 3) - - @pytest.mark.parametrize('animal, echo', [("fish", 3)], indirect=True) - def test_2(animal, echo): - assert animal == 'fish' - assert echo in (1, 2, 3) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 3 passed *"]) - - def test_parametrize_issue634(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture(scope='module') - def foo(request): - print('preparing foo-%d' % request.param) - return 'foo-%d' % request.param - - def test_one(foo): - pass - - def test_two(foo): - pass - - test_two.test_with = (2, 3) - - def pytest_generate_tests(metafunc): - params = (1, 2, 3, 4) - if not 'foo' in metafunc.fixturenames: - return - - test_with = getattr(metafunc.function, 'test_with', None) - if test_with: - params = test_with - metafunc.parametrize('foo', params, indirect=True) - """ - ) - result = testdir.runpytest("-s") - output = result.stdout.str() - assert output.count("preparing foo-2") == 1 - assert output.count("preparing foo-3") == 1 - - -@pytest.mark.filterwarnings("ignore:Applying marks directly to parameters") -@pytest.mark.issue308 -class TestMarkersWithParametrization(object): - - def test_simple_mark(self, testdir): - s = """ - import pytest - - @pytest.mark.foo - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.bar((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - items = testdir.getitems(s) - assert len(items) == 3 - for item in items: - assert "foo" in item.keywords - assert "bar" not in items[0].keywords - assert "bar" in items[1].keywords - assert "bar" not in items[2].keywords - - def test_select_based_on_mark(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.foo((2, 3)), - (3, 4), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - rec = testdir.inline_run("-m", "foo") - passed, skipped, fail = rec.listoutcomes() - assert len(passed) == 1 - assert len(skipped) == 0 - assert len(fail) == 0 - - @pytest.mark.xfail(reason="is this important to support??") - def test_nested_marks(self, testdir): - s = """ - import pytest - mastermark = pytest.mark.foo(pytest.mark.bar) - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - mastermark((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - items = testdir.getitems(s) - assert len(items) == 3 - for mark in ["foo", "bar"]: - assert mark not in items[0].keywords - assert mark in items[1].keywords - assert mark not in items[2].keywords - - def test_simple_xfail(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - # xfail is skip?? - reprec.assertoutcome(passed=2, skipped=1) - - def test_simple_xfail_single_argname(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize("n", [ - 2, - pytest.mark.xfail(3), - 4, - ]) - def test_isEven(n): - assert n % 2 == 0 - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2, skipped=1) - - def test_xfail_with_arg(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail("True")((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2, skipped=1) - - def test_xfail_with_kwarg(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail(reason="some bug")((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2, skipped=1) - - def test_xfail_with_arg_and_kwarg(self, testdir): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail("True", reason="some bug")((1, 3)), - (2, 3), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2, skipped=1) - - @pytest.mark.parametrize("strict", [True, False]) - def test_xfail_passing_is_xpass(self, testdir, strict): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - (1, 2), - pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict})((2, 3)), - (3, 4), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """.format( - strict=strict - ) - testdir.makepyfile(s) - reprec = testdir.inline_run() - passed, failed = (2, 1) if strict else (3, 0) - reprec.assertoutcome(passed=passed, failed=failed) - - def test_parametrize_called_in_generate_tests(self, testdir): - s = """ - import pytest - - - def pytest_generate_tests(metafunc): - passingTestData = [(1, 2), - (2, 3)] - failingTestData = [(1, 3), - (2, 2)] - - testData = passingTestData + [pytest.mark.xfail(d) - for d in failingTestData] - metafunc.parametrize(("n", "expected"), testData) - - - def test_increment(n, expected): - assert n + 1 == expected - """ - testdir.makepyfile(s) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2, skipped=2) - - @pytest.mark.issue290 - def test_parametrize_ID_generation_string_int_works(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def myfixture(): - return 'example' - @pytest.mark.parametrize( - 'limit', (0, '0')) - def test_limit(limit, myfixture): - return - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=2) - - @pytest.mark.parametrize("strict", [True, False]) - def test_parametrize_marked_value(self, testdir, strict): - s = """ - import pytest - - @pytest.mark.parametrize(("n", "expected"), [ - pytest.param( - 2,3, - marks=pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict}), - ), - pytest.param( - 2,3, - marks=[pytest.mark.xfail("sys.version_info > (0, 0, 0)", reason="some bug", strict={strict})], - ), - ]) - def test_increment(n, expected): - assert n + 1 == expected - """.format( - strict=strict - ) - testdir.makepyfile(s) - reprec = testdir.inline_run() - passed, failed = (0, 2) if strict else (2, 0) - reprec.assertoutcome(passed=passed, failed=failed) - - def test_pytest_make_parametrize_id(self, testdir): - testdir.makeconftest( - """ - def pytest_make_parametrize_id(config, val): - return str(val * 2) - """ - ) - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize("x", range(2)) - def test_func(x): - pass - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*test_func*0*PASS*", "*test_func*2*PASS*"]) - - def test_pytest_make_parametrize_id_with_argname(self, testdir): - testdir.makeconftest( - """ - def pytest_make_parametrize_id(config, val, argname): - return str(val * 2 if argname == 'x' else val * 10) - """ - ) - testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize("x", range(2)) - def test_func_a(x): - pass - - @pytest.mark.parametrize("y", [1]) - def test_func_b(y): - pass - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - ["*test_func_a*0*PASS*", "*test_func_a*2*PASS*", "*test_func_b*10*PASS*"] - ) diff --git a/third_party/python/pytest/testing/python/raises.py b/third_party/python/pytest/testing/python/raises.py deleted file mode 100644 index 64199c3b6f5f..000000000000 --- a/third_party/python/pytest/testing/python/raises.py +++ /dev/null @@ -1,177 +0,0 @@ -from _pytest.outcomes import Failed -import pytest -import sys - - -class TestRaises(object): - - def test_raises(self): - source = "int('qwe')" - excinfo = pytest.raises(ValueError, source) - code = excinfo.traceback[-1].frame.code - s = str(code.fullsource) - assert s == source - - def test_raises_exec(self): - pytest.raises(ValueError, "a,x = []") - - def test_raises_syntax_error(self): - pytest.raises(SyntaxError, "qwe qwe qwe") - - def test_raises_function(self): - pytest.raises(ValueError, int, "hello") - - def test_raises_callable_no_exception(self): - - class A(object): - - def __call__(self): - pass - - try: - pytest.raises(ValueError, A()) - except pytest.raises.Exception: - pass - - def test_raises_as_contextmanager(self, testdir): - testdir.makepyfile( - """ - from __future__ import with_statement - import py, pytest - import _pytest._code - - def test_simple(): - with pytest.raises(ZeroDivisionError) as excinfo: - assert isinstance(excinfo, _pytest._code.ExceptionInfo) - 1/0 - print (excinfo) - assert excinfo.type == ZeroDivisionError - assert isinstance(excinfo.value, ZeroDivisionError) - - def test_noraise(): - with pytest.raises(pytest.raises.Exception): - with pytest.raises(ValueError): - int() - - def test_raise_wrong_exception_passes_by(): - with pytest.raises(ZeroDivisionError): - with pytest.raises(ValueError): - 1/0 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*3 passed*"]) - - def test_noclass(self): - with pytest.raises(TypeError): - pytest.raises("wrong", lambda: None) - - def test_invalid_arguments_to_raises(self): - with pytest.raises(TypeError, match="unknown"): - with pytest.raises(TypeError, unknown="bogus"): - raise ValueError() - - def test_tuple(self): - with pytest.raises((KeyError, ValueError)): - raise KeyError("oops") - - def test_no_raise_message(self): - try: - pytest.raises(ValueError, int, "0") - except pytest.raises.Exception as e: - assert e.msg == "DID NOT RAISE {}".format(repr(ValueError)) - else: - assert False, "Expected pytest.raises.Exception" - - try: - with pytest.raises(ValueError): - pass - except pytest.raises.Exception as e: - assert e.msg == "DID NOT RAISE {}".format(repr(ValueError)) - else: - assert False, "Expected pytest.raises.Exception" - - def test_custom_raise_message(self): - message = "TEST_MESSAGE" - try: - with pytest.raises(ValueError, message=message): - pass - except pytest.raises.Exception as e: - assert e.msg == message - else: - assert False, "Expected pytest.raises.Exception" - - @pytest.mark.parametrize("method", ["function", "with"]) - def test_raises_cyclic_reference(self, method): - """ - Ensure pytest.raises does not leave a reference cycle (#1965). - """ - import gc - - class T(object): - - def __call__(self): - raise ValueError - - t = T() - if method == "function": - pytest.raises(ValueError, t) - else: - with pytest.raises(ValueError): - t() - - # ensure both forms of pytest.raises don't leave exceptions in sys.exc_info() - assert sys.exc_info() == (None, None, None) - - del t - - # ensure the t instance is not stuck in a cyclic reference - for o in gc.get_objects(): - assert type(o) is not T - - def test_raises_match(self): - msg = r"with base \d+" - with pytest.raises(ValueError, match=msg): - int("asdf") - - msg = "with base 10" - with pytest.raises(ValueError, match=msg): - int("asdf") - - msg = "with base 16" - expr = r"Pattern '{}' not found in 'invalid literal for int\(\) with base 10: 'asdf''".format( - msg - ) - with pytest.raises(AssertionError, match=expr): - with pytest.raises(ValueError, match=msg): - int("asdf", base=10) - - def test_raises_match_wrong_type(self): - """Raising an exception with the wrong type and match= given. - - pytest should throw the unexpected exception - the pattern match is not - really relevant if we got a different exception. - """ - with pytest.raises(ValueError): - with pytest.raises(IndexError, match="nomatch"): - int("asdf") - - def test_raises_exception_looks_iterable(self): - from six import add_metaclass - - class Meta(type(object)): - - def __getitem__(self, item): - return 1 / 0 - - def __len__(self): - return 1 - - @add_metaclass(Meta) - class ClassLooksIterableException(Exception): - pass - - with pytest.raises( - Failed, match="DID NOT RAISE " - ): - pytest.raises(ClassLooksIterableException, lambda: None) diff --git a/third_party/python/pytest/testing/python/setup_only.py b/third_party/python/pytest/testing/python/setup_only.py deleted file mode 100644 index 4ae24b15a6da..000000000000 --- a/third_party/python/pytest/testing/python/setup_only.py +++ /dev/null @@ -1,269 +0,0 @@ -import pytest - - -@pytest.fixture(params=["--setup-only", "--setup-plan", "--setup-show"], scope="module") -def mode(request): - return request.param - - -def test_show_only_active_fixtures(testdir, mode): - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def _arg0(): - """hidden arg0 fixture""" - @pytest.fixture - def arg1(): - """arg1 docstring""" - def test_arg1(arg1): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - ["*SETUP F arg1*", "*test_arg1 (fixtures used: arg1)*", "*TEARDOWN F arg1*"] - ) - assert "_arg0" not in result.stdout.str() - - -def test_show_different_scopes(testdir, mode): - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def arg_function(): - """function scoped fixture""" - @pytest.fixture(scope='session') - def arg_session(): - """session scoped fixture""" - def test_arg1(arg_session, arg_function): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "SETUP S arg_session*", - "*SETUP F arg_function*", - "*test_arg1 (fixtures used: arg_function, arg_session)*", - "*TEARDOWN F arg_function*", - "TEARDOWN S arg_session*", - ] - ) - - -def test_show_nested_fixtures(testdir, mode): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture(scope='session') - def arg_same(): - """session scoped fixture""" - ''' - ) - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture(scope='function') - def arg_same(arg_same): - """function scoped fixture""" - def test_arg1(arg_same): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "SETUP S arg_same*", - "*SETUP F arg_same (fixtures used: arg_same)*", - "*test_arg1 (fixtures used: arg_same)*", - "*TEARDOWN F arg_same*", - "TEARDOWN S arg_same*", - ] - ) - - -def test_show_fixtures_with_autouse(testdir, mode): - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def arg_function(): - """function scoped fixture""" - @pytest.fixture(scope='session', autouse=True) - def arg_session(): - """session scoped fixture""" - def test_arg1(arg_function): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "SETUP S arg_session*", - "*SETUP F arg_function*", - "*test_arg1 (fixtures used: arg_function, arg_session)*", - ] - ) - - -def test_show_fixtures_with_parameters(testdir, mode): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture(scope='session', params=['foo', 'bar']) - def arg_same(): - """session scoped fixture""" - ''' - ) - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture(scope='function') - def arg_other(arg_same): - """function scoped fixture""" - def test_arg1(arg_other): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "SETUP S arg_same?foo?", - "TEARDOWN S arg_same?foo?", - "SETUP S arg_same?bar?", - "TEARDOWN S arg_same?bar?", - ] - ) - - -def test_show_fixtures_with_parameter_ids(testdir, mode): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture( - scope='session', params=['foo', 'bar'], ids=['spam', 'ham']) - def arg_same(): - """session scoped fixture""" - ''' - ) - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture(scope='function') - def arg_other(arg_same): - """function scoped fixture""" - def test_arg1(arg_other): - pass - ''' - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - ["SETUP S arg_same?spam?", "SETUP S arg_same?ham?"] - ) - - -def test_show_fixtures_with_parameter_ids_function(testdir, mode): - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture(params=['foo', 'bar'], ids=lambda p: p.upper()) - def foobar(): - pass - def test_foobar(foobar): - pass - """ - ) - - result = testdir.runpytest(mode, p) - assert result.ret == 0 - - result.stdout.fnmatch_lines(["*SETUP F foobar?FOO?", "*SETUP F foobar?BAR?"]) - - -def test_dynamic_fixture_request(testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture() - def dynamically_requested_fixture(): - pass - @pytest.fixture() - def dependent_fixture(request): - request.getfixturevalue('dynamically_requested_fixture') - def test_dyn(dependent_fixture): - pass - """ - ) - - result = testdir.runpytest("--setup-only", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "*SETUP F dynamically_requested_fixture", - "*TEARDOWN F dynamically_requested_fixture", - ] - ) - - -def test_capturing(testdir): - p = testdir.makepyfile( - """ - import pytest, sys - @pytest.fixture() - def one(): - sys.stdout.write('this should be captured') - sys.stderr.write('this should also be captured') - @pytest.fixture() - def two(one): - assert 0 - def test_capturing(two): - pass - """ - ) - - result = testdir.runpytest("--setup-only", p) - result.stdout.fnmatch_lines( - ["this should be captured", "this should also be captured"] - ) - - -def test_show_fixtures_and_execute_test(testdir): - """ Verifies that setups are shown and tests are executed. """ - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture - def arg(): - assert True - def test_arg(arg): - assert False - """ - ) - - result = testdir.runpytest("--setup-show", p) - assert result.ret == 1 - - result.stdout.fnmatch_lines( - ["*SETUP F arg*", "*test_arg (fixtures used: arg)F*", "*TEARDOWN F arg*"] - ) diff --git a/third_party/python/pytest/testing/python/setup_plan.py b/third_party/python/pytest/testing/python/setup_plan.py deleted file mode 100644 index 0321939a8aac..000000000000 --- a/third_party/python/pytest/testing/python/setup_plan.py +++ /dev/null @@ -1,19 +0,0 @@ -def test_show_fixtures_and_test(testdir): - """ Verifies that fixtures are not executed. """ - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture - def arg(): - assert False - def test_arg(arg): - assert False - """ - ) - - result = testdir.runpytest("--setup-plan", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - ["*SETUP F arg*", "*test_arg (fixtures used: arg)", "*TEARDOWN F arg*"] - ) diff --git a/third_party/python/pytest/testing/python/show_fixtures_per_test.py b/third_party/python/pytest/testing/python/show_fixtures_per_test.py deleted file mode 100644 index e14344d4ebf7..000000000000 --- a/third_party/python/pytest/testing/python/show_fixtures_per_test.py +++ /dev/null @@ -1,183 +0,0 @@ -# -*- coding: utf-8 -*- - - -def test_no_items_should_not_show_output(testdir): - result = testdir.runpytest("--fixtures-per-test") - assert "fixtures used by" not in result.stdout.str() - assert result.ret == 0 - - -def test_fixtures_in_module(testdir): - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def _arg0(): - """hidden arg0 fixture""" - @pytest.fixture - def arg1(): - """arg1 docstring""" - def test_arg1(arg1): - pass - ''' - ) - - result = testdir.runpytest("--fixtures-per-test", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "*fixtures used by test_arg1*", - "*(test_fixtures_in_module.py:9)*", - "arg1", - " arg1 docstring", - ] - ) - assert "_arg0" not in result.stdout.str() - - -def test_fixtures_in_conftest(testdir): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture - def arg1(): - """arg1 docstring""" - @pytest.fixture - def arg2(): - """arg2 docstring""" - @pytest.fixture - def arg3(arg1, arg2): - """arg3 - docstring - """ - ''' - ) - p = testdir.makepyfile( - """ - def test_arg2(arg2): - pass - def test_arg3(arg3): - pass - """ - ) - result = testdir.runpytest("--fixtures-per-test", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "*fixtures used by test_arg2*", - "*(test_fixtures_in_conftest.py:2)*", - "arg2", - " arg2 docstring", - "*fixtures used by test_arg3*", - "*(test_fixtures_in_conftest.py:4)*", - "arg1", - " arg1 docstring", - "arg2", - " arg2 docstring", - "arg3", - " arg3", - " docstring", - ] - ) - - -def test_should_show_fixtures_used_by_test(testdir): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture - def arg1(): - """arg1 from conftest""" - @pytest.fixture - def arg2(): - """arg2 from conftest""" - ''' - ) - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def arg1(): - """arg1 from testmodule""" - def test_args(arg1, arg2): - pass - ''' - ) - result = testdir.runpytest("--fixtures-per-test", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "*fixtures used by test_args*", - "*(test_should_show_fixtures_used_by_test.py:6)*", - "arg1", - " arg1 from testmodule", - "arg2", - " arg2 from conftest", - ] - ) - - -def test_verbose_include_private_fixtures_and_loc(testdir): - testdir.makeconftest( - ''' - import pytest - @pytest.fixture - def _arg1(): - """_arg1 from conftest""" - @pytest.fixture - def arg2(_arg1): - """arg2 from conftest""" - ''' - ) - p = testdir.makepyfile( - ''' - import pytest - @pytest.fixture - def arg3(): - """arg3 from testmodule""" - def test_args(arg2, arg3): - pass - ''' - ) - result = testdir.runpytest("--fixtures-per-test", "-v", p) - assert result.ret == 0 - - result.stdout.fnmatch_lines( - [ - "*fixtures used by test_args*", - "*(test_verbose_include_private_fixtures_and_loc.py:6)*", - "_arg1 -- conftest.py:3", - " _arg1 from conftest", - "arg2 -- conftest.py:6", - " arg2 from conftest", - "arg3 -- test_verbose_include_private_fixtures_and_loc.py:3", - " arg3 from testmodule", - ] - ) - - -def test_doctest_items(testdir): - testdir.makepyfile( - ''' - def foo(): - """ - >>> 1 + 1 - 2 - """ - ''' - ) - testdir.maketxtfile( - """ - >>> 1 + 1 - 2 - """ - ) - result = testdir.runpytest( - "--fixtures-per-test", "--doctest-modules", "--doctest-glob=*.txt", "-v" - ) - assert result.ret == 0 - - result.stdout.fnmatch_lines(["*collected 2 items*"]) diff --git a/third_party/python/pytest/testing/python/test_deprecations.py b/third_party/python/pytest/testing/python/test_deprecations.py deleted file mode 100644 index b0c11f0b03b4..000000000000 --- a/third_party/python/pytest/testing/python/test_deprecations.py +++ /dev/null @@ -1,22 +0,0 @@ -import pytest - -from _pytest.python import PyCollector - - -class PyCollectorMock(PyCollector): - """evil hack""" - - def __init__(self): - self.called = False - - def _makeitem(self, *k): - """hack to disable the actual behaviour""" - self.called = True - - -def test_pycollector_makeitem_is_deprecated(): - - collector = PyCollectorMock() - with pytest.deprecated_call(): - collector.makeitem("foo", "bar") - assert collector.called diff --git a/third_party/python/pytest/testing/test_argcomplete.py b/third_party/python/pytest/testing/test_argcomplete.py deleted file mode 100644 index b042de5ce5be..000000000000 --- a/third_party/python/pytest/testing/test_argcomplete.py +++ /dev/null @@ -1,109 +0,0 @@ -from __future__ import absolute_import, division, print_function -import subprocess -import sys -import pytest - -# test for _argcomplete but not specific for any application - - -def equal_with_bash(prefix, ffc, fc, out=None): - res = ffc(prefix) - res_bash = set(fc(prefix)) - retval = set(res) == res_bash - if out: - out.write("equal_with_bash %s %s\n" % (retval, res)) - if not retval: - out.write(" python - bash: %s\n" % (set(res) - res_bash)) - out.write(" bash - python: %s\n" % (res_bash - set(res))) - return retval - - -# copied from argcomplete.completers as import from there -# also pulls in argcomplete.__init__ which opens filedescriptor 9 -# this gives an IOError at the end of testrun - - -def _wrapcall(*args, **kargs): - try: - if sys.version_info > (2, 7): - return subprocess.check_output(*args, **kargs).decode().splitlines() - if "stdout" in kargs: - raise ValueError("stdout argument not allowed, it will be overridden.") - process = subprocess.Popen(stdout=subprocess.PIPE, *args, **kargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kargs.get("args") - if cmd is None: - cmd = args[0] - raise subprocess.CalledProcessError(retcode, cmd) - return output.decode().splitlines() - except subprocess.CalledProcessError: - return [] - - -class FilesCompleter(object): - "File completer class, optionally takes a list of allowed extensions" - - def __init__(self, allowednames=(), directories=True): - # Fix if someone passes in a string instead of a list - if type(allowednames) is str: - allowednames = [allowednames] - - self.allowednames = [x.lstrip("*").lstrip(".") for x in allowednames] - self.directories = directories - - def __call__(self, prefix, **kwargs): - completion = [] - if self.allowednames: - if self.directories: - files = _wrapcall( - ["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)] - ) - completion += [f + "/" for f in files] - for x in self.allowednames: - completion += _wrapcall( - [ - "bash", - "-c", - "compgen -A file -X '!*.{0}' -- '{p}'".format(x, p=prefix), - ] - ) - else: - completion += _wrapcall( - ["bash", "-c", "compgen -A file -- '{p}'".format(p=prefix)] - ) - - anticomp = _wrapcall( - ["bash", "-c", "compgen -A directory -- '{p}'".format(p=prefix)] - ) - - completion = list(set(completion) - set(anticomp)) - - if self.directories: - completion += [f + "/" for f in anticomp] - return completion - - -class TestArgComplete(object): - - @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") - def test_compare_with_compgen(self): - from _pytest._argcomplete import FastFilesCompleter - - ffc = FastFilesCompleter() - fc = FilesCompleter() - for x in ["/", "/d", "/data", "qqq", ""]: - assert equal_with_bash(x, ffc, fc, out=sys.stdout) - - @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") - def test_remove_dir_prefix(self): - """this is not compatible with compgen but it is with bash itself: - ls /usr/ - """ - from _pytest._argcomplete import FastFilesCompleter - - ffc = FastFilesCompleter() - fc = FilesCompleter() - for x in "/usr/".split(): - assert not equal_with_bash(x, ffc, fc, out=sys.stdout) diff --git a/third_party/python/pytest/testing/test_assertion.py b/third_party/python/pytest/testing/test_assertion.py deleted file mode 100644 index 393cf817c7e9..000000000000 --- a/third_party/python/pytest/testing/test_assertion.py +++ /dev/null @@ -1,1172 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function -import sys -import textwrap - -import _pytest.assertion as plugin -import py -import pytest -from _pytest.assertion import util -from _pytest.assertion import truncate - -PY3 = sys.version_info >= (3, 0) - - -@pytest.fixture -def mock_config(): - - class Config(object): - verbose = False - - def getoption(self, name): - if name == "verbose": - return self.verbose - raise KeyError("Not mocked out: %s" % name) - - return Config() - - -class TestImportHookInstallation(object): - - @pytest.mark.parametrize("initial_conftest", [True, False]) - @pytest.mark.parametrize("mode", ["plain", "rewrite"]) - def test_conftest_assertion_rewrite(self, testdir, initial_conftest, mode): - """Test that conftest files are using assertion rewrite on import. - (#1619) - """ - testdir.tmpdir.join("foo/tests").ensure(dir=1) - conftest_path = "conftest.py" if initial_conftest else "foo/conftest.py" - contents = { - conftest_path: """ - import pytest - @pytest.fixture - def check_first(): - def check(values, value): - assert values.pop(0) == value - return check - """, - "foo/tests/test_foo.py": """ - def test(check_first): - check_first([10, 30], 30) - """, - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess("--assert=%s" % mode) - if mode == "plain": - expected = "E AssertionError" - elif mode == "rewrite": - expected = "*assert 10 == 30*" - else: - assert 0 - result.stdout.fnmatch_lines([expected]) - - def test_rewrite_assertions_pytester_plugin(self, testdir): - """ - Assertions in the pytester plugin must also benefit from assertion - rewriting (#1920). - """ - testdir.makepyfile( - """ - pytest_plugins = ['pytester'] - def test_dummy_failure(testdir): # how meta! - testdir.makepyfile('def test(): assert 0') - r = testdir.inline_run() - r.assertoutcome(passed=1) - """ - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*assert 1 == 0*"]) - - @pytest.mark.parametrize("mode", ["plain", "rewrite"]) - def test_pytest_plugins_rewrite(self, testdir, mode): - contents = { - "conftest.py": """ - pytest_plugins = ['ham'] - """, - "ham.py": """ - import pytest - @pytest.fixture - def check_first(): - def check(values, value): - assert values.pop(0) == value - return check - """, - "test_foo.py": """ - def test_foo(check_first): - check_first([10, 30], 30) - """, - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess("--assert=%s" % mode) - if mode == "plain": - expected = "E AssertionError" - elif mode == "rewrite": - expected = "*assert 10 == 30*" - else: - assert 0 - result.stdout.fnmatch_lines([expected]) - - @pytest.mark.parametrize("mode", ["str", "list"]) - def test_pytest_plugins_rewrite_module_names(self, testdir, mode): - """Test that pluginmanager correct marks pytest_plugins variables - for assertion rewriting if they are defined as plain strings or - list of strings (#1888). - """ - plugins = '"ham"' if mode == "str" else '["ham"]' - contents = { - "conftest.py": """ - pytest_plugins = {plugins} - """.format( - plugins=plugins - ), - "ham.py": """ - import pytest - """, - "test_foo.py": """ - def test_foo(pytestconfig): - assert 'ham' in pytestconfig.pluginmanager.rewrite_hook._must_rewrite - """, - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess("--assert=rewrite") - assert result.ret == 0 - - def test_pytest_plugins_rewrite_module_names_correctly(self, testdir): - """Test that we match files correctly when they are marked for rewriting (#2939).""" - contents = { - "conftest.py": """ - pytest_plugins = "ham" - """, - "ham.py": "", - "hamster.py": "", - "test_foo.py": """ - def test_foo(pytestconfig): - assert pytestconfig.pluginmanager.rewrite_hook.find_module('ham') is not None - assert pytestconfig.pluginmanager.rewrite_hook.find_module('hamster') is None - """, - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess("--assert=rewrite") - assert result.ret == 0 - - @pytest.mark.parametrize("mode", ["plain", "rewrite"]) - @pytest.mark.parametrize("plugin_state", ["development", "installed"]) - def test_installed_plugin_rewrite(self, testdir, mode, plugin_state): - # Make sure the hook is installed early enough so that plugins - # installed via setuptools are rewritten. - testdir.tmpdir.join("hampkg").ensure(dir=1) - contents = { - "hampkg/__init__.py": """ - import pytest - - @pytest.fixture - def check_first2(): - def check(values, value): - assert values.pop(0) == value - return check - """, - "spamplugin.py": """ - import pytest - from hampkg import check_first2 - - @pytest.fixture - def check_first(): - def check(values, value): - assert values.pop(0) == value - return check - """, - "mainwrapper.py": """ - import pytest, pkg_resources - - plugin_state = "{plugin_state}" - - class DummyDistInfo(object): - project_name = 'spam' - version = '1.0' - - def _get_metadata(self, name): - # 'RECORD' meta-data only available in installed plugins - if name == 'RECORD' and plugin_state == "installed": - return ['spamplugin.py,sha256=abc,123', - 'hampkg/__init__.py,sha256=abc,123'] - # 'SOURCES.txt' meta-data only available for plugins in development mode - elif name == 'SOURCES.txt' and plugin_state == "development": - return ['spamplugin.py', - 'hampkg/__init__.py'] - return [] - - class DummyEntryPoint(object): - name = 'spam' - module_name = 'spam.py' - attrs = () - extras = None - dist = DummyDistInfo() - - def load(self, require=True, *args, **kwargs): - import spamplugin - return spamplugin - - def iter_entry_points(name): - yield DummyEntryPoint() - - pkg_resources.iter_entry_points = iter_entry_points - pytest.main() - """.format( - plugin_state=plugin_state - ), - "test_foo.py": """ - def test(check_first): - check_first([10, 30], 30) - - def test2(check_first2): - check_first([10, 30], 30) - """, - } - testdir.makepyfile(**contents) - result = testdir.run( - sys.executable, "mainwrapper.py", "-s", "--assert=%s" % mode - ) - if mode == "plain": - expected = "E AssertionError" - elif mode == "rewrite": - expected = "*assert 10 == 30*" - else: - assert 0 - result.stdout.fnmatch_lines([expected]) - - def test_rewrite_ast(self, testdir): - testdir.tmpdir.join("pkg").ensure(dir=1) - contents = { - "pkg/__init__.py": """ - import pytest - pytest.register_assert_rewrite('pkg.helper') - """, - "pkg/helper.py": """ - def tool(): - a, b = 2, 3 - assert a == b - """, - "pkg/plugin.py": """ - import pytest, pkg.helper - @pytest.fixture - def tool(): - return pkg.helper.tool - """, - "pkg/other.py": """ - values = [3, 2] - def tool(): - assert values.pop() == 3 - """, - "conftest.py": """ - pytest_plugins = ['pkg.plugin'] - """, - "test_pkg.py": """ - import pkg.other - def test_tool(tool): - tool() - def test_other(): - pkg.other.tool() - """, - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess("--assert=rewrite") - result.stdout.fnmatch_lines( - [ - ">*assert a == b*", - "E*assert 2 == 3*", - ">*assert values.pop() == 3*", - "E*AssertionError", - ] - ) - - def test_register_assert_rewrite_checks_types(self): - with pytest.raises(TypeError): - pytest.register_assert_rewrite(["pytest_tests_internal_non_existing"]) - pytest.register_assert_rewrite( - "pytest_tests_internal_non_existing", "pytest_tests_internal_non_existing2" - ) - - -class TestBinReprIntegration(object): - - def test_pytest_assertrepr_compare_called(self, testdir): - testdir.makeconftest( - """ - import pytest - values = [] - def pytest_assertrepr_compare(op, left, right): - values.append((op, left, right)) - - @pytest.fixture - def list(request): - return values - """ - ) - testdir.makepyfile( - """ - def test_hello(): - assert 0 == 1 - def test_check(list): - assert list == [("==", 0, 1)] - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["*test_hello*FAIL*", "*test_check*PASS*"]) - - -def callequal(left, right, verbose=False): - config = mock_config() - config.verbose = verbose - return plugin.pytest_assertrepr_compare(config, "==", left, right) - - -class TestAssert_reprcompare(object): - - def test_different_types(self): - assert callequal([0, 1], "foo") is None - - def test_summary(self): - summary = callequal([0, 1], [0, 2])[0] - assert len(summary) < 65 - - def test_text_diff(self): - diff = callequal("spam", "eggs")[1:] - assert "- spam" in diff - assert "+ eggs" in diff - - def test_text_skipping(self): - lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs") - assert "Skipping" in lines[1] - for line in lines: - assert "a" * 50 not in line - - def test_text_skipping_verbose(self): - lines = callequal("a" * 50 + "spam", "a" * 50 + "eggs", verbose=True) - assert "- " + "a" * 50 + "spam" in lines - assert "+ " + "a" * 50 + "eggs" in lines - - def test_multiline_text_diff(self): - left = "foo\nspam\nbar" - right = "foo\neggs\nbar" - diff = callequal(left, right) - assert "- spam" in diff - assert "+ eggs" in diff - - def test_list(self): - expl = callequal([0, 1], [0, 2]) - assert len(expl) > 1 - - @pytest.mark.parametrize( - ["left", "right", "expected"], - [ - ( - [0, 1], - [0, 2], - """ - Full diff: - - [0, 1] - ? ^ - + [0, 2] - ? ^ - """, - ), - ( - {0: 1}, - {0: 2}, - """ - Full diff: - - {0: 1} - ? ^ - + {0: 2} - ? ^ - """, - ), - ( - {0, 1}, - {0, 2}, - """ - Full diff: - - set([0, 1]) - ? ^ - + set([0, 2]) - ? ^ - """ - if not PY3 - else """ - Full diff: - - {0, 1} - ? ^ - + {0, 2} - ? ^ - """, - ), - ], - ) - def test_iterable_full_diff(self, left, right, expected): - """Test the full diff assertion failure explanation. - - When verbose is False, then just a -v notice to get the diff is rendered, - when verbose is True, then ndiff of the pprint is returned. - """ - expl = callequal(left, right, verbose=False) - assert expl[-1] == "Use -v to get the full diff" - expl = "\n".join(callequal(left, right, verbose=True)) - assert expl.endswith(textwrap.dedent(expected).strip()) - - def test_list_different_lengths(self): - expl = callequal([0, 1], [0, 1, 2]) - assert len(expl) > 1 - expl = callequal([0, 1, 2], [0, 1]) - assert len(expl) > 1 - - def test_dict(self): - expl = callequal({"a": 0}, {"a": 1}) - assert len(expl) > 1 - - def test_dict_omitting(self): - lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1}) - assert lines[1].startswith("Omitting 1 identical item") - assert "Common items" not in lines - for line in lines[1:]: - assert "b" not in line - - def test_dict_omitting_with_verbosity_1(self): - """ Ensure differing items are visible for verbosity=1 (#1512) """ - lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1}, verbose=1) - assert lines[1].startswith("Omitting 1 identical item") - assert lines[2].startswith("Differing items") - assert lines[3] == "{'a': 0} != {'a': 1}" - assert "Common items" not in lines - - def test_dict_omitting_with_verbosity_2(self): - lines = callequal({"a": 0, "b": 1}, {"a": 1, "b": 1}, verbose=2) - assert lines[1].startswith("Common items:") - assert "Omitting" not in lines[1] - assert lines[2] == "{'b': 1}" - - def test_set(self): - expl = callequal({0, 1}, {0, 2}) - assert len(expl) > 1 - - def test_frozenzet(self): - expl = callequal(frozenset([0, 1]), {0, 2}) - assert len(expl) > 1 - - def test_Sequence(self): - col = py.builtin._tryimport("collections.abc", "collections", "sys") - if not hasattr(col, "MutableSequence"): - pytest.skip("cannot import MutableSequence") - MutableSequence = col.MutableSequence - - class TestSequence(MutableSequence): # works with a Sequence subclass - - def __init__(self, iterable): - self.elements = list(iterable) - - def __getitem__(self, item): - return self.elements[item] - - def __len__(self): - return len(self.elements) - - def __setitem__(self, item, value): - pass - - def __delitem__(self, item): - pass - - def insert(self, item, index): - pass - - expl = callequal(TestSequence([0, 1]), list([0, 2])) - assert len(expl) > 1 - - def test_list_tuples(self): - expl = callequal([], [(1, 2)]) - assert len(expl) > 1 - expl = callequal([(1, 2)], []) - assert len(expl) > 1 - - def test_list_bad_repr(self): - - class A(object): - - def __repr__(self): - raise ValueError(42) - - expl = callequal([], [A()]) - assert "ValueError" in "".join(expl) - expl = callequal({}, {"1": A()}) - assert "faulty" in "".join(expl) - - def test_one_repr_empty(self): - """ - the faulty empty string repr did trigger - an unbound local error in _diff_text - """ - - class A(str): - - def __repr__(self): - return "" - - expl = callequal(A(), "") - assert not expl - - def test_repr_no_exc(self): - expl = " ".join(callequal("foo", "bar")) - assert "raised in repr()" not in expl - - def test_unicode(self): - left = py.builtin._totext("£€", "utf-8") - right = py.builtin._totext("£", "utf-8") - expl = callequal(left, right) - assert expl[0] == py.builtin._totext("'£€' == '£'", "utf-8") - assert expl[1] == py.builtin._totext("- £€", "utf-8") - assert expl[2] == py.builtin._totext("+ £", "utf-8") - - def test_nonascii_text(self): - """ - :issue: 877 - non ascii python2 str caused a UnicodeDecodeError - """ - - class A(str): - - def __repr__(self): - return "\xff" - - expl = callequal(A(), "1") - assert expl - - def test_format_nonascii_explanation(self): - assert util.format_explanation("λ") - - def test_mojibake(self): - # issue 429 - left = "e" - right = "\xc3\xa9" - if not isinstance(left, bytes): - left = bytes(left, "utf-8") - right = bytes(right, "utf-8") - expl = callequal(left, right) - for line in expl: - assert isinstance(line, py.builtin.text) - msg = py.builtin._totext("\n").join(expl) - assert msg - - -class TestFormatExplanation(object): - - def test_special_chars_full(self, testdir): - # Issue 453, for the bug this would raise IndexError - testdir.makepyfile( - """ - def test_foo(): - assert '\\n}' == '' - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines(["*AssertionError*"]) - - def test_fmt_simple(self): - expl = "assert foo" - assert util.format_explanation(expl) == "assert foo" - - def test_fmt_where(self): - expl = "\n".join(["assert 1", "{1 = foo", "} == 2"]) - res = "\n".join(["assert 1 == 2", " + where 1 = foo"]) - assert util.format_explanation(expl) == res - - def test_fmt_and(self): - expl = "\n".join(["assert 1", "{1 = foo", "} == 2", "{2 = bar", "}"]) - res = "\n".join(["assert 1 == 2", " + where 1 = foo", " + and 2 = bar"]) - assert util.format_explanation(expl) == res - - def test_fmt_where_nested(self): - expl = "\n".join(["assert 1", "{1 = foo", "{foo = bar", "}", "} == 2"]) - res = "\n".join(["assert 1 == 2", " + where 1 = foo", " + where foo = bar"]) - assert util.format_explanation(expl) == res - - def test_fmt_newline(self): - expl = "\n".join(['assert "foo" == "bar"', "~- foo", "~+ bar"]) - res = "\n".join(['assert "foo" == "bar"', " - foo", " + bar"]) - assert util.format_explanation(expl) == res - - def test_fmt_newline_escaped(self): - expl = "\n".join(["assert foo == bar", "baz"]) - res = "assert foo == bar\\nbaz" - assert util.format_explanation(expl) == res - - def test_fmt_newline_before_where(self): - expl = "\n".join( - [ - "the assertion message here", - ">assert 1", - "{1 = foo", - "} == 2", - "{2 = bar", - "}", - ] - ) - res = "\n".join( - [ - "the assertion message here", - "assert 1 == 2", - " + where 1 = foo", - " + and 2 = bar", - ] - ) - assert util.format_explanation(expl) == res - - def test_fmt_multi_newline_before_where(self): - expl = "\n".join( - [ - "the assertion", - "~message here", - ">assert 1", - "{1 = foo", - "} == 2", - "{2 = bar", - "}", - ] - ) - res = "\n".join( - [ - "the assertion", - " message here", - "assert 1 == 2", - " + where 1 = foo", - " + and 2 = bar", - ] - ) - assert util.format_explanation(expl) == res - - -class TestTruncateExplanation(object): - - """ Confirm assertion output is truncated as expected """ - - # The number of lines in the truncation explanation message. Used - # to calculate that results have the expected length. - LINES_IN_TRUNCATION_MSG = 2 - - def test_doesnt_truncate_when_input_is_empty_list(self): - expl = [] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) - assert result == expl - - def test_doesnt_truncate_at_when_input_is_5_lines_and_LT_max_chars(self): - expl = ["a" * 100 for x in range(5)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) - assert result == expl - - def test_truncates_at_8_lines_when_given_list_of_empty_strings(self): - expl = ["" for x in range(50)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) - assert result != expl - assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG - assert "Full output truncated" in result[-1] - assert "43 lines hidden" in result[-1] - last_line_before_trunc_msg = result[-self.LINES_IN_TRUNCATION_MSG - 1] - assert last_line_before_trunc_msg.endswith("...") - - def test_truncates_at_8_lines_when_first_8_lines_are_LT_max_chars(self): - expl = ["a" for x in range(100)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) - assert result != expl - assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG - assert "Full output truncated" in result[-1] - assert "93 lines hidden" in result[-1] - last_line_before_trunc_msg = result[-self.LINES_IN_TRUNCATION_MSG - 1] - assert last_line_before_trunc_msg.endswith("...") - - def test_truncates_at_8_lines_when_first_8_lines_are_EQ_max_chars(self): - expl = ["a" * 80 for x in range(16)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=8 * 80) - assert result != expl - assert len(result) == 8 + self.LINES_IN_TRUNCATION_MSG - assert "Full output truncated" in result[-1] - assert "9 lines hidden" in result[-1] - last_line_before_trunc_msg = result[-self.LINES_IN_TRUNCATION_MSG - 1] - assert last_line_before_trunc_msg.endswith("...") - - def test_truncates_at_4_lines_when_first_4_lines_are_GT_max_chars(self): - expl = ["a" * 250 for x in range(10)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=999) - assert result != expl - assert len(result) == 4 + self.LINES_IN_TRUNCATION_MSG - assert "Full output truncated" in result[-1] - assert "7 lines hidden" in result[-1] - last_line_before_trunc_msg = result[-self.LINES_IN_TRUNCATION_MSG - 1] - assert last_line_before_trunc_msg.endswith("...") - - def test_truncates_at_1_line_when_first_line_is_GT_max_chars(self): - expl = ["a" * 250 for x in range(1000)] - result = truncate._truncate_explanation(expl, max_lines=8, max_chars=100) - assert result != expl - assert len(result) == 1 + self.LINES_IN_TRUNCATION_MSG - assert "Full output truncated" in result[-1] - assert "1000 lines hidden" in result[-1] - last_line_before_trunc_msg = result[-self.LINES_IN_TRUNCATION_MSG - 1] - assert last_line_before_trunc_msg.endswith("...") - - def test_full_output_truncated(self, monkeypatch, testdir): - """ Test against full runpytest() output. """ - - line_count = 7 - line_len = 100 - expected_truncated_lines = 2 - testdir.makepyfile( - r""" - def test_many_lines(): - a = list([str(i)[0] * %d for i in range(%d)]) - b = a[::2] - a = '\n'.join(map(str, a)) - b = '\n'.join(map(str, b)) - assert a == b - """ - % (line_len, line_count) - ) - monkeypatch.delenv("CI", raising=False) - - result = testdir.runpytest() - # without -vv, truncate the message showing a few diff lines only - result.stdout.fnmatch_lines( - [ - "*- 1*", - "*- 3*", - "*- 5*", - "*truncated (%d lines hidden)*use*-vv*" % expected_truncated_lines, - ] - ) - - result = testdir.runpytest("-vv") - result.stdout.fnmatch_lines(["* 6*"]) - - monkeypatch.setenv("CI", "1") - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 6*"]) - - -def test_python25_compile_issue257(testdir): - testdir.makepyfile( - """ - def test_rewritten(): - assert 1 == 2 - # some comment - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines( - """ - *E*assert 1 == 2* - *1 failed* - """ - ) - - -def test_rewritten(testdir): - testdir.makepyfile( - """ - def test_rewritten(): - assert "@py_builtins" in globals() - """ - ) - assert testdir.runpytest().ret == 0 - - -def test_reprcompare_notin(mock_config): - detail = plugin.pytest_assertrepr_compare( - mock_config, "not in", "foo", "aaafoobbb" - )[ - 1: - ] - assert detail == ["'foo' is contained here:", " aaafoobbb", "? +++"] - - -def test_reprcompare_whitespaces(mock_config): - detail = plugin.pytest_assertrepr_compare(mock_config, "==", "\r\n", "\n") - assert ( - detail - == [ - r"'\r\n' == '\n'", - r"Strings contain only whitespace, escaping them using repr()", - r"- '\r\n'", - r"? --", - r"+ '\n'", - ] - ) - - -def test_pytest_assertrepr_compare_integration(testdir): - testdir.makepyfile( - """ - def test_hello(): - x = set(range(100)) - y = x.copy() - y.remove(50) - assert x == y - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*def test_hello():*", "*assert x == y*", "*E*Extra items*left*", "*E*50*"] - ) - - -def test_sequence_comparison_uses_repr(testdir): - testdir.makepyfile( - """ - def test_hello(): - x = set("hello x") - y = set("hello y") - assert x == y - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*def test_hello():*", - "*assert x == y*", - "*E*Extra items*left*", - "*E*'x'*", - "*E*Extra items*right*", - "*E*'y'*", - ] - ) - - -def test_assertrepr_loaded_per_dir(testdir): - testdir.makepyfile(test_base=["def test_base(): assert 1 == 2"]) - a = testdir.mkdir("a") - a_test = a.join("test_a.py") - a_test.write("def test_a(): assert 1 == 2") - a_conftest = a.join("conftest.py") - a_conftest.write('def pytest_assertrepr_compare(): return ["summary a"]') - b = testdir.mkdir("b") - b_test = b.join("test_b.py") - b_test.write("def test_b(): assert 1 == 2") - b_conftest = b.join("conftest.py") - b_conftest.write('def pytest_assertrepr_compare(): return ["summary b"]') - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*def test_base():*", - "*E*assert 1 == 2*", - "*def test_a():*", - "*E*assert summary a*", - "*def test_b():*", - "*E*assert summary b*", - ] - ) - - -def test_assertion_options(testdir): - testdir.makepyfile( - """ - def test_hello(): - x = 3 - assert x == 4 - """ - ) - result = testdir.runpytest() - assert "3 == 4" in result.stdout.str() - result = testdir.runpytest_subprocess("--assert=plain") - assert "3 == 4" not in result.stdout.str() - - -def test_triple_quoted_string_issue113(testdir): - testdir.makepyfile( - """ - def test_hello(): - assert "" == ''' - '''""" - ) - result = testdir.runpytest("--fulltrace") - result.stdout.fnmatch_lines(["*1 failed*"]) - assert "SyntaxError" not in result.stdout.str() - - -def test_traceback_failure(testdir): - p1 = testdir.makepyfile( - """ - def g(): - return 2 - def f(x): - assert x == g() - def test_onefails(): - f(3) - """ - ) - result = testdir.runpytest(p1, "--tb=long") - result.stdout.fnmatch_lines( - [ - "*test_traceback_failure.py F*", - "====* FAILURES *====", - "____*____", - "", - " def test_onefails():", - "> f(3)", - "", - "*test_*.py:6: ", - "_ _ _ *", - # "", - " def f(x):", - "> assert x == g()", - "E assert 3 == 2", - "E + where 2 = g()", - "", - "*test_traceback_failure.py:4: AssertionError", - ] - ) - - result = testdir.runpytest(p1) # "auto" - result.stdout.fnmatch_lines( - [ - "*test_traceback_failure.py F*", - "====* FAILURES *====", - "____*____", - "", - " def test_onefails():", - "> f(3)", - "", - "*test_*.py:6: ", - "", - " def f(x):", - "> assert x == g()", - "E assert 3 == 2", - "E + where 2 = g()", - "", - "*test_traceback_failure.py:4: AssertionError", - ] - ) - - -@pytest.mark.skipif( - sys.version_info[:2] <= (3, 3), - reason="Python 3.4+ shows chained exceptions on multiprocess", -) -def test_exception_handling_no_traceback(testdir): - """ - Handle chain exceptions in tasks submitted by the multiprocess module (#1984). - """ - p1 = testdir.makepyfile( - """ - from multiprocessing import Pool - - def process_task(n): - assert n == 10 - - def multitask_job(): - tasks = [1] - with Pool(processes=1) as pool: - pool.map(process_task, tasks) - - def test_multitask_job(): - multitask_job() - """ - ) - result = testdir.runpytest(p1, "--tb=long") - result.stdout.fnmatch_lines( - [ - "====* FAILURES *====", - "*multiprocessing.pool.RemoteTraceback:*", - "Traceback (most recent call last):", - "*assert n == 10", - "The above exception was the direct cause of the following exception:", - "> * multitask_job()", - ] - ) - - -@pytest.mark.skipif( - "'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')" -) -def test_warn_missing(testdir): - testdir.makepyfile("") - result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h") - result.stderr.fnmatch_lines(["*WARNING*assert statements are not executed*"]) - result = testdir.run(sys.executable, "-OO", "-m", "pytest") - result.stderr.fnmatch_lines(["*WARNING*assert statements are not executed*"]) - - -def test_recursion_source_decode(testdir): - testdir.makepyfile( - """ - def test_something(): - pass - """ - ) - testdir.makeini( - """ - [pytest] - python_files = *.py - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines( - """ - - """ - ) - - -def test_AssertionError_message(testdir): - testdir.makepyfile( - """ - def test_hello(): - x,y = 1,2 - assert 0, (x,y) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *def test_hello* - *assert 0, (x,y)* - *AssertionError: (1, 2)* - """ - ) - - -@pytest.mark.skipif(PY3, reason="This bug does not exist on PY3") -def test_set_with_unsortable_elements(): - # issue #718 - class UnsortableKey(object): - - def __init__(self, name): - self.name = name - - def __lt__(self, other): - raise RuntimeError() - - def __repr__(self): - return "repr({})".format(self.name) - - def __eq__(self, other): - return self.name == other.name - - def __hash__(self): - return hash(self.name) - - left_set = {UnsortableKey(str(i)) for i in range(1, 3)} - right_set = {UnsortableKey(str(i)) for i in range(2, 4)} - expl = callequal(left_set, right_set, verbose=True) - # skip first line because it contains the "construction" of the set, which does not have a guaranteed order - expl = expl[1:] - dedent = textwrap.dedent( - """ - Extra items in the left set: - repr(1) - Extra items in the right set: - repr(3) - Full diff (fallback to calling repr on each item): - - repr(1) - repr(2) - + repr(3) - """ - ).strip() - assert "\n".join(expl) == dedent - - -def test_diff_newline_at_end(monkeypatch, testdir): - testdir.makepyfile( - r""" - def test_diff(): - assert 'asdf' == 'asdf\n' - """ - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - r""" - *assert 'asdf' == 'asdf\n' - * - asdf - * + asdf - * ? + - """ - ) - - -def test_assert_tuple_warning(testdir): - testdir.makepyfile( - """ - def test_tuple(): - assert(False, 'you shall not pass') - """ - ) - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - ["*test_assert_tuple_warning.py:2", "*assertion is always true*"] - ) - - -def test_assert_indirect_tuple_no_warning(testdir): - testdir.makepyfile( - """ - def test_tuple(): - tpl = ('foo', 'bar') - assert tpl - """ - ) - result = testdir.runpytest("-rw") - output = "\n".join(result.stdout.lines) - assert "WR1" not in output - - -def test_assert_with_unicode(monkeypatch, testdir): - testdir.makepyfile( - u""" - # -*- coding: utf-8 -*- - def test_unicode(): - assert u'유니코드' == u'Unicode' - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*AssertionError*"]) - - -def test_raise_unprintable_assertion_error(testdir): - testdir.makepyfile( - r""" - def test_raise_assertion_error(): - raise AssertionError('\xff') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [r"> raise AssertionError('\xff')", "E AssertionError: *"] - ) - - -def test_raise_assertion_error_raisin_repr(testdir): - testdir.makepyfile( - u""" - class RaisingRepr(object): - def __repr__(self): - raise Exception() - def test_raising_repr(): - raise AssertionError(RaisingRepr()) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["E AssertionError: "] - ) - - -def test_issue_1944(testdir): - testdir.makepyfile( - """ - def f(): - return - - assert f() == 10 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 error*"]) - assert "AttributeError: 'Module' object has no attribute '_obj'" not in result.stdout.str() diff --git a/third_party/python/pytest/testing/test_assertrewrite.py b/third_party/python/pytest/testing/test_assertrewrite.py deleted file mode 100644 index 144f625bc6c3..000000000000 --- a/third_party/python/pytest/testing/test_assertrewrite.py +++ /dev/null @@ -1,1144 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import glob -import os -import py_compile -import stat -import sys -import textwrap -import zipfile -import py -import pytest - -import _pytest._code -from _pytest.assertion import util -from _pytest.assertion.rewrite import ( - rewrite_asserts, - PYTEST_TAG, - AssertionRewritingHook, -) -from _pytest.main import EXIT_NOTESTSCOLLECTED - -ast = pytest.importorskip("ast") -if sys.platform.startswith("java"): - # XXX should be xfail - pytest.skip("assert rewrite does currently not work on jython") - - -def setup_module(mod): - mod._old_reprcompare = util._reprcompare - _pytest._code._reprcompare = None - - -def teardown_module(mod): - util._reprcompare = mod._old_reprcompare - del mod._old_reprcompare - - -def rewrite(src): - tree = ast.parse(src) - rewrite_asserts(tree) - return tree - - -def getmsg(f, extra_ns=None, must_pass=False): - """Rewrite the assertions in f, run it, and get the failure message.""" - src = "\n".join(_pytest._code.Code(f).source().lines) - mod = rewrite(src) - code = compile(mod, "", "exec") - ns = {} - if extra_ns is not None: - ns.update(extra_ns) - py.builtin.exec_(code, ns) - func = ns[f.__name__] - try: - func() - except AssertionError: - if must_pass: - pytest.fail("shouldn't have raised") - s = str(sys.exc_info()[1]) - if not s.startswith("assert"): - return "AssertionError: " + s - return s - else: - if not must_pass: - pytest.fail("function didn't raise at all") - - -def adjust_body_for_new_docstring_in_module_node(m): - """Module docstrings in 3.8 are part of Module node. - This was briefly in 3.7 as well but got reverted in beta 5. - - It's not in the body so we remove it so the following body items have - the same indexes on all Python versions: - - TODO: - - We have a complicated sys.version_info if in here to ease testing on - various Python 3.7 versions, but we should remove the 3.7 check after - 3.7 is released as stable to make this check more straightforward. - """ - if ( - sys.version_info < (3, 8) - and not ((3, 7) <= sys.version_info <= (3, 7, 0, "beta", 4)) - ): - assert len(m.body) > 1 - assert isinstance(m.body[0], ast.Expr) - assert isinstance(m.body[0].value, ast.Str) - del m.body[0] - - -class TestAssertionRewrite(object): - - def test_place_initial_imports(self): - s = """'Doc string'\nother = stuff""" - m = rewrite(s) - adjust_body_for_new_docstring_in_module_node(m) - for imp in m.body[0:2]: - assert isinstance(imp, ast.Import) - assert imp.lineno == 2 - assert imp.col_offset == 0 - assert isinstance(m.body[2], ast.Assign) - s = """from __future__ import with_statement\nother_stuff""" - m = rewrite(s) - assert isinstance(m.body[0], ast.ImportFrom) - for imp in m.body[1:3]: - assert isinstance(imp, ast.Import) - assert imp.lineno == 2 - assert imp.col_offset == 0 - assert isinstance(m.body[3], ast.Expr) - s = """'doc string'\nfrom __future__ import with_statement""" - m = rewrite(s) - adjust_body_for_new_docstring_in_module_node(m) - assert isinstance(m.body[0], ast.ImportFrom) - for imp in m.body[1:3]: - assert isinstance(imp, ast.Import) - assert imp.lineno == 2 - assert imp.col_offset == 0 - s = """'doc string'\nfrom __future__ import with_statement\nother""" - m = rewrite(s) - adjust_body_for_new_docstring_in_module_node(m) - assert isinstance(m.body[0], ast.ImportFrom) - for imp in m.body[1:3]: - assert isinstance(imp, ast.Import) - assert imp.lineno == 3 - assert imp.col_offset == 0 - assert isinstance(m.body[3], ast.Expr) - s = """from . import relative\nother_stuff""" - m = rewrite(s) - for imp in m.body[0:2]: - assert isinstance(imp, ast.Import) - assert imp.lineno == 1 - assert imp.col_offset == 0 - assert isinstance(m.body[3], ast.Expr) - - def test_dont_rewrite(self): - s = """'PYTEST_DONT_REWRITE'\nassert 14""" - m = rewrite(s) - adjust_body_for_new_docstring_in_module_node(m) - assert len(m.body) == 1 - assert m.body[0].msg is None - - def test_dont_rewrite_plugin(self, testdir): - contents = { - "conftest.py": "pytest_plugins = 'plugin'; import plugin", - "plugin.py": "'PYTEST_DONT_REWRITE'", - "test_foo.py": "def test_foo(): pass", - } - testdir.makepyfile(**contents) - result = testdir.runpytest_subprocess() - assert "warnings" not in "".join(result.outlines) - - def test_name(self): - - def f(): - assert False - - assert getmsg(f) == "assert False" - - def f(): - f = False - assert f - - assert getmsg(f) == "assert False" - - def f(): - assert a_global # noqa - - assert getmsg(f, {"a_global": False}) == "assert False" - - def f(): - assert sys == 42 - - assert getmsg(f, {"sys": sys}) == "assert sys == 42" - - def f(): - assert cls == 42 # noqa - - class X(object): - pass - - assert getmsg(f, {"cls": X}) == "assert cls == 42" - - def test_assert_already_has_message(self): - - def f(): - assert False, "something bad!" - - assert getmsg(f) == "AssertionError: something bad!\nassert False" - - def test_assertion_message(self, testdir): - testdir.makepyfile( - """ - def test_foo(): - assert 1 == 2, "The failure message" - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines( - ["*AssertionError*The failure message*", "*assert 1 == 2*"] - ) - - def test_assertion_message_multiline(self, testdir): - testdir.makepyfile( - """ - def test_foo(): - assert 1 == 2, "A multiline\\nfailure message" - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines( - ["*AssertionError*A multiline*", "*failure message*", "*assert 1 == 2*"] - ) - - def test_assertion_message_tuple(self, testdir): - testdir.makepyfile( - """ - def test_foo(): - assert 1 == 2, (1, 2) - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines( - ["*AssertionError*%s*" % repr((1, 2)), "*assert 1 == 2*"] - ) - - def test_assertion_message_expr(self, testdir): - testdir.makepyfile( - """ - def test_foo(): - assert 1 == 2, 1 + 2 - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines(["*AssertionError*3*", "*assert 1 == 2*"]) - - def test_assertion_message_escape(self, testdir): - testdir.makepyfile( - """ - def test_foo(): - assert 1 == 2, 'To be escaped: %' - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - result.stdout.fnmatch_lines( - ["*AssertionError: To be escaped: %", "*assert 1 == 2"] - ) - - def test_boolop(self): - - def f(): - f = g = False - assert f and g - - assert getmsg(f) == "assert (False)" - - def f(): - f = True - g = False - assert f and g - - assert getmsg(f) == "assert (True and False)" - - def f(): - f = False - g = True - assert f and g - - assert getmsg(f) == "assert (False)" - - def f(): - f = g = False - assert f or g - - assert getmsg(f) == "assert (False or False)" - - def f(): - f = g = False - assert not f and not g - - getmsg(f, must_pass=True) - - def x(): - return False - - def f(): - assert x() and x() - - assert ( - getmsg(f, {"x": x}) - == """assert (False) - + where False = x()""" - ) - - def f(): - assert False or x() - - assert ( - getmsg(f, {"x": x}) - == """assert (False or False) - + where False = x()""" - ) - - def f(): - assert 1 in {} and 2 in {} - - assert getmsg(f) == "assert (1 in {})" - - def f(): - x = 1 - y = 2 - assert x in {1: None} and y in {} - - assert getmsg(f) == "assert (1 in {1: None} and 2 in {})" - - def f(): - f = True - g = False - assert f or g - - getmsg(f, must_pass=True) - - def f(): - f = g = h = lambda: True - assert f() and g() and h() - - getmsg(f, must_pass=True) - - def test_short_circuit_evaluation(self): - - def f(): - assert True or explode # noqa - - getmsg(f, must_pass=True) - - def f(): - x = 1 - assert x == 1 or x == 2 - - getmsg(f, must_pass=True) - - def test_unary_op(self): - - def f(): - x = True - assert not x - - assert getmsg(f) == "assert not True" - - def f(): - x = 0 - assert ~x + 1 - - assert getmsg(f) == "assert (~0 + 1)" - - def f(): - x = 3 - assert -x + x - - assert getmsg(f) == "assert (-3 + 3)" - - def f(): - x = 0 - assert +x + x - - assert getmsg(f) == "assert (+0 + 0)" - - def test_binary_op(self): - - def f(): - x = 1 - y = -1 - assert x + y - - assert getmsg(f) == "assert (1 + -1)" - - def f(): - assert not 5 % 4 - - assert getmsg(f) == "assert not (5 % 4)" - - def test_boolop_percent(self): - - def f(): - assert 3 % 2 and False - - assert getmsg(f) == "assert ((3 % 2) and False)" - - def f(): - assert False or 4 % 2 - - assert getmsg(f) == "assert (False or (4 % 2))" - - @pytest.mark.skipif("sys.version_info < (3,5)") - def test_at_operator_issue1290(self, testdir): - testdir.makepyfile( - """ - class Matrix(object): - def __init__(self, num): - self.num = num - def __matmul__(self, other): - return self.num * other.num - - def test_multmat_operator(): - assert Matrix(2) @ Matrix(3) == 6""" - ) - testdir.runpytest().assert_outcomes(passed=1) - - def test_call(self): - - def g(a=42, *args, **kwargs): - return False - - ns = {"g": g} - - def f(): - assert g() - - assert ( - getmsg(f, ns) - == """assert False - + where False = g()""" - ) - - def f(): - assert g(1) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(1)""" - ) - - def f(): - assert g(1, 2) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(1, 2)""" - ) - - def f(): - assert g(1, g=42) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(1, g=42)""" - ) - - def f(): - assert g(1, 3, g=23) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(1, 3, g=23)""" - ) - - def f(): - seq = [1, 2, 3] - assert g(*seq) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(*[1, 2, 3])""" - ) - - def f(): - x = "a" - assert g(**{x: 2}) - - assert ( - getmsg(f, ns) - == """assert False - + where False = g(**{'a': 2})""" - ) - - def test_attribute(self): - - class X(object): - g = 3 - - ns = {"x": X} - - def f(): - assert not x.g # noqa - - assert ( - getmsg(f, ns) - == """assert not 3 - + where 3 = x.g""" - ) - - def f(): - x.a = False # noqa - assert x.a # noqa - - assert ( - getmsg(f, ns) - == """assert False - + where False = x.a""" - ) - - def test_comparisons(self): - - def f(): - a, b = range(2) - assert b < a - - assert getmsg(f) == """assert 1 < 0""" - - def f(): - a, b, c = range(3) - assert a > b > c - - assert getmsg(f) == """assert 0 > 1""" - - def f(): - a, b, c = range(3) - assert a < b > c - - assert getmsg(f) == """assert 1 > 2""" - - def f(): - a, b, c = range(3) - assert a < b <= c - - getmsg(f, must_pass=True) - - def f(): - a, b, c = range(3) - assert a < b - assert b < c - - getmsg(f, must_pass=True) - - def test_len(self): - - def f(): - values = list(range(10)) - assert len(values) == 11 - - assert getmsg(f).startswith( - """assert 10 == 11 - + where 10 = len([""" - ) - - def test_custom_reprcompare(self, monkeypatch): - - def my_reprcompare(op, left, right): - return "42" - - monkeypatch.setattr(util, "_reprcompare", my_reprcompare) - - def f(): - assert 42 < 3 - - assert getmsg(f) == "assert 42" - - def my_reprcompare(op, left, right): - return "%s %s %s" % (left, op, right) - - monkeypatch.setattr(util, "_reprcompare", my_reprcompare) - - def f(): - assert 1 < 3 < 5 <= 4 < 7 - - assert getmsg(f) == "assert 5 <= 4" - - def test_assert_raising_nonzero_in_comparison(self): - - def f(): - - class A(object): - - def __nonzero__(self): - raise ValueError(42) - - def __lt__(self, other): - return A() - - def __repr__(self): - return "" - - def myany(x): - return False - - assert myany(A() < 0) - - assert " < 0" in getmsg(f) - - def test_formatchar(self): - - def f(): - assert "%test" == "test" - - assert getmsg(f).startswith("assert '%test' == 'test'") - - def test_custom_repr(self): - - def f(): - - class Foo(object): - a = 1 - - def __repr__(self): - return "\n{ \n~ \n}" - - f = Foo() - assert 0 == f.a - - assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0] - - -class TestRewriteOnImport(object): - - def test_pycache_is_a_file(self, testdir): - testdir.tmpdir.join("__pycache__").write("Hello") - testdir.makepyfile( - """ - def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - assert testdir.runpytest().ret == 0 - - def test_pycache_is_readonly(self, testdir): - cache = testdir.tmpdir.mkdir("__pycache__") - old_mode = cache.stat().mode - cache.chmod(old_mode ^ stat.S_IWRITE) - testdir.makepyfile( - """ - def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - try: - assert testdir.runpytest().ret == 0 - finally: - cache.chmod(old_mode) - - def test_zipfile(self, testdir): - z = testdir.tmpdir.join("myzip.zip") - z_fn = str(z) - f = zipfile.ZipFile(z_fn, "w") - try: - f.writestr("test_gum/__init__.py", "") - f.writestr("test_gum/test_lizard.py", "") - finally: - f.close() - z.chmod(256) - testdir.makepyfile( - """ - import sys - sys.path.append(%r) - import test_gum.test_lizard""" - % (z_fn,) - ) - assert testdir.runpytest().ret == EXIT_NOTESTSCOLLECTED - - def test_readonly(self, testdir): - sub = testdir.mkdir("testing") - sub.join("test_readonly.py").write( - py.builtin._totext( - """ -def test_rewritten(): - assert "@py_builtins" in globals() - """ - ).encode( - "utf-8" - ), - "wb", - ) - old_mode = sub.stat().mode - sub.chmod(320) - try: - assert testdir.runpytest().ret == 0 - finally: - sub.chmod(old_mode) - - def test_dont_write_bytecode(self, testdir, monkeypatch): - testdir.makepyfile( - """ - import os - def test_no_bytecode(): - assert "__pycache__" in __cached__ - assert not os.path.exists(__cached__) - assert not os.path.exists(os.path.dirname(__cached__))""" - ) - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", "1") - assert testdir.runpytest_subprocess().ret == 0 - - def test_orphaned_pyc_file(self, testdir): - if sys.version_info < (3, 0) and hasattr(sys, "pypy_version_info"): - pytest.skip("pypy2 doesn't run orphaned pyc files") - - testdir.makepyfile( - """ - import orphan - def test_it(): - assert orphan.value == 17 - """ - ) - testdir.makepyfile( - orphan=""" - value = 17 - """ - ) - py_compile.compile("orphan.py") - os.remove("orphan.py") - - # Python 3 puts the .pyc files in a __pycache__ directory, and will - # not import from there without source. It will import a .pyc from - # the source location though. - if not os.path.exists("orphan.pyc"): - pycs = glob.glob("__pycache__/orphan.*.pyc") - assert len(pycs) == 1 - os.rename(pycs[0], "orphan.pyc") - - assert testdir.runpytest().ret == 0 - - @pytest.mark.skipif('"__pypy__" in sys.modules') - def test_pyc_vs_pyo(self, testdir, monkeypatch): - testdir.makepyfile( - """ - import pytest - def test_optimized(): - "hello" - assert test_optimized.__doc__ is None""" - ) - p = py.path.local.make_numbered_dir( - prefix="runpytest-", keep=None, rootdir=testdir.tmpdir - ) - tmp = "--basetemp=%s" % p - monkeypatch.setenv("PYTHONOPTIMIZE", "2") - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) - assert testdir.runpytest_subprocess(tmp).ret == 0 - tagged = "test_pyc_vs_pyo." + PYTEST_TAG - assert tagged + ".pyo" in os.listdir("__pycache__") - monkeypatch.undo() - monkeypatch.delenv("PYTHONDONTWRITEBYTECODE", raising=False) - assert testdir.runpytest_subprocess(tmp).ret == 1 - assert tagged + ".pyc" in os.listdir("__pycache__") - - def test_package(self, testdir): - pkg = testdir.tmpdir.join("pkg") - pkg.mkdir() - pkg.join("__init__.py").ensure() - pkg.join("test_blah.py").write( - """ -def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - assert testdir.runpytest().ret == 0 - - def test_translate_newlines(self, testdir): - content = "def test_rewritten():\r\n assert '@py_builtins' in globals()" - b = content.encode("utf-8") - testdir.tmpdir.join("test_newlines.py").write(b, "wb") - assert testdir.runpytest().ret == 0 - - @pytest.mark.skipif( - sys.version_info < (3, 4), - reason="packages without __init__.py not supported on python 2", - ) - def test_package_without__init__py(self, testdir): - pkg = testdir.mkdir("a_package_without_init_py") - pkg.join("module.py").ensure() - testdir.makepyfile("import a_package_without_init_py.module") - assert testdir.runpytest().ret == EXIT_NOTESTSCOLLECTED - - def test_rewrite_warning(self, pytestconfig, monkeypatch): - hook = AssertionRewritingHook(pytestconfig) - warnings = [] - - def mywarn(code, msg): - warnings.append((code, msg)) - - monkeypatch.setattr(hook.config, "warn", mywarn) - hook.mark_rewrite("_pytest") - assert "_pytest" in warnings[0][1] - - def test_rewrite_module_imported_from_conftest(self, testdir): - testdir.makeconftest( - """ - import test_rewrite_module_imported - """ - ) - testdir.makepyfile( - test_rewrite_module_imported=""" - def test_rewritten(): - assert "@py_builtins" in globals() - """ - ) - assert testdir.runpytest_subprocess().ret == 0 - - def test_remember_rewritten_modules(self, pytestconfig, testdir, monkeypatch): - """ - AssertionRewriteHook should remember rewritten modules so it - doesn't give false positives (#2005). - """ - monkeypatch.syspath_prepend(testdir.tmpdir) - testdir.makepyfile(test_remember_rewritten_modules="") - warnings = [] - hook = AssertionRewritingHook(pytestconfig) - monkeypatch.setattr(hook.config, "warn", lambda code, msg: warnings.append(msg)) - hook.find_module("test_remember_rewritten_modules") - hook.load_module("test_remember_rewritten_modules") - hook.mark_rewrite("test_remember_rewritten_modules") - hook.mark_rewrite("test_remember_rewritten_modules") - assert warnings == [] - - def test_rewrite_warning_using_pytest_plugins(self, testdir): - testdir.makepyfile( - **{ - "conftest.py": "pytest_plugins = ['core', 'gui', 'sci']", - "core.py": "", - "gui.py": "pytest_plugins = ['core', 'sci']", - "sci.py": "pytest_plugins = ['core']", - "test_rewrite_warning_pytest_plugins.py": "def test(): pass", - } - ) - testdir.chdir() - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*= 1 passed in *=*"]) - assert "pytest-warning summary" not in result.stdout.str() - - def test_rewrite_warning_using_pytest_plugins_env_var(self, testdir, monkeypatch): - monkeypatch.setenv("PYTEST_PLUGINS", "plugin") - testdir.makepyfile( - **{ - "plugin.py": "", - "test_rewrite_warning_using_pytest_plugins_env_var.py": """ - import plugin - pytest_plugins = ['plugin'] - def test(): - pass - """, - } - ) - testdir.chdir() - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*= 1 passed in *=*"]) - assert "pytest-warning summary" not in result.stdout.str() - - @pytest.mark.skipif(sys.version_info[0] > 2, reason="python 2 only") - def test_rewrite_future_imports(self, testdir): - """Test that rewritten modules don't inherit the __future__ flags - from the assertrewrite module. - - assertion.rewrite imports __future__.division (and others), so - ensure rewritten modules don't inherit those flags. - - The test below will fail if __future__.division is enabled - """ - testdir.makepyfile( - """ - def test(): - x = 1 / 2 - assert type(x) is int - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - - -class TestAssertionRewriteHookDetails(object): - - def test_loader_is_package_false_for_module(self, testdir): - testdir.makepyfile( - test_fun=""" - def test_loader(): - assert not __loader__.is_package(__name__) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 1 passed*"]) - - def test_loader_is_package_true_for_package(self, testdir): - testdir.makepyfile( - test_fun=""" - def test_loader(): - assert not __loader__.is_package(__name__) - - def test_fun(): - assert __loader__.is_package('fun') - - def test_missing(): - assert not __loader__.is_package('pytest_not_there') - """ - ) - testdir.mkpydir("fun") - result = testdir.runpytest() - result.stdout.fnmatch_lines(["* 3 passed*"]) - - @pytest.mark.skipif("sys.version_info[0] >= 3") - @pytest.mark.xfail("hasattr(sys, 'pypy_translation_info')") - def test_assume_ascii(self, testdir): - content = "u'\xe2\x99\xa5\x01\xfe'" - testdir.tmpdir.join("test_encoding.py").write(content, "wb") - res = testdir.runpytest() - assert res.ret != 0 - assert "SyntaxError: Non-ASCII character" in res.stdout.str() - - @pytest.mark.skipif("sys.version_info[0] >= 3") - def test_detect_coding_cookie(self, testdir): - testdir.makepyfile( - test_cookie=""" - # -*- coding: utf-8 -*- - u"St\xc3\xa4d" - def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - assert testdir.runpytest().ret == 0 - - @pytest.mark.skipif("sys.version_info[0] >= 3") - def test_detect_coding_cookie_second_line(self, testdir): - testdir.makepyfile( - test_cookie=""" - # -*- coding: utf-8 -*- - u"St\xc3\xa4d" - def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - assert testdir.runpytest().ret == 0 - - @pytest.mark.skipif("sys.version_info[0] >= 3") - def test_detect_coding_cookie_crlf(self, testdir): - testdir.makepyfile( - test_cookie=""" - # -*- coding: utf-8 -*- - u"St\xc3\xa4d" - def test_rewritten(): - assert "@py_builtins" in globals()""" - ) - assert testdir.runpytest().ret == 0 - - def test_sys_meta_path_munged(self, testdir): - testdir.makepyfile( - """ - def test_meta_path(): - import sys; sys.meta_path = []""" - ) - assert testdir.runpytest().ret == 0 - - def test_write_pyc(self, testdir, tmpdir, monkeypatch): - from _pytest.assertion.rewrite import _write_pyc - from _pytest.assertion import AssertionState - import atomicwrites - from contextlib import contextmanager - - config = testdir.parseconfig([]) - state = AssertionState(config, "rewrite") - source_path = tmpdir.ensure("source.py") - pycpath = tmpdir.join("pyc").strpath - assert _write_pyc(state, [1], source_path.stat(), pycpath) - - @contextmanager - def atomic_write_failed(fn, mode="r", overwrite=False): - e = IOError() - e.errno = 10 - raise e - yield # noqa - - monkeypatch.setattr(atomicwrites, "atomic_write", atomic_write_failed) - assert not _write_pyc(state, [1], source_path.stat(), pycpath) - - def test_resources_provider_for_loader(self, testdir): - """ - Attempts to load resources from a package should succeed normally, - even when the AssertionRewriteHook is used to load the modules. - - See #366 for details. - """ - pytest.importorskip("pkg_resources") - - testdir.mkpydir("testpkg") - contents = { - "testpkg/test_pkg": """ - import pkg_resources - - import pytest - from _pytest.assertion.rewrite import AssertionRewritingHook - - def test_load_resource(): - assert isinstance(__loader__, AssertionRewritingHook) - res = pkg_resources.resource_string(__name__, 'resource.txt') - res = res.decode('ascii') - assert res == 'Load me please.' - """ - } - testdir.makepyfile(**contents) - testdir.maketxtfile(**{"testpkg/resource": "Load me please."}) - - result = testdir.runpytest_subprocess() - result.assert_outcomes(passed=1) - - def test_read_pyc(self, tmpdir): - """ - Ensure that the `_read_pyc` can properly deal with corrupted pyc files. - In those circumstances it should just give up instead of generating - an exception that is propagated to the caller. - """ - import py_compile - from _pytest.assertion.rewrite import _read_pyc - - source = tmpdir.join("source.py") - pyc = source + "c" - - source.write("def test(): pass") - py_compile.compile(str(source), str(pyc)) - - contents = pyc.read(mode="rb") - strip_bytes = 20 # header is around 8 bytes, strip a little more - assert len(contents) > strip_bytes - pyc.write(contents[:strip_bytes], mode="wb") - - assert _read_pyc(source, str(pyc)) is None # no error - - def test_reload_is_same(self, testdir): - # A file that will be picked up during collecting. - testdir.tmpdir.join("file.py").ensure() - testdir.tmpdir.join("pytest.ini").write( - textwrap.dedent( - """ - [pytest] - python_files = *.py - """ - ) - ) - - testdir.makepyfile( - test_fun=""" - import sys - try: - from imp import reload - except ImportError: - pass - - def test_loader(): - import file - assert sys.modules["file"] is reload(file) - """ - ) - result = testdir.runpytest("-s") - result.stdout.fnmatch_lines(["* 1 passed*"]) - - def test_get_data_support(self, testdir): - """Implement optional PEP302 api (#808). - """ - path = testdir.mkpydir("foo") - path.join("test_foo.py").write( - _pytest._code.Source( - """ - class Test(object): - def test_foo(self): - import pkgutil - data = pkgutil.get_data('foo.test_foo', 'data.txt') - assert data == b'Hey' - """ - ) - ) - path.join("data.txt").write("Hey") - result = testdir.runpytest() - result.stdout.fnmatch_lines("*1 passed*") - - -def test_issue731(testdir): - testdir.makepyfile( - """ - class LongReprWithBraces(object): - def __repr__(self): - return 'LongReprWithBraces({' + ('a' * 80) + '}' + ('a' * 120) + ')' - - def some_method(self): - return False - - def test_long_repr(): - obj = LongReprWithBraces() - assert obj.some_method() - """ - ) - result = testdir.runpytest() - assert "unbalanced braces" not in result.stdout.str() - - -class TestIssue925(object): - - def test_simple_case(self, testdir): - testdir.makepyfile( - """ - def test_ternary_display(): - assert (False == False) == False - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*E*assert (False == False) == False") - - def test_long_case(self, testdir): - testdir.makepyfile( - """ - def test_ternary_display(): - assert False == (False == True) == True - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*E*assert (False == True) == True") - - def test_many_brackets(self, testdir): - testdir.makepyfile( - """ - def test_ternary_display(): - assert True == ((False == True) == True) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*E*assert True == ((False == True) == True)") - - -class TestIssue2121(): - - def test_simple(self, testdir): - testdir.tmpdir.join("tests/file.py").ensure().write( - """ -def test_simple_failure(): - assert 1 + 1 == 3 -""" - ) - testdir.tmpdir.join("pytest.ini").write( - textwrap.dedent( - """ - [pytest] - python_files = tests/**.py - """ - ) - ) - - result = testdir.runpytest() - result.stdout.fnmatch_lines("*E*assert (1 + 1) == 3") diff --git a/third_party/python/pytest/testing/test_cacheprovider.py b/third_party/python/pytest/testing/test_cacheprovider.py deleted file mode 100644 index 33d1dd8448c1..000000000000 --- a/third_party/python/pytest/testing/test_cacheprovider.py +++ /dev/null @@ -1,820 +0,0 @@ -from __future__ import absolute_import, division, print_function -import sys -import py -import _pytest -import pytest -import os -import shutil - -pytest_plugins = "pytester", - - -class TestNewAPI(object): - - def test_config_cache_makedir(self, testdir): - testdir.makeini("[pytest]") - config = testdir.parseconfigure() - with pytest.raises(ValueError): - config.cache.makedir("key/name") - - p = config.cache.makedir("name") - assert p.check() - - def test_config_cache_dataerror(self, testdir): - testdir.makeini("[pytest]") - config = testdir.parseconfigure() - cache = config.cache - pytest.raises(TypeError, lambda: cache.set("key/name", cache)) - config.cache.set("key/name", 0) - config.cache._getvaluepath("key/name").write("123invalid") - val = config.cache.get("key/name", -2) - assert val == -2 - - def test_cache_writefail_cachfile_silent(self, testdir): - testdir.makeini("[pytest]") - testdir.tmpdir.join(".pytest_cache").write("gone wrong") - config = testdir.parseconfigure() - cache = config.cache - cache.set("test/broken", []) - - @pytest.mark.skipif(sys.platform.startswith("win"), reason="no chmod on windows") - def test_cache_writefail_permissions(self, testdir): - testdir.makeini("[pytest]") - testdir.tmpdir.ensure_dir(".pytest_cache").chmod(0) - config = testdir.parseconfigure() - cache = config.cache - cache.set("test/broken", []) - - @pytest.mark.skipif(sys.platform.startswith("win"), reason="no chmod on windows") - def test_cache_failure_warns(self, testdir): - testdir.tmpdir.ensure_dir(".pytest_cache").chmod(0) - testdir.makepyfile( - """ - def test_error(): - raise Exception - - """ - ) - result = testdir.runpytest("-rw") - assert result.ret == 1 - result.stdout.fnmatch_lines(["*could not create cache path*", "*2 warnings*"]) - - def test_config_cache(self, testdir): - testdir.makeconftest( - """ - def pytest_configure(config): - # see that we get cache information early on - assert hasattr(config, "cache") - """ - ) - testdir.makepyfile( - """ - def test_session(pytestconfig): - assert hasattr(pytestconfig, "cache") - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_cachefuncarg(self, testdir): - testdir.makepyfile( - """ - import pytest - def test_cachefuncarg(cache): - val = cache.get("some/thing", None) - assert val is None - cache.set("some/thing", [1]) - pytest.raises(TypeError, lambda: cache.get("some/thing")) - val = cache.get("some/thing", []) - assert val == [1] - """ - ) - result = testdir.runpytest() - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_custom_rel_cache_dir(self, testdir): - rel_cache_dir = os.path.join("custom_cache_dir", "subdir") - testdir.makeini( - """ - [pytest] - cache_dir = {cache_dir} - """.format( - cache_dir=rel_cache_dir - ) - ) - testdir.makepyfile(test_errored="def test_error():\n assert False") - testdir.runpytest() - assert testdir.tmpdir.join(rel_cache_dir).isdir() - - def test_custom_abs_cache_dir(self, testdir, tmpdir_factory): - tmp = str(tmpdir_factory.mktemp("tmp")) - abs_cache_dir = os.path.join(tmp, "custom_cache_dir") - testdir.makeini( - """ - [pytest] - cache_dir = {cache_dir} - """.format( - cache_dir=abs_cache_dir - ) - ) - testdir.makepyfile(test_errored="def test_error():\n assert False") - testdir.runpytest() - assert py.path.local(abs_cache_dir).isdir() - - def test_custom_cache_dir_with_env_var(self, testdir, monkeypatch): - monkeypatch.setenv("env_var", "custom_cache_dir") - testdir.makeini( - """ - [pytest] - cache_dir = {cache_dir} - """.format( - cache_dir="$env_var" - ) - ) - testdir.makepyfile(test_errored="def test_error():\n assert False") - testdir.runpytest() - assert testdir.tmpdir.join("custom_cache_dir").isdir() - - -def test_cache_reportheader(testdir): - testdir.makepyfile( - """ - def test_hello(): - pass - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines(["cachedir: .pytest_cache"]) - - -def test_cache_show(testdir): - result = testdir.runpytest("--cache-show") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*cache is empty*"]) - testdir.makeconftest( - """ - def pytest_configure(config): - config.cache.set("my/name", [1,2,3]) - config.cache.set("other/some", {1:2}) - dp = config.cache.makedir("mydb") - dp.ensure("hello") - dp.ensure("world") - """ - ) - result = testdir.runpytest() - assert result.ret == 5 # no tests executed - result = testdir.runpytest("--cache-show") - result.stdout.fnmatch_lines_random( - [ - "*cachedir:*", - "-*cache values*-", - "*my/name contains:", - " [1, 2, 3]", - "*other/some contains*", - " {*1*: 2}", - "-*cache directories*-", - "*mydb/hello*length 0*", - "*mydb/world*length 0*", - ] - ) - - -class TestLastFailed(object): - - def test_lastfailed_usecase(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) - p = testdir.makepyfile( - """ - def test_1(): - assert 0 - def test_2(): - assert 0 - def test_3(): - assert 1 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 failed*"]) - p.write( - _pytest._code.Source( - """ - def test_1(): - assert 1 - - def test_2(): - assert 1 - - def test_3(): - assert 0 - """ - ) - ) - result = testdir.runpytest("--lf") - result.stdout.fnmatch_lines(["*2 passed*1 desel*"]) - result = testdir.runpytest("--lf") - result.stdout.fnmatch_lines(["*1 failed*2 passed*"]) - result = testdir.runpytest("--lf", "--cache-clear") - result.stdout.fnmatch_lines(["*1 failed*2 passed*"]) - - # Run this again to make sure clear-cache is robust - if os.path.isdir(".pytest_cache"): - shutil.rmtree(".pytest_cache") - result = testdir.runpytest("--lf", "--cache-clear") - result.stdout.fnmatch_lines(["*1 failed*2 passed*"]) - - def test_failedfirst_order(self, testdir): - testdir.tmpdir.join("test_a.py").write( - _pytest._code.Source( - """ - def test_always_passes(): - assert 1 - """ - ) - ) - testdir.tmpdir.join("test_b.py").write( - _pytest._code.Source( - """ - def test_always_fails(): - assert 0 - """ - ) - ) - result = testdir.runpytest() - # Test order will be collection order; alphabetical - result.stdout.fnmatch_lines(["test_a.py*", "test_b.py*"]) - result = testdir.runpytest("--ff") - # Test order will be failing tests firs - result.stdout.fnmatch_lines(["test_b.py*", "test_a.py*"]) - - def test_lastfailed_failedfirst_order(self, testdir): - testdir.makepyfile( - **{ - "test_a.py": """ - def test_always_passes(): - assert 1 - """, - "test_b.py": """ - def test_always_fails(): - assert 0 - """, - } - ) - result = testdir.runpytest() - # Test order will be collection order; alphabetical - result.stdout.fnmatch_lines(["test_a.py*", "test_b.py*"]) - result = testdir.runpytest("--lf", "--ff") - # Test order will be failing tests firs - result.stdout.fnmatch_lines(["test_b.py*"]) - assert "test_a.py" not in result.stdout.str() - - def test_lastfailed_difference_invocations(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) - testdir.makepyfile( - test_a=""" - def test_a1(): - assert 0 - def test_a2(): - assert 1 - """, - test_b=""" - def test_b1(): - assert 0 - """, - ) - p = testdir.tmpdir.join("test_a.py") - p2 = testdir.tmpdir.join("test_b.py") - - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 failed*"]) - result = testdir.runpytest("--lf", p2) - result.stdout.fnmatch_lines(["*1 failed*"]) - p2.write( - _pytest._code.Source( - """ - def test_b1(): - assert 1 - """ - ) - ) - result = testdir.runpytest("--lf", p2) - result.stdout.fnmatch_lines(["*1 passed*"]) - result = testdir.runpytest("--lf", p) - result.stdout.fnmatch_lines(["*1 failed*1 desel*"]) - - def test_lastfailed_usecase_splice(self, testdir, monkeypatch): - monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) - testdir.makepyfile( - """ - def test_1(): - assert 0 - """ - ) - p2 = testdir.tmpdir.join("test_something.py") - p2.write( - _pytest._code.Source( - """ - def test_2(): - assert 0 - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 failed*"]) - result = testdir.runpytest("--lf", p2) - result.stdout.fnmatch_lines(["*1 failed*"]) - result = testdir.runpytest("--lf") - result.stdout.fnmatch_lines(["*2 failed*"]) - - def test_lastfailed_xpass(self, testdir): - testdir.inline_runsource( - """ - import pytest - @pytest.mark.xfail - def test_hello(): - assert 1 - """ - ) - config = testdir.parseconfigure() - lastfailed = config.cache.get("cache/lastfailed", -1) - assert lastfailed == -1 - - def test_non_serializable_parametrize(self, testdir): - """Test that failed parametrized tests with unmarshable parameters - don't break pytest-cache. - """ - testdir.makepyfile( - r""" - import pytest - - @pytest.mark.parametrize('val', [ - b'\xac\x10\x02G', - ]) - def test_fail(val): - assert False - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*1 failed in*") - - def test_terminal_report_lastfailed(self, testdir): - test_a = testdir.makepyfile( - test_a=""" - def test_a1(): - pass - def test_a2(): - pass - """ - ) - test_b = testdir.makepyfile( - test_b=""" - def test_b1(): - assert 0 - def test_b2(): - assert 0 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["collected 4 items", "*2 failed, 2 passed in*"]) - - result = testdir.runpytest("--lf") - result.stdout.fnmatch_lines( - [ - "collected 4 items / 2 deselected", - "run-last-failure: rerun previous 2 failures", - "*2 failed, 2 deselected in*", - ] - ) - - result = testdir.runpytest(test_a, "--lf") - result.stdout.fnmatch_lines( - [ - "collected 2 items", - "run-last-failure: run all (no recorded failures)", - "*2 passed in*", - ] - ) - - result = testdir.runpytest(test_b, "--lf") - result.stdout.fnmatch_lines( - [ - "collected 2 items", - "run-last-failure: rerun previous 2 failures", - "*2 failed in*", - ] - ) - - result = testdir.runpytest("test_b.py::test_b1", "--lf") - result.stdout.fnmatch_lines( - [ - "collected 1 item", - "run-last-failure: rerun previous 1 failure", - "*1 failed in*", - ] - ) - - def test_terminal_report_failedfirst(self, testdir): - testdir.makepyfile( - test_a=""" - def test_a1(): - assert 0 - def test_a2(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["collected 2 items", "*1 failed, 1 passed in*"]) - - result = testdir.runpytest("--ff") - result.stdout.fnmatch_lines( - [ - "collected 2 items", - "run-last-failure: rerun previous 1 failure first", - "*1 failed, 1 passed in*", - ] - ) - - def test_lastfailed_collectfailure(self, testdir, monkeypatch): - - testdir.makepyfile( - test_maybe=""" - import os - env = os.environ - if '1' == env['FAILIMPORT']: - raise ImportError('fail') - def test_hello(): - assert '0' == env['FAILTEST'] - """ - ) - - def rlf(fail_import, fail_run): - monkeypatch.setenv("FAILIMPORT", fail_import) - monkeypatch.setenv("FAILTEST", fail_run) - - testdir.runpytest("-q") - config = testdir.parseconfigure() - lastfailed = config.cache.get("cache/lastfailed", -1) - return lastfailed - - lastfailed = rlf(fail_import=0, fail_run=0) - assert lastfailed == -1 - - lastfailed = rlf(fail_import=1, fail_run=0) - assert list(lastfailed) == ["test_maybe.py"] - - lastfailed = rlf(fail_import=0, fail_run=1) - assert list(lastfailed) == ["test_maybe.py::test_hello"] - - def test_lastfailed_failure_subset(self, testdir, monkeypatch): - - testdir.makepyfile( - test_maybe=""" - import os - env = os.environ - if '1' == env['FAILIMPORT']: - raise ImportError('fail') - def test_hello(): - assert '0' == env['FAILTEST'] - """ - ) - - testdir.makepyfile( - test_maybe2=""" - import os - env = os.environ - if '1' == env['FAILIMPORT']: - raise ImportError('fail') - def test_hello(): - assert '0' == env['FAILTEST'] - - def test_pass(): - pass - """ - ) - - def rlf(fail_import, fail_run, args=()): - monkeypatch.setenv("FAILIMPORT", fail_import) - monkeypatch.setenv("FAILTEST", fail_run) - - result = testdir.runpytest("-q", "--lf", *args) - config = testdir.parseconfigure() - lastfailed = config.cache.get("cache/lastfailed", -1) - return result, lastfailed - - result, lastfailed = rlf(fail_import=0, fail_run=0) - assert lastfailed == -1 - result.stdout.fnmatch_lines(["*3 passed*"]) - - result, lastfailed = rlf(fail_import=1, fail_run=0) - assert sorted(list(lastfailed)) == ["test_maybe.py", "test_maybe2.py"] - - result, lastfailed = rlf(fail_import=0, fail_run=0, args=("test_maybe2.py",)) - assert list(lastfailed) == ["test_maybe.py"] - - # edge case of test selection - even if we remember failures - # from other tests we still need to run all tests if no test - # matches the failures - result, lastfailed = rlf(fail_import=0, fail_run=0, args=("test_maybe2.py",)) - assert list(lastfailed) == ["test_maybe.py"] - result.stdout.fnmatch_lines(["*2 passed*"]) - - def test_lastfailed_creates_cache_when_needed(self, testdir): - # Issue #1342 - testdir.makepyfile(test_empty="") - testdir.runpytest("-q", "--lf") - assert not os.path.exists(".pytest_cache/v/cache/lastfailed") - - testdir.makepyfile(test_successful="def test_success():\n assert True") - testdir.runpytest("-q", "--lf") - assert not os.path.exists(".pytest_cache/v/cache/lastfailed") - - testdir.makepyfile(test_errored="def test_error():\n assert False") - testdir.runpytest("-q", "--lf") - assert os.path.exists(".pytest_cache/v/cache/lastfailed") - - def test_xfail_not_considered_failure(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail - def test(): - assert 0 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*1 xfailed*") - assert self.get_cached_last_failed(testdir) == [] - - def test_xfail_strict_considered_failure(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(strict=True) - def test(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*1 failed*") - assert ( - self.get_cached_last_failed(testdir) - == ["test_xfail_strict_considered_failure.py::test"] - ) - - @pytest.mark.parametrize("mark", ["mark.xfail", "mark.skip"]) - def test_failed_changed_to_xfail_or_skip(self, testdir, mark): - testdir.makepyfile( - """ - import pytest - def test(): - assert 0 - """ - ) - result = testdir.runpytest() - assert ( - self.get_cached_last_failed(testdir) - == ["test_failed_changed_to_xfail_or_skip.py::test"] - ) - assert result.ret == 1 - - testdir.makepyfile( - """ - import pytest - @pytest.{mark} - def test(): - assert 0 - """.format( - mark=mark - ) - ) - result = testdir.runpytest() - assert result.ret == 0 - assert self.get_cached_last_failed(testdir) == [] - assert result.ret == 0 - - def get_cached_last_failed(self, testdir): - config = testdir.parseconfigure() - return sorted(config.cache.get("cache/lastfailed", {})) - - def test_cache_cumulative(self, testdir): - """ - Test workflow where user fixes errors gradually file by file using --lf. - """ - # 1. initial run - test_bar = testdir.makepyfile( - test_bar=""" - def test_bar_1(): - pass - def test_bar_2(): - assert 0 - """ - ) - test_foo = testdir.makepyfile( - test_foo=""" - def test_foo_3(): - pass - def test_foo_4(): - assert 0 - """ - ) - testdir.runpytest() - assert ( - self.get_cached_last_failed(testdir) - == ["test_bar.py::test_bar_2", "test_foo.py::test_foo_4"] - ) - - # 2. fix test_bar_2, run only test_bar.py - testdir.makepyfile( - test_bar=""" - def test_bar_1(): - pass - def test_bar_2(): - pass - """ - ) - result = testdir.runpytest(test_bar) - result.stdout.fnmatch_lines("*2 passed*") - # ensure cache does not forget that test_foo_4 failed once before - assert self.get_cached_last_failed(testdir) == ["test_foo.py::test_foo_4"] - - result = testdir.runpytest("--last-failed") - result.stdout.fnmatch_lines("*1 failed, 3 deselected*") - assert self.get_cached_last_failed(testdir) == ["test_foo.py::test_foo_4"] - - # 3. fix test_foo_4, run only test_foo.py - test_foo = testdir.makepyfile( - test_foo=""" - def test_foo_3(): - pass - def test_foo_4(): - pass - """ - ) - result = testdir.runpytest(test_foo, "--last-failed") - result.stdout.fnmatch_lines("*1 passed, 1 deselected*") - assert self.get_cached_last_failed(testdir) == [] - - result = testdir.runpytest("--last-failed") - result.stdout.fnmatch_lines("*4 passed*") - assert self.get_cached_last_failed(testdir) == [] - - def test_lastfailed_no_failures_behavior_all_passed(self, testdir): - testdir.makepyfile( - """ - def test_1(): - assert True - def test_2(): - assert True - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 passed*"]) - result = testdir.runpytest("--lf") - result.stdout.fnmatch_lines(["*2 passed*"]) - result = testdir.runpytest("--lf", "--lfnf", "all") - result.stdout.fnmatch_lines(["*2 passed*"]) - result = testdir.runpytest("--lf", "--lfnf", "none") - result.stdout.fnmatch_lines(["*2 desel*"]) - - def test_lastfailed_no_failures_behavior_empty_cache(self, testdir): - testdir.makepyfile( - """ - def test_1(): - assert True - def test_2(): - assert False - """ - ) - result = testdir.runpytest("--lf", "--cache-clear") - result.stdout.fnmatch_lines(["*1 failed*1 passed*"]) - result = testdir.runpytest("--lf", "--cache-clear", "--lfnf", "all") - result.stdout.fnmatch_lines(["*1 failed*1 passed*"]) - result = testdir.runpytest("--lf", "--cache-clear", "--lfnf", "none") - result.stdout.fnmatch_lines(["*2 desel*"]) - - -class TestNewFirst(object): - - def test_newfirst_usecase(self, testdir): - testdir.makepyfile( - **{ - "test_1/test_1.py": """ - def test_1(): assert 1 - def test_2(): assert 1 - def test_3(): assert 1 - """, - "test_2/test_2.py": """ - def test_1(): assert 1 - def test_2(): assert 1 - def test_3(): assert 1 - """, - } - ) - - testdir.tmpdir.join("test_1/test_1.py").setmtime(1) - - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - [ - "*test_1/test_1.py::test_1 PASSED*", - "*test_1/test_1.py::test_2 PASSED*", - "*test_1/test_1.py::test_3 PASSED*", - "*test_2/test_2.py::test_1 PASSED*", - "*test_2/test_2.py::test_2 PASSED*", - "*test_2/test_2.py::test_3 PASSED*", - ] - ) - - result = testdir.runpytest("-v", "--nf") - - result.stdout.fnmatch_lines( - [ - "*test_2/test_2.py::test_1 PASSED*", - "*test_2/test_2.py::test_2 PASSED*", - "*test_2/test_2.py::test_3 PASSED*", - "*test_1/test_1.py::test_1 PASSED*", - "*test_1/test_1.py::test_2 PASSED*", - "*test_1/test_1.py::test_3 PASSED*", - ] - ) - - testdir.tmpdir.join("test_1/test_1.py").write( - "def test_1(): assert 1\n" - "def test_2(): assert 1\n" - "def test_3(): assert 1\n" - "def test_4(): assert 1\n" - ) - testdir.tmpdir.join("test_1/test_1.py").setmtime(1) - - result = testdir.runpytest("-v", "--nf") - - result.stdout.fnmatch_lines( - [ - "*test_1/test_1.py::test_4 PASSED*", - "*test_2/test_2.py::test_1 PASSED*", - "*test_2/test_2.py::test_2 PASSED*", - "*test_2/test_2.py::test_3 PASSED*", - "*test_1/test_1.py::test_1 PASSED*", - "*test_1/test_1.py::test_2 PASSED*", - "*test_1/test_1.py::test_3 PASSED*", - ] - ) - - def test_newfirst_parametrize(self, testdir): - testdir.makepyfile( - **{ - "test_1/test_1.py": """ - import pytest - @pytest.mark.parametrize('num', [1, 2]) - def test_1(num): assert num - """, - "test_2/test_2.py": """ - import pytest - @pytest.mark.parametrize('num', [1, 2]) - def test_1(num): assert num - """, - } - ) - - testdir.tmpdir.join("test_1/test_1.py").setmtime(1) - - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - [ - "*test_1/test_1.py::test_1[1*", - "*test_1/test_1.py::test_1[2*", - "*test_2/test_2.py::test_1[1*", - "*test_2/test_2.py::test_1[2*", - ] - ) - - result = testdir.runpytest("-v", "--nf") - - result.stdout.fnmatch_lines( - [ - "*test_2/test_2.py::test_1[1*", - "*test_2/test_2.py::test_1[2*", - "*test_1/test_1.py::test_1[1*", - "*test_1/test_1.py::test_1[2*", - ] - ) - - testdir.tmpdir.join("test_1/test_1.py").write( - "import pytest\n" - "@pytest.mark.parametrize('num', [1, 2, 3])\n" - "def test_1(num): assert num\n" - ) - testdir.tmpdir.join("test_1/test_1.py").setmtime(1) - - result = testdir.runpytest("-v", "--nf") - - result.stdout.fnmatch_lines( - [ - "*test_1/test_1.py::test_1[3*", - "*test_2/test_2.py::test_1[1*", - "*test_2/test_2.py::test_1[2*", - "*test_1/test_1.py::test_1[1*", - "*test_1/test_1.py::test_1[2*", - ] - ) diff --git a/third_party/python/pytest/testing/test_capture.py b/third_party/python/pytest/testing/test_capture.py deleted file mode 100644 index e14b3af78517..000000000000 --- a/third_party/python/pytest/testing/test_capture.py +++ /dev/null @@ -1,1394 +0,0 @@ -from __future__ import absolute_import, division, print_function - -# note: py.io capture tests where copied from -# pylib 1.4.20.dev2 (rev 13d9af95547e) -from __future__ import with_statement -import pickle -import os -import sys -from io import UnsupportedOperation - -import _pytest._code -import py -import pytest -import contextlib -from six import binary_type, text_type -from _pytest import capture -from _pytest.capture import CaptureManager -from _pytest.main import EXIT_NOTESTSCOLLECTED - - -needsosdup = pytest.mark.xfail("not hasattr(os, 'dup')") - - -def tobytes(obj): - if isinstance(obj, text_type): - obj = obj.encode("UTF-8") - assert isinstance(obj, binary_type) - return obj - - -def totext(obj): - if isinstance(obj, binary_type): - obj = text_type(obj, "UTF-8") - assert isinstance(obj, text_type) - return obj - - -def oswritebytes(fd, obj): - os.write(fd, tobytes(obj)) - - -def StdCaptureFD(out=True, err=True, in_=True): - return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture) - - -def StdCapture(out=True, err=True, in_=True): - return capture.MultiCapture(out, err, in_, Capture=capture.SysCapture) - - -class TestCaptureManager(object): - - def test_getmethod_default_no_fd(self, monkeypatch): - from _pytest.capture import pytest_addoption - from _pytest.config.argparsing import Parser - - parser = Parser() - pytest_addoption(parser) - default = parser._groups[0].options[0].default - assert default == "fd" if hasattr(os, "dup") else "sys" - parser = Parser() - monkeypatch.delattr(os, "dup", raising=False) - pytest_addoption(parser) - assert parser._groups[0].options[0].default == "sys" - - @needsosdup - @pytest.mark.parametrize( - "method", ["no", "sys", pytest.mark.skipif('not hasattr(os, "dup")', "fd")] - ) - def test_capturing_basic_api(self, method): - capouter = StdCaptureFD() - old = sys.stdout, sys.stderr, sys.stdin - try: - capman = CaptureManager(method) - capman.start_global_capturing() - outerr = capman.suspend_global_capture() - assert outerr == ("", "") - outerr = capman.suspend_global_capture() - assert outerr == ("", "") - print("hello") - out, err = capman.suspend_global_capture() - if method == "no": - assert old == (sys.stdout, sys.stderr, sys.stdin) - else: - assert not out - capman.resume_global_capture() - print("hello") - out, err = capman.suspend_global_capture() - if method != "no": - assert out == "hello\n" - capman.stop_global_capturing() - finally: - capouter.stop_capturing() - - @needsosdup - def test_init_capturing(self): - capouter = StdCaptureFD() - try: - capman = CaptureManager("fd") - capman.start_global_capturing() - pytest.raises(AssertionError, "capman.start_global_capturing()") - capman.stop_global_capturing() - finally: - capouter.stop_capturing() - - -@pytest.mark.parametrize("method", ["fd", "sys"]) -def test_capturing_unicode(testdir, method): - if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2, 2): - pytest.xfail("does not work on pypy < 2.2") - if sys.version_info >= (3, 0): - obj = "'b\u00f6y'" - else: - obj = "u'\u00f6y'" - testdir.makepyfile( - """ - # coding=utf8 - # taken from issue 227 from nosetests - def test_unicode(): - import sys - print (sys.stdout) - print (%s) - """ - % obj - ) - result = testdir.runpytest("--capture=%s" % method) - result.stdout.fnmatch_lines(["*1 passed*"]) - - -@pytest.mark.parametrize("method", ["fd", "sys"]) -def test_capturing_bytes_in_utf8_encoding(testdir, method): - testdir.makepyfile( - """ - def test_unicode(): - print ('b\\u00f6y') - """ - ) - result = testdir.runpytest("--capture=%s" % method) - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_collect_capturing(testdir): - p = testdir.makepyfile( - """ - print ("collect %s failure" % 13) - import xyz42123 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*Captured stdout*", "*collect 13 failure*"]) - - -class TestPerTestCapturing(object): - - def test_capture_and_fixtures(self, testdir): - p = testdir.makepyfile( - """ - def setup_module(mod): - print ("setup module") - def setup_function(function): - print ("setup " + function.__name__) - def test_func1(): - print ("in func1") - assert 0 - def test_func2(): - print ("in func2") - assert 0 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "setup module*", - "setup test_func1*", - "in func1*", - "setup test_func2*", - "in func2*", - ] - ) - - @pytest.mark.xfail(reason="unimplemented feature") - def test_capture_scope_cache(self, testdir): - p = testdir.makepyfile( - """ - import sys - def setup_module(func): - print ("module-setup") - def setup_function(func): - print ("function-setup") - def test_func(): - print ("in function") - assert 0 - def teardown_function(func): - print ("in teardown") - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "*test_func():*", - "*Captured stdout during setup*", - "module-setup*", - "function-setup*", - "*Captured stdout*", - "in teardown*", - ] - ) - - def test_no_carry_over(self, testdir): - p = testdir.makepyfile( - """ - def test_func1(): - print ("in func1") - def test_func2(): - print ("in func2") - assert 0 - """ - ) - result = testdir.runpytest(p) - s = result.stdout.str() - assert "in func1" not in s - assert "in func2" in s - - def test_teardown_capturing(self, testdir): - p = testdir.makepyfile( - """ - def setup_function(function): - print ("setup func1") - def teardown_function(function): - print ("teardown func1") - assert 0 - def test_func1(): - print ("in func1") - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "*teardown_function*", - "*Captured stdout*", - "setup func1*", - "in func1*", - "teardown func1*", - # "*1 fixture failure*" - ] - ) - - def test_teardown_capturing_final(self, testdir): - p = testdir.makepyfile( - """ - def teardown_module(mod): - print ("teardown module") - assert 0 - def test_func(): - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "*def teardown_module(mod):*", - "*Captured stdout*", - "*teardown module*", - "*1 error*", - ] - ) - - def test_capturing_outerr(self, testdir): - p1 = testdir.makepyfile( - """ - import sys - def test_capturing(): - print (42) - sys.stderr.write(str(23)) - def test_capturing_error(): - print (1) - sys.stderr.write(str(2)) - raise ValueError - """ - ) - result = testdir.runpytest(p1) - result.stdout.fnmatch_lines( - [ - "*test_capturing_outerr.py .F*", - "====* FAILURES *====", - "____*____", - "*test_capturing_outerr.py:8: ValueError", - "*--- Captured stdout *call*", - "1", - "*--- Captured stderr *call*", - "2", - ] - ) - - -class TestLoggingInteraction(object): - - def test_logging_stream_ownership(self, testdir): - p = testdir.makepyfile( - """ - def test_logging(): - import logging - import pytest - stream = capture.CaptureIO() - logging.basicConfig(stream=stream) - stream.close() # to free memory/release resources - """ - ) - result = testdir.runpytest_subprocess(p) - assert result.stderr.str().find("atexit") == -1 - - def test_logging_and_immediate_setupteardown(self, testdir): - p = testdir.makepyfile( - """ - import logging - def setup_function(function): - logging.warn("hello1") - - def test_logging(): - logging.warn("hello2") - assert 0 - - def teardown_function(function): - logging.warn("hello3") - assert 0 - """ - ) - for optargs in (("--capture=sys",), ("--capture=fd",)): - print(optargs) - result = testdir.runpytest_subprocess(p, *optargs) - s = result.stdout.str() - result.stdout.fnmatch_lines( - ["*WARN*hello3", "*WARN*hello1", "*WARN*hello2"] # errors show first! - ) - # verify proper termination - assert "closed" not in s - - def test_logging_and_crossscope_fixtures(self, testdir): - p = testdir.makepyfile( - """ - import logging - def setup_module(function): - logging.warn("hello1") - - def test_logging(): - logging.warn("hello2") - assert 0 - - def teardown_module(function): - logging.warn("hello3") - assert 0 - """ - ) - for optargs in (("--capture=sys",), ("--capture=fd",)): - print(optargs) - result = testdir.runpytest_subprocess(p, *optargs) - s = result.stdout.str() - result.stdout.fnmatch_lines( - ["*WARN*hello3", "*WARN*hello1", "*WARN*hello2"] # errors come first - ) - # verify proper termination - assert "closed" not in s - - def test_conftestlogging_is_shown(self, testdir): - testdir.makeconftest( - """ - import logging - logging.basicConfig() - logging.warn("hello435") - """ - ) - # make sure that logging is still captured in tests - result = testdir.runpytest_subprocess("-s", "-p", "no:capturelog") - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stderr.fnmatch_lines(["WARNING*hello435*"]) - assert "operation on closed file" not in result.stderr.str() - - def test_conftestlogging_and_test_logging(self, testdir): - testdir.makeconftest( - """ - import logging - logging.basicConfig() - """ - ) - # make sure that logging is still captured in tests - p = testdir.makepyfile( - """ - def test_hello(): - import logging - logging.warn("hello433") - assert 0 - """ - ) - result = testdir.runpytest_subprocess(p, "-p", "no:capturelog") - assert result.ret != 0 - result.stdout.fnmatch_lines(["WARNING*hello433*"]) - assert "something" not in result.stderr.str() - assert "operation on closed file" not in result.stderr.str() - - -class TestCaptureFixture(object): - - @pytest.mark.parametrize("opt", [[], ["-s"]]) - def test_std_functional(self, testdir, opt): - reprec = testdir.inline_runsource( - """ - def test_hello(capsys): - print (42) - out, err = capsys.readouterr() - assert out.startswith("42") - """, - *opt - ) - reprec.assertoutcome(passed=1) - - def test_capsyscapfd(self, testdir): - p = testdir.makepyfile( - """ - def test_one(capsys, capfd): - pass - def test_two(capfd, capsys): - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "*ERROR*setup*test_one*", - "E*capfd*capsys*same*time*", - "*ERROR*setup*test_two*", - "E*capsys*capfd*same*time*", - "*2 error*", - ] - ) - - def test_capturing_getfixturevalue(self, testdir): - """Test that asking for "capfd" and "capsys" using request.getfixturevalue - in the same test is an error. - """ - testdir.makepyfile( - """ - def test_one(capsys, request): - request.getfixturevalue("capfd") - def test_two(capfd, request): - request.getfixturevalue("capsys") - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*test_one*", - "*capsys*capfd*same*time*", - "*test_two*", - "*capfd*capsys*same*time*", - "*2 failed in*", - ] - ) - - def test_capsyscapfdbinary(self, testdir): - p = testdir.makepyfile( - """ - def test_one(capsys, capfdbinary): - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - ["*ERROR*setup*test_one*", "E*capfdbinary*capsys*same*time*", "*1 error*"] - ) - - @pytest.mark.parametrize("method", ["sys", "fd"]) - def test_capture_is_represented_on_failure_issue128(self, testdir, method): - p = testdir.makepyfile( - """ - def test_hello(cap%s): - print ("xxx42xxx") - assert 0 - """ - % method - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["xxx42xxx"]) - - @needsosdup - def test_stdfd_functional(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_hello(capfd): - import os - os.write(1, "42".encode('ascii')) - out, err = capfd.readouterr() - assert out.startswith("42") - capfd.close() - """ - ) - reprec.assertoutcome(passed=1) - - @needsosdup - def test_capfdbinary(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_hello(capfdbinary): - import os - # some likely un-decodable bytes - os.write(1, b'\\xfe\\x98\\x20') - out, err = capfdbinary.readouterr() - assert out == b'\\xfe\\x98\\x20' - assert err == b'' - """ - ) - reprec.assertoutcome(passed=1) - - @pytest.mark.skipif( - sys.version_info < (3,), reason="only have capsysbinary in python 3" - ) - def test_capsysbinary(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_hello(capsysbinary): - import sys - # some likely un-decodable bytes - sys.stdout.buffer.write(b'\\xfe\\x98\\x20') - out, err = capsysbinary.readouterr() - assert out == b'\\xfe\\x98\\x20' - assert err == b'' - """ - ) - reprec.assertoutcome(passed=1) - - @pytest.mark.skipif( - sys.version_info >= (3,), reason="only have capsysbinary in python 3" - ) - def test_capsysbinary_forbidden_in_python2(self, testdir): - testdir.makepyfile( - """ - def test_hello(capsysbinary): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*test_hello*", - "*capsysbinary is only supported on python 3*", - "*1 error in*", - ] - ) - - def test_partial_setup_failure(self, testdir): - p = testdir.makepyfile( - """ - def test_hello(capsys, missingarg): - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*test_partial_setup_failure*", "*1 error*"]) - - @needsosdup - def test_keyboardinterrupt_disables_capturing(self, testdir): - p = testdir.makepyfile( - """ - def test_hello(capfd): - import os - os.write(1, str(42).encode('ascii')) - raise KeyboardInterrupt() - """ - ) - result = testdir.runpytest_subprocess(p) - result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) - assert result.ret == 2 - - @pytest.mark.issue14 - def test_capture_and_logging(self, testdir): - p = testdir.makepyfile( - """ - import logging - def test_log(capsys): - logging.error('x') - """ - ) - result = testdir.runpytest_subprocess(p) - assert "closed" not in result.stderr.str() - - @pytest.mark.parametrize("fixture", ["capsys", "capfd"]) - @pytest.mark.parametrize("no_capture", [True, False]) - def test_disabled_capture_fixture(self, testdir, fixture, no_capture): - testdir.makepyfile( - """ - def test_disabled({fixture}): - print('captured before') - with {fixture}.disabled(): - print('while capture is disabled') - print('captured after') - assert {fixture}.readouterr() == ('captured before\\ncaptured after\\n', '') - - def test_normal(): - print('test_normal executed') - """.format( - fixture=fixture - ) - ) - args = ("-s",) if no_capture else () - result = testdir.runpytest_subprocess(*args) - result.stdout.fnmatch_lines( - """ - *while capture is disabled* - """ - ) - assert "captured before" not in result.stdout.str() - assert "captured after" not in result.stdout.str() - if no_capture: - assert "test_normal executed" in result.stdout.str() - else: - assert "test_normal executed" not in result.stdout.str() - - @pytest.mark.parametrize("fixture", ["capsys", "capfd"]) - def test_fixture_use_by_other_fixtures(self, testdir, fixture): - """ - Ensure that capsys and capfd can be used by other fixtures during setup and teardown. - """ - testdir.makepyfile( - """ - from __future__ import print_function - import sys - import pytest - - @pytest.fixture - def captured_print({fixture}): - print('stdout contents begin') - print('stderr contents begin', file=sys.stderr) - out, err = {fixture}.readouterr() - - yield out, err - - print('stdout contents end') - print('stderr contents end', file=sys.stderr) - out, err = {fixture}.readouterr() - assert out == 'stdout contents end\\n' - assert err == 'stderr contents end\\n' - - def test_captured_print(captured_print): - out, err = captured_print - assert out == 'stdout contents begin\\n' - assert err == 'stderr contents begin\\n' - """.format( - fixture=fixture - ) - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines("*1 passed*") - assert "stdout contents begin" not in result.stdout.str() - assert "stderr contents begin" not in result.stdout.str() - - -def test_setup_failure_does_not_kill_capturing(testdir): - sub1 = testdir.mkpydir("sub1") - sub1.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_runtest_setup(item): - raise ValueError(42) - """ - ) - ) - sub1.join("test_mod.py").write("def test_func1(): pass") - result = testdir.runpytest(testdir.tmpdir, "--traceconfig") - result.stdout.fnmatch_lines(["*ValueError(42)*", "*1 error*"]) - - -def test_fdfuncarg_skips_on_no_osdup(testdir): - testdir.makepyfile( - """ - import os - if hasattr(os, 'dup'): - del os.dup - def test_hello(capfd): - pass - """ - ) - result = testdir.runpytest_subprocess("--capture=no") - result.stdout.fnmatch_lines(["*1 skipped*"]) - - -def test_capture_conftest_runtest_setup(testdir): - testdir.makeconftest( - """ - def pytest_runtest_setup(): - print ("hello19") - """ - ) - testdir.makepyfile("def test_func(): pass") - result = testdir.runpytest() - assert result.ret == 0 - assert "hello19" not in result.stdout.str() - - -def test_capture_badoutput_issue412(testdir): - testdir.makepyfile( - """ - import os - - def test_func(): - omg = bytearray([1,129,1]) - os.write(1, omg) - assert 0 - """ - ) - result = testdir.runpytest("--cap=fd") - result.stdout.fnmatch_lines( - """ - *def test_func* - *assert 0* - *Captured* - *1 failed* - """ - ) - - -def test_capture_early_option_parsing(testdir): - testdir.makeconftest( - """ - def pytest_runtest_setup(): - print ("hello19") - """ - ) - testdir.makepyfile("def test_func(): pass") - result = testdir.runpytest("-vs") - assert result.ret == 0 - assert "hello19" in result.stdout.str() - - -def test_capture_binary_output(testdir): - testdir.makepyfile( - r""" - import pytest - - def test_a(): - import sys - import subprocess - subprocess.call([sys.executable, __file__]) - - def test_foo(): - import os;os.write(1, b'\xc3') - - if __name__ == '__main__': - test_foo() - """ - ) - result = testdir.runpytest("--assert=plain") - result.assert_outcomes(passed=2) - - -def test_error_during_readouterr(testdir): - """Make sure we suspend capturing if errors occur during readouterr""" - testdir.makepyfile( - pytest_xyz=""" - from _pytest.capture import FDCapture - def bad_snap(self): - raise Exception('boom') - assert FDCapture.snap - FDCapture.snap = bad_snap - """ - ) - result = testdir.runpytest_subprocess( - "-p", "pytest_xyz", "--version", syspathinsert=True - ) - result.stderr.fnmatch_lines( - ["*in bad_snap", " raise Exception('boom')", "Exception: boom"] - ) - - -class TestCaptureIO(object): - - def test_text(self): - f = capture.CaptureIO() - f.write("hello") - s = f.getvalue() - assert s == "hello" - f.close() - - def test_unicode_and_str_mixture(self): - f = capture.CaptureIO() - if sys.version_info >= (3, 0): - f.write("\u00f6") - pytest.raises(TypeError, "f.write(bytes('hello', 'UTF-8'))") - else: - f.write(text_type("\u00f6", "UTF-8")) - f.write("hello") # bytes - s = f.getvalue() - f.close() - assert isinstance(s, text_type) - - @pytest.mark.skipif(sys.version_info[0] == 2, reason="python 3 only behaviour") - def test_write_bytes_to_buffer(self): - """In python3, stdout / stderr are text io wrappers (exposing a buffer - property of the underlying bytestream). See issue #1407 - """ - f = capture.CaptureIO() - f.buffer.write(b"foo\r\n") - assert f.getvalue() == "foo\r\n" - - -def test_bytes_io(): - f = py.io.BytesIO() - f.write(tobytes("hello")) - pytest.raises(TypeError, "f.write(totext('hello'))") - s = f.getvalue() - assert s == tobytes("hello") - - -def test_dontreadfrominput(): - from _pytest.capture import DontReadFromInput - - f = DontReadFromInput() - assert not f.isatty() - pytest.raises(IOError, f.read) - pytest.raises(IOError, f.readlines) - iter_f = iter(f) - pytest.raises(IOError, next, iter_f) - pytest.raises(UnsupportedOperation, f.fileno) - f.close() # just for completeness - - -@pytest.mark.skipif("sys.version_info < (3,)", reason="python2 has no buffer") -def test_dontreadfrominput_buffer_python3(): - from _pytest.capture import DontReadFromInput - - f = DontReadFromInput() - fb = f.buffer - assert not fb.isatty() - pytest.raises(IOError, fb.read) - pytest.raises(IOError, fb.readlines) - iter_f = iter(f) - pytest.raises(IOError, next, iter_f) - pytest.raises(ValueError, fb.fileno) - f.close() # just for completeness - - -@pytest.mark.skipif("sys.version_info >= (3,)", reason="python2 has no buffer") -def test_dontreadfrominput_buffer_python2(): - from _pytest.capture import DontReadFromInput - - f = DontReadFromInput() - with pytest.raises(AttributeError): - f.buffer - f.close() # just for completeness - - -@pytest.yield_fixture -def tmpfile(testdir): - f = testdir.makepyfile("").open("wb+") - yield f - if not f.closed: - f.close() - - -@needsosdup -def test_dupfile(tmpfile): - flist = [] - for i in range(5): - nf = capture.safe_text_dupfile(tmpfile, "wb") - assert nf != tmpfile - assert nf.fileno() != tmpfile.fileno() - assert nf not in flist - print(i, end="", file=nf) - flist.append(nf) - - fname_open = flist[0].name - assert fname_open == repr(flist[0].buffer) - - for i in range(5): - f = flist[i] - f.close() - fname_closed = flist[0].name - assert fname_closed == repr(flist[0].buffer) - assert fname_closed != fname_open - tmpfile.seek(0) - s = tmpfile.read() - assert "01234" in repr(s) - tmpfile.close() - assert fname_closed == repr(flist[0].buffer) - - -def test_dupfile_on_bytesio(): - io = py.io.BytesIO() - f = capture.safe_text_dupfile(io, "wb") - f.write("hello") - assert io.getvalue() == b"hello" - assert "BytesIO object" in f.name - - -def test_dupfile_on_textio(): - io = py.io.TextIO() - f = capture.safe_text_dupfile(io, "wb") - f.write("hello") - assert io.getvalue() == "hello" - assert not hasattr(f, "name") - - -@contextlib.contextmanager -def lsof_check(): - pid = os.getpid() - try: - out = py.process.cmdexec("lsof -p %d" % pid) - except (py.process.cmdexec.Error, UnicodeDecodeError): - # about UnicodeDecodeError, see note on pytester - pytest.skip("could not run 'lsof'") - yield - out2 = py.process.cmdexec("lsof -p %d" % pid) - len1 = len([x for x in out.split("\n") if "REG" in x]) - len2 = len([x for x in out2.split("\n") if "REG" in x]) - assert len2 < len1 + 3, out2 - - -class TestFDCapture(object): - pytestmark = needsosdup - - def test_simple(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd) - data = tobytes("hello") - os.write(fd, data) - s = cap.snap() - cap.done() - assert not s - cap = capture.FDCapture(fd) - cap.start() - os.write(fd, data) - s = cap.snap() - cap.done() - assert s == "hello" - - def test_simple_many(self, tmpfile): - for i in range(10): - self.test_simple(tmpfile) - - def test_simple_many_check_open_files(self, testdir): - with lsof_check(): - with testdir.makepyfile("").open("wb+") as tmpfile: - self.test_simple_many(tmpfile) - - def test_simple_fail_second_start(self, tmpfile): - fd = tmpfile.fileno() - cap = capture.FDCapture(fd) - cap.done() - pytest.raises(ValueError, cap.start) - - def test_stderr(self): - cap = capture.FDCapture(2) - cap.start() - print("hello", file=sys.stderr) - s = cap.snap() - cap.done() - assert s == "hello\n" - - def test_stdin(self, tmpfile): - cap = capture.FDCapture(0) - cap.start() - x = os.read(0, 100).strip() - cap.done() - assert x == tobytes("") - - def test_writeorg(self, tmpfile): - data1, data2 = tobytes("foo"), tobytes("bar") - cap = capture.FDCapture(tmpfile.fileno()) - cap.start() - tmpfile.write(data1) - tmpfile.flush() - cap.writeorg(data2) - scap = cap.snap() - cap.done() - assert scap == totext(data1) - with open(tmpfile.name, "rb") as stmp_file: - stmp = stmp_file.read() - assert stmp == data2 - - def test_simple_resume_suspend(self, tmpfile): - with saved_fd(1): - cap = capture.FDCapture(1) - cap.start() - data = tobytes("hello") - os.write(1, data) - sys.stdout.write("whatever") - s = cap.snap() - assert s == "hellowhatever" - cap.suspend() - os.write(1, tobytes("world")) - sys.stdout.write("qlwkej") - assert not cap.snap() - cap.resume() - os.write(1, tobytes("but now")) - sys.stdout.write(" yes\n") - s = cap.snap() - assert s == "but now yes\n" - cap.suspend() - cap.done() - pytest.raises(AttributeError, cap.suspend) - - -@contextlib.contextmanager -def saved_fd(fd): - new_fd = os.dup(fd) - try: - yield - finally: - os.dup2(new_fd, fd) - os.close(new_fd) - - -class TestStdCapture(object): - captureclass = staticmethod(StdCapture) - - @contextlib.contextmanager - def getcapture(self, **kw): - cap = self.__class__.captureclass(**kw) - cap.start_capturing() - try: - yield cap - finally: - cap.stop_capturing() - - def test_capturing_done_simple(self): - with self.getcapture() as cap: - sys.stdout.write("hello") - sys.stderr.write("world") - out, err = cap.readouterr() - assert out == "hello" - assert err == "world" - - def test_capturing_reset_simple(self): - with self.getcapture() as cap: - print("hello world") - sys.stderr.write("hello error\n") - out, err = cap.readouterr() - assert out == "hello world\n" - assert err == "hello error\n" - - def test_capturing_readouterr(self): - with self.getcapture() as cap: - print("hello world") - sys.stderr.write("hello error\n") - out, err = cap.readouterr() - assert out == "hello world\n" - assert err == "hello error\n" - sys.stderr.write("error2") - out, err = cap.readouterr() - assert err == "error2" - - def test_capture_results_accessible_by_attribute(self): - with self.getcapture() as cap: - sys.stdout.write("hello") - sys.stderr.write("world") - capture_result = cap.readouterr() - assert capture_result.out == "hello" - assert capture_result.err == "world" - - def test_capturing_readouterr_unicode(self): - with self.getcapture() as cap: - print("hx\xc4\x85\xc4\x87") - out, err = cap.readouterr() - assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8") - - @pytest.mark.skipif( - "sys.version_info >= (3,)", reason="text output different for bytes on python3" - ) - def test_capturing_readouterr_decode_error_handling(self): - with self.getcapture() as cap: - # triggered an internal error in pytest - print("\xa6") - out, err = cap.readouterr() - assert out == py.builtin._totext("\ufffd\n", "unicode-escape") - - def test_reset_twice_error(self): - with self.getcapture() as cap: - print("hello") - out, err = cap.readouterr() - pytest.raises(ValueError, cap.stop_capturing) - assert out == "hello\n" - assert not err - - def test_capturing_modify_sysouterr_in_between(self): - oldout = sys.stdout - olderr = sys.stderr - with self.getcapture() as cap: - sys.stdout.write("hello") - sys.stderr.write("world") - sys.stdout = capture.CaptureIO() - sys.stderr = capture.CaptureIO() - print("not seen") - sys.stderr.write("not seen\n") - out, err = cap.readouterr() - assert out == "hello" - assert err == "world" - assert sys.stdout == oldout - assert sys.stderr == olderr - - def test_capturing_error_recursive(self): - with self.getcapture() as cap1: - print("cap1") - with self.getcapture() as cap2: - print("cap2") - out2, err2 = cap2.readouterr() - out1, err1 = cap1.readouterr() - assert out1 == "cap1\n" - assert out2 == "cap2\n" - - def test_just_out_capture(self): - with self.getcapture(out=True, err=False) as cap: - sys.stdout.write("hello") - sys.stderr.write("world") - out, err = cap.readouterr() - assert out == "hello" - assert not err - - def test_just_err_capture(self): - with self.getcapture(out=False, err=True) as cap: - sys.stdout.write("hello") - sys.stderr.write("world") - out, err = cap.readouterr() - assert err == "world" - assert not out - - def test_stdin_restored(self): - old = sys.stdin - with self.getcapture(in_=True): - newstdin = sys.stdin - assert newstdin != sys.stdin - assert sys.stdin is old - - def test_stdin_nulled_by_default(self): - print("XXX this test may well hang instead of crashing") - print("XXX which indicates an error in the underlying capturing") - print("XXX mechanisms") - with self.getcapture(): - pytest.raises(IOError, "sys.stdin.read()") - - -class TestStdCaptureFD(TestStdCapture): - pytestmark = needsosdup - captureclass = staticmethod(StdCaptureFD) - - def test_simple_only_fd(self, testdir): - testdir.makepyfile( - """ - import os - def test_x(): - os.write(1, "hello\\n".encode("ascii")) - assert 0 - """ - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines( - """ - *test_x* - *assert 0* - *Captured stdout* - """ - ) - - def test_intermingling(self): - with self.getcapture() as cap: - oswritebytes(1, "1") - sys.stdout.write(str(2)) - sys.stdout.flush() - oswritebytes(1, "3") - oswritebytes(2, "a") - sys.stderr.write("b") - sys.stderr.flush() - oswritebytes(2, "c") - out, err = cap.readouterr() - assert out == "123" - assert err == "abc" - - def test_many(self, capfd): - with lsof_check(): - for i in range(10): - cap = StdCaptureFD() - cap.stop_capturing() - - -class TestStdCaptureFDinvalidFD(object): - pytestmark = needsosdup - - def test_stdcapture_fd_invalid_fd(self, testdir): - testdir.makepyfile( - """ - import os - from _pytest import capture - def StdCaptureFD(out=True, err=True, in_=True): - return capture.MultiCapture(out, err, in_, - Capture=capture.FDCapture) - def test_stdout(): - os.close(1) - cap = StdCaptureFD(out=True, err=False, in_=False) - cap.stop_capturing() - def test_stderr(): - os.close(2) - cap = StdCaptureFD(out=False, err=True, in_=False) - cap.stop_capturing() - def test_stdin(): - os.close(0) - cap = StdCaptureFD(out=False, err=False, in_=True) - cap.stop_capturing() - """ - ) - result = testdir.runpytest_subprocess("--capture=fd") - assert result.ret == 0 - assert result.parseoutcomes()["passed"] == 3 - - -def test_capture_not_started_but_reset(): - capsys = StdCapture() - capsys.stop_capturing() - - -def test_using_capsys_fixture_works_with_sys_stdout_encoding(capsys): - test_text = "test text" - - print(test_text.encode(sys.stdout.encoding, "replace")) - (out, err) = capsys.readouterr() - assert out - assert err == "" - - -def test_capsys_results_accessible_by_attribute(capsys): - sys.stdout.write("spam") - sys.stderr.write("eggs") - capture_result = capsys.readouterr() - assert capture_result.out == "spam" - assert capture_result.err == "eggs" - - -@needsosdup -@pytest.mark.parametrize("use", [True, False]) -def test_fdcapture_tmpfile_remains_the_same(tmpfile, use): - if not use: - tmpfile = True - cap = StdCaptureFD(out=False, err=tmpfile) - try: - cap.start_capturing() - capfile = cap.err.tmpfile - cap.readouterr() - finally: - cap.stop_capturing() - capfile2 = cap.err.tmpfile - assert capfile2 == capfile - - -@needsosdup -def test_close_and_capture_again(testdir): - testdir.makepyfile( - """ - import os - def test_close(): - os.close(1) - def test_capture_again(): - os.write(1, b"hello\\n") - assert 0 - """ - ) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines( - """ - *test_capture_again* - *assert 0* - *stdout* - *hello* - """ - ) - - -@pytest.mark.parametrize("method", ["SysCapture", "FDCapture"]) -def test_capturing_and_logging_fundamentals(testdir, method): - if method == "StdCaptureFD" and not hasattr(os, "dup"): - pytest.skip("need os.dup") - # here we check a fundamental feature - p = testdir.makepyfile( - """ - import sys, os - import py, logging - from _pytest import capture - cap = capture.MultiCapture(out=False, in_=False, - Capture=capture.%s) - cap.start_capturing() - - logging.warn("hello1") - outerr = cap.readouterr() - print ("suspend, captured %%s" %%(outerr,)) - logging.warn("hello2") - - cap.pop_outerr_to_orig() - logging.warn("hello3") - - outerr = cap.readouterr() - print ("suspend2, captured %%s" %% (outerr,)) - """ - % (method,) - ) - result = testdir.runpython(p) - result.stdout.fnmatch_lines( - """ - suspend, captured*hello1* - suspend2, captured*WARNING:root:hello3* - """ - ) - result.stderr.fnmatch_lines( - """ - WARNING:root:hello2 - """ - ) - assert "atexit" not in result.stderr.str() - - -def test_error_attribute_issue555(testdir): - testdir.makepyfile( - """ - import sys - def test_capattr(): - assert sys.stdout.errors == "strict" - assert sys.stderr.errors == "strict" - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -@pytest.mark.skipif( - not sys.platform.startswith("win") and sys.version_info[:2] >= (3, 6), - reason="only py3.6+ on windows", -) -def test_py36_windowsconsoleio_workaround_non_standard_streams(): - """ - Ensure _py36_windowsconsoleio_workaround function works with objects that - do not implement the full ``io``-based stream protocol, for example execnet channels (#2666). - """ - from _pytest.capture import _py36_windowsconsoleio_workaround - - class DummyStream(object): - - def write(self, s): - pass - - stream = DummyStream() - _py36_windowsconsoleio_workaround(stream) - - -def test_dontreadfrominput_has_encoding(testdir): - testdir.makepyfile( - """ - import sys - def test_capattr(): - # should not raise AttributeError - assert sys.stdout.encoding - assert sys.stderr.encoding - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -def test_crash_on_closing_tmpfile_py27(testdir): - testdir.makepyfile( - """ - from __future__ import print_function - import time - import threading - import sys - - def spam(): - f = sys.stderr - while True: - print('.', end='', file=f) - - def test_silly(): - t = threading.Thread(target=spam) - t.daemon = True - t.start() - time.sleep(0.5) - - """ - ) - result = testdir.runpytest_subprocess() - assert result.ret == 0 - assert "IOError" not in result.stdout.str() - - -def test_pickling_and_unpickling_encoded_file(): - # See https://bitbucket.org/pytest-dev/pytest/pull-request/194 - # pickle.loads() raises infinite recursion if - # EncodedFile.__getattr__ is not implemented properly - ef = capture.EncodedFile(None, None) - ef_as_str = pickle.dumps(ef) - pickle.loads(ef_as_str) diff --git a/third_party/python/pytest/testing/test_collection.py b/third_party/python/pytest/testing/test_collection.py deleted file mode 100644 index 657d64c74e24..000000000000 --- a/third_party/python/pytest/testing/test_collection.py +++ /dev/null @@ -1,944 +0,0 @@ -from __future__ import absolute_import, division, print_function -import pprint -import sys -import pytest - -import _pytest._code -from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv - - -class TestCollector(object): - - def test_collect_versus_item(self): - from pytest import Collector, Item - - assert not issubclass(Collector, Item) - assert not issubclass(Item, Collector) - - def test_compat_attributes(self, testdir, recwarn): - modcol = testdir.getmodulecol( - """ - def test_pass(): pass - def test_fail(): assert 0 - """ - ) - recwarn.clear() - assert modcol.Module == pytest.Module - assert modcol.Class == pytest.Class - assert modcol.Item == pytest.Item - assert modcol.File == pytest.File - assert modcol.Function == pytest.Function - - def test_check_equality(self, testdir): - modcol = testdir.getmodulecol( - """ - def test_pass(): pass - def test_fail(): assert 0 - """ - ) - fn1 = testdir.collect_by_name(modcol, "test_pass") - assert isinstance(fn1, pytest.Function) - fn2 = testdir.collect_by_name(modcol, "test_pass") - assert isinstance(fn2, pytest.Function) - - assert fn1 == fn2 - assert fn1 != modcol - if sys.version_info < (3, 0): - assert cmp(fn1, fn2) == 0 # NOQA - assert hash(fn1) == hash(fn2) - - fn3 = testdir.collect_by_name(modcol, "test_fail") - assert isinstance(fn3, pytest.Function) - assert not (fn1 == fn3) - assert fn1 != fn3 - - for fn in fn1, fn2, fn3: - assert fn != 3 - assert fn != modcol - assert fn != [1, 2, 3] - assert [1, 2, 3] != fn - assert modcol != fn - - def test_getparent(self, testdir): - modcol = testdir.getmodulecol( - """ - class TestClass(object): - def test_foo(): - pass - """ - ) - cls = testdir.collect_by_name(modcol, "TestClass") - fn = testdir.collect_by_name(testdir.collect_by_name(cls, "()"), "test_foo") - - parent = fn.getparent(pytest.Module) - assert parent is modcol - - parent = fn.getparent(pytest.Function) - assert parent is fn - - parent = fn.getparent(pytest.Class) - assert parent is cls - - def test_getcustomfile_roundtrip(self, testdir): - hello = testdir.makefile(".xxx", hello="world") - testdir.makepyfile( - conftest=""" - import pytest - class CustomFile(pytest.File): - pass - def pytest_collect_file(path, parent): - if path.ext == ".xxx": - return CustomFile(path, parent=parent) - """ - ) - node = testdir.getpathnode(hello) - assert isinstance(node, pytest.File) - assert node.name == "hello.xxx" - nodes = node.session.perform_collect([node.nodeid], genitems=False) - assert len(nodes) == 1 - assert isinstance(nodes[0], pytest.File) - - def test_can_skip_class_with_test_attr(self, testdir): - """Assure test class is skipped when using `__test__=False` (See #2007).""" - testdir.makepyfile( - """ - class TestFoo(object): - __test__ = False - def __init__(self): - pass - def test_foo(): - assert True - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["collected 0 items", "*no tests ran in*"]) - - -class TestCollectFS(object): - - def test_ignored_certain_directories(self, testdir): - tmpdir = testdir.tmpdir - tmpdir.ensure("build", "test_notfound.py") - tmpdir.ensure("dist", "test_notfound.py") - tmpdir.ensure("_darcs", "test_notfound.py") - tmpdir.ensure("CVS", "test_notfound.py") - tmpdir.ensure("{arch}", "test_notfound.py") - tmpdir.ensure(".whatever", "test_notfound.py") - tmpdir.ensure(".bzr", "test_notfound.py") - tmpdir.ensure("normal", "test_found.py") - for x in tmpdir.visit("test_*.py"): - x.write("def test_hello(): pass") - - result = testdir.runpytest("--collect-only") - s = result.stdout.str() - assert "test_notfound" not in s - assert "test_found" in s - - @pytest.mark.parametrize( - "fname", - ( - "activate", - "activate.csh", - "activate.fish", - "Activate", - "Activate.bat", - "Activate.ps1", - ), - ) - def test_ignored_virtualenvs(self, testdir, fname): - bindir = "Scripts" if sys.platform.startswith("win") else "bin" - testdir.tmpdir.ensure("virtual", bindir, fname) - testfile = testdir.tmpdir.ensure("virtual", "test_invenv.py") - testfile.write("def test_hello(): pass") - - # by default, ignore tests inside a virtualenv - result = testdir.runpytest() - assert "test_invenv" not in result.stdout.str() - # allow test collection if user insists - result = testdir.runpytest("--collect-in-virtualenv") - assert "test_invenv" in result.stdout.str() - # allow test collection if user directly passes in the directory - result = testdir.runpytest("virtual") - assert "test_invenv" in result.stdout.str() - - @pytest.mark.parametrize( - "fname", - ( - "activate", - "activate.csh", - "activate.fish", - "Activate", - "Activate.bat", - "Activate.ps1", - ), - ) - def test_ignored_virtualenvs_norecursedirs_precedence(self, testdir, fname): - bindir = "Scripts" if sys.platform.startswith("win") else "bin" - # norecursedirs takes priority - testdir.tmpdir.ensure(".virtual", bindir, fname) - testfile = testdir.tmpdir.ensure(".virtual", "test_invenv.py") - testfile.write("def test_hello(): pass") - result = testdir.runpytest("--collect-in-virtualenv") - assert "test_invenv" not in result.stdout.str() - # ...unless the virtualenv is explicitly given on the CLI - result = testdir.runpytest("--collect-in-virtualenv", ".virtual") - assert "test_invenv" in result.stdout.str() - - @pytest.mark.parametrize( - "fname", - ( - "activate", - "activate.csh", - "activate.fish", - "Activate", - "Activate.bat", - "Activate.ps1", - ), - ) - def test__in_venv(self, testdir, fname): - """Directly test the virtual env detection function""" - bindir = "Scripts" if sys.platform.startswith("win") else "bin" - # no bin/activate, not a virtualenv - base_path = testdir.tmpdir.mkdir("venv") - assert _in_venv(base_path) is False - # with bin/activate, totally a virtualenv - base_path.ensure(bindir, fname) - assert _in_venv(base_path) is True - - def test_custom_norecursedirs(self, testdir): - testdir.makeini( - """ - [pytest] - norecursedirs = mydir xyz* - """ - ) - tmpdir = testdir.tmpdir - tmpdir.ensure("mydir", "test_hello.py").write("def test_1(): pass") - tmpdir.ensure("xyz123", "test_2.py").write("def test_2(): 0/0") - tmpdir.ensure("xy", "test_ok.py").write("def test_3(): pass") - rec = testdir.inline_run() - rec.assertoutcome(passed=1) - rec = testdir.inline_run("xyz123/test_2.py") - rec.assertoutcome(failed=1) - - def test_testpaths_ini(self, testdir, monkeypatch): - testdir.makeini( - """ - [pytest] - testpaths = gui uts - """ - ) - tmpdir = testdir.tmpdir - tmpdir.ensure("env", "test_1.py").write("def test_env(): pass") - tmpdir.ensure("gui", "test_2.py").write("def test_gui(): pass") - tmpdir.ensure("uts", "test_3.py").write("def test_uts(): pass") - - # executing from rootdir only tests from `testpaths` directories - # are collected - items, reprec = testdir.inline_genitems("-v") - assert [x.name for x in items] == ["test_gui", "test_uts"] - - # check that explicitly passing directories in the command-line - # collects the tests - for dirname in ("env", "gui", "uts"): - items, reprec = testdir.inline_genitems(tmpdir.join(dirname)) - assert [x.name for x in items] == ["test_%s" % dirname] - - # changing cwd to each subdirectory and running pytest without - # arguments collects the tests in that directory normally - for dirname in ("env", "gui", "uts"): - monkeypatch.chdir(testdir.tmpdir.join(dirname)) - items, reprec = testdir.inline_genitems() - assert [x.name for x in items] == ["test_%s" % dirname] - - -class TestCollectPluginHookRelay(object): - - def test_pytest_collect_file(self, testdir): - wascalled = [] - - class Plugin(object): - - def pytest_collect_file(self, path, parent): - if not path.basename.startswith("."): - # Ignore hidden files, e.g. .testmondata. - wascalled.append(path) - - testdir.makefile(".abc", "xyz") - pytest.main([testdir.tmpdir], plugins=[Plugin()]) - assert len(wascalled) == 1 - assert wascalled[0].ext == ".abc" - - def test_pytest_collect_directory(self, testdir): - wascalled = [] - - class Plugin(object): - - def pytest_collect_directory(self, path, parent): - wascalled.append(path.basename) - - testdir.mkdir("hello") - testdir.mkdir("world") - pytest.main(testdir.tmpdir, plugins=[Plugin()]) - assert "hello" in wascalled - assert "world" in wascalled - - -class TestPrunetraceback(object): - - def test_custom_repr_failure(self, testdir): - p = testdir.makepyfile( - """ - import not_exists - """ - ) - testdir.makeconftest( - """ - import pytest - def pytest_collect_file(path, parent): - return MyFile(path, parent) - class MyError(Exception): - pass - class MyFile(pytest.File): - def collect(self): - raise MyError() - def repr_failure(self, excinfo): - if excinfo.errisinstance(MyError): - return "hello world" - return pytest.File.repr_failure(self, excinfo) - """ - ) - - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*ERROR collecting*", "*hello world*"]) - - @pytest.mark.xfail(reason="other mechanism for adding to reporting needed") - def test_collect_report_postprocessing(self, testdir): - p = testdir.makepyfile( - """ - import not_exists - """ - ) - testdir.makeconftest( - """ - import pytest - @pytest.hookimpl(hookwrapper=True) - def pytest_make_collect_report(): - outcome = yield - rep = outcome.get_result() - rep.headerlines += ["header1"] - outcome.force_result(rep) - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*ERROR collecting*", "*header1*"]) - - -class TestCustomConftests(object): - - def test_ignore_collect_path(self, testdir): - testdir.makeconftest( - """ - def pytest_ignore_collect(path, config): - return path.basename.startswith("x") or \ - path.basename == "test_one.py" - """ - ) - sub = testdir.mkdir("xy123") - sub.ensure("test_hello.py").write("syntax error") - sub.join("conftest.py").write("syntax error") - testdir.makepyfile("def test_hello(): pass") - testdir.makepyfile(test_one="syntax error") - result = testdir.runpytest("--fulltrace") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_ignore_collect_not_called_on_argument(self, testdir): - testdir.makeconftest( - """ - def pytest_ignore_collect(path, config): - return True - """ - ) - p = testdir.makepyfile("def test_hello(): pass") - result = testdir.runpytest(p) - assert result.ret == 0 - result.stdout.fnmatch_lines("*1 passed*") - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stdout.fnmatch_lines("*collected 0 items*") - - def test_collectignore_exclude_on_option(self, testdir): - testdir.makeconftest( - """ - collect_ignore = ['hello', 'test_world.py'] - def pytest_addoption(parser): - parser.addoption("--XX", action="store_true", default=False) - def pytest_configure(config): - if config.getvalue("XX"): - collect_ignore[:] = [] - """ - ) - testdir.mkdir("hello") - testdir.makepyfile(test_world="def test_hello(): pass") - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - assert "passed" not in result.stdout.str() - result = testdir.runpytest("--XX") - assert result.ret == 0 - assert "passed" in result.stdout.str() - - def test_pytest_fs_collect_hooks_are_seen(self, testdir): - testdir.makeconftest( - """ - import pytest - class MyModule(pytest.Module): - pass - def pytest_collect_file(path, parent): - if path.ext == ".py": - return MyModule(path, parent) - """ - ) - testdir.mkdir("sub") - testdir.makepyfile("def test_x(): pass") - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*MyModule*", "*test_x*"]) - - def test_pytest_collect_file_from_sister_dir(self, testdir): - sub1 = testdir.mkpydir("sub1") - sub2 = testdir.mkpydir("sub2") - conf1 = testdir.makeconftest( - """ - import pytest - class MyModule1(pytest.Module): - pass - def pytest_collect_file(path, parent): - if path.ext == ".py": - return MyModule1(path, parent) - """ - ) - conf1.move(sub1.join(conf1.basename)) - conf2 = testdir.makeconftest( - """ - import pytest - class MyModule2(pytest.Module): - pass - def pytest_collect_file(path, parent): - if path.ext == ".py": - return MyModule2(path, parent) - """ - ) - conf2.move(sub2.join(conf2.basename)) - p = testdir.makepyfile("def test_x(): pass") - p.copy(sub1.join(p.basename)) - p.copy(sub2.join(p.basename)) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*MyModule1*", "*MyModule2*", "*test_x*"]) - - -class TestSession(object): - - def test_parsearg(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - subdir = testdir.mkdir("sub") - subdir.ensure("__init__.py") - target = subdir.join(p.basename) - p.move(target) - subdir.chdir() - config = testdir.parseconfig(p.basename) - rcol = Session(config=config) - assert rcol.fspath == subdir - parts = rcol._parsearg(p.basename) - - assert parts[0] == target - assert len(parts) == 1 - parts = rcol._parsearg(p.basename + "::test_func") - assert parts[0] == target - assert parts[1] == "test_func" - assert len(parts) == 2 - - def test_collect_topdir(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - id = "::".join([p.basename, "test_func"]) - # XXX migrate to collectonly? (see below) - config = testdir.parseconfig(id) - topdir = testdir.tmpdir - rcol = Session(config) - assert topdir == rcol.fspath - # rootid = rcol.nodeid - # root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0] - # assert root2 == rcol, rootid - colitems = rcol.perform_collect([rcol.nodeid], genitems=False) - assert len(colitems) == 1 - assert colitems[0].fspath == p - - def get_reported_items(self, hookrec): - """Return pytest.Item instances reported by the pytest_collectreport hook""" - calls = hookrec.getcalls("pytest_collectreport") - return [ - x - for call in calls - for x in call.report.result - if isinstance(x, pytest.Item) - ] - - def test_collect_protocol_single_function(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - id = "::".join([p.basename, "test_func"]) - items, hookrec = testdir.inline_genitems(id) - item, = items - assert item.name == "test_func" - newid = item.nodeid - assert newid == id - pprint.pprint(hookrec.calls) - topdir = testdir.tmpdir # noqa - hookrec.assert_contains( - [ - ("pytest_collectstart", "collector.fspath == topdir"), - ("pytest_make_collect_report", "collector.fspath == topdir"), - ("pytest_collectstart", "collector.fspath == p"), - ("pytest_make_collect_report", "collector.fspath == p"), - ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.result[0].name == 'test_func'"), - ] - ) - # ensure we are reporting the collection of the single test item (#2464) - assert [x.name for x in self.get_reported_items(hookrec)] == ["test_func"] - - def test_collect_protocol_method(self, testdir): - p = testdir.makepyfile( - """ - class TestClass(object): - def test_method(self): - pass - """ - ) - normid = p.basename + "::TestClass::()::test_method" - for id in [ - p.basename, - p.basename + "::TestClass", - p.basename + "::TestClass::()", - normid, - ]: - items, hookrec = testdir.inline_genitems(id) - assert len(items) == 1 - assert items[0].name == "test_method" - newid = items[0].nodeid - assert newid == normid - # ensure we are reporting the collection of the single test item (#2464) - assert [x.name for x in self.get_reported_items(hookrec)] == ["test_method"] - - def test_collect_custom_nodes_multi_id(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - testdir.makeconftest( - """ - import pytest - class SpecialItem(pytest.Item): - def runtest(self): - return # ok - class SpecialFile(pytest.File): - def collect(self): - return [SpecialItem(name="check", parent=self)] - def pytest_collect_file(path, parent): - if path.basename == %r: - return SpecialFile(fspath=path, parent=parent) - """ - % p.basename - ) - id = p.basename - - items, hookrec = testdir.inline_genitems(id) - pprint.pprint(hookrec.calls) - assert len(items) == 2 - hookrec.assert_contains( - [ - ("pytest_collectstart", "collector.fspath == collector.session.fspath"), - ( - "pytest_collectstart", - "collector.__class__.__name__ == 'SpecialFile'", - ), - ("pytest_collectstart", "collector.__class__.__name__ == 'Module'"), - ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.nodeid.startswith(p.basename)"), - ] - ) - assert len(self.get_reported_items(hookrec)) == 2 - - def test_collect_subdir_event_ordering(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - aaa = testdir.mkpydir("aaa") - test_aaa = aaa.join("test_aaa.py") - p.move(test_aaa) - - items, hookrec = testdir.inline_genitems() - assert len(items) == 1 - pprint.pprint(hookrec.calls) - hookrec.assert_contains( - [ - ("pytest_collectstart", "collector.fspath == test_aaa"), - ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.nodeid.startswith('aaa/test_aaa.py')"), - ] - ) - - def test_collect_two_commandline_args(self, testdir): - p = testdir.makepyfile("def test_func(): pass") - aaa = testdir.mkpydir("aaa") - bbb = testdir.mkpydir("bbb") - test_aaa = aaa.join("test_aaa.py") - p.copy(test_aaa) - test_bbb = bbb.join("test_bbb.py") - p.move(test_bbb) - - id = "." - - items, hookrec = testdir.inline_genitems(id) - assert len(items) == 2 - pprint.pprint(hookrec.calls) - hookrec.assert_contains( - [ - ("pytest_collectstart", "collector.fspath == test_aaa"), - ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.nodeid == 'aaa/test_aaa.py'"), - ("pytest_collectstart", "collector.fspath == test_bbb"), - ("pytest_pycollect_makeitem", "name == 'test_func'"), - ("pytest_collectreport", "report.nodeid == 'bbb/test_bbb.py'"), - ] - ) - - def test_serialization_byid(self, testdir): - testdir.makepyfile("def test_func(): pass") - items, hookrec = testdir.inline_genitems() - assert len(items) == 1 - item, = items - items2, hookrec = testdir.inline_genitems(item.nodeid) - item2, = items2 - assert item2.name == item.name - assert item2.fspath == item.fspath - - def test_find_byid_without_instance_parents(self, testdir): - p = testdir.makepyfile( - """ - class TestClass(object): - def test_method(self): - pass - """ - ) - arg = p.basename + "::TestClass::test_method" - items, hookrec = testdir.inline_genitems(arg) - assert len(items) == 1 - item, = items - assert item.nodeid.endswith("TestClass::()::test_method") - # ensure we are reporting the collection of the single test item (#2464) - assert [x.name for x in self.get_reported_items(hookrec)] == ["test_method"] - - -class Test_getinitialnodes(object): - - def test_global_file(self, testdir, tmpdir): - x = tmpdir.ensure("x.py") - with tmpdir.as_cwd(): - config = testdir.parseconfigure(x) - col = testdir.getnode(config, x) - assert isinstance(col, pytest.Module) - assert col.name == "x.py" - assert col.parent.parent is None - for col in col.listchain(): - assert col.config is config - - def test_pkgfile(self, testdir): - tmpdir = testdir.tmpdir - subdir = tmpdir.join("subdir") - x = subdir.ensure("x.py") - subdir.ensure("__init__.py") - with subdir.as_cwd(): - config = testdir.parseconfigure(x) - col = testdir.getnode(config, x) - assert isinstance(col, pytest.Module) - assert col.name == "x.py" - assert col.parent.parent is None - for col in col.listchain(): - assert col.config is config - - -class Test_genitems(object): - - def test_check_collect_hashes(self, testdir): - p = testdir.makepyfile( - """ - def test_1(): - pass - - def test_2(): - pass - """ - ) - p.copy(p.dirpath(p.purebasename + "2" + ".py")) - items, reprec = testdir.inline_genitems(p.dirpath()) - assert len(items) == 4 - for numi, i in enumerate(items): - for numj, j in enumerate(items): - if numj != numi: - assert hash(i) != hash(j) - assert i != j - - def test_example_items1(self, testdir): - p = testdir.makepyfile( - """ - def testone(): - pass - - class TestX(object): - def testmethod_one(self): - pass - - class TestY(TestX): - pass - """ - ) - items, reprec = testdir.inline_genitems(p) - assert len(items) == 3 - assert items[0].name == "testone" - assert items[1].name == "testmethod_one" - assert items[2].name == "testmethod_one" - - # let's also test getmodpath here - assert items[0].getmodpath() == "testone" - assert items[1].getmodpath() == "TestX.testmethod_one" - assert items[2].getmodpath() == "TestY.testmethod_one" - - s = items[0].getmodpath(stopatmodule=False) - assert s.endswith("test_example_items1.testone") - print(s) - - def test_class_and_functions_discovery_using_glob(self, testdir): - """ - tests that python_classes and python_functions config options work - as prefixes and glob-like patterns (issue #600). - """ - testdir.makeini( - """ - [pytest] - python_classes = *Suite Test - python_functions = *_test test - """ - ) - p = testdir.makepyfile( - """ - class MyTestSuite(object): - def x_test(self): - pass - - class TestCase(object): - def test_y(self): - pass - """ - ) - items, reprec = testdir.inline_genitems(p) - ids = [x.getmodpath() for x in items] - assert ids == ["MyTestSuite.x_test", "TestCase.test_y"] - - -def test_matchnodes_two_collections_same_file(testdir): - testdir.makeconftest( - """ - import pytest - def pytest_configure(config): - config.pluginmanager.register(Plugin2()) - - class Plugin2(object): - def pytest_collect_file(self, path, parent): - if path.ext == ".abc": - return MyFile2(path, parent) - - def pytest_collect_file(path, parent): - if path.ext == ".abc": - return MyFile1(path, parent) - - class MyFile1(pytest.Item, pytest.File): - def runtest(self): - pass - class MyFile2(pytest.File): - def collect(self): - return [Item2("hello", parent=self)] - - class Item2(pytest.Item): - def runtest(self): - pass - """ - ) - p = testdir.makefile(".abc", "") - result = testdir.runpytest() - assert result.ret == 0 - result.stdout.fnmatch_lines(["*2 passed*"]) - res = testdir.runpytest("%s::hello" % p.basename) - res.stdout.fnmatch_lines(["*1 passed*"]) - - -class TestNodekeywords(object): - - def test_no_under(self, testdir): - modcol = testdir.getmodulecol( - """ - def test_pass(): pass - def test_fail(): assert 0 - """ - ) - values = list(modcol.keywords) - assert modcol.name in values - for x in values: - assert not x.startswith("_") - assert modcol.name in repr(modcol.keywords) - - def test_issue345(self, testdir): - testdir.makepyfile( - """ - def test_should_not_be_selected(): - assert False, 'I should not have been selected to run' - - def test___repr__(): - pass - """ - ) - reprec = testdir.inline_run("-k repr") - reprec.assertoutcome(passed=1, failed=0) - - -COLLECTION_ERROR_PY_FILES = dict( - test_01_failure=""" - def test_1(): - assert False - """, - test_02_import_error=""" - import asdfasdfasdf - def test_2(): - assert True - """, - test_03_import_error=""" - import asdfasdfasdf - def test_3(): - assert True - """, - test_04_success=""" - def test_4(): - assert True - """, -) - - -def test_exit_on_collection_error(testdir): - """Verify that all collection errors are collected and no tests executed""" - testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) - - res = testdir.runpytest() - assert res.ret == 2 - - res.stdout.fnmatch_lines( - [ - "collected 2 items / 2 errors", - "*ERROR collecting test_02_import_error.py*", - "*No module named *asdfa*", - "*ERROR collecting test_03_import_error.py*", - "*No module named *asdfa*", - ] - ) - - -def test_exit_on_collection_with_maxfail_smaller_than_n_errors(testdir): - """ - Verify collection is aborted once maxfail errors are encountered ignoring - further modules which would cause more collection errors. - """ - testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) - - res = testdir.runpytest("--maxfail=1") - assert res.ret == 1 - - res.stdout.fnmatch_lines( - ["*ERROR collecting test_02_import_error.py*", "*No module named *asdfa*"] - ) - - assert "test_03" not in res.stdout.str() - - -def test_exit_on_collection_with_maxfail_bigger_than_n_errors(testdir): - """ - Verify the test run aborts due to collection errors even if maxfail count of - errors was not reached. - """ - testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) - - res = testdir.runpytest("--maxfail=4") - assert res.ret == 2 - - res.stdout.fnmatch_lines( - [ - "collected 2 items / 2 errors", - "*ERROR collecting test_02_import_error.py*", - "*No module named *asdfa*", - "*ERROR collecting test_03_import_error.py*", - "*No module named *asdfa*", - ] - ) - - -def test_continue_on_collection_errors(testdir): - """ - Verify tests are executed even when collection errors occur when the - --continue-on-collection-errors flag is set - """ - testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) - - res = testdir.runpytest("--continue-on-collection-errors") - assert res.ret == 1 - - res.stdout.fnmatch_lines( - ["collected 2 items / 2 errors", "*1 failed, 1 passed, 2 error*"] - ) - - -def test_continue_on_collection_errors_maxfail(testdir): - """ - Verify tests are executed even when collection errors occur and that maxfail - is honoured (including the collection error count). - 4 tests: 2 collection errors + 1 failure + 1 success - test_4 is never executed because the test run is with --maxfail=3 which - means it is interrupted after the 2 collection errors + 1 failure. - """ - testdir.makepyfile(**COLLECTION_ERROR_PY_FILES) - - res = testdir.runpytest("--continue-on-collection-errors", "--maxfail=3") - assert res.ret == 1 - - res.stdout.fnmatch_lines(["collected 2 items / 2 errors", "*1 failed, 2 error*"]) - - -def test_fixture_scope_sibling_conftests(testdir): - """Regression test case for https://github.com/pytest-dev/pytest/issues/2836""" - foo_path = testdir.mkpydir("foo") - foo_path.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def fix(): - return 1 - """ - ) - ) - foo_path.join("test_foo.py").write("def test_foo(fix): assert fix == 1") - - # Tests in `food/` should not see the conftest fixture from `foo/` - food_path = testdir.mkpydir("food") - food_path.join("test_food.py").write("def test_food(fix): assert fix == 1") - - res = testdir.runpytest() - assert res.ret == 1 - - res.stdout.fnmatch_lines( - [ - "*ERROR at setup of test_food*", - "E*fixture 'fix' not found", - "*1 passed, 1 error*", - ] - ) diff --git a/third_party/python/pytest/testing/test_compat.py b/third_party/python/pytest/testing/test_compat.py deleted file mode 100644 index 550a8f1b3544..000000000000 --- a/third_party/python/pytest/testing/test_compat.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import absolute_import, division, print_function -import sys - -import pytest -from _pytest.compat import is_generator, get_real_func, safe_getattr -from _pytest.outcomes import OutcomeException - - -def test_is_generator(): - - def zap(): - yield - - def foo(): - pass - - assert is_generator(zap) - assert not is_generator(foo) - - -def test_real_func_loop_limit(): - - class Evil(object): - - def __init__(self): - self.left = 1000 - - def __repr__(self): - return "".format(left=self.left) - - def __getattr__(self, attr): - if not self.left: - raise RuntimeError("its over") - self.left -= 1 - return self - - evil = Evil() - - with pytest.raises(ValueError): - res = get_real_func(evil) - print(res) - - -@pytest.mark.skipif( - sys.version_info < (3, 4), reason="asyncio available in Python 3.4+" -) -def test_is_generator_asyncio(testdir): - testdir.makepyfile( - """ - from _pytest.compat import is_generator - import asyncio - @asyncio.coroutine - def baz(): - yield from [1,2,3] - - def test_is_generator_asyncio(): - assert not is_generator(baz) - """ - ) - # avoid importing asyncio into pytest's own process, - # which in turn imports logging (#8) - result = testdir.runpytest_subprocess() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -@pytest.mark.skipif( - sys.version_info < (3, 5), reason="async syntax available in Python 3.5+" -) -def test_is_generator_async_syntax(testdir): - testdir.makepyfile( - """ - from _pytest.compat import is_generator - def test_is_generator_py35(): - async def foo(): - await foo() - - async def bar(): - pass - - assert not is_generator(foo) - assert not is_generator(bar) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -class ErrorsHelper(object): - - @property - def raise_exception(self): - raise Exception("exception should be catched") - - @property - def raise_fail(self): - pytest.fail("fail should be catched") - - -def test_helper_failures(): - helper = ErrorsHelper() - with pytest.raises(Exception): - helper.raise_exception - with pytest.raises(OutcomeException): - helper.raise_fail - - -def test_safe_getattr(): - helper = ErrorsHelper() - assert safe_getattr(helper, "raise_exception", "default") == "default" - assert safe_getattr(helper, "raise_fail", "default") == "default" diff --git a/third_party/python/pytest/testing/test_config.py b/third_party/python/pytest/testing/test_config.py deleted file mode 100644 index 5fb048364f7c..000000000000 --- a/third_party/python/pytest/testing/test_config.py +++ /dev/null @@ -1,1068 +0,0 @@ -from __future__ import absolute_import, division, print_function -import sys -import textwrap -import pytest - -import _pytest._code -from _pytest.config.findpaths import getcfg, get_common_ancestor, determine_setup -from _pytest.config import _iter_rewritable_modules -from _pytest.main import EXIT_NOTESTSCOLLECTED - - -class TestParseIni(object): - - @pytest.mark.parametrize( - "section, filename", [("pytest", "pytest.ini"), ("tool:pytest", "setup.cfg")] - ) - def test_getcfg_and_config(self, testdir, tmpdir, section, filename): - sub = tmpdir.mkdir("sub") - sub.chdir() - tmpdir.join(filename).write( - _pytest._code.Source( - """ - [{section}] - name = value - """.format( - section=section - ) - ) - ) - rootdir, inifile, cfg = getcfg([sub]) - assert cfg["name"] == "value" - config = testdir.parseconfigure(sub) - assert config.inicfg["name"] == "value" - - def test_getcfg_empty_path(self): - """correctly handle zero length arguments (a la pytest '')""" - getcfg([""]) - - def test_append_parse_args(self, testdir, tmpdir, monkeypatch): - monkeypatch.setenv("PYTEST_ADDOPTS", '--color no -rs --tb="short"') - tmpdir.join("pytest.ini").write( - _pytest._code.Source( - """ - [pytest] - addopts = --verbose - """ - ) - ) - config = testdir.parseconfig(tmpdir) - assert config.option.color == "no" - assert config.option.reportchars == "s" - assert config.option.tbstyle == "short" - assert config.option.verbose - - def test_tox_ini_wrong_version(self, testdir): - testdir.makefile( - ".ini", - tox=""" - [pytest] - minversion=9.0 - """, - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stderr.fnmatch_lines(["*tox.ini:2*requires*9.0*actual*"]) - - @pytest.mark.parametrize( - "section, name", - [("tool:pytest", "setup.cfg"), ("pytest", "tox.ini"), ("pytest", "pytest.ini")], - ) - def test_ini_names(self, testdir, name, section): - testdir.tmpdir.join(name).write( - textwrap.dedent( - """ - [{section}] - minversion = 1.0 - """.format( - section=section - ) - ) - ) - config = testdir.parseconfig() - assert config.getini("minversion") == "1.0" - - def test_toxini_before_lower_pytestini(self, testdir): - sub = testdir.tmpdir.mkdir("sub") - sub.join("tox.ini").write( - textwrap.dedent( - """ - [pytest] - minversion = 2.0 - """ - ) - ) - testdir.tmpdir.join("pytest.ini").write( - textwrap.dedent( - """ - [pytest] - minversion = 1.5 - """ - ) - ) - config = testdir.parseconfigure(sub) - assert config.getini("minversion") == "2.0" - - @pytest.mark.xfail(reason="probably not needed") - def test_confcutdir(self, testdir): - sub = testdir.mkdir("sub") - sub.chdir() - testdir.makeini( - """ - [pytest] - addopts = --qwe - """ - ) - result = testdir.inline_run("--confcutdir=.") - assert result.ret == 0 - - -class TestConfigCmdlineParsing(object): - - def test_parsing_again_fails(self, testdir): - config = testdir.parseconfig() - pytest.raises(AssertionError, lambda: config.parse([])) - - def test_explicitly_specified_config_file_is_loaded(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("custom", "") - """ - ) - testdir.makeini( - """ - [pytest] - custom = 0 - """ - ) - testdir.makefile( - ".cfg", - custom=""" - [pytest] - custom = 1 - """, - ) - config = testdir.parseconfig("-c", "custom.cfg") - assert config.getini("custom") == "1" - - testdir.makefile( - ".cfg", - custom_tool_pytest_section=""" - [tool:pytest] - custom = 1 - """, - ) - config = testdir.parseconfig("-c", "custom_tool_pytest_section.cfg") - assert config.getini("custom") == "1" - - def test_absolute_win32_path(self, testdir): - temp_cfg_file = testdir.makefile( - ".cfg", - custom=""" - [pytest] - addopts = --version - """, - ) - from os.path import normpath - - temp_cfg_file = normpath(str(temp_cfg_file)) - ret = pytest.main("-c " + temp_cfg_file) - assert ret == _pytest.main.EXIT_OK - - -class TestConfigAPI(object): - - def test_config_trace(self, testdir): - config = testdir.parseconfig() - values = [] - config.trace.root.setwriter(values.append) - config.trace("hello") - assert len(values) == 1 - assert values[0] == "hello [config]\n" - - def test_config_getoption(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addoption("--hello", "-X", dest="hello") - """ - ) - config = testdir.parseconfig("--hello=this") - for x in ("hello", "--hello", "-X"): - assert config.getoption(x) == "this" - pytest.raises(ValueError, "config.getoption('qweqwe')") - - @pytest.mark.skipif("sys.version_info[0] < 3") - def test_config_getoption_unicode(self, testdir): - testdir.makeconftest( - """ - from __future__ import unicode_literals - - def pytest_addoption(parser): - parser.addoption('--hello', type=str) - """ - ) - config = testdir.parseconfig("--hello=this") - assert config.getoption("hello") == "this" - - def test_config_getvalueorskip(self, testdir): - config = testdir.parseconfig() - pytest.raises(pytest.skip.Exception, "config.getvalueorskip('hello')") - verbose = config.getvalueorskip("verbose") - assert verbose == config.option.verbose - - def test_config_getvalueorskip_None(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addoption("--hello") - """ - ) - config = testdir.parseconfig() - with pytest.raises(pytest.skip.Exception): - config.getvalueorskip("hello") - - def test_getoption(self, testdir): - config = testdir.parseconfig() - with pytest.raises(ValueError): - config.getvalue("x") - assert config.getoption("x", 1) == 1 - - def test_getconftest_pathlist(self, testdir, tmpdir): - somepath = tmpdir.join("x", "y", "z") - p = tmpdir.join("conftest.py") - p.write("pathlist = ['.', %r]" % str(somepath)) - config = testdir.parseconfigure(p) - assert config._getconftest_pathlist("notexist", path=tmpdir) is None - pl = config._getconftest_pathlist("pathlist", path=tmpdir) - print(pl) - assert len(pl) == 2 - assert pl[0] == tmpdir - assert pl[1] == somepath - - def test_addini(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("myname", "my new ini value") - """ - ) - testdir.makeini( - """ - [pytest] - myname=hello - """ - ) - config = testdir.parseconfig() - val = config.getini("myname") - assert val == "hello" - pytest.raises(ValueError, config.getini, "other") - - def test_addini_pathlist(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("paths", "my new ini value", type="pathlist") - parser.addini("abc", "abc value") - """ - ) - p = testdir.makeini( - """ - [pytest] - paths=hello world/sub.py - """ - ) - config = testdir.parseconfig() - values = config.getini("paths") - assert len(values) == 2 - assert values[0] == p.dirpath("hello") - assert values[1] == p.dirpath("world/sub.py") - pytest.raises(ValueError, config.getini, "other") - - def test_addini_args(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("args", "new args", type="args") - parser.addini("a2", "", "args", default="1 2 3".split()) - """ - ) - testdir.makeini( - """ - [pytest] - args=123 "123 hello" "this" - """ - ) - config = testdir.parseconfig() - values = config.getini("args") - assert len(values) == 3 - assert values == ["123", "123 hello", "this"] - values = config.getini("a2") - assert values == list("123") - - def test_addini_linelist(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("xy", "", type="linelist") - parser.addini("a2", "", "linelist") - """ - ) - testdir.makeini( - """ - [pytest] - xy= 123 345 - second line - """ - ) - config = testdir.parseconfig() - values = config.getini("xy") - assert len(values) == 2 - assert values == ["123 345", "second line"] - values = config.getini("a2") - assert values == [] - - @pytest.mark.parametrize( - "str_val, bool_val", [("True", True), ("no", False), ("no-ini", True)] - ) - def test_addini_bool(self, testdir, str_val, bool_val): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("strip", "", type="bool", default=True) - """ - ) - if str_val != "no-ini": - testdir.makeini( - """ - [pytest] - strip=%s - """ - % str_val - ) - config = testdir.parseconfig() - assert config.getini("strip") is bool_val - - def test_addinivalue_line_existing(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("xy", "", type="linelist") - """ - ) - testdir.makeini( - """ - [pytest] - xy= 123 - """ - ) - config = testdir.parseconfig() - values = config.getini("xy") - assert len(values) == 1 - assert values == ["123"] - config.addinivalue_line("xy", "456") - values = config.getini("xy") - assert len(values) == 2 - assert values == ["123", "456"] - - def test_addinivalue_line_new(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("xy", "", type="linelist") - """ - ) - config = testdir.parseconfig() - assert not config.getini("xy") - config.addinivalue_line("xy", "456") - values = config.getini("xy") - assert len(values) == 1 - assert values == ["456"] - config.addinivalue_line("xy", "123") - values = config.getini("xy") - assert len(values) == 2 - assert values == ["456", "123"] - - def test_confcutdir_check_isdir(self, testdir): - """Give an error if --confcutdir is not a valid directory (#2078)""" - with pytest.raises(pytest.UsageError): - testdir.parseconfig( - "--confcutdir", testdir.tmpdir.join("file").ensure(file=1) - ) - with pytest.raises(pytest.UsageError): - testdir.parseconfig("--confcutdir", testdir.tmpdir.join("inexistant")) - config = testdir.parseconfig( - "--confcutdir", testdir.tmpdir.join("dir").ensure(dir=1) - ) - assert config.getoption("confcutdir") == str(testdir.tmpdir.join("dir")) - - @pytest.mark.parametrize( - "names, expected", - [ - (["bar.py"], ["bar"]), - (["foo", "bar.py"], []), - (["foo", "bar.pyc"], []), - (["foo", "__init__.py"], ["foo"]), - (["foo", "bar", "__init__.py"], []), - ], - ) - def test_iter_rewritable_modules(self, names, expected): - assert list(_iter_rewritable_modules(["/".join(names)])) == expected - - -class TestConfigFromdictargs(object): - - def test_basic_behavior(self): - from _pytest.config import Config - - option_dict = {"verbose": 444, "foo": "bar", "capture": "no"} - args = ["a", "b"] - - config = Config.fromdictargs(option_dict, args) - with pytest.raises(AssertionError): - config.parse(["should refuse to parse again"]) - assert config.option.verbose == 444 - assert config.option.foo == "bar" - assert config.option.capture == "no" - assert config.args == args - - def test_origargs(self): - """Show that fromdictargs can handle args in their "orig" format""" - from _pytest.config import Config - - option_dict = {} - args = ["-vvvv", "-s", "a", "b"] - - config = Config.fromdictargs(option_dict, args) - assert config.args == ["a", "b"] - assert config._origargs == args - assert config.option.verbose == 4 - assert config.option.capture == "no" - - def test_inifilename(self, tmpdir): - tmpdir.join("foo/bar.ini").ensure().write( - _pytest._code.Source( - """ - [pytest] - name = value - """ - ) - ) - - from _pytest.config import Config - - inifile = "../../foo/bar.ini" - option_dict = {"inifilename": inifile, "capture": "no"} - - cwd = tmpdir.join("a/b") - cwd.join("pytest.ini").ensure().write( - _pytest._code.Source( - """ - [pytest] - name = wrong-value - should_not_be_set = true - """ - ) - ) - with cwd.ensure(dir=True).as_cwd(): - config = Config.fromdictargs(option_dict, ()) - - assert config.args == [str(cwd)] - assert config.option.inifilename == inifile - assert config.option.capture == "no" - - # this indicates this is the file used for getting configuration values - assert config.inifile == inifile - assert config.inicfg.get("name") == "value" - assert config.inicfg.get("should_not_be_set") is None - - -def test_options_on_small_file_do_not_blow_up(testdir): - - def runfiletest(opts): - reprec = testdir.inline_run(*opts) - passed, skipped, failed = reprec.countoutcomes() - assert failed == 2 - assert skipped == passed == 0 - - path = testdir.makepyfile( - """ - def test_f1(): assert 0 - def test_f2(): assert 0 - """ - ) - - for opts in ( - [], - ["-l"], - ["-s"], - ["--tb=no"], - ["--tb=short"], - ["--tb=long"], - ["--fulltrace"], - ["--traceconfig"], - ["-v"], - ["-v", "-v"], - ): - runfiletest(opts + [path]) - - -def test_preparse_ordering_with_setuptools(testdir, monkeypatch): - pkg_resources = pytest.importorskip("pkg_resources") - - def my_iter(name): - assert name == "pytest11" - - class Dist(object): - project_name = "spam" - version = "1.0" - - def _get_metadata(self, name): - return ["foo.txt,sha256=abc,123"] - - class EntryPoint(object): - name = "mytestplugin" - dist = Dist() - - def load(self): - - class PseudoPlugin(object): - x = 42 - - return PseudoPlugin() - - return iter([EntryPoint()]) - - monkeypatch.setattr(pkg_resources, "iter_entry_points", my_iter) - testdir.makeconftest( - """ - pytest_plugins = "mytestplugin", - """ - ) - monkeypatch.setenv("PYTEST_PLUGINS", "mytestplugin") - config = testdir.parseconfig() - plugin = config.pluginmanager.getplugin("mytestplugin") - assert plugin.x == 42 - - -def test_setuptools_importerror_issue1479(testdir, monkeypatch): - pkg_resources = pytest.importorskip("pkg_resources") - - def my_iter(name): - assert name == "pytest11" - - class Dist(object): - project_name = "spam" - version = "1.0" - - def _get_metadata(self, name): - return ["foo.txt,sha256=abc,123"] - - class EntryPoint(object): - name = "mytestplugin" - dist = Dist() - - def load(self): - raise ImportError("Don't hide me!") - - return iter([EntryPoint()]) - - monkeypatch.setattr(pkg_resources, "iter_entry_points", my_iter) - with pytest.raises(ImportError): - testdir.parseconfig() - - -@pytest.mark.parametrize("block_it", [True, False]) -def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block_it): - pkg_resources = pytest.importorskip("pkg_resources") - - plugin_module_placeholder = object() - - def my_iter(name): - assert name == "pytest11" - - class Dist(object): - project_name = "spam" - version = "1.0" - - def _get_metadata(self, name): - return ["foo.txt,sha256=abc,123"] - - class EntryPoint(object): - name = "mytestplugin" - dist = Dist() - - def load(self): - return plugin_module_placeholder - - return iter([EntryPoint()]) - - monkeypatch.setattr(pkg_resources, "iter_entry_points", my_iter) - args = ("-p", "no:mytestplugin") if block_it else () - config = testdir.parseconfig(*args) - config.pluginmanager.import_plugin("mytestplugin") - if block_it: - assert "mytestplugin" not in sys.modules - assert config.pluginmanager.get_plugin("mytestplugin") is None - else: - assert config.pluginmanager.get_plugin( - "mytestplugin" - ) is plugin_module_placeholder - - -def test_cmdline_processargs_simple(testdir): - testdir.makeconftest( - """ - def pytest_cmdline_preparse(args): - args.append("-h") - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*pytest*", "*-h*"]) - - -def test_invalid_options_show_extra_information(testdir): - """display extra information when pytest exits due to unrecognized - options in the command-line""" - testdir.makeini( - """ - [pytest] - addopts = --invalid-option - """ - ) - result = testdir.runpytest() - result.stderr.fnmatch_lines( - [ - "*error: unrecognized arguments: --invalid-option*", - "* inifile: %s*" % testdir.tmpdir.join("tox.ini"), - "* rootdir: %s*" % testdir.tmpdir, - ] - ) - - -@pytest.mark.parametrize( - "args", - [ - ["dir1", "dir2", "-v"], - ["dir1", "-v", "dir2"], - ["dir2", "-v", "dir1"], - ["-v", "dir2", "dir1"], - ], -) -def test_consider_args_after_options_for_rootdir_and_inifile(testdir, args): - """ - Consider all arguments in the command-line for rootdir and inifile - discovery, even if they happen to occur after an option. #949 - """ - # replace "dir1" and "dir2" from "args" into their real directory - root = testdir.tmpdir.mkdir("myroot") - d1 = root.mkdir("dir1") - d2 = root.mkdir("dir2") - for i, arg in enumerate(args): - if arg == "dir1": - args[i] = d1 - elif arg == "dir2": - args[i] = d2 - with root.as_cwd(): - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines(["*rootdir: *myroot, inifile:"]) - - -@pytest.mark.skipif("sys.platform == 'win32'") -def test_toolongargs_issue224(testdir): - result = testdir.runpytest("-m", "hello" * 500) - assert result.ret == EXIT_NOTESTSCOLLECTED - - -def test_config_in_subdirectory_colon_command_line_issue2148(testdir): - conftest_source = """ - def pytest_addoption(parser): - parser.addini('foo', 'foo') - """ - - testdir.makefile( - ".ini", - **{"pytest": "[pytest]\nfoo = root", "subdir/pytest": "[pytest]\nfoo = subdir"} - ) - - testdir.makepyfile( - **{ - "conftest": conftest_source, - "subdir/conftest": conftest_source, - "subdir/test_foo": """ - def test_foo(pytestconfig): - assert pytestconfig.getini('foo') == 'subdir' - """, - } - ) - - result = testdir.runpytest("subdir/test_foo.py::test_foo") - assert result.ret == 0 - - -def test_notify_exception(testdir, capfd): - config = testdir.parseconfig() - excinfo = pytest.raises(ValueError, "raise ValueError(1)") - config.notify_exception(excinfo) - out, err = capfd.readouterr() - assert "ValueError" in err - - class A(object): - - def pytest_internalerror(self, excrepr): - return True - - config.pluginmanager.register(A()) - config.notify_exception(excinfo) - out, err = capfd.readouterr() - assert not err - - -def test_load_initial_conftest_last_ordering(testdir): - from _pytest.config import get_config - - pm = get_config().pluginmanager - - class My(object): - - def pytest_load_initial_conftests(self): - pass - - m = My() - pm.register(m) - hc = pm.hook.pytest_load_initial_conftests - values = hc._nonwrappers + hc._wrappers - expected = ["_pytest.config", "test_config", "_pytest.capture"] - assert [x.function.__module__ for x in values] == expected - - -def test_get_plugin_specs_as_list(): - from _pytest.config import _get_plugin_specs_as_list - - with pytest.raises(pytest.UsageError): - _get_plugin_specs_as_list({"foo"}) - with pytest.raises(pytest.UsageError): - _get_plugin_specs_as_list(dict()) - - assert _get_plugin_specs_as_list(None) == [] - assert _get_plugin_specs_as_list("") == [] - assert _get_plugin_specs_as_list("foo") == ["foo"] - assert _get_plugin_specs_as_list("foo,bar") == ["foo", "bar"] - assert _get_plugin_specs_as_list(["foo", "bar"]) == ["foo", "bar"] - assert _get_plugin_specs_as_list(("foo", "bar")) == ["foo", "bar"] - - -class TestWarning(object): - - def test_warn_config(self, testdir): - testdir.makeconftest( - """ - values = [] - def pytest_configure(config): - config.warn("C1", "hello") - def pytest_logwarning(code, message): - if message == "hello" and code == "C1": - values.append(1) - """ - ) - testdir.makepyfile( - """ - def test_proper(pytestconfig): - import conftest - assert conftest.values == [1] - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - def test_warn_on_test_item_from_request(self, testdir, request): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def fix(request): - request.node.warn("T1", "hello") - - def test_hello(fix): - pass - """ - ) - result = testdir.runpytest("--disable-pytest-warnings") - assert result.parseoutcomes()["warnings"] > 0 - assert "hello" not in result.stdout.str() - - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - ===*warnings summary*=== - *test_warn_on_test_item_from_request.py::test_hello* - *hello* - """ - ) - - -class TestRootdir(object): - - def test_simple_noini(self, tmpdir): - assert get_common_ancestor([tmpdir]) == tmpdir - a = tmpdir.mkdir("a") - assert get_common_ancestor([a, tmpdir]) == tmpdir - assert get_common_ancestor([tmpdir, a]) == tmpdir - with tmpdir.as_cwd(): - assert get_common_ancestor([]) == tmpdir - no_path = tmpdir.join("does-not-exist") - assert get_common_ancestor([no_path]) == tmpdir - assert get_common_ancestor([no_path.join("a")]) == tmpdir - - @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) - def test_with_ini(self, tmpdir, name): - inifile = tmpdir.join(name) - inifile.write("[pytest]\n") - - a = tmpdir.mkdir("a") - b = a.mkdir("b") - for args in ([tmpdir], [a], [b]): - rootdir, inifile, inicfg = determine_setup(None, args) - assert rootdir == tmpdir - assert inifile == inifile - rootdir, inifile, inicfg = determine_setup(None, [b, a]) - assert rootdir == tmpdir - assert inifile == inifile - - @pytest.mark.parametrize("name", "setup.cfg tox.ini".split()) - def test_pytestini_overides_empty_other(self, tmpdir, name): - inifile = tmpdir.ensure("pytest.ini") - a = tmpdir.mkdir("a") - a.ensure(name) - rootdir, inifile, inicfg = determine_setup(None, [a]) - assert rootdir == tmpdir - assert inifile == inifile - - def test_setuppy_fallback(self, tmpdir): - a = tmpdir.mkdir("a") - a.ensure("setup.cfg") - tmpdir.ensure("setup.py") - rootdir, inifile, inicfg = determine_setup(None, [a]) - assert rootdir == tmpdir - assert inifile is None - assert inicfg == {} - - def test_nothing(self, tmpdir, monkeypatch): - monkeypatch.chdir(str(tmpdir)) - rootdir, inifile, inicfg = determine_setup(None, [tmpdir]) - assert rootdir == tmpdir - assert inifile is None - assert inicfg == {} - - def test_with_specific_inifile(self, tmpdir): - inifile = tmpdir.ensure("pytest.ini") - rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir]) - assert rootdir == tmpdir - - -class TestOverrideIniArgs(object): - - @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) - def test_override_ini_names(self, testdir, name): - testdir.tmpdir.join(name).write( - textwrap.dedent( - """ - [pytest] - custom = 1.0""" - ) - ) - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("custom", "")""" - ) - testdir.makepyfile( - """ - def test_pass(pytestconfig): - ini_val = pytestconfig.getini("custom") - print('\\ncustom_option:%s\\n' % ini_val)""" - ) - - result = testdir.runpytest("--override-ini", "custom=2.0", "-s") - assert result.ret == 0 - result.stdout.fnmatch_lines(["custom_option:2.0"]) - - result = testdir.runpytest( - "--override-ini", "custom=2.0", "--override-ini=custom=3.0", "-s" - ) - assert result.ret == 0 - result.stdout.fnmatch_lines(["custom_option:3.0"]) - - def test_override_ini_pathlist(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - parser.addini("paths", "my new ini value", type="pathlist")""" - ) - testdir.makeini( - """ - [pytest] - paths=blah.py""" - ) - testdir.makepyfile( - """ - import py.path - def test_pathlist(pytestconfig): - config_paths = pytestconfig.getini("paths") - print(config_paths) - for cpf in config_paths: - print('\\nuser_path:%s' % cpf.basename)""" - ) - result = testdir.runpytest( - "--override-ini", "paths=foo/bar1.py foo/bar2.py", "-s" - ) - result.stdout.fnmatch_lines(["user_path:bar1.py", "user_path:bar2.py"]) - - def test_override_multiple_and_default(self, testdir): - testdir.makeconftest( - """ - def pytest_addoption(parser): - addini = parser.addini - addini("custom_option_1", "", default="o1") - addini("custom_option_2", "", default="o2") - addini("custom_option_3", "", default=False, type="bool") - addini("custom_option_4", "", default=True, type="bool")""" - ) - testdir.makeini( - """ - [pytest] - custom_option_1=custom_option_1 - custom_option_2=custom_option_2 - """ - ) - testdir.makepyfile( - """ - def test_multiple_options(pytestconfig): - prefix = "custom_option" - for x in range(1, 5): - ini_value=pytestconfig.getini("%s_%d" % (prefix, x)) - print('\\nini%d:%s' % (x, ini_value)) - """ - ) - result = testdir.runpytest( - "--override-ini", - "custom_option_1=fulldir=/tmp/user1", - "-o", - "custom_option_2=url=/tmp/user2?a=b&d=e", - "-o", - "custom_option_3=True", - "-o", - "custom_option_4=no", - "-s", - ) - result.stdout.fnmatch_lines( - [ - "ini1:fulldir=/tmp/user1", - "ini2:url=/tmp/user2?a=b&d=e", - "ini3:True", - "ini4:False", - ] - ) - - def test_override_ini_usage_error_bad_style(self, testdir): - testdir.makeini( - """ - [pytest] - xdist_strict=False - """ - ) - result = testdir.runpytest("--override-ini", "xdist_strict True", "-s") - result.stderr.fnmatch_lines(["*ERROR* *expects option=value*"]) - - @pytest.mark.parametrize("with_ini", [True, False]) - def test_override_ini_handled_asap(self, testdir, with_ini): - """-o should be handled as soon as possible and always override what's in ini files (#2238)""" - if with_ini: - testdir.makeini( - """ - [pytest] - python_files=test_*.py - """ - ) - testdir.makepyfile( - unittest_ini_handle=""" - def test(): - pass - """ - ) - result = testdir.runpytest("--override-ini", "python_files=unittest_*.py") - result.stdout.fnmatch_lines(["*1 passed in*"]) - - def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): - monkeypatch.chdir(str(tmpdir)) - a = tmpdir.mkdir("a") - b = tmpdir.mkdir("b") - rootdir, inifile, inicfg = determine_setup(None, [a, b]) - assert rootdir == tmpdir - assert inifile is None - - def test_with_arg_outside_cwd_with_inifile(self, tmpdir): - a = tmpdir.mkdir("a") - b = tmpdir.mkdir("b") - inifile = a.ensure("pytest.ini") - rootdir, parsed_inifile, inicfg = determine_setup(None, [a, b]) - assert rootdir == a - assert inifile == parsed_inifile - - @pytest.mark.parametrize("dirs", ([], ["does-not-exist"], ["a/does-not-exist"])) - def test_with_non_dir_arg(self, dirs, tmpdir): - with tmpdir.ensure(dir=True).as_cwd(): - rootdir, inifile, inicfg = determine_setup(None, dirs) - assert rootdir == tmpdir - assert inifile is None - - def test_with_existing_file_in_subdir(self, tmpdir): - a = tmpdir.mkdir("a") - a.ensure("exist") - with tmpdir.as_cwd(): - rootdir, inifile, inicfg = determine_setup(None, ["a/exist"]) - assert rootdir == tmpdir - assert inifile is None - - def test_addopts_before_initini(self, monkeypatch): - cache_dir = ".custom_cache" - monkeypatch.setenv("PYTEST_ADDOPTS", "-o cache_dir=%s" % cache_dir) - from _pytest.config import get_config - - config = get_config() - config._preparse([], addopts=True) - assert config._override_ini == ["cache_dir=%s" % cache_dir] - - def test_override_ini_does_not_contain_paths(self): - """Check that -o no longer swallows all options after it (#3103)""" - from _pytest.config import get_config - - config = get_config() - config._preparse(["-o", "cache_dir=/cache", "/some/test/path"]) - assert config._override_ini == ["cache_dir=/cache"] - - def test_multiple_override_ini_options(self, testdir, request): - """Ensure a file path following a '-o' option does not generate an error (#3103)""" - testdir.makepyfile( - **{ - "conftest.py": """ - def pytest_addoption(parser): - parser.addini('foo', default=None, help='some option') - parser.addini('bar', default=None, help='some option') - """, - "test_foo.py": """ - def test(pytestconfig): - assert pytestconfig.getini('foo') == '1' - assert pytestconfig.getini('bar') == '0' - """, - "test_bar.py": """ - def test(): - assert False - """, - } - ) - result = testdir.runpytest("-o", "foo=1", "-o", "bar=0", "test_foo.py") - assert "ERROR:" not in result.stderr.str() - result.stdout.fnmatch_lines(["collected 1 item", "*= 1 passed in *="]) diff --git a/third_party/python/pytest/testing/test_conftest.py b/third_party/python/pytest/testing/test_conftest.py deleted file mode 100644 index 61b640976f11..000000000000 --- a/third_party/python/pytest/testing/test_conftest.py +++ /dev/null @@ -1,543 +0,0 @@ -from __future__ import absolute_import, division, print_function -from textwrap import dedent - -import _pytest._code -import py -import pytest -from _pytest.config import PytestPluginManager -from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR - - -@pytest.fixture(scope="module", params=["global", "inpackage"]) -def basedir(request, tmpdir_factory): - from _pytest.tmpdir import tmpdir - - tmpdir = tmpdir(request, tmpdir_factory) - tmpdir.ensure("adir/conftest.py").write("a=1 ; Directory = 3") - tmpdir.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") - if request.param == "inpackage": - tmpdir.ensure("adir/__init__.py") - tmpdir.ensure("adir/b/__init__.py") - return tmpdir - - -def ConftestWithSetinitial(path): - conftest = PytestPluginManager() - conftest_setinitial(conftest, [path]) - return conftest - - -def conftest_setinitial(conftest, args, confcutdir=None): - - class Namespace(object): - - def __init__(self): - self.file_or_dir = args - self.confcutdir = str(confcutdir) - self.noconftest = False - - conftest._set_initial_conftests(Namespace()) - - -class TestConftestValueAccessGlobal(object): - - def test_basic_init(self, basedir): - conftest = PytestPluginManager() - p = basedir.join("adir") - assert conftest._rget_with_confmod("a", p)[1] == 1 - - def test_immediate_initialiation_and_incremental_are_the_same(self, basedir): - conftest = PytestPluginManager() - len(conftest._path2confmods) - conftest._getconftestmodules(basedir) - snap1 = len(conftest._path2confmods) - # assert len(conftest._path2confmods) == snap1 + 1 - conftest._getconftestmodules(basedir.join("adir")) - assert len(conftest._path2confmods) == snap1 + 1 - conftest._getconftestmodules(basedir.join("b")) - assert len(conftest._path2confmods) == snap1 + 2 - - def test_value_access_not_existing(self, basedir): - conftest = ConftestWithSetinitial(basedir) - with pytest.raises(KeyError): - conftest._rget_with_confmod("a", basedir) - - def test_value_access_by_path(self, basedir): - conftest = ConftestWithSetinitial(basedir) - adir = basedir.join("adir") - assert conftest._rget_with_confmod("a", adir)[1] == 1 - assert conftest._rget_with_confmod("a", adir.join("b"))[1] == 1.5 - - def test_value_access_with_confmod(self, basedir): - startdir = basedir.join("adir", "b") - startdir.ensure("xx", dir=True) - conftest = ConftestWithSetinitial(startdir) - mod, value = conftest._rget_with_confmod("a", startdir) - assert value == 1.5 - path = py.path.local(mod.__file__) - assert path.dirpath() == basedir.join("adir", "b") - assert path.purebasename.startswith("conftest") - - -def test_conftest_in_nonpkg_with_init(tmpdir): - tmpdir.ensure("adir-1.0/conftest.py").write("a=1 ; Directory = 3") - tmpdir.ensure("adir-1.0/b/conftest.py").write("b=2 ; a = 1.5") - tmpdir.ensure("adir-1.0/b/__init__.py") - tmpdir.ensure("adir-1.0/__init__.py") - ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) - - -def test_doubledash_considered(testdir): - conf = testdir.mkdir("--option") - conf.ensure("conftest.py") - conftest = PytestPluginManager() - conftest_setinitial(conftest, [conf.basename, conf.basename]) - values = conftest._getconftestmodules(conf) - assert len(values) == 1 - - -def test_issue151_load_all_conftests(testdir): - names = "code proj src".split() - for name in names: - p = testdir.mkdir(name) - p.ensure("conftest.py") - - conftest = PytestPluginManager() - conftest_setinitial(conftest, names) - d = list(conftest._conftestpath2mod.values()) - assert len(d) == len(names) - - -def test_conftest_global_import(testdir): - testdir.makeconftest("x=3") - p = testdir.makepyfile( - """ - import py, pytest - from _pytest.config import PytestPluginManager - conf = PytestPluginManager() - mod = conf._importconftest(py.path.local("conftest.py")) - assert mod.x == 3 - import conftest - assert conftest is mod, (conftest, mod) - subconf = py.path.local().ensure("sub", "conftest.py") - subconf.write("y=4") - mod2 = conf._importconftest(subconf) - assert mod != mod2 - assert mod2.y == 4 - import conftest - assert conftest is mod2, (conftest, mod) - """ - ) - res = testdir.runpython(p) - assert res.ret == 0 - - -def test_conftestcutdir(testdir): - conf = testdir.makeconftest("") - p = testdir.mkdir("x") - conftest = PytestPluginManager() - conftest_setinitial(conftest, [testdir.tmpdir], confcutdir=p) - values = conftest._getconftestmodules(p) - assert len(values) == 0 - values = conftest._getconftestmodules(conf.dirpath()) - assert len(values) == 0 - assert conf not in conftest._conftestpath2mod - # but we can still import a conftest directly - conftest._importconftest(conf) - values = conftest._getconftestmodules(conf.dirpath()) - assert values[0].__file__.startswith(str(conf)) - # and all sub paths get updated properly - values = conftest._getconftestmodules(p) - assert len(values) == 1 - assert values[0].__file__.startswith(str(conf)) - - -def test_conftestcutdir_inplace_considered(testdir): - conf = testdir.makeconftest("") - conftest = PytestPluginManager() - conftest_setinitial(conftest, [conf.dirpath()], confcutdir=conf.dirpath()) - values = conftest._getconftestmodules(conf.dirpath()) - assert len(values) == 1 - assert values[0].__file__.startswith(str(conf)) - - -@pytest.mark.parametrize("name", "test tests whatever .dotdir".split()) -def test_setinitial_conftest_subdirs(testdir, name): - sub = testdir.mkdir(name) - subconftest = sub.ensure("conftest.py") - conftest = PytestPluginManager() - conftest_setinitial(conftest, [sub.dirpath()], confcutdir=testdir.tmpdir) - if name not in ("whatever", ".dotdir"): - assert subconftest in conftest._conftestpath2mod - assert len(conftest._conftestpath2mod) == 1 - else: - assert subconftest not in conftest._conftestpath2mod - assert len(conftest._conftestpath2mod) == 0 - - -def test_conftest_confcutdir(testdir): - testdir.makeconftest("assert 0") - x = testdir.mkdir("x") - x.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_addoption(parser): - parser.addoption("--xyz", action="store_true") - """ - ) - ) - result = testdir.runpytest("-h", "--confcutdir=%s" % x, x) - result.stdout.fnmatch_lines(["*--xyz*"]) - assert "warning: could not load initial" not in result.stdout.str() - - -def test_no_conftest(testdir): - testdir.makeconftest("assert 0") - result = testdir.runpytest("--noconftest") - assert result.ret == EXIT_NOTESTSCOLLECTED - - result = testdir.runpytest() - assert result.ret == EXIT_USAGEERROR - - -def test_conftest_existing_resultlog(testdir): - x = testdir.mkdir("tests") - x.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_addoption(parser): - parser.addoption("--xyz", action="store_true") - """ - ) - ) - testdir.makefile(ext=".log", result="") # Writes result.log - result = testdir.runpytest("-h", "--resultlog", "result.log") - result.stdout.fnmatch_lines(["*--xyz*"]) - - -def test_conftest_existing_junitxml(testdir): - x = testdir.mkdir("tests") - x.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_addoption(parser): - parser.addoption("--xyz", action="store_true") - """ - ) - ) - testdir.makefile(ext=".xml", junit="") # Writes junit.xml - result = testdir.runpytest("-h", "--junitxml", "junit.xml") - result.stdout.fnmatch_lines(["*--xyz*"]) - - -def test_conftest_import_order(testdir, monkeypatch): - ct1 = testdir.makeconftest("") - sub = testdir.mkdir("sub") - ct2 = sub.join("conftest.py") - ct2.write("") - - def impct(p): - return p - - conftest = PytestPluginManager() - conftest._confcutdir = testdir.tmpdir - monkeypatch.setattr(conftest, "_importconftest", impct) - assert conftest._getconftestmodules(sub) == [ct1, ct2] - - -def test_fixture_dependency(testdir, monkeypatch): - ct1 = testdir.makeconftest("") - ct1 = testdir.makepyfile("__init__.py") - ct1.write("") - sub = testdir.mkdir("sub") - sub.join("__init__.py").write("") - sub.join("conftest.py").write( - dedent( - """ - import pytest - - @pytest.fixture - def not_needed(): - assert False, "Should not be called!" - - @pytest.fixture - def foo(): - assert False, "Should not be called!" - - @pytest.fixture - def bar(foo): - return 'bar' - """ - ) - ) - subsub = sub.mkdir("subsub") - subsub.join("__init__.py").write("") - subsub.join("test_bar.py").write( - dedent( - """ - import pytest - - @pytest.fixture - def bar(): - return 'sub bar' - - def test_event_fixture(bar): - assert bar == 'sub bar' - """ - ) - ) - result = testdir.runpytest("sub") - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_conftest_found_with_double_dash(testdir): - sub = testdir.mkdir("sub") - sub.join("conftest.py").write( - dedent( - """ - def pytest_addoption(parser): - parser.addoption("--hello-world", action="store_true") - """ - ) - ) - p = sub.join("test_hello.py") - p.write("def test_hello(): pass") - result = testdir.runpytest(str(p) + "::test_hello", "-h") - result.stdout.fnmatch_lines( - """ - *--hello-world* - """ - ) - - -class TestConftestVisibility(object): - - def _setup_tree(self, testdir): # for issue616 - # example mostly taken from: - # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html - runner = testdir.mkdir("empty") - package = testdir.mkdir("package") - - package.join("conftest.py").write( - dedent( - """\ - import pytest - @pytest.fixture - def fxtr(): - return "from-package" - """ - ) - ) - package.join("test_pkgroot.py").write( - dedent( - """\ - def test_pkgroot(fxtr): - assert fxtr == "from-package" - """ - ) - ) - - swc = package.mkdir("swc") - swc.join("__init__.py").ensure() - swc.join("conftest.py").write( - dedent( - """\ - import pytest - @pytest.fixture - def fxtr(): - return "from-swc" - """ - ) - ) - swc.join("test_with_conftest.py").write( - dedent( - """\ - def test_with_conftest(fxtr): - assert fxtr == "from-swc" - - """ - ) - ) - - snc = package.mkdir("snc") - snc.join("__init__.py").ensure() - snc.join("test_no_conftest.py").write( - dedent( - """\ - def test_no_conftest(fxtr): - assert fxtr == "from-package" # No local conftest.py, so should - # use value from parent dir's - - """ - ) - ) - print("created directory structure:") - for x in testdir.tmpdir.visit(): - print(" " + x.relto(testdir.tmpdir)) - - return {"runner": runner, "package": package, "swc": swc, "snc": snc} - - # N.B.: "swc" stands for "subdir with conftest.py" - # "snc" stands for "subdir no [i.e. without] conftest.py" - @pytest.mark.parametrize( - "chdir,testarg,expect_ntests_passed", - [ - # Effective target: package/.. - ("runner", "..", 3), - ("package", "..", 3), - ("swc", "../..", 3), - ("snc", "../..", 3), - # Effective target: package - ("runner", "../package", 3), - ("package", ".", 3), - ("swc", "..", 3), - ("snc", "..", 3), - # Effective target: package/swc - ("runner", "../package/swc", 1), - ("package", "./swc", 1), - ("swc", ".", 1), - ("snc", "../swc", 1), - # Effective target: package/snc - ("runner", "../package/snc", 1), - ("package", "./snc", 1), - ("swc", "../snc", 1), - ("snc", ".", 1), - ], - ) - @pytest.mark.issue616 - def test_parsefactories_relative_node_ids( - self, testdir, chdir, testarg, expect_ntests_passed - ): - dirs = self._setup_tree(testdir) - print("pytest run in cwd: %s" % (dirs[chdir].relto(testdir.tmpdir))) - print("pytestarg : %s" % (testarg)) - print("expected pass : %s" % (expect_ntests_passed)) - with dirs[chdir].as_cwd(): - reprec = testdir.inline_run(testarg, "-q", "--traceconfig") - reprec.assertoutcome(passed=expect_ntests_passed) - - -@pytest.mark.parametrize( - "confcutdir,passed,error", [(".", 2, 0), ("src", 1, 1), (None, 1, 1)] -) -def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error): - """Test that conftest files are detected only up to an ini file, unless - an explicit --confcutdir option is given. - """ - root = testdir.tmpdir - src = root.join("src").ensure(dir=1) - src.join("pytest.ini").write("[pytest]") - src.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def fix1(): pass - """ - ) - ) - src.join("test_foo.py").write( - _pytest._code.Source( - """ - def test_1(fix1): - pass - def test_2(out_of_reach): - pass - """ - ) - ) - root.join("conftest.py").write( - _pytest._code.Source( - """ - import pytest - @pytest.fixture - def out_of_reach(): pass - """ - ) - ) - - args = [str(src)] - if confcutdir: - args = ["--confcutdir=%s" % root.join(confcutdir)] - result = testdir.runpytest(*args) - match = "" - if passed: - match += "*%d passed*" % passed - if error: - match += "*%d error*" % error - result.stdout.fnmatch_lines(match) - - -def test_issue1073_conftest_special_objects(testdir): - testdir.makeconftest( - """ - class DontTouchMe(object): - def __getattr__(self, x): - raise Exception('cant touch me') - - x = DontTouchMe() - """ - ) - testdir.makepyfile( - """ - def test_some(): - pass - """ - ) - res = testdir.runpytest() - assert res.ret == 0 - - -def test_conftest_exception_handling(testdir): - testdir.makeconftest( - """ - raise ValueError() - """ - ) - testdir.makepyfile( - """ - def test_some(): - pass - """ - ) - res = testdir.runpytest() - assert res.ret == 4 - assert "raise ValueError()" in [line.strip() for line in res.errlines] - - -def test_hook_proxy(testdir): - """Session's gethookproxy() would cache conftests incorrectly (#2016). - It was decided to remove the cache altogether. - """ - testdir.makepyfile( - **{ - "root/demo-0/test_foo1.py": "def test1(): pass", - "root/demo-a/test_foo2.py": "def test1(): pass", - "root/demo-a/conftest.py": """ - def pytest_ignore_collect(path, config): - return True - """, - "root/demo-b/test_foo3.py": "def test1(): pass", - "root/demo-c/test_foo4.py": "def test1(): pass", - } - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - ["*test_foo1.py*", "*test_foo3.py*", "*test_foo4.py*", "*3 passed*"] - ) - - -def test_required_option_help(testdir): - testdir.makeconftest("assert 0") - x = testdir.mkdir("x") - x.join("conftest.py").write( - _pytest._code.Source( - """ - def pytest_addoption(parser): - parser.addoption("--xyz", action="store_true", required=True) - """ - ) - ) - result = testdir.runpytest("-h", x) - assert "argument --xyz is required" not in result.stdout.str() - assert "general:" in result.stdout.str() diff --git a/third_party/python/pytest/testing/test_doctest.py b/third_party/python/pytest/testing/test_doctest.py deleted file mode 100644 index 7f3aff3b0e10..000000000000 --- a/third_party/python/pytest/testing/test_doctest.py +++ /dev/null @@ -1,1206 +0,0 @@ -# encoding: utf-8 -from __future__ import absolute_import, division, print_function -import sys -import _pytest._code -from _pytest.compat import MODULE_NOT_FOUND_ERROR -from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile -import pytest - - -class TestDoctests(object): - - def test_collect_testtextfile(self, testdir): - w = testdir.maketxtfile(whatever="") - checkfile = testdir.maketxtfile( - test_something=""" - alskdjalsdk - >>> i = 5 - >>> i-1 - 4 - """ - ) - - for x in (testdir.tmpdir, checkfile): - # print "checking that %s returns custom items" % (x,) - items, reprec = testdir.inline_genitems(x) - assert len(items) == 1 - assert isinstance(items[0], DoctestItem) - assert isinstance(items[0].parent, DoctestTextfile) - # Empty file has no items. - items, reprec = testdir.inline_genitems(w) - assert len(items) == 0 - - def test_collect_module_empty(self, testdir): - path = testdir.makepyfile(whatever="#") - for p in (path, testdir.tmpdir): - items, reprec = testdir.inline_genitems(p, "--doctest-modules") - assert len(items) == 0 - - def test_collect_module_single_modulelevel_doctest(self, testdir): - path = testdir.makepyfile(whatever='""">>> pass"""') - for p in (path, testdir.tmpdir): - items, reprec = testdir.inline_genitems(p, "--doctest-modules") - assert len(items) == 1 - assert isinstance(items[0], DoctestItem) - assert isinstance(items[0].parent, DoctestModule) - - def test_collect_module_two_doctest_one_modulelevel(self, testdir): - path = testdir.makepyfile( - whatever=""" - '>>> x = None' - def my_func(): - ">>> magic = 42 " - """ - ) - for p in (path, testdir.tmpdir): - items, reprec = testdir.inline_genitems(p, "--doctest-modules") - assert len(items) == 2 - assert isinstance(items[0], DoctestItem) - assert isinstance(items[1], DoctestItem) - assert isinstance(items[0].parent, DoctestModule) - assert items[0].parent is items[1].parent - - def test_collect_module_two_doctest_no_modulelevel(self, testdir): - path = testdir.makepyfile( - whatever=""" - '# Empty' - def my_func(): - ">>> magic = 42 " - def unuseful(): - ''' - # This is a function - # >>> # it doesn't have any doctest - ''' - def another(): - ''' - # This is another function - >>> import os # this one does have a doctest - ''' - """ - ) - for p in (path, testdir.tmpdir): - items, reprec = testdir.inline_genitems(p, "--doctest-modules") - assert len(items) == 2 - assert isinstance(items[0], DoctestItem) - assert isinstance(items[1], DoctestItem) - assert isinstance(items[0].parent, DoctestModule) - assert items[0].parent is items[1].parent - - def test_simple_doctestfile(self, testdir): - p = testdir.maketxtfile( - test_doc=""" - >>> x = 1 - >>> x == 1 - False - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(failed=1) - - def test_new_pattern(self, testdir): - p = testdir.maketxtfile( - xdoc=""" - >>> x = 1 - >>> x == 1 - False - """ - ) - reprec = testdir.inline_run(p, "--doctest-glob=x*.txt") - reprec.assertoutcome(failed=1) - - def test_multiple_patterns(self, testdir): - """Test support for multiple --doctest-glob arguments (#1255). - """ - testdir.maketxtfile( - xdoc=""" - >>> 1 - 1 - """ - ) - testdir.makefile( - ".foo", - test=""" - >>> 1 - 1 - """, - ) - testdir.maketxtfile( - test_normal=""" - >>> 1 - 1 - """ - ) - expected = {"xdoc.txt", "test.foo", "test_normal.txt"} - assert {x.basename for x in testdir.tmpdir.listdir()} == expected - args = ["--doctest-glob=xdoc*.txt", "--doctest-glob=*.foo"] - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines(["*test.foo *", "*xdoc.txt *", "*2 passed*"]) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*test_normal.txt *", "*1 passed*"]) - - @pytest.mark.parametrize( - " test_string, encoding", - [(u"foo", "ascii"), (u"öäü", "latin1"), (u"öäü", "utf-8")], - ) - def test_encoding(self, testdir, test_string, encoding): - """Test support for doctest_encoding ini option. - """ - testdir.makeini( - """ - [pytest] - doctest_encoding={} - """.format( - encoding - ) - ) - doctest = u""" - >>> u"{}" - {} - """.format( - test_string, repr(test_string) - ) - testdir._makefile(".txt", [doctest], {}, encoding=encoding) - - result = testdir.runpytest() - - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_doctest_unexpected_exception(self, testdir): - testdir.maketxtfile( - """ - >>> i = 0 - >>> 0 / i - 2 - """ - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines( - [ - "*unexpected_exception*", - "*>>> i = 0*", - "*>>> 0 / i*", - "*UNEXPECTED*ZeroDivision*", - ] - ) - - def test_docstring_partial_context_around_error(self, testdir): - """Test that we show some context before the actual line of a failing - doctest. - """ - testdir.makepyfile( - ''' - def foo(): - """ - text-line-1 - text-line-2 - text-line-3 - text-line-4 - text-line-5 - text-line-6 - text-line-7 - text-line-8 - text-line-9 - text-line-10 - text-line-11 - >>> 1 + 1 - 3 - - text-line-after - """ - ''' - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines( - [ - "*docstring_partial_context_around_error*", - "005*text-line-3", - "006*text-line-4", - "013*text-line-11", - "014*>>> 1 + 1", - "Expected:", - " 3", - "Got:", - " 2", - ] - ) - # lines below should be trimmed out - assert "text-line-2" not in result.stdout.str() - assert "text-line-after" not in result.stdout.str() - - def test_docstring_full_context_around_error(self, testdir): - """Test that we show the whole context before the actual line of a failing - doctest, provided that the context is up to 10 lines long. - """ - testdir.makepyfile( - ''' - def foo(): - """ - text-line-1 - text-line-2 - - >>> 1 + 1 - 3 - """ - ''' - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines( - [ - "*docstring_full_context_around_error*", - "003*text-line-1", - "004*text-line-2", - "006*>>> 1 + 1", - "Expected:", - " 3", - "Got:", - " 2", - ] - ) - - def test_doctest_linedata_missing(self, testdir): - testdir.tmpdir.join("hello.py").write( - _pytest._code.Source( - """ - class Fun(object): - @property - def test(self): - ''' - >>> a = 1 - >>> 1/0 - ''' - """ - ) - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines( - [ - "*hello*", - "*EXAMPLE LOCATION UNKNOWN, not showing all tests of that example*", - "*1/0*", - "*UNEXPECTED*ZeroDivision*", - "*1 failed*", - ] - ) - - def test_doctest_unex_importerror_only_txt(self, testdir): - testdir.maketxtfile( - """ - >>> import asdalsdkjaslkdjasd - >>> - """ - ) - result = testdir.runpytest() - # doctest is never executed because of error during hello.py collection - result.stdout.fnmatch_lines( - [ - "*>>> import asdals*", - "*UNEXPECTED*{e}*".format(e=MODULE_NOT_FOUND_ERROR), - "{e}: No module named *asdal*".format(e=MODULE_NOT_FOUND_ERROR), - ] - ) - - def test_doctest_unex_importerror_with_module(self, testdir): - testdir.tmpdir.join("hello.py").write( - _pytest._code.Source( - """ - import asdalsdkjaslkdjasd - """ - ) - ) - testdir.maketxtfile( - """ - >>> import hello - >>> - """ - ) - result = testdir.runpytest("--doctest-modules") - # doctest is never executed because of error during hello.py collection - result.stdout.fnmatch_lines( - [ - "*ERROR collecting hello.py*", - "*{e}: No module named *asdals*".format(e=MODULE_NOT_FOUND_ERROR), - "*Interrupted: 1 errors during collection*", - ] - ) - - def test_doctestmodule(self, testdir): - p = testdir.makepyfile( - """ - ''' - >>> x = 1 - >>> x == 1 - False - - ''' - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(failed=1) - - def test_doctestmodule_external_and_issue116(self, testdir): - p = testdir.mkpydir("hello") - p.join("__init__.py").write( - _pytest._code.Source( - """ - def somefunc(): - ''' - >>> i = 0 - >>> i + 1 - 2 - ''' - """ - ) - ) - result = testdir.runpytest(p, "--doctest-modules") - result.stdout.fnmatch_lines( - [ - "004 *>>> i = 0", - "005 *>>> i + 1", - "*Expected:", - "* 2", - "*Got:", - "* 1", - "*:5: DocTestFailure", - ] - ) - - def test_txtfile_failing(self, testdir): - p = testdir.maketxtfile( - """ - >>> i = 0 - >>> i + 1 - 2 - """ - ) - result = testdir.runpytest(p, "-s") - result.stdout.fnmatch_lines( - [ - "001 >>> i = 0", - "002 >>> i + 1", - "Expected:", - " 2", - "Got:", - " 1", - "*test_txtfile_failing.txt:2: DocTestFailure", - ] - ) - - def test_txtfile_with_fixtures(self, testdir): - p = testdir.maketxtfile( - """ - >>> dir = getfixture('tmpdir') - >>> type(dir).__name__ - 'LocalPath' - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(passed=1) - - def test_txtfile_with_usefixtures_in_ini(self, testdir): - testdir.makeini( - """ - [pytest] - usefixtures = myfixture - """ - ) - testdir.makeconftest( - """ - import pytest - @pytest.fixture - def myfixture(monkeypatch): - monkeypatch.setenv("HELLO", "WORLD") - """ - ) - - p = testdir.maketxtfile( - """ - >>> import os - >>> os.environ["HELLO"] - 'WORLD' - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(passed=1) - - def test_doctestmodule_with_fixtures(self, testdir): - p = testdir.makepyfile( - """ - ''' - >>> dir = getfixture('tmpdir') - >>> type(dir).__name__ - 'LocalPath' - ''' - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(passed=1) - - def test_doctestmodule_three_tests(self, testdir): - p = testdir.makepyfile( - """ - ''' - >>> dir = getfixture('tmpdir') - >>> type(dir).__name__ - 'LocalPath' - ''' - def my_func(): - ''' - >>> magic = 42 - >>> magic - 42 - 0 - ''' - def unuseful(): - pass - def another(): - ''' - >>> import os - >>> os is os - True - ''' - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(passed=3) - - def test_doctestmodule_two_tests_one_fail(self, testdir): - p = testdir.makepyfile( - """ - class MyClass(object): - def bad_meth(self): - ''' - >>> magic = 42 - >>> magic - 0 - ''' - def nice_meth(self): - ''' - >>> magic = 42 - >>> magic - 42 - 0 - ''' - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(failed=1, passed=1) - - def test_ignored_whitespace(self, testdir): - testdir.makeini( - """ - [pytest] - doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE - """ - ) - p = testdir.makepyfile( - """ - class MyClass(object): - ''' - >>> a = "foo " - >>> print(a) - foo - ''' - pass - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(passed=1) - - def test_non_ignored_whitespace(self, testdir): - testdir.makeini( - """ - [pytest] - doctest_optionflags = ELLIPSIS - """ - ) - p = testdir.makepyfile( - """ - class MyClass(object): - ''' - >>> a = "foo " - >>> print(a) - foo - ''' - pass - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(failed=1, passed=0) - - def test_ignored_whitespace_glob(self, testdir): - testdir.makeini( - """ - [pytest] - doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE - """ - ) - p = testdir.maketxtfile( - xdoc=""" - >>> a = "foo " - >>> print(a) - foo - """ - ) - reprec = testdir.inline_run(p, "--doctest-glob=x*.txt") - reprec.assertoutcome(passed=1) - - def test_non_ignored_whitespace_glob(self, testdir): - testdir.makeini( - """ - [pytest] - doctest_optionflags = ELLIPSIS - """ - ) - p = testdir.maketxtfile( - xdoc=""" - >>> a = "foo " - >>> print(a) - foo - """ - ) - reprec = testdir.inline_run(p, "--doctest-glob=x*.txt") - reprec.assertoutcome(failed=1, passed=0) - - def test_contains_unicode(self, testdir): - """Fix internal error with docstrings containing non-ascii characters. - """ - testdir.makepyfile( - u''' - # encoding: utf-8 - def foo(): - """ - >>> name = 'с' # not letter 'c' but instead Cyrillic 's'. - 'anything' - """ - ''' - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines(["Got nothing", "* 1 failed in*"]) - - def test_ignore_import_errors_on_doctest(self, testdir): - p = testdir.makepyfile( - """ - import asdf - - def add_one(x): - ''' - >>> add_one(1) - 2 - ''' - return x + 1 - """ - ) - - reprec = testdir.inline_run( - p, "--doctest-modules", "--doctest-ignore-import-errors" - ) - reprec.assertoutcome(skipped=1, failed=1, passed=0) - - def test_junit_report_for_doctest(self, testdir): - """ - #713: Fix --junit-xml option when used with --doctest-modules. - """ - p = testdir.makepyfile( - """ - def foo(): - ''' - >>> 1 + 1 - 3 - ''' - pass - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules", "--junit-xml=junit.xml") - reprec.assertoutcome(failed=1) - - def test_unicode_doctest(self, testdir): - """ - Test case for issue 2434: DecodeError on Python 2 when doctest contains non-ascii - characters. - """ - p = testdir.maketxtfile( - test_unicode_doctest=""" - .. doctest:: - - >>> print( - ... "Hi\\n\\nByé") - Hi - ... - Byé - >>> 1/0 # Byé - 1 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - ["*UNEXPECTED EXCEPTION: ZeroDivisionError*", "*1 failed*"] - ) - - def test_unicode_doctest_module(self, testdir): - """ - Test case for issue 2434: DecodeError on Python 2 when doctest docstring - contains non-ascii characters. - """ - p = testdir.makepyfile( - test_unicode_doctest_module=""" - # -*- encoding: utf-8 -*- - from __future__ import unicode_literals - - def fix_bad_unicode(text): - ''' - >>> print(fix_bad_unicode('único')) - único - ''' - return "único" - """ - ) - result = testdir.runpytest(p, "--doctest-modules") - result.stdout.fnmatch_lines(["* 1 passed *"]) - - def test_print_unicode_value(self, testdir): - """ - Test case for issue 3583: Printing Unicode in doctest under Python 2.7 - doesn't work - """ - p = testdir.maketxtfile( - test_print_unicode_value=r""" - Here is a doctest:: - - >>> print(u'\xE5\xE9\xEE\xF8\xFC') - åéîøü - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["* 1 passed *"]) - - def test_reportinfo(self, testdir): - """ - Test case to make sure that DoctestItem.reportinfo() returns lineno. - """ - p = testdir.makepyfile( - test_reportinfo=""" - def foo(x): - ''' - >>> foo('a') - 'b' - ''' - return 'c' - """ - ) - items, reprec = testdir.inline_genitems(p, "--doctest-modules") - reportinfo = items[0].reportinfo() - assert reportinfo[1] == 1 - - def test_valid_setup_py(self, testdir): - """ - Test to make sure that pytest ignores valid setup.py files when ran - with --doctest-modules - """ - p = testdir.makepyfile( - setup=""" - from setuptools import setup, find_packages - setup(name='sample', - version='0.0', - description='description', - packages=find_packages() - ) - """ - ) - result = testdir.runpytest(p, "--doctest-modules") - result.stdout.fnmatch_lines(["*collected 0 items*"]) - - def test_invalid_setup_py(self, testdir): - """ - Test to make sure that pytest reads setup.py files that are not used - for python packages when ran with --doctest-modules - """ - p = testdir.makepyfile( - setup=""" - def test_foo(): - return 'bar' - """ - ) - result = testdir.runpytest(p, "--doctest-modules") - result.stdout.fnmatch_lines(["*collected 1 item*"]) - - -class TestLiterals(object): - - @pytest.mark.parametrize("config_mode", ["ini", "comment"]) - def test_allow_unicode(self, testdir, config_mode): - """Test that doctests which output unicode work in all python versions - tested by pytest when the ALLOW_UNICODE option is used (either in - the ini file or by an inline comment). - """ - if config_mode == "ini": - testdir.makeini( - """ - [pytest] - doctest_optionflags = ALLOW_UNICODE - """ - ) - comment = "" - else: - comment = "#doctest: +ALLOW_UNICODE" - - testdir.maketxtfile( - test_doc=""" - >>> b'12'.decode('ascii') {comment} - '12' - """.format( - comment=comment - ) - ) - testdir.makepyfile( - foo=""" - def foo(): - ''' - >>> b'12'.decode('ascii') {comment} - '12' - ''' - """.format( - comment=comment - ) - ) - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(passed=2) - - @pytest.mark.parametrize("config_mode", ["ini", "comment"]) - def test_allow_bytes(self, testdir, config_mode): - """Test that doctests which output bytes work in all python versions - tested by pytest when the ALLOW_BYTES option is used (either in - the ini file or by an inline comment)(#1287). - """ - if config_mode == "ini": - testdir.makeini( - """ - [pytest] - doctest_optionflags = ALLOW_BYTES - """ - ) - comment = "" - else: - comment = "#doctest: +ALLOW_BYTES" - - testdir.maketxtfile( - test_doc=""" - >>> b'foo' {comment} - 'foo' - """.format( - comment=comment - ) - ) - testdir.makepyfile( - foo=""" - def foo(): - ''' - >>> b'foo' {comment} - 'foo' - ''' - """.format( - comment=comment - ) - ) - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(passed=2) - - def test_unicode_string(self, testdir): - """Test that doctests which output unicode fail in Python 2 when - the ALLOW_UNICODE option is not used. The same test should pass - in Python 3. - """ - testdir.maketxtfile( - test_doc=""" - >>> b'12'.decode('ascii') - '12' - """ - ) - reprec = testdir.inline_run() - passed = int(sys.version_info[0] >= 3) - reprec.assertoutcome(passed=passed, failed=int(not passed)) - - def test_bytes_literal(self, testdir): - """Test that doctests which output bytes fail in Python 3 when - the ALLOW_BYTES option is not used. The same test should pass - in Python 2 (#1287). - """ - testdir.maketxtfile( - test_doc=""" - >>> b'foo' - 'foo' - """ - ) - reprec = testdir.inline_run() - passed = int(sys.version_info[0] == 2) - reprec.assertoutcome(passed=passed, failed=int(not passed)) - - -class TestDoctestSkips(object): - """ - If all examples in a doctest are skipped due to the SKIP option, then - the tests should be SKIPPED rather than PASSED. (#957) - """ - - @pytest.fixture(params=["text", "module"]) - def makedoctest(self, testdir, request): - - def makeit(doctest): - mode = request.param - if mode == "text": - testdir.maketxtfile(doctest) - else: - assert mode == "module" - testdir.makepyfile('"""\n%s"""' % doctest) - - return makeit - - def test_one_skipped(self, testdir, makedoctest): - makedoctest( - """ - >>> 1 + 1 # doctest: +SKIP - 2 - >>> 2 + 2 - 4 - """ - ) - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(passed=1) - - def test_one_skipped_failed(self, testdir, makedoctest): - makedoctest( - """ - >>> 1 + 1 # doctest: +SKIP - 2 - >>> 2 + 2 - 200 - """ - ) - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(failed=1) - - def test_all_skipped(self, testdir, makedoctest): - makedoctest( - """ - >>> 1 + 1 # doctest: +SKIP - 2 - >>> 2 + 2 # doctest: +SKIP - 200 - """ - ) - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(skipped=1) - - def test_vacuous_all_skipped(self, testdir, makedoctest): - makedoctest("") - reprec = testdir.inline_run("--doctest-modules") - reprec.assertoutcome(passed=0, skipped=0) - - def test_continue_on_failure(self, testdir): - testdir.maketxtfile( - test_something=""" - >>> i = 5 - >>> def foo(): - ... raise ValueError('error1') - >>> foo() - >>> i - >>> i + 2 - 7 - >>> i + 1 - """ - ) - result = testdir.runpytest("--doctest-modules", "--doctest-continue-on-failure") - result.assert_outcomes(passed=0, failed=1) - # The lines that contains the failure are 4, 5, and 8. The first one - # is a stack trace and the other two are mismatches. - result.stdout.fnmatch_lines( - ["*4: UnexpectedException*", "*5: DocTestFailure*", "*8: DocTestFailure*"] - ) - - -class TestDoctestAutoUseFixtures(object): - - SCOPES = ["module", "session", "class", "function"] - - def test_doctest_module_session_fixture(self, testdir): - """Test that session fixtures are initialized for doctest modules (#768) - """ - # session fixture which changes some global data, which will - # be accessed by doctests in a module - testdir.makeconftest( - """ - import pytest - import sys - - @pytest.yield_fixture(autouse=True, scope='session') - def myfixture(): - assert not hasattr(sys, 'pytest_session_data') - sys.pytest_session_data = 1 - yield - del sys.pytest_session_data - """ - ) - testdir.makepyfile( - foo=""" - import sys - - def foo(): - ''' - >>> assert sys.pytest_session_data == 1 - ''' - - def bar(): - ''' - >>> assert sys.pytest_session_data == 1 - ''' - """ - ) - result = testdir.runpytest("--doctest-modules") - result.stdout.fnmatch_lines("*2 passed*") - - @pytest.mark.parametrize("scope", SCOPES) - @pytest.mark.parametrize("enable_doctest", [True, False]) - def test_fixture_scopes(self, testdir, scope, enable_doctest): - """Test that auto-use fixtures work properly with doctest modules. - See #1057 and #1100. - """ - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(autouse=True, scope="{scope}") - def auto(request): - return 99 - """.format( - scope=scope - ) - ) - testdir.makepyfile( - test_1=''' - def test_foo(): - """ - >>> getfixture('auto') + 1 - 100 - """ - def test_bar(): - assert 1 - ''' - ) - params = ("--doctest-modules",) if enable_doctest else () - passes = 3 if enable_doctest else 2 - result = testdir.runpytest(*params) - result.stdout.fnmatch_lines(["*=== %d passed in *" % passes]) - - @pytest.mark.parametrize("scope", SCOPES) - @pytest.mark.parametrize("autouse", [True, False]) - @pytest.mark.parametrize("use_fixture_in_doctest", [True, False]) - def test_fixture_module_doctest_scopes( - self, testdir, scope, autouse, use_fixture_in_doctest - ): - """Test that auto-use fixtures work properly with doctest files. - See #1057 and #1100. - """ - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(autouse={autouse}, scope="{scope}") - def auto(request): - return 99 - """.format( - scope=scope, autouse=autouse - ) - ) - if use_fixture_in_doctest: - testdir.maketxtfile( - test_doc=""" - >>> getfixture('auto') - 99 - """ - ) - else: - testdir.maketxtfile( - test_doc=""" - >>> 1 + 1 - 2 - """ - ) - result = testdir.runpytest("--doctest-modules") - assert "FAILURES" not in str(result.stdout.str()) - result.stdout.fnmatch_lines(["*=== 1 passed in *"]) - - @pytest.mark.parametrize("scope", SCOPES) - def test_auto_use_request_attributes(self, testdir, scope): - """Check that all attributes of a request in an autouse fixture - behave as expected when requested for a doctest item. - """ - testdir.makeconftest( - """ - import pytest - - @pytest.fixture(autouse=True, scope="{scope}") - def auto(request): - if "{scope}" == 'module': - assert request.module is None - if "{scope}" == 'class': - assert request.cls is None - if "{scope}" == 'function': - assert request.function is None - return 99 - """.format( - scope=scope - ) - ) - testdir.maketxtfile( - test_doc=""" - >>> 1 + 1 - 2 - """ - ) - result = testdir.runpytest("--doctest-modules") - assert "FAILURES" not in str(result.stdout.str()) - result.stdout.fnmatch_lines(["*=== 1 passed in *"]) - - -class TestDoctestNamespaceFixture(object): - - SCOPES = ["module", "session", "class", "function"] - - @pytest.mark.parametrize("scope", SCOPES) - def test_namespace_doctestfile(self, testdir, scope): - """ - Check that inserting something into the namespace works in a - simple text file doctest - """ - testdir.makeconftest( - """ - import pytest - import contextlib - - @pytest.fixture(autouse=True, scope="{scope}") - def add_contextlib(doctest_namespace): - doctest_namespace['cl'] = contextlib - """.format( - scope=scope - ) - ) - p = testdir.maketxtfile( - """ - >>> print(cl.__name__) - contextlib - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(passed=1) - - @pytest.mark.parametrize("scope", SCOPES) - def test_namespace_pyfile(self, testdir, scope): - """ - Check that inserting something into the namespace works in a - simple Python file docstring doctest - """ - testdir.makeconftest( - """ - import pytest - import contextlib - - @pytest.fixture(autouse=True, scope="{scope}") - def add_contextlib(doctest_namespace): - doctest_namespace['cl'] = contextlib - """.format( - scope=scope - ) - ) - p = testdir.makepyfile( - """ - def foo(): - ''' - >>> print(cl.__name__) - contextlib - ''' - """ - ) - reprec = testdir.inline_run(p, "--doctest-modules") - reprec.assertoutcome(passed=1) - - -class TestDoctestReportingOption(object): - - def _run_doctest_report(self, testdir, format): - testdir.makepyfile( - """ - def foo(): - ''' - >>> foo() - a b - 0 1 4 - 1 2 4 - 2 3 6 - ''' - print(' a b\\n' - '0 1 4\\n' - '1 2 5\\n' - '2 3 6') - """ - ) - return testdir.runpytest("--doctest-modules", "--doctest-report", format) - - @pytest.mark.parametrize("format", ["udiff", "UDIFF", "uDiFf"]) - def test_doctest_report_udiff(self, testdir, format): - result = self._run_doctest_report(testdir, format) - result.stdout.fnmatch_lines( - [" 0 1 4", " -1 2 4", " +1 2 5", " 2 3 6"] - ) - - def test_doctest_report_cdiff(self, testdir): - result = self._run_doctest_report(testdir, "cdiff") - result.stdout.fnmatch_lines( - [ - " a b", - " 0 1 4", - " ! 1 2 4", - " 2 3 6", - " --- 1,4 ----", - " a b", - " 0 1 4", - " ! 1 2 5", - " 2 3 6", - ] - ) - - def test_doctest_report_ndiff(self, testdir): - result = self._run_doctest_report(testdir, "ndiff") - result.stdout.fnmatch_lines( - [ - " a b", - " 0 1 4", - " - 1 2 4", - " ? ^", - " + 1 2 5", - " ? ^", - " 2 3 6", - ] - ) - - @pytest.mark.parametrize("format", ["none", "only_first_failure"]) - def test_doctest_report_none_or_only_first_failure(self, testdir, format): - result = self._run_doctest_report(testdir, format) - result.stdout.fnmatch_lines( - [ - "Expected:", - " a b", - " 0 1 4", - " 1 2 4", - " 2 3 6", - "Got:", - " a b", - " 0 1 4", - " 1 2 5", - " 2 3 6", - ] - ) - - def test_doctest_report_invalid(self, testdir): - result = self._run_doctest_report(testdir, "obviously_invalid_format") - result.stderr.fnmatch_lines( - [ - "*error: argument --doctest-report: invalid choice: 'obviously_invalid_format' (choose from*" - ] - ) diff --git a/third_party/python/pytest/testing/test_entry_points.py b/third_party/python/pytest/testing/test_entry_points.py deleted file mode 100644 index 8f734778faa8..000000000000 --- a/third_party/python/pytest/testing/test_entry_points.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import absolute_import, division, print_function -import pkg_resources - -import pytest - - -@pytest.mark.parametrize("entrypoint", ["py.test", "pytest"]) -def test_entry_point_exist(entrypoint): - assert entrypoint in pkg_resources.get_entry_map("pytest")["console_scripts"] - - -def test_pytest_entry_points_are_identical(): - entryMap = pkg_resources.get_entry_map("pytest")["console_scripts"] - assert entryMap["pytest"].module_name == entryMap["py.test"].module_name diff --git a/third_party/python/pytest/testing/test_helpconfig.py b/third_party/python/pytest/testing/test_helpconfig.py deleted file mode 100644 index b5424235b168..000000000000 --- a/third_party/python/pytest/testing/test_helpconfig.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import absolute_import, division, print_function -from _pytest.main import EXIT_NOTESTSCOLLECTED -import pytest - - -def test_version(testdir, pytestconfig): - result = testdir.runpytest("--version") - assert result.ret == 0 - # p = py.path.local(py.__file__).dirpath() - result.stderr.fnmatch_lines(["*pytest*%s*imported from*" % (pytest.__version__,)]) - if pytestconfig.pluginmanager.list_plugin_distinfo(): - result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"]) - - -def test_help(testdir): - result = testdir.runpytest("--help") - assert result.ret == 0 - result.stdout.fnmatch_lines( - """ - *-v*verbose* - *setup.cfg* - *minversion* - *to see*markers*pytest --markers* - *to see*fixtures*pytest --fixtures* - """ - ) - - -def test_hookvalidation_unknown(testdir): - testdir.makeconftest( - """ - def pytest_hello(xyz): - pass - """ - ) - result = testdir.runpytest() - assert result.ret != 0 - result.stdout.fnmatch_lines(["*unknown hook*pytest_hello*"]) - - -def test_hookvalidation_optional(testdir): - testdir.makeconftest( - """ - import pytest - @pytest.hookimpl(optionalhook=True) - def pytest_hello(xyz): - pass - """ - ) - result = testdir.runpytest() - assert result.ret == EXIT_NOTESTSCOLLECTED - - -def test_traceconfig(testdir): - result = testdir.runpytest("--traceconfig") - result.stdout.fnmatch_lines(["*using*pytest*py*", "*active plugins*"]) - - -def test_debug(testdir, monkeypatch): - result = testdir.runpytest_subprocess("--debug") - assert result.ret == EXIT_NOTESTSCOLLECTED - p = testdir.tmpdir.join("pytestdebug.log") - assert "pytest_sessionstart" in p.read() - - -def test_PYTEST_DEBUG(testdir, monkeypatch): - monkeypatch.setenv("PYTEST_DEBUG", "1") - result = testdir.runpytest_subprocess() - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stderr.fnmatch_lines( - ["*pytest_plugin_registered*", "*manager*PluginManager*"] - ) diff --git a/third_party/python/pytest/testing/test_junitxml.py b/third_party/python/pytest/testing/test_junitxml.py deleted file mode 100644 index d0be5f267596..000000000000 --- a/third_party/python/pytest/testing/test_junitxml.py +++ /dev/null @@ -1,1231 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function -from xml.dom import minidom -import py -import sys -import os -from _pytest.junitxml import LogXML -import pytest - - -def runandparse(testdir, *args): - resultpath = testdir.tmpdir.join("junit.xml") - result = testdir.runpytest("--junitxml=%s" % resultpath, *args) - xmldoc = minidom.parse(str(resultpath)) - return result, DomNode(xmldoc) - - -def assert_attr(node, **kwargs): - __tracebackhide__ = True - - def nodeval(node, name): - anode = node.getAttributeNode(name) - if anode is not None: - return anode.value - - expected = {name: str(value) for name, value in kwargs.items()} - on_node = {name: nodeval(node, name) for name in expected} - assert on_node == expected - - -class DomNode(object): - - def __init__(self, dom): - self.__node = dom - - def __repr__(self): - return self.__node.toxml() - - def find_first_by_tag(self, tag): - return self.find_nth_by_tag(tag, 0) - - def _by_tag(self, tag): - return self.__node.getElementsByTagName(tag) - - def find_nth_by_tag(self, tag, n): - items = self._by_tag(tag) - try: - nth = items[n] - except IndexError: - pass - else: - return type(self)(nth) - - def find_by_tag(self, tag): - t = type(self) - return [t(x) for x in self.__node.getElementsByTagName(tag)] - - def __getitem__(self, key): - node = self.__node.getAttributeNode(key) - if node is not None: - return node.value - - def assert_attr(self, **kwargs): - __tracebackhide__ = True - return assert_attr(self.__node, **kwargs) - - def toxml(self): - return self.__node.toxml() - - @property - def text(self): - return self.__node.childNodes[0].wholeText - - @property - def tag(self): - return self.__node.tagName - - @property - def next_siebling(self): - return type(self)(self.__node.nextSibling) - - -class TestPython(object): - - def test_summing_simple(self, testdir): - testdir.makepyfile( - """ - import pytest - def test_pass(): - pass - def test_fail(): - assert 0 - def test_skip(): - pytest.skip("") - @pytest.mark.xfail - def test_xfail(): - assert 0 - @pytest.mark.xfail - def test_xpass(): - assert 1 - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(name="pytest", errors=0, failures=1, skips=2, tests=5) - - def test_summing_simple_with_errors(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture - def fixture(): - raise Exception() - def test_pass(): - pass - def test_fail(): - assert 0 - def test_error(fixture): - pass - @pytest.mark.xfail - def test_xfail(): - assert False - @pytest.mark.xfail(strict=True) - def test_xpass(): - assert True - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(name="pytest", errors=1, failures=2, skips=1, tests=5) - - def test_timing_function(self, testdir): - testdir.makepyfile( - """ - import time, pytest - def setup_module(): - time.sleep(0.01) - def teardown_module(): - time.sleep(0.01) - def test_sleep(): - time.sleep(0.01) - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - val = tnode["time"] - assert round(float(val), 2) >= 0.03 - - def test_setup_error(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg(request): - raise ValueError() - def test_function(arg): - pass - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_setup_error.py", - line="5", - classname="test_setup_error", - name="test_function", - ) - fnode = tnode.find_first_by_tag("error") - fnode.assert_attr(message="test setup failure") - assert "ValueError" in fnode.toxml() - - def test_teardown_error(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg(): - yield - raise ValueError() - def test_function(arg): - pass - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_teardown_error.py", - line="6", - classname="test_teardown_error", - name="test_function", - ) - fnode = tnode.find_first_by_tag("error") - fnode.assert_attr(message="test teardown failure") - assert "ValueError" in fnode.toxml() - - def test_call_failure_teardown_error(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg(): - yield - raise Exception("Teardown Exception") - def test_function(arg): - raise Exception("Call Exception") - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, failures=1, tests=1) - first, second = dom.find_by_tag("testcase") - if not first or not second or first == second: - assert 0 - fnode = first.find_first_by_tag("failure") - fnode.assert_attr(message="Exception: Call Exception") - snode = second.find_first_by_tag("error") - snode.assert_attr(message="test teardown failure") - - def test_skip_contains_name_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - def test_skip(): - pytest.skip("hello23") - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_skip_contains_name_reason.py", - line="1", - classname="test_skip_contains_name_reason", - name="test_skip", - ) - snode = tnode.find_first_by_tag("skipped") - snode.assert_attr(type="pytest.skip", message="hello23") - - def test_mark_skip_contains_name_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip(reason="hello24") - def test_skip(): - assert True - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_mark_skip_contains_name_reason.py", - line="1", - classname="test_mark_skip_contains_name_reason", - name="test_skip", - ) - snode = tnode.find_first_by_tag("skipped") - snode.assert_attr(type="pytest.skip", message="hello24") - - def test_mark_skipif_contains_name_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - GLOBAL_CONDITION = True - @pytest.mark.skipif(GLOBAL_CONDITION, reason="hello25") - def test_skip(): - assert True - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_mark_skipif_contains_name_reason.py", - line="2", - classname="test_mark_skipif_contains_name_reason", - name="test_skip", - ) - snode = tnode.find_first_by_tag("skipped") - snode.assert_attr(type="pytest.skip", message="hello25") - - def test_mark_skip_doesnt_capture_output(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip(reason="foo") - def test_skip(): - print("bar!") - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node_xml = dom.find_first_by_tag("testsuite").toxml() - assert "bar!" not in node_xml - - def test_classname_instance(self, testdir): - testdir.makepyfile( - """ - class TestClass(object): - def test_method(self): - assert 0 - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(failures=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_classname_instance.py", - line="1", - classname="test_classname_instance.TestClass", - name="test_method", - ) - - def test_classname_nested_dir(self, testdir): - p = testdir.tmpdir.ensure("sub", "test_hello.py") - p.write("def test_func(): 0/0") - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(failures=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file=os.path.join("sub", "test_hello.py"), - line="0", - classname="sub.test_hello", - name="test_func", - ) - - def test_internal_error(self, testdir): - testdir.makeconftest("def pytest_runtest_protocol(): 0 / 0") - testdir.makepyfile("def test_function(): pass") - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr(classname="pytest", name="internal") - fnode = tnode.find_first_by_tag("error") - fnode.assert_attr(message="internal error") - assert "Division" in fnode.toxml() - - @pytest.mark.parametrize("junit_logging", ["no", "system-out", "system-err"]) - def test_failure_function(self, testdir, junit_logging): - testdir.makepyfile( - """ - import logging - import sys - - def test_fail(): - print ("hello-stdout") - sys.stderr.write("hello-stderr\\n") - logging.info('info msg') - logging.warning('warning msg') - raise ValueError(42) - """ - ) - - result, dom = runandparse(testdir, "-o", "junit_logging=%s" % junit_logging) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(failures=1, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_failure_function.py", - line="3", - classname="test_failure_function", - name="test_fail", - ) - fnode = tnode.find_first_by_tag("failure") - fnode.assert_attr(message="ValueError: 42") - assert "ValueError" in fnode.toxml() - systemout = fnode.next_siebling - assert systemout.tag == "system-out" - assert "hello-stdout" in systemout.toxml() - assert "info msg" not in systemout.toxml() - systemerr = systemout.next_siebling - assert systemerr.tag == "system-err" - assert "hello-stderr" in systemerr.toxml() - assert "info msg" not in systemerr.toxml() - - if junit_logging == "system-out": - assert "warning msg" in systemout.toxml() - assert "warning msg" not in systemerr.toxml() - elif junit_logging == "system-err": - assert "warning msg" not in systemout.toxml() - assert "warning msg" in systemerr.toxml() - elif junit_logging == "no": - assert "warning msg" not in systemout.toxml() - assert "warning msg" not in systemerr.toxml() - - def test_failure_verbose_message(self, testdir): - testdir.makepyfile( - """ - import sys - def test_fail(): - assert 0, "An error" - """ - ) - - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - fnode = tnode.find_first_by_tag("failure") - fnode.assert_attr(message="AssertionError: An error assert 0") - - def test_failure_escape(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('arg1', "<&'", ids="<&'") - def test_func(arg1): - print(arg1) - assert 0 - """ - ) - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(failures=3, tests=3) - - for index, char in enumerate("<&'"): - - tnode = node.find_nth_by_tag("testcase", index) - tnode.assert_attr( - file="test_failure_escape.py", - line="1", - classname="test_failure_escape", - name="test_func[%s]" % char, - ) - sysout = tnode.find_first_by_tag("system-out") - text = sysout.text - assert text == "%s\n" % char - - def test_junit_prefixing(self, testdir): - testdir.makepyfile( - """ - def test_func(): - assert 0 - class TestHello(object): - def test_hello(self): - pass - """ - ) - result, dom = runandparse(testdir, "--junitprefix=xyz") - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(failures=1, tests=2) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_junit_prefixing.py", - line="0", - classname="xyz.test_junit_prefixing", - name="test_func", - ) - tnode = node.find_nth_by_tag("testcase", 1) - tnode.assert_attr( - file="test_junit_prefixing.py", - line="3", - classname="xyz.test_junit_prefixing." "TestHello", - name="test_hello", - ) - - def test_xfailure_function(self, testdir): - testdir.makepyfile( - """ - import pytest - def test_xfail(): - pytest.xfail("42") - """ - ) - result, dom = runandparse(testdir) - assert not result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=1, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_xfailure_function.py", - line="1", - classname="test_xfailure_function", - name="test_xfail", - ) - fnode = tnode.find_first_by_tag("skipped") - fnode.assert_attr(message="expected test failure") - # assert "ValueError" in fnode.toxml() - - def test_xfail_captures_output_once(self, testdir): - testdir.makepyfile( - """ - import sys - import pytest - - @pytest.mark.xfail() - def test_fail(): - sys.stdout.write('XFAIL This is stdout') - sys.stderr.write('XFAIL This is stderr') - assert 0 - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - assert len(tnode.find_by_tag("system-err")) == 1 - assert len(tnode.find_by_tag("system-out")) == 1 - - def test_xfailure_xpass(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail - def test_xpass(): - pass - """ - ) - result, dom = runandparse(testdir) - # assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=0, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_xfailure_xpass.py", - line="1", - classname="test_xfailure_xpass", - name="test_xpass", - ) - - def test_xfailure_xpass_strict(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(strict=True, reason="This needs to fail!") - def test_xpass(): - pass - """ - ) - result, dom = runandparse(testdir) - # assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(skips=0, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr( - file="test_xfailure_xpass_strict.py", - line="1", - classname="test_xfailure_xpass_strict", - name="test_xpass", - ) - fnode = tnode.find_first_by_tag("failure") - fnode.assert_attr(message="[XPASS(strict)] This needs to fail!") - - def test_collect_error(self, testdir): - testdir.makepyfile("syntax error") - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=1, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr(file="test_collect_error.py", name="test_collect_error") - assert tnode["line"] is None - fnode = tnode.find_first_by_tag("error") - fnode.assert_attr(message="collection failure") - assert "SyntaxError" in fnode.toxml() - - def test_unicode(self, testdir): - value = "hx\xc4\x85\xc4\x87\n" - testdir.makepyfile( - """ - # coding: latin1 - def test_hello(): - print (%r) - assert 0 - """ - % value - ) - result, dom = runandparse(testdir) - assert result.ret == 1 - tnode = dom.find_first_by_tag("testcase") - fnode = tnode.find_first_by_tag("failure") - if not sys.platform.startswith("java"): - assert "hx" in fnode.toxml() - - def test_assertion_binchars(self, testdir): - """this test did fail when the escaping wasnt strict""" - testdir.makepyfile( - """ - - M1 = '\x01\x02\x03\x04' - M2 = '\x01\x02\x03\x05' - - def test_str_compare(): - assert M1 == M2 - """ - ) - result, dom = runandparse(testdir) - print(dom.toxml()) - - def test_pass_captures_stdout(self, testdir): - testdir.makepyfile( - """ - def test_pass(): - print('hello-stdout') - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - pnode = node.find_first_by_tag("testcase") - systemout = pnode.find_first_by_tag("system-out") - assert "hello-stdout" in systemout.toxml() - - def test_pass_captures_stderr(self, testdir): - testdir.makepyfile( - """ - import sys - def test_pass(): - sys.stderr.write('hello-stderr') - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - pnode = node.find_first_by_tag("testcase") - systemout = pnode.find_first_by_tag("system-err") - assert "hello-stderr" in systemout.toxml() - - def test_setup_error_captures_stdout(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg(request): - print('hello-stdout') - raise ValueError() - def test_function(arg): - pass - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - pnode = node.find_first_by_tag("testcase") - systemout = pnode.find_first_by_tag("system-out") - assert "hello-stdout" in systemout.toxml() - - def test_setup_error_captures_stderr(self, testdir): - testdir.makepyfile( - """ - import sys - import pytest - - @pytest.fixture - def arg(request): - sys.stderr.write('hello-stderr') - raise ValueError() - def test_function(arg): - pass - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - pnode = node.find_first_by_tag("testcase") - systemout = pnode.find_first_by_tag("system-err") - assert "hello-stderr" in systemout.toxml() - - def test_avoid_double_stdout(self, testdir): - testdir.makepyfile( - """ - import sys - import pytest - - @pytest.fixture - def arg(request): - yield - sys.stdout.write('hello-stdout teardown') - raise ValueError() - def test_function(arg): - sys.stdout.write('hello-stdout call') - """ - ) - result, dom = runandparse(testdir) - node = dom.find_first_by_tag("testsuite") - pnode = node.find_first_by_tag("testcase") - systemout = pnode.find_first_by_tag("system-out") - assert "hello-stdout call" in systemout.toxml() - assert "hello-stdout teardown" in systemout.toxml() - - -def test_mangle_test_address(): - from _pytest.junitxml import mangle_test_address - - address = "::".join(["a/my.py.thing.py", "Class", "()", "method", "[a-1-::]"]) - newnames = mangle_test_address(address) - assert newnames == ["a.my.py.thing", "Class", "method", "[a-1-::]"] - - -def test_dont_configure_on_slaves(tmpdir): - gotten = [] - - class FakeConfig(object): - - def __init__(self): - self.pluginmanager = self - self.option = self - - def getini(self, name): - return "pytest" - - junitprefix = None - # XXX: shouldnt need tmpdir ? - xmlpath = str(tmpdir.join("junix.xml")) - register = gotten.append - - fake_config = FakeConfig() - from _pytest import junitxml - - junitxml.pytest_configure(fake_config) - assert len(gotten) == 1 - FakeConfig.slaveinput = None - junitxml.pytest_configure(fake_config) - assert len(gotten) == 1 - - -class TestNonPython(object): - - def test_summing_simple(self, testdir): - testdir.makeconftest( - """ - import pytest - def pytest_collect_file(path, parent): - if path.ext == ".xyz": - return MyItem(path, parent) - class MyItem(pytest.Item): - def __init__(self, path, parent): - super(MyItem, self).__init__(path.basename, parent) - self.fspath = path - def runtest(self): - raise ValueError(42) - def repr_failure(self, excinfo): - return "custom item runtest failed" - """ - ) - testdir.tmpdir.join("myfile.xyz").write("hello") - result, dom = runandparse(testdir) - assert result.ret - node = dom.find_first_by_tag("testsuite") - node.assert_attr(errors=0, failures=1, skips=0, tests=1) - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr(name="myfile.xyz") - fnode = tnode.find_first_by_tag("failure") - fnode.assert_attr(message="custom item runtest failed") - assert "custom item runtest failed" in fnode.toxml() - - -def test_nullbyte(testdir): - # A null byte can not occur in XML (see section 2.2 of the spec) - testdir.makepyfile( - """ - import sys - def test_print_nullbyte(): - sys.stdout.write('Here the null -->' + chr(0) + '<--') - sys.stdout.write('In repr form -->' + repr(chr(0)) + '<--') - assert False - """ - ) - xmlf = testdir.tmpdir.join("junit.xml") - testdir.runpytest("--junitxml=%s" % xmlf) - text = xmlf.read() - assert "\x00" not in text - assert "#x00" in text - - -def test_nullbyte_replace(testdir): - # Check if the null byte gets replaced - testdir.makepyfile( - """ - import sys - def test_print_nullbyte(): - sys.stdout.write('Here the null -->' + chr(0) + '<--') - sys.stdout.write('In repr form -->' + repr(chr(0)) + '<--') - assert False - """ - ) - xmlf = testdir.tmpdir.join("junit.xml") - testdir.runpytest("--junitxml=%s" % xmlf) - text = xmlf.read() - assert "#x0" in text - - -def test_invalid_xml_escape(): - # Test some more invalid xml chars, the full range should be - # tested really but let's just thest the edges of the ranges - # intead. - # XXX This only tests low unicode character points for now as - # there are some issues with the testing infrastructure for - # the higher ones. - # XXX Testing 0xD (\r) is tricky as it overwrites the just written - # line in the output, so we skip it too. - global unichr - try: - unichr(65) - except NameError: - unichr = chr - invalid = ( - 0x00, - 0x1, - 0xB, - 0xC, - 0xE, - 0x19, - 27, # issue #126 - 0xD800, - 0xDFFF, - 0xFFFE, - 0x0FFFF, - ) # , 0x110000) - valid = (0x9, 0xA, 0x20) - # 0xD, 0xD7FF, 0xE000, 0xFFFD, 0x10000, 0x10FFFF) - - from _pytest.junitxml import bin_xml_escape - - for i in invalid: - got = bin_xml_escape(unichr(i)).uniobj - if i <= 0xFF: - expected = "#x%02X" % i - else: - expected = "#x%04X" % i - assert got == expected - for i in valid: - assert chr(i) == bin_xml_escape(unichr(i)).uniobj - - -def test_logxml_path_expansion(tmpdir, monkeypatch): - home_tilde = py.path.local(os.path.expanduser("~")).join("test.xml") - - xml_tilde = LogXML("~%stest.xml" % tmpdir.sep, None) - assert xml_tilde.logfile == home_tilde - - # this is here for when $HOME is not set correct - monkeypatch.setenv("HOME", tmpdir) - home_var = os.path.normpath(os.path.expandvars("$HOME/test.xml")) - - xml_var = LogXML("$HOME%stest.xml" % tmpdir.sep, None) - assert xml_var.logfile == home_var - - -def test_logxml_changingdir(testdir): - testdir.makepyfile( - """ - def test_func(): - import os - os.chdir("a") - """ - ) - testdir.tmpdir.mkdir("a") - result = testdir.runpytest("--junitxml=a/x.xml") - assert result.ret == 0 - assert testdir.tmpdir.join("a/x.xml").check() - - -def test_logxml_makedir(testdir): - """--junitxml should automatically create directories for the xml file""" - testdir.makepyfile( - """ - def test_pass(): - pass - """ - ) - result = testdir.runpytest("--junitxml=path/to/results.xml") - assert result.ret == 0 - assert testdir.tmpdir.join("path/to/results.xml").check() - - -def test_logxml_check_isdir(testdir): - """Give an error if --junit-xml is a directory (#2089)""" - result = testdir.runpytest("--junit-xml=.") - result.stderr.fnmatch_lines(["*--junitxml must be a filename*"]) - - -def test_escaped_parametrized_names_xml(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('char', [u"\\x00"]) - def test_func(char): - assert char - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testcase") - node.assert_attr(name="test_func[\\x00]") - - -def test_double_colon_split_function_issue469(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('param', ["double::colon"]) - def test_func(param): - pass - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testcase") - node.assert_attr(classname="test_double_colon_split_function_issue469") - node.assert_attr(name="test_func[double::colon]") - - -def test_double_colon_split_method_issue469(testdir): - testdir.makepyfile( - """ - import pytest - class TestClass(object): - @pytest.mark.parametrize('param', ["double::colon"]) - def test_func(self, param): - pass - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testcase") - node.assert_attr(classname="test_double_colon_split_method_issue469.TestClass") - node.assert_attr(name="test_func[double::colon]") - - -def test_unicode_issue368(testdir): - path = testdir.tmpdir.join("test.xml") - log = LogXML(str(path), None) - ustr = py.builtin._totext("ВНИ!", "utf-8") - from _pytest.runner import BaseReport - - class Report(BaseReport): - longrepr = ustr - sections = [] - nodeid = "something" - location = "tests/filename.py", 42, "TestClass.method" - - test_report = Report() - - # hopefully this is not too brittle ... - log.pytest_sessionstart() - node_reporter = log._opentestcase(test_report) - node_reporter.append_failure(test_report) - node_reporter.append_collect_error(test_report) - node_reporter.append_collect_skipped(test_report) - node_reporter.append_error(test_report) - test_report.longrepr = "filename", 1, ustr - node_reporter.append_skipped(test_report) - test_report.longrepr = "filename", 1, "Skipped: 卡嘣嘣" - node_reporter.append_skipped(test_report) - test_report.wasxfail = ustr - node_reporter.append_skipped(test_report) - log.pytest_sessionfinish() - - -def test_record_property(testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def other(record_property): - record_property("bar", 1) - def test_record(record_property, other): - record_property("foo", "<1"); - """ - ) - result, dom = runandparse(testdir, "-rwv") - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - psnode = tnode.find_first_by_tag("properties") - pnodes = psnode.find_by_tag("property") - pnodes[0].assert_attr(name="bar", value="1") - pnodes[1].assert_attr(name="foo", value="<1") - - -def test_record_property_same_name(testdir): - testdir.makepyfile( - """ - def test_record_with_same_name(record_property): - record_property("foo", "bar") - record_property("foo", "baz") - """ - ) - result, dom = runandparse(testdir, "-rw") - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - psnode = tnode.find_first_by_tag("properties") - pnodes = psnode.find_by_tag("property") - pnodes[0].assert_attr(name="foo", value="bar") - pnodes[1].assert_attr(name="foo", value="baz") - - -def test_record_attribute(testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def other(record_xml_attribute): - record_xml_attribute("bar", 1) - def test_record(record_xml_attribute, other): - record_xml_attribute("foo", "<1"); - """ - ) - result, dom = runandparse(testdir, "-rw") - node = dom.find_first_by_tag("testsuite") - tnode = node.find_first_by_tag("testcase") - tnode.assert_attr(bar="1") - tnode.assert_attr(foo="<1") - result.stdout.fnmatch_lines( - ["test_record_attribute.py::test_record", "*record_xml_attribute*experimental*"] - ) - - -def test_random_report_log_xdist(testdir): - """xdist calls pytest_runtest_logreport as they are executed by the slaves, - with nodes from several nodes overlapping, so junitxml must cope with that - to produce correct reports. #1064 - """ - pytest.importorskip("xdist") - testdir.makepyfile( - """ - import pytest, time - @pytest.mark.parametrize('i', list(range(30))) - def test_x(i): - assert i != 22 - """ - ) - _, dom = runandparse(testdir, "-n2") - suite_node = dom.find_first_by_tag("testsuite") - failed = [] - for case_node in suite_node.find_by_tag("testcase"): - if case_node.find_first_by_tag("failure"): - failed.append(case_node["name"]) - - assert failed == ["test_x[22]"] - - -def test_runs_twice(testdir): - f = testdir.makepyfile( - """ - def test_pass(): - pass - """ - ) - - result, dom = runandparse(testdir, f, f) - assert "INTERNALERROR" not in result.stdout.str() - first, second = [x["classname"] for x in dom.find_by_tag("testcase")] - assert first == second - - -@pytest.mark.xfail(reason="hangs", run=False) -def test_runs_twice_xdist(testdir): - pytest.importorskip("xdist") - f = testdir.makepyfile( - """ - def test_pass(): - pass - """ - ) - - result, dom = runandparse(testdir, f, "--dist", "each", "--tx", "2*popen") - assert "INTERNALERROR" not in result.stdout.str() - first, second = [x["classname"] for x in dom.find_by_tag("testcase")] - assert first == second - - -def test_fancy_items_regression(testdir): - # issue 1259 - testdir.makeconftest( - """ - import pytest - class FunItem(pytest.Item): - def runtest(self): - pass - class NoFunItem(pytest.Item): - def runtest(self): - pass - - class FunCollector(pytest.File): - def collect(self): - return [ - FunItem('a', self), - NoFunItem('a', self), - NoFunItem('b', self), - ] - - def pytest_collect_file(path, parent): - if path.check(ext='.py'): - return FunCollector(path, parent) - """ - ) - - testdir.makepyfile( - """ - def test_pass(): - pass - """ - ) - - result, dom = runandparse(testdir) - - assert "INTERNALERROR" not in result.stdout.str() - - items = sorted( - "%(classname)s %(name)s %(file)s" % x for x in dom.find_by_tag("testcase") - ) - import pprint - - pprint.pprint(items) - assert ( - items - == [ - u"conftest a conftest.py", - u"conftest a conftest.py", - u"conftest b conftest.py", - u"test_fancy_items_regression a test_fancy_items_regression.py", - u"test_fancy_items_regression a test_fancy_items_regression.py", - u"test_fancy_items_regression b test_fancy_items_regression.py", - u"test_fancy_items_regression test_pass" u" test_fancy_items_regression.py", - ] - ) - - -def test_global_properties(testdir): - path = testdir.tmpdir.join("test_global_properties.xml") - log = LogXML(str(path), None) - from _pytest.runner import BaseReport - - class Report(BaseReport): - sections = [] - nodeid = "test_node_id" - - log.pytest_sessionstart() - log.add_global_property("foo", 1) - log.add_global_property("bar", 2) - log.pytest_sessionfinish() - - dom = minidom.parse(str(path)) - - properties = dom.getElementsByTagName("properties") - - assert properties.length == 1, "There must be one node" - - property_list = dom.getElementsByTagName("property") - - assert property_list.length == 2, "There most be only 2 property nodes" - - expected = {"foo": "1", "bar": "2"} - actual = {} - - for p in property_list: - k = str(p.getAttribute("name")) - v = str(p.getAttribute("value")) - actual[k] = v - - assert actual == expected - - -def test_url_property(testdir): - test_url = "http://www.github.com/pytest-dev" - path = testdir.tmpdir.join("test_url_property.xml") - log = LogXML(str(path), None) - from _pytest.runner import BaseReport - - class Report(BaseReport): - longrepr = "FooBarBaz" - sections = [] - nodeid = "something" - location = "tests/filename.py", 42, "TestClass.method" - url = test_url - - test_report = Report() - - log.pytest_sessionstart() - node_reporter = log._opentestcase(test_report) - node_reporter.append_failure(test_report) - log.pytest_sessionfinish() - - test_case = minidom.parse(str(path)).getElementsByTagName("testcase")[0] - - assert ( - test_case.getAttribute("url") == test_url - ), "The URL did not get written to the xml" - - -@pytest.mark.parametrize("suite_name", ["my_suite", ""]) -def test_set_suite_name(testdir, suite_name): - if suite_name: - testdir.makeini( - """ - [pytest] - junit_suite_name={} - """.format( - suite_name - ) - ) - expected = suite_name - else: - expected = "pytest" - testdir.makepyfile( - """ - import pytest - - def test_func(): - pass - """ - ) - result, dom = runandparse(testdir) - assert result.ret == 0 - node = dom.find_first_by_tag("testsuite") - node.assert_attr(name=expected) diff --git a/third_party/python/pytest/testing/test_mark.py b/third_party/python/pytest/testing/test_mark.py deleted file mode 100644 index e2e7369dc798..000000000000 --- a/third_party/python/pytest/testing/test_mark.py +++ /dev/null @@ -1,1134 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os -import sys -import mock -import pytest -from _pytest.mark import ( - MarkGenerator as Mark, - ParameterSet, - transfer_markers, - EMPTY_PARAMETERSET_OPTION, -) -from _pytest.nodes import Node - -ignore_markinfo = pytest.mark.filterwarnings( - "ignore:MarkInfo objects:_pytest.deprecated.RemovedInPytest4Warning" -) - - -class TestMark(object): - - def test_markinfo_repr(self): - from _pytest.mark import MarkInfo, Mark - - m = MarkInfo.for_mark(Mark("hello", (1, 2), {})) - repr(m) - - @pytest.mark.parametrize("attr", ["mark", "param"]) - @pytest.mark.parametrize("modulename", ["py.test", "pytest"]) - def test_pytest_exists_in_namespace_all(self, attr, modulename): - module = sys.modules[modulename] - assert attr in module.__all__ - - def test_pytest_mark_notcallable(self): - mark = Mark() - pytest.raises((AttributeError, TypeError), mark) - - def test_mark_with_param(self): - - def some_function(abc): - pass - - class SomeClass(object): - pass - - assert pytest.mark.fun(some_function) is some_function - assert pytest.mark.fun.with_args(some_function) is not some_function - - assert pytest.mark.fun(SomeClass) is SomeClass - assert pytest.mark.fun.with_args(SomeClass) is not SomeClass - - def test_pytest_mark_name_starts_with_underscore(self): - mark = Mark() - pytest.raises(AttributeError, getattr, mark, "_some_name") - - def test_pytest_mark_bare(self): - mark = Mark() - - def f(): - pass - - mark.hello(f) - assert f.hello - - @ignore_markinfo - def test_pytest_mark_keywords(self): - mark = Mark() - - def f(): - pass - - mark.world(x=3, y=4)(f) - assert f.world - assert f.world.kwargs["x"] == 3 - assert f.world.kwargs["y"] == 4 - - @ignore_markinfo - def test_apply_multiple_and_merge(self): - mark = Mark() - - def f(): - pass - - mark.world - mark.world(x=3)(f) - assert f.world.kwargs["x"] == 3 - mark.world(y=4)(f) - assert f.world.kwargs["x"] == 3 - assert f.world.kwargs["y"] == 4 - mark.world(y=1)(f) - assert f.world.kwargs["y"] == 1 - assert len(f.world.args) == 0 - - @ignore_markinfo - def test_pytest_mark_positional(self): - mark = Mark() - - def f(): - pass - - mark.world("hello")(f) - assert f.world.args[0] == "hello" - mark.world("world")(f) - - @ignore_markinfo - def test_pytest_mark_positional_func_and_keyword(self): - mark = Mark() - - def f(): - raise Exception - - m = mark.world(f, omega="hello") - - def g(): - pass - - assert m(g) == g - assert g.world.args[0] is f - assert g.world.kwargs["omega"] == "hello" - - @ignore_markinfo - def test_pytest_mark_reuse(self): - mark = Mark() - - def f(): - pass - - w = mark.some - w("hello", reason="123")(f) - assert f.some.args[0] == "hello" - assert f.some.kwargs["reason"] == "123" - - def g(): - pass - - w("world", reason2="456")(g) - assert g.some.args[0] == "world" - assert "reason" not in g.some.kwargs - assert g.some.kwargs["reason2"] == "456" - - -def test_marked_class_run_twice(testdir, request): - """Test fails file is run twice that contains marked class. - See issue#683. - """ - py_file = testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('abc', [1, 2, 3]) - class Test1(object): - def test_1(self, abc): - assert abc in [1, 2, 3] - """ - ) - file_name = os.path.basename(py_file.strpath) - rec = testdir.inline_run(file_name, file_name) - rec.assertoutcome(passed=6) - - -def test_ini_markers(testdir): - testdir.makeini( - """ - [pytest] - markers = - a1: this is a webtest marker - a2: this is a smoke marker - """ - ) - testdir.makepyfile( - """ - def test_markers(pytestconfig): - markers = pytestconfig.getini("markers") - print (markers) - assert len(markers) >= 2 - assert markers[0].startswith("a1:") - assert markers[1].startswith("a2:") - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(passed=1) - - -def test_markers_option(testdir): - testdir.makeini( - """ - [pytest] - markers = - a1: this is a webtest marker - a1some: another marker - nodescription - """ - ) - result = testdir.runpytest("--markers") - result.stdout.fnmatch_lines( - ["*a1*this is a webtest*", "*a1some*another marker", "*nodescription*"] - ) - - -def test_ini_markers_whitespace(testdir): - testdir.makeini( - """ - [pytest] - markers = - a1 : this is a whitespace marker - """ - ) - testdir.makepyfile( - """ - import pytest - - @pytest.mark.a1 - def test_markers(): - assert True - """ - ) - rec = testdir.inline_run("--strict", "-m", "a1") - rec.assertoutcome(passed=1) - - -def test_marker_without_description(testdir): - testdir.makefile( - ".cfg", - setup=""" - [tool:pytest] - markers=slow - """, - ) - testdir.makeconftest( - """ - import pytest - pytest.mark.xfail('FAIL') - """ - ) - ftdir = testdir.mkdir("ft1_dummy") - testdir.tmpdir.join("conftest.py").move(ftdir.join("conftest.py")) - rec = testdir.runpytest_subprocess("--strict") - rec.assert_outcomes() - - -def test_markers_option_with_plugin_in_current_dir(testdir): - testdir.makeconftest('pytest_plugins = "flip_flop"') - testdir.makepyfile( - flip_flop="""\ - def pytest_configure(config): - config.addinivalue_line("markers", "flip:flop") - - def pytest_generate_tests(metafunc): - try: - mark = metafunc.function.flipper - except AttributeError: - return - metafunc.parametrize("x", (10, 20))""" - ) - testdir.makepyfile( - """\ - import pytest - @pytest.mark.flipper - def test_example(x): - assert x""" - ) - - result = testdir.runpytest("--markers") - result.stdout.fnmatch_lines(["*flip*flop*"]) - - -def test_mark_on_pseudo_function(testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.mark.r(lambda x: 0/0) - def test_hello(): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -def test_strict_prohibits_unregistered_markers(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.unregisteredmark - def test_hello(): - pass - """ - ) - result = testdir.runpytest("--strict") - assert result.ret != 0 - result.stdout.fnmatch_lines(["*unregisteredmark*not*registered*"]) - - -@pytest.mark.parametrize( - "spec", - [ - ("xyz", ("test_one",)), - ("xyz and xyz2", ()), - ("xyz2", ("test_two",)), - ("xyz or xyz2", ("test_one", "test_two")), - ], -) -def test_mark_option(spec, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xyz - def test_one(): - pass - @pytest.mark.xyz2 - def test_two(): - pass - """ - ) - opt, passed_result = spec - rec = testdir.inline_run("-m", opt) - passed, skipped, fail = rec.listoutcomes() - passed = [x.nodeid.split("::")[-1] for x in passed] - assert len(passed) == len(passed_result) - assert list(passed) == list(passed_result) - - -@pytest.mark.parametrize( - "spec", [("interface", ("test_interface",)), ("not interface", ("test_nointer",))] -) -def test_mark_option_custom(spec, testdir): - testdir.makeconftest( - """ - import pytest - def pytest_collection_modifyitems(items): - for item in items: - if "interface" in item.nodeid: - item.add_marker(pytest.mark.interface) - """ - ) - testdir.makepyfile( - """ - def test_interface(): - pass - def test_nointer(): - pass - """ - ) - opt, passed_result = spec - rec = testdir.inline_run("-m", opt) - passed, skipped, fail = rec.listoutcomes() - passed = [x.nodeid.split("::")[-1] for x in passed] - assert len(passed) == len(passed_result) - assert list(passed) == list(passed_result) - - -@pytest.mark.parametrize( - "spec", - [ - ("interface", ("test_interface",)), - ("not interface", ("test_nointer", "test_pass")), - ("pass", ("test_pass",)), - ("not pass", ("test_interface", "test_nointer")), - ], -) -def test_keyword_option_custom(spec, testdir): - testdir.makepyfile( - """ - def test_interface(): - pass - def test_nointer(): - pass - def test_pass(): - pass - """ - ) - opt, passed_result = spec - rec = testdir.inline_run("-k", opt) - passed, skipped, fail = rec.listoutcomes() - passed = [x.nodeid.split("::")[-1] for x in passed] - assert len(passed) == len(passed_result) - assert list(passed) == list(passed_result) - - -@pytest.mark.parametrize( - "spec", - [ - ("None", ("test_func[None]",)), - ("1.3", ("test_func[1.3]",)), - ("2-3", ("test_func[2-3]",)), - ], -) -def test_keyword_option_parametrize(spec, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize("arg", [None, 1.3, "2-3"]) - def test_func(arg): - pass - """ - ) - opt, passed_result = spec - rec = testdir.inline_run("-k", opt) - passed, skipped, fail = rec.listoutcomes() - passed = [x.nodeid.split("::")[-1] for x in passed] - assert len(passed) == len(passed_result) - assert list(passed) == list(passed_result) - - -@pytest.mark.parametrize( - "spec", - [ - ( - "foo or import", - "ERROR: Python keyword 'import' not accepted in expressions passed to '-k'", - ), - ("foo or", "ERROR: Wrong expression passed to '-k': foo or"), - ], -) -def test_keyword_option_wrong_arguments(spec, testdir, capsys): - testdir.makepyfile( - """ - def test_func(arg): - pass - """ - ) - opt, expected_result = spec - testdir.inline_run("-k", opt) - out = capsys.readouterr().err - assert expected_result in out - - -def test_parametrized_collected_from_command_line(testdir): - """Parametrized test not collected if test named specified - in command line issue#649. - """ - py_file = testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize("arg", [None, 1.3, "2-3"]) - def test_func(arg): - pass - """ - ) - file_name = os.path.basename(py_file.strpath) - rec = testdir.inline_run(file_name + "::" + "test_func") - rec.assertoutcome(passed=3) - - -def test_parametrized_collect_with_wrong_args(testdir): - """Test collect parametrized func with wrong number of args.""" - py_file = testdir.makepyfile( - """ - import pytest - - @pytest.mark.parametrize('foo, bar', [(1, 2, 3)]) - def test_func(foo, bar): - pass - """ - ) - - result = testdir.runpytest(py_file) - result.stdout.fnmatch_lines( - [ - 'E ValueError: In "parametrize" the number of values ((1, 2, 3)) ' - "must be equal to the number of names (['foo', 'bar'])" - ] - ) - - -def test_parametrized_with_kwargs(testdir): - """Test collect parametrized func with wrong number of args.""" - py_file = testdir.makepyfile( - """ - import pytest - - @pytest.fixture(params=[1,2]) - def a(request): - return request.param - - @pytest.mark.parametrize(argnames='b', argvalues=[1, 2]) - def test_func(a, b): - pass - """ - ) - - result = testdir.runpytest(py_file) - assert result.ret == 0 - - -class TestFunctional(object): - - def test_mark_per_function(self, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.hello - def test_hello(): - assert hasattr(test_hello, 'hello') - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_mark_per_module(self, testdir): - item = testdir.getitem( - """ - import pytest - pytestmark = pytest.mark.hello - def test_func(): - pass - """ - ) - keywords = item.keywords - assert "hello" in keywords - - def test_marklist_per_class(self, testdir): - item = testdir.getitem( - """ - import pytest - class TestClass(object): - pytestmark = [pytest.mark.hello, pytest.mark.world] - def test_func(self): - assert TestClass.test_func.hello - assert TestClass.test_func.world - """ - ) - keywords = item.keywords - assert "hello" in keywords - - def test_marklist_per_module(self, testdir): - item = testdir.getitem( - """ - import pytest - pytestmark = [pytest.mark.hello, pytest.mark.world] - class TestClass(object): - def test_func(self): - assert TestClass.test_func.hello - assert TestClass.test_func.world - """ - ) - keywords = item.keywords - assert "hello" in keywords - assert "world" in keywords - - def test_mark_per_class_decorator(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.hello - class TestClass(object): - def test_func(self): - assert TestClass.test_func.hello - """ - ) - keywords = item.keywords - assert "hello" in keywords - - def test_mark_per_class_decorator_plus_existing_dec(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.hello - class TestClass(object): - pytestmark = pytest.mark.world - def test_func(self): - assert TestClass.test_func.hello - assert TestClass.test_func.world - """ - ) - keywords = item.keywords - assert "hello" in keywords - assert "world" in keywords - - @ignore_markinfo - def test_merging_markers(self, testdir): - p = testdir.makepyfile( - """ - import pytest - pytestmark = pytest.mark.hello("pos1", x=1, y=2) - class TestClass(object): - # classlevel overrides module level - pytestmark = pytest.mark.hello(x=3) - @pytest.mark.hello("pos0", z=4) - def test_func(self): - pass - """ - ) - items, rec = testdir.inline_genitems(p) - item, = items - keywords = item.keywords - marker = keywords["hello"] - assert marker.args == ("pos0", "pos1") - assert marker.kwargs == {"x": 1, "y": 2, "z": 4} - - # test the new __iter__ interface - values = list(marker) - assert len(values) == 3 - assert values[0].args == ("pos0",) - assert values[1].args == () - assert values[2].args == ("pos1",) - - def test_merging_markers_deep(self, testdir): - # issue 199 - propagate markers into nested classes - p = testdir.makepyfile( - """ - import pytest - class TestA(object): - pytestmark = pytest.mark.a - def test_b(self): - assert True - class TestC(object): - # this one didnt get marked - def test_d(self): - assert True - """ - ) - items, rec = testdir.inline_genitems(p) - for item in items: - print(item, item.keywords) - assert [x for x in item.iter_markers() if x.name == "a"] - - def test_mark_decorator_subclass_does_not_propagate_to_base(self, testdir): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.a - class Base(object): pass - - @pytest.mark.b - class Test1(Base): - def test_foo(self): pass - - class Test2(Base): - def test_bar(self): pass - """ - ) - items, rec = testdir.inline_genitems(p) - self.assert_markers(items, test_foo=("a", "b"), test_bar=("a",)) - - @pytest.mark.issue568 - def test_mark_should_not_pass_to_siebling_class(self, testdir): - p = testdir.makepyfile( - """ - import pytest - - class TestBase(object): - def test_foo(self): - pass - - @pytest.mark.b - class TestSub(TestBase): - pass - - - class TestOtherSub(TestBase): - pass - - """ - ) - items, rec = testdir.inline_genitems(p) - base_item, sub_item, sub_item_other = items - print(items, [x.nodeid for x in items]) - # legacy api smears - assert hasattr(base_item.obj, "b") - assert hasattr(sub_item_other.obj, "b") - assert hasattr(sub_item.obj, "b") - - # new api seregates - assert not list(base_item.iter_markers(name="b")) - assert not list(sub_item_other.iter_markers(name="b")) - assert list(sub_item.iter_markers(name="b")) - - def test_mark_decorator_baseclasses_merged(self, testdir): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.a - class Base(object): pass - - @pytest.mark.b - class Base2(Base): pass - - @pytest.mark.c - class Test1(Base2): - def test_foo(self): pass - - class Test2(Base2): - @pytest.mark.d - def test_bar(self): pass - """ - ) - items, rec = testdir.inline_genitems(p) - self.assert_markers(items, test_foo=("a", "b", "c"), test_bar=("a", "b", "d")) - - def test_mark_closest(self, testdir): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.c(location="class") - class Test: - @pytest.mark.c(location="function") - def test_has_own(): - pass - - def test_has_inherited(): - pass - - """ - ) - items, rec = testdir.inline_genitems(p) - has_own, has_inherited = items - assert has_own.get_closest_marker("c").kwargs == {"location": "function"} - assert has_inherited.get_closest_marker("c").kwargs == {"location": "class"} - assert has_own.get_closest_marker("missing") is None - - def test_mark_with_wrong_marker(self, testdir): - reprec = testdir.inline_runsource( - """ - import pytest - class pytestmark(object): - pass - def test_func(): - pass - """ - ) - values = reprec.getfailedcollections() - assert len(values) == 1 - assert "TypeError" in str(values[0].longrepr) - - def test_mark_dynamically_in_funcarg(self, testdir): - testdir.makeconftest( - """ - import pytest - @pytest.fixture - def arg(request): - request.applymarker(pytest.mark.hello) - def pytest_terminal_summary(terminalreporter): - values = terminalreporter.stats['passed'] - terminalreporter._tw.line("keyword: %s" % values[0].keywords) - """ - ) - testdir.makepyfile( - """ - def test_func(arg): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["keyword: *hello*"]) - - @ignore_markinfo - def test_merging_markers_two_functions(self, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.hello("pos1", z=4) - @pytest.mark.hello("pos0", z=3) - def test_func(): - pass - """ - ) - items, rec = testdir.inline_genitems(p) - item, = items - keywords = item.keywords - marker = keywords["hello"] - values = list(marker) - assert len(values) == 2 - assert values[0].args == ("pos0",) - assert values[1].args == ("pos1",) - - def test_no_marker_match_on_unmarked_names(self, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.shouldmatch - def test_marked(): - assert 1 - - def test_unmarked(): - assert 1 - """ - ) - reprec = testdir.inline_run("-m", "test_unmarked", p) - passed, skipped, failed = reprec.listoutcomes() - assert len(passed) + len(skipped) + len(failed) == 0 - dlist = reprec.getcalls("pytest_deselected") - deselected_tests = dlist[0].items - assert len(deselected_tests) == 2 - - def test_keywords_at_node_level(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope="session", autouse=True) - def some(request): - request.keywords["hello"] = 42 - assert "world" not in request.keywords - - @pytest.fixture(scope="function", autouse=True) - def funcsetup(request): - assert "world" in request.keywords - assert "hello" in request.keywords - - @pytest.mark.world - def test_function(): - pass - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - @ignore_markinfo - def test_keyword_added_for_session(self, testdir): - testdir.makeconftest( - """ - import pytest - def pytest_collection_modifyitems(session): - session.add_marker("mark1") - session.add_marker(pytest.mark.mark2) - session.add_marker(pytest.mark.mark3) - pytest.raises(ValueError, lambda: - session.add_marker(10)) - """ - ) - testdir.makepyfile( - """ - def test_some(request): - assert "mark1" in request.keywords - assert "mark2" in request.keywords - assert "mark3" in request.keywords - assert 10 not in request.keywords - marker = request.node.get_marker("mark1") - assert marker.name == "mark1" - assert marker.args == () - assert marker.kwargs == {} - """ - ) - reprec = testdir.inline_run("-m", "mark1") - reprec.assertoutcome(passed=1) - - def assert_markers(self, items, **expected): - """assert that given items have expected marker names applied to them. - expected should be a dict of (item name -> seq of expected marker names) - - .. note:: this could be moved to ``testdir`` if proven to be useful - to other modules. - """ - from _pytest.mark import MarkInfo - - items = {x.name: x for x in items} - for name, expected_markers in expected.items(): - markers = items[name].keywords._markers - marker_names = { - name for (name, v) in markers.items() if isinstance(v, MarkInfo) - } - assert marker_names == set(expected_markers) - - @pytest.mark.issue1540 - @pytest.mark.filterwarnings("ignore") - def test_mark_from_parameters(self, testdir): - testdir.makepyfile( - """ - import pytest - - pytestmark = pytest.mark.skipif(True, reason='skip all') - - # skipifs inside fixture params - params = [pytest.mark.skipif(False, reason='dont skip')('parameter')] - - - @pytest.fixture(params=params) - def parameter(request): - return request.param - - - def test_1(parameter): - assert True - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=1) - - -class TestKeywordSelection(object): - - def test_select_simple(self, testdir): - file_test = testdir.makepyfile( - """ - def test_one(): - assert 0 - class TestClass(object): - def test_method_one(self): - assert 42 == 43 - """ - ) - - def check(keyword, name): - reprec = testdir.inline_run("-s", "-k", keyword, file_test) - passed, skipped, failed = reprec.listoutcomes() - assert len(failed) == 1 - assert failed[0].nodeid.split("::")[-1] == name - assert len(reprec.getcalls("pytest_deselected")) == 1 - - for keyword in ["test_one", "est_on"]: - check(keyword, "test_one") - check("TestClass and test", "test_method_one") - - @pytest.mark.parametrize( - "keyword", - [ - "xxx", - "xxx and test_2", - "TestClass", - "xxx and not test_1", - "TestClass and test_2", - "xxx and TestClass and test_2", - ], - ) - def test_select_extra_keywords(self, testdir, keyword): - p = testdir.makepyfile( - test_select=""" - def test_1(): - pass - class TestClass(object): - def test_2(self): - pass - """ - ) - testdir.makepyfile( - conftest=""" - import pytest - @pytest.hookimpl(hookwrapper=True) - def pytest_pycollect_makeitem(name): - outcome = yield - if name == "TestClass": - item = outcome.get_result() - item.extra_keyword_matches.add("xxx") - """ - ) - reprec = testdir.inline_run(p.dirpath(), "-s", "-k", keyword) - print("keyword", repr(keyword)) - passed, skipped, failed = reprec.listoutcomes() - assert len(passed) == 1 - assert passed[0].nodeid.endswith("test_2") - dlist = reprec.getcalls("pytest_deselected") - assert len(dlist) == 1 - assert dlist[0].items[0].name == "test_1" - - def test_select_starton(self, testdir): - threepass = testdir.makepyfile( - test_threepass=""" - def test_one(): assert 1 - def test_two(): assert 1 - def test_three(): assert 1 - """ - ) - reprec = testdir.inline_run("-k", "test_two:", threepass) - passed, skipped, failed = reprec.listoutcomes() - assert len(passed) == 2 - assert not failed - dlist = reprec.getcalls("pytest_deselected") - assert len(dlist) == 1 - item = dlist[0].items[0] - assert item.name == "test_one" - - def test_keyword_extra(self, testdir): - p = testdir.makepyfile( - """ - def test_one(): - assert 0 - test_one.mykeyword = True - """ - ) - reprec = testdir.inline_run("-k", "mykeyword", p) - passed, skipped, failed = reprec.countoutcomes() - assert failed == 1 - - @pytest.mark.xfail - def test_keyword_extra_dash(self, testdir): - p = testdir.makepyfile( - """ - def test_one(): - assert 0 - test_one.mykeyword = True - """ - ) - # with argparse the argument to an option cannot - # start with '-' - reprec = testdir.inline_run("-k", "-mykeyword", p) - passed, skipped, failed = reprec.countoutcomes() - assert passed + skipped + failed == 0 - - def test_no_magic_values(self, testdir): - """Make sure the tests do not match on magic values, - no double underscored values, like '__dict__', - and no instance values, like '()'. - """ - p = testdir.makepyfile( - """ - def test_one(): assert 1 - """ - ) - - def assert_test_is_not_selected(keyword): - reprec = testdir.inline_run("-k", keyword, p) - passed, skipped, failed = reprec.countoutcomes() - dlist = reprec.getcalls("pytest_deselected") - assert passed + skipped + failed == 0 - deselected_tests = dlist[0].items - assert len(deselected_tests) == 1 - - assert_test_is_not_selected("__") - assert_test_is_not_selected("()") - - -@pytest.mark.parametrize( - "argval, expected", - [ - ( - pytest.mark.skip()((1, 2)), - ParameterSet(values=(1, 2), marks=[pytest.mark.skip], id=None), - ), - ( - pytest.mark.xfail(pytest.mark.skip()((1, 2))), - ParameterSet( - values=(1, 2), marks=[pytest.mark.xfail, pytest.mark.skip], id=None - ), - ), - ], -) -@pytest.mark.filterwarnings("ignore") -def test_parameterset_extractfrom(argval, expected): - extracted = ParameterSet.extract_from(argval) - assert extracted == expected - - -def test_legacy_transfer(): - - class FakeModule(object): - pytestmark = [] - - class FakeClass(object): - pytestmark = pytest.mark.nofun - - @pytest.mark.fun - def fake_method(self): - pass - - transfer_markers(fake_method, FakeClass, FakeModule) - - # legacy marks transfer smeared - assert fake_method.nofun - assert fake_method.fun - # pristine marks dont transfer - assert fake_method.pytestmark == [pytest.mark.fun.mark] - - -class TestMarkDecorator(object): - - @pytest.mark.parametrize( - "lhs, rhs, expected", - [ - (pytest.mark.foo(), pytest.mark.foo(), True), - (pytest.mark.foo(), pytest.mark.bar(), False), - (pytest.mark.foo(), "bar", False), - ("foo", pytest.mark.bar(), False), - ], - ) - def test__eq__(self, lhs, rhs, expected): - assert (lhs == rhs) == expected - - -@pytest.mark.parametrize("mark", [None, "", "skip", "xfail"]) -def test_parameterset_for_parametrize_marks(testdir, mark): - if mark is not None: - testdir.makeini("[pytest]\n{}={}".format(EMPTY_PARAMETERSET_OPTION, mark)) - - config = testdir.parseconfig() - from _pytest.mark import pytest_configure, get_empty_parameterset_mark - - pytest_configure(config) - result_mark = get_empty_parameterset_mark(config, ["a"], all) - if mark in (None, ""): - # normalize to the requested name - mark = "skip" - assert result_mark.name == mark - assert result_mark.kwargs["reason"].startswith("got empty parameter set ") - if mark == "xfail": - assert result_mark.kwargs.get("run") is False - - -def test_parameterset_for_parametrize_bad_markname(testdir): - with pytest.raises(pytest.UsageError): - test_parameterset_for_parametrize_marks(testdir, "bad") - - -def test_mark_expressions_no_smear(testdir): - testdir.makepyfile( - """ - import pytest - - class BaseTests(object): - def test_something(self): - pass - - @pytest.mark.FOO - class TestFooClass(BaseTests): - pass - - @pytest.mark.BAR - class TestBarClass(BaseTests): - pass - """ - ) - - reprec = testdir.inline_run("-m", "FOO") - passed, skipped, failed = reprec.countoutcomes() - dlist = reprec.getcalls("pytest_deselected") - assert passed == 1 - assert skipped == failed == 0 - deselected_tests = dlist[0].items - assert len(deselected_tests) == 1 - - # keywords smear - expected behaviour - reprec_keywords = testdir.inline_run("-k", "FOO") - passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes() - assert passed_k == 2 - assert skipped_k == failed_k == 0 - - -def test_addmarker_getmarker(): - node = Node("Test", config=mock.Mock(), session=mock.Mock(), nodeid="Test") - node.add_marker(pytest.mark.a(1)) - node.add_marker("b") - node.get_marker("a").combined - node.get_marker("b").combined diff --git a/third_party/python/pytest/testing/test_modimport.py b/third_party/python/pytest/testing/test_modimport.py deleted file mode 100644 index f7b92a0b6f67..000000000000 --- a/third_party/python/pytest/testing/test_modimport.py +++ /dev/null @@ -1,29 +0,0 @@ -import py -import subprocess -import sys -import pytest -import _pytest - -MODSET = [ - x - for x in py.path.local(_pytest.__file__).dirpath().visit("*.py") - if x.purebasename != "__init__" -] - - -@pytest.mark.parametrize("modfile", MODSET, ids=lambda x: x.purebasename) -def test_fileimport(modfile): - # this test ensures all internal packages can import - # without needing the pytest namespace being set - # this is critical for the initialization of xdist - - res = subprocess.call( - [ - sys.executable, - "-c", - "import sys, py; py.path.local(sys.argv[1]).pyimport()", - modfile.strpath, - ] - ) - if res: - pytest.fail("command result %s" % res) diff --git a/third_party/python/pytest/testing/test_monkeypatch.py b/third_party/python/pytest/testing/test_monkeypatch.py deleted file mode 100644 index c298ce0d9290..000000000000 --- a/third_party/python/pytest/testing/test_monkeypatch.py +++ /dev/null @@ -1,368 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os -import sys -import textwrap - -import pytest -from _pytest.monkeypatch import MonkeyPatch - - -@pytest.fixture -def mp(): - cwd = os.getcwd() - sys_path = list(sys.path) - yield MonkeyPatch() - sys.path[:] = sys_path - os.chdir(cwd) - - -def test_setattr(): - - class A(object): - x = 1 - - monkeypatch = MonkeyPatch() - pytest.raises(AttributeError, "monkeypatch.setattr(A, 'notexists', 2)") - monkeypatch.setattr(A, "y", 2, raising=False) - assert A.y == 2 - monkeypatch.undo() - assert not hasattr(A, "y") - - monkeypatch = MonkeyPatch() - monkeypatch.setattr(A, "x", 2) - assert A.x == 2 - monkeypatch.setattr(A, "x", 3) - assert A.x == 3 - monkeypatch.undo() - assert A.x == 1 - - A.x = 5 - monkeypatch.undo() # double-undo makes no modification - assert A.x == 5 - - -class TestSetattrWithImportPath(object): - - def test_string_expression(self, monkeypatch): - monkeypatch.setattr("os.path.abspath", lambda x: "hello2") - assert os.path.abspath("123") == "hello2" - - def test_string_expression_class(self, monkeypatch): - monkeypatch.setattr("_pytest.config.Config", 42) - import _pytest - - assert _pytest.config.Config == 42 - - def test_unicode_string(self, monkeypatch): - monkeypatch.setattr("_pytest.config.Config", 42) - import _pytest - - assert _pytest.config.Config == 42 - monkeypatch.delattr("_pytest.config.Config") - - def test_wrong_target(self, monkeypatch): - pytest.raises(TypeError, lambda: monkeypatch.setattr(None, None)) - - def test_unknown_import(self, monkeypatch): - pytest.raises(ImportError, lambda: monkeypatch.setattr("unkn123.classx", None)) - - def test_unknown_attr(self, monkeypatch): - pytest.raises( - AttributeError, lambda: monkeypatch.setattr("os.path.qweqwe", None) - ) - - def test_unknown_attr_non_raising(self, monkeypatch): - # https://github.com/pytest-dev/pytest/issues/746 - monkeypatch.setattr("os.path.qweqwe", 42, raising=False) - assert os.path.qweqwe == 42 - - def test_delattr(self, monkeypatch): - monkeypatch.delattr("os.path.abspath") - assert not hasattr(os.path, "abspath") - monkeypatch.undo() - assert os.path.abspath - - -def test_delattr(): - - class A(object): - x = 1 - - monkeypatch = MonkeyPatch() - monkeypatch.delattr(A, "x") - assert not hasattr(A, "x") - monkeypatch.undo() - assert A.x == 1 - - monkeypatch = MonkeyPatch() - monkeypatch.delattr(A, "x") - pytest.raises(AttributeError, "monkeypatch.delattr(A, 'y')") - monkeypatch.delattr(A, "y", raising=False) - monkeypatch.setattr(A, "x", 5, raising=False) - assert A.x == 5 - monkeypatch.undo() - assert A.x == 1 - - -def test_setitem(): - d = {"x": 1} - monkeypatch = MonkeyPatch() - monkeypatch.setitem(d, "x", 2) - monkeypatch.setitem(d, "y", 1700) - monkeypatch.setitem(d, "y", 1700) - assert d["x"] == 2 - assert d["y"] == 1700 - monkeypatch.setitem(d, "x", 3) - assert d["x"] == 3 - monkeypatch.undo() - assert d["x"] == 1 - assert "y" not in d - d["x"] = 5 - monkeypatch.undo() - assert d["x"] == 5 - - -def test_setitem_deleted_meanwhile(): - d = {} - monkeypatch = MonkeyPatch() - monkeypatch.setitem(d, "x", 2) - del d["x"] - monkeypatch.undo() - assert not d - - -@pytest.mark.parametrize("before", [True, False]) -def test_setenv_deleted_meanwhile(before): - key = "qwpeoip123" - if before: - os.environ[key] = "world" - monkeypatch = MonkeyPatch() - monkeypatch.setenv(key, "hello") - del os.environ[key] - monkeypatch.undo() - if before: - assert os.environ[key] == "world" - del os.environ[key] - else: - assert key not in os.environ - - -def test_delitem(): - d = {"x": 1} - monkeypatch = MonkeyPatch() - monkeypatch.delitem(d, "x") - assert "x" not in d - monkeypatch.delitem(d, "y", raising=False) - pytest.raises(KeyError, "monkeypatch.delitem(d, 'y')") - assert not d - monkeypatch.setitem(d, "y", 1700) - assert d["y"] == 1700 - d["hello"] = "world" - monkeypatch.setitem(d, "x", 1500) - assert d["x"] == 1500 - monkeypatch.undo() - assert d == {"hello": "world", "x": 1} - - -def test_setenv(): - monkeypatch = MonkeyPatch() - monkeypatch.setenv("XYZ123", 2) - import os - - assert os.environ["XYZ123"] == "2" - monkeypatch.undo() - assert "XYZ123" not in os.environ - - -def test_delenv(): - name = "xyz1234" - assert name not in os.environ - monkeypatch = MonkeyPatch() - pytest.raises(KeyError, "monkeypatch.delenv(%r, raising=True)" % name) - monkeypatch.delenv(name, raising=False) - monkeypatch.undo() - os.environ[name] = "1" - try: - monkeypatch = MonkeyPatch() - monkeypatch.delenv(name) - assert name not in os.environ - monkeypatch.setenv(name, "3") - assert os.environ[name] == "3" - monkeypatch.undo() - assert os.environ[name] == "1" - finally: - if name in os.environ: - del os.environ[name] - - -def test_setenv_prepend(): - import os - - monkeypatch = MonkeyPatch() - monkeypatch.setenv("XYZ123", 2, prepend="-") - assert os.environ["XYZ123"] == "2" - monkeypatch.setenv("XYZ123", 3, prepend="-") - assert os.environ["XYZ123"] == "3-2" - monkeypatch.undo() - assert "XYZ123" not in os.environ - - -def test_monkeypatch_plugin(testdir): - reprec = testdir.inline_runsource( - """ - def test_method(monkeypatch): - assert monkeypatch.__class__.__name__ == "MonkeyPatch" - """ - ) - res = reprec.countoutcomes() - assert tuple(res) == (1, 0, 0), res - - -def test_syspath_prepend(mp): - old = list(sys.path) - mp.syspath_prepend("world") - mp.syspath_prepend("hello") - assert sys.path[0] == "hello" - assert sys.path[1] == "world" - mp.undo() - assert sys.path == old - mp.undo() - assert sys.path == old - - -def test_syspath_prepend_double_undo(mp): - mp.syspath_prepend("hello world") - mp.undo() - sys.path.append("more hello world") - mp.undo() - assert sys.path[-1] == "more hello world" - - -def test_chdir_with_path_local(mp, tmpdir): - mp.chdir(tmpdir) - assert os.getcwd() == tmpdir.strpath - - -def test_chdir_with_str(mp, tmpdir): - mp.chdir(tmpdir.strpath) - assert os.getcwd() == tmpdir.strpath - - -def test_chdir_undo(mp, tmpdir): - cwd = os.getcwd() - mp.chdir(tmpdir) - mp.undo() - assert os.getcwd() == cwd - - -def test_chdir_double_undo(mp, tmpdir): - mp.chdir(tmpdir.strpath) - mp.undo() - tmpdir.chdir() - mp.undo() - assert os.getcwd() == tmpdir.strpath - - -def test_issue185_time_breaks(testdir): - testdir.makepyfile( - """ - import time - def test_m(monkeypatch): - def f(): - raise Exception - monkeypatch.setattr(time, "time", f) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *1 passed* - """ - ) - - -def test_importerror(testdir): - p = testdir.mkpydir("package") - p.join("a.py").write( - textwrap.dedent( - """\ - import doesnotexist - - x = 1 - """ - ) - ) - testdir.tmpdir.join("test_importerror.py").write( - textwrap.dedent( - """\ - def test_importerror(monkeypatch): - monkeypatch.setattr('package.a.x', 2) - """ - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *import error in package.a: No module named {0}doesnotexist{0}* - """.format( - "'" if sys.version_info > (3, 0) else "" - ) - ) - - -class SampleNew(object): - - @staticmethod - def hello(): - return True - - -class SampleNewInherit(SampleNew): - pass - - -class SampleOld(object): - # oldstyle on python2 - @staticmethod - def hello(): - return True - - -class SampleOldInherit(SampleOld): - pass - - -@pytest.mark.parametrize( - "Sample", - [SampleNew, SampleNewInherit, SampleOld, SampleOldInherit], - ids=["new", "new-inherit", "old", "old-inherit"], -) -def test_issue156_undo_staticmethod(Sample): - monkeypatch = MonkeyPatch() - - monkeypatch.setattr(Sample, "hello", None) - assert Sample.hello is None - - monkeypatch.undo() - assert Sample.hello() - - -def test_issue1338_name_resolving(): - pytest.importorskip("requests") - monkeypatch = MonkeyPatch() - try: - monkeypatch.delattr("requests.sessions.Session.request") - finally: - monkeypatch.undo() - - -def test_context(): - monkeypatch = MonkeyPatch() - - import functools - import inspect - - with monkeypatch.context() as m: - m.setattr(functools, "partial", 3) - assert not inspect.isclass(functools.partial) - assert inspect.isclass(functools.partial) diff --git a/third_party/python/pytest/testing/test_nodes.py b/third_party/python/pytest/testing/test_nodes.py deleted file mode 100644 index eee3ac8e9e4c..000000000000 --- a/third_party/python/pytest/testing/test_nodes.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from _pytest import nodes - - -@pytest.mark.parametrize( - "baseid, nodeid, expected", - ( - ("", "", True), - ("", "foo", True), - ("", "foo/bar", True), - ("", "foo/bar::TestBaz::()", True), - ("foo", "food", False), - ("foo/bar::TestBaz::()", "foo/bar", False), - ("foo/bar::TestBaz::()", "foo/bar::TestBop::()", False), - ("foo/bar", "foo/bar::TestBop::()", True), - ), -) -def test_ischildnode(baseid, nodeid, expected): - result = nodes.ischildnode(baseid, nodeid) - assert result is expected diff --git a/third_party/python/pytest/testing/test_nose.py b/third_party/python/pytest/testing/test_nose.py deleted file mode 100644 index abe7323754ed..000000000000 --- a/third_party/python/pytest/testing/test_nose.py +++ /dev/null @@ -1,433 +0,0 @@ -from __future__ import absolute_import, division, print_function -import pytest - - -def setup_module(mod): - mod.nose = pytest.importorskip("nose") - - -def test_nose_setup(testdir): - p = testdir.makepyfile( - """ - values = [] - from nose.tools import with_setup - - @with_setup(lambda: values.append(1), lambda: values.append(2)) - def test_hello(): - assert values == [1] - - def test_world(): - assert values == [1,2] - - test_hello.setup = lambda: values.append(1) - test_hello.teardown = lambda: values.append(2) - """ - ) - result = testdir.runpytest(p, "-p", "nose") - result.assert_outcomes(passed=2) - - -def test_setup_func_with_setup_decorator(): - from _pytest.nose import call_optional - - values = [] - - class A(object): - - @pytest.fixture(autouse=True) - def f(self): - values.append(1) - - call_optional(A(), "f") - assert not values - - -def test_setup_func_not_callable(): - from _pytest.nose import call_optional - - class A(object): - f = 1 - - call_optional(A(), "f") - - -def test_nose_setup_func(testdir): - p = testdir.makepyfile( - """ - from nose.tools import with_setup - - values = [] - - def my_setup(): - a = 1 - values.append(a) - - def my_teardown(): - b = 2 - values.append(b) - - @with_setup(my_setup, my_teardown) - def test_hello(): - print (values) - assert values == [1] - - def test_world(): - print (values) - assert values == [1,2] - - """ - ) - result = testdir.runpytest(p, "-p", "nose") - result.assert_outcomes(passed=2) - - -def test_nose_setup_func_failure(testdir): - p = testdir.makepyfile( - """ - from nose.tools import with_setup - - values = [] - my_setup = lambda x: 1 - my_teardown = lambda x: 2 - - @with_setup(my_setup, my_teardown) - def test_hello(): - print (values) - assert values == [1] - - def test_world(): - print (values) - assert values == [1,2] - - """ - ) - result = testdir.runpytest(p, "-p", "nose") - result.stdout.fnmatch_lines(["*TypeError: ()*"]) - - -def test_nose_setup_func_failure_2(testdir): - testdir.makepyfile( - """ - values = [] - - my_setup = 1 - my_teardown = 2 - - def test_hello(): - assert values == [] - - test_hello.setup = my_setup - test_hello.teardown = my_teardown - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -def test_nose_setup_partial(testdir): - pytest.importorskip("functools") - p = testdir.makepyfile( - """ - from functools import partial - - values = [] - - def my_setup(x): - a = x - values.append(a) - - def my_teardown(x): - b = x - values.append(b) - - my_setup_partial = partial(my_setup, 1) - my_teardown_partial = partial(my_teardown, 2) - - def test_hello(): - print (values) - assert values == [1] - - def test_world(): - print (values) - assert values == [1,2] - - test_hello.setup = my_setup_partial - test_hello.teardown = my_teardown_partial - """ - ) - result = testdir.runpytest(p, "-p", "nose") - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_nose_test_generator_fixtures(testdir): - p = testdir.makepyfile( - """ - # taken from nose-0.11.1 unit_tests/test_generator_fixtures.py - from nose.tools import eq_ - called = [] - - def outer_setup(): - called.append('outer_setup') - - def outer_teardown(): - called.append('outer_teardown') - - def inner_setup(): - called.append('inner_setup') - - def inner_teardown(): - called.append('inner_teardown') - - def test_gen(): - called[:] = [] - for i in range(0, 5): - yield check, i - - def check(i): - expect = ['outer_setup'] - for x in range(0, i): - expect.append('inner_setup') - expect.append('inner_teardown') - expect.append('inner_setup') - eq_(called, expect) - - - test_gen.setup = outer_setup - test_gen.teardown = outer_teardown - check.setup = inner_setup - check.teardown = inner_teardown - - class TestClass(object): - def setup(self): - print ("setup called in %s" % self) - self.called = ['setup'] - - def teardown(self): - print ("teardown called in %s" % self) - eq_(self.called, ['setup']) - self.called.append('teardown') - - def test(self): - print ("test called in %s" % self) - for i in range(0, 5): - yield self.check, i - - def check(self, i): - print ("check called in %s" % self) - expect = ['setup'] - #for x in range(0, i): - # expect.append('setup') - # expect.append('teardown') - #expect.append('setup') - eq_(self.called, expect) - """ - ) - result = testdir.runpytest(p, "-p", "nose") - result.stdout.fnmatch_lines(["*10 passed*"]) - - -def test_module_level_setup(testdir): - testdir.makepyfile( - """ - from nose.tools import with_setup - items = {} - - def setup(): - items[1]=1 - - def teardown(): - del items[1] - - def setup2(): - items[2] = 2 - - def teardown2(): - del items[2] - - def test_setup_module_setup(): - assert items[1] == 1 - - @with_setup(setup2, teardown2) - def test_local_setup(): - assert items[2] == 2 - assert 1 not in items - """ - ) - result = testdir.runpytest("-p", "nose") - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_nose_style_setup_teardown(testdir): - testdir.makepyfile( - """ - values = [] - - def setup_module(): - values.append(1) - - def teardown_module(): - del values[0] - - def test_hello(): - assert values == [1] - - def test_world(): - assert values == [1] - """ - ) - result = testdir.runpytest("-p", "nose") - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_nose_setup_ordering(testdir): - testdir.makepyfile( - """ - def setup_module(mod): - mod.visited = True - - class TestClass(object): - def setup(self): - assert visited - def test_first(self): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_apiwrapper_problem_issue260(testdir): - # this would end up trying a call an optional teardown on the class - # for plain unittests we dont want nose behaviour - testdir.makepyfile( - """ - import unittest - class TestCase(unittest.TestCase): - def setup(self): - #should not be called in unittest testcases - assert 0, 'setup' - def teardown(self): - #should not be called in unittest testcases - assert 0, 'teardown' - def setUp(self): - print('setup') - def tearDown(self): - print('teardown') - def test_fun(self): - pass - """ - ) - result = testdir.runpytest() - result.assert_outcomes(passed=1) - - -def test_setup_teardown_linking_issue265(testdir): - # we accidentally didnt integrate nose setupstate with normal setupstate - # this test ensures that won't happen again - testdir.makepyfile( - ''' - import pytest - - class TestGeneric(object): - def test_nothing(self): - """Tests the API of the implementation (for generic and specialized).""" - - @pytest.mark.skipif("True", reason= - "Skip tests to check if teardown is skipped as well.") - class TestSkipTeardown(TestGeneric): - - def setup(self): - """Sets up my specialized implementation for $COOL_PLATFORM.""" - raise Exception("should not call setup for skipped tests") - - def teardown(self): - """Undoes the setup.""" - raise Exception("should not call teardown for skipped tests") - ''' - ) - reprec = testdir.runpytest() - reprec.assert_outcomes(passed=1, skipped=1) - - -def test_SkipTest_during_collection(testdir): - p = testdir.makepyfile( - """ - import nose - raise nose.SkipTest("during collection") - def test_failing(): - assert False - """ - ) - result = testdir.runpytest(p) - result.assert_outcomes(skipped=1) - - -def test_SkipTest_in_test(testdir): - testdir.makepyfile( - """ - import nose - - def test_skipping(): - raise nose.SkipTest("in test") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(skipped=1) - - -def test_istest_function_decorator(testdir): - p = testdir.makepyfile( - """ - import nose.tools - @nose.tools.istest - def not_test_prefix(): - pass - """ - ) - result = testdir.runpytest(p) - result.assert_outcomes(passed=1) - - -def test_nottest_function_decorator(testdir): - testdir.makepyfile( - """ - import nose.tools - @nose.tools.nottest - def test_prefix(): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - calls = reprec.getreports("pytest_runtest_logreport") - assert not calls - - -def test_istest_class_decorator(testdir): - p = testdir.makepyfile( - """ - import nose.tools - @nose.tools.istest - class NotTestPrefix(object): - def test_method(self): - pass - """ - ) - result = testdir.runpytest(p) - result.assert_outcomes(passed=1) - - -def test_nottest_class_decorator(testdir): - testdir.makepyfile( - """ - import nose.tools - @nose.tools.nottest - class TestPrefix(object): - def test_method(self): - pass - """ - ) - reprec = testdir.inline_run() - assert not reprec.getfailedcollections() - calls = reprec.getreports("pytest_runtest_logreport") - assert not calls diff --git a/third_party/python/pytest/testing/test_parseopt.py b/third_party/python/pytest/testing/test_parseopt.py deleted file mode 100644 index 79076cafd810..000000000000 --- a/third_party/python/pytest/testing/test_parseopt.py +++ /dev/null @@ -1,336 +0,0 @@ -from __future__ import absolute_import, division, print_function -import argparse -import sys -import os -import py -import pytest -from _pytest.config import argparsing as parseopt - - -@pytest.fixture -def parser(): - return parseopt.Parser() - - -class TestParser(object): - - def test_no_help_by_default(self, capsys): - parser = parseopt.Parser(usage="xyz") - pytest.raises(SystemExit, lambda: parser.parse(["-h"])) - out, err = capsys.readouterr() - assert err.find("error: unrecognized arguments") != -1 - - def test_argument(self): - with pytest.raises(parseopt.ArgumentError): - # need a short or long option - argument = parseopt.Argument() - argument = parseopt.Argument("-t") - assert argument._short_opts == ["-t"] - assert argument._long_opts == [] - assert argument.dest == "t" - argument = parseopt.Argument("-t", "--test") - assert argument._short_opts == ["-t"] - assert argument._long_opts == ["--test"] - assert argument.dest == "test" - argument = parseopt.Argument("-t", "--test", dest="abc") - assert argument.dest == "abc" - assert ( - str(argument) - == ("Argument(_short_opts: ['-t'], _long_opts: ['--test'], dest: 'abc')") - ) - - def test_argument_type(self): - argument = parseopt.Argument("-t", dest="abc", type=int) - assert argument.type is int - argument = parseopt.Argument("-t", dest="abc", type=str) - assert argument.type is str - argument = parseopt.Argument("-t", dest="abc", type=float) - assert argument.type is float - with pytest.warns(DeprecationWarning): - with pytest.raises(KeyError): - argument = parseopt.Argument("-t", dest="abc", type="choice") - argument = parseopt.Argument( - "-t", dest="abc", type=str, choices=["red", "blue"] - ) - assert argument.type is str - - def test_argument_processopt(self): - argument = parseopt.Argument("-t", type=int) - argument.default = 42 - argument.dest = "abc" - res = argument.attrs() - assert res["default"] == 42 - assert res["dest"] == "abc" - - def test_group_add_and_get(self, parser): - group = parser.getgroup("hello", description="desc") - assert group.name == "hello" - assert group.description == "desc" - - def test_getgroup_simple(self, parser): - group = parser.getgroup("hello", description="desc") - assert group.name == "hello" - assert group.description == "desc" - group2 = parser.getgroup("hello") - assert group2 is group - - def test_group_ordering(self, parser): - parser.getgroup("1") - parser.getgroup("2") - parser.getgroup("3", after="1") - groups = parser._groups - groups_names = [x.name for x in groups] - assert groups_names == list("132") - - def test_group_addoption(self): - group = parseopt.OptionGroup("hello") - group.addoption("--option1", action="store_true") - assert len(group.options) == 1 - assert isinstance(group.options[0], parseopt.Argument) - - def test_group_addoption_conflict(self): - group = parseopt.OptionGroup("hello again") - group.addoption("--option1", "--option-1", action="store_true") - with pytest.raises(ValueError) as err: - group.addoption("--option1", "--option-one", action="store_true") - assert str({"--option1"}) in str(err.value) - - def test_group_shortopt_lowercase(self, parser): - group = parser.getgroup("hello") - pytest.raises( - ValueError, - """ - group.addoption("-x", action="store_true") - """, - ) - assert len(group.options) == 0 - group._addoption("-x", action="store_true") - assert len(group.options) == 1 - - def test_parser_addoption(self, parser): - group = parser.getgroup("custom options") - assert len(group.options) == 0 - group.addoption("--option1", action="store_true") - assert len(group.options) == 1 - - def test_parse(self, parser): - parser.addoption("--hello", dest="hello", action="store") - args = parser.parse(["--hello", "world"]) - assert args.hello == "world" - assert not getattr(args, parseopt.FILE_OR_DIR) - - def test_parse2(self, parser): - args = parser.parse([py.path.local()]) - assert getattr(args, parseopt.FILE_OR_DIR)[0] == py.path.local() - - def test_parse_known_args(self, parser): - parser.parse_known_args([py.path.local()]) - parser.addoption("--hello", action="store_true") - ns = parser.parse_known_args(["x", "--y", "--hello", "this"]) - assert ns.hello - assert ns.file_or_dir == ["x"] - - def test_parse_known_and_unknown_args(self, parser): - parser.addoption("--hello", action="store_true") - ns, unknown = parser.parse_known_and_unknown_args( - ["x", "--y", "--hello", "this"] - ) - assert ns.hello - assert ns.file_or_dir == ["x"] - assert unknown == ["--y", "this"] - - def test_parse_will_set_default(self, parser): - parser.addoption("--hello", dest="hello", default="x", action="store") - option = parser.parse([]) - assert option.hello == "x" - del option.hello - parser.parse_setoption([], option) - assert option.hello == "x" - - def test_parse_setoption(self, parser): - parser.addoption("--hello", dest="hello", action="store") - parser.addoption("--world", dest="world", default=42) - - class A(object): - pass - - option = A() - args = parser.parse_setoption(["--hello", "world"], option) - assert option.hello == "world" - assert option.world == 42 - assert not args - - def test_parse_special_destination(self, parser): - parser.addoption("--ultimate-answer", type=int) - args = parser.parse(["--ultimate-answer", "42"]) - assert args.ultimate_answer == 42 - - def test_parse_split_positional_arguments(self, parser): - parser.addoption("-R", action="store_true") - parser.addoption("-S", action="store_false") - args = parser.parse(["-R", "4", "2", "-S"]) - assert getattr(args, parseopt.FILE_OR_DIR) == ["4", "2"] - args = parser.parse(["-R", "-S", "4", "2", "-R"]) - assert getattr(args, parseopt.FILE_OR_DIR) == ["4", "2"] - assert args.R is True - assert args.S is False - args = parser.parse(["-R", "4", "-S", "2"]) - assert getattr(args, parseopt.FILE_OR_DIR) == ["4", "2"] - assert args.R is True - assert args.S is False - - def test_parse_defaultgetter(self): - - def defaultget(option): - if not hasattr(option, "type"): - return - if option.type is int: - option.default = 42 - elif option.type is str: - option.default = "world" - - parser = parseopt.Parser(processopt=defaultget) - parser.addoption("--this", dest="this", type=int, action="store") - parser.addoption("--hello", dest="hello", type=str, action="store") - parser.addoption("--no", dest="no", action="store_true") - option = parser.parse([]) - assert option.hello == "world" - assert option.this == 42 - assert option.no is False - - def test_drop_short_helper(self): - parser = argparse.ArgumentParser( - formatter_class=parseopt.DropShorterLongHelpFormatter - ) - parser.add_argument( - "-t", "--twoword", "--duo", "--two-word", "--two", help="foo" - ).map_long_option = { - "two": "two-word" - } - # throws error on --deux only! - parser.add_argument( - "-d", "--deuxmots", "--deux-mots", action="store_true", help="foo" - ).map_long_option = { - "deux": "deux-mots" - } - parser.add_argument("-s", action="store_true", help="single short") - parser.add_argument("--abc", "-a", action="store_true", help="bar") - parser.add_argument("--klm", "-k", "--kl-m", action="store_true", help="bar") - parser.add_argument( - "-P", "--pq-r", "-p", "--pqr", action="store_true", help="bar" - ) - parser.add_argument( - "--zwei-wort", "--zweiwort", "--zweiwort", action="store_true", help="bar" - ) - parser.add_argument( - "-x", "--exit-on-first", "--exitfirst", action="store_true", help="spam" - ).map_long_option = { - "exitfirst": "exit-on-first" - } - parser.add_argument("files_and_dirs", nargs="*") - args = parser.parse_args(["-k", "--duo", "hallo", "--exitfirst"]) - assert args.twoword == "hallo" - assert args.klm is True - assert args.zwei_wort is False - assert args.exit_on_first is True - assert args.s is False - args = parser.parse_args(["--deux-mots"]) - with pytest.raises(AttributeError): - assert args.deux_mots is True - assert args.deuxmots is True - args = parser.parse_args(["file", "dir"]) - assert "|".join(args.files_and_dirs) == "file|dir" - - def test_drop_short_0(self, parser): - parser.addoption("--funcarg", "--func-arg", action="store_true") - parser.addoption("--abc-def", "--abc-def", action="store_true") - parser.addoption("--klm-hij", action="store_true") - args = parser.parse(["--funcarg", "--k"]) - assert args.funcarg is True - assert args.abc_def is False - assert args.klm_hij is True - - def test_drop_short_2(self, parser): - parser.addoption("--func-arg", "--doit", action="store_true") - args = parser.parse(["--doit"]) - assert args.func_arg is True - - def test_drop_short_3(self, parser): - parser.addoption("--func-arg", "--funcarg", "--doit", action="store_true") - args = parser.parse(["abcd"]) - assert args.func_arg is False - assert args.file_or_dir == ["abcd"] - - def test_drop_short_help0(self, parser, capsys): - parser.addoption("--func-args", "--doit", help="foo", action="store_true") - parser.parse([]) - help = parser.optparser.format_help() - assert "--func-args, --doit foo" in help - - # testing would be more helpful with all help generated - def test_drop_short_help1(self, parser, capsys): - group = parser.getgroup("general") - group.addoption("--doit", "--func-args", action="store_true", help="foo") - group._addoption( - "-h", - "--help", - action="store_true", - dest="help", - help="show help message and configuration info", - ) - parser.parse(["-h"]) - help = parser.optparser.format_help() - assert "-doit, --func-args foo" in help - - def test_multiple_metavar_help(self, parser): - """ - Help text for options with a metavar tuple should display help - in the form "--preferences=value1 value2 value3" (#2004). - """ - group = parser.getgroup("general") - group.addoption( - "--preferences", metavar=("value1", "value2", "value3"), nargs=3 - ) - group._addoption("-h", "--help", action="store_true", dest="help") - parser.parse(["-h"]) - help = parser.optparser.format_help() - assert "--preferences=value1 value2 value3" in help - - -def test_argcomplete(testdir, monkeypatch): - if not py.path.local.sysfind("bash"): - pytest.skip("bash not available") - script = str(testdir.tmpdir.join("test_argcomplete")) - pytest_bin = sys.argv[0] - if "pytest" not in os.path.basename(pytest_bin): - pytest.skip("need to be run with pytest executable, not %s" % (pytest_bin,)) - - with open(str(script), "w") as fp: - # redirect output from argcomplete to stdin and stderr is not trivial - # http://stackoverflow.com/q/12589419/1307905 - # so we use bash - fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" %s 8>&1 9>&2' % pytest_bin) - # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able - # to handle a keyword argument env that replaces os.environ in popen or - # extends the copy, advantage: could not forget to restore - monkeypatch.setenv("_ARGCOMPLETE", "1") - monkeypatch.setenv("_ARGCOMPLETE_IFS", "\x0b") - monkeypatch.setenv("COMP_WORDBREAKS", " \\t\\n\"\\'><=;|&(:") - - arg = "--fu" - monkeypatch.setenv("COMP_LINE", "pytest " + arg) - monkeypatch.setenv("COMP_POINT", str(len("pytest " + arg))) - result = testdir.run("bash", str(script), arg) - if result.ret == 255: - # argcomplete not found - pytest.skip("argcomplete not available") - elif not result.stdout.str(): - pytest.skip("bash provided no output, argcomplete not available?") - else: - result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) - os.mkdir("test_argcomplete.d") - arg = "test_argc" - monkeypatch.setenv("COMP_LINE", "pytest " + arg) - monkeypatch.setenv("COMP_POINT", str(len("pytest " + arg))) - result = testdir.run("bash", str(script), arg) - result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) diff --git a/third_party/python/pytest/testing/test_pastebin.py b/third_party/python/pytest/testing/test_pastebin.py deleted file mode 100644 index ad7c4d0c1c06..000000000000 --- a/third_party/python/pytest/testing/test_pastebin.py +++ /dev/null @@ -1,132 +0,0 @@ -# encoding: utf-8 -from __future__ import absolute_import, division, print_function -import sys -import pytest - - -class TestPasteCapture(object): - - @pytest.fixture - def pastebinlist(self, monkeypatch, request): - pastebinlist = [] - plugin = request.config.pluginmanager.getplugin("pastebin") - monkeypatch.setattr(plugin, "create_new_paste", pastebinlist.append) - return pastebinlist - - def test_failed(self, testdir, pastebinlist): - testpath = testdir.makepyfile( - """ - import pytest - def test_pass(): - pass - def test_fail(): - assert 0 - def test_skip(): - pytest.skip("") - """ - ) - reprec = testdir.inline_run(testpath, "--paste=failed") - assert len(pastebinlist) == 1 - s = pastebinlist[0] - assert s.find("def test_fail") != -1 - assert reprec.countoutcomes() == [1, 1, 1] - - def test_all(self, testdir, pastebinlist): - from _pytest.pytester import LineMatcher - - testpath = testdir.makepyfile( - """ - import pytest - def test_pass(): - pass - def test_fail(): - assert 0 - def test_skip(): - pytest.skip("") - """ - ) - reprec = testdir.inline_run(testpath, "--pastebin=all", "-v") - assert reprec.countoutcomes() == [1, 1, 1] - assert len(pastebinlist) == 1 - contents = pastebinlist[0].decode("utf-8") - matcher = LineMatcher(contents.splitlines()) - matcher.fnmatch_lines( - [ - "*test_pass PASSED*", - "*test_fail FAILED*", - "*test_skip SKIPPED*", - "*== 1 failed, 1 passed, 1 skipped in *", - ] - ) - - def test_non_ascii_paste_text(self, testdir): - """Make sure that text which contains non-ascii characters is pasted - correctly. See #1219. - """ - testdir.makepyfile( - test_unicode=""" - # encoding: utf-8 - def test(): - assert '☺' == 1 - """ - ) - result = testdir.runpytest("--pastebin=all") - if sys.version_info[0] == 3: - expected_msg = "*assert '☺' == 1*" - else: - expected_msg = "*assert '\\xe2\\x98\\xba' == 1*" - result.stdout.fnmatch_lines( - [ - expected_msg, - "*== 1 failed in *", - "*Sending information to Paste Service*", - ] - ) - - -class TestPaste(object): - - @pytest.fixture - def pastebin(self, request): - return request.config.pluginmanager.getplugin("pastebin") - - @pytest.fixture - def mocked_urlopen(self, monkeypatch): - """ - monkeypatch the actual urlopen calls done by the internal plugin - function that connects to bpaste service. - """ - calls = [] - - def mocked(url, data): - calls.append((url, data)) - - class DummyFile(object): - - def read(self): - # part of html of a normal response - return b'View raw.' - - return DummyFile() - - if sys.version_info < (3, 0): - import urllib - - monkeypatch.setattr(urllib, "urlopen", mocked) - else: - import urllib.request - - monkeypatch.setattr(urllib.request, "urlopen", mocked) - return calls - - def test_create_new_paste(self, pastebin, mocked_urlopen): - result = pastebin.create_new_paste(b"full-paste-contents") - assert result == "https://bpaste.net/show/3c0c6750bd" - assert len(mocked_urlopen) == 1 - url, data = mocked_urlopen[0] - assert type(data) is bytes - lexer = "python3" if sys.version_info[0] == 3 else "python" - assert url == "https://bpaste.net" - assert "lexer=%s" % lexer in data.decode() - assert "code=full-paste-contents" in data.decode() - assert "expiry=1week" in data.decode() diff --git a/third_party/python/pytest/testing/test_pdb.py b/third_party/python/pytest/testing/test_pdb.py deleted file mode 100644 index 615d52e83454..000000000000 --- a/third_party/python/pytest/testing/test_pdb.py +++ /dev/null @@ -1,702 +0,0 @@ -from __future__ import absolute_import, division, print_function -import sys -import platform -import os - -import _pytest._code -from _pytest.debugging import SUPPORTS_BREAKPOINT_BUILTIN -import pytest - - -_ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "") - - -def runpdb_and_get_report(testdir, source): - p = testdir.makepyfile(source) - result = testdir.runpytest_inprocess("--pdb", p) - reports = result.reprec.getreports("pytest_runtest_logreport") - assert len(reports) == 3, reports # setup/call/teardown - return reports[1] - - -@pytest.fixture -def custom_pdb_calls(): - called = [] - - # install dummy debugger class and track which methods were called on it - class _CustomPdb(object): - - def __init__(self, *args, **kwargs): - called.append("init") - - def reset(self): - called.append("reset") - - def interaction(self, *args): - called.append("interaction") - - _pytest._CustomPdb = _CustomPdb - return called - - -@pytest.fixture -def custom_debugger_hook(): - called = [] - - # install dummy debugger class and track which methods were called on it - class _CustomDebugger(object): - - def __init__(self, *args, **kwargs): - called.append("init") - - def reset(self): - called.append("reset") - - def interaction(self, *args): - called.append("interaction") - - def set_trace(self, frame): - print("**CustomDebugger**") - called.append("set_trace") - - _pytest._CustomDebugger = _CustomDebugger - yield called - del _pytest._CustomDebugger - - -class TestPDB(object): - - @pytest.fixture - def pdblist(self, request): - monkeypatch = request.getfixturevalue("monkeypatch") - pdblist = [] - - def mypdb(*args): - pdblist.append(args) - - plugin = request.config.pluginmanager.getplugin("debugging") - monkeypatch.setattr(plugin, "post_mortem", mypdb) - return pdblist - - def test_pdb_on_fail(self, testdir, pdblist): - rep = runpdb_and_get_report( - testdir, - """ - def test_func(): - assert 0 - """, - ) - assert rep.failed - assert len(pdblist) == 1 - tb = _pytest._code.Traceback(pdblist[0][0]) - assert tb[-1].name == "test_func" - - def test_pdb_on_xfail(self, testdir, pdblist): - rep = runpdb_and_get_report( - testdir, - """ - import pytest - @pytest.mark.xfail - def test_func(): - assert 0 - """, - ) - assert "xfail" in rep.keywords - assert not pdblist - - def test_pdb_on_skip(self, testdir, pdblist): - rep = runpdb_and_get_report( - testdir, - """ - import pytest - def test_func(): - pytest.skip("hello") - """, - ) - assert rep.skipped - assert len(pdblist) == 0 - - def test_pdb_on_BdbQuit(self, testdir, pdblist): - rep = runpdb_and_get_report( - testdir, - """ - import bdb - def test_func(): - raise bdb.BdbQuit - """, - ) - assert rep.failed - assert len(pdblist) == 0 - - def test_pdb_on_KeyboardInterrupt(self, testdir, pdblist): - rep = runpdb_and_get_report( - testdir, - """ - def test_func(): - raise KeyboardInterrupt - """, - ) - assert rep.failed - assert len(pdblist) == 1 - - def test_pdb_interaction(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - i = 0 - assert i == 1 - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect(".*def test_1") - child.expect(".*i = 0") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "def test_1" not in rest - self.flush(child) - - @staticmethod - def flush(child): - if platform.system() == "Darwin": - return - if child.isalive(): - child.wait() - - def test_pdb_unittest_postmortem(self, testdir): - p1 = testdir.makepyfile( - """ - import unittest - class Blub(unittest.TestCase): - def tearDown(self): - self.filename = None - def test_false(self): - self.filename = 'debug' + '.me' - assert 0 - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect("(Pdb)") - child.sendline("p self.filename") - child.sendeof() - rest = child.read().decode("utf8") - assert "debug.me" in rest - self.flush(child) - - def test_pdb_unittest_skip(self, testdir): - """Test for issue #2137""" - p1 = testdir.makepyfile( - """ - import unittest - @unittest.skipIf(True, 'Skipping also with pdb active') - class MyTestCase(unittest.TestCase): - def test_one(self): - assert 0 - """ - ) - child = testdir.spawn_pytest("-rs --pdb %s" % p1) - child.expect("Skipping also with pdb active") - child.expect("1 skipped in") - child.sendeof() - self.flush(child) - - def test_pdb_print_captured_stdout(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - print("get\\x20rekt") - assert False - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect("captured stdout") - child.expect("get rekt") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "get rekt" not in rest - self.flush(child) - - def test_pdb_print_captured_stderr(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - import sys - sys.stderr.write("get\\x20rekt") - assert False - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect("captured stderr") - child.expect("get rekt") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "get rekt" not in rest - self.flush(child) - - def test_pdb_dont_print_empty_captured_stdout_and_stderr(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - assert False - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect("(Pdb)") - output = child.before.decode("utf8") - child.sendeof() - assert "captured stdout" not in output - assert "captured stderr" not in output - self.flush(child) - - @pytest.mark.parametrize("showcapture", ["all", "no", "log"]) - def test_pdb_print_captured_logs(self, testdir, showcapture): - p1 = testdir.makepyfile( - """ - def test_1(): - import logging - logging.warn("get " + "rekt") - assert False - """ - ) - child = testdir.spawn_pytest("--show-capture=%s --pdb %s" % (showcapture, p1)) - if showcapture in ("all", "log"): - child.expect("captured log") - child.expect("get rekt") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - self.flush(child) - - def test_pdb_print_captured_logs_nologging(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - import logging - logging.warn("get " + "rekt") - assert False - """ - ) - child = testdir.spawn_pytest( - "--show-capture=all --pdb " "-p no:logging %s" % p1 - ) - child.expect("get rekt") - output = child.before.decode("utf8") - assert "captured log" not in output - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - self.flush(child) - - def test_pdb_interaction_exception(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def globalfunc(): - pass - def test_1(): - pytest.raises(ValueError, globalfunc) - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - child.expect(".*def test_1") - child.expect(".*pytest.raises.*globalfunc") - child.expect("(Pdb)") - child.sendline("globalfunc") - child.expect(".*function") - child.sendeof() - child.expect("1 failed") - self.flush(child) - - def test_pdb_interaction_on_collection_issue181(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - xxx - """ - ) - child = testdir.spawn_pytest("--pdb %s" % p1) - # child.expect(".*import pytest.*") - child.expect("(Pdb)") - child.sendeof() - child.expect("1 error") - self.flush(child) - - def test_pdb_interaction_on_internal_error(self, testdir): - testdir.makeconftest( - """ - def pytest_runtest_protocol(): - 0/0 - """ - ) - p1 = testdir.makepyfile("def test_func(): pass") - child = testdir.spawn_pytest("--pdb %s" % p1) - # child.expect(".*import pytest.*") - child.expect("(Pdb)") - child.sendeof() - self.flush(child) - - def test_pdb_interaction_capturing_simple(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def test_1(): - i = 0 - print ("hello17") - pytest.set_trace() - x = 3 - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.expect("x = 3") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf-8") - assert "1 failed" in rest - assert "def test_1" in rest - assert "hello17" in rest # out is captured - self.flush(child) - - def test_pdb_set_trace_interception(self, testdir): - p1 = testdir.makepyfile( - """ - import pdb - def test_1(): - pdb.set_trace() - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "reading from stdin while output" not in rest - self.flush(child) - - def test_pdb_and_capsys(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def test_1(capsys): - print ("hello1") - pytest.set_trace() - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.send("capsys.readouterr()\n") - child.expect("hello1") - child.sendeof() - child.read() - self.flush(child) - - def test_set_trace_capturing_afterwards(self, testdir): - p1 = testdir.makepyfile( - """ - import pdb - def test_1(): - pdb.set_trace() - def test_2(): - print ("hello") - assert 0 - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.send("c\n") - child.expect("test_2") - child.expect("Captured") - child.expect("hello") - child.sendeof() - child.read() - self.flush(child) - - def test_pdb_interaction_doctest(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def function_1(): - ''' - >>> i = 0 - >>> assert i == 1 - ''' - """ - ) - child = testdir.spawn_pytest("--doctest-modules --pdb %s" % p1) - child.expect("(Pdb)") - child.sendline("i") - child.expect("0") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - self.flush(child) - - def test_pdb_interaction_capturing_twice(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def test_1(): - i = 0 - print ("hello17") - pytest.set_trace() - x = 3 - print ("hello18") - pytest.set_trace() - x = 4 - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.expect("x = 3") - child.expect("(Pdb)") - child.sendline("c") - child.expect("x = 4") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "def test_1" in rest - assert "hello17" in rest # out is captured - assert "hello18" in rest # out is captured - self.flush(child) - - def test_pdb_used_outside_test(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - pytest.set_trace() - x = 5 - """ - ) - child = testdir.spawn("%s %s" % (sys.executable, p1)) - child.expect("x = 5") - child.sendeof() - self.flush(child) - - def test_pdb_used_in_generate_tests(self, testdir): - p1 = testdir.makepyfile( - """ - import pytest - def pytest_generate_tests(metafunc): - pytest.set_trace() - x = 5 - def test_foo(a): - pass - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("x = 5") - child.sendeof() - self.flush(child) - - def test_pdb_collection_failure_is_shown(self, testdir): - p1 = testdir.makepyfile("xxx") - result = testdir.runpytest_subprocess("--pdb", p1) - result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"]) - - def test_enter_pdb_hook_is_called(self, testdir): - testdir.makeconftest( - """ - def pytest_enter_pdb(config): - assert config.testing_verification == 'configured' - print 'enter_pdb_hook' - - def pytest_configure(config): - config.testing_verification = 'configured' - """ - ) - p1 = testdir.makepyfile( - """ - import pytest - - def test_foo(): - pytest.set_trace() - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("enter_pdb_hook") - child.send("c\n") - child.sendeof() - self.flush(child) - - def test_pdb_custom_cls(self, testdir, custom_pdb_calls): - p1 = testdir.makepyfile("""xxx """) - result = testdir.runpytest_inprocess("--pdb", "--pdbcls=_pytest:_CustomPdb", p1) - result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"]) - assert custom_pdb_calls == ["init", "reset", "interaction"] - - def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls): - p1 = testdir.makepyfile("""xxx """) - result = testdir.runpytest_inprocess("--pdbcls=_pytest:_CustomPdb", p1) - result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"]) - assert custom_pdb_calls == [] - - def test_pdb_custom_cls_with_settrace(self, testdir, monkeypatch): - testdir.makepyfile( - custom_pdb=""" - class CustomPdb(object): - def set_trace(*args, **kwargs): - print 'custom set_trace>' - """ - ) - p1 = testdir.makepyfile( - """ - import pytest - - def test_foo(): - pytest.set_trace() - """ - ) - monkeypatch.setenv("PYTHONPATH", str(testdir.tmpdir)) - child = testdir.spawn_pytest("--pdbcls=custom_pdb:CustomPdb %s" % str(p1)) - - child.expect("custom set_trace>") - self.flush(child) - - -class TestDebuggingBreakpoints(object): - - def test_supports_breakpoint_module_global(self): - """ - Test that supports breakpoint global marks on Python 3.7+ and not on - CPython 3.5, 2.7 - """ - if sys.version_info.major == 3 and sys.version_info.minor >= 7: - assert SUPPORTS_BREAKPOINT_BUILTIN is True - if sys.version_info.major == 3 and sys.version_info.minor == 5: - assert SUPPORTS_BREAKPOINT_BUILTIN is False - if sys.version_info.major == 2 and sys.version_info.minor == 7: - assert SUPPORTS_BREAKPOINT_BUILTIN is False - - @pytest.mark.skipif( - not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin" - ) - @pytest.mark.parametrize("arg", ["--pdb", ""]) - def test_sys_breakpointhook_configure_and_unconfigure(self, testdir, arg): - """ - Test that sys.breakpointhook is set to the custom Pdb class once configured, test that - hook is reset to system value once pytest has been unconfigured - """ - testdir.makeconftest( - """ - import sys - from pytest import hookimpl - from _pytest.debugging import pytestPDB - - def pytest_configure(config): - config._cleanup.append(check_restored) - - def check_restored(): - assert sys.breakpointhook == sys.__breakpointhook__ - - def test_check(): - assert sys.breakpointhook == pytestPDB.set_trace - """ - ) - testdir.makepyfile( - """ - def test_nothing(): pass - """ - ) - args = (arg,) if arg else () - result = testdir.runpytest_subprocess(*args) - result.stdout.fnmatch_lines(["*1 passed in *"]) - - @pytest.mark.skipif( - not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin" - ) - def test_pdb_custom_cls(self, testdir, custom_debugger_hook): - p1 = testdir.makepyfile( - """ - def test_nothing(): - breakpoint() - """ - ) - result = testdir.runpytest_inprocess( - "--pdb", "--pdbcls=_pytest:_CustomDebugger", p1 - ) - result.stdout.fnmatch_lines(["*CustomDebugger*", "*1 passed*"]) - assert custom_debugger_hook == ["init", "set_trace"] - - @pytest.mark.parametrize("arg", ["--pdb", ""]) - @pytest.mark.skipif( - not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin" - ) - def test_environ_custom_class(self, testdir, custom_debugger_hook, arg): - testdir.makeconftest( - """ - import os - import sys - - os.environ['PYTHONBREAKPOINT'] = '_pytest._CustomDebugger.set_trace' - - def pytest_configure(config): - config._cleanup.append(check_restored) - - def check_restored(): - assert sys.breakpointhook == sys.__breakpointhook__ - - def test_check(): - import _pytest - assert sys.breakpointhook is _pytest._CustomDebugger.set_trace - """ - ) - testdir.makepyfile( - """ - def test_nothing(): pass - """ - ) - args = (arg,) if arg else () - result = testdir.runpytest_subprocess(*args) - result.stdout.fnmatch_lines(["*1 passed in *"]) - - @pytest.mark.skipif( - not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin" - ) - @pytest.mark.skipif( - not _ENVIRON_PYTHONBREAKPOINT == "", - reason="Requires breakpoint() default value", - ) - def test_sys_breakpoint_interception(self, testdir): - p1 = testdir.makepyfile( - """ - def test_1(): - breakpoint() - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "reading from stdin while output" not in rest - TestPDB.flush(child) - - @pytest.mark.skipif( - not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin" - ) - def test_pdb_not_altered(self, testdir): - p1 = testdir.makepyfile( - """ - import pdb - def test_1(): - pdb.set_trace() - """ - ) - child = testdir.spawn_pytest(str(p1)) - child.expect("test_1") - child.expect("(Pdb)") - child.sendeof() - rest = child.read().decode("utf8") - assert "1 failed" in rest - assert "reading from stdin while output" not in rest - TestPDB.flush(child) diff --git a/third_party/python/pytest/testing/test_pluginmanager.py b/third_party/python/pytest/testing/test_pluginmanager.py deleted file mode 100644 index 22cea4207c64..000000000000 --- a/third_party/python/pytest/testing/test_pluginmanager.py +++ /dev/null @@ -1,386 +0,0 @@ -# encoding: UTF-8 -from __future__ import absolute_import, division, print_function -import pytest -import os -import re -import sys -import types - -from _pytest.config import get_config, PytestPluginManager -from _pytest.main import EXIT_NOTESTSCOLLECTED, Session - - -@pytest.fixture -def pytestpm(): - return PytestPluginManager() - - -class TestPytestPluginInteractions(object): - - def test_addhooks_conftestplugin(self, testdir): - testdir.makepyfile( - newhooks=""" - def pytest_myhook(xyz): - "new hook" - """ - ) - conf = testdir.makeconftest( - """ - import sys ; sys.path.insert(0, '.') - import newhooks - def pytest_addhooks(pluginmanager): - pluginmanager.addhooks(newhooks) - def pytest_myhook(xyz): - return xyz + 1 - """ - ) - config = get_config() - pm = config.pluginmanager - pm.hook.pytest_addhooks.call_historic( - kwargs=dict(pluginmanager=config.pluginmanager) - ) - config.pluginmanager._importconftest(conf) - # print(config.pluginmanager.get_plugins()) - res = config.hook.pytest_myhook(xyz=10) - assert res == [11] - - def test_addhooks_nohooks(self, testdir): - testdir.makeconftest( - """ - import sys - def pytest_addhooks(pluginmanager): - pluginmanager.addhooks(sys) - """ - ) - res = testdir.runpytest() - assert res.ret != 0 - res.stderr.fnmatch_lines(["*did not find*sys*"]) - - def test_namespace_early_from_import(self, testdir): - p = testdir.makepyfile( - """ - from pytest import Item - from pytest import Item as Item2 - assert Item is Item2 - """ - ) - result = testdir.runpython(p) - assert result.ret == 0 - - def test_do_ext_namespace(self, testdir): - testdir.makeconftest( - """ - def pytest_namespace(): - return {'hello': 'world'} - """ - ) - p = testdir.makepyfile( - """ - from pytest import hello - import pytest - def test_hello(): - assert hello == "world" - assert 'hello' in pytest.__all__ - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(passed=1) - - def test_do_option_postinitialize(self, testdir): - config = testdir.parseconfigure() - assert not hasattr(config.option, "test123") - p = testdir.makepyfile( - """ - def pytest_addoption(parser): - parser.addoption('--test123', action="store_true", - default=True) - """ - ) - config.pluginmanager._importconftest(p) - assert config.option.test123 - - def test_configure(self, testdir): - config = testdir.parseconfig() - values = [] - - class A(object): - - def pytest_configure(self, config): - values.append(self) - - config.pluginmanager.register(A()) - assert len(values) == 0 - config._do_configure() - assert len(values) == 1 - config.pluginmanager.register(A()) # leads to a configured() plugin - assert len(values) == 2 - assert values[0] != values[1] - - config._ensure_unconfigure() - config.pluginmanager.register(A()) - assert len(values) == 2 - - def test_hook_tracing(self): - pytestpm = get_config().pluginmanager # fully initialized with plugins - saveindent = [] - - class api1(object): - - def pytest_plugin_registered(self): - saveindent.append(pytestpm.trace.root.indent) - - class api2(object): - - def pytest_plugin_registered(self): - saveindent.append(pytestpm.trace.root.indent) - raise ValueError() - - values = [] - pytestpm.trace.root.setwriter(values.append) - undo = pytestpm.enable_tracing() - try: - indent = pytestpm.trace.root.indent - p = api1() - pytestpm.register(p) - assert pytestpm.trace.root.indent == indent - assert len(values) >= 2 - assert "pytest_plugin_registered" in values[0] - assert "finish" in values[1] - - values[:] = [] - with pytest.raises(ValueError): - pytestpm.register(api2()) - assert pytestpm.trace.root.indent == indent - assert saveindent[0] > indent - finally: - undo() - - def test_hook_proxy(self, testdir): - """Test the gethookproxy function(#2016)""" - config = testdir.parseconfig() - session = Session(config) - testdir.makepyfile(**{"tests/conftest.py": "", "tests/subdir/conftest.py": ""}) - - conftest1 = testdir.tmpdir.join("tests/conftest.py") - conftest2 = testdir.tmpdir.join("tests/subdir/conftest.py") - - config.pluginmanager._importconftest(conftest1) - ihook_a = session.gethookproxy(testdir.tmpdir.join("tests")) - assert ihook_a is not None - config.pluginmanager._importconftest(conftest2) - ihook_b = session.gethookproxy(testdir.tmpdir.join("tests")) - assert ihook_a is not ihook_b - - def test_warn_on_deprecated_addhooks(self, pytestpm): - warnings = [] - - class get_warnings(object): - - def pytest_logwarning(self, code, fslocation, message, nodeid): - warnings.append(message) - - class Plugin(object): - - def pytest_testhook(): - pass - - pytestpm.register(get_warnings()) - before = list(warnings) - pytestpm.addhooks(Plugin()) - assert len(warnings) == len(before) + 1 - assert "deprecated" in warnings[-1] - - -def test_namespace_has_default_and_env_plugins(testdir): - p = testdir.makepyfile( - """ - import pytest - pytest.mark - """ - ) - result = testdir.runpython(p) - assert result.ret == 0 - - -def test_default_markers(testdir): - result = testdir.runpytest("--markers") - result.stdout.fnmatch_lines(["*tryfirst*first*", "*trylast*last*"]) - - -def test_importplugin_error_message(testdir, pytestpm): - """Don't hide import errors when importing plugins and provide - an easy to debug message. - - See #375 and #1998. - """ - testdir.syspathinsert(testdir.tmpdir) - testdir.makepyfile( - qwe=""" - # encoding: UTF-8 - def test_traceback(): - raise ImportError(u'Not possible to import: ☺') - test_traceback() - """ - ) - with pytest.raises(ImportError) as excinfo: - pytestpm.import_plugin("qwe") - - expected_message = '.*Error importing plugin "qwe": Not possible to import: .' - expected_traceback = ".*in test_traceback" - assert re.match(expected_message, str(excinfo.value)) - assert re.match(expected_traceback, str(excinfo.traceback[-1])) - - -class TestPytestPluginManager(object): - - def test_register_imported_modules(self): - pm = PytestPluginManager() - mod = types.ModuleType("x.y.pytest_hello") - pm.register(mod) - assert pm.is_registered(mod) - values = pm.get_plugins() - assert mod in values - pytest.raises(ValueError, "pm.register(mod)") - pytest.raises(ValueError, lambda: pm.register(mod)) - # assert not pm.is_registered(mod2) - assert pm.get_plugins() == values - - def test_canonical_import(self, monkeypatch): - mod = types.ModuleType("pytest_xyz") - monkeypatch.setitem(sys.modules, "pytest_xyz", mod) - pm = PytestPluginManager() - pm.import_plugin("pytest_xyz") - assert pm.get_plugin("pytest_xyz") == mod - assert pm.is_registered(mod) - - def test_consider_module(self, testdir, pytestpm): - testdir.syspathinsert() - testdir.makepyfile(pytest_p1="#") - testdir.makepyfile(pytest_p2="#") - mod = types.ModuleType("temp") - mod.pytest_plugins = ["pytest_p1", "pytest_p2"] - pytestpm.consider_module(mod) - assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1" - assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2" - - def test_consider_module_import_module(self, testdir): - pytestpm = get_config().pluginmanager - mod = types.ModuleType("x") - mod.pytest_plugins = "pytest_a" - aplugin = testdir.makepyfile(pytest_a="#") - reprec = testdir.make_hook_recorder(pytestpm) - # syspath.prepend(aplugin.dirpath()) - sys.path.insert(0, str(aplugin.dirpath())) - pytestpm.consider_module(mod) - call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name) - assert call.plugin.__name__ == "pytest_a" - - # check that it is not registered twice - pytestpm.consider_module(mod) - values = reprec.getcalls("pytest_plugin_registered") - assert len(values) == 1 - - def test_consider_env_fails_to_import(self, monkeypatch, pytestpm): - monkeypatch.setenv("PYTEST_PLUGINS", "nonexisting", prepend=",") - with pytest.raises(ImportError): - pytestpm.consider_env() - - def test_plugin_skip(self, testdir, monkeypatch): - p = testdir.makepyfile( - skipping1=""" - import pytest - pytest.skip("hello") - """ - ) - p.copy(p.dirpath("skipping2.py")) - monkeypatch.setenv("PYTEST_PLUGINS", "skipping2") - result = testdir.runpytest("-rw", "-p", "skipping1", syspathinsert=True) - assert result.ret == EXIT_NOTESTSCOLLECTED - result.stdout.fnmatch_lines( - ["*skipped plugin*skipping1*hello*", "*skipped plugin*skipping2*hello*"] - ) - - def test_consider_env_plugin_instantiation(self, testdir, monkeypatch, pytestpm): - testdir.syspathinsert() - testdir.makepyfile(xy123="#") - monkeypatch.setitem(os.environ, "PYTEST_PLUGINS", "xy123") - l1 = len(pytestpm.get_plugins()) - pytestpm.consider_env() - l2 = len(pytestpm.get_plugins()) - assert l2 == l1 + 1 - assert pytestpm.get_plugin("xy123") - pytestpm.consider_env() - l3 = len(pytestpm.get_plugins()) - assert l2 == l3 - - def test_pluginmanager_ENV_startup(self, testdir, monkeypatch): - testdir.makepyfile(pytest_x500="#") - p = testdir.makepyfile( - """ - import pytest - def test_hello(pytestconfig): - plugin = pytestconfig.pluginmanager.get_plugin('pytest_x500') - assert plugin is not None - """ - ) - monkeypatch.setenv("PYTEST_PLUGINS", "pytest_x500", prepend=",") - result = testdir.runpytest(p, syspathinsert=True) - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - def test_import_plugin_importname(self, testdir, pytestpm): - pytest.raises(ImportError, 'pytestpm.import_plugin("qweqwex.y")') - pytest.raises(ImportError, 'pytestpm.import_plugin("pytest_qweqwx.y")') - - testdir.syspathinsert() - pluginname = "pytest_hello" - testdir.makepyfile(**{pluginname: ""}) - pytestpm.import_plugin("pytest_hello") - len1 = len(pytestpm.get_plugins()) - pytestpm.import_plugin("pytest_hello") - len2 = len(pytestpm.get_plugins()) - assert len1 == len2 - plugin1 = pytestpm.get_plugin("pytest_hello") - assert plugin1.__name__.endswith("pytest_hello") - plugin2 = pytestpm.get_plugin("pytest_hello") - assert plugin2 is plugin1 - - def test_import_plugin_dotted_name(self, testdir, pytestpm): - pytest.raises(ImportError, 'pytestpm.import_plugin("qweqwex.y")') - pytest.raises(ImportError, 'pytestpm.import_plugin("pytest_qweqwex.y")') - - testdir.syspathinsert() - testdir.mkpydir("pkg").join("plug.py").write("x=3") - pluginname = "pkg.plug" - pytestpm.import_plugin(pluginname) - mod = pytestpm.get_plugin("pkg.plug") - assert mod.x == 3 - - def test_consider_conftest_deps(self, testdir, pytestpm): - mod = testdir.makepyfile("pytest_plugins='xyz'").pyimport() - with pytest.raises(ImportError): - pytestpm.consider_conftest(mod) - - -class TestPytestPluginManagerBootstrapming(object): - - def test_preparse_args(self, pytestpm): - pytest.raises( - ImportError, lambda: pytestpm.consider_preparse(["xyz", "-p", "hello123"]) - ) - - def test_plugin_prevent_register(self, pytestpm): - pytestpm.consider_preparse(["xyz", "-p", "no:abc"]) - l1 = pytestpm.get_plugins() - pytestpm.register(42, name="abc") - l2 = pytestpm.get_plugins() - assert len(l2) == len(l1) - assert 42 not in l2 - - def test_plugin_prevent_register_unregistered_alredy_registered(self, pytestpm): - pytestpm.register(42, name="abc") - l1 = pytestpm.get_plugins() - assert 42 in l1 - pytestpm.consider_preparse(["xyz", "-p", "no:abc"]) - l2 = pytestpm.get_plugins() - assert 42 not in l2 diff --git a/third_party/python/pytest/testing/test_pytester.py b/third_party/python/pytest/testing/test_pytester.py deleted file mode 100644 index b74c0b7f70c2..000000000000 --- a/third_party/python/pytest/testing/test_pytester.py +++ /dev/null @@ -1,401 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function -import os -import py.path -import pytest -import sys -import _pytest.pytester as pytester -from _pytest.pytester import HookRecorder -from _pytest.pytester import CwdSnapshot, SysModulesSnapshot, SysPathsSnapshot -from _pytest.config import PytestPluginManager -from _pytest.main import EXIT_OK, EXIT_TESTSFAILED - - -def test_make_hook_recorder(testdir): - item = testdir.getitem("def test_func(): pass") - recorder = testdir.make_hook_recorder(item.config.pluginmanager) - assert not recorder.getfailures() - - pytest.xfail("internal reportrecorder tests need refactoring") - - class rep(object): - excinfo = None - passed = False - failed = True - skipped = False - when = "call" - - recorder.hook.pytest_runtest_logreport(report=rep) - failures = recorder.getfailures() - assert failures == [rep] - failures = recorder.getfailures() - assert failures == [rep] - - class rep(object): - excinfo = None - passed = False - failed = False - skipped = True - when = "call" - - rep.passed = False - rep.skipped = True - recorder.hook.pytest_runtest_logreport(report=rep) - - modcol = testdir.getmodulecol("") - rep = modcol.config.hook.pytest_make_collect_report(collector=modcol) - rep.passed = False - rep.failed = True - rep.skipped = False - recorder.hook.pytest_collectreport(report=rep) - - passed, skipped, failed = recorder.listoutcomes() - assert not passed and skipped and failed - - numpassed, numskipped, numfailed = recorder.countoutcomes() - assert numpassed == 0 - assert numskipped == 1 - assert numfailed == 1 - assert len(recorder.getfailedcollections()) == 1 - - recorder.unregister() - recorder.clear() - recorder.hook.pytest_runtest_logreport(report=rep) - pytest.raises(ValueError, "recorder.getfailures()") - - -def test_parseconfig(testdir): - config1 = testdir.parseconfig() - config2 = testdir.parseconfig() - assert config2 != config1 - assert config1 != pytest.config - - -def test_testdir_runs_with_plugin(testdir): - testdir.makepyfile( - """ - pytest_plugins = "pytester" - def test_hello(testdir): - assert 1 - """ - ) - result = testdir.runpytest() - result.assert_outcomes(passed=1) - - -def make_holder(): - - class apiclass(object): - - def pytest_xyz(self, arg): - "x" - - def pytest_xyz_noarg(self): - "x" - - apimod = type(os)("api") - - def pytest_xyz(arg): - "x" - - def pytest_xyz_noarg(): - "x" - - apimod.pytest_xyz = pytest_xyz - apimod.pytest_xyz_noarg = pytest_xyz_noarg - return apiclass, apimod - - -@pytest.mark.parametrize("holder", make_holder()) -def test_hookrecorder_basic(holder): - pm = PytestPluginManager() - pm.addhooks(holder) - rec = HookRecorder(pm) - pm.hook.pytest_xyz(arg=123) - call = rec.popcall("pytest_xyz") - assert call.arg == 123 - assert call._name == "pytest_xyz" - pytest.raises(pytest.fail.Exception, "rec.popcall('abc')") - pm.hook.pytest_xyz_noarg() - call = rec.popcall("pytest_xyz_noarg") - assert call._name == "pytest_xyz_noarg" - - -def test_makepyfile_unicode(testdir): - global unichr - try: - unichr(65) - except NameError: - unichr = chr - testdir.makepyfile(unichr(0xfffd)) - - -def test_makepyfile_utf8(testdir): - """Ensure makepyfile accepts utf-8 bytes as input (#2738)""" - utf8_contents = u""" - def setup_function(function): - mixed_encoding = u'São Paulo' - """.encode( - "utf-8" - ) - p = testdir.makepyfile(utf8_contents) - assert u"mixed_encoding = u'São Paulo'".encode("utf-8") in p.read("rb") - - -class TestInlineRunModulesCleanup(object): - - def test_inline_run_test_module_not_cleaned_up(self, testdir): - test_mod = testdir.makepyfile("def test_foo(): assert True") - result = testdir.inline_run(str(test_mod)) - assert result.ret == EXIT_OK - # rewrite module, now test should fail if module was re-imported - test_mod.write("def test_foo(): assert False") - result2 = testdir.inline_run(str(test_mod)) - assert result2.ret == EXIT_TESTSFAILED - - def spy_factory(self): - - class SysModulesSnapshotSpy(object): - instances = [] - - def __init__(self, preserve=None): - SysModulesSnapshotSpy.instances.append(self) - self._spy_restore_count = 0 - self._spy_preserve = preserve - self.__snapshot = SysModulesSnapshot(preserve=preserve) - - def restore(self): - self._spy_restore_count += 1 - return self.__snapshot.restore() - - return SysModulesSnapshotSpy - - def test_inline_run_taking_and_restoring_a_sys_modules_snapshot( - self, testdir, monkeypatch - ): - spy_factory = self.spy_factory() - monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory) - original = dict(sys.modules) - testdir.syspathinsert() - testdir.makepyfile(import1="# you son of a silly person") - testdir.makepyfile(import2="# my hovercraft is full of eels") - test_mod = testdir.makepyfile( - """ - import import1 - def test_foo(): import import2""" - ) - testdir.inline_run(str(test_mod)) - assert len(spy_factory.instances) == 1 - spy = spy_factory.instances[0] - assert spy._spy_restore_count == 1 - assert sys.modules == original - assert all(sys.modules[x] is original[x] for x in sys.modules) - - def test_inline_run_sys_modules_snapshot_restore_preserving_modules( - self, testdir, monkeypatch - ): - spy_factory = self.spy_factory() - monkeypatch.setattr(pytester, "SysModulesSnapshot", spy_factory) - test_mod = testdir.makepyfile("def test_foo(): pass") - testdir.inline_run(str(test_mod)) - spy = spy_factory.instances[0] - assert not spy._spy_preserve("black_knight") - assert spy._spy_preserve("zope") - assert spy._spy_preserve("zope.interface") - assert spy._spy_preserve("zopelicious") - - def test_external_test_module_imports_not_cleaned_up(self, testdir): - testdir.syspathinsert() - testdir.makepyfile(imported="data = 'you son of a silly person'") - import imported - - test_mod = testdir.makepyfile( - """ - def test_foo(): - import imported - imported.data = 42""" - ) - testdir.inline_run(str(test_mod)) - assert imported.data == 42 - - -def test_inline_run_clean_sys_paths(testdir): - - def test_sys_path_change_cleanup(self, testdir): - test_path1 = testdir.tmpdir.join("boink1").strpath - test_path2 = testdir.tmpdir.join("boink2").strpath - test_path3 = testdir.tmpdir.join("boink3").strpath - sys.path.append(test_path1) - sys.meta_path.append(test_path1) - original_path = list(sys.path) - original_meta_path = list(sys.meta_path) - test_mod = testdir.makepyfile( - """ - import sys - sys.path.append({:test_path2}) - sys.meta_path.append({:test_path2}) - def test_foo(): - sys.path.append({:test_path3}) - sys.meta_path.append({:test_path3})""".format( - locals() - ) - ) - testdir.inline_run(str(test_mod)) - assert sys.path == original_path - assert sys.meta_path == original_meta_path - - def spy_factory(self): - - class SysPathsSnapshotSpy(object): - instances = [] - - def __init__(self): - SysPathsSnapshotSpy.instances.append(self) - self._spy_restore_count = 0 - self.__snapshot = SysPathsSnapshot() - - def restore(self): - self._spy_restore_count += 1 - return self.__snapshot.restore() - - return SysPathsSnapshotSpy - - def test_inline_run_taking_and_restoring_a_sys_paths_snapshot( - self, testdir, monkeypatch - ): - spy_factory = self.spy_factory() - monkeypatch.setattr(pytester, "SysPathsSnapshot", spy_factory) - test_mod = testdir.makepyfile("def test_foo(): pass") - testdir.inline_run(str(test_mod)) - assert len(spy_factory.instances) == 1 - spy = spy_factory.instances[0] - assert spy._spy_restore_count == 1 - - -def test_assert_outcomes_after_pytest_error(testdir): - testdir.makepyfile("def test_foo(): assert True") - - result = testdir.runpytest("--unexpected-argument") - with pytest.raises(ValueError, message="Pytest terminal report not found"): - result.assert_outcomes(passed=0) - - -def test_cwd_snapshot(tmpdir): - foo = tmpdir.ensure("foo", dir=1) - bar = tmpdir.ensure("bar", dir=1) - foo.chdir() - snapshot = CwdSnapshot() - bar.chdir() - assert py.path.local() == bar - snapshot.restore() - assert py.path.local() == foo - - -class TestSysModulesSnapshot(object): - key = "my-test-module" - - def test_remove_added(self): - original = dict(sys.modules) - assert self.key not in sys.modules - snapshot = SysModulesSnapshot() - sys.modules[self.key] = "something" - assert self.key in sys.modules - snapshot.restore() - assert sys.modules == original - - def test_add_removed(self, monkeypatch): - assert self.key not in sys.modules - monkeypatch.setitem(sys.modules, self.key, "something") - assert self.key in sys.modules - original = dict(sys.modules) - snapshot = SysModulesSnapshot() - del sys.modules[self.key] - assert self.key not in sys.modules - snapshot.restore() - assert sys.modules == original - - def test_restore_reloaded(self, monkeypatch): - assert self.key not in sys.modules - monkeypatch.setitem(sys.modules, self.key, "something") - assert self.key in sys.modules - original = dict(sys.modules) - snapshot = SysModulesSnapshot() - sys.modules[self.key] = "something else" - snapshot.restore() - assert sys.modules == original - - def test_preserve_modules(self, monkeypatch): - key = [self.key + str(i) for i in range(3)] - assert not any(k in sys.modules for k in key) - for i, k in enumerate(key): - monkeypatch.setitem(sys.modules, k, "something" + str(i)) - original = dict(sys.modules) - - def preserve(name): - return name in (key[0], key[1], "some-other-key") - - snapshot = SysModulesSnapshot(preserve=preserve) - sys.modules[key[0]] = original[key[0]] = "something else0" - sys.modules[key[1]] = original[key[1]] = "something else1" - sys.modules[key[2]] = "something else2" - snapshot.restore() - assert sys.modules == original - - def test_preserve_container(self, monkeypatch): - original = dict(sys.modules) - assert self.key not in original - replacement = dict(sys.modules) - replacement[self.key] = "life of brian" - snapshot = SysModulesSnapshot() - monkeypatch.setattr(sys, "modules", replacement) - snapshot.restore() - assert sys.modules is replacement - assert sys.modules == original - - -@pytest.mark.parametrize("path_type", ("path", "meta_path")) -class TestSysPathsSnapshot(object): - other_path = {"path": "meta_path", "meta_path": "path"} - - @staticmethod - def path(n): - return "my-dirty-little-secret-" + str(n) - - def test_restore(self, monkeypatch, path_type): - other_path_type = self.other_path[path_type] - for i in range(10): - assert self.path(i) not in getattr(sys, path_type) - sys_path = [self.path(i) for i in range(6)] - monkeypatch.setattr(sys, path_type, sys_path) - original = list(sys_path) - original_other = list(getattr(sys, other_path_type)) - snapshot = SysPathsSnapshot() - transformation = { - "source": (0, 1, 2, 3, 4, 5), "target": (6, 2, 9, 7, 5, 8) - } # noqa: E201 - assert sys_path == [self.path(x) for x in transformation["source"]] - sys_path[1] = self.path(6) - sys_path[3] = self.path(7) - sys_path.append(self.path(8)) - del sys_path[4] - sys_path[3:3] = [self.path(9)] - del sys_path[0] - assert sys_path == [self.path(x) for x in transformation["target"]] - snapshot.restore() - assert getattr(sys, path_type) is sys_path - assert getattr(sys, path_type) == original - assert getattr(sys, other_path_type) == original_other - - def test_preserve_container(self, monkeypatch, path_type): - other_path_type = self.other_path[path_type] - original_data = list(getattr(sys, path_type)) - original_other = getattr(sys, other_path_type) - original_other_data = list(original_other) - new = [] - snapshot = SysPathsSnapshot() - monkeypatch.setattr(sys, path_type, new) - snapshot.restore() - assert getattr(sys, path_type) is new - assert getattr(sys, path_type) == original_data - assert getattr(sys, other_path_type) is original_other - assert getattr(sys, other_path_type) == original_other_data diff --git a/third_party/python/pytest/testing/test_recwarn.py b/third_party/python/pytest/testing/test_recwarn.py deleted file mode 100644 index a8e2fb803780..000000000000 --- a/third_party/python/pytest/testing/test_recwarn.py +++ /dev/null @@ -1,347 +0,0 @@ -from __future__ import absolute_import, division, print_function -import warnings -import re - -import pytest -from _pytest.recwarn import WarningsRecorder - - -def test_recwarn_functional(testdir): - reprec = testdir.inline_runsource( - """ - import warnings - def test_method(recwarn): - warnings.warn("hello") - warn = recwarn.pop() - assert isinstance(warn.message, UserWarning) - """ - ) - res = reprec.countoutcomes() - assert tuple(res) == (1, 0, 0), res - - -class TestWarningsRecorderChecker(object): - - def test_recording(self): - rec = WarningsRecorder() - with rec: - assert not rec.list - warnings.warn_explicit("hello", UserWarning, "xyz", 13) - assert len(rec.list) == 1 - warnings.warn(DeprecationWarning("hello")) - assert len(rec.list) == 2 - warn = rec.pop() - assert str(warn.message) == "hello" - values = rec.list - rec.clear() - assert len(rec.list) == 0 - assert values is rec.list - pytest.raises(AssertionError, "rec.pop()") - - def test_typechecking(self): - from _pytest.recwarn import WarningsChecker - - with pytest.raises(TypeError): - WarningsChecker(5) - with pytest.raises(TypeError): - WarningsChecker(("hi", RuntimeWarning)) - with pytest.raises(TypeError): - WarningsChecker([DeprecationWarning, RuntimeWarning]) - - def test_invalid_enter_exit(self): - # wrap this test in WarningsRecorder to ensure warning state gets reset - with WarningsRecorder(): - with pytest.raises(RuntimeError): - rec = WarningsRecorder() - rec.__exit__(None, None, None) # can't exit before entering - - with pytest.raises(RuntimeError): - rec = WarningsRecorder() - with rec: - with rec: - pass # can't enter twice - - -class TestDeprecatedCall(object): - """test pytest.deprecated_call()""" - - def dep(self, i, j=None): - if i == 0: - warnings.warn("is deprecated", DeprecationWarning, stacklevel=1) - return 42 - - def dep_explicit(self, i): - if i == 0: - warnings.warn_explicit( - "dep_explicit", category=DeprecationWarning, filename="hello", lineno=3 - ) - - def test_deprecated_call_raises(self): - with pytest.raises(AssertionError) as excinfo: - pytest.deprecated_call(self.dep, 3, 5) - assert "Did not produce" in str(excinfo) - - def test_deprecated_call(self): - pytest.deprecated_call(self.dep, 0, 5) - - def test_deprecated_call_ret(self): - ret = pytest.deprecated_call(self.dep, 0) - assert ret == 42 - - def test_deprecated_call_preserves(self): - onceregistry = warnings.onceregistry.copy() - filters = warnings.filters[:] - warn = warnings.warn - warn_explicit = warnings.warn_explicit - self.test_deprecated_call_raises() - self.test_deprecated_call() - assert onceregistry == warnings.onceregistry - assert filters == warnings.filters - assert warn is warnings.warn - assert warn_explicit is warnings.warn_explicit - - def test_deprecated_explicit_call_raises(self): - with pytest.raises(AssertionError): - pytest.deprecated_call(self.dep_explicit, 3) - - def test_deprecated_explicit_call(self): - pytest.deprecated_call(self.dep_explicit, 0) - pytest.deprecated_call(self.dep_explicit, 0) - - @pytest.mark.parametrize("mode", ["context_manager", "call"]) - def test_deprecated_call_no_warning(self, mode): - """Ensure deprecated_call() raises the expected failure when its block/function does - not raise a deprecation warning. - """ - - def f(): - pass - - msg = "Did not produce DeprecationWarning or PendingDeprecationWarning" - with pytest.raises(AssertionError, match=msg): - if mode == "call": - pytest.deprecated_call(f) - else: - with pytest.deprecated_call(): - f() - - @pytest.mark.parametrize( - "warning_type", [PendingDeprecationWarning, DeprecationWarning] - ) - @pytest.mark.parametrize("mode", ["context_manager", "call"]) - @pytest.mark.parametrize("call_f_first", [True, False]) - @pytest.mark.filterwarnings("ignore") - def test_deprecated_call_modes(self, warning_type, mode, call_f_first): - """Ensure deprecated_call() captures a deprecation warning as expected inside its - block/function. - """ - - def f(): - warnings.warn(warning_type("hi")) - return 10 - - # ensure deprecated_call() can capture the warning even if it has already been triggered - if call_f_first: - assert f() == 10 - if mode == "call": - assert pytest.deprecated_call(f) == 10 - else: - with pytest.deprecated_call(): - assert f() == 10 - - @pytest.mark.parametrize("mode", ["context_manager", "call"]) - def test_deprecated_call_exception_is_raised(self, mode): - """If the block of the code being tested by deprecated_call() raises an exception, - it must raise the exception undisturbed. - """ - - def f(): - raise ValueError("some exception") - - with pytest.raises(ValueError, match="some exception"): - if mode == "call": - pytest.deprecated_call(f) - else: - with pytest.deprecated_call(): - f() - - def test_deprecated_call_specificity(self): - other_warnings = [ - Warning, - UserWarning, - SyntaxWarning, - RuntimeWarning, - FutureWarning, - ImportWarning, - UnicodeWarning, - ] - for warning in other_warnings: - - def f(): - warnings.warn(warning("hi")) - - with pytest.raises(AssertionError): - pytest.deprecated_call(f) - with pytest.raises(AssertionError): - with pytest.deprecated_call(): - f() - - -class TestWarns(object): - - def test_strings(self): - # different messages, b/c Python suppresses multiple identical warnings - source1 = "warnings.warn('w1', RuntimeWarning)" - source2 = "warnings.warn('w2', RuntimeWarning)" - source3 = "warnings.warn('w3', RuntimeWarning)" - pytest.warns(RuntimeWarning, source1) - pytest.raises(pytest.fail.Exception, lambda: pytest.warns(UserWarning, source2)) - pytest.warns(RuntimeWarning, source3) - - def test_function(self): - pytest.warns( - SyntaxWarning, lambda msg: warnings.warn(msg, SyntaxWarning), "syntax" - ) - - def test_warning_tuple(self): - pytest.warns( - (RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w1", RuntimeWarning) - ) - pytest.warns( - (RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning) - ) - pytest.raises( - pytest.fail.Exception, - lambda: pytest.warns( - (RuntimeWarning, SyntaxWarning), - lambda: warnings.warn("w3", UserWarning), - ), - ) - - def test_as_contextmanager(self): - with pytest.warns(RuntimeWarning): - warnings.warn("runtime", RuntimeWarning) - - with pytest.warns(UserWarning): - warnings.warn("user", UserWarning) - - with pytest.raises(pytest.fail.Exception) as excinfo: - with pytest.warns(RuntimeWarning): - warnings.warn("user", UserWarning) - excinfo.match( - r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) was emitted. " - r"The list of emitted warnings is: \[UserWarning\('user',?\)\]." - ) - - with pytest.raises(pytest.fail.Exception) as excinfo: - with pytest.warns(UserWarning): - warnings.warn("runtime", RuntimeWarning) - excinfo.match( - r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " - r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)\]." - ) - - with pytest.raises(pytest.fail.Exception) as excinfo: - with pytest.warns(UserWarning): - pass - excinfo.match( - r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. " - r"The list of emitted warnings is: \[\]." - ) - - warning_classes = (UserWarning, FutureWarning) - with pytest.raises(pytest.fail.Exception) as excinfo: - with pytest.warns(warning_classes) as warninfo: - warnings.warn("runtime", RuntimeWarning) - warnings.warn("import", ImportWarning) - - message_template = ( - "DID NOT WARN. No warnings of type {0} was emitted. " - "The list of emitted warnings is: {1}." - ) - excinfo.match( - re.escape( - message_template.format( - warning_classes, [each.message for each in warninfo] - ) - ) - ) - - def test_record(self): - with pytest.warns(UserWarning) as record: - warnings.warn("user", UserWarning) - - assert len(record) == 1 - assert str(record[0].message) == "user" - - def test_record_only(self): - with pytest.warns(None) as record: - warnings.warn("user", UserWarning) - warnings.warn("runtime", RuntimeWarning) - - assert len(record) == 2 - assert str(record[0].message) == "user" - assert str(record[1].message) == "runtime" - - def test_record_by_subclass(self): - with pytest.warns(Warning) as record: - warnings.warn("user", UserWarning) - warnings.warn("runtime", RuntimeWarning) - - assert len(record) == 2 - assert str(record[0].message) == "user" - assert str(record[1].message) == "runtime" - - class MyUserWarning(UserWarning): - pass - - class MyRuntimeWarning(RuntimeWarning): - pass - - with pytest.warns((UserWarning, RuntimeWarning)) as record: - warnings.warn("user", MyUserWarning) - warnings.warn("runtime", MyRuntimeWarning) - - assert len(record) == 2 - assert str(record[0].message) == "user" - assert str(record[1].message) == "runtime" - - def test_double_test(self, testdir): - """If a test is run again, the warning should still be raised""" - testdir.makepyfile( - """ - import pytest - import warnings - - @pytest.mark.parametrize('run', [1, 2]) - def test(run): - with pytest.warns(RuntimeWarning): - warnings.warn("runtime", RuntimeWarning) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 passed in*"]) - - def test_match_regex(self): - with pytest.warns(UserWarning, match=r"must be \d+$"): - warnings.warn("value must be 42", UserWarning) - - with pytest.raises(pytest.fail.Exception): - with pytest.warns(UserWarning, match=r"must be \d+$"): - warnings.warn("this is not here", UserWarning) - - with pytest.raises(pytest.fail.Exception): - with pytest.warns(FutureWarning, match=r"must be \d+$"): - warnings.warn("value must be 42", UserWarning) - - def test_one_from_multiple_warns(self): - with pytest.warns(UserWarning, match=r"aaa"): - warnings.warn("cccccccccc", UserWarning) - warnings.warn("bbbbbbbbbb", UserWarning) - warnings.warn("aaaaaaaaaa", UserWarning) - - def test_none_of_multiple_warns(self): - with pytest.raises(pytest.fail.Exception): - with pytest.warns(UserWarning, match=r"aaa"): - warnings.warn("bbbbbbbbbb", UserWarning) - warnings.warn("cccccccccc", UserWarning) diff --git a/third_party/python/pytest/testing/test_resultlog.py b/third_party/python/pytest/testing/test_resultlog.py deleted file mode 100644 index 173384ffb30b..000000000000 --- a/third_party/python/pytest/testing/test_resultlog.py +++ /dev/null @@ -1,243 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os - -import _pytest._code -import py -import pytest -from _pytest.nodes import Node, Item, FSCollector -from _pytest.resultlog import ( - generic_path, - ResultLog, - pytest_configure, - pytest_unconfigure, -) - - -def test_generic_path(testdir): - from _pytest.main import Session - - config = testdir.parseconfig() - session = Session(config) - p1 = Node("a", config=config, session=session, nodeid="a") - # assert p1.fspath is None - p2 = Node("B", parent=p1) - p3 = Node("()", parent=p2) - item = Item("c", parent=p3) - - res = generic_path(item) - assert res == "a.B().c" - - p0 = FSCollector("proj/test", config=config, session=session) - p1 = FSCollector("proj/test/a", parent=p0) - p2 = Node("B", parent=p1) - p3 = Node("()", parent=p2) - p4 = Node("c", parent=p3) - item = Item("[1]", parent=p4) - - res = generic_path(item) - assert res == "test/a:B().c[1]" - - -def test_write_log_entry(): - reslog = ResultLog(None, None) - reslog.logfile = py.io.TextIO() - reslog.write_log_entry("name", ".", "") - entry = reslog.logfile.getvalue() - assert entry[-1] == "\n" - entry_lines = entry.splitlines() - assert len(entry_lines) == 1 - assert entry_lines[0] == ". name" - - reslog.logfile = py.io.TextIO() - reslog.write_log_entry("name", "s", "Skipped") - entry = reslog.logfile.getvalue() - assert entry[-1] == "\n" - entry_lines = entry.splitlines() - assert len(entry_lines) == 2 - assert entry_lines[0] == "s name" - assert entry_lines[1] == " Skipped" - - reslog.logfile = py.io.TextIO() - reslog.write_log_entry("name", "s", "Skipped\n") - entry = reslog.logfile.getvalue() - assert entry[-1] == "\n" - entry_lines = entry.splitlines() - assert len(entry_lines) == 2 - assert entry_lines[0] == "s name" - assert entry_lines[1] == " Skipped" - - reslog.logfile = py.io.TextIO() - longrepr = " tb1\n tb 2\nE tb3\nSome Error" - reslog.write_log_entry("name", "F", longrepr) - entry = reslog.logfile.getvalue() - assert entry[-1] == "\n" - entry_lines = entry.splitlines() - assert len(entry_lines) == 5 - assert entry_lines[0] == "F name" - assert entry_lines[1:] == [" " + line for line in longrepr.splitlines()] - - -class TestWithFunctionIntegration(object): - # XXX (hpk) i think that the resultlog plugin should - # provide a Parser object so that one can remain - # ignorant regarding formatting details. - def getresultlog(self, testdir, arg): - resultlog = testdir.tmpdir.join("resultlog") - testdir.plugins.append("resultlog") - args = ["--resultlog=%s" % resultlog] + [arg] - testdir.runpytest(*args) - return [x for x in resultlog.readlines(cr=0) if x] - - def test_collection_report(self, testdir): - ok = testdir.makepyfile(test_collection_ok="") - fail = testdir.makepyfile(test_collection_fail="XXX") - lines = self.getresultlog(testdir, ok) - assert not lines - - lines = self.getresultlog(testdir, fail) - assert lines - assert lines[0].startswith("F ") - assert lines[0].endswith("test_collection_fail.py"), lines[0] - for x in lines[1:]: - assert x.startswith(" ") - assert "XXX" in "".join(lines[1:]) - - def test_log_test_outcomes(self, testdir): - mod = testdir.makepyfile( - test_mod=""" - import pytest - def test_pass(): pass - def test_skip(): pytest.skip("hello") - def test_fail(): raise ValueError("FAIL") - - @pytest.mark.xfail - def test_xfail(): raise ValueError("XFAIL") - @pytest.mark.xfail - def test_xpass(): pass - - """ - ) - lines = self.getresultlog(testdir, mod) - assert len(lines) >= 3 - assert lines[0].startswith(". ") - assert lines[0].endswith("test_pass") - assert lines[1].startswith("s "), lines[1] - assert lines[1].endswith("test_skip") - assert lines[2].find("hello") != -1 - - assert lines[3].startswith("F ") - assert lines[3].endswith("test_fail") - tb = "".join(lines[4:8]) - assert tb.find('raise ValueError("FAIL")') != -1 - - assert lines[8].startswith("x ") - tb = "".join(lines[8:14]) - assert tb.find('raise ValueError("XFAIL")') != -1 - - assert lines[14].startswith("X ") - assert len(lines) == 15 - - @pytest.mark.parametrize("style", ("native", "long", "short")) - def test_internal_exception(self, style): - # they are produced for example by a teardown failing - # at the end of the run or a failing hook invocation - try: - raise ValueError - except ValueError: - excinfo = _pytest._code.ExceptionInfo() - reslog = ResultLog(None, py.io.TextIO()) - reslog.pytest_internalerror(excinfo.getrepr(style=style)) - entry = reslog.logfile.getvalue() - entry_lines = entry.splitlines() - - assert entry_lines[0].startswith("! ") - if style != "native": - assert os.path.basename(__file__)[:-9] in entry_lines[0] # .pyc/class - assert entry_lines[-1][0] == " " - assert "ValueError" in entry - - -def test_generic(testdir, LineMatcher): - testdir.plugins.append("resultlog") - testdir.makepyfile( - """ - import pytest - def test_pass(): - pass - def test_fail(): - assert 0 - def test_skip(): - pytest.skip("") - @pytest.mark.xfail - def test_xfail(): - assert 0 - @pytest.mark.xfail(run=False) - def test_xfail_norun(): - assert 0 - """ - ) - testdir.runpytest("--resultlog=result.log") - lines = testdir.tmpdir.join("result.log").readlines(cr=0) - LineMatcher(lines).fnmatch_lines( - [ - ". *:test_pass", - "F *:test_fail", - "s *:test_skip", - "x *:test_xfail", - "x *:test_xfail_norun", - ] - ) - - -def test_makedir_for_resultlog(testdir, LineMatcher): - """--resultlog should automatically create directories for the log file""" - testdir.plugins.append("resultlog") - testdir.makepyfile( - """ - import pytest - def test_pass(): - pass - """ - ) - testdir.runpytest("--resultlog=path/to/result.log") - lines = testdir.tmpdir.join("path/to/result.log").readlines(cr=0) - LineMatcher(lines).fnmatch_lines([". *:test_pass"]) - - -def test_no_resultlog_on_slaves(testdir): - config = testdir.parseconfig("-p", "resultlog", "--resultlog=resultlog") - - assert not hasattr(config, "_resultlog") - pytest_configure(config) - assert hasattr(config, "_resultlog") - pytest_unconfigure(config) - assert not hasattr(config, "_resultlog") - - config.slaveinput = {} - pytest_configure(config) - assert not hasattr(config, "_resultlog") - pytest_unconfigure(config) - assert not hasattr(config, "_resultlog") - - -def test_failure_issue380(testdir): - testdir.makeconftest( - """ - import pytest - class MyCollector(pytest.File): - def collect(self): - raise ValueError() - def repr_failure(self, excinfo): - return "somestring" - def pytest_collect_file(path, parent): - return MyCollector(parent=parent, fspath=path) - """ - ) - testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - result = testdir.runpytest("--resultlog=log") - assert result.ret == 2 diff --git a/third_party/python/pytest/testing/test_runner.py b/third_party/python/pytest/testing/test_runner.py deleted file mode 100644 index f5430a90da53..000000000000 --- a/third_party/python/pytest/testing/test_runner.py +++ /dev/null @@ -1,951 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function - -import _pytest._code -import inspect -import os -import py -import pytest -import sys -import types -from _pytest import runner, main, outcomes - - -class TestSetupState(object): - - def test_setup(self, testdir): - ss = runner.SetupState() - item = testdir.getitem("def test_func(): pass") - values = [1] - ss.prepare(item) - ss.addfinalizer(values.pop, colitem=item) - assert values - ss._pop_and_teardown() - assert not values - - def test_teardown_exact_stack_empty(self, testdir): - item = testdir.getitem("def test_func(): pass") - ss = runner.SetupState() - ss.teardown_exact(item, None) - ss.teardown_exact(item, None) - ss.teardown_exact(item, None) - - def test_setup_fails_and_failure_is_cached(self, testdir): - item = testdir.getitem( - """ - def setup_module(mod): - raise ValueError(42) - def test_func(): pass - """ - ) - ss = runner.SetupState() - pytest.raises(ValueError, lambda: ss.prepare(item)) - pytest.raises(ValueError, lambda: ss.prepare(item)) - - def test_teardown_multiple_one_fails(self, testdir): - r = [] - - def fin1(): - r.append("fin1") - - def fin2(): - raise Exception("oops") - - def fin3(): - r.append("fin3") - - item = testdir.getitem("def test_func(): pass") - ss = runner.SetupState() - ss.addfinalizer(fin1, item) - ss.addfinalizer(fin2, item) - ss.addfinalizer(fin3, item) - with pytest.raises(Exception) as err: - ss._callfinalizers(item) - assert err.value.args == ("oops",) - assert r == ["fin3", "fin1"] - - def test_teardown_multiple_fail(self, testdir): - # Ensure the first exception is the one which is re-raised. - # Ideally both would be reported however. - def fin1(): - raise Exception("oops1") - - def fin2(): - raise Exception("oops2") - - item = testdir.getitem("def test_func(): pass") - ss = runner.SetupState() - ss.addfinalizer(fin1, item) - ss.addfinalizer(fin2, item) - with pytest.raises(Exception) as err: - ss._callfinalizers(item) - assert err.value.args == ("oops2",) - - def test_teardown_multiple_scopes_one_fails(self, testdir): - module_teardown = [] - - def fin_func(): - raise Exception("oops1") - - def fin_module(): - module_teardown.append("fin_module") - - item = testdir.getitem("def test_func(): pass") - ss = runner.SetupState() - ss.addfinalizer(fin_module, item.listchain()[-2]) - ss.addfinalizer(fin_func, item) - ss.prepare(item) - with pytest.raises(Exception, match="oops1"): - ss.teardown_exact(item, None) - assert module_teardown - - -class BaseFunctionalTests(object): - - def test_passfunction(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - pass - """ - ) - rep = reports[1] - assert rep.passed - assert not rep.failed - assert rep.outcome == "passed" - assert not rep.longrepr - - def test_failfunction(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - assert 0 - """ - ) - rep = reports[1] - assert not rep.passed - assert not rep.skipped - assert rep.failed - assert rep.when == "call" - assert rep.outcome == "failed" - # assert isinstance(rep.longrepr, ReprExceptionInfo) - - def test_skipfunction(self, testdir): - reports = testdir.runitem( - """ - import pytest - def test_func(): - pytest.skip("hello") - """ - ) - rep = reports[1] - assert not rep.failed - assert not rep.passed - assert rep.skipped - assert rep.outcome == "skipped" - # assert rep.skipped.when == "call" - # assert rep.skipped.when == "call" - # assert rep.skipped == "%sreason == "hello" - # assert rep.skipped.location.lineno == 3 - # assert rep.skipped.location.path - # assert not rep.skipped.failurerepr - - def test_skip_in_setup_function(self, testdir): - reports = testdir.runitem( - """ - import pytest - def setup_function(func): - pytest.skip("hello") - def test_func(): - pass - """ - ) - print(reports) - rep = reports[0] - assert not rep.failed - assert not rep.passed - assert rep.skipped - # assert rep.skipped.reason == "hello" - # assert rep.skipped.location.lineno == 3 - # assert rep.skipped.location.lineno == 3 - assert len(reports) == 2 - assert reports[1].passed # teardown - - def test_failure_in_setup_function(self, testdir): - reports = testdir.runitem( - """ - import pytest - def setup_function(func): - raise ValueError(42) - def test_func(): - pass - """ - ) - rep = reports[0] - assert not rep.skipped - assert not rep.passed - assert rep.failed - assert rep.when == "setup" - assert len(reports) == 2 - - def test_failure_in_teardown_function(self, testdir): - reports = testdir.runitem( - """ - import pytest - def teardown_function(func): - raise ValueError(42) - def test_func(): - pass - """ - ) - print(reports) - assert len(reports) == 3 - rep = reports[2] - assert not rep.skipped - assert not rep.passed - assert rep.failed - assert rep.when == "teardown" - # assert rep.longrepr.reprcrash.lineno == 3 - # assert rep.longrepr.reprtraceback.reprentries - - def test_custom_failure_repr(self, testdir): - testdir.makepyfile( - conftest=""" - import pytest - class Function(pytest.Function): - def repr_failure(self, excinfo): - return "hello" - """ - ) - reports = testdir.runitem( - """ - import pytest - def test_func(): - assert 0 - """ - ) - rep = reports[1] - assert not rep.skipped - assert not rep.passed - assert rep.failed - # assert rep.outcome.when == "call" - # assert rep.failed.where.lineno == 3 - # assert rep.failed.where.path.basename == "test_func.py" - # assert rep.failed.failurerepr == "hello" - - def test_teardown_final_returncode(self, testdir): - rec = testdir.inline_runsource( - """ - def test_func(): - pass - def teardown_function(func): - raise ValueError(42) - """ - ) - assert rec.ret == 1 - - def test_logstart_logfinish_hooks(self, testdir): - rec = testdir.inline_runsource( - """ - import pytest - def test_func(): - pass - """ - ) - reps = rec.getcalls("pytest_runtest_logstart pytest_runtest_logfinish") - assert ( - [x._name for x in reps] - == ["pytest_runtest_logstart", "pytest_runtest_logfinish"] - ) - for rep in reps: - assert rep.nodeid == "test_logstart_logfinish_hooks.py::test_func" - assert rep.location == ("test_logstart_logfinish_hooks.py", 1, "test_func") - - def test_exact_teardown_issue90(self, testdir): - rec = testdir.inline_runsource( - """ - import pytest - - class TestClass(object): - def test_method(self): - pass - def teardown_class(cls): - raise Exception() - - def test_func(): - import sys - # on python2 exc_info is keept till a function exits - # so we would end up calling test functions while - # sys.exc_info would return the indexerror - # from guessing the lastitem - excinfo = sys.exc_info() - import traceback - assert excinfo[0] is None, \ - traceback.format_exception(*excinfo) - def teardown_function(func): - raise ValueError(42) - """ - ) - reps = rec.getreports("pytest_runtest_logreport") - print(reps) - for i in range(2): - assert reps[i].nodeid.endswith("test_method") - assert reps[i].passed - assert reps[2].when == "teardown" - assert reps[2].failed - assert len(reps) == 6 - for i in range(3, 5): - assert reps[i].nodeid.endswith("test_func") - assert reps[i].passed - assert reps[5].when == "teardown" - assert reps[5].nodeid.endswith("test_func") - assert reps[5].failed - - def test_exact_teardown_issue1206(self, testdir): - """issue shadowing error with wrong number of arguments on teardown_method.""" - rec = testdir.inline_runsource( - """ - import pytest - - class TestClass(object): - def teardown_method(self, x, y, z): - pass - - def test_method(self): - assert True - """ - ) - reps = rec.getreports("pytest_runtest_logreport") - print(reps) - assert len(reps) == 3 - # - assert reps[0].nodeid.endswith("test_method") - assert reps[0].passed - assert reps[0].when == "setup" - # - assert reps[1].nodeid.endswith("test_method") - assert reps[1].passed - assert reps[1].when == "call" - # - assert reps[2].nodeid.endswith("test_method") - assert reps[2].failed - assert reps[2].when == "teardown" - assert reps[2].longrepr.reprcrash.message in ( - # python3 error - "TypeError: teardown_method() missing 2 required positional arguments: 'y' and 'z'", - # python2 error - "TypeError: teardown_method() takes exactly 4 arguments (2 given)", - ) - - def test_failure_in_setup_function_ignores_custom_repr(self, testdir): - testdir.makepyfile( - conftest=""" - import pytest - class Function(pytest.Function): - def repr_failure(self, excinfo): - assert 0 - """ - ) - reports = testdir.runitem( - """ - def setup_function(func): - raise ValueError(42) - def test_func(): - pass - """ - ) - assert len(reports) == 2 - rep = reports[0] - print(rep) - assert not rep.skipped - assert not rep.passed - assert rep.failed - # assert rep.outcome.when == "setup" - # assert rep.outcome.where.lineno == 3 - # assert rep.outcome.where.path.basename == "test_func.py" - # assert instanace(rep.failed.failurerepr, PythonFailureRepr) - - def test_systemexit_does_not_bail_out(self, testdir): - try: - reports = testdir.runitem( - """ - def test_func(): - raise SystemExit(42) - """ - ) - except SystemExit: - pytest.fail("runner did not catch SystemExit") - rep = reports[1] - assert rep.failed - assert rep.when == "call" - - def test_exit_propagates(self, testdir): - try: - testdir.runitem( - """ - import pytest - def test_func(): - raise pytest.exit.Exception() - """ - ) - except pytest.exit.Exception: - pass - else: - pytest.fail("did not raise") - - -class TestExecutionNonForked(BaseFunctionalTests): - - def getrunner(self): - - def f(item): - return runner.runtestprotocol(item, log=False) - - return f - - def test_keyboardinterrupt_propagates(self, testdir): - try: - testdir.runitem( - """ - def test_func(): - raise KeyboardInterrupt("fake") - """ - ) - except KeyboardInterrupt: - pass - else: - pytest.fail("did not raise") - - -class TestExecutionForked(BaseFunctionalTests): - pytestmark = pytest.mark.skipif("not hasattr(os, 'fork')") - - def getrunner(self): - # XXX re-arrange this test to live in pytest-xdist - boxed = pytest.importorskip("xdist.boxed") - return boxed.forked_run_report - - def test_suicide(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - import os - os.kill(os.getpid(), 15) - """ - ) - rep = reports[0] - assert rep.failed - assert rep.when == "???" - - -class TestSessionReports(object): - - def test_collect_result(self, testdir): - col = testdir.getmodulecol( - """ - def test_func1(): - pass - class TestClass(object): - pass - """ - ) - rep = runner.collect_one_node(col) - assert not rep.failed - assert not rep.skipped - assert rep.passed - locinfo = rep.location - assert locinfo[0] == col.fspath.basename - assert not locinfo[1] - assert locinfo[2] == col.fspath.basename - res = rep.result - assert len(res) == 2 - assert res[0].name == "test_func1" - assert res[1].name == "TestClass" - - -reporttypes = [ - runner.BaseReport, - runner.TestReport, - runner.TeardownErrorReport, - runner.CollectReport, -] - - -@pytest.mark.parametrize( - "reporttype", reporttypes, ids=[x.__name__ for x in reporttypes] -) -def test_report_extra_parameters(reporttype): - if hasattr(inspect, "signature"): - args = list(inspect.signature(reporttype.__init__).parameters.keys())[1:] - else: - args = inspect.getargspec(reporttype.__init__)[0][1:] - basekw = dict.fromkeys(args, []) - report = reporttype(newthing=1, **basekw) - assert report.newthing == 1 - - -def test_callinfo(): - ci = runner.CallInfo(lambda: 0, "123") - assert ci.when == "123" - assert ci.result == 0 - assert "result" in repr(ci) - ci = runner.CallInfo(lambda: 0 / 0, "123") - assert ci.when == "123" - assert not hasattr(ci, "result") - assert ci.excinfo - assert "exc" in repr(ci) - - -# design question: do we want general hooks in python files? -# then something like the following functional tests makes sense - - -@pytest.mark.xfail -def test_runtest_in_module_ordering(testdir): - p1 = testdir.makepyfile( - """ - import pytest - def pytest_runtest_setup(item): # runs after class-level! - item.function.mylist.append("module") - class TestClass(object): - def pytest_runtest_setup(self, item): - assert not hasattr(item.function, 'mylist') - item.function.mylist = ['class'] - @pytest.fixture - def mylist(self, request): - return request.function.mylist - def pytest_runtest_call(self, item, __multicall__): - try: - __multicall__.execute() - except ValueError: - pass - def test_hello1(self, mylist): - assert mylist == ['class', 'module'], mylist - raise ValueError() - def test_hello2(self, mylist): - assert mylist == ['class', 'module'], mylist - def pytest_runtest_teardown(item): - del item.function.mylist - """ - ) - result = testdir.runpytest(p1) - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_outcomeexception_exceptionattributes(): - outcome = outcomes.OutcomeException("test") - assert outcome.args[0] == outcome.msg - - -def test_outcomeexception_passes_except_Exception(): - with pytest.raises(outcomes.OutcomeException): - try: - raise outcomes.OutcomeException("test") - except Exception: - pass - - -def test_pytest_exit(): - try: - pytest.exit("hello") - except pytest.exit.Exception: - excinfo = _pytest._code.ExceptionInfo() - assert excinfo.errisinstance(KeyboardInterrupt) - - -def test_pytest_fail(): - try: - pytest.fail("hello") - except pytest.fail.Exception: - excinfo = _pytest._code.ExceptionInfo() - s = excinfo.exconly(tryshort=True) - assert s.startswith("Failed") - - -def test_pytest_exit_msg(testdir): - testdir.makeconftest( - """ - import pytest - - def pytest_configure(config): - pytest.exit('oh noes') - """ - ) - result = testdir.runpytest() - result.stderr.fnmatch_lines(["Exit: oh noes"]) - - -def test_pytest_fail_notrace(testdir): - testdir.makepyfile( - """ - import pytest - def test_hello(): - pytest.fail("hello", pytrace=False) - def teardown_function(function): - pytest.fail("world", pytrace=False) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["world", "hello"]) - assert "def teardown_function" not in result.stdout.str() - - -@pytest.mark.parametrize("str_prefix", ["u", ""]) -def test_pytest_fail_notrace_non_ascii(testdir, str_prefix): - """Fix pytest.fail with pytrace=False with non-ascii characters (#1178). - - This tests with native and unicode strings containing non-ascii chars. - """ - testdir.makepyfile( - u""" - # coding: utf-8 - import pytest - - def test_hello(): - pytest.fail(%s'oh oh: ☺', pytrace=False) - """ - % str_prefix - ) - result = testdir.runpytest() - if sys.version_info[0] >= 3: - result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"]) - else: - result.stdout.fnmatch_lines(["*test_hello*", "oh oh: *"]) - assert "def test_hello" not in result.stdout.str() - - -def test_pytest_no_tests_collected_exit_status(testdir): - result = testdir.runpytest() - result.stdout.fnmatch_lines("*collected 0 items*") - assert result.ret == main.EXIT_NOTESTSCOLLECTED - - testdir.makepyfile( - test_foo=""" - def test_foo(): - assert 1 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*collected 1 item*") - result.stdout.fnmatch_lines("*1 passed*") - assert result.ret == main.EXIT_OK - - result = testdir.runpytest("-k nonmatch") - result.stdout.fnmatch_lines("*collected 1 item*") - result.stdout.fnmatch_lines("*1 deselected*") - assert result.ret == main.EXIT_NOTESTSCOLLECTED - - -def test_exception_printing_skip(): - try: - pytest.skip("hello") - except pytest.skip.Exception: - excinfo = _pytest._code.ExceptionInfo() - s = excinfo.exconly(tryshort=True) - assert s.startswith("Skipped") - - -def test_importorskip(monkeypatch): - importorskip = pytest.importorskip - - def f(): - importorskip("asdlkj") - - try: - sysmod = importorskip("sys") - assert sysmod is sys - # path = pytest.importorskip("os.path") - # assert path == os.path - excinfo = pytest.raises(pytest.skip.Exception, f) - path = py.path.local(excinfo.getrepr().reprcrash.path) - # check that importorskip reports the actual call - # in this test the test_runner.py file - assert path.purebasename == "test_runner" - pytest.raises(SyntaxError, "pytest.importorskip('x y z')") - pytest.raises(SyntaxError, "pytest.importorskip('x=y')") - mod = types.ModuleType("hello123") - mod.__version__ = "1.3" - monkeypatch.setitem(sys.modules, "hello123", mod) - pytest.raises( - pytest.skip.Exception, - """ - pytest.importorskip("hello123", minversion="1.3.1") - """, - ) - mod2 = pytest.importorskip("hello123", minversion="1.3") - assert mod2 == mod - except pytest.skip.Exception: - print(_pytest._code.ExceptionInfo()) - pytest.fail("spurious skip") - - -def test_importorskip_imports_last_module_part(): - ospath = pytest.importorskip("os.path") - assert os.path == ospath - - -def test_importorskip_dev_module(monkeypatch): - try: - mod = types.ModuleType("mockmodule") - mod.__version__ = "0.13.0.dev-43290" - monkeypatch.setitem(sys.modules, "mockmodule", mod) - mod2 = pytest.importorskip("mockmodule", minversion="0.12.0") - assert mod2 == mod - pytest.raises( - pytest.skip.Exception, - """ - pytest.importorskip('mockmodule1', minversion='0.14.0')""", - ) - except pytest.skip.Exception: - print(_pytest._code.ExceptionInfo()) - pytest.fail("spurious skip") - - -def test_importorskip_module_level(testdir): - """importorskip must be able to skip entire modules when used at module level""" - testdir.makepyfile( - """ - import pytest - foobarbaz = pytest.importorskip("foobarbaz") - - def test_foo(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*collected 0 items / 1 skipped*"]) - - -def test_pytest_cmdline_main(testdir): - p = testdir.makepyfile( - """ - import pytest - def test_hello(): - assert 1 - if __name__ == '__main__': - pytest.cmdline.main([__file__]) - """ - ) - import subprocess - - popen = subprocess.Popen([sys.executable, str(p)], stdout=subprocess.PIPE) - popen.communicate() - ret = popen.wait() - assert ret == 0 - - -def test_unicode_in_longrepr(testdir): - testdir.makeconftest( - """ - # -*- coding: utf-8 -*- - import pytest - @pytest.hookimpl(hookwrapper=True) - def pytest_runtest_makereport(): - outcome = yield - rep = outcome.get_result() - if rep.when == "call": - rep.longrepr = u'ä' - """ - ) - testdir.makepyfile( - """ - def test_out(): - assert 0 - """ - ) - result = testdir.runpytest() - assert result.ret == 1 - assert "UnicodeEncodeError" not in result.stderr.str() - - -def test_failure_in_setup(testdir): - testdir.makepyfile( - """ - def setup_module(): - 0/0 - def test_func(): - pass - """ - ) - result = testdir.runpytest("--tb=line") - assert "def setup_module" not in result.stdout.str() - - -def test_makereport_getsource(testdir): - testdir.makepyfile( - """ - def test_foo(): - if False: pass - else: assert False - """ - ) - result = testdir.runpytest() - assert "INTERNALERROR" not in result.stdout.str() - result.stdout.fnmatch_lines(["*else: assert False*"]) - - -def test_makereport_getsource_dynamic_code(testdir, monkeypatch): - """Test that exception in dynamically generated code doesn't break getting the source line.""" - import inspect - - original_findsource = inspect.findsource - - def findsource(obj, *args, **kwargs): - # Can be triggered by dynamically created functions - if obj.__name__ == "foo": - raise IndexError() - return original_findsource(obj, *args, **kwargs) - - monkeypatch.setattr(inspect, "findsource", findsource) - - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def foo(missing): - pass - - def test_fix(foo): - assert False - """ - ) - result = testdir.runpytest("-vv") - assert "INTERNALERROR" not in result.stdout.str() - result.stdout.fnmatch_lines(["*test_fix*", "*fixture*'missing'*not found*"]) - - -def test_store_except_info_on_error(): - """ Test that upon test failure, the exception info is stored on - sys.last_traceback and friends. - """ - # Simulate item that might raise a specific exception, depending on `raise_error` class var - class ItemMightRaise(object): - nodeid = "item_that_raises" - raise_error = True - - def runtest(self): - if self.raise_error: - raise IndexError("TEST") - - try: - runner.pytest_runtest_call(ItemMightRaise()) - except IndexError: - pass - # Check that exception info is stored on sys - assert sys.last_type is IndexError - assert sys.last_value.args[0] == "TEST" - assert sys.last_traceback - - # The next run should clear the exception info stored by the previous run - ItemMightRaise.raise_error = False - runner.pytest_runtest_call(ItemMightRaise()) - assert sys.last_type is None - assert sys.last_value is None - assert sys.last_traceback is None - - -def test_current_test_env_var(testdir, monkeypatch): - pytest_current_test_vars = [] - monkeypatch.setattr( - sys, "pytest_current_test_vars", pytest_current_test_vars, raising=False - ) - testdir.makepyfile( - """ - import pytest - import sys - import os - - @pytest.fixture - def fix(): - sys.pytest_current_test_vars.append(('setup', os.environ['PYTEST_CURRENT_TEST'])) - yield - sys.pytest_current_test_vars.append(('teardown', os.environ['PYTEST_CURRENT_TEST'])) - - def test(fix): - sys.pytest_current_test_vars.append(('call', os.environ['PYTEST_CURRENT_TEST'])) - """ - ) - result = testdir.runpytest_inprocess() - assert result.ret == 0 - test_id = "test_current_test_env_var.py::test" - assert ( - pytest_current_test_vars - == [ - ("setup", test_id + " (setup)"), - ("call", test_id + " (call)"), - ("teardown", test_id + " (teardown)"), - ] - ) - assert "PYTEST_CURRENT_TEST" not in os.environ - - -class TestReportContents(object): - """ - Test user-level API of ``TestReport`` objects. - """ - - def getrunner(self): - return lambda item: runner.runtestprotocol(item, log=False) - - def test_longreprtext_pass(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - pass - """ - ) - rep = reports[1] - assert rep.longreprtext == "" - - def test_longreprtext_failure(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - x = 1 - assert x == 4 - """ - ) - rep = reports[1] - assert "assert 1 == 4" in rep.longreprtext - - def test_captured_text(self, testdir): - reports = testdir.runitem( - """ - import pytest - import sys - - @pytest.fixture - def fix(): - sys.stdout.write('setup: stdout\\n') - sys.stderr.write('setup: stderr\\n') - yield - sys.stdout.write('teardown: stdout\\n') - sys.stderr.write('teardown: stderr\\n') - assert 0 - - def test_func(fix): - sys.stdout.write('call: stdout\\n') - sys.stderr.write('call: stderr\\n') - assert 0 - """ - ) - setup, call, teardown = reports - assert setup.capstdout == "setup: stdout\n" - assert call.capstdout == "setup: stdout\ncall: stdout\n" - assert teardown.capstdout == "setup: stdout\ncall: stdout\nteardown: stdout\n" - - assert setup.capstderr == "setup: stderr\n" - assert call.capstderr == "setup: stderr\ncall: stderr\n" - assert teardown.capstderr == "setup: stderr\ncall: stderr\nteardown: stderr\n" - - def test_no_captured_text(self, testdir): - reports = testdir.runitem( - """ - def test_func(): - pass - """ - ) - rep = reports[1] - assert rep.capstdout == "" - assert rep.capstderr == "" diff --git a/third_party/python/pytest/testing/test_runner_xunit.py b/third_party/python/pytest/testing/test_runner_xunit.py deleted file mode 100644 index 8316aafbf561..000000000000 --- a/third_party/python/pytest/testing/test_runner_xunit.py +++ /dev/null @@ -1,352 +0,0 @@ -""" - test correct setup/teardowns at - module, class, and instance level -""" -from __future__ import absolute_import, division, print_function -import pytest - - -def test_module_and_function_setup(testdir): - reprec = testdir.inline_runsource( - """ - modlevel = [] - def setup_module(module): - assert not modlevel - module.modlevel.append(42) - - def teardown_module(module): - modlevel.pop() - - def setup_function(function): - function.answer = 17 - - def teardown_function(function): - del function.answer - - def test_modlevel(): - assert modlevel[0] == 42 - assert test_modlevel.answer == 17 - - class TestFromClass(object): - def test_module(self): - assert modlevel[0] == 42 - assert not hasattr(test_modlevel, 'answer') - """ - ) - rep = reprec.matchreport("test_modlevel") - assert rep.passed - rep = reprec.matchreport("test_module") - assert rep.passed - - -def test_module_setup_failure_no_teardown(testdir): - reprec = testdir.inline_runsource( - """ - values = [] - def setup_module(module): - values.append(1) - 0/0 - - def test_nothing(): - pass - - def teardown_module(module): - values.append(2) - """ - ) - reprec.assertoutcome(failed=1) - calls = reprec.getcalls("pytest_runtest_setup") - assert calls[0].item.module.values == [1] - - -def test_setup_function_failure_no_teardown(testdir): - reprec = testdir.inline_runsource( - """ - modlevel = [] - def setup_function(function): - modlevel.append(1) - 0/0 - - def teardown_function(module): - modlevel.append(2) - - def test_func(): - pass - """ - ) - calls = reprec.getcalls("pytest_runtest_setup") - assert calls[0].item.module.modlevel == [1] - - -def test_class_setup(testdir): - reprec = testdir.inline_runsource( - """ - class TestSimpleClassSetup(object): - clslevel = [] - def setup_class(cls): - cls.clslevel.append(23) - - def teardown_class(cls): - cls.clslevel.pop() - - def test_classlevel(self): - assert self.clslevel[0] == 23 - - class TestInheritedClassSetupStillWorks(TestSimpleClassSetup): - def test_classlevel_anothertime(self): - assert self.clslevel == [23] - - def test_cleanup(): - assert not TestSimpleClassSetup.clslevel - assert not TestInheritedClassSetupStillWorks.clslevel - """ - ) - reprec.assertoutcome(passed=1 + 2 + 1) - - -def test_class_setup_failure_no_teardown(testdir): - reprec = testdir.inline_runsource( - """ - class TestSimpleClassSetup(object): - clslevel = [] - def setup_class(cls): - 0/0 - - def teardown_class(cls): - cls.clslevel.append(1) - - def test_classlevel(self): - pass - - def test_cleanup(): - assert not TestSimpleClassSetup.clslevel - """ - ) - reprec.assertoutcome(failed=1, passed=1) - - -def test_method_setup(testdir): - reprec = testdir.inline_runsource( - """ - class TestSetupMethod(object): - def setup_method(self, meth): - self.methsetup = meth - def teardown_method(self, meth): - del self.methsetup - - def test_some(self): - assert self.methsetup == self.test_some - - def test_other(self): - assert self.methsetup == self.test_other - """ - ) - reprec.assertoutcome(passed=2) - - -def test_method_setup_failure_no_teardown(testdir): - reprec = testdir.inline_runsource( - """ - class TestMethodSetup(object): - clslevel = [] - def setup_method(self, method): - self.clslevel.append(1) - 0/0 - - def teardown_method(self, method): - self.clslevel.append(2) - - def test_method(self): - pass - - def test_cleanup(): - assert TestMethodSetup.clslevel == [1] - """ - ) - reprec.assertoutcome(failed=1, passed=1) - - -def test_method_generator_setup(testdir): - reprec = testdir.inline_runsource( - """ - class TestSetupTeardownOnInstance(object): - def setup_class(cls): - cls.classsetup = True - - def setup_method(self, method): - self.methsetup = method - - def test_generate(self): - assert self.classsetup - assert self.methsetup == self.test_generate - yield self.generated, 5 - yield self.generated, 2 - - def generated(self, value): - assert self.classsetup - assert self.methsetup == self.test_generate - assert value == 5 - """ - ) - reprec.assertoutcome(passed=1, failed=1) - - -def test_func_generator_setup(testdir): - reprec = testdir.inline_runsource( - """ - import sys - - def setup_module(mod): - print ("setup_module") - mod.x = [] - - def setup_function(fun): - print ("setup_function") - x.append(1) - - def teardown_function(fun): - print ("teardown_function") - x.pop() - - def test_one(): - assert x == [1] - def check(): - print ("check") - sys.stderr.write("e\\n") - assert x == [1] - yield check - assert x == [1] - """ - ) - rep = reprec.matchreport("test_one", names="pytest_runtest_logreport") - assert rep.passed - - -def test_method_setup_uses_fresh_instances(testdir): - reprec = testdir.inline_runsource( - """ - class TestSelfState1(object): - memory = [] - def test_hello(self): - self.memory.append(self) - - def test_afterhello(self): - assert self != self.memory[0] - """ - ) - reprec.assertoutcome(passed=2, failed=0) - - -def test_setup_that_skips_calledagain(testdir): - p = testdir.makepyfile( - """ - import pytest - def setup_module(mod): - pytest.skip("x") - def test_function1(): - pass - def test_function2(): - pass - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(skipped=2) - - -def test_setup_fails_again_on_all_tests(testdir): - p = testdir.makepyfile( - """ - import pytest - def setup_module(mod): - raise ValueError(42) - def test_function1(): - pass - def test_function2(): - pass - """ - ) - reprec = testdir.inline_run(p) - reprec.assertoutcome(failed=2) - - -def test_setup_funcarg_setup_when_outer_scope_fails(testdir): - p = testdir.makepyfile( - """ - import pytest - def setup_module(mod): - raise ValueError(42) - @pytest.fixture - def hello(request): - raise ValueError("xyz43") - def test_function1(hello): - pass - def test_function2(hello): - pass - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines( - [ - "*function1*", - "*ValueError*42*", - "*function2*", - "*ValueError*42*", - "*2 error*", - ] - ) - assert "xyz43" not in result.stdout.str() - - -@pytest.mark.parametrize("arg", ["", "arg"]) -def test_setup_teardown_function_level_with_optional_argument( - testdir, monkeypatch, arg -): - """parameter to setup/teardown xunit-style functions parameter is now optional (#1728).""" - import sys - - trace_setups_teardowns = [] - monkeypatch.setattr( - sys, "trace_setups_teardowns", trace_setups_teardowns, raising=False - ) - p = testdir.makepyfile( - """ - import pytest - import sys - - trace = sys.trace_setups_teardowns.append - - def setup_module({arg}): trace('setup_module') - def teardown_module({arg}): trace('teardown_module') - - def setup_function({arg}): trace('setup_function') - def teardown_function({arg}): trace('teardown_function') - - def test_function_1(): pass - def test_function_2(): pass - - class Test(object): - def setup_method(self, {arg}): trace('setup_method') - def teardown_method(self, {arg}): trace('teardown_method') - - def test_method_1(self): pass - def test_method_2(self): pass - """.format( - arg=arg - ) - ) - result = testdir.inline_run(p) - result.assertoutcome(passed=4) - - expected = [ - "setup_module", - "setup_function", - "teardown_function", - "setup_function", - "teardown_function", - "setup_method", - "teardown_method", - "setup_method", - "teardown_method", - "teardown_module", - ] - assert trace_setups_teardowns == expected diff --git a/third_party/python/pytest/testing/test_session.py b/third_party/python/pytest/testing/test_session.py deleted file mode 100644 index 4a594009bab5..000000000000 --- a/third_party/python/pytest/testing/test_session.py +++ /dev/null @@ -1,343 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import pytest - -from _pytest.main import EXIT_NOTESTSCOLLECTED - - -class SessionTests(object): - - def test_basic_testitem_events(self, testdir): - tfile = testdir.makepyfile( - """ - def test_one(): - pass - def test_one_one(): - assert 0 - def test_other(): - raise ValueError(23) - class TestClass(object): - def test_two(self, someargs): - pass - """ - ) - reprec = testdir.inline_run(tfile) - passed, skipped, failed = reprec.listoutcomes() - assert len(skipped) == 0 - assert len(passed) == 1 - assert len(failed) == 3 - - def end(x): - return x.nodeid.split("::")[-1] - - assert end(failed[0]) == "test_one_one" - assert end(failed[1]) == "test_other" - itemstarted = reprec.getcalls("pytest_itemcollected") - assert len(itemstarted) == 4 - # XXX check for failing funcarg setup - # colreports = reprec.getcalls("pytest_collectreport") - # assert len(colreports) == 4 - # assert colreports[1].report.failed - - def test_nested_import_error(self, testdir): - tfile = testdir.makepyfile( - """ - import import_fails - def test_this(): - assert import_fails.a == 1 - """, - import_fails=""" - import does_not_work - a = 1 - """, - ) - reprec = testdir.inline_run(tfile) - values = reprec.getfailedcollections() - assert len(values) == 1 - out = str(values[0].longrepr) - assert out.find("does_not_work") != -1 - - def test_raises_output(self, testdir): - reprec = testdir.inline_runsource( - """ - import pytest - def test_raises_doesnt(): - pytest.raises(ValueError, int, "3") - """ - ) - passed, skipped, failed = reprec.listoutcomes() - assert len(failed) == 1 - out = failed[0].longrepr.reprcrash.message - if not out.find("DID NOT RAISE") != -1: - print(out) - pytest.fail("incorrect raises() output") - - def test_generator_yields_None(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_1(): - yield None - """ - ) - failures = reprec.getfailedcollections() - out = failures[0].longrepr.reprcrash.message - i = out.find("TypeError") - assert i != -1 - - def test_syntax_error_module(self, testdir): - reprec = testdir.inline_runsource("this is really not python") - values = reprec.getfailedcollections() - assert len(values) == 1 - out = str(values[0].longrepr) - assert out.find(str("not python")) != -1 - - def test_exit_first_problem(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_one(): assert 0 - def test_two(): assert 0 - """, - "--exitfirst", - ) - passed, skipped, failed = reprec.countoutcomes() - assert failed == 1 - assert passed == skipped == 0 - - def test_maxfail(self, testdir): - reprec = testdir.inline_runsource( - """ - def test_one(): assert 0 - def test_two(): assert 0 - def test_three(): assert 0 - """, - "--maxfail=2", - ) - passed, skipped, failed = reprec.countoutcomes() - assert failed == 2 - assert passed == skipped == 0 - - def test_broken_repr(self, testdir): - p = testdir.makepyfile( - """ - import pytest - class BrokenRepr1(object): - foo=0 - def __repr__(self): - raise Exception("Ha Ha fooled you, I'm a broken repr().") - - class TestBrokenClass(object): - def test_explicit_bad_repr(self): - t = BrokenRepr1() - pytest.raises(Exception, 'repr(t)') - - def test_implicit_bad_repr1(self): - t = BrokenRepr1() - assert t.foo == 1 - - """ - ) - reprec = testdir.inline_run(p) - passed, skipped, failed = reprec.listoutcomes() - assert len(failed) == 1 - out = failed[0].longrepr.reprcrash.message - assert ( - out.find( - """[Exception("Ha Ha fooled you, I'm a broken repr().") raised in repr()]""" - ) - != -1 - ) # ' - - def test_skip_file_by_conftest(self, testdir): - testdir.makepyfile( - conftest=""" - import pytest - def pytest_collect_file(): - pytest.skip("intentional") - """, - test_file=""" - def test_one(): pass - """, - ) - try: - reprec = testdir.inline_run(testdir.tmpdir) - except pytest.skip.Exception: - pytest.fail("wrong skipped caught") - reports = reprec.getreports("pytest_collectreport") - assert len(reports) == 1 - assert reports[0].skipped - - -class TestNewSession(SessionTests): - - def test_order_of_execution(self, testdir): - reprec = testdir.inline_runsource( - """ - values = [] - def test_1(): - values.append(1) - def test_2(): - values.append(2) - def test_3(): - assert values == [1,2] - class Testmygroup(object): - reslist = values - def test_1(self): - self.reslist.append(1) - def test_2(self): - self.reslist.append(2) - def test_3(self): - self.reslist.append(3) - def test_4(self): - assert self.reslist == [1,2,1,2,3] - """ - ) - passed, skipped, failed = reprec.countoutcomes() - assert failed == skipped == 0 - assert passed == 7 - # also test listnames() here ... - - def test_collect_only_with_various_situations(self, testdir): - p = testdir.makepyfile( - test_one=""" - def test_one(): - raise ValueError() - - class TestX(object): - def test_method_one(self): - pass - - class TestY(TestX): - pass - """, - test_three="xxxdsadsadsadsa", - __init__="", - ) - reprec = testdir.inline_run("--collect-only", p.dirpath()) - - itemstarted = reprec.getcalls("pytest_itemcollected") - assert len(itemstarted) == 3 - assert not reprec.getreports("pytest_runtest_logreport") - started = reprec.getcalls("pytest_collectstart") - finished = reprec.getreports("pytest_collectreport") - assert len(started) == len(finished) - assert len(started) == 7 # XXX extra TopCollector - colfail = [x for x in finished if x.failed] - assert len(colfail) == 1 - - def test_minus_x_import_error(self, testdir): - testdir.makepyfile(__init__="") - testdir.makepyfile(test_one="xxxx", test_two="yyyy") - reprec = testdir.inline_run("-x", testdir.tmpdir) - finished = reprec.getreports("pytest_collectreport") - colfail = [x for x in finished if x.failed] - assert len(colfail) == 1 - - def test_minus_x_overridden_by_maxfail(self, testdir): - testdir.makepyfile(__init__="") - testdir.makepyfile(test_one="xxxx", test_two="yyyy", test_third="zzz") - reprec = testdir.inline_run("-x", "--maxfail=2", testdir.tmpdir) - finished = reprec.getreports("pytest_collectreport") - colfail = [x for x in finished if x.failed] - assert len(colfail) == 2 - - -def test_plugin_specify(testdir): - pytest.raises( - ImportError, - """ - testdir.parseconfig("-p", "nqweotexistent") - """, - ) - # pytest.raises(ImportError, - # "config.do_configure(config)" - # ) - - -def test_plugin_already_exists(testdir): - config = testdir.parseconfig("-p", "terminal") - assert config.option.plugins == ["terminal"] - config._do_configure() - config._ensure_unconfigure() - - -def test_exclude(testdir): - hellodir = testdir.mkdir("hello") - hellodir.join("test_hello.py").write("x y syntaxerror") - hello2dir = testdir.mkdir("hello2") - hello2dir.join("test_hello2.py").write("x y syntaxerror") - testdir.makepyfile(test_ok="def test_pass(): pass") - result = testdir.runpytest("--ignore=hello", "--ignore=hello2") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_deselect(testdir): - testdir.makepyfile( - test_a=""" - import pytest - def test_a1(): pass - @pytest.mark.parametrize('b', range(3)) - def test_a2(b): pass - """ - ) - result = testdir.runpytest( - "-v", "--deselect=test_a.py::test_a2[1]", "--deselect=test_a.py::test_a2[2]" - ) - assert result.ret == 0 - result.stdout.fnmatch_lines(["*2 passed, 2 deselected*"]) - for line in result.stdout.lines: - assert not line.startswith(("test_a.py::test_a2[1]", "test_a.py::test_a2[2]")) - - -def test_sessionfinish_with_start(testdir): - testdir.makeconftest( - """ - import os - values = [] - def pytest_sessionstart(): - values.append(os.getcwd()) - os.chdir("..") - - def pytest_sessionfinish(): - assert values[0] == os.getcwd() - - """ - ) - res = testdir.runpytest("--collect-only") - assert res.ret == EXIT_NOTESTSCOLLECTED - - -@pytest.mark.parametrize("path", ["root", "{relative}/root", "{environment}/root"]) -def test_rootdir_option_arg(testdir, monkeypatch, path): - monkeypatch.setenv("PY_ROOTDIR_PATH", str(testdir.tmpdir)) - path = path.format(relative=str(testdir.tmpdir), environment="$PY_ROOTDIR_PATH") - - rootdir = testdir.mkdir("root") - rootdir.mkdir("tests") - testdir.makepyfile( - """ - import os - def test_one(): - assert 1 - """ - ) - - result = testdir.runpytest("--rootdir={}".format(path)) - result.stdout.fnmatch_lines( - ["*rootdir: {}/root, inifile:*".format(testdir.tmpdir), "*1 passed*"] - ) - - -def test_rootdir_wrong_option_arg(testdir): - testdir.makepyfile( - """ - import os - def test_one(): - assert 1 - """ - ) - - result = testdir.runpytest("--rootdir=wrong_dir") - result.stderr.fnmatch_lines( - ["*Directory *wrong_dir* not found. Check your '--rootdir' option.*"] - ) diff --git a/third_party/python/pytest/testing/test_skipping.py b/third_party/python/pytest/testing/test_skipping.py deleted file mode 100644 index 5d970e2fea0a..000000000000 --- a/third_party/python/pytest/testing/test_skipping.py +++ /dev/null @@ -1,1194 +0,0 @@ -from __future__ import absolute_import, division, print_function -import pytest -import sys - -from _pytest.skipping import MarkEvaluator, folded_skips, pytest_runtest_setup -from _pytest.runner import runtestprotocol - - -class TestEvaluator(object): - - def test_no_marker(self, testdir): - item = testdir.getitem("def test_func(): pass") - evalskipif = MarkEvaluator(item, "skipif") - assert not evalskipif - assert not evalskipif.istrue() - - def test_marked_no_args(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xyz - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "xyz") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "" - assert not ev.get("run", False) - - def test_marked_one_arg(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xyz("hasattr(os, 'sep')") - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "xyz") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "condition: hasattr(os, 'sep')" - - @pytest.mark.skipif("sys.version_info[0] >= 3") - def test_marked_one_arg_unicode(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xyz(u"hasattr(os, 'sep')") - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "xyz") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "condition: hasattr(os, 'sep')" - - def test_marked_one_arg_with_reason(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xyz("hasattr(os, 'sep')", attr=2, reason="hello world") - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "xyz") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "hello world" - assert ev.get("attr") == 2 - - def test_marked_one_arg_twice(self, testdir): - lines = [ - """@pytest.mark.skipif("not hasattr(os, 'murks')")""", - """@pytest.mark.skipif("hasattr(os, 'murks')")""", - ] - for i in range(0, 2): - item = testdir.getitem( - """ - import pytest - %s - %s - def test_func(): - pass - """ - % (lines[i], lines[(i + 1) % 2]) - ) - ev = MarkEvaluator(item, "skipif") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "condition: not hasattr(os, 'murks')" - - def test_marked_one_arg_twice2(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.skipif("hasattr(os, 'murks')") - @pytest.mark.skipif("not hasattr(os, 'murks')") - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "skipif") - assert ev - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "condition: not hasattr(os, 'murks')" - - def test_marked_skip_with_not_string(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.skipif(False) - def test_func(): - pass - """ - ) - ev = MarkEvaluator(item, "skipif") - exc = pytest.raises(pytest.fail.Exception, ev.istrue) - assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg - - def test_skipif_class(self, testdir): - item, = testdir.getitems( - """ - import pytest - class TestClass(object): - pytestmark = pytest.mark.skipif("config._hackxyz") - def test_func(self): - pass - """ - ) - item.config._hackxyz = 3 - ev = MarkEvaluator(item, "skipif") - assert ev.istrue() - expl = ev.getexplanation() - assert expl == "condition: config._hackxyz" - - -class TestXFail(object): - - @pytest.mark.parametrize("strict", [True, False]) - def test_xfail_simple(self, testdir, strict): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xfail(strict=%s) - def test_func(): - assert 0 - """ - % strict - ) - reports = runtestprotocol(item, log=False) - assert len(reports) == 3 - callreport = reports[1] - assert callreport.skipped - assert callreport.wasxfail == "" - - def test_xfail_xpassed(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xfail(reason="this is an xfail") - def test_func(): - assert 1 - """ - ) - reports = runtestprotocol(item, log=False) - assert len(reports) == 3 - callreport = reports[1] - assert callreport.passed - assert callreport.wasxfail == "this is an xfail" - - def test_xfail_using_platform(self, testdir): - """ - Verify that platform can be used with xfail statements. - """ - item = testdir.getitem( - """ - import pytest - @pytest.mark.xfail("platform.platform() == platform.platform()") - def test_func(): - assert 0 - """ - ) - reports = runtestprotocol(item, log=False) - assert len(reports) == 3 - callreport = reports[1] - assert callreport.wasxfail - - def test_xfail_xpassed_strict(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xfail(strict=True, reason="nope") - def test_func(): - assert 1 - """ - ) - reports = runtestprotocol(item, log=False) - assert len(reports) == 3 - callreport = reports[1] - assert callreport.failed - assert callreport.longrepr == "[XPASS(strict)] nope" - assert not hasattr(callreport, "wasxfail") - - def test_xfail_run_anyway(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail - def test_func(): - assert 0 - def test_func2(): - pytest.xfail("hello") - """ - ) - result = testdir.runpytest("--runxfail") - result.stdout.fnmatch_lines( - ["*def test_func():*", "*assert 0*", "*1 failed*1 pass*"] - ) - - def test_xfail_evalfalse_but_fails(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.xfail('False') - def test_func(): - assert 0 - """ - ) - reports = runtestprotocol(item, log=False) - callreport = reports[1] - assert callreport.failed - assert not hasattr(callreport, "wasxfail") - assert "xfail" in callreport.keywords - - def test_xfail_not_report_default(self, testdir): - p = testdir.makepyfile( - test_one=""" - import pytest - @pytest.mark.xfail - def test_this(): - assert 0 - """ - ) - testdir.runpytest(p, "-v") - # result.stdout.fnmatch_lines([ - # "*HINT*use*-r*" - # ]) - - def test_xfail_not_run_xfail_reporting(self, testdir): - p = testdir.makepyfile( - test_one=""" - import pytest - @pytest.mark.xfail(run=False, reason="noway") - def test_this(): - assert 0 - @pytest.mark.xfail("True", run=False) - def test_this_true(): - assert 0 - @pytest.mark.xfail("False", run=False, reason="huh") - def test_this_false(): - assert 1 - """ - ) - result = testdir.runpytest(p, "-rx") - result.stdout.fnmatch_lines( - [ - "*test_one*test_this*", - "*NOTRUN*noway", - "*test_one*test_this_true*", - "*NOTRUN*condition:*True*", - "*1 passed*", - ] - ) - - def test_xfail_not_run_no_setup_run(self, testdir): - p = testdir.makepyfile( - test_one=""" - import pytest - @pytest.mark.xfail(run=False, reason="hello") - def test_this(): - assert 0 - def setup_module(mod): - raise ValueError(42) - """ - ) - result = testdir.runpytest(p, "-rx") - result.stdout.fnmatch_lines( - ["*test_one*test_this*", "*NOTRUN*hello", "*1 xfailed*"] - ) - - def test_xfail_xpass(self, testdir): - p = testdir.makepyfile( - test_one=""" - import pytest - @pytest.mark.xfail - def test_that(): - assert 1 - """ - ) - result = testdir.runpytest(p, "-rX") - result.stdout.fnmatch_lines(["*XPASS*test_that*", "*1 xpassed*"]) - assert result.ret == 0 - - def test_xfail_imperative(self, testdir): - p = testdir.makepyfile( - """ - import pytest - def test_this(): - pytest.xfail("hello") - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*1 xfailed*"]) - result = testdir.runpytest(p, "-rx") - result.stdout.fnmatch_lines(["*XFAIL*test_this*", "*reason:*hello*"]) - result = testdir.runpytest(p, "--runxfail") - result.stdout.fnmatch_lines("*1 pass*") - - def test_xfail_imperative_in_setup_function(self, testdir): - p = testdir.makepyfile( - """ - import pytest - def setup_function(function): - pytest.xfail("hello") - - def test_this(): - assert 0 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*1 xfailed*"]) - result = testdir.runpytest(p, "-rx") - result.stdout.fnmatch_lines(["*XFAIL*test_this*", "*reason:*hello*"]) - result = testdir.runpytest(p, "--runxfail") - result.stdout.fnmatch_lines( - """ - *def test_this* - *1 fail* - """ - ) - - def xtest_dynamic_xfail_set_during_setup(self, testdir): - p = testdir.makepyfile( - """ - import pytest - def setup_function(function): - pytest.mark.xfail(function) - def test_this(): - assert 0 - def test_that(): - assert 1 - """ - ) - result = testdir.runpytest(p, "-rxX") - result.stdout.fnmatch_lines(["*XFAIL*test_this*", "*XPASS*test_that*"]) - - def test_dynamic_xfail_no_run(self, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture - def arg(request): - request.applymarker(pytest.mark.xfail(run=False)) - def test_this(arg): - assert 0 - """ - ) - result = testdir.runpytest(p, "-rxX") - result.stdout.fnmatch_lines(["*XFAIL*test_this*", "*NOTRUN*"]) - - def test_dynamic_xfail_set_during_funcarg_setup(self, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.fixture - def arg(request): - request.applymarker(pytest.mark.xfail) - def test_this2(arg): - assert 0 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*1 xfailed*"]) - - @pytest.mark.parametrize( - "expected, actual, matchline", - [ - ("TypeError", "TypeError", "*1 xfailed*"), - ("(AttributeError, TypeError)", "TypeError", "*1 xfailed*"), - ("TypeError", "IndexError", "*1 failed*"), - ("(AttributeError, TypeError)", "IndexError", "*1 failed*"), - ], - ) - def test_xfail_raises(self, expected, actual, matchline, testdir): - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(raises=%s) - def test_raises(): - raise %s() - """ - % (expected, actual) - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines([matchline]) - - def test_strict_sanity(self, testdir): - """sanity check for xfail(strict=True): a failing test should behave - exactly like a normal xfail. - """ - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(reason='unsupported feature', strict=True) - def test_foo(): - assert 0 - """ - ) - result = testdir.runpytest(p, "-rxX") - result.stdout.fnmatch_lines(["*XFAIL*", "*unsupported feature*"]) - assert result.ret == 0 - - @pytest.mark.parametrize("strict", [True, False]) - def test_strict_xfail(self, testdir, strict): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.xfail(reason='unsupported feature', strict=%s) - def test_foo(): - with open('foo_executed', 'w'): pass # make sure test executes - """ - % strict - ) - result = testdir.runpytest(p, "-rxX") - if strict: - result.stdout.fnmatch_lines( - ["*test_foo*", "*XPASS(strict)*unsupported feature*"] - ) - else: - result.stdout.fnmatch_lines( - [ - "*test_strict_xfail*", - "XPASS test_strict_xfail.py::test_foo unsupported feature", - ] - ) - assert result.ret == (1 if strict else 0) - assert testdir.tmpdir.join("foo_executed").isfile() - - @pytest.mark.parametrize("strict", [True, False]) - def test_strict_xfail_condition(self, testdir, strict): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.xfail(False, reason='unsupported feature', strict=%s) - def test_foo(): - pass - """ - % strict - ) - result = testdir.runpytest(p, "-rxX") - result.stdout.fnmatch_lines("*1 passed*") - assert result.ret == 0 - - @pytest.mark.parametrize("strict", [True, False]) - def test_xfail_condition_keyword(self, testdir, strict): - p = testdir.makepyfile( - """ - import pytest - - @pytest.mark.xfail(condition=False, reason='unsupported feature', strict=%s) - def test_foo(): - pass - """ - % strict - ) - result = testdir.runpytest(p, "-rxX") - result.stdout.fnmatch_lines("*1 passed*") - assert result.ret == 0 - - @pytest.mark.parametrize("strict_val", ["true", "false"]) - def test_strict_xfail_default_from_file(self, testdir, strict_val): - testdir.makeini( - """ - [pytest] - xfail_strict = %s - """ - % strict_val - ) - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(reason='unsupported feature') - def test_foo(): - pass - """ - ) - result = testdir.runpytest(p, "-rxX") - strict = strict_val == "true" - result.stdout.fnmatch_lines("*1 failed*" if strict else "*1 xpassed*") - assert result.ret == (1 if strict else 0) - - -class TestXFailwithSetupTeardown(object): - - def test_failing_setup_issue9(self, testdir): - testdir.makepyfile( - """ - import pytest - def setup_function(func): - assert 0 - - @pytest.mark.xfail - def test_func(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 xfail*"]) - - def test_failing_teardown_issue9(self, testdir): - testdir.makepyfile( - """ - import pytest - def teardown_function(func): - assert 0 - - @pytest.mark.xfail - def test_func(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 xfail*"]) - - -class TestSkip(object): - - def test_skip_class(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip - class TestSomething(object): - def test_foo(self): - pass - def test_bar(self): - pass - - def test_baz(): - pass - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(skipped=2, passed=1) - - def test_skips_on_false_string(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip('False') - def test_foo(): - pass - """ - ) - rec = testdir.inline_run() - rec.assertoutcome(skipped=1) - - def test_arg_as_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip('testing stuff') - def test_bar(): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*testing stuff*", "*1 skipped*"]) - - def test_skip_no_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip - def test_foo(): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*unconditional skip*", "*1 skipped*"]) - - def test_skip_with_reason(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip(reason="for lolz") - def test_bar(): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*for lolz*", "*1 skipped*"]) - - def test_only_skips_marked_test(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip - def test_foo(): - pass - @pytest.mark.skip(reason="nothing in particular") - def test_bar(): - pass - def test_baz(): - assert True - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*nothing in particular*", "*1 passed*2 skipped*"]) - - def test_strict_and_skip(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skip - def test_hello(): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*unconditional skip*", "*1 skipped*"]) - - -class TestSkipif(object): - - def test_skipif_conditional(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.skipif("hasattr(os, 'sep')") - def test_func(): - pass - """ - ) - x = pytest.raises(pytest.skip.Exception, lambda: pytest_runtest_setup(item)) - assert x.value.msg == "condition: hasattr(os, 'sep')" - - @pytest.mark.parametrize( - "params", ["\"hasattr(sys, 'platform')\"", 'True, reason="invalid platform"'] - ) - def test_skipif_reporting(self, testdir, params): - p = testdir.makepyfile( - test_foo=""" - import pytest - @pytest.mark.skipif(%(params)s) - def test_that(): - assert 0 - """ - % dict(params=params) - ) - result = testdir.runpytest(p, "-s", "-rs") - result.stdout.fnmatch_lines(["*SKIP*1*test_foo.py*platform*", "*1 skipped*"]) - assert result.ret == 0 - - def test_skipif_using_platform(self, testdir): - item = testdir.getitem( - """ - import pytest - @pytest.mark.skipif("platform.platform() == platform.platform()") - def test_func(): - pass - """ - ) - pytest.raises(pytest.skip.Exception, lambda: pytest_runtest_setup(item)) - - @pytest.mark.parametrize( - "marker, msg1, msg2", - [("skipif", "SKIP", "skipped"), ("xfail", "XPASS", "xpassed")], - ) - def test_skipif_reporting_multiple(self, testdir, marker, msg1, msg2): - testdir.makepyfile( - test_foo=""" - import pytest - @pytest.mark.{marker}(False, reason='first_condition') - @pytest.mark.{marker}(True, reason='second_condition') - def test_foobar(): - assert 1 - """.format( - marker=marker - ) - ) - result = testdir.runpytest("-s", "-rsxX") - result.stdout.fnmatch_lines( - [ - "*{msg1}*test_foo.py*second_condition*".format(msg1=msg1), - "*1 {msg2}*".format(msg2=msg2), - ] - ) - assert result.ret == 0 - - -def test_skip_not_report_default(testdir): - p = testdir.makepyfile( - test_one=""" - import pytest - def test_this(): - pytest.skip("hello") - """ - ) - result = testdir.runpytest(p, "-v") - result.stdout.fnmatch_lines( - [ - # "*HINT*use*-r*", - "*1 skipped*" - ] - ) - - -def test_skipif_class(testdir): - p = testdir.makepyfile( - """ - import pytest - - class TestClass(object): - pytestmark = pytest.mark.skipif("True") - def test_that(self): - assert 0 - def test_though(self): - assert 0 - """ - ) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines(["*2 skipped*"]) - - -def test_skip_reasons_folding(): - path = "xyz" - lineno = 3 - message = "justso" - longrepr = (path, lineno, message) - - class X(object): - pass - - ev1 = X() - ev1.when = "execute" - ev1.skipped = True - ev1.longrepr = longrepr - - ev2 = X() - ev2.when = "execute" - ev2.longrepr = longrepr - ev2.skipped = True - - # ev3 might be a collection report - ev3 = X() - ev3.longrepr = longrepr - ev3.skipped = True - - values = folded_skips([ev1, ev2, ev3]) - assert len(values) == 1 - num, fspath, lineno, reason = values[0] - assert num == 3 - assert fspath == path - assert lineno == lineno - assert reason == message - - -def test_skipped_reasons_functional(testdir): - testdir.makepyfile( - test_one=""" - from conftest import doskip - def setup_function(func): - doskip() - def test_func(): - pass - class TestClass(object): - def test_method(self): - doskip() - """, - conftest=""" - import pytest - def doskip(): - pytest.skip('test') - """, - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*SKIP*2*conftest.py:4: test"]) - assert result.ret == 0 - - -def test_skipped_folding(testdir): - testdir.makepyfile( - test_one=""" - import pytest - pytestmark = pytest.mark.skip("Folding") - def setup_function(func): - pass - def test_func(): - pass - class TestClass(object): - def test_method(self): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines(["*SKIP*2*test_one.py: Folding"]) - assert result.ret == 0 - - -def test_reportchars(testdir): - testdir.makepyfile( - """ - import pytest - def test_1(): - assert 0 - @pytest.mark.xfail - def test_2(): - assert 0 - @pytest.mark.xfail - def test_3(): - pass - def test_4(): - pytest.skip("four") - """ - ) - result = testdir.runpytest("-rfxXs") - result.stdout.fnmatch_lines( - ["FAIL*test_1*", "XFAIL*test_2*", "XPASS*test_3*", "SKIP*four*"] - ) - - -def test_reportchars_error(testdir): - testdir.makepyfile( - conftest=""" - def pytest_runtest_teardown(): - assert 0 - """, - test_simple=""" - def test_foo(): - pass - """, - ) - result = testdir.runpytest("-rE") - result.stdout.fnmatch_lines(["ERROR*test_foo*"]) - - -def test_reportchars_all(testdir): - testdir.makepyfile( - """ - import pytest - def test_1(): - assert 0 - @pytest.mark.xfail - def test_2(): - assert 0 - @pytest.mark.xfail - def test_3(): - pass - def test_4(): - pytest.skip("four") - """ - ) - result = testdir.runpytest("-ra") - result.stdout.fnmatch_lines( - ["FAIL*test_1*", "SKIP*four*", "XFAIL*test_2*", "XPASS*test_3*"] - ) - - -def test_reportchars_all_error(testdir): - testdir.makepyfile( - conftest=""" - def pytest_runtest_teardown(): - assert 0 - """, - test_simple=""" - def test_foo(): - pass - """, - ) - result = testdir.runpytest("-ra") - result.stdout.fnmatch_lines(["ERROR*test_foo*"]) - - -@pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") -def test_errors_in_xfail_skip_expressions(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skipif("asd") - def test_nameerror(): - pass - @pytest.mark.xfail("syntax error") - def test_syntax(): - pass - - def test_func(): - pass - """ - ) - result = testdir.runpytest() - markline = " ^" - if sys.platform.startswith("java"): - # XXX report this to java - markline = "*" + markline[8:] - result.stdout.fnmatch_lines( - [ - "*ERROR*test_nameerror*", - "*evaluating*skipif*expression*", - "*asd*", - "*ERROR*test_syntax*", - "*evaluating*xfail*expression*", - " syntax error", - markline, - "SyntaxError: invalid syntax", - "*1 pass*2 error*", - ] - ) - - -def test_xfail_skipif_with_globals(testdir): - testdir.makepyfile( - """ - import pytest - x = 3 - @pytest.mark.skipif("x == 3") - def test_skip1(): - pass - @pytest.mark.xfail("x == 3") - def test_boolean(): - assert 0 - """ - ) - result = testdir.runpytest("-rsx") - result.stdout.fnmatch_lines(["*SKIP*x == 3*", "*XFAIL*test_boolean*", "*x == 3*"]) - - -def test_direct_gives_error(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skipif(True) - def test_skip1(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 error*"]) - - -def test_default_markers(testdir): - result = testdir.runpytest("--markers") - result.stdout.fnmatch_lines( - [ - "*skipif(*condition)*skip*", - "*xfail(*condition, reason=None, run=True, raises=None, strict=False)*expected failure*", - ] - ) - - -def test_xfail_test_setup_exception(testdir): - testdir.makeconftest( - """ - def pytest_runtest_setup(): - 0 / 0 - """ - ) - p = testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail - def test_func(): - assert 0 - """ - ) - result = testdir.runpytest(p) - assert result.ret == 0 - assert "xfailed" in result.stdout.str() - assert "xpassed" not in result.stdout.str() - - -def test_imperativeskip_on_xfail_test(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail - def test_that_fails(): - assert 0 - - @pytest.mark.skipif("True") - def test_hello(): - pass - """ - ) - testdir.makeconftest( - """ - import pytest - def pytest_runtest_setup(item): - pytest.skip("abc") - """ - ) - result = testdir.runpytest("-rsxX") - result.stdout.fnmatch_lines_random( - """ - *SKIP*abc* - *SKIP*condition: True* - *2 skipped* - """ - ) - - -class TestBooleanCondition(object): - - def test_skipif(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skipif(True, reason="True123") - def test_func1(): - pass - @pytest.mark.skipif(False, reason="True123") - def test_func2(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *1 passed*1 skipped* - """ - ) - - def test_skipif_noreason(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.skipif(True) - def test_func(): - pass - """ - ) - result = testdir.runpytest("-rs") - result.stdout.fnmatch_lines( - """ - *1 error* - """ - ) - - def test_xfail(self, testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.xfail(True, reason="True123") - def test_func(): - assert 0 - """ - ) - result = testdir.runpytest("-rxs") - result.stdout.fnmatch_lines( - """ - *XFAIL* - *True123* - *1 xfail* - """ - ) - - -def test_xfail_item(testdir): - # Ensure pytest.xfail works with non-Python Item - testdir.makeconftest( - """ - import pytest - - class MyItem(pytest.Item): - nodeid = 'foo' - def runtest(self): - pytest.xfail("Expected Failure") - - def pytest_collect_file(path, parent): - return MyItem("foo", parent) - """ - ) - result = testdir.inline_run() - passed, skipped, failed = result.listoutcomes() - assert not failed - xfailed = [r for r in skipped if hasattr(r, "wasxfail")] - assert xfailed - - -def test_module_level_skip_error(testdir): - """ - Verify that using pytest.skip at module level causes a collection error - """ - testdir.makepyfile( - """ - import pytest - @pytest.skip - def test_func(): - assert True - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*Using pytest.skip outside of a test is not allowed*") - - -def test_module_level_skip_with_allow_module_level(testdir): - """ - Verify that using pytest.skip(allow_module_level=True) is allowed - """ - testdir.makepyfile( - """ - import pytest - pytest.skip("skip_module_level", allow_module_level=True) - - def test_func(): - assert 0 - """ - ) - result = testdir.runpytest("-rxs") - result.stdout.fnmatch_lines("*SKIP*skip_module_level") - - -def test_invalid_skip_keyword_parameter(testdir): - """ - Verify that using pytest.skip() with unknown parameter raises an error - """ - testdir.makepyfile( - """ - import pytest - pytest.skip("skip_module_level", unknown=1) - - def test_func(): - assert 0 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*TypeError:*['unknown']*") - - -def test_mark_xfail_item(testdir): - # Ensure pytest.mark.xfail works with non-Python Item - testdir.makeconftest( - """ - import pytest - - class MyItem(pytest.Item): - nodeid = 'foo' - def setup(self): - marker = pytest.mark.xfail(True, reason="Expected failure") - self.add_marker(marker) - def runtest(self): - assert False - - def pytest_collect_file(path, parent): - return MyItem("foo", parent) - """ - ) - result = testdir.inline_run() - passed, skipped, failed = result.listoutcomes() - assert not failed - xfailed = [r for r in skipped if hasattr(r, "wasxfail")] - assert xfailed - - -def test_summary_list_after_errors(testdir): - """Ensure the list of errors/fails/xfails/skips appears after tracebacks in terminal reporting.""" - testdir.makepyfile( - """ - import pytest - def test_fail(): - assert 0 - """ - ) - result = testdir.runpytest("-ra") - result.stdout.fnmatch_lines( - [ - "=* FAILURES *=", - "*= short test summary info =*", - "FAIL test_summary_list_after_errors.py::test_fail", - ] - ) diff --git a/third_party/python/pytest/testing/test_terminal.py b/third_party/python/pytest/testing/test_terminal.py deleted file mode 100644 index 8f08ad34fa1f..000000000000 --- a/third_party/python/pytest/testing/test_terminal.py +++ /dev/null @@ -1,1267 +0,0 @@ -""" -terminal reporting of the full testing process. -""" -from __future__ import absolute_import, division, print_function -import collections -import sys - -import pluggy -import _pytest._code -import py -import pytest -from _pytest.main import EXIT_NOTESTSCOLLECTED -from _pytest.terminal import TerminalReporter, repr_pythonversion, getreportopt -from _pytest.terminal import build_summary_stats_line, _plugin_nameversions - - -DistInfo = collections.namedtuple("DistInfo", ["project_name", "version"]) - - -class Option(object): - - def __init__(self, verbose=False, fulltrace=False): - self.verbose = verbose - self.fulltrace = fulltrace - - @property - def args(self): - values = [] - if self.verbose: - values.append("-v") - if self.fulltrace: - values.append("--fulltrace") - return values - - -@pytest.fixture( - params=[ - Option(verbose=False), - Option(verbose=True), - Option(verbose=-1), - Option(fulltrace=True), - ], - ids=["default", "verbose", "quiet", "fulltrace"], -) -def option(request): - return request.param - - -@pytest.mark.parametrize( - "input,expected", - [ - ([DistInfo(project_name="test", version=1)], ["test-1"]), - ([DistInfo(project_name="pytest-test", version=1)], ["test-1"]), - ( - [ - DistInfo(project_name="test", version=1), - DistInfo(project_name="test", version=1), - ], - ["test-1"], - ), - ], - ids=["normal", "prefix-strip", "deduplicate"], -) -def test_plugin_nameversion(input, expected): - pluginlist = [(None, x) for x in input] - result = _plugin_nameversions(pluginlist) - assert result == expected - - -class TestTerminal(object): - - def test_pass_skip_fail(self, testdir, option): - testdir.makepyfile( - """ - import pytest - def test_ok(): - pass - def test_skip(): - pytest.skip("xx") - def test_func(): - assert 0 - """ - ) - result = testdir.runpytest(*option.args) - if option.verbose: - result.stdout.fnmatch_lines( - [ - "*test_pass_skip_fail.py::test_ok PASS*", - "*test_pass_skip_fail.py::test_skip SKIP*", - "*test_pass_skip_fail.py::test_func FAIL*", - ] - ) - else: - result.stdout.fnmatch_lines(["*test_pass_skip_fail.py .sF*"]) - result.stdout.fnmatch_lines( - [" def test_func():", "> assert 0", "E assert 0"] - ) - - def test_internalerror(self, testdir, linecomp): - modcol = testdir.getmodulecol("def test_one(): pass") - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - excinfo = pytest.raises(ValueError, "raise ValueError('hello')") - rep.pytest_internalerror(excinfo.getrepr()) - linecomp.assert_contains_lines(["INTERNALERROR> *ValueError*hello*"]) - - def test_writeline(self, testdir, linecomp): - modcol = testdir.getmodulecol("def test_one(): pass") - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - rep.write_fspath_result(modcol.nodeid, ".") - rep.write_line("hello world") - lines = linecomp.stringio.getvalue().split("\n") - assert not lines[0] - assert lines[1].endswith(modcol.name + " .") - assert lines[2] == "hello world" - - def test_show_runtest_logstart(self, testdir, linecomp): - item = testdir.getitem("def test_func(): pass") - tr = TerminalReporter(item.config, file=linecomp.stringio) - item.config.pluginmanager.register(tr) - location = item.reportinfo() - tr.config.hook.pytest_runtest_logstart( - nodeid=item.nodeid, location=location, fspath=str(item.fspath) - ) - linecomp.assert_contains_lines(["*test_show_runtest_logstart.py*"]) - - def test_runtest_location_shown_before_test_starts(self, testdir): - testdir.makepyfile( - """ - def test_1(): - import time - time.sleep(20) - """ - ) - child = testdir.spawn_pytest("") - child.expect(".*test_runtest_location.*py") - child.sendeof() - child.kill(15) - - def test_itemreport_subclasses_show_subclassed_file(self, testdir): - testdir.makepyfile( - test_p1=""" - class BaseTests(object): - def test_p1(self): - pass - class TestClass(BaseTests): - pass - """ - ) - p2 = testdir.makepyfile( - test_p2=""" - from test_p1 import BaseTests - class TestMore(BaseTests): - pass - """ - ) - result = testdir.runpytest(p2) - result.stdout.fnmatch_lines(["*test_p2.py .*", "*1 passed*"]) - result = testdir.runpytest("-v", p2) - result.stdout.fnmatch_lines( - ["*test_p2.py::TestMore::test_p1* <- *test_p1.py*PASSED*"] - ) - - def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): - a = testdir.mkpydir("a123") - a.join("test_hello123.py").write( - _pytest._code.Source( - """ - class TestClass(object): - def test_method(self): - pass - """ - ) - ) - result = testdir.runpytest("-v") - assert result.ret == 0 - result.stdout.fnmatch_lines(["*a123/test_hello123.py*PASS*"]) - assert " <- " not in result.stdout.str() - - def test_keyboard_interrupt(self, testdir, option): - testdir.makepyfile( - """ - def test_foobar(): - assert 0 - def test_spamegg(): - import py; pytest.skip('skip me please!') - def test_interrupt_me(): - raise KeyboardInterrupt # simulating the user - """ - ) - - result = testdir.runpytest(*option.args, no_reraise_ctrlc=True) - result.stdout.fnmatch_lines( - [ - " def test_foobar():", - "> assert 0", - "E assert 0", - "*_keyboard_interrupt.py:6: KeyboardInterrupt*", - ] - ) - if option.fulltrace: - result.stdout.fnmatch_lines( - ["*raise KeyboardInterrupt # simulating the user*"] - ) - else: - result.stdout.fnmatch_lines( - ["(to show a full traceback on KeyboardInterrupt use --fulltrace)"] - ) - result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) - - def test_keyboard_in_sessionstart(self, testdir): - testdir.makeconftest( - """ - def pytest_sessionstart(): - raise KeyboardInterrupt - """ - ) - testdir.makepyfile( - """ - def test_foobar(): - pass - """ - ) - - result = testdir.runpytest(no_reraise_ctrlc=True) - assert result.ret == 2 - result.stdout.fnmatch_lines(["*KeyboardInterrupt*"]) - - def test_collect_single_item(self, testdir): - """Use singular 'item' when reporting a single test item""" - testdir.makepyfile( - """ - def test_foobar(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["collected 1 item"]) - - def test_rewrite(self, testdir, monkeypatch): - config = testdir.parseconfig() - f = py.io.TextIO() - monkeypatch.setattr(f, "isatty", lambda *args: True) - tr = TerminalReporter(config, f) - tr._tw.fullwidth = 10 - tr.write("hello") - tr.rewrite("hey", erase=True) - assert f.getvalue() == "hello" + "\r" + "hey" + (6 * " ") - - -class TestCollectonly(object): - - def test_collectonly_basic(self, testdir): - testdir.makepyfile( - """ - def test_func(): - pass - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines( - ["", " "] - ) - - def test_collectonly_skipped_module(self, testdir): - testdir.makepyfile( - """ - import pytest - pytest.skip("hello") - """ - ) - result = testdir.runpytest("--collect-only", "-rs") - result.stdout.fnmatch_lines(["*ERROR collecting*"]) - - def test_collectonly_failed_module(self, testdir): - testdir.makepyfile("""raise ValueError(0)""") - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*raise ValueError*", "*1 error*"]) - - def test_collectonly_fatal(self, testdir): - testdir.makeconftest( - """ - def pytest_collectstart(collector): - assert 0, "urgs" - """ - ) - result = testdir.runpytest("--collect-only") - result.stdout.fnmatch_lines(["*INTERNAL*args*"]) - assert result.ret == 3 - - def test_collectonly_simple(self, testdir): - p = testdir.makepyfile( - """ - def test_func1(): - pass - class TestClass(object): - def test_method(self): - pass - """ - ) - result = testdir.runpytest("--collect-only", p) - # assert stderr.startswith("inserting into sys.path") - assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*", - "* ", - "* ", - # "* ", - "* ", - ] - ) - - def test_collectonly_error(self, testdir): - p = testdir.makepyfile("import Errlkjqweqwe") - result = testdir.runpytest("--collect-only", p) - assert result.ret == 2 - result.stdout.fnmatch_lines( - _pytest._code.Source( - """ - *ERROR* - *ImportError* - *No module named *Errlk* - *1 error* - """ - ).strip() - ) - - def test_collectonly_missing_path(self, testdir): - """this checks issue 115, - failure in parseargs will cause session - not to have the items attribute - """ - result = testdir.runpytest("--collect-only", "uhm_missing_path") - assert result.ret == 4 - result.stderr.fnmatch_lines(["*ERROR: file not found*"]) - - def test_collectonly_quiet(self, testdir): - testdir.makepyfile("def test_foo(): pass") - result = testdir.runpytest("--collect-only", "-q") - result.stdout.fnmatch_lines(["*test_foo*"]) - - def test_collectonly_more_quiet(self, testdir): - testdir.makepyfile(test_fun="def test_foo(): pass") - result = testdir.runpytest("--collect-only", "-qq") - result.stdout.fnmatch_lines(["*test_fun.py: 1*"]) - - -def test_repr_python_version(monkeypatch): - try: - monkeypatch.setattr(sys, "version_info", (2, 5, 1, "final", 0)) - assert repr_pythonversion() == "2.5.1-final-0" - sys.version_info = x = (2, 3) - assert repr_pythonversion() == str(x) - finally: - monkeypatch.undo() # do this early as pytest can get confused - - -class TestFixtureReporting(object): - - def test_setup_fixture_error(self, testdir): - testdir.makepyfile( - """ - def setup_function(function): - print ("setup func") - assert 0 - def test_nada(): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ERROR at setup of test_nada*", - "*setup_function(function):*", - "*setup func*", - "*assert 0*", - "*1 error*", - ] - ) - assert result.ret != 0 - - def test_teardown_fixture_error(self, testdir): - testdir.makepyfile( - """ - def test_nada(): - pass - def teardown_function(function): - print ("teardown func") - assert 0 - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ERROR at teardown*", - "*teardown_function(function):*", - "*assert 0*", - "*Captured stdout*", - "*teardown func*", - "*1 passed*1 error*", - ] - ) - - def test_teardown_fixture_error_and_test_failure(self, testdir): - testdir.makepyfile( - """ - def test_fail(): - assert 0, "failingfunc" - - def teardown_function(function): - print ("teardown func") - assert False - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ERROR at teardown of test_fail*", - "*teardown_function(function):*", - "*assert False*", - "*Captured stdout*", - "*teardown func*", - "*test_fail*", - "*def test_fail():", - "*failingfunc*", - "*1 failed*1 error*", - ] - ) - - def test_setup_teardown_output_and_test_failure(self, testdir): - """ Test for issue #442 """ - testdir.makepyfile( - """ - def setup_function(function): - print ("setup func") - - def test_fail(): - assert 0, "failingfunc" - - def teardown_function(function): - print ("teardown func") - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*test_fail*", - "*def test_fail():", - "*failingfunc*", - "*Captured stdout setup*", - "*setup func*", - "*Captured stdout teardown*", - "*teardown func*", - "*1 failed*", - ] - ) - - -class TestTerminalFunctional(object): - - def test_deselected(self, testdir): - testpath = testdir.makepyfile( - """ - def test_one(): - pass - def test_two(): - pass - def test_three(): - pass - """ - ) - result = testdir.runpytest("-k", "test_two:", testpath) - result.stdout.fnmatch_lines( - ["collected 3 items / 1 deselected", "*test_deselected.py ..*"] - ) - assert result.ret == 0 - - def test_show_deselected_items_using_markexpr_before_test_execution(self, testdir): - testdir.makepyfile( - """ - import pytest - - @pytest.mark.foo - def test_foobar(): - pass - - @pytest.mark.bar - def test_bar(): - pass - - def test_pass(): - pass - """ - ) - result = testdir.runpytest("-m", "not foo") - result.stdout.fnmatch_lines( - [ - "collected 3 items / 1 deselected", - "*test_show_des*.py ..*", - "*= 2 passed, 1 deselected in * =*", - ] - ) - assert "= 1 deselected =" not in result.stdout.str() - assert result.ret == 0 - - def test_no_skip_summary_if_failure(self, testdir): - testdir.makepyfile( - """ - import pytest - def test_ok(): - pass - def test_fail(): - assert 0 - def test_skip(): - pytest.skip("dontshow") - """ - ) - result = testdir.runpytest() - assert result.stdout.str().find("skip test summary") == -1 - assert result.ret == 1 - - def test_passes(self, testdir): - p1 = testdir.makepyfile( - """ - def test_passes(): - pass - class TestClass(object): - def test_method(self): - pass - """ - ) - old = p1.dirpath().chdir() - try: - result = testdir.runpytest() - finally: - old.chdir() - result.stdout.fnmatch_lines(["test_passes.py ..*", "* 2 pass*"]) - assert result.ret == 0 - - def test_header_trailer_info(self, testdir): - testdir.makepyfile( - """ - def test_passes(): - pass - """ - ) - result = testdir.runpytest() - verinfo = ".".join(map(str, sys.version_info[:3])) - result.stdout.fnmatch_lines( - [ - "*===== test session starts ====*", - "platform %s -- Python %s*pytest-%s*py-%s*pluggy-%s" - % ( - sys.platform, - verinfo, - pytest.__version__, - py.__version__, - pluggy.__version__, - ), - "*test_header_trailer_info.py .*", - "=* 1 passed*in *.[0-9][0-9] seconds *=", - ] - ) - if pytest.config.pluginmanager.list_plugin_distinfo(): - result.stdout.fnmatch_lines(["plugins: *"]) - - def test_showlocals(self, testdir): - p1 = testdir.makepyfile( - """ - def test_showlocals(): - x = 3 - y = "x" * 5000 - assert 0 - """ - ) - result = testdir.runpytest(p1, "-l") - result.stdout.fnmatch_lines( - [ - # "_ _ * Locals *", - "x* = 3", - "y* = 'xxxxxx*", - ] - ) - - def test_verbose_reporting(self, testdir, pytestconfig): - p1 = testdir.makepyfile( - """ - import pytest - def test_fail(): - raise ValueError() - def test_pass(): - pass - class TestClass(object): - def test_skip(self): - pytest.skip("hello") - def test_gen(): - def check(x): - assert x == 1 - yield check, 0 - """ - ) - result = testdir.runpytest(p1, "-v") - result.stdout.fnmatch_lines( - [ - "*test_verbose_reporting.py::test_fail *FAIL*", - "*test_verbose_reporting.py::test_pass *PASS*", - "*test_verbose_reporting.py::TestClass::test_skip *SKIP*", - "*test_verbose_reporting.py::test_gen*0* *FAIL*", - ] - ) - assert result.ret == 1 - - if not pytestconfig.pluginmanager.get_plugin("xdist"): - pytest.skip("xdist plugin not installed") - - result = testdir.runpytest(p1, "-v", "-n 1") - result.stdout.fnmatch_lines(["*FAIL*test_verbose_reporting.py::test_fail*"]) - assert result.ret == 1 - - def test_quiet_reporting(self, testdir): - p1 = testdir.makepyfile("def test_pass(): pass") - result = testdir.runpytest(p1, "-q") - s = result.stdout.str() - assert "test session starts" not in s - assert p1.basename not in s - assert "===" not in s - assert "passed" in s - - def test_more_quiet_reporting(self, testdir): - p1 = testdir.makepyfile("def test_pass(): pass") - result = testdir.runpytest(p1, "-qq") - s = result.stdout.str() - assert "test session starts" not in s - assert p1.basename not in s - assert "===" not in s - assert "passed" not in s - - def test_report_collectionfinish_hook(self, testdir): - testdir.makeconftest( - """ - def pytest_report_collectionfinish(config, startdir, items): - return ['hello from hook: {0} items'.format(len(items))] - """ - ) - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('i', range(3)) - def test(i): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["collected 3 items", "hello from hook: 3 items"]) - - -def test_fail_extra_reporting(testdir): - testdir.makepyfile("def test_this(): assert 0") - result = testdir.runpytest() - assert "short test summary" not in result.stdout.str() - result = testdir.runpytest("-rf") - result.stdout.fnmatch_lines(["*test summary*", "FAIL*test_fail_extra_reporting*"]) - - -def test_fail_reporting_on_pass(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("-rf") - assert "short test summary" not in result.stdout.str() - - -def test_pass_extra_reporting(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest() - assert "short test summary" not in result.stdout.str() - result = testdir.runpytest("-rp") - result.stdout.fnmatch_lines(["*test summary*", "PASS*test_pass_extra_reporting*"]) - - -def test_pass_reporting_on_fail(testdir): - testdir.makepyfile("def test_this(): assert 0") - result = testdir.runpytest("-rp") - assert "short test summary" not in result.stdout.str() - - -def test_pass_output_reporting(testdir): - testdir.makepyfile( - """ - def test_pass_output(): - print("Four score and seven years ago...") - """ - ) - result = testdir.runpytest() - assert "Four score and seven years ago..." not in result.stdout.str() - result = testdir.runpytest("-rP") - result.stdout.fnmatch_lines(["Four score and seven years ago..."]) - - -def test_color_yes(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("--color=yes") - assert "test session starts" in result.stdout.str() - assert "\x1b[1m" in result.stdout.str() - - -def test_color_no(testdir): - testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest("--color=no") - assert "test session starts" in result.stdout.str() - assert "\x1b[1m" not in result.stdout.str() - - -@pytest.mark.parametrize("verbose", [True, False]) -def test_color_yes_collection_on_non_atty(testdir, verbose): - """skip collect progress report when working on non-terminals. - #1397 - """ - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize('i', range(10)) - def test_this(i): - assert 1 - """ - ) - args = ["--color=yes"] - if verbose: - args.append("-vv") - result = testdir.runpytest(*args) - assert "test session starts" in result.stdout.str() - assert "\x1b[1m" in result.stdout.str() - assert "collecting 10 items" not in result.stdout.str() - if verbose: - assert "collecting ..." in result.stdout.str() - assert "collected 10 items" in result.stdout.str() - - -def test_getreportopt(): - - class Config(object): - - class Option(object): - reportchars = "" - disable_warnings = True - - option = Option() - - config = Config() - - config.option.reportchars = "sf" - assert getreportopt(config) == "sf" - - config.option.reportchars = "sfxw" - assert getreportopt(config) == "sfx" - - config.option.reportchars = "sfx" - config.option.disable_warnings = False - assert getreportopt(config) == "sfxw" - - config.option.reportchars = "sfxw" - config.option.disable_warnings = False - assert getreportopt(config) == "sfxw" - - -def test_terminalreporter_reportopt_addopts(testdir): - testdir.makeini("[pytest]\naddopts=-rs") - testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def tr(request): - tr = request.config.pluginmanager.getplugin("terminalreporter") - return tr - def test_opt(tr): - assert tr.hasopt('skipped') - assert not tr.hasopt('qwe') - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*1 passed*"]) - - -def test_tbstyle_short(testdir): - p = testdir.makepyfile( - """ - import pytest - - @pytest.fixture - def arg(request): - return 42 - def test_opt(arg): - x = 0 - assert x - """ - ) - result = testdir.runpytest("--tb=short") - s = result.stdout.str() - assert "arg = 42" not in s - assert "x = 0" not in s - result.stdout.fnmatch_lines(["*%s:8*" % p.basename, " assert x", "E assert*"]) - result = testdir.runpytest() - s = result.stdout.str() - assert "x = 0" in s - assert "assert x" in s - - -def test_traceconfig(testdir, monkeypatch): - result = testdir.runpytest("--traceconfig") - result.stdout.fnmatch_lines(["*active plugins*"]) - assert result.ret == EXIT_NOTESTSCOLLECTED - - -class TestGenericReporting(object): - """ this test class can be subclassed with a different option - provider to run e.g. distributed tests. - """ - - def test_collect_fail(self, testdir, option): - testdir.makepyfile("import xyz\n") - result = testdir.runpytest(*option.args) - result.stdout.fnmatch_lines( - ["ImportError while importing*", "*No module named *xyz*", "*1 error*"] - ) - - def test_maxfailures(self, testdir, option): - testdir.makepyfile( - """ - def test_1(): - assert 0 - def test_2(): - assert 0 - def test_3(): - assert 0 - """ - ) - result = testdir.runpytest("--maxfail=2", *option.args) - result.stdout.fnmatch_lines( - ["*def test_1():*", "*def test_2():*", "*2 failed*"] - ) - - def test_tb_option(self, testdir, option): - testdir.makepyfile( - """ - import pytest - def g(): - raise IndexError - def test_func(): - print (6*7) - g() # --calling-- - """ - ) - for tbopt in ["long", "short", "no"]: - print("testing --tb=%s..." % tbopt) - result = testdir.runpytest("--tb=%s" % tbopt) - s = result.stdout.str() - if tbopt == "long": - assert "print (6*7)" in s - else: - assert "print (6*7)" not in s - if tbopt != "no": - assert "--calling--" in s - assert "IndexError" in s - else: - assert "FAILURES" not in s - assert "--calling--" not in s - assert "IndexError" not in s - - def test_tb_crashline(self, testdir, option): - p = testdir.makepyfile( - """ - import pytest - def g(): - raise IndexError - def test_func1(): - print (6*7) - g() # --calling-- - def test_func2(): - assert 0, "hello" - """ - ) - result = testdir.runpytest("--tb=line") - bn = p.basename - result.stdout.fnmatch_lines( - ["*%s:3: IndexError*" % bn, "*%s:8: AssertionError: hello*" % bn] - ) - s = result.stdout.str() - assert "def test_func2" not in s - - def test_pytest_report_header(self, testdir, option): - testdir.makeconftest( - """ - def pytest_sessionstart(session): - session.config._somevalue = 42 - def pytest_report_header(config): - return "hello: %s" % config._somevalue - """ - ) - testdir.mkdir("a").join("conftest.py").write( - """ -def pytest_report_header(config, startdir): - return ["line1", str(startdir)] -""" - ) - result = testdir.runpytest("a") - result.stdout.fnmatch_lines(["*hello: 42*", "line1", str(testdir.tmpdir)]) - - def test_show_capture(self, testdir): - testdir.makepyfile( - """ - import sys - import logging - def test_one(): - sys.stdout.write('!This is stdout!') - sys.stderr.write('!This is stderr!') - logging.warning('!This is a warning log msg!') - assert False, 'Something failed' - """ - ) - - result = testdir.runpytest("--tb=short") - result.stdout.fnmatch_lines( - [ - "!This is stdout!", - "!This is stderr!", - "*WARNING*!This is a warning log msg!", - ] - ) - - result = testdir.runpytest("--show-capture=all", "--tb=short") - result.stdout.fnmatch_lines( - [ - "!This is stdout!", - "!This is stderr!", - "*WARNING*!This is a warning log msg!", - ] - ) - - stdout = testdir.runpytest("--show-capture=stdout", "--tb=short").stdout.str() - assert "!This is stderr!" not in stdout - assert "!This is stdout!" in stdout - assert "!This is a warning log msg!" not in stdout - - stdout = testdir.runpytest("--show-capture=stderr", "--tb=short").stdout.str() - assert "!This is stdout!" not in stdout - assert "!This is stderr!" in stdout - assert "!This is a warning log msg!" not in stdout - - stdout = testdir.runpytest("--show-capture=log", "--tb=short").stdout.str() - assert "!This is stdout!" not in stdout - assert "!This is stderr!" not in stdout - assert "!This is a warning log msg!" in stdout - - stdout = testdir.runpytest("--show-capture=no", "--tb=short").stdout.str() - assert "!This is stdout!" not in stdout - assert "!This is stderr!" not in stdout - assert "!This is a warning log msg!" not in stdout - - -@pytest.mark.xfail("not hasattr(os, 'dup')") -def test_fdopen_kept_alive_issue124(testdir): - testdir.makepyfile( - """ - import os, sys - k = [] - def test_open_file_and_keep_alive(capfd): - stdout = os.fdopen(1, 'w', 1) - k.append(stdout) - - def test_close_kept_alive_file(): - stdout = k.pop() - stdout.close() - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_tbstyle_native_setup_error(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture - def setup_error_fixture(): - raise Exception("error in exception") - - def test_error_fixture(setup_error_fixture): - pass - """ - ) - result = testdir.runpytest("--tb=native") - result.stdout.fnmatch_lines( - ['*File *test_tbstyle_native_setup_error.py", line *, in setup_error_fixture*'] - ) - - -def test_terminal_summary(testdir): - testdir.makeconftest( - """ - def pytest_terminal_summary(terminalreporter, exitstatus): - w = terminalreporter - w.section("hello") - w.line("world") - w.line("exitstatus: {0}".format(exitstatus)) - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - """ - *==== hello ====* - world - exitstatus: 5 - """ - ) - - -def test_terminal_summary_warnings_are_displayed(testdir): - """Test that warnings emitted during pytest_terminal_summary are displayed. - (#1305). - """ - testdir.makeconftest( - """ - def pytest_terminal_summary(terminalreporter): - config = terminalreporter.config - config.warn('C1', 'internal warning') - """ - ) - result = testdir.runpytest("-rw") - result.stdout.fnmatch_lines( - ["", "*internal warning", "*== 1 warnings in *"] - ) - assert "None" not in result.stdout.str() - - -@pytest.mark.parametrize( - "exp_color, exp_line, stats_arg", - [ - # The method under test only cares about the length of each - # dict value, not the actual contents, so tuples of anything - # suffice - # Important statuses -- the highest priority of these always wins - ("red", "1 failed", {"failed": (1,)}), - ("red", "1 failed, 1 passed", {"failed": (1,), "passed": (1,)}), - ("red", "1 error", {"error": (1,)}), - ("red", "1 passed, 1 error", {"error": (1,), "passed": (1,)}), - # (a status that's not known to the code) - ("yellow", "1 weird", {"weird": (1,)}), - ("yellow", "1 passed, 1 weird", {"weird": (1,), "passed": (1,)}), - ("yellow", "1 warnings", {"warnings": (1,)}), - ("yellow", "1 passed, 1 warnings", {"warnings": (1,), "passed": (1,)}), - ("green", "5 passed", {"passed": (1, 2, 3, 4, 5)}), - # "Boring" statuses. These have no effect on the color of the summary - # line. Thus, if *every* test has a boring status, the summary line stays - # at its default color, i.e. yellow, to warn the user that the test run - # produced no useful information - ("yellow", "1 skipped", {"skipped": (1,)}), - ("green", "1 passed, 1 skipped", {"skipped": (1,), "passed": (1,)}), - ("yellow", "1 deselected", {"deselected": (1,)}), - ("green", "1 passed, 1 deselected", {"deselected": (1,), "passed": (1,)}), - ("yellow", "1 xfailed", {"xfailed": (1,)}), - ("green", "1 passed, 1 xfailed", {"xfailed": (1,), "passed": (1,)}), - ("yellow", "1 xpassed", {"xpassed": (1,)}), - ("green", "1 passed, 1 xpassed", {"xpassed": (1,), "passed": (1,)}), - # Likewise if no tests were found at all - ("yellow", "no tests ran", {}), - # Test the empty-key special case - ("yellow", "no tests ran", {"": (1,)}), - ("green", "1 passed", {"": (1,), "passed": (1,)}), - # A couple more complex combinations - ( - "red", - "1 failed, 2 passed, 3 xfailed", - {"passed": (1, 2), "failed": (1,), "xfailed": (1, 2, 3)}, - ), - ( - "green", - "1 passed, 2 skipped, 3 deselected, 2 xfailed", - { - "passed": (1,), - "skipped": (1, 2), - "deselected": (1, 2, 3), - "xfailed": (1, 2), - }, - ), - ], -) -def test_summary_stats(exp_line, exp_color, stats_arg): - print("Based on stats: %s" % stats_arg) - print('Expect summary: "%s"; with color "%s"' % (exp_line, exp_color)) - (line, color) = build_summary_stats_line(stats_arg) - print('Actually got: "%s"; with color "%s"' % (line, color)) - assert line == exp_line - assert color == exp_color - - -def test_no_trailing_whitespace_after_inifile_word(testdir): - result = testdir.runpytest("") - assert "inifile:\n" in result.stdout.str() - - testdir.makeini("[pytest]") - result = testdir.runpytest("") - assert "inifile: tox.ini\n" in result.stdout.str() - - -class TestProgress(object): - - @pytest.fixture - def many_tests_files(self, testdir): - testdir.makepyfile( - test_bar=""" - import pytest - @pytest.mark.parametrize('i', range(10)) - def test_bar(i): pass - """, - test_foo=""" - import pytest - @pytest.mark.parametrize('i', range(5)) - def test_foo(i): pass - """, - test_foobar=""" - import pytest - @pytest.mark.parametrize('i', range(5)) - def test_foobar(i): pass - """, - ) - - def test_zero_tests_collected(self, testdir): - """Some plugins (testmon for example) might issue pytest_runtest_logreport without any tests being - actually collected (#2971).""" - testdir.makeconftest( - """ - def pytest_collection_modifyitems(items, config): - from _pytest.runner import CollectReport - for node_id in ('nodeid1', 'nodeid2'): - rep = CollectReport(node_id, 'passed', None, None) - rep.when = 'passed' - rep.duration = 0.1 - config.hook.pytest_runtest_logreport(report=rep) - """ - ) - output = testdir.runpytest() - assert "ZeroDivisionError" not in output.stdout.str() - output.stdout.fnmatch_lines(["=* 2 passed in *="]) - - def test_normal(self, many_tests_files, testdir): - output = testdir.runpytest() - output.stdout.re_match_lines( - [ - r"test_bar.py \.{10} \s+ \[ 50%\]", - r"test_foo.py \.{5} \s+ \[ 75%\]", - r"test_foobar.py \.{5} \s+ \[100%\]", - ] - ) - - def test_verbose(self, many_tests_files, testdir): - output = testdir.runpytest("-v") - output.stdout.re_match_lines( - [ - r"test_bar.py::test_bar\[0\] PASSED \s+ \[ 5%\]", - r"test_foo.py::test_foo\[4\] PASSED \s+ \[ 75%\]", - r"test_foobar.py::test_foobar\[4\] PASSED \s+ \[100%\]", - ] - ) - - def test_xdist_normal(self, many_tests_files, testdir): - pytest.importorskip("xdist") - output = testdir.runpytest("-n2") - output.stdout.re_match_lines([r"\.{20} \s+ \[100%\]"]) - - def test_xdist_verbose(self, many_tests_files, testdir): - pytest.importorskip("xdist") - output = testdir.runpytest("-n2", "-v") - output.stdout.re_match_lines_random( - [ - r"\[gw\d\] \[\s*\d+%\] PASSED test_bar.py::test_bar\[1\]", - r"\[gw\d\] \[\s*\d+%\] PASSED test_foo.py::test_foo\[1\]", - r"\[gw\d\] \[\s*\d+%\] PASSED test_foobar.py::test_foobar\[1\]", - ] - ) - - def test_capture_no(self, many_tests_files, testdir): - output = testdir.runpytest("-s") - output.stdout.re_match_lines( - [r"test_bar.py \.{10}", r"test_foo.py \.{5}", r"test_foobar.py \.{5}"] - ) - - output = testdir.runpytest("--capture=no") - assert "%]" not in output.stdout.str() - - -class TestProgressWithTeardown(object): - """Ensure we show the correct percentages for tests that fail during teardown (#3088)""" - - @pytest.fixture - def contest_with_teardown_fixture(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def fail_teardown(): - yield - assert False - """ - ) - - @pytest.fixture - def many_files(self, testdir, contest_with_teardown_fixture): - testdir.makepyfile( - test_bar=""" - import pytest - @pytest.mark.parametrize('i', range(5)) - def test_bar(fail_teardown, i): - pass - """, - test_foo=""" - import pytest - @pytest.mark.parametrize('i', range(15)) - def test_foo(fail_teardown, i): - pass - """, - ) - - def test_teardown_simple(self, testdir, contest_with_teardown_fixture): - testdir.makepyfile( - """ - def test_foo(fail_teardown): - pass - """ - ) - output = testdir.runpytest() - output.stdout.re_match_lines([r"test_teardown_simple.py \.E\s+\[100%\]"]) - - def test_teardown_with_test_also_failing( - self, testdir, contest_with_teardown_fixture - ): - testdir.makepyfile( - """ - def test_foo(fail_teardown): - assert False - """ - ) - output = testdir.runpytest() - output.stdout.re_match_lines( - [r"test_teardown_with_test_also_failing.py FE\s+\[100%\]"] - ) - - def test_teardown_many(self, testdir, many_files): - output = testdir.runpytest() - output.stdout.re_match_lines( - [r"test_bar.py (\.E){5}\s+\[ 25%\]", r"test_foo.py (\.E){15}\s+\[100%\]"] - ) - - def test_teardown_many_verbose(self, testdir, many_files): - output = testdir.runpytest("-v") - output.stdout.re_match_lines( - [ - r"test_bar.py::test_bar\[0\] PASSED\s+\[ 5%\]", - r"test_bar.py::test_bar\[0\] ERROR\s+\[ 5%\]", - r"test_bar.py::test_bar\[4\] PASSED\s+\[ 25%\]", - r"test_bar.py::test_bar\[4\] ERROR\s+\[ 25%\]", - ] - ) - - def test_xdist_normal(self, many_files, testdir): - pytest.importorskip("xdist") - output = testdir.runpytest("-n2") - output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"]) diff --git a/third_party/python/pytest/testing/test_tmpdir.py b/third_party/python/pytest/testing/test_tmpdir.py deleted file mode 100644 index 336249094957..000000000000 --- a/third_party/python/pytest/testing/test_tmpdir.py +++ /dev/null @@ -1,212 +0,0 @@ -from __future__ import absolute_import, division, print_function -import sys -import py -import pytest - -from _pytest.tmpdir import tmpdir - - -def test_funcarg(testdir): - testdir.makepyfile( - """ - def pytest_generate_tests(metafunc): - metafunc.addcall(id='a') - metafunc.addcall(id='b') - def test_func(tmpdir): pass - """ - ) - from _pytest.tmpdir import TempdirFactory - - reprec = testdir.inline_run() - calls = reprec.getcalls("pytest_runtest_setup") - item = calls[0].item - config = item.config - tmpdirhandler = TempdirFactory(config) - item._initrequest() - p = tmpdir(item._request, tmpdirhandler) - assert p.check() - bn = p.basename.strip("0123456789") - assert bn.endswith("test_func_a_") - item.name = "qwe/\\abc" - p = tmpdir(item._request, tmpdirhandler) - assert p.check() - bn = p.basename.strip("0123456789") - assert bn == "qwe__abc" - - -def test_ensuretemp(recwarn): - d1 = pytest.ensuretemp("hello") - d2 = pytest.ensuretemp("hello") - assert d1 == d2 - assert d1.check(dir=1) - - -class TestTempdirHandler(object): - - def test_mktemp(self, testdir): - from _pytest.tmpdir import TempdirFactory - - config = testdir.parseconfig() - config.option.basetemp = testdir.mkdir("hello") - t = TempdirFactory(config) - tmp = t.mktemp("world") - assert tmp.relto(t.getbasetemp()) == "world0" - tmp = t.mktemp("this") - assert tmp.relto(t.getbasetemp()).startswith("this") - tmp2 = t.mktemp("this") - assert tmp2.relto(t.getbasetemp()).startswith("this") - assert tmp2 != tmp - - -class TestConfigTmpdir(object): - - def test_getbasetemp_custom_removes_old(self, testdir): - mytemp = testdir.tmpdir.join("xyz") - p = testdir.makepyfile( - """ - def test_1(tmpdir): - pass - """ - ) - testdir.runpytest(p, "--basetemp=%s" % mytemp) - mytemp.check() - mytemp.ensure("hello") - - testdir.runpytest(p, "--basetemp=%s" % mytemp) - mytemp.check() - assert not mytemp.join("hello").check() - - -def test_basetemp(testdir): - mytemp = testdir.tmpdir.mkdir("mytemp") - p = testdir.makepyfile( - """ - import pytest - def test_1(): - pytest.ensuretemp("hello") - """ - ) - result = testdir.runpytest(p, "--basetemp=%s" % mytemp) - assert result.ret == 0 - assert mytemp.join("hello").check() - - -@pytest.mark.skipif( - not hasattr(py.path.local, "mksymlinkto"), - reason="symlink not available on this platform", -) -def test_tmpdir_always_is_realpath(testdir): - # the reason why tmpdir should be a realpath is that - # when you cd to it and do "os.getcwd()" you will anyway - # get the realpath. Using the symlinked path can thus - # easily result in path-inequality - # XXX if that proves to be a problem, consider using - # os.environ["PWD"] - realtemp = testdir.tmpdir.mkdir("myrealtemp") - linktemp = testdir.tmpdir.join("symlinktemp") - linktemp.mksymlinkto(realtemp) - p = testdir.makepyfile( - """ - def test_1(tmpdir): - import os - assert os.path.realpath(str(tmpdir)) == str(tmpdir) - """ - ) - result = testdir.runpytest("-s", p, "--basetemp=%s/bt" % linktemp) - assert not result.ret - - -def test_tmpdir_too_long_on_parametrization(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.mark.parametrize("arg", ["1"*1000]) - def test_some(arg, tmpdir): - tmpdir.ensure("hello") - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -def test_tmpdir_factory(testdir): - testdir.makepyfile( - """ - import pytest - @pytest.fixture(scope='session') - def session_dir(tmpdir_factory): - return tmpdir_factory.mktemp('data', numbered=False) - def test_some(session_dir): - session_dir.isdir() - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -def test_tmpdir_fallback_tox_env(testdir, monkeypatch): - """Test that tmpdir works even if environment variables required by getpass - module are missing (#1010). - """ - monkeypatch.delenv("USER", raising=False) - monkeypatch.delenv("USERNAME", raising=False) - testdir.makepyfile( - """ - import pytest - def test_some(tmpdir): - assert tmpdir.isdir() - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -@pytest.fixture -def break_getuser(monkeypatch): - monkeypatch.setattr("os.getuid", lambda: -1) - # taken from python 2.7/3.4 - for envvar in ("LOGNAME", "USER", "LNAME", "USERNAME"): - monkeypatch.delenv(envvar, raising=False) - - -@pytest.mark.usefixtures("break_getuser") -@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows") -def test_tmpdir_fallback_uid_not_found(testdir): - """Test that tmpdir works even if the current process's user id does not - correspond to a valid user. - """ - - testdir.makepyfile( - """ - import pytest - def test_some(tmpdir): - assert tmpdir.isdir() - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -@pytest.mark.usefixtures("break_getuser") -@pytest.mark.skipif(sys.platform.startswith("win"), reason="no os.getuid on windows") -def test_get_user_uid_not_found(): - """Test that get_user() function works even if the current process's - user id does not correspond to a valid user (e.g. running pytest in a - Docker container with 'docker run -u'. - """ - from _pytest.tmpdir import get_user - - assert get_user() is None - - -@pytest.mark.skipif(not sys.platform.startswith("win"), reason="win only") -def test_get_user(monkeypatch): - """Test that get_user() function works even if environment variables - required by getpass module are missing from the environment on Windows - (#1010). - """ - from _pytest.tmpdir import get_user - - monkeypatch.delenv("USER", raising=False) - monkeypatch.delenv("USERNAME", raising=False) - assert get_user() is None diff --git a/third_party/python/pytest/testing/test_unittest.py b/third_party/python/pytest/testing/test_unittest.py deleted file mode 100644 index 65ffdb97538b..000000000000 --- a/third_party/python/pytest/testing/test_unittest.py +++ /dev/null @@ -1,992 +0,0 @@ -from __future__ import absolute_import, division, print_function -from _pytest.main import EXIT_NOTESTSCOLLECTED -import pytest -import gc - - -def test_simple_unittest(testdir): - testpath = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - def testpassing(self): - self.assertEqual('foo', 'foo') - def test_failing(self): - self.assertEqual('foo', 'bar') - """ - ) - reprec = testdir.inline_run(testpath) - assert reprec.matchreport("testpassing").passed - assert reprec.matchreport("test_failing").failed - - -def test_runTest_method(testdir): - testdir.makepyfile( - """ - import unittest - class MyTestCaseWithRunTest(unittest.TestCase): - def runTest(self): - self.assertEqual('foo', 'foo') - class MyTestCaseWithoutRunTest(unittest.TestCase): - def runTest(self): - self.assertEqual('foo', 'foo') - def test_something(self): - pass - """ - ) - result = testdir.runpytest("-v") - result.stdout.fnmatch_lines( - """ - *MyTestCaseWithRunTest::runTest* - *MyTestCaseWithoutRunTest::test_something* - *2 passed* - """ - ) - - -def test_isclasscheck_issue53(testdir): - testpath = testdir.makepyfile( - """ - import unittest - class _E(object): - def __getattr__(self, tag): - pass - E = _E() - """ - ) - result = testdir.runpytest(testpath) - assert result.ret == EXIT_NOTESTSCOLLECTED - - -def test_setup(testdir): - testpath = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - def setUp(self): - self.foo = 1 - def setup_method(self, method): - self.foo2 = 1 - def test_both(self): - self.assertEqual(1, self.foo) - assert self.foo2 == 1 - def teardown_method(self, method): - assert 0, "42" - - """ - ) - reprec = testdir.inline_run("-s", testpath) - assert reprec.matchreport("test_both", when="call").passed - rep = reprec.matchreport("test_both", when="teardown") - assert rep.failed and "42" in str(rep.longrepr) - - -def test_setUpModule(testdir): - testpath = testdir.makepyfile( - """ - values = [] - - def setUpModule(): - values.append(1) - - def tearDownModule(): - del values[0] - - def test_hello(): - assert values == [1] - - def test_world(): - assert values == [1] - """ - ) - result = testdir.runpytest(testpath) - result.stdout.fnmatch_lines(["*2 passed*"]) - - -def test_setUpModule_failing_no_teardown(testdir): - testpath = testdir.makepyfile( - """ - values = [] - - def setUpModule(): - 0/0 - - def tearDownModule(): - values.append(1) - - def test_hello(): - pass - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=0, failed=1) - call = reprec.getcalls("pytest_runtest_setup")[0] - assert not call.item.module.values - - -def test_new_instances(testdir): - testpath = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - def test_func1(self): - self.x = 2 - def test_func2(self): - assert not hasattr(self, 'x') - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=2) - - -def test_teardown(testdir): - testpath = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - values = [] - def test_one(self): - pass - def tearDown(self): - self.values.append(None) - class Second(unittest.TestCase): - def test_check(self): - self.assertEqual(MyTestCase.values, [None]) - """ - ) - reprec = testdir.inline_run(testpath) - passed, skipped, failed = reprec.countoutcomes() - assert failed == 0, failed - assert passed == 2 - assert passed + skipped + failed == 2 - - -def test_teardown_issue1649(testdir): - """ - Are TestCase objects cleaned up? Often unittest TestCase objects set - attributes that are large and expensive during setUp. - - The TestCase will not be cleaned up if the test fails, because it - would then exist in the stackframe. - """ - testpath = testdir.makepyfile( - """ - import unittest - class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase): - def setUp(self): - self.an_expensive_object = 1 - def test_demo(self): - pass - - """ - ) - testdir.inline_run("-s", testpath) - gc.collect() - for obj in gc.get_objects(): - assert type(obj).__name__ != "TestCaseObjectsShouldBeCleanedUp" - - -def test_unittest_skip_issue148(testdir): - testpath = testdir.makepyfile( - """ - import unittest - - @unittest.skip("hello") - class MyTestCase(unittest.TestCase): - @classmethod - def setUpClass(self): - xxx - def test_one(self): - pass - @classmethod - def tearDownClass(self): - xxx - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(skipped=1) - - -def test_method_and_teardown_failing_reporting(testdir): - testdir.makepyfile( - """ - import unittest, pytest - class TC(unittest.TestCase): - def tearDown(self): - assert 0, "down1" - def test_method(self): - assert False, "down2" - """ - ) - result = testdir.runpytest("-s") - assert result.ret == 1 - result.stdout.fnmatch_lines( - [ - "*tearDown*", - "*assert 0*", - "*test_method*", - "*assert False*", - "*1 failed*1 error*", - ] - ) - - -def test_setup_failure_is_shown(testdir): - testdir.makepyfile( - """ - import unittest - import pytest - class TC(unittest.TestCase): - def setUp(self): - assert 0, "down1" - def test_method(self): - print ("never42") - xyz - """ - ) - result = testdir.runpytest("-s") - assert result.ret == 1 - result.stdout.fnmatch_lines(["*setUp*", "*assert 0*down1*", "*1 failed*"]) - assert "never42" not in result.stdout.str() - - -def test_setup_setUpClass(testdir): - testpath = testdir.makepyfile( - """ - import unittest - import pytest - class MyTestCase(unittest.TestCase): - x = 0 - @classmethod - def setUpClass(cls): - cls.x += 1 - def test_func1(self): - assert self.x == 1 - def test_func2(self): - assert self.x == 1 - @classmethod - def tearDownClass(cls): - cls.x -= 1 - def test_teareddown(): - assert MyTestCase.x == 0 - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=3) - - -def test_setup_class(testdir): - testpath = testdir.makepyfile( - """ - import unittest - import pytest - class MyTestCase(unittest.TestCase): - x = 0 - def setup_class(cls): - cls.x += 1 - def test_func1(self): - assert self.x == 1 - def test_func2(self): - assert self.x == 1 - def teardown_class(cls): - cls.x -= 1 - def test_teareddown(): - assert MyTestCase.x == 0 - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=3) - - -@pytest.mark.parametrize("type", ["Error", "Failure"]) -def test_testcase_adderrorandfailure_defers(testdir, type): - testdir.makepyfile( - """ - from unittest import TestCase - import pytest - class MyTestCase(TestCase): - def run(self, result): - excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0) - try: - result.add%s(self, excinfo._excinfo) - except KeyboardInterrupt: - raise - except: - pytest.fail("add%s should not raise") - def test_hello(self): - pass - """ - % (type, type) - ) - result = testdir.runpytest() - assert "should not raise" not in result.stdout.str() - - -@pytest.mark.parametrize("type", ["Error", "Failure"]) -def test_testcase_custom_exception_info(testdir, type): - testdir.makepyfile( - """ - from unittest import TestCase - import py, pytest - import _pytest._code - class MyTestCase(TestCase): - def run(self, result): - excinfo = pytest.raises(ZeroDivisionError, lambda: 0/0) - # we fake an incompatible exception info - from _pytest.monkeypatch import MonkeyPatch - mp = MonkeyPatch() - def t(*args): - mp.undo() - raise TypeError() - mp.setattr(_pytest._code, 'ExceptionInfo', t) - try: - excinfo = excinfo._excinfo - result.add%(type)s(self, excinfo) - finally: - mp.undo() - def test_hello(self): - pass - """ - % locals() - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "NOTE: Incompatible Exception Representation*", - "*ZeroDivisionError*", - "*1 failed*", - ] - ) - - -def test_testcase_totally_incompatible_exception_info(testdir): - item, = testdir.getitems( - """ - from unittest import TestCase - class MyTestCase(TestCase): - def test_hello(self): - pass - """ - ) - item.addError(None, 42) - excinfo = item._excinfo.pop(0) - assert "ERROR: Unknown Incompatible" in str(excinfo.getrepr()) - - -def test_module_level_pytestmark(testdir): - testpath = testdir.makepyfile( - """ - import unittest - import pytest - pytestmark = pytest.mark.xfail - class MyTestCase(unittest.TestCase): - def test_func1(self): - assert 0 - """ - ) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - -class TestTrialUnittest(object): - - def setup_class(cls): - cls.ut = pytest.importorskip("twisted.trial.unittest") - # on windows trial uses a socket for a reactor and apparently doesn't close it properly - # https://twistedmatrix.com/trac/ticket/9227 - cls.ignore_unclosed_socket_warning = ("-W", "always") - - def test_trial_testcase_runtest_not_collected(self, testdir): - testdir.makepyfile( - """ - from twisted.trial.unittest import TestCase - - class TC(TestCase): - def test_hello(self): - pass - """ - ) - reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) - reprec.assertoutcome(passed=1) - testdir.makepyfile( - """ - from twisted.trial.unittest import TestCase - - class TC(TestCase): - def runTest(self): - pass - """ - ) - reprec = testdir.inline_run(*self.ignore_unclosed_socket_warning) - reprec.assertoutcome(passed=1) - - def test_trial_exceptions_with_skips(self, testdir): - testdir.makepyfile( - """ - from twisted.trial import unittest - import pytest - class TC(unittest.TestCase): - def test_hello(self): - pytest.skip("skip_in_method") - @pytest.mark.skipif("sys.version_info != 1") - def test_hello2(self): - pass - @pytest.mark.xfail(reason="iwanto") - def test_hello3(self): - assert 0 - def test_hello4(self): - pytest.xfail("i2wanto") - def test_trial_skip(self): - pass - test_trial_skip.skip = "trialselfskip" - - def test_trial_todo(self): - assert 0 - test_trial_todo.todo = "mytodo" - - def test_trial_todo_success(self): - pass - test_trial_todo_success.todo = "mytodo" - - class TC2(unittest.TestCase): - def setup_class(cls): - pytest.skip("skip_in_setup_class") - def test_method(self): - pass - """ - ) - from _pytest.compat import _is_unittest_unexpected_success_a_failure - - should_fail = _is_unittest_unexpected_success_a_failure() - result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning) - result.stdout.fnmatch_lines_random( - [ - "*XFAIL*test_trial_todo*", - "*trialselfskip*", - "*skip_in_setup_class*", - "*iwanto*", - "*i2wanto*", - "*sys.version_info*", - "*skip_in_method*", - "*1 failed*4 skipped*3 xfailed*" - if should_fail - else "*4 skipped*3 xfail*1 xpass*", - ] - ) - assert result.ret == (1 if should_fail else 0) - - def test_trial_error(self, testdir): - testdir.makepyfile( - """ - from twisted.trial.unittest import TestCase - from twisted.internet.defer import Deferred - from twisted.internet import reactor - - class TC(TestCase): - def test_one(self): - crash - - def test_two(self): - def f(_): - crash - - d = Deferred() - d.addCallback(f) - reactor.callLater(0.3, d.callback, None) - return d - - def test_three(self): - def f(): - pass # will never get called - reactor.callLater(0.3, f) - # will crash at teardown - - def test_four(self): - def f(_): - reactor.callLater(0.3, f) - crash - - d = Deferred() - d.addCallback(f) - reactor.callLater(0.3, d.callback, None) - return d - # will crash both at test time and at teardown - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*ERRORS*", - "*DelayedCalls*", - "*test_four*", - "*NameError*crash*", - "*test_one*", - "*NameError*crash*", - "*test_three*", - "*DelayedCalls*", - "*test_two*", - "*crash*", - ] - ) - - def test_trial_pdb(self, testdir): - p = testdir.makepyfile( - """ - from twisted.trial import unittest - import pytest - class TC(unittest.TestCase): - def test_hello(self): - assert 0, "hellopdb" - """ - ) - child = testdir.spawn_pytest(p) - child.expect("hellopdb") - child.sendeof() - - def test_trial_testcase_skip_property(self, testdir): - testpath = testdir.makepyfile( - """ - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - skip = 'dont run' - def test_func(self): - pass - """ - ) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - def test_trial_testfunction_skip_property(self, testdir): - testpath = testdir.makepyfile( - """ - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - def test_func(self): - pass - test_func.skip = 'dont run' - """ - ) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - def test_trial_testcase_todo_property(self, testdir): - testpath = testdir.makepyfile( - """ - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - todo = 'dont run' - def test_func(self): - assert 0 - """ - ) - reprec = testdir.inline_run(testpath, "-s") - reprec.assertoutcome(skipped=1) - - def test_trial_testfunction_todo_property(self, testdir): - testpath = testdir.makepyfile( - """ - from twisted.trial import unittest - class MyTestCase(unittest.TestCase): - def test_func(self): - assert 0 - test_func.todo = 'dont run' - """ - ) - reprec = testdir.inline_run( - testpath, "-s", *self.ignore_unclosed_socket_warning - ) - reprec.assertoutcome(skipped=1) - - -def test_djangolike_testcase(testdir): - # contributed from Morten Breekevold - testdir.makepyfile( - """ - from unittest import TestCase, main - - class DjangoLikeTestCase(TestCase): - - def setUp(self): - print ("setUp()") - - def test_presetup_has_been_run(self): - print ("test_thing()") - self.assertTrue(hasattr(self, 'was_presetup')) - - def tearDown(self): - print ("tearDown()") - - def __call__(self, result=None): - try: - self._pre_setup() - except (KeyboardInterrupt, SystemExit): - raise - except Exception: - import sys - result.addError(self, sys.exc_info()) - return - super(DjangoLikeTestCase, self).__call__(result) - try: - self._post_teardown() - except (KeyboardInterrupt, SystemExit): - raise - except Exception: - import sys - result.addError(self, sys.exc_info()) - return - - def _pre_setup(self): - print ("_pre_setup()") - self.was_presetup = True - - def _post_teardown(self): - print ("_post_teardown()") - """ - ) - result = testdir.runpytest("-s") - assert result.ret == 0 - result.stdout.fnmatch_lines( - [ - "*_pre_setup()*", - "*setUp()*", - "*test_thing()*", - "*tearDown()*", - "*_post_teardown()*", - ] - ) - - -def test_unittest_not_shown_in_traceback(testdir): - testdir.makepyfile( - """ - import unittest - class t(unittest.TestCase): - def test_hello(self): - x = 3 - self.assertEqual(x, 4) - """ - ) - res = testdir.runpytest() - assert "failUnlessEqual" not in res.stdout.str() - - -def test_unorderable_types(testdir): - testdir.makepyfile( - """ - import unittest - class TestJoinEmpty(unittest.TestCase): - pass - - def make_test(): - class Test(unittest.TestCase): - pass - Test.__name__ = "TestFoo" - return Test - TestFoo = make_test() - """ - ) - result = testdir.runpytest() - assert "TypeError" not in result.stdout.str() - assert result.ret == EXIT_NOTESTSCOLLECTED - - -def test_unittest_typerror_traceback(testdir): - testdir.makepyfile( - """ - import unittest - class TestJoinEmpty(unittest.TestCase): - def test_hello(self, arg1): - pass - """ - ) - result = testdir.runpytest() - assert "TypeError" in result.stdout.str() - assert result.ret == 1 - - -@pytest.mark.parametrize("runner", ["pytest", "unittest"]) -def test_unittest_expected_failure_for_failing_test_is_xfail(testdir, runner): - script = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - @unittest.expectedFailure - def test_failing_test_is_xfail(self): - assert False - if __name__ == '__main__': - unittest.main() - """ - ) - if runner == "pytest": - result = testdir.runpytest("-rxX") - result.stdout.fnmatch_lines( - ["*XFAIL*MyTestCase*test_failing_test_is_xfail*", "*1 xfailed*"] - ) - else: - result = testdir.runpython(script) - result.stderr.fnmatch_lines(["*1 test in*", "*OK*(expected failures=1)*"]) - assert result.ret == 0 - - -@pytest.mark.parametrize("runner", ["pytest", "unittest"]) -def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner): - script = testdir.makepyfile( - """ - import unittest - class MyTestCase(unittest.TestCase): - @unittest.expectedFailure - def test_passing_test_is_fail(self): - assert True - if __name__ == '__main__': - unittest.main() - """ - ) - from _pytest.compat import _is_unittest_unexpected_success_a_failure - - should_fail = _is_unittest_unexpected_success_a_failure() - if runner == "pytest": - result = testdir.runpytest("-rxX") - result.stdout.fnmatch_lines( - [ - "*MyTestCase*test_passing_test_is_fail*", - "*1 failed*" if should_fail else "*1 xpassed*", - ] - ) - else: - result = testdir.runpython(script) - result.stderr.fnmatch_lines(["*1 test in*", "*(unexpected successes=1)*"]) - - assert result.ret == (1 if should_fail else 0) - - -@pytest.mark.parametrize( - "fix_type, stmt", [("fixture", "return"), ("yield_fixture", "yield")] -) -def test_unittest_setup_interaction(testdir, fix_type, stmt): - testdir.makepyfile( - """ - import unittest - import pytest - class MyTestCase(unittest.TestCase): - @pytest.{fix_type}(scope="class", autouse=True) - def perclass(self, request): - request.cls.hello = "world" - {stmt} - @pytest.{fix_type}(scope="function", autouse=True) - def perfunction(self, request): - request.instance.funcname = request.function.__name__ - {stmt} - - def test_method1(self): - assert self.funcname == "test_method1" - assert self.hello == "world" - - def test_method2(self): - assert self.funcname == "test_method2" - - def test_classattr(self): - assert self.__class__.hello == "world" - """.format( - fix_type=fix_type, stmt=stmt - ) - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*3 passed*") - - -def test_non_unittest_no_setupclass_support(testdir): - testpath = testdir.makepyfile( - """ - class TestFoo(object): - x = 0 - - @classmethod - def setUpClass(cls): - cls.x = 1 - - def test_method1(self): - assert self.x == 0 - - @classmethod - def tearDownClass(cls): - cls.x = 1 - - def test_not_teareddown(): - assert TestFoo.x == 0 - - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=2) - - -def test_no_teardown_if_setupclass_failed(testdir): - testpath = testdir.makepyfile( - """ - import unittest - - class MyTestCase(unittest.TestCase): - x = 0 - - @classmethod - def setUpClass(cls): - cls.x = 1 - assert False - - def test_func1(self): - cls.x = 10 - - @classmethod - def tearDownClass(cls): - cls.x = 100 - - def test_notTornDown(): - assert MyTestCase.x == 1 - """ - ) - reprec = testdir.inline_run(testpath) - reprec.assertoutcome(passed=1, failed=1) - - -def test_issue333_result_clearing(testdir): - testdir.makeconftest( - """ - import pytest - @pytest.hookimpl(hookwrapper=True) - def pytest_runtest_call(item): - yield - assert 0 - """ - ) - testdir.makepyfile( - """ - import unittest - class TestIt(unittest.TestCase): - def test_func(self): - 0/0 - """ - ) - - reprec = testdir.inline_run() - reprec.assertoutcome(failed=1) - - -def test_unittest_raise_skip_issue748(testdir): - testdir.makepyfile( - test_foo=""" - import unittest - - class MyTestCase(unittest.TestCase): - def test_one(self): - raise unittest.SkipTest('skipping due to reasons') - """ - ) - result = testdir.runpytest("-v", "-rs") - result.stdout.fnmatch_lines( - """ - *SKIP*[1]*test_foo.py*skipping due to reasons* - *1 skipped* - """ - ) - - -def test_unittest_skip_issue1169(testdir): - testdir.makepyfile( - test_foo=""" - import unittest - - class MyTestCase(unittest.TestCase): - @unittest.skip("skipping due to reasons") - def test_skip(self): - self.fail() - """ - ) - result = testdir.runpytest("-v", "-rs") - result.stdout.fnmatch_lines( - """ - *SKIP*[1]*skipping due to reasons* - *1 skipped* - """ - ) - - -def test_class_method_containing_test_issue1558(testdir): - testdir.makepyfile( - test_foo=""" - import unittest - - class MyTestCase(unittest.TestCase): - def test_should_run(self): - pass - def test_should_not_run(self): - pass - test_should_not_run.__test__ = False - """ - ) - reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - - -@pytest.mark.issue(3498) -@pytest.mark.parametrize( - "base", ["six.moves.builtins.object", "unittest.TestCase", "unittest2.TestCase"] -) -def test_usefixtures_marker_on_unittest(base, testdir): - module = base.rsplit(".", 1)[0] - pytest.importorskip(module) - testdir.makepyfile( - conftest=""" - import pytest - - @pytest.fixture(scope='function') - def fixture1(request, monkeypatch): - monkeypatch.setattr(request.instance, 'fixture1', True ) - - - @pytest.fixture(scope='function') - def fixture2(request, monkeypatch): - monkeypatch.setattr(request.instance, 'fixture2', True ) - - def node_and_marks(item): - print(item.nodeid) - for mark in item.iter_markers(): - print(" ", mark) - - @pytest.fixture(autouse=True) - def my_marks(request): - node_and_marks(request.node) - - def pytest_collection_modifyitems(items): - for item in items: - node_and_marks(item) - - """ - ) - - testdir.makepyfile( - """ - import pytest - import {module} - - class Tests({base}): - fixture1 = False - fixture2 = False - - @pytest.mark.usefixtures("fixture1") - def test_one(self): - assert self.fixture1 - assert not self.fixture2 - - @pytest.mark.usefixtures("fixture1", "fixture2") - def test_two(self): - assert self.fixture1 - assert self.fixture2 - - - """.format( - module=module, base=base - ) - ) - - result = testdir.runpytest("-s") - result.assert_outcomes(passed=2) diff --git a/third_party/python/pytest/testing/test_warnings.py b/third_party/python/pytest/testing/test_warnings.py deleted file mode 100644 index c5bea052a47e..000000000000 --- a/third_party/python/pytest/testing/test_warnings.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf8 -*- -from __future__ import unicode_literals - -import sys - -import pytest - - -WARNINGS_SUMMARY_HEADER = "warnings summary" - - -@pytest.fixture -def pyfile_with_warnings(testdir, request): - """ - Create a test file which calls a function in a module which generates warnings. - """ - testdir.syspathinsert() - test_name = request.function.__name__ - module_name = test_name.lstrip("test_") + "_module" - testdir.makepyfile( - **{ - module_name: """ - import warnings - def foo(): - warnings.warn(UserWarning("user warning")) - warnings.warn(RuntimeWarning("runtime warning")) - return 1 - """, - test_name: """ - import {module_name} - def test_func(): - assert {module_name}.foo() == 1 - """.format( - module_name=module_name - ), - } - ) - - -@pytest.mark.filterwarnings("always") -def test_normal_flow(testdir, pyfile_with_warnings): - """ - Check that the warnings section is displayed, containing test node ids followed by - all warnings generated by that test node. - """ - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*== %s ==*" % WARNINGS_SUMMARY_HEADER, - "*test_normal_flow.py::test_func", - "*normal_flow_module.py:3: UserWarning: user warning", - '* warnings.warn(UserWarning("user warning"))', - "*normal_flow_module.py:4: RuntimeWarning: runtime warning", - '* warnings.warn(RuntimeWarning("runtime warning"))', - "* 1 passed, 2 warnings*", - ] - ) - assert result.stdout.str().count("test_normal_flow.py::test_func") == 1 - - -@pytest.mark.filterwarnings("always") -def test_setup_teardown_warnings(testdir, pyfile_with_warnings): - testdir.makepyfile( - """ - import warnings - import pytest - - @pytest.fixture - def fix(): - warnings.warn(UserWarning("warning during setup")) - yield - warnings.warn(UserWarning("warning during teardown")) - - def test_func(fix): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*== %s ==*" % WARNINGS_SUMMARY_HEADER, - "*test_setup_teardown_warnings.py:6: UserWarning: warning during setup", - '*warnings.warn(UserWarning("warning during setup"))', - "*test_setup_teardown_warnings.py:8: UserWarning: warning during teardown", - '*warnings.warn(UserWarning("warning during teardown"))', - "* 1 passed, 2 warnings*", - ] - ) - - -@pytest.mark.parametrize("method", ["cmdline", "ini"]) -def test_as_errors(testdir, pyfile_with_warnings, method): - args = ("-W", "error") if method == "cmdline" else () - if method == "ini": - testdir.makeini( - """ - [pytest] - filterwarnings= error - """ - ) - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines( - [ - "E UserWarning: user warning", - "as_errors_module.py:3: UserWarning", - "* 1 failed in *", - ] - ) - - -@pytest.mark.parametrize("method", ["cmdline", "ini"]) -def test_ignore(testdir, pyfile_with_warnings, method): - args = ("-W", "ignore") if method == "cmdline" else () - if method == "ini": - testdir.makeini( - """ - [pytest] - filterwarnings= ignore - """ - ) - - result = testdir.runpytest(*args) - result.stdout.fnmatch_lines(["* 1 passed in *"]) - assert WARNINGS_SUMMARY_HEADER not in result.stdout.str() - - -@pytest.mark.skipif( - sys.version_info < (3, 0), reason="warnings message is unicode is ok in python3" -) -@pytest.mark.filterwarnings("always") -def test_unicode(testdir, pyfile_with_warnings): - testdir.makepyfile( - """ - # -*- coding: utf8 -*- - import warnings - import pytest - - - @pytest.fixture - def fix(): - warnings.warn(u"测试") - yield - - def test_func(fix): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*== %s ==*" % WARNINGS_SUMMARY_HEADER, - "*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*", - "* 1 passed, 1 warnings*", - ] - ) - - -@pytest.mark.skipif( - sys.version_info >= (3, 0), - reason="warnings message is broken as it is not str instance", -) -def test_py2_unicode(testdir, pyfile_with_warnings): - if ( - getattr(sys, "pypy_version_info", ())[:2] == (5, 9) - and sys.platform.startswith("win") - ): - pytest.xfail("fails with unicode error on PyPy2 5.9 and Windows (#2905)") - testdir.makepyfile( - """ - # -*- coding: utf8 -*- - import warnings - import pytest - - - @pytest.fixture - def fix(): - warnings.warn(u"测试") - yield - - @pytest.mark.filterwarnings('always') - def test_func(fix): - pass - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*== %s ==*" % WARNINGS_SUMMARY_HEADER, - "*test_py2_unicode.py:8: UserWarning: \\u6d4b\\u8bd5", - '*warnings.warn(u"\u6d4b\u8bd5")', - "*warnings.py:*: UnicodeWarning: Warning is using unicode non*", - "* 1 passed, 2 warnings*", - ] - ) - - -def test_py2_unicode_ascii(testdir): - """Ensure that our warning about 'unicode warnings containing non-ascii messages' - does not trigger with ascii-convertible messages""" - testdir.makeini("[pytest]") - testdir.makepyfile( - """ - import pytest - import warnings - - @pytest.mark.filterwarnings('always') - def test_func(): - warnings.warn(u"hello") - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines( - [ - "*== %s ==*" % WARNINGS_SUMMARY_HEADER, - '*warnings.warn(u"hello")', - "* 1 passed, 1 warnings in*", - ] - ) - - -def test_works_with_filterwarnings(testdir): - """Ensure our warnings capture does not mess with pre-installed filters (#2430).""" - testdir.makepyfile( - """ - import warnings - - class MyWarning(Warning): - pass - - warnings.filterwarnings("error", category=MyWarning) - - class TestWarnings(object): - def test_my_warning(self): - try: - warnings.warn(MyWarning("warn!")) - assert False - except MyWarning: - assert True - """ - ) - result = testdir.runpytest() - result.stdout.fnmatch_lines(["*== 1 passed in *"]) - - -@pytest.mark.parametrize("default_config", ["ini", "cmdline"]) -def test_filterwarnings_mark(testdir, default_config): - """ - Test ``filterwarnings`` mark works and takes precedence over command line and ini options. - """ - if default_config == "ini": - testdir.makeini( - """ - [pytest] - filterwarnings = always - """ - ) - testdir.makepyfile( - """ - import warnings - import pytest - - @pytest.mark.filterwarnings('ignore::RuntimeWarning') - def test_ignore_runtime_warning(): - warnings.warn(RuntimeWarning()) - - @pytest.mark.filterwarnings('error') - def test_warning_error(): - warnings.warn(RuntimeWarning()) - - def test_show_warning(): - warnings.warn(RuntimeWarning()) - """ - ) - result = testdir.runpytest("-W always" if default_config == "cmdline" else "") - result.stdout.fnmatch_lines(["*= 1 failed, 2 passed, 1 warnings in *"]) - - -def test_non_string_warning_argument(testdir): - """Non-str argument passed to warning breaks pytest (#2956)""" - testdir.makepyfile( - """ - import warnings - import pytest - - def test(): - warnings.warn(UserWarning(1, u'foo')) - """ - ) - result = testdir.runpytest("-W", "always") - result.stdout.fnmatch_lines(["*= 1 passed, 1 warnings in *"]) diff --git a/third_party/python/pytest/tox.ini b/third_party/python/pytest/tox.ini deleted file mode 100644 index cb3846d5422a..000000000000 --- a/third_party/python/pytest/tox.ini +++ /dev/null @@ -1,212 +0,0 @@ -[tox] -minversion = 2.0 -distshare = {homedir}/.tox/distshare -# make sure to update environment list in travis.yml and appveyor.yml -envlist = - linting - py27 - py34 - py35 - py36 - py37 - pypy - {py27,py36}-{pexpect,xdist,trial,numpy,pluggymaster} - py27-nobyte - doctesting - py36-freeze - docs - -[testenv] -commands = pytest --lsof -ra {posargs:testing} -passenv = USER USERNAME -deps = - hypothesis>=3.56 - nose - mock - requests - -[testenv:py27-subprocess] -changedir = . -deps = - pytest-xdist>=1.13 - mock - nose -commands = - pytest -n3 -ra --runpytest=subprocess {posargs:testing} - - -[testenv:linting] -skipsdist = True -usedevelop = True -basepython = python3.6 -deps = pre-commit -commands = pre-commit run --all-files --show-diff-on-failure - -[testenv:py27-xdist] -deps = - pytest-xdist>=1.13 - mock - nose - hypothesis>=3.56 -changedir=testing -commands = - pytest -n8 -ra {posargs:.} - -[testenv:py36-xdist] -deps = {[testenv:py27-xdist]deps} -commands = {[testenv:py27-xdist]commands} - -[testenv:py27-pexpect] -changedir = testing -platform = linux|darwin -deps = pexpect -commands = - pytest -ra test_pdb.py test_terminal.py test_unittest.py - -[testenv:py36-pexpect] -changedir = {[testenv:py27-pexpect]changedir} -platform = {[testenv:py27-pexpect]platform} -deps = {[testenv:py27-pexpect]deps} -commands = {[testenv:py27-pexpect]commands} - -[testenv:py27-nobyte] -deps = - pytest-xdist>=1.13 - hypothesis>=3.56 - mock -distribute = true -changedir=testing -setenv = - PYTHONDONTWRITEBYTECODE=1 -commands = - pytest -n3 -ra {posargs:.} - -[testenv:py27-trial] -deps = twisted -commands = - pytest -ra {posargs:testing/test_unittest.py} - -[testenv:py36-trial] -deps = {[testenv:py27-trial]deps} -commands = {[testenv:py27-trial]commands} - -[testenv:py27-numpy] -deps = numpy -commands= - pytest -ra {posargs:testing/python/approx.py} - -[testenv:py36-numpy] -deps = {[testenv:py27-numpy]deps} -commands = {[testenv:py27-numpy]commands} - -[testenv:py27-pluggymaster] -setenv= - _PYTEST_SETUP_SKIP_PLUGGY_DEP=1 -deps = - {[testenv]deps} - git+https://github.com/pytest-dev/pluggy.git@master - -[testenv:py36-pluggymaster] -setenv = {[testenv:py27-pluggymaster]setenv} -deps = {[testenv:py27-pluggymaster]deps} - -[testenv:docs] -skipsdist = True -usedevelop = True -changedir = doc/en -deps = - attrs - more-itertools - PyYAML - sphinx - sphinxcontrib-trio - -commands = - sphinx-build -W -b html . _build - -[testenv:doctesting] -basepython = python -usedevelop = True -skipsdist = True -# ensure the given pyargs can't mean anything else -changedir = doc/ -deps = - PyYAML -commands = - pytest -ra en - pytest --doctest-modules --pyargs _pytest - -[testenv:regen] -changedir = doc/en -skipsdist = True -basepython = python3.5 -deps = - sphinx - PyYAML - regendoc>=0.6.1 -whitelist_externals = - rm - make -commands = - rm -rf /tmp/doc-exec* - make regen - -[testenv:fix-lint] -skipsdist = True -usedevelop = True -deps = - autopep8 -commands = - autopep8 --in-place -r --max-line-length=120 --exclude=test_source_multiline_block.py _pytest testing setup.py pytest.py - -[testenv:jython] -changedir = testing -commands = - {envpython} {envbindir}/py.test-jython -ra {posargs} - -[testenv:py36-freeze] -changedir = testing/freeze -deps = pyinstaller -commands = - {envpython} create_executable.py - {envpython} tox_run.py - - -[testenv:coveralls] -passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH COVERALLS_REPO_TOKEN -usedevelop = True -changedir = . -deps = - {[testenv]deps} - coveralls -commands = - coverage run --source=_pytest -m pytest testing - coverage report -m - coveralls - -[pytest] -minversion = 2.0 -plugins = pytester -addopts = -ra -p pytester --ignore=testing/cx_freeze -rsyncdirs = tox.ini pytest.py _pytest testing -python_files = test_*.py *_test.py testing/*/*.py -python_classes = Test Acceptance -python_functions = test -norecursedirs = .tox ja .hg cx_freeze_source -xfail_strict=true -filterwarnings = - error - # produced by path.local - ignore:bad escape.*:DeprecationWarning:re - # produced by path.readlines - ignore:.*U.*mode is deprecated:DeprecationWarning - # produced by pytest-xdist - ignore:.*type argument to addoption.*:DeprecationWarning - # produced by python >=3.5 on execnet (pytest-xdist) - ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning - # ignore warning about package resolution using __spec__ or __package__ - # should be a temporary solution, see #3061 for discussion - ignore:.*can't resolve package from __spec__ or __package__.*:ImportWarning - -[flake8] -max-line-length = 120 diff --git a/third_party/python/redo/README.md b/third_party/python/redo/README.md deleted file mode 100644 index bb9ea4c77adb..000000000000 --- a/third_party/python/redo/README.md +++ /dev/null @@ -1,147 +0,0 @@ - -# Redo - Utilities to retry Python callables -****************************************** - -## Introduction - -Redo provides various means to add seamless ability to retry to any Python callable. Redo includes a plain function `(redo.retry)`, a decorator `(redo.retriable)`, and a context manager `(redo.retrying)` to enable you to integrate it in the best possible way for your project. As a bonus, a standalone interface is also included `("retry")`. - -## Installation - -For installing with pip, run following commands -> pip install redo - -## How To Use -Below is the list of functions available -* retrier -* retry -* retriable -* retrying (contextmanager) - -### retrier(attempts=5, sleeptime=10, max_sleeptime=300, sleepscale=1.5, jitter=1) -A generator function that sleeps between retries, handles exponential back off and jitter. The action you are retrying is meant to run after retrier yields. At each iteration, we sleep for `sleeptime + random.randint(-jitter, jitter)`. Afterwards sleeptime is multiplied by sleepscale for the next iteration. - -**Arguments Detail:** - -1. **attempts (int):** maximum number of times to try; defaults to 5 -2. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute) -3. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes) -4. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5 -5. **jitter (int):** random jitter to introduce to sleep time each iteration. the amount is chosen at random between `[-jitter, +jitter]` defaults to 1 - -**Output:** -None, a maximum of `attempts` number of times - -**Example:** - - >>> n = 0 - >>> for _ in retrier(sleeptime=0, jitter=0): - ... if n == 3: - ... # We did the thing! - ... break - ... n += 1 - >>> n - 3 - >>> n = 0 - >>> for _ in retrier(sleeptime=0, jitter=0): - ... if n == 6: - ... # We did the thing! - ... break - ... n += 1 - ... else: - ... print("max tries hit") - max tries hit - -### retry(action, attempts=5, sleeptime=60, max_sleeptime=5 * 60, sleepscale=1.5, jitter=1, retry_exceptions=(Exception,), cleanup=None, args=(), kwargs={}) -Calls an action function until it succeeds, or we give up. - -**Arguments Detail:** - -1. **action (callable):** the function to retry -2. **attempts (int):** maximum number of times to try; defaults to 5 -3. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute) -4. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes) -5. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5 -6. **jitter (int):** random jitter to introduce to sleep time each iteration. The amount is chosen at random between `[-jitter, +jitter]` defaults to 1 -7. **retry_exceptions (tuple):** tuple of exceptions to be caught. If other exceptions are raised by `action()`, then these are immediately re-raised to the caller. -8. **cleanup (callable):** optional; called if one of `retry_exceptions` is caught. No arguments are passed to the cleanup function; if your cleanup requires arguments, consider using `functools.partial` or a `lambda` function. -9. **args (tuple):** positional arguments to call `action` with -10. **kwargs (dict):** keyword arguments to call `action` with - -**Output:** - Whatever action`(*args, **kwargs)` returns - - **Output:** - Whatever action(*args, **kwargs) raises. `retry_exceptions` are caught - up until the last attempt, in which case they are re-raised. - -**Example:** - - >>> count = 0 - >>> def foo(): - ... global count - ... count += 1 - ... print(count) - ... if count < 3: - ... raise ValueError("count is too small!") - ... return "success!" - >>> retry(foo, sleeptime=0, jitter=0) - 1 - 2 - 3 - 'success!' - -### retriable(*retry_args, **retry_kwargs) -A decorator factory for `retry()`. Wrap your function in `@retriable(...)` to give it retry powers! - -**Arguments Detail:** - Same as for `retry`, with the exception of `action`, `args`, and `kwargs`, - which are left to the normal function definition. - -**Output:** -A function decorator - -**Example:** - - >>> count = 0 - >>> @retriable(sleeptime=0, jitter=0) - ... def foo(): - ... global count - ... count += 1 - ... print(count) - ... if count < 3: - ... raise ValueError("count too small") - ... return "success!" - >>> foo() - 1 - 2 - 3 - 'success!' - -### retrying(func, *retry_args, **retry_kwargs) -A context manager for wrapping functions with retry functionality. - -**Arguments Detail:** - -1. **func (callable):** the function to wrap -other arguments as per `retry` - -**Output:** -A context manager that returns `retriable(func)` on `__enter__` - -**Example:** - - >>> count = 0 - >>> def foo(): - ... global count - ... count += 1 - ... print(count) - ... if count < 3: - ... raise ValueError("count too small") - ... return "success!" - >>> with retrying(foo, sleeptime=0, jitter=0) as f: - ... f() - 1 - 2 - 3 - 'success!' \ No newline at end of file diff --git a/third_party/python/redo/redo-2.0.3.dist-info/AUTHORS b/third_party/python/redo/redo-2.0.3.dist-info/AUTHORS new file mode 100644 index 000000000000..b2e24333c062 --- /dev/null +++ b/third_party/python/redo/redo-2.0.3.dist-info/AUTHORS @@ -0,0 +1,7 @@ +Rail Aliiev (https://github.com/rail) +Chris AtLee (https://github.com/catlee) +Ben Hearsum (https://github.com/bhearsum) +John Hopkins (https://github.com/jhopkinsmoz) +Justin Wood (https://github.com/callek) +Terry Chia (https://github.com/Ayrx) +Mr. Deathless (https://github.com/mrdeathless) diff --git a/third_party/python/redo/PKG-INFO b/third_party/python/redo/redo-2.0.3.dist-info/METADATA similarity index 82% rename from third_party/python/redo/PKG-INFO rename to third_party/python/redo/redo-2.0.3.dist-info/METADATA index 0bf4bd5d9f78..e43a46e13ab9 100644 --- a/third_party/python/redo/PKG-INFO +++ b/third_party/python/redo/redo-2.0.3.dist-info/METADATA @@ -1,4 +1,4 @@ -Metadata-Version: 1.0 +Metadata-Version: 2.1 Name: redo Version: 2.0.3 Summary: Utilities to retry Python callables. @@ -6,5 +6,8 @@ Home-page: https://github.com/bhearsum/redo Author: Ben Hearsum Author-email: ben@hearsum.ca License: UNKNOWN -Description: UNKNOWN Platform: UNKNOWN + +UNKNOWN + + diff --git a/third_party/python/redo/redo-2.0.3.dist-info/RECORD b/third_party/python/redo/redo-2.0.3.dist-info/RECORD new file mode 100644 index 000000000000..d8f82bf7da93 --- /dev/null +++ b/third_party/python/redo/redo-2.0.3.dist-info/RECORD @@ -0,0 +1,8 @@ +redo/__init__.py,sha256=6VZUeFfbFkBJ_lxY_cJWk0S8mgSkrSRIwVniVm_sKsw,8518 +redo/cmd.py,sha256=F1axa3CVChlIvrSnq4xZZIyZ4M4wnnZjpv8wy46ugS4,2085 +redo-2.0.3.dist-info/AUTHORS,sha256=uIuTIaIlfQwklq75eg8VTjdnzENPlN_WKxa1UxQWTtQ,290 +redo-2.0.3.dist-info/METADATA,sha256=0DOrbjh62qccs3wFTgTxP9kQ1S4cphhUnupdfv0_6ms,233 +redo-2.0.3.dist-info/WHEEL,sha256=_wJFdOYk7i3xxT8ElOkUJvOdOvfNGbR9g-bf6UQT6sU,110 +redo-2.0.3.dist-info/entry_points.txt,sha256=ftcg9P_jTwZ9bYYDKB-s-5eIY6mHGiRHvd_HAGc7UPc,41 +redo-2.0.3.dist-info/top_level.txt,sha256=o1qXhN94bANfd7pz4zervaf8ytHEG_UVfhFZKMmmdvo,5 +redo-2.0.3.dist-info/RECORD,, diff --git a/third_party/python/redo/redo-2.0.3.dist-info/WHEEL b/third_party/python/redo/redo-2.0.3.dist-info/WHEEL new file mode 100644 index 000000000000..c4bde3037775 --- /dev/null +++ b/third_party/python/redo/redo-2.0.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.32.3) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/redo/redo.egg-info/entry_points.txt b/third_party/python/redo/redo-2.0.3.dist-info/entry_points.txt similarity index 100% rename from third_party/python/redo/redo.egg-info/entry_points.txt rename to third_party/python/redo/redo-2.0.3.dist-info/entry_points.txt diff --git a/third_party/python/redo/redo.egg-info/top_level.txt b/third_party/python/redo/redo-2.0.3.dist-info/top_level.txt similarity index 100% rename from third_party/python/redo/redo.egg-info/top_level.txt rename to third_party/python/redo/redo-2.0.3.dist-info/top_level.txt diff --git a/third_party/python/redo/redo.egg-info/PKG-INFO b/third_party/python/redo/redo.egg-info/PKG-INFO deleted file mode 100644 index 0bf4bd5d9f78..000000000000 --- a/third_party/python/redo/redo.egg-info/PKG-INFO +++ /dev/null @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: redo -Version: 2.0.3 -Summary: Utilities to retry Python callables. -Home-page: https://github.com/bhearsum/redo -Author: Ben Hearsum -Author-email: ben@hearsum.ca -License: UNKNOWN -Description: UNKNOWN -Platform: UNKNOWN diff --git a/third_party/python/redo/redo.egg-info/SOURCES.txt b/third_party/python/redo/redo.egg-info/SOURCES.txt deleted file mode 100644 index a238a81759d2..000000000000 --- a/third_party/python/redo/redo.egg-info/SOURCES.txt +++ /dev/null @@ -1,10 +0,0 @@ -README.md -setup.cfg -setup.py -redo/__init__.py -redo/cmd.py -redo.egg-info/PKG-INFO -redo.egg-info/SOURCES.txt -redo.egg-info/dependency_links.txt -redo.egg-info/entry_points.txt -redo.egg-info/top_level.txt \ No newline at end of file diff --git a/third_party/python/redo/redo.egg-info/dependency_links.txt b/third_party/python/redo/redo.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/redo/redo.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/redo/setup.cfg b/third_party/python/redo/setup.cfg deleted file mode 100644 index 1e3eb367c116..000000000000 --- a/third_party/python/redo/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/redo/setup.py b/third_party/python/redo/setup.py deleted file mode 100644 index 255f80ea5278..000000000000 --- a/third_party/python/redo/setup.py +++ /dev/null @@ -1,16 +0,0 @@ -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - - -setup( - name="redo", - version="2.0.3", - description="Utilities to retry Python callables.", - author="Ben Hearsum", - author_email="ben@hearsum.ca", - packages=["redo"], - entry_points={"console_scripts": ["retry = redo.cmd:main"]}, - url="https://github.com/bhearsum/redo", -) diff --git a/third_party/python/requests/HISTORY.md b/third_party/python/requests/HISTORY.md deleted file mode 100644 index 0331d187f7e7..000000000000 --- a/third_party/python/requests/HISTORY.md +++ /dev/null @@ -1,1710 +0,0 @@ -Release History -=============== - -dev ---- - -- \[Short description of non-trivial change.\] - -2.25.1 (2020-12-16) -------------------- - -**Bugfixes** - -- Requests now treats `application/json` as `utf8` by default. Resolving - inconsistencies between `r.text` and `r.json` output. (#5673) - -**Dependencies** - -- Requests now supports chardet v4.x. - -2.25.0 (2020-11-11) ------------------- - -**Improvements** - -- Added support for NETRC environment variable. (#5643) - -**Dependencies** - -- Requests now supports urllib3 v1.26. - -**Deprecations** - -- Requests v2.25.x will be the last release series with support for Python 3.5. -- The `requests[security]` extra is officially deprecated and will be removed - in Requests v2.26.0. - -2.24.0 (2020-06-17) -------------------- - -**Improvements** - -- pyOpenSSL TLS implementation is now only used if Python - either doesn't have an `ssl` module or doesn't support - SNI. Previously pyOpenSSL was unconditionally used if available. - This applies even if pyOpenSSL is installed via the - `requests[security]` extra (#5443) - -- Redirect resolution should now only occur when - `allow_redirects` is True. (#5492) - -- No longer perform unnecessary Content-Length calculation for - requests that won't use it. (#5496) - -2.23.0 (2020-02-19) -------------------- - -**Improvements** - -- Remove defunct reference to `prefetch` in Session `__attrs__` (#5110) - -**Bugfixes** - -- Requests no longer outputs password in basic auth usage warning. (#5099) - -**Dependencies** - -- Pinning for `chardet` and `idna` now uses major version instead of minor. - This hopefully reduces the need for releases everytime a dependency is updated. - -2.22.0 (2019-05-15) -------------------- - -**Dependencies** - -- Requests now supports urllib3 v1.25.2. - (note: 1.25.0 and 1.25.1 are incompatible) - -**Deprecations** - -- Requests has officially stopped support for Python 3.4. - -2.21.0 (2018-12-10) -------------------- - -**Dependencies** - -- Requests now supports idna v2.8. - -2.20.1 (2018-11-08) -------------------- - -**Bugfixes** - -- Fixed bug with unintended Authorization header stripping for - redirects using default ports (http/80, https/443). - -2.20.0 (2018-10-18) -------------------- - -**Bugfixes** - -- Content-Type header parsing is now case-insensitive (e.g. - charset=utf8 v Charset=utf8). -- Fixed exception leak where certain redirect urls would raise - uncaught urllib3 exceptions. -- Requests removes Authorization header from requests redirected - from https to http on the same hostname. (CVE-2018-18074) -- `should_bypass_proxies` now handles URIs without hostnames (e.g. - files). - -**Dependencies** - -- Requests now supports urllib3 v1.24. - -**Deprecations** - -- Requests has officially stopped support for Python 2.6. - -2.19.1 (2018-06-14) -------------------- - -**Bugfixes** - -- Fixed issue where status\_codes.py's `init` function failed trying - to append to a `__doc__` value of `None`. - -2.19.0 (2018-06-12) -------------------- - -**Improvements** - -- Warn user about possible slowdown when using cryptography version - < 1.3.4 -- Check for invalid host in proxy URL, before forwarding request to - adapter. -- Fragments are now properly maintained across redirects. (RFC7231 - 7.1.2) -- Removed use of cgi module to expedite library load time. -- Added support for SHA-256 and SHA-512 digest auth algorithms. -- Minor performance improvement to `Request.content`. -- Migrate to using collections.abc for 3.7 compatibility. - -**Bugfixes** - -- Parsing empty `Link` headers with `parse_header_links()` no longer - return one bogus entry. -- Fixed issue where loading the default certificate bundle from a zip - archive would raise an `IOError`. -- Fixed issue with unexpected `ImportError` on windows system which do - not support `winreg` module. -- DNS resolution in proxy bypass no longer includes the username and - password in the request. This also fixes the issue of DNS queries - failing on macOS. -- Properly normalize adapter prefixes for url comparison. -- Passing `None` as a file pointer to the `files` param no longer - raises an exception. -- Calling `copy` on a `RequestsCookieJar` will now preserve the cookie - policy correctly. - -**Dependencies** - -- We now support idna v2.7. -- We now support urllib3 v1.23. - -2.18.4 (2017-08-15) -------------------- - -**Improvements** - -- Error messages for invalid headers now include the header name for - easier debugging - -**Dependencies** - -- We now support idna v2.6. - -2.18.3 (2017-08-02) -------------------- - -**Improvements** - -- Running `$ python -m requests.help` now includes the installed - version of idna. - -**Bugfixes** - -- Fixed issue where Requests would raise `ConnectionError` instead of - `SSLError` when encountering SSL problems when using urllib3 v1.22. - -2.18.2 (2017-07-25) -------------------- - -**Bugfixes** - -- `requests.help` no longer fails on Python 2.6 due to the absence of - `ssl.OPENSSL_VERSION_NUMBER`. - -**Dependencies** - -- We now support urllib3 v1.22. - -2.18.1 (2017-06-14) -------------------- - -**Bugfixes** - -- Fix an error in the packaging whereby the `*.whl` contained - incorrect data that regressed the fix in v2.17.3. - -2.18.0 (2017-06-14) -------------------- - -**Improvements** - -- `Response` is now a context manager, so can be used directly in a - `with` statement without first having to be wrapped by - `contextlib.closing()`. - -**Bugfixes** - -- Resolve installation failure if multiprocessing is not available -- Resolve tests crash if multiprocessing is not able to determine the - number of CPU cores -- Resolve error swallowing in utils set\_environ generator - -2.17.3 (2017-05-29) -------------------- - -**Improvements** - -- Improved `packages` namespace identity support, for monkeypatching - libraries. - -2.17.2 (2017-05-29) -------------------- - -**Improvements** - -- Improved `packages` namespace identity support, for monkeypatching - libraries. - -2.17.1 (2017-05-29) -------------------- - -**Improvements** - -- Improved `packages` namespace identity support, for monkeypatching - libraries. - -2.17.0 (2017-05-29) -------------------- - -**Improvements** - -- Removal of the 301 redirect cache. This improves thread-safety. - -2.16.5 (2017-05-28) -------------------- - -- Improvements to `$ python -m requests.help`. - -2.16.4 (2017-05-27) -------------------- - -- Introduction of the `$ python -m requests.help` command, for - debugging with maintainers! - -2.16.3 (2017-05-27) -------------------- - -- Further restored the `requests.packages` namespace for compatibility - reasons. - -2.16.2 (2017-05-27) -------------------- - -- Further restored the `requests.packages` namespace for compatibility - reasons. - -No code modification (noted below) should be necessary any longer. - -2.16.1 (2017-05-27) -------------------- - -- Restored the `requests.packages` namespace for compatibility - reasons. -- Bugfix for `urllib3` version parsing. - -**Note**: code that was written to import against the -`requests.packages` namespace previously will have to import code that -rests at this module-level now. - -For example: - - from requests.packages.urllib3.poolmanager import PoolManager - -Will need to be re-written to be: - - from requests.packages import urllib3 - urllib3.poolmanager.PoolManager - -Or, even better: - - from urllib3.poolmanager import PoolManager - -2.16.0 (2017-05-26) -------------------- - -- Unvendor ALL the things! - -2.15.1 (2017-05-26) -------------------- - -- Everyone makes mistakes. - -2.15.0 (2017-05-26) -------------------- - -**Improvements** - -- Introduction of the `Response.next` property, for getting the next - `PreparedResponse` from a redirect chain (when - `allow_redirects=False`). -- Internal refactoring of `__version__` module. - -**Bugfixes** - -- Restored once-optional parameter for - `requests.utils.get_environ_proxies()`. - -2.14.2 (2017-05-10) -------------------- - -**Bugfixes** - -- Changed a less-than to an equal-to and an or in the dependency - markers to widen compatibility with older setuptools releases. - -2.14.1 (2017-05-09) -------------------- - -**Bugfixes** - -- Changed the dependency markers to widen compatibility with older pip - releases. - -2.14.0 (2017-05-09) -------------------- - -**Improvements** - -- It is now possible to pass `no_proxy` as a key to the `proxies` - dictionary to provide handling similar to the `NO_PROXY` environment - variable. -- When users provide invalid paths to certificate bundle files or - directories Requests now raises `IOError`, rather than failing at - the time of the HTTPS request with a fairly inscrutable certificate - validation error. -- The behavior of `SessionRedirectMixin` was slightly altered. - `resolve_redirects` will now detect a redirect by calling - `get_redirect_target(response)` instead of directly querying - `Response.is_redirect` and `Response.headers['location']`. Advanced - users will be able to process malformed redirects more easily. -- Changed the internal calculation of elapsed request time to have - higher resolution on Windows. -- Added `win_inet_pton` as conditional dependency for the `[socks]` - extra on Windows with Python 2.7. -- Changed the proxy bypass implementation on Windows: the proxy bypass - check doesn't use forward and reverse DNS requests anymore -- URLs with schemes that begin with `http` but are not `http` or - `https` no longer have their host parts forced to lowercase. - -**Bugfixes** - -- Much improved handling of non-ASCII `Location` header values in - redirects. Fewer `UnicodeDecodeErrors` are encountered on Python 2, - and Python 3 now correctly understands that Latin-1 is unlikely to - be the correct encoding. -- If an attempt to `seek` file to find out its length fails, we now - appropriately handle that by aborting our content-length - calculations. -- Restricted `HTTPDigestAuth` to only respond to auth challenges made - on 4XX responses, rather than to all auth challenges. -- Fixed some code that was firing `DeprecationWarning` on Python 3.6. -- The dismayed person emoticon (`/o\\`) no longer has a big head. I'm - sure this is what you were all worrying about most. - -**Miscellaneous** - -- Updated bundled urllib3 to v1.21.1. -- Updated bundled chardet to v3.0.2. -- Updated bundled idna to v2.5. -- Updated bundled certifi to 2017.4.17. - -2.13.0 (2017-01-24) -------------------- - -**Features** - -- Only load the `idna` library when we've determined we need it. This - will save some memory for users. - -**Miscellaneous** - -- Updated bundled urllib3 to 1.20. -- Updated bundled idna to 2.2. - -2.12.5 (2017-01-18) -------------------- - -**Bugfixes** - -- Fixed an issue with JSON encoding detection, specifically detecting - big-endian UTF-32 with BOM. - -2.12.4 (2016-12-14) -------------------- - -**Bugfixes** - -- Fixed regression from 2.12.2 where non-string types were rejected in - the basic auth parameters. While support for this behaviour has been - readded, the behaviour is deprecated and will be removed in the - future. - -2.12.3 (2016-12-01) -------------------- - -**Bugfixes** - -- Fixed regression from v2.12.1 for URLs with schemes that begin with - "http". These URLs have historically been processed as though they - were HTTP-schemed URLs, and so have had parameters added. This was - removed in v2.12.2 in an overzealous attempt to resolve problems - with IDNA-encoding those URLs. This change was reverted: the other - fixes for IDNA-encoding have been judged to be sufficient to return - to the behaviour Requests had before v2.12.0. - -2.12.2 (2016-11-30) -------------------- - -**Bugfixes** - -- Fixed several issues with IDNA-encoding URLs that are technically - invalid but which are widely accepted. Requests will now attempt to - IDNA-encode a URL if it can but, if it fails, and the host contains - only ASCII characters, it will be passed through optimistically. - This will allow users to opt-in to using IDNA2003 themselves if they - want to, and will also allow technically invalid but still common - hostnames. -- Fixed an issue where URLs with leading whitespace would raise - `InvalidSchema` errors. -- Fixed an issue where some URLs without the HTTP or HTTPS schemes - would still have HTTP URL preparation applied to them. -- Fixed an issue where Unicode strings could not be used in basic - auth. -- Fixed an issue encountered by some Requests plugins where - constructing a Response object would cause `Response.content` to - raise an `AttributeError`. - -2.12.1 (2016-11-16) -------------------- - -**Bugfixes** - -- Updated setuptools 'security' extra for the new PyOpenSSL backend in - urllib3. - -**Miscellaneous** - -- Updated bundled urllib3 to 1.19.1. - -2.12.0 (2016-11-15) -------------------- - -**Improvements** - -- Updated support for internationalized domain names from IDNA2003 to - IDNA2008. This updated support is required for several forms of IDNs - and is mandatory for .de domains. -- Much improved heuristics for guessing content lengths: Requests will - no longer read an entire `StringIO` into memory. -- Much improved logic for recalculating `Content-Length` headers for - `PreparedRequest` objects. -- Improved tolerance for file-like objects that have no `tell` method - but do have a `seek` method. -- Anything that is a subclass of `Mapping` is now treated like a - dictionary by the `data=` keyword argument. -- Requests now tolerates empty passwords in proxy credentials, rather - than stripping the credentials. -- If a request is made with a file-like object as the body and that - request is redirected with a 307 or 308 status code, Requests will - now attempt to rewind the body object so it can be replayed. - -**Bugfixes** - -- When calling `response.close`, the call to `close` will be - propagated through to non-urllib3 backends. -- Fixed issue where the `ALL_PROXY` environment variable would be - preferred over scheme-specific variables like `HTTP_PROXY`. -- Fixed issue where non-UTF8 reason phrases got severely mangled by - falling back to decoding using ISO 8859-1 instead. -- Fixed a bug where Requests would not correctly correlate cookies set - when using custom Host headers if those Host headers did not use the - native string type for the platform. - -**Miscellaneous** - -- Updated bundled urllib3 to 1.19. -- Updated bundled certifi certs to 2016.09.26. - -2.11.1 (2016-08-17) -------------------- - -**Bugfixes** - -- Fixed a bug when using `iter_content` with `decode_unicode=True` for - streamed bodies would raise `AttributeError`. This bug was - introduced in 2.11. -- Strip Content-Type and Transfer-Encoding headers from the header - block when following a redirect that transforms the verb from - POST/PUT to GET. - -2.11.0 (2016-08-08) -------------------- - -**Improvements** - -- Added support for the `ALL_PROXY` environment variable. -- Reject header values that contain leading whitespace or newline - characters to reduce risk of header smuggling. - -**Bugfixes** - -- Fixed occasional `TypeError` when attempting to decode a JSON - response that occurred in an error case. Now correctly returns a - `ValueError`. -- Requests would incorrectly ignore a non-CIDR IP address in the - `NO_PROXY` environment variables: Requests now treats it as a - specific IP. -- Fixed a bug when sending JSON data that could cause us to encounter - obscure OpenSSL errors in certain network conditions (yes, really). -- Added type checks to ensure that `iter_content` only accepts - integers and `None` for chunk sizes. -- Fixed issue where responses whose body had not been fully consumed - would have the underlying connection closed but not returned to the - connection pool, which could cause Requests to hang in situations - where the `HTTPAdapter` had been configured to use a blocking - connection pool. - -**Miscellaneous** - -- Updated bundled urllib3 to 1.16. -- Some previous releases accidentally accepted non-strings as - acceptable header values. This release does not. - -2.10.0 (2016-04-29) -------------------- - -**New Features** - -- SOCKS Proxy Support! (requires PySocks; - `$ pip install requests[socks]`) - -**Miscellaneous** - -- Updated bundled urllib3 to 1.15.1. - -2.9.2 (2016-04-29) ------------------- - -**Improvements** - -- Change built-in CaseInsensitiveDict (used for headers) to use - OrderedDict as its underlying datastore. - -**Bugfixes** - -- Don't use redirect\_cache if allow\_redirects=False -- When passed objects that throw exceptions from `tell()`, send them - via chunked transfer encoding instead of failing. -- Raise a ProxyError for proxy related connection issues. - -2.9.1 (2015-12-21) ------------------- - -**Bugfixes** - -- Resolve regression introduced in 2.9.0 that made it impossible to - send binary strings as bodies in Python 3. -- Fixed errors when calculating cookie expiration dates in certain - locales. - -**Miscellaneous** - -- Updated bundled urllib3 to 1.13.1. - -2.9.0 (2015-12-15) ------------------- - -**Minor Improvements** (Backwards compatible) - -- The `verify` keyword argument now supports being passed a path to a - directory of CA certificates, not just a single-file bundle. -- Warnings are now emitted when sending files opened in text mode. -- Added the 511 Network Authentication Required status code to the - status code registry. - -**Bugfixes** - -- For file-like objects that are not sought to the very beginning, we - now send the content length for the number of bytes we will actually - read, rather than the total size of the file, allowing partial file - uploads. -- When uploading file-like objects, if they are empty or have no - obvious content length we set `Transfer-Encoding: chunked` rather - than `Content-Length: 0`. -- We correctly receive the response in buffered mode when uploading - chunked bodies. -- We now handle being passed a query string as a bytestring on Python - 3, by decoding it as UTF-8. -- Sessions are now closed in all cases (exceptional and not) when - using the functional API rather than leaking and waiting for the - garbage collector to clean them up. -- Correctly handle digest auth headers with a malformed `qop` - directive that contains no token, by treating it the same as if no - `qop` directive was provided at all. -- Minor performance improvements when removing specific cookies by - name. - -**Miscellaneous** - -- Updated urllib3 to 1.13. - -2.8.1 (2015-10-13) ------------------- - -**Bugfixes** - -- Update certificate bundle to match `certifi` 2015.9.6.2's weak - certificate bundle. -- Fix a bug in 2.8.0 where requests would raise `ConnectTimeout` - instead of `ConnectionError` -- When using the PreparedRequest flow, requests will now correctly - respect the `json` parameter. Broken in 2.8.0. -- When using the PreparedRequest flow, requests will now correctly - handle a Unicode-string method name on Python 2. Broken in 2.8.0. - -2.8.0 (2015-10-05) ------------------- - -**Minor Improvements** (Backwards Compatible) - -- Requests now supports per-host proxies. This allows the `proxies` - dictionary to have entries of the form - `{'://': ''}`. Host-specific proxies will - be used in preference to the previously-supported scheme-specific - ones, but the previous syntax will continue to work. -- `Response.raise_for_status` now prints the URL that failed as part - of the exception message. -- `requests.utils.get_netrc_auth` now takes an `raise_errors` kwarg, - defaulting to `False`. When `True`, errors parsing `.netrc` files - cause exceptions to be thrown. -- Change to bundled projects import logic to make it easier to - unbundle requests downstream. -- Changed the default User-Agent string to avoid leaking data on - Linux: now contains only the requests version. - -**Bugfixes** - -- The `json` parameter to `post()` and friends will now only be used - if neither `data` nor `files` are present, consistent with the - documentation. -- We now ignore empty fields in the `NO_PROXY` environment variable. -- Fixed problem where `httplib.BadStatusLine` would get raised if - combining `stream=True` with `contextlib.closing`. -- Prevented bugs where we would attempt to return the same connection - back to the connection pool twice when sending a Chunked body. -- Miscellaneous minor internal changes. -- Digest Auth support is now thread safe. - -**Updates** - -- Updated urllib3 to 1.12. - -2.7.0 (2015-05-03) ------------------- - -This is the first release that follows our new release process. For -more, see [our -documentation](https://requests.readthedocs.io/en/latest/community/release-process/). - -**Bugfixes** - -- Updated urllib3 to 1.10.4, resolving several bugs involving chunked - transfer encoding and response framing. - -2.6.2 (2015-04-23) ------------------- - -**Bugfixes** - -- Fix regression where compressed data that was sent as chunked data - was not properly decompressed. (\#2561) - -2.6.1 (2015-04-22) ------------------- - -**Bugfixes** - -- Remove VendorAlias import machinery introduced in v2.5.2. -- Simplify the PreparedRequest.prepare API: We no longer require the - user to pass an empty list to the hooks keyword argument. (c.f. - \#2552) -- Resolve redirects now receives and forwards all of the original - arguments to the adapter. (\#2503) -- Handle UnicodeDecodeErrors when trying to deal with a unicode URL - that cannot be encoded in ASCII. (\#2540) -- Populate the parsed path of the URI field when performing Digest - Authentication. (\#2426) -- Copy a PreparedRequest's CookieJar more reliably when it is not an - instance of RequestsCookieJar. (\#2527) - -2.6.0 (2015-03-14) ------------------- - -**Bugfixes** - -- CVE-2015-2296: Fix handling of cookies on redirect. Previously a - cookie without a host value set would use the hostname for the - redirected URL exposing requests users to session fixation attacks - and potentially cookie stealing. This was disclosed privately by - Matthew Daley of [BugFuzz](https://bugfuzz.com). This affects all - versions of requests from v2.1.0 to v2.5.3 (inclusive on both ends). -- Fix error when requests is an `install_requires` dependency and - `python setup.py test` is run. (\#2462) -- Fix error when urllib3 is unbundled and requests continues to use - the vendored import location. -- Include fixes to `urllib3`'s header handling. -- Requests' handling of unvendored dependencies is now more - restrictive. - -**Features and Improvements** - -- Support bytearrays when passed as parameters in the `files` - argument. (\#2468) -- Avoid data duplication when creating a request with `str`, `bytes`, - or `bytearray` input to the `files` argument. - -2.5.3 (2015-02-24) ------------------- - -**Bugfixes** - -- Revert changes to our vendored certificate bundle. For more context - see (\#2455, \#2456, and ) - -2.5.2 (2015-02-23) ------------------- - -**Features and Improvements** - -- Add sha256 fingerprint support. - ([shazow/urllib3\#540](https://github.com/shazow/urllib3/pull/540)) -- Improve the performance of headers. - ([shazow/urllib3\#544](https://github.com/shazow/urllib3/pull/544)) - -**Bugfixes** - -- Copy pip's import machinery. When downstream redistributors remove - requests.packages.urllib3 the import machinery will continue to let - those same symbols work. Example usage in requests' documentation - and 3rd-party libraries relying on the vendored copies of urllib3 - will work without having to fallback to the system urllib3. -- Attempt to quote parts of the URL on redirect if unquoting and then - quoting fails. (\#2356) -- Fix filename type check for multipart form-data uploads. (\#2411) -- Properly handle the case where a server issuing digest - authentication challenges provides both auth and auth-int - qop-values. (\#2408) -- Fix a socket leak. - ([shazow/urllib3\#549](https://github.com/shazow/urllib3/pull/549)) -- Fix multiple `Set-Cookie` headers properly. - ([shazow/urllib3\#534](https://github.com/shazow/urllib3/pull/534)) -- Disable the built-in hostname verification. - ([shazow/urllib3\#526](https://github.com/shazow/urllib3/pull/526)) -- Fix the behaviour of decoding an exhausted stream. - ([shazow/urllib3\#535](https://github.com/shazow/urllib3/pull/535)) - -**Security** - -- Pulled in an updated `cacert.pem`. -- Drop RC4 from the default cipher list. - ([shazow/urllib3\#551](https://github.com/shazow/urllib3/pull/551)) - -2.5.1 (2014-12-23) ------------------- - -**Behavioural Changes** - -- Only catch HTTPErrors in raise\_for\_status (\#2382) - -**Bugfixes** - -- Handle LocationParseError from urllib3 (\#2344) -- Handle file-like object filenames that are not strings (\#2379) -- Unbreak HTTPDigestAuth handler. Allow new nonces to be negotiated - (\#2389) - -2.5.0 (2014-12-01) ------------------- - -**Improvements** - -- Allow usage of urllib3's Retry object with HTTPAdapters (\#2216) -- The `iter_lines` method on a response now accepts a delimiter with - which to split the content (\#2295) - -**Behavioural Changes** - -- Add deprecation warnings to functions in requests.utils that will be - removed in 3.0 (\#2309) -- Sessions used by the functional API are always closed (\#2326) -- Restrict requests to HTTP/1.1 and HTTP/1.0 (stop accepting HTTP/0.9) - (\#2323) - -**Bugfixes** - -- Only parse the URL once (\#2353) -- Allow Content-Length header to always be overridden (\#2332) -- Properly handle files in HTTPDigestAuth (\#2333) -- Cap redirect\_cache size to prevent memory abuse (\#2299) -- Fix HTTPDigestAuth handling of redirects after authenticating - successfully (\#2253) -- Fix crash with custom method parameter to Session.request (\#2317) -- Fix how Link headers are parsed using the regular expression library - (\#2271) - -**Documentation** - -- Add more references for interlinking (\#2348) -- Update CSS for theme (\#2290) -- Update width of buttons and sidebar (\#2289) -- Replace references of Gittip with Gratipay (\#2282) -- Add link to changelog in sidebar (\#2273) - -2.4.3 (2014-10-06) ------------------- - -**Bugfixes** - -- Unicode URL improvements for Python 2. -- Re-order JSON param for backwards compat. -- Automatically defrag authentication schemes from host/pass URIs. - ([\#2249](https://github.com/psf/requests/issues/2249)) - -2.4.2 (2014-10-05) ------------------- - -**Improvements** - -- FINALLY! Add json parameter for uploads! - ([\#2258](https://github.com/psf/requests/pull/2258)) -- Support for bytestring URLs on Python 3.x - ([\#2238](https://github.com/psf/requests/pull/2238)) - -**Bugfixes** - -- Avoid getting stuck in a loop - ([\#2244](https://github.com/psf/requests/pull/2244)) -- Multiple calls to iter\* fail with unhelpful error. - ([\#2240](https://github.com/psf/requests/issues/2240), - [\#2241](https://github.com/psf/requests/issues/2241)) - -**Documentation** - -- Correct redirection introduction - ([\#2245](https://github.com/psf/requests/pull/2245/)) -- Added example of how to send multiple files in one request. - ([\#2227](https://github.com/psf/requests/pull/2227/)) -- Clarify how to pass a custom set of CAs - ([\#2248](https://github.com/psf/requests/pull/2248/)) - -2.4.1 (2014-09-09) ------------------- - -- Now has a "security" package extras set, - `$ pip install requests[security]` -- Requests will now use Certifi if it is available. -- Capture and re-raise urllib3 ProtocolError -- Bugfix for responses that attempt to redirect to themselves forever - (wtf?). - -2.4.0 (2014-08-29) ------------------- - -**Behavioral Changes** - -- `Connection: keep-alive` header is now sent automatically. - -**Improvements** - -- Support for connect timeouts! Timeout now accepts a tuple (connect, - read) which is used to set individual connect and read timeouts. -- Allow copying of PreparedRequests without headers/cookies. -- Updated bundled urllib3 version. -- Refactored settings loading from environment -- new - Session.merge\_environment\_settings. -- Handle socket errors in iter\_content. - -2.3.0 (2014-05-16) ------------------- - -**API Changes** - -- New `Response` property `is_redirect`, which is true when the - library could have processed this response as a redirection (whether - or not it actually did). -- The `timeout` parameter now affects requests with both `stream=True` - and `stream=False` equally. -- The change in v2.0.0 to mandate explicit proxy schemes has been - reverted. Proxy schemes now default to `http://`. -- The `CaseInsensitiveDict` used for HTTP headers now behaves like a - normal dictionary when references as string or viewed in the - interpreter. - -**Bugfixes** - -- No longer expose Authorization or Proxy-Authorization headers on - redirect. Fix CVE-2014-1829 and CVE-2014-1830 respectively. -- Authorization is re-evaluated each redirect. -- On redirect, pass url as native strings. -- Fall-back to autodetected encoding for JSON when Unicode detection - fails. -- Headers set to `None` on the `Session` are now correctly not sent. -- Correctly honor `decode_unicode` even if it wasn't used earlier in - the same response. -- Stop advertising `compress` as a supported Content-Encoding. -- The `Response.history` parameter is now always a list. -- Many, many `urllib3` bugfixes. - -2.2.1 (2014-01-23) ------------------- - -**Bugfixes** - -- Fixes incorrect parsing of proxy credentials that contain a literal - or encoded '\#' character. -- Assorted urllib3 fixes. - -2.2.0 (2014-01-09) ------------------- - -**API Changes** - -- New exception: `ContentDecodingError`. Raised instead of `urllib3` - `DecodeError` exceptions. - -**Bugfixes** - -- Avoid many many exceptions from the buggy implementation of - `proxy_bypass` on OS X in Python 2.6. -- Avoid crashing when attempting to get authentication credentials - from \~/.netrc when running as a user without a home directory. -- Use the correct pool size for pools of connections to proxies. -- Fix iteration of `CookieJar` objects. -- Ensure that cookies are persisted over redirect. -- Switch back to using chardet, since it has merged with charade. - -2.1.0 (2013-12-05) ------------------- - -- Updated CA Bundle, of course. -- Cookies set on individual Requests through a `Session` (e.g. via - `Session.get()`) are no longer persisted to the `Session`. -- Clean up connections when we hit problems during chunked upload, - rather than leaking them. -- Return connections to the pool when a chunked upload is successful, - rather than leaking it. -- Match the HTTPbis recommendation for HTTP 301 redirects. -- Prevent hanging when using streaming uploads and Digest Auth when a - 401 is received. -- Values of headers set by Requests are now always the native string - type. -- Fix previously broken SNI support. -- Fix accessing HTTP proxies using proxy authentication. -- Unencode HTTP Basic usernames and passwords extracted from URLs. -- Support for IP address ranges for no\_proxy environment variable -- Parse headers correctly when users override the default `Host:` - header. -- Avoid munging the URL in case of case-sensitive servers. -- Looser URL handling for non-HTTP/HTTPS urls. -- Accept unicode methods in Python 2.6 and 2.7. -- More resilient cookie handling. -- Make `Response` objects pickleable. -- Actually added MD5-sess to Digest Auth instead of pretending to like - last time. -- Updated internal urllib3. -- Fixed @Lukasa's lack of taste. - -2.0.1 (2013-10-24) ------------------- - -- Updated included CA Bundle with new mistrusts and automated process - for the future -- Added MD5-sess to Digest Auth -- Accept per-file headers in multipart file POST messages. -- Fixed: Don't send the full URL on CONNECT messages. -- Fixed: Correctly lowercase a redirect scheme. -- Fixed: Cookies not persisted when set via functional API. -- Fixed: Translate urllib3 ProxyError into a requests ProxyError - derived from ConnectionError. -- Updated internal urllib3 and chardet. - -2.0.0 (2013-09-24) ------------------- - -**API Changes:** - -- Keys in the Headers dictionary are now native strings on all Python - versions, i.e. bytestrings on Python 2, unicode on Python 3. -- Proxy URLs now *must* have an explicit scheme. A `MissingSchema` - exception will be raised if they don't. -- Timeouts now apply to read time if `Stream=False`. -- `RequestException` is now a subclass of `IOError`, not - `RuntimeError`. -- Added new method to `PreparedRequest` objects: - `PreparedRequest.copy()`. -- Added new method to `Session` objects: `Session.update_request()`. - This method updates a `Request` object with the data (e.g. cookies) - stored on the `Session`. -- Added new method to `Session` objects: `Session.prepare_request()`. - This method updates and prepares a `Request` object, and returns the - corresponding `PreparedRequest` object. -- Added new method to `HTTPAdapter` objects: - `HTTPAdapter.proxy_headers()`. This should not be called directly, - but improves the subclass interface. -- `httplib.IncompleteRead` exceptions caused by incorrect chunked - encoding will now raise a Requests `ChunkedEncodingError` instead. -- Invalid percent-escape sequences now cause a Requests `InvalidURL` - exception to be raised. -- HTTP 208 no longer uses reason phrase `"im_used"`. Correctly uses - `"already_reported"`. -- HTTP 226 reason added (`"im_used"`). - -**Bugfixes:** - -- Vastly improved proxy support, including the CONNECT verb. Special - thanks to the many contributors who worked towards this improvement. -- Cookies are now properly managed when 401 authentication responses - are received. -- Chunked encoding fixes. -- Support for mixed case schemes. -- Better handling of streaming downloads. -- Retrieve environment proxies from more locations. -- Minor cookies fixes. -- Improved redirect behaviour. -- Improved streaming behaviour, particularly for compressed data. -- Miscellaneous small Python 3 text encoding bugs. -- `.netrc` no longer overrides explicit auth. -- Cookies set by hooks are now correctly persisted on Sessions. -- Fix problem with cookies that specify port numbers in their host - field. -- `BytesIO` can be used to perform streaming uploads. -- More generous parsing of the `no_proxy` environment variable. -- Non-string objects can be passed in data values alongside files. - -1.2.3 (2013-05-25) ------------------- - -- Simple packaging fix - -1.2.2 (2013-05-23) ------------------- - -- Simple packaging fix - -1.2.1 (2013-05-20) ------------------- - -- 301 and 302 redirects now change the verb to GET for all verbs, not - just POST, improving browser compatibility. -- Python 3.3.2 compatibility -- Always percent-encode location headers -- Fix connection adapter matching to be most-specific first -- new argument to the default connection adapter for passing a block - argument -- prevent a KeyError when there's no link headers - -1.2.0 (2013-03-31) ------------------- - -- Fixed cookies on sessions and on requests -- Significantly change how hooks are dispatched - hooks now receive - all the arguments specified by the user when making a request so - hooks can make a secondary request with the same parameters. This is - especially necessary for authentication handler authors -- certifi support was removed -- Fixed bug where using OAuth 1 with body `signature_type` sent no - data -- Major proxy work thanks to @Lukasa including parsing of proxy - authentication from the proxy url -- Fix DigestAuth handling too many 401s -- Update vendored urllib3 to include SSL bug fixes -- Allow keyword arguments to be passed to `json.loads()` via the - `Response.json()` method -- Don't send `Content-Length` header by default on `GET` or `HEAD` - requests -- Add `elapsed` attribute to `Response` objects to time how long a - request took. -- Fix `RequestsCookieJar` -- Sessions and Adapters are now picklable, i.e., can be used with the - multiprocessing library -- Update charade to version 1.0.3 - -The change in how hooks are dispatched will likely cause a great deal of -issues. - -1.1.0 (2013-01-10) ------------------- - -- CHUNKED REQUESTS -- Support for iterable response bodies -- Assume servers persist redirect params -- Allow explicit content types to be specified for file data -- Make merge\_kwargs case-insensitive when looking up keys - -1.0.3 (2012-12-18) ------------------- - -- Fix file upload encoding bug -- Fix cookie behavior - -1.0.2 (2012-12-17) ------------------- - -- Proxy fix for HTTPAdapter. - -1.0.1 (2012-12-17) ------------------- - -- Cert verification exception bug. -- Proxy fix for HTTPAdapter. - -1.0.0 (2012-12-17) ------------------- - -- Massive Refactor and Simplification -- Switch to Apache 2.0 license -- Swappable Connection Adapters -- Mountable Connection Adapters -- Mutable ProcessedRequest chain -- /s/prefetch/stream -- Removal of all configuration -- Standard library logging -- Make Response.json() callable, not property. -- Usage of new charade project, which provides python 2 and 3 - simultaneous chardet. -- Removal of all hooks except 'response' -- Removal of all authentication helpers (OAuth, Kerberos) - -This is not a backwards compatible change. - -0.14.2 (2012-10-27) -------------------- - -- Improved mime-compatible JSON handling -- Proxy fixes -- Path hack fixes -- Case-Insensitive Content-Encoding headers -- Support for CJK parameters in form posts - -0.14.1 (2012-10-01) -------------------- - -- Python 3.3 Compatibility -- Simply default accept-encoding -- Bugfixes - -0.14.0 (2012-09-02) -------------------- - -- No more iter\_content errors if already downloaded. - -0.13.9 (2012-08-25) -------------------- - -- Fix for OAuth + POSTs -- Remove exception eating from dispatch\_hook -- General bugfixes - -0.13.8 (2012-08-21) -------------------- - -- Incredible Link header support :) - -0.13.7 (2012-08-19) -------------------- - -- Support for (key, value) lists everywhere. -- Digest Authentication improvements. -- Ensure proxy exclusions work properly. -- Clearer UnicodeError exceptions. -- Automatic casting of URLs to strings (fURL and such) -- Bugfixes. - -0.13.6 (2012-08-06) -------------------- - -- Long awaited fix for hanging connections! - -0.13.5 (2012-07-27) -------------------- - -- Packaging fix - -0.13.4 (2012-07-27) -------------------- - -- GSSAPI/Kerberos authentication! -- App Engine 2.7 Fixes! -- Fix leaking connections (from urllib3 update) -- OAuthlib path hack fix -- OAuthlib URL parameters fix. - -0.13.3 (2012-07-12) -------------------- - -- Use simplejson if available. -- Do not hide SSLErrors behind Timeouts. -- Fixed param handling with urls containing fragments. -- Significantly improved information in User Agent. -- client certificates are ignored when verify=False - -0.13.2 (2012-06-28) -------------------- - -- Zero dependencies (once again)! -- New: Response.reason -- Sign querystring parameters in OAuth 1.0 -- Client certificates no longer ignored when verify=False -- Add openSUSE certificate support - -0.13.1 (2012-06-07) -------------------- - -- Allow passing a file or file-like object as data. -- Allow hooks to return responses that indicate errors. -- Fix Response.text and Response.json for body-less responses. - -0.13.0 (2012-05-29) -------------------- - -- Removal of Requests.async in favor of - [grequests](https://github.com/kennethreitz/grequests) -- Allow disabling of cookie persistence. -- New implementation of safe\_mode -- cookies.get now supports default argument -- Session cookies not saved when Session.request is called with - return\_response=False -- Env: no\_proxy support. -- RequestsCookieJar improvements. -- Various bug fixes. - -0.12.1 (2012-05-08) -------------------- - -- New `Response.json` property. -- Ability to add string file uploads. -- Fix out-of-range issue with iter\_lines. -- Fix iter\_content default size. -- Fix POST redirects containing files. - -0.12.0 (2012-05-02) -------------------- - -- EXPERIMENTAL OAUTH SUPPORT! -- Proper CookieJar-backed cookies interface with awesome dict-like - interface. -- Speed fix for non-iterated content chunks. -- Move `pre_request` to a more usable place. -- New `pre_send` hook. -- Lazily encode data, params, files. -- Load system Certificate Bundle if `certify` isn't available. -- Cleanups, fixes. - -0.11.2 (2012-04-22) -------------------- - -- Attempt to use the OS's certificate bundle if `certifi` isn't - available. -- Infinite digest auth redirect fix. -- Multi-part file upload improvements. -- Fix decoding of invalid %encodings in URLs. -- If there is no content in a response don't throw an error the second - time that content is attempted to be read. -- Upload data on redirects. - -0.11.1 (2012-03-30) -------------------- - -- POST redirects now break RFC to do what browsers do: Follow up with - a GET. -- New `strict_mode` configuration to disable new redirect behavior. - -0.11.0 (2012-03-14) -------------------- - -- Private SSL Certificate support -- Remove select.poll from Gevent monkeypatching -- Remove redundant generator for chunked transfer encoding -- Fix: Response.ok raises Timeout Exception in safe\_mode - -0.10.8 (2012-03-09) -------------------- - -- Generate chunked ValueError fix -- Proxy configuration by environment variables -- Simplification of iter\_lines. -- New trust\_env configuration for disabling system/environment hints. -- Suppress cookie errors. - -0.10.7 (2012-03-07) -------------------- - -- encode\_uri = False - -0.10.6 (2012-02-25) -------------------- - -- Allow '=' in cookies. - -0.10.5 (2012-02-25) -------------------- - -- Response body with 0 content-length fix. -- New async.imap. -- Don't fail on netrc. - -0.10.4 (2012-02-20) -------------------- - -- Honor netrc. - -0.10.3 (2012-02-20) -------------------- - -- HEAD requests don't follow redirects anymore. -- raise\_for\_status() doesn't raise for 3xx anymore. -- Make Session objects picklable. -- ValueError for invalid schema URLs. - -0.10.2 (2012-01-15) -------------------- - -- Vastly improved URL quoting. -- Additional allowed cookie key values. -- Attempted fix for "Too many open files" Error -- Replace unicode errors on first pass, no need for second pass. -- Append '/' to bare-domain urls before query insertion. -- Exceptions now inherit from RuntimeError. -- Binary uploads + auth fix. -- Bugfixes. - -0.10.1 (2012-01-23) -------------------- - -- PYTHON 3 SUPPORT! -- Dropped 2.5 Support. (*Backwards Incompatible*) - -0.10.0 (2012-01-21) -------------------- - -- `Response.content` is now bytes-only. (*Backwards Incompatible*) -- New `Response.text` is unicode-only. -- If no `Response.encoding` is specified and `chardet` is available, - `Response.text` will guess an encoding. -- Default to ISO-8859-1 (Western) encoding for "text" subtypes. -- Removal of decode\_unicode. (*Backwards Incompatible*) -- New multiple-hooks system. -- New `Response.register_hook` for registering hooks within the - pipeline. -- `Response.url` is now Unicode. - -0.9.3 (2012-01-18) ------------------- - -- SSL verify=False bugfix (apparent on windows machines). - -0.9.2 (2012-01-18) ------------------- - -- Asynchronous async.send method. -- Support for proper chunk streams with boundaries. -- session argument for Session classes. -- Print entire hook tracebacks, not just exception instance. -- Fix response.iter\_lines from pending next line. -- Fix but in HTTP-digest auth w/ URI having query strings. -- Fix in Event Hooks section. -- Urllib3 update. - -0.9.1 (2012-01-06) ------------------- - -- danger\_mode for automatic Response.raise\_for\_status() -- Response.iter\_lines refactor - -0.9.0 (2011-12-28) ------------------- - -- verify ssl is default. - -0.8.9 (2011-12-28) ------------------- - -- Packaging fix. - -0.8.8 (2011-12-28) ------------------- - -- SSL CERT VERIFICATION! -- Release of Cerifi: Mozilla's cert list. -- New 'verify' argument for SSL requests. -- Urllib3 update. - -0.8.7 (2011-12-24) ------------------- - -- iter\_lines last-line truncation fix -- Force safe\_mode for async requests -- Handle safe\_mode exceptions more consistently -- Fix iteration on null responses in safe\_mode - -0.8.6 (2011-12-18) ------------------- - -- Socket timeout fixes. -- Proxy Authorization support. - -0.8.5 (2011-12-14) ------------------- - -- Response.iter\_lines! - -0.8.4 (2011-12-11) ------------------- - -- Prefetch bugfix. -- Added license to installed version. - -0.8.3 (2011-11-27) ------------------- - -- Converted auth system to use simpler callable objects. -- New session parameter to API methods. -- Display full URL while logging. - -0.8.2 (2011-11-19) ------------------- - -- New Unicode decoding system, based on over-ridable - Response.encoding. -- Proper URL slash-quote handling. -- Cookies with `[`, `]`, and `_` allowed. - -0.8.1 (2011-11-15) ------------------- - -- URL Request path fix -- Proxy fix. -- Timeouts fix. - -0.8.0 (2011-11-13) ------------------- - -- Keep-alive support! -- Complete removal of Urllib2 -- Complete removal of Poster -- Complete removal of CookieJars -- New ConnectionError raising -- Safe\_mode for error catching -- prefetch parameter for request methods -- OPTION method -- Async pool size throttling -- File uploads send real names -- Vendored in urllib3 - -0.7.6 (2011-11-07) ------------------- - -- Digest authentication bugfix (attach query data to path) - -0.7.5 (2011-11-04) ------------------- - -- Response.content = None if there was an invalid response. -- Redirection auth handling. - -0.7.4 (2011-10-26) ------------------- - -- Session Hooks fix. - -0.7.3 (2011-10-23) ------------------- - -- Digest Auth fix. - -0.7.2 (2011-10-23) ------------------- - -- PATCH Fix. - -0.7.1 (2011-10-23) ------------------- - -- Move away from urllib2 authentication handling. -- Fully Remove AuthManager, AuthObject, &c. -- New tuple-based auth system with handler callbacks. - -0.7.0 (2011-10-22) ------------------- - -- Sessions are now the primary interface. -- Deprecated InvalidMethodException. -- PATCH fix. -- New config system (no more global settings). - -0.6.6 (2011-10-19) ------------------- - -- Session parameter bugfix (params merging). - -0.6.5 (2011-10-18) ------------------- - -- Offline (fast) test suite. -- Session dictionary argument merging. - -0.6.4 (2011-10-13) ------------------- - -- Automatic decoding of unicode, based on HTTP Headers. -- New `decode_unicode` setting. -- Removal of `r.read/close` methods. -- New `r.faw` interface for advanced response usage.\* -- Automatic expansion of parameterized headers. - -0.6.3 (2011-10-13) ------------------- - -- Beautiful `requests.async` module, for making async requests w/ - gevent. - -0.6.2 (2011-10-09) ------------------- - -- GET/HEAD obeys allow\_redirects=False. - -0.6.1 (2011-08-20) ------------------- - -- Enhanced status codes experience `\o/` -- Set a maximum number of redirects (`settings.max_redirects`) -- Full Unicode URL support -- Support for protocol-less redirects. -- Allow for arbitrary request types. -- Bugfixes - -0.6.0 (2011-08-17) ------------------- - -- New callback hook system -- New persistent sessions object and context manager -- Transparent Dict-cookie handling -- Status code reference object -- Removed Response.cached -- Added Response.request -- All args are kwargs -- Relative redirect support -- HTTPError handling improvements -- Improved https testing -- Bugfixes - -0.5.1 (2011-07-23) ------------------- - -- International Domain Name Support! -- Access headers without fetching entire body (`read()`) -- Use lists as dicts for parameters -- Add Forced Basic Authentication -- Forced Basic is default authentication type -- `python-requests.org` default User-Agent header -- CaseInsensitiveDict lower-case caching -- Response.history bugfix - -0.5.0 (2011-06-21) ------------------- - -- PATCH Support -- Support for Proxies -- HTTPBin Test Suite -- Redirect Fixes -- settings.verbose stream writing -- Querystrings for all methods -- URLErrors (Connection Refused, Timeout, Invalid URLs) are treated as - explicitly raised - `r.requests.get('hwe://blah'); r.raise_for_status()` - -0.4.1 (2011-05-22) ------------------- - -- Improved Redirection Handling -- New 'allow\_redirects' param for following non-GET/HEAD Redirects -- Settings module refactoring - -0.4.0 (2011-05-15) ------------------- - -- Response.history: list of redirected responses -- Case-Insensitive Header Dictionaries! -- Unicode URLs - -0.3.4 (2011-05-14) ------------------- - -- Urllib2 HTTPAuthentication Recursion fix (Basic/Digest) -- Internal Refactor -- Bytes data upload Bugfix - -0.3.3 (2011-05-12) ------------------- - -- Request timeouts -- Unicode url-encoded data -- Settings context manager and module - -0.3.2 (2011-04-15) ------------------- - -- Automatic Decompression of GZip Encoded Content -- AutoAuth Support for Tupled HTTP Auth - -0.3.1 (2011-04-01) ------------------- - -- Cookie Changes -- Response.read() -- Poster fix - -0.3.0 (2011-02-25) ------------------- - -- Automatic Authentication API Change -- Smarter Query URL Parameterization -- Allow file uploads and POST data together -- - - New Authentication Manager System - - : - Simpler Basic HTTP System - - Supports all build-in urllib2 Auths - - Allows for custom Auth Handlers - -0.2.4 (2011-02-19) ------------------- - -- Python 2.5 Support -- PyPy-c v1.4 Support -- Auto-Authentication tests -- Improved Request object constructor - -0.2.3 (2011-02-15) ------------------- - -- - - New HTTPHandling Methods - - : - Response.\_\_nonzero\_\_ (false if bad HTTP Status) - - Response.ok (True if expected HTTP Status) - - Response.error (Logged HTTPError if bad HTTP Status) - - Response.raise\_for\_status() (Raises stored HTTPError) - -0.2.2 (2011-02-14) ------------------- - -- Still handles request in the event of an HTTPError. (Issue \#2) -- Eventlet and Gevent Monkeypatch support. -- Cookie Support (Issue \#1) - -0.2.1 (2011-02-14) ------------------- - -- Added file attribute to POST and PUT requests for multipart-encode - file uploads. -- Added Request.url attribute for context and redirects - -0.2.0 (2011-02-14) ------------------- - -- Birth! - -0.0.1 (2011-02-13) ------------------- - -- Frustration -- Conception - diff --git a/third_party/python/requests/MANIFEST.in b/third_party/python/requests/MANIFEST.in deleted file mode 100644 index 633be369e217..000000000000 --- a/third_party/python/requests/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include README.md LICENSE NOTICE HISTORY.md pytest.ini requirements-dev.txt -recursive-include tests *.py diff --git a/third_party/python/requests/NOTICE b/third_party/python/requests/NOTICE deleted file mode 100644 index 1ff62db68827..000000000000 --- a/third_party/python/requests/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -Requests -Copyright 2019 Kenneth Reitz diff --git a/third_party/python/requests/PKG-INFO b/third_party/python/requests/PKG-INFO deleted file mode 100644 index e0c4f7984dfa..000000000000 --- a/third_party/python/requests/PKG-INFO +++ /dev/null @@ -1,93 +0,0 @@ -Metadata-Version: 2.1 -Name: requests -Version: 2.25.1 -Summary: Python HTTP for Humans. -Home-page: https://requests.readthedocs.io -Author: Kenneth Reitz -Author-email: me@kennethreitz.org -License: Apache 2.0 -Project-URL: Documentation, https://requests.readthedocs.io -Project-URL: Source, https://github.com/psf/requests -Description: # Requests - - **Requests** is a simple, yet elegant HTTP library. - - ```python - >>> import requests - >>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) - >>> r.status_code - 200 - >>> r.headers['content-type'] - 'application/json; charset=utf8' - >>> r.encoding - 'utf-8' - >>> r.text - '{"type":"User"...' - >>> r.json() - {'disk_usage': 368627, 'private_gists': 484, ...} - ``` - - Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method! - - Requests is one of the most downloaded Python package today, pulling in around `14M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `500,000+` repositories. You may certainly put your trust in this code. - - [![Downloads](https://pepy.tech/badge/requests/month)](https://pepy.tech/project/requests/month) - [![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests) - [![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors) - - ## Installing Requests and Supported Versions - - Requests is available on PyPI: - - ```console - $ python -m pip install requests - ``` - - Requests officially supports Python 2.7 & 3.5+. - - ## Supported Features & Best–Practices - - Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today. - - - Keep-Alive & Connection Pooling - - International Domains and URLs - - Sessions with Cookie Persistence - - Browser-style TLS/SSL Verification - - Basic & Digest Authentication - - Familiar `dict`–like Cookies - - Automatic Content Decompression and Decoding - - Multi-part File Uploads - - SOCKS Proxy Support - - Connection Timeouts - - Streaming Downloads - - Automatic honoring of `.netrc` - - Chunked HTTP Requests - - ## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io) - - [![Read the Docs](https://raw.githubusercontent.com/psf/requests/master/ext/ss.png)](https://requests.readthedocs.io) - - --- - - [![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/master/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/master/ext/psf.png)](https://www.python.org/psf) - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* -Description-Content-Type: text/markdown -Provides-Extra: security -Provides-Extra: socks diff --git a/third_party/python/requests/pytest.ini b/third_party/python/requests/pytest.ini deleted file mode 100644 index 13fa000028ac..000000000000 --- a/third_party/python/requests/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -addopts = -p no:warnings --doctest-modules -doctest_optionflags= NORMALIZE_WHITESPACE ELLIPSIS \ No newline at end of file diff --git a/third_party/python/requests/LICENSE b/third_party/python/requests/requests-2.25.1.dist-info/LICENSE similarity index 100% rename from third_party/python/requests/LICENSE rename to third_party/python/requests/requests-2.25.1.dist-info/LICENSE diff --git a/third_party/python/requests/README.md b/third_party/python/requests/requests-2.25.1.dist-info/METADATA similarity index 59% rename from third_party/python/requests/README.md rename to third_party/python/requests/requests-2.25.1.dist-info/METADATA index 74d368952f83..6aaa2dda9066 100644 --- a/third_party/python/requests/README.md +++ b/third_party/python/requests/requests-2.25.1.dist-info/METADATA @@ -1,3 +1,42 @@ +Metadata-Version: 2.1 +Name: requests +Version: 2.25.1 +Summary: Python HTTP for Humans. +Home-page: https://requests.readthedocs.io +Author: Kenneth Reitz +Author-email: me@kennethreitz.org +License: Apache 2.0 +Project-URL: Documentation, https://requests.readthedocs.io +Project-URL: Source, https://github.com/psf/requests +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/markdown +Requires-Dist: chardet (<5,>=3.0.2) +Requires-Dist: idna (<3,>=2.5) +Requires-Dist: urllib3 (<1.27,>=1.21.1) +Requires-Dist: certifi (>=2017.4.17) +Provides-Extra: security +Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'security' +Requires-Dist: cryptography (>=1.3.4) ; extra == 'security' +Provides-Extra: socks +Requires-Dist: PySocks (!=1.5.7,>=1.5.6) ; extra == 'socks' +Requires-Dist: win-inet-pton ; (sys_platform == "win32" and python_version == "2.7") and extra == 'socks' + # Requests **Requests** is a simple, yet elegant HTTP library. @@ -60,3 +99,5 @@ Requests is ready for the demands of building robust and reliable HTTP–speakin --- [![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/master/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/master/ext/psf.png)](https://www.python.org/psf) + + diff --git a/third_party/python/requests/requests-2.25.1.dist-info/RECORD b/third_party/python/requests/requests-2.25.1.dist-info/RECORD new file mode 100644 index 000000000000..8b3838689046 --- /dev/null +++ b/third_party/python/requests/requests-2.25.1.dist-info/RECORD @@ -0,0 +1,23 @@ +requests/__init__.py,sha256=rsmg7xmbbCE_zmDcG6EDk_pyvdEfadztdBaWIkInlH8,4141 +requests/__version__.py,sha256=k4J8c1yFRFzwGWwlN7miaDOclFtbcIs1GlnmT17YbXQ,441 +requests/_internal_utils.py,sha256=Zx3PnEUccyfsB-ie11nZVAW8qClJy0gx1qNME7rgT18,1096 +requests/adapters.py,sha256=WelSM1BCQXdbjEuDsBxqKDADeY8BHmxlrwbNnLN2rr4,21344 +requests/api.py,sha256=PlHM-HT3PQ5lyufoeGmV-nJxRi7UnUyGVh7OV7B9XV4,6496 +requests/auth.py,sha256=OMoJIVKyRLy9THr91y8rxysZuclwPB-K1Xg1zBomUhQ,10207 +requests/certs.py,sha256=dOB5rV2DZ13dEhq9BUa_4hd5kAqg59e_zUZB00faYz8,453 +requests/compat.py,sha256=iBRvu-X540CH4PJsuxr0vcGTnl_TZhq_75SwmeckQ7w,1782 +requests/cookies.py,sha256=Y-bKX6TvW3FnYlE6Au0SXtVVWcaNdFvuAwQxw-G0iTI,18430 +requests/exceptions.py,sha256=xXoj1rdhnxTS_DYphKZ9OvFZJQZ333A64REc9ZDZIgU,3161 +requests/help.py,sha256=lLcBtKAar8T6T78e9Tc4Zfd_EEJFhntxgib1JHNctEI,3515 +requests/hooks.py,sha256=QReGyy0bRcr5rkwCuObNakbYsc7EkiKeBwG4qHekr2Q,757 +requests/models.py,sha256=Uhb4Ra_ubNGBf-6ktHShgO5mUSCGZKa5D_wLGVCMtYk,34308 +requests/packages.py,sha256=Q2rF0L5mc3wQAvc6q_lAVtPTDOaOeFgD-7kWSQLkjEQ,542 +requests/sessions.py,sha256=BsnR-zYILgoFzJ6yq4T8ht_i0PwwPGVAxWxWaV5dcHg,30137 +requests/status_codes.py,sha256=gT79Pbs_cQjBgp-fvrUgg1dn2DQO32bDj4TInjnMPSc,4188 +requests/structures.py,sha256=msAtr9mq1JxHd-JRyiILfdFlpbJwvvFuP3rfUQT_QxE,3005 +requests/utils.py,sha256=_K9AgkN6efPe-a-zgZurXzds5PBC0CzDkyjAE2oCQFQ,30529 +requests-2.25.1.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142 +requests-2.25.1.dist-info/METADATA,sha256=RuNh38uN0IMsRT3OwaTNB_WyGx6RMwwQoMwujXfkUVM,4168 +requests-2.25.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +requests-2.25.1.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9 +requests-2.25.1.dist-info/RECORD,, diff --git a/third_party/python/requests/requests-2.25.1.dist-info/WHEEL b/third_party/python/requests/requests-2.25.1.dist-info/WHEEL new file mode 100644 index 000000000000..01b8fc7d4a10 --- /dev/null +++ b/third_party/python/requests/requests-2.25.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/requests/requests.egg-info/top_level.txt b/third_party/python/requests/requests-2.25.1.dist-info/top_level.txt similarity index 100% rename from third_party/python/requests/requests.egg-info/top_level.txt rename to third_party/python/requests/requests-2.25.1.dist-info/top_level.txt diff --git a/third_party/python/requests/requests.egg-info/PKG-INFO b/third_party/python/requests/requests.egg-info/PKG-INFO deleted file mode 100644 index e0c4f7984dfa..000000000000 --- a/third_party/python/requests/requests.egg-info/PKG-INFO +++ /dev/null @@ -1,93 +0,0 @@ -Metadata-Version: 2.1 -Name: requests -Version: 2.25.1 -Summary: Python HTTP for Humans. -Home-page: https://requests.readthedocs.io -Author: Kenneth Reitz -Author-email: me@kennethreitz.org -License: Apache 2.0 -Project-URL: Documentation, https://requests.readthedocs.io -Project-URL: Source, https://github.com/psf/requests -Description: # Requests - - **Requests** is a simple, yet elegant HTTP library. - - ```python - >>> import requests - >>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) - >>> r.status_code - 200 - >>> r.headers['content-type'] - 'application/json; charset=utf8' - >>> r.encoding - 'utf-8' - >>> r.text - '{"type":"User"...' - >>> r.json() - {'disk_usage': 368627, 'private_gists': 484, ...} - ``` - - Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method! - - Requests is one of the most downloaded Python package today, pulling in around `14M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `500,000+` repositories. You may certainly put your trust in this code. - - [![Downloads](https://pepy.tech/badge/requests/month)](https://pepy.tech/project/requests/month) - [![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests) - [![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors) - - ## Installing Requests and Supported Versions - - Requests is available on PyPI: - - ```console - $ python -m pip install requests - ``` - - Requests officially supports Python 2.7 & 3.5+. - - ## Supported Features & Best–Practices - - Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today. - - - Keep-Alive & Connection Pooling - - International Domains and URLs - - Sessions with Cookie Persistence - - Browser-style TLS/SSL Verification - - Basic & Digest Authentication - - Familiar `dict`–like Cookies - - Automatic Content Decompression and Decoding - - Multi-part File Uploads - - SOCKS Proxy Support - - Connection Timeouts - - Streaming Downloads - - Automatic honoring of `.netrc` - - Chunked HTTP Requests - - ## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io) - - [![Read the Docs](https://raw.githubusercontent.com/psf/requests/master/ext/ss.png)](https://requests.readthedocs.io) - - --- - - [![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/master/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/master/ext/psf.png)](https://www.python.org/psf) - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* -Description-Content-Type: text/markdown -Provides-Extra: security -Provides-Extra: socks diff --git a/third_party/python/requests/requests.egg-info/SOURCES.txt b/third_party/python/requests/requests.egg-info/SOURCES.txt deleted file mode 100644 index 01cc20801d9c..000000000000 --- a/third_party/python/requests/requests.egg-info/SOURCES.txt +++ /dev/null @@ -1,47 +0,0 @@ -HISTORY.md -LICENSE -MANIFEST.in -NOTICE -README.md -pytest.ini -requirements-dev.txt -setup.cfg -setup.py -requests/__init__.py -requests/__version__.py -requests/_internal_utils.py -requests/adapters.py -requests/api.py -requests/auth.py -requests/certs.py -requests/compat.py -requests/cookies.py -requests/exceptions.py -requests/help.py -requests/hooks.py -requests/models.py -requests/packages.py -requests/sessions.py -requests/status_codes.py -requests/structures.py -requests/utils.py -requests.egg-info/PKG-INFO -requests.egg-info/SOURCES.txt -requests.egg-info/dependency_links.txt -requests.egg-info/not-zip-safe -requests.egg-info/requires.txt -requests.egg-info/top_level.txt -tests/__init__.py -tests/compat.py -tests/conftest.py -tests/test_help.py -tests/test_hooks.py -tests/test_lowlevel.py -tests/test_packages.py -tests/test_requests.py -tests/test_structures.py -tests/test_testserver.py -tests/test_utils.py -tests/utils.py -tests/testserver/__init__.py -tests/testserver/server.py \ No newline at end of file diff --git a/third_party/python/requests/requests.egg-info/dependency_links.txt b/third_party/python/requests/requests.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/requests/requests.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/requests/requests.egg-info/not-zip-safe b/third_party/python/requests/requests.egg-info/not-zip-safe deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/requests/requests.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/requests/requests.egg-info/requires.txt b/third_party/python/requests/requests.egg-info/requires.txt deleted file mode 100644 index 0d195cab43de..000000000000 --- a/third_party/python/requests/requests.egg-info/requires.txt +++ /dev/null @@ -1,14 +0,0 @@ -chardet<5,>=3.0.2 -idna<3,>=2.5 -urllib3<1.27,>=1.21.1 -certifi>=2017.4.17 - -[security] -pyOpenSSL>=0.14 -cryptography>=1.3.4 - -[socks] -PySocks!=1.5.7,>=1.5.6 - -[socks:sys_platform == "win32" and python_version == "2.7"] -win_inet_pton diff --git a/third_party/python/requests/requirements-dev.txt b/third_party/python/requests/requirements-dev.txt deleted file mode 100644 index b80a32e42221..000000000000 --- a/third_party/python/requests/requirements-dev.txt +++ /dev/null @@ -1,6 +0,0 @@ -pytest>=2.8.0,<=3.10.1 -pytest-cov -pytest-httpbin<1.0 -pytest-mock==2.0.0 -httpbin==0.7.0 -wheel diff --git a/third_party/python/requests/setup.cfg b/third_party/python/requests/setup.cfg deleted file mode 100644 index 51b5f83b3da1..000000000000 --- a/third_party/python/requests/setup.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/requests/setup.py b/third_party/python/requests/setup.py deleted file mode 100755 index 7ba4b2a25fa1..000000000000 --- a/third_party/python/requests/setup.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python -# Learn more: https://github.com/kennethreitz/setup.py -import os -import re -import sys - -from codecs import open - -from setuptools import setup -from setuptools.command.test import test as TestCommand - -here = os.path.abspath(os.path.dirname(__file__)) - -class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass into py.test")] - - def initialize_options(self): - TestCommand.initialize_options(self) - try: - from multiprocessing import cpu_count - self.pytest_args = ['-n', str(cpu_count()), '--boxed'] - except (ImportError, NotImplementedError): - self.pytest_args = ['-n', '1', '--boxed'] - - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = [] - self.test_suite = True - - def run_tests(self): - import pytest - - errno = pytest.main(self.pytest_args) - sys.exit(errno) - -# 'setup.py publish' shortcut. -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel') - os.system('twine upload dist/*') - sys.exit() - -packages = ['requests'] - -requires = [ - 'chardet>=3.0.2,<5', - 'idna>=2.5,<3', - 'urllib3>=1.21.1,<1.27', - 'certifi>=2017.4.17' - -] -test_requirements = [ - 'pytest-httpbin==0.0.7', - 'pytest-cov', - 'pytest-mock', - 'pytest-xdist', - 'PySocks>=1.5.6, !=1.5.7', - 'pytest>=3' -] - -about = {} -with open(os.path.join(here, 'requests', '__version__.py'), 'r', 'utf-8') as f: - exec(f.read(), about) - -with open('README.md', 'r', 'utf-8') as f: - readme = f.read() - -setup( - name=about['__title__'], - version=about['__version__'], - description=about['__description__'], - long_description=readme, - long_description_content_type='text/markdown', - author=about['__author__'], - author_email=about['__author_email__'], - url=about['__url__'], - packages=packages, - package_data={'': ['LICENSE', 'NOTICE']}, - package_dir={'requests': 'requests'}, - include_package_data=True, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", - install_requires=requires, - license=about['__license__'], - zip_safe=False, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Natural Language :: English', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy' - ], - cmdclass={'test': PyTest}, - tests_require=test_requirements, - extras_require={ - 'security': ['pyOpenSSL >= 0.14', 'cryptography>=1.3.4'], - 'socks': ['PySocks>=1.5.6, !=1.5.7'], - 'socks:sys_platform == "win32" and python_version == "2.7"': ['win_inet_pton'], - }, - project_urls={ - 'Documentation': 'https://requests.readthedocs.io', - 'Source': 'https://github.com/psf/requests', - }, -) diff --git a/third_party/python/responses/CHANGES b/third_party/python/responses/CHANGES deleted file mode 100644 index 569f52f99d78..000000000000 --- a/third_party/python/responses/CHANGES +++ /dev/null @@ -1,119 +0,0 @@ -0.10.6 ------- - -- Improved documentation. -- Improved installation requirements for py3 -- ConnectionError's raised by responses now indicate which request - path/method failed to match a mock. -- `test_responses.py` is no longer part of the installation targets. - -0.10.5 ------- - -- Improved support for raising exceptions from callback mocks. If a mock - callback returns an exception object that exception will be raised. - -0.10.4 ------- - -- Fixed generated wrapper when using `@responses.activate` in Python 3.6+ - when decorated functions use parameter and/or return annotations. - -0.10.3 ------- - -- Fixed deprecation warnings in python 3.7 for inspect module usage. - -0.10.2 ------- - -- Fixed build setup to use undeprecated `pytest` bin stub. -- Updated `tox` configuration. -- Added example of using responses with `pytest.fixture` -- Removed dependency on `biscuits` in py3. Instead `http.cookies` is being used. - -0.10.1 ------- - -- Packaging fix to distribute wheel (#219) - -0.10.0 ------- - -- Fix passing through extra settings (#207) -- Fix collections.abc warning on Python 3.7 (#215) -- Use 'biscuits' library instead of 'cookies' on Python 3.4+ (#218) - -0.9.0 ------ - -- Support for Python 3.7 (#196) -- Support streaming responses for BaseResponse (#192) -- Support custom patch targets for mock (#189) -- Fix unicode support for passthru urls (#178) -- Fix support for unicode in domain names and tlds (177) - -0.8.0 ------ - -- Added the ability to passthru real requests via ``add_passthru()`` - and ``passthru_prefixes`` configurations. - -0.7.0 ------ - -- Responses will now be rotated until the final match is hit, and - then persist using that response (GH-171). - -0.6.2 ------ - -- Fixed call counting with exceptions (GH-163). -- Fixed behavior with arbitrary status codes (GH-164). -- Fixed handling of multiple responses with the same match (GH-165). -- Fixed default path behavior with ``match_querystring`` (GH-166). - -0.6.1 ------ - -- Restored ``adding_headers`` compatibility (GH-160). - -0.6.0 ------ - -- Allow empty list/dict as json object (GH-100). -- Added `response_callback` (GH-151). -- Added ``Response`` interfaces (GH-155). -- Fixed unicode characters in querystring (GH-153). -- Added support for streaming IO buffers (GH-154). -- Added support for empty (unset) Content-Type (GH-139). -- Added reason to mocked responses (GH-132). -- ``yapf`` autoformatting now enforced on codebase. - -0.5.1 ------ - -- Add LICENSE, README and CHANGES to the PyPI distribution (GH-97). - -0.5.0 ------ - -- Allow passing a JSON body to `response.add` (GH-82) -- Improve ConnectionError emulation (GH-73) -- Correct assertion in assert_all_requests_are_fired (GH-71) - -0.4.0 ------ - -- Requests 2.0+ is required -- Mocking now happens on the adapter instead of the session - -0.3.0 ------ - -- Add the ability to mock errors (GH-22) -- Add responses.mock context manager (GH-36) -- Support custom adapters (GH-33) -- Add support for regexp error matching (GH-25) -- Add support for dynamic bodies via `responses.add_callback` (GH-24) -- Preserve argspec when using `responses.activate` decorator (GH-18) diff --git a/third_party/python/responses/MANIFEST.in b/third_party/python/responses/MANIFEST.in deleted file mode 100644 index 12977a99c80d..000000000000 --- a/third_party/python/responses/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include README.rst CHANGES LICENSE -include test_responses.py tox.ini -global-exclude *~ diff --git a/third_party/python/responses/PKG-INFO b/third_party/python/responses/PKG-INFO deleted file mode 100644 index 54677a9dd395..000000000000 --- a/third_party/python/responses/PKG-INFO +++ /dev/null @@ -1,443 +0,0 @@ -Metadata-Version: 2.1 -Name: responses -Version: 0.10.6 -Summary: A utility library for mocking out the `requests` Python library. -Home-page: https://github.com/getsentry/responses -Author: David Cramer -License: Apache 2.0 -Description: Responses - ========= - - .. image:: https://travis-ci.org/getsentry/responses.svg?branch=master - :target: https://travis-ci.org/getsentry/responses - - A utility library for mocking out the `requests` Python library. - - .. note:: - - Responses requires Python 2.7 or newer, and requests >= 2.0 - - - Installing - ---------- - - ``pip install responses`` - - - Basics - ------ - - The core of ``responses`` comes from registering mock responses: - - .. code-block:: python - - import responses - import requests - - @responses.activate - def test_simple(): - responses.add(responses.GET, 'http://twitter.com/api/1/foobar', - json={'error': 'not found'}, status=404) - - resp = requests.get('http://twitter.com/api/1/foobar') - - assert resp.json() == {"error": "not found"} - - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar' - assert responses.calls[0].response.text == '{"error": "not found"}' - - If you attempt to fetch a url which doesn't hit a match, ``responses`` will raise - a ``ConnectionError``: - - .. code-block:: python - - import responses - import requests - - from requests.exceptions import ConnectionError - - @responses.activate - def test_simple(): - with pytest.raises(ConnectionError): - requests.get('http://twitter.com/api/1/foobar') - - Lastly, you can pass an ``Exception`` as the body to trigger an error on the request: - - .. code-block:: python - - import responses - import requests - - @responses.activate - def test_simple(): - responses.add(responses.GET, 'http://twitter.com/api/1/foobar', - body=Exception('...')) - with pytest.raises(Exception): - requests.get('http://twitter.com/api/1/foobar') - - - Response Parameters - ------------------- - - Responses are automatically registered via params on ``add``, but can also be - passed directly: - - .. code-block:: python - - import responses - - responses.add( - responses.Response( - method='GET', - url='http://example.com', - ) - ) - - The following attributes can be passed to a Response mock: - - method (``str``) - The HTTP method (GET, POST, etc). - - url (``str`` or compiled regular expression) - The full resource URL. - - match_querystring (``bool``) - Include the query string when matching requests. - Enabled by default if the response URL contains a query string, - disabled if it doesn't or the URL is a regular expression. - - body (``str`` or ``BufferedReader``) - The response body. - - json - A Python object representing the JSON response body. Automatically configures - the appropriate Content-Type. - - status (``int``) - The HTTP status code. - - content_type (``content_type``) - Defaults to ``text/plain``. - - headers (``dict``) - Response headers. - - stream (``bool``) - Disabled by default. Indicates the response should use the streaming API. - - - Dynamic Responses - ----------------- - - You can utilize callbacks to provide dynamic responses. The callback must return - a tuple of (``status``, ``headers``, ``body``). - - .. code-block:: python - - import json - - import responses - import requests - - @responses.activate - def test_calc_api(): - - def request_callback(request): - payload = json.loads(request.body) - resp_body = {'value': sum(payload['numbers'])} - headers = {'request-id': '728d329e-0e86-11e4-a748-0c84dc037c13'} - return (200, headers, json.dumps(resp_body)) - - responses.add_callback( - responses.POST, 'http://calc.com/sum', - callback=request_callback, - content_type='application/json', - ) - - resp = requests.post( - 'http://calc.com/sum', - json.dumps({'numbers': [1, 2, 3]}), - headers={'content-type': 'application/json'}, - ) - - assert resp.json() == {'value': 6} - - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == 'http://calc.com/sum' - assert responses.calls[0].response.text == '{"value": 6}' - assert ( - responses.calls[0].response.headers['request-id'] == - '728d329e-0e86-11e4-a748-0c84dc037c13' - ) - - You can also pass a compiled regex to `add_callback` to match multiple urls: - - .. code-block:: python - - import re, json - - from functools import reduce - - import responses - import requests - - operators = { - 'sum': lambda x, y: x+y, - 'prod': lambda x, y: x*y, - 'pow': lambda x, y: x**y - } - - @responses.activate - def test_regex_url(): - - def request_callback(request): - payload = json.loads(request.body) - operator_name = request.path_url[1:] - - operator = operators[operator_name] - - resp_body = {'value': reduce(operator, payload['numbers'])} - headers = {'request-id': '728d329e-0e86-11e4-a748-0c84dc037c13'} - return (200, headers, json.dumps(resp_body)) - - responses.add_callback( - responses.POST, - re.compile('http://calc.com/(sum|prod|pow|unsupported)'), - callback=request_callback, - content_type='application/json', - ) - - resp = requests.post( - 'http://calc.com/prod', - json.dumps({'numbers': [2, 3, 4]}), - headers={'content-type': 'application/json'}, - ) - assert resp.json() == {'value': 24} - - test_regex_url() - - - If you want to pass extra keyword arguments to the callback function, for example when reusing - a callback function to give a slightly different result, you can use ``functools.partial``: - - .. code-block:: python - - from functools import partial - - ... - - def request_callback(request, id=None): - payload = json.loads(request.body) - resp_body = {'value': sum(payload['numbers'])} - headers = {'request-id': id} - return (200, headers, json.dumps(resp_body)) - - responses.add_callback( - responses.POST, 'http://calc.com/sum', - callback=partial(request_callback, id='728d329e-0e86-11e4-a748-0c84dc037c13'), - content_type='application/json', - ) - - - Responses as a context manager - ------------------------------ - - .. code-block:: python - - import responses - import requests - - def test_my_api(): - with responses.RequestsMock() as rsps: - rsps.add(responses.GET, 'http://twitter.com/api/1/foobar', - body='{}', status=200, - content_type='application/json') - resp = requests.get('http://twitter.com/api/1/foobar') - - assert resp.status_code == 200 - - # outside the context manager requests will hit the remote server - resp = requests.get('http://twitter.com/api/1/foobar') - resp.status_code == 404 - - Responses as a pytest fixture - ----------------------------- - - .. code-block:: python - - @pytest.fixture - def mocked_responses(): - with responses.RequestsMock() as rsps: - yield rsps - - def test_api(mocked_responses): - mocked_responses.add( - responses.GET, 'http://twitter.com/api/1/foobar', - body='{}', status=200, - content_type='application/json') - resp = requests.get('http://twitter.com/api/1/foobar') - assert resp.status_code == 200 - - Assertions on declared responses - -------------------------------- - - When used as a context manager, Responses will, by default, raise an assertion - error if a url was registered but not accessed. This can be disabled by passing - the ``assert_all_requests_are_fired`` value: - - .. code-block:: python - - import responses - import requests - - def test_my_api(): - with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: - rsps.add(responses.GET, 'http://twitter.com/api/1/foobar', - body='{}', status=200, - content_type='application/json') - - - Multiple Responses - ------------------ - - You can also add multiple responses for the same url: - - .. code-block:: python - - import responses - import requests - - @responses.activate - def test_my_api(): - responses.add(responses.GET, 'http://twitter.com/api/1/foobar', status=500) - responses.add(responses.GET, 'http://twitter.com/api/1/foobar', - body='{}', status=200, - content_type='application/json') - - resp = requests.get('http://twitter.com/api/1/foobar') - assert resp.status_code == 500 - resp = requests.get('http://twitter.com/api/1/foobar') - assert resp.status_code == 200 - - - Using a callback to modify the response - --------------------------------------- - - If you use customized processing in `requests` via subclassing/mixins, or if you - have library tools that interact with `requests` at a low level, you may need - to add extended processing to the mocked Response object to fully simulate the - environment for your tests. A `response_callback` can be used, which will be - wrapped by the library before being returned to the caller. The callback - accepts a `response` as it's single argument, and is expected to return a - single `response` object. - - .. code-block:: python - - import responses - import requests - - def response_callback(resp): - resp.callback_processed = True - return resp - - with responses.RequestsMock(response_callback=response_callback) as m: - m.add(responses.GET, 'http://example.com', body=b'test') - resp = requests.get('http://example.com') - assert resp.text == "test" - assert hasattr(resp, 'callback_processed') - assert resp.callback_processed is True - - - Passing thru real requests - -------------------------- - - In some cases you may wish to allow for certain requests to pass thru responses - and hit a real server. This can be done with the 'passthru' methods: - - .. code-block:: python - - import responses - - @responses.activate - def test_my_api(): - responses.add_passthru('https://percy.io') - - This will allow any requests matching that prefix, that is otherwise not registered - as a mock response, to passthru using the standard behavior. - - - Viewing/Modifying registered responses - -------------------------------------- - - Registered responses are available as a private attribute of the RequestMock - instance. It is sometimes useful for debugging purposes to view the stack of - registered responses which can be accessed via ``responses.mock._matches``. - - The ``replace`` function allows a previously registered ``response`` to be - changed. The method signature is identical to ``add``. ``response``s are - identified using ``method`` and ``url``. Only the first matched ``response`` is - replaced. - - .. code-block:: python - - import responses - import requests - - @responses.activate - def test_replace(): - - responses.add(responses.GET, 'http://example.org', json={'data': 1}) - responses.replace(responses.GET, 'http://example.org', json={'data': 2}) - - resp = requests.get('http://example.org') - - assert resp.json() == {'data': 2} - - - ``remove`` takes a ``method`` and ``url`` argument and will remove *all* - matched ``response``s from the registered list. - - Finally, ``clear`` will reset all registered ``response``s - - - - Contributing - ------------ - - Responses uses several linting and autoformatting utilities, so it's important that when - submitting patches you use the appropriate toolchain: - - Clone the repository: - - .. code-block:: shell - - git clone https://github.com/getsentry/responses.git - - Create an environment (e.g. with ``virtualenv``): - - .. code-block:: shell - - virtualenv .env && source .env/bin/activate - - Configure development requirements: - - .. code-block:: shell - - make develop - -Platform: UNKNOWN -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Topic :: Software Development -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* -Provides-Extra: tests diff --git a/third_party/python/responses/LICENSE b/third_party/python/responses/responses-0.10.6.dist-info/LICENSE similarity index 100% rename from third_party/python/responses/LICENSE rename to third_party/python/responses/responses-0.10.6.dist-info/LICENSE diff --git a/third_party/python/responses/README.rst b/third_party/python/responses/responses-0.10.6.dist-info/METADATA similarity index 90% rename from third_party/python/responses/README.rst rename to third_party/python/responses/responses-0.10.6.dist-info/METADATA index 73a6d7a8f2da..45368b35d557 100644 --- a/third_party/python/responses/README.rst +++ b/third_party/python/responses/responses-0.10.6.dist-info/METADATA @@ -1,3 +1,35 @@ +Metadata-Version: 2.1 +Name: responses +Version: 0.10.6 +Summary: A utility library for mocking out the `requests` Python library. +Home-page: https://github.com/getsentry/responses +Author: David Cramer +License: Apache 2.0 +Platform: UNKNOWN +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Topic :: Software Development +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: requests (>=2.0) +Requires-Dist: six +Requires-Dist: mock ; python_version < "3.3" +Requires-Dist: cookies ; python_version < "3.4" +Provides-Extra: tests +Requires-Dist: pytest ; extra == 'tests' +Requires-Dist: coverage (<5.0.0,>=3.7.1) ; extra == 'tests' +Requires-Dist: pytest-cov ; extra == 'tests' +Requires-Dist: pytest-localserver ; extra == 'tests' +Requires-Dist: flake8 ; extra == 'tests' + Responses ========= @@ -418,3 +450,5 @@ Configure development requirements: .. code-block:: shell make develop + + diff --git a/third_party/python/responses/responses-0.10.6.dist-info/RECORD b/third_party/python/responses/responses-0.10.6.dist-info/RECORD new file mode 100644 index 000000000000..ab6546d203a9 --- /dev/null +++ b/third_party/python/responses/responses-0.10.6.dist-info/RECORD @@ -0,0 +1,6 @@ +responses.py,sha256=We44OwS185MQp72HCzsUCoGnzmfOhI6AH_MQq0yLQuU,19550 +responses-0.10.6.dist-info/LICENSE,sha256=SJ7LcLREfANKEJeKSwjaAVyb2fqVyjrq8hnZgVQWpnw,10835 +responses-0.10.6.dist-info/METADATA,sha256=pW-WNNN44ZdoLe1C7UQstvt2ffO-WNFyQ_haglud19o,13088 +responses-0.10.6.dist-info/WHEEL,sha256=HX-v9-noUkyUoxyZ1PMSuS7auUxDAR4VBdoYLqD0xws,110 +responses-0.10.6.dist-info/top_level.txt,sha256=aQhzfC0bq4TkAaB_Yr-7cv4u2Xnc8WiVzvh4KdZo0Qo,10 +responses-0.10.6.dist-info/RECORD,, diff --git a/third_party/python/responses/responses-0.10.6.dist-info/WHEEL b/third_party/python/responses/responses-0.10.6.dist-info/WHEEL new file mode 100644 index 000000000000..c8240f03e87f --- /dev/null +++ b/third_party/python/responses/responses-0.10.6.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/responses/responses-0.10.6.dist-info/top_level.txt b/third_party/python/responses/responses-0.10.6.dist-info/top_level.txt new file mode 100644 index 000000000000..2cb24f43db3b --- /dev/null +++ b/third_party/python/responses/responses-0.10.6.dist-info/top_level.txt @@ -0,0 +1 @@ +responses diff --git a/third_party/python/responses/setup.cfg b/third_party/python/responses/setup.cfg deleted file mode 100644 index 79de8cb6e560..000000000000 --- a/third_party/python/responses/setup.cfg +++ /dev/null @@ -1,16 +0,0 @@ -[tool:pytest] -addopts = --tb=short - -[bdist_wheel] -universal = 1 - -[flake8] -max-line-length = 100 - -[yapf] -based_on_style = pep8 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/responses/setup.py b/third_party/python/responses/setup.py deleted file mode 100644 index 779aa32f400c..000000000000 --- a/third_party/python/responses/setup.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -""" -responses -========= - -A utility library for mocking out the `requests` Python library. - -:copyright: (c) 2015 David Cramer -:license: Apache 2.0 -""" - -import sys - -from setuptools import setup -from setuptools.command.test import test as TestCommand - -setup_requires = [] - -if "test" in sys.argv: - setup_requires.append("pytest") - -install_requires = [ - "cookies; python_version < '3.4'", - "mock; python_version < '3.3'", - "requests>=2.0", - "six", -] - -tests_require = [ - "pytest", - "coverage >= 3.7.1, < 5.0.0", - "pytest-cov", - "pytest-localserver", - "flake8", -] - -extras_require = {"tests": tests_require} - - -class PyTest(TestCommand): - def finalize_options(self): - TestCommand.finalize_options(self) - self.test_args = ["test_responses.py"] - self.test_suite = True - - def run_tests(self): - # import here, cause outside the eggs aren't loaded - import pytest - - errno = pytest.main(self.test_args) - sys.exit(errno) - - -setup( - name="responses", - version="0.10.6", - author="David Cramer", - description=("A utility library for mocking out the `requests` Python library."), - url="https://github.com/getsentry/responses", - license="Apache 2.0", - long_description=open("README.rst").read(), - py_modules=["responses"], - zip_safe=False, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", - install_requires=install_requires, - extras_require=extras_require, - tests_require=tests_require, - setup_requires=setup_requires, - cmdclass={"test": PyTest}, - include_package_data=True, - classifiers=[ - "Intended Audience :: Developers", - "Intended Audience :: System Administrators", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Topic :: Software Development", - ], -) diff --git a/third_party/python/responses/test_responses.py b/third_party/python/responses/test_responses.py deleted file mode 100644 index 0350e49538e9..000000000000 --- a/third_party/python/responses/test_responses.py +++ /dev/null @@ -1,924 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import, print_function, division, unicode_literals - -import inspect -import re -import six - -import pytest -import requests -import responses -from requests.exceptions import ConnectionError, HTTPError -from responses import BaseResponse, Response - -try: - from mock import patch, Mock -except ImportError: - from unittest.mock import patch, Mock - - -def assert_reset(): - assert len(responses._default_mock._matches) == 0 - assert len(responses.calls) == 0 - - -def assert_response(resp, body=None, content_type="text/plain"): - assert resp.status_code == 200 - assert resp.reason == "OK" - if content_type is not None: - assert resp.headers["Content-Type"] == content_type - else: - assert "Content-Type" not in resp.headers - assert resp.text == body - - -def test_response(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com", body=b"test") - resp = requests.get("http://example.com") - assert_response(resp, "test") - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == "http://example.com/" - assert responses.calls[0].response.content == b"test" - - resp = requests.get("http://example.com?foo=bar") - assert_response(resp, "test") - assert len(responses.calls) == 2 - assert responses.calls[1].request.url == "http://example.com/?foo=bar" - assert responses.calls[1].response.content == b"test" - - run() - assert_reset() - - -def test_response_encoded(): - @responses.activate - def run(): - # Path contains urlencoded =/()[] - url = "http://example.org/foo.bar%3D%2F%28%29%5B%5D" - responses.add(responses.GET, url, body="it works", status=200) - resp = requests.get(url) - assert_response(resp, "it works") - - run() - assert_reset() - - -def test_response_with_instance(): - @responses.activate - def run(): - responses.add( - responses.Response(method=responses.GET, url="http://example.com") - ) - resp = requests.get("http://example.com") - assert_response(resp, "") - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == "http://example.com/" - - resp = requests.get("http://example.com?foo=bar") - assert_response(resp, "") - assert len(responses.calls) == 2 - assert responses.calls[1].request.url == "http://example.com/?foo=bar" - - -@pytest.mark.parametrize( - "original,replacement", - [ - ("http://example.com/two", "http://example.com/two"), - ( - Response(method=responses.GET, url="http://example.com/two"), - Response( - method=responses.GET, url="http://example.com/two", body="testtwo" - ), - ), - ( - re.compile(r"http://example\.com/two"), - re.compile(r"http://example\.com/two"), - ), - ], -) -def test_replace(original, replacement): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com/one", body="test1") - - if isinstance(original, BaseResponse): - responses.add(original) - else: - responses.add(responses.GET, original, body="test2") - - responses.add(responses.GET, "http://example.com/three", body="test3") - responses.add( - responses.GET, re.compile(r"http://example\.com/four"), body="test3" - ) - - if isinstance(replacement, BaseResponse): - responses.replace(replacement) - else: - responses.replace(responses.GET, replacement, body="testtwo") - - resp = requests.get("http://example.com/two") - assert_response(resp, "testtwo") - - run() - assert_reset() - - -@pytest.mark.parametrize( - "original,replacement", - [ - ("http://example.com/one", re.compile(r"http://example\.com/one")), - (re.compile(r"http://example\.com/one"), "http://example.com/one"), - ], -) -def test_replace_error(original, replacement): - @responses.activate - def run(): - responses.add(responses.GET, original) - with pytest.raises(ValueError): - responses.replace(responses.GET, replacement) - - run() - assert_reset() - - -def test_remove(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com/zero") - responses.add(responses.GET, "http://example.com/one") - responses.add(responses.GET, "http://example.com/two") - responses.add(responses.GET, re.compile(r"http://example\.com/three")) - responses.add(responses.GET, re.compile(r"http://example\.com/four")) - re.purge() - responses.remove(responses.GET, "http://example.com/two") - responses.remove(Response(method=responses.GET, url="http://example.com/zero")) - responses.remove(responses.GET, re.compile(r"http://example\.com/four")) - - with pytest.raises(ConnectionError): - requests.get("http://example.com/zero") - requests.get("http://example.com/one") - with pytest.raises(ConnectionError): - requests.get("http://example.com/two") - requests.get("http://example.com/three") - with pytest.raises(ConnectionError): - requests.get("http://example.com/four") - - run() - assert_reset() - - -@pytest.mark.parametrize( - "args1,kwargs1,args2,kwargs2,expected", - [ - ((responses.GET, "a"), {}, (responses.GET, "a"), {}, True), - ((responses.GET, "a"), {}, (responses.GET, "b"), {}, False), - ((responses.GET, "a"), {}, (responses.POST, "a"), {}, False), - ( - (responses.GET, "a"), - {"match_querystring": True}, - (responses.GET, "a"), - {}, - True, - ), - ], -) -def test_response_equality(args1, kwargs1, args2, kwargs2, expected): - o1 = BaseResponse(*args1, **kwargs1) - o2 = BaseResponse(*args2, **kwargs2) - assert (o1 == o2) is expected - assert (o1 != o2) is not expected - - -def test_response_equality_different_objects(): - o1 = BaseResponse(method=responses.GET, url="a") - o2 = "str" - assert (o1 == o2) is False - assert (o1 != o2) is True - - -def test_connection_error(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com") - - with pytest.raises(ConnectionError): - requests.get("http://example.com/foo") - - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == "http://example.com/foo" - assert type(responses.calls[0].response) is ConnectionError - assert responses.calls[0].response.request - - run() - assert_reset() - - -def test_match_querystring(): - @responses.activate - def run(): - url = "http://example.com?test=1&foo=bar" - responses.add(responses.GET, url, match_querystring=True, body=b"test") - resp = requests.get("http://example.com?test=1&foo=bar") - assert_response(resp, "test") - resp = requests.get("http://example.com?foo=bar&test=1") - assert_response(resp, "test") - resp = requests.get("http://example.com/?foo=bar&test=1") - assert_response(resp, "test") - - run() - assert_reset() - - -def test_match_empty_querystring(): - @responses.activate - def run(): - responses.add( - responses.GET, "http://example.com", body=b"test", match_querystring=True - ) - resp = requests.get("http://example.com") - assert_response(resp, "test") - resp = requests.get("http://example.com/") - assert_response(resp, "test") - with pytest.raises(ConnectionError): - requests.get("http://example.com?query=foo") - - run() - assert_reset() - - -def test_match_querystring_error(): - @responses.activate - def run(): - responses.add( - responses.GET, "http://example.com/?test=1", match_querystring=True - ) - - with pytest.raises(ConnectionError): - requests.get("http://example.com/foo/?test=2") - - run() - assert_reset() - - -def test_match_querystring_regex(): - @responses.activate - def run(): - """Note that `match_querystring` value shouldn't matter when passing a - regular expression""" - - responses.add( - responses.GET, - re.compile(r"http://example\.com/foo/\?test=1"), - body="test1", - match_querystring=True, - ) - - resp = requests.get("http://example.com/foo/?test=1") - assert_response(resp, "test1") - - responses.add( - responses.GET, - re.compile(r"http://example\.com/foo/\?test=2"), - body="test2", - match_querystring=False, - ) - - resp = requests.get("http://example.com/foo/?test=2") - assert_response(resp, "test2") - - run() - assert_reset() - - -def test_match_querystring_error_regex(): - @responses.activate - def run(): - """Note that `match_querystring` value shouldn't matter when passing a - regular expression""" - - responses.add( - responses.GET, - re.compile(r"http://example\.com/foo/\?test=1"), - match_querystring=True, - ) - - with pytest.raises(ConnectionError): - requests.get("http://example.com/foo/?test=3") - - responses.add( - responses.GET, - re.compile(r"http://example\.com/foo/\?test=2"), - match_querystring=False, - ) - - with pytest.raises(ConnectionError): - requests.get("http://example.com/foo/?test=4") - - run() - assert_reset() - - -def test_match_querystring_auto_activates(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com?test=1", body=b"test") - resp = requests.get("http://example.com?test=1") - assert_response(resp, "test") - with pytest.raises(ConnectionError): - requests.get("http://example.com/?test=2") - - run() - assert_reset() - - -def test_accept_string_body(): - @responses.activate - def run(): - url = "http://example.com/" - responses.add(responses.GET, url, body="test") - resp = requests.get(url) - assert_response(resp, "test") - - run() - assert_reset() - - -def test_accept_json_body(): - @responses.activate - def run(): - content_type = "application/json" - - url = "http://example.com/" - responses.add(responses.GET, url, json={"message": "success"}) - resp = requests.get(url) - assert_response(resp, '{"message": "success"}', content_type) - - url = "http://example.com/1/" - responses.add(responses.GET, url, json=[]) - resp = requests.get(url) - assert_response(resp, "[]", content_type) - - run() - assert_reset() - - -def test_no_content_type(): - @responses.activate - def run(): - url = "http://example.com/" - responses.add(responses.GET, url, body="test", content_type=None) - resp = requests.get(url) - assert_response(resp, "test", content_type=None) - - run() - assert_reset() - - -def test_arbitrary_status_code(): - @responses.activate - def run(): - url = "http://example.com/" - responses.add(responses.GET, url, body="test", status=418) - resp = requests.get(url) - assert resp.status_code == 418 - assert resp.reason is None - - run() - assert_reset() - - -def test_throw_connection_error_explicit(): - @responses.activate - def run(): - url = "http://example.com" - exception = HTTPError("HTTP Error") - responses.add(responses.GET, url, exception) - - with pytest.raises(HTTPError) as HE: - requests.get(url) - - assert str(HE.value) == "HTTP Error" - - run() - assert_reset() - - -def test_callback(): - body = b"test callback" - status = 400 - reason = "Bad Request" - headers = {"foo": "bar"} - url = "http://example.com/" - - def request_callback(request): - return (status, headers, body) - - @responses.activate - def run(): - responses.add_callback(responses.GET, url, request_callback) - resp = requests.get(url) - assert resp.text == "test callback" - assert resp.status_code == status - assert resp.reason == reason - assert "foo" in resp.headers - assert resp.headers["foo"] == "bar" - - run() - assert_reset() - - -def test_callback_exception_result(): - result = Exception() - url = "http://example.com/" - - def request_callback(request): - return result - - @responses.activate - def run(): - responses.add_callback(responses.GET, url, request_callback) - - with pytest.raises(Exception) as e: - requests.get(url) - - assert e.value is result - - run() - assert_reset() - - -def test_callback_exception_body(): - body = Exception() - url = "http://example.com/" - - def request_callback(request): - return (200, {}, body) - - @responses.activate - def run(): - responses.add_callback(responses.GET, url, request_callback) - - with pytest.raises(Exception) as e: - requests.get(url) - - assert e.value is body - - run() - assert_reset() - - -def test_callback_no_content_type(): - body = b"test callback" - status = 400 - reason = "Bad Request" - headers = {"foo": "bar"} - url = "http://example.com/" - - def request_callback(request): - return (status, headers, body) - - @responses.activate - def run(): - responses.add_callback(responses.GET, url, request_callback, content_type=None) - resp = requests.get(url) - assert resp.text == "test callback" - assert resp.status_code == status - assert resp.reason == reason - assert "foo" in resp.headers - assert "Content-Type" not in resp.headers - - run() - assert_reset() - - -def test_regular_expression_url(): - @responses.activate - def run(): - url = re.compile(r"https?://(.*\.)?example.com") - responses.add(responses.GET, url, body=b"test") - - resp = requests.get("http://example.com") - assert_response(resp, "test") - - resp = requests.get("https://example.com") - assert_response(resp, "test") - - resp = requests.get("https://uk.example.com") - assert_response(resp, "test") - - with pytest.raises(ConnectionError): - requests.get("https://uk.exaaample.com") - - run() - assert_reset() - - -def test_custom_adapter(): - @responses.activate - def run(): - url = "http://example.com" - responses.add(responses.GET, url, body=b"test") - - calls = [0] - - class DummyAdapter(requests.adapters.HTTPAdapter): - def send(self, *a, **k): - calls[0] += 1 - return super(DummyAdapter, self).send(*a, **k) - - # Test that the adapter is actually used - session = requests.Session() - session.mount("http://", DummyAdapter()) - - resp = session.get(url, allow_redirects=False) - assert calls[0] == 1 - - # Test that the response is still correctly emulated - session = requests.Session() - session.mount("http://", DummyAdapter()) - - resp = session.get(url) - assert_response(resp, "test") - - run() - - -def test_responses_as_context_manager(): - def run(): - with responses.mock: - responses.add(responses.GET, "http://example.com", body=b"test") - resp = requests.get("http://example.com") - assert_response(resp, "test") - assert len(responses.calls) == 1 - assert responses.calls[0].request.url == "http://example.com/" - assert responses.calls[0].response.content == b"test" - - resp = requests.get("http://example.com?foo=bar") - assert_response(resp, "test") - assert len(responses.calls) == 2 - assert responses.calls[1].request.url == "http://example.com/?foo=bar" - assert responses.calls[1].response.content == b"test" - - run() - assert_reset() - - -def test_activate_doesnt_change_signature(): - def test_function(a, b=None): - return (a, b) - - decorated_test_function = responses.activate(test_function) - if hasattr(inspect, "signature"): - assert inspect.signature(test_function) == inspect.signature( - decorated_test_function - ) - else: - assert inspect.getargspec(test_function) == inspect.getargspec( - decorated_test_function - ) - assert decorated_test_function(1, 2) == test_function(1, 2) - assert decorated_test_function(3) == test_function(3) - - -def test_activate_mock_interaction(): - @patch("sys.stdout") - def test_function(mock_stdout): - return mock_stdout - - decorated_test_function = responses.activate(test_function) - if hasattr(inspect, "signature"): - assert inspect.signature(test_function) == inspect.signature( - decorated_test_function - ) - else: - assert inspect.getargspec(test_function) == inspect.getargspec( - decorated_test_function - ) - - value = test_function() - assert isinstance(value, Mock) - - value = decorated_test_function() - assert isinstance(value, Mock) - - -@pytest.mark.skipif(six.PY2, reason="Cannot run in python2") -def test_activate_doesnt_change_signature_with_return_type(): - def test_function(a, b=None): - return (a, b) - - # Add type annotations as they are syntax errors in py2. - # Use a class to test for import errors in evaled code. - test_function.__annotations__["return"] = Mock - test_function.__annotations__["a"] = Mock - - decorated_test_function = responses.activate(test_function) - if hasattr(inspect, "signature"): - assert inspect.signature(test_function) == inspect.signature( - decorated_test_function - ) - else: - assert inspect.getargspec(test_function) == inspect.getargspec( - decorated_test_function - ) - assert decorated_test_function(1, 2) == test_function(1, 2) - assert decorated_test_function(3) == test_function(3) - - -def test_activate_doesnt_change_signature_for_method(): - class TestCase(object): - def test_function(self, a, b=None): - return (self, a, b) - - decorated_test_function = responses.activate(test_function) - - test_case = TestCase() - assert test_case.decorated_test_function(1, 2) == test_case.test_function(1, 2) - assert test_case.decorated_test_function(3) == test_case.test_function(3) - - -def test_response_cookies(): - body = b"test callback" - status = 200 - headers = {"set-cookie": "session_id=12345; a=b; c=d"} - url = "http://example.com/" - - def request_callback(request): - return (status, headers, body) - - @responses.activate - def run(): - responses.add_callback(responses.GET, url, request_callback) - resp = requests.get(url) - assert resp.text == "test callback" - assert resp.status_code == status - assert "session_id" in resp.cookies - assert resp.cookies["session_id"] == "12345" - assert resp.cookies["a"] == "b" - assert resp.cookies["c"] == "d" - - run() - assert_reset() - - -def test_response_callback(): - """adds a callback to decorate the response, then checks it""" - - def run(): - def response_callback(resp): - resp._is_mocked = True - return resp - - with responses.RequestsMock(response_callback=response_callback) as m: - m.add(responses.GET, "http://example.com", body=b"test") - resp = requests.get("http://example.com") - assert resp.text == "test" - assert hasattr(resp, "_is_mocked") - assert resp._is_mocked is True - - run() - assert_reset() - - -def test_response_filebody(): - """ Adds the possibility to use actual (binary) files as responses """ - - def run(): - with responses.RequestsMock() as m: - with open("README.rst", "rb") as out: - m.add(responses.GET, "http://example.com", body=out, stream=True) - resp = requests.get("http://example.com") - with open("README.rst", "r") as out: - assert resp.text == out.read() - - -def test_assert_all_requests_are_fired(): - def run(): - with pytest.raises(AssertionError) as excinfo: - with responses.RequestsMock(assert_all_requests_are_fired=True) as m: - m.add(responses.GET, "http://example.com", body=b"test") - assert "http://example.com" in str(excinfo.value) - assert responses.GET in str(excinfo) - - # check that assert_all_requests_are_fired default to True - with pytest.raises(AssertionError): - with responses.RequestsMock() as m: - m.add(responses.GET, "http://example.com", body=b"test") - - # check that assert_all_requests_are_fired doesn't swallow exceptions - with pytest.raises(ValueError): - with responses.RequestsMock() as m: - m.add(responses.GET, "http://example.com", body=b"test") - raise ValueError() - - # check that assert_all_requests_are_fired=True doesn't remove urls - with responses.RequestsMock(assert_all_requests_are_fired=True) as m: - m.add(responses.GET, "http://example.com", body=b"test") - assert len(m._matches) == 1 - requests.get("http://example.com") - assert len(m._matches) == 1 - - # check that assert_all_requests_are_fired=True counts mocked errors - with responses.RequestsMock(assert_all_requests_are_fired=True) as m: - m.add(responses.GET, "http://example.com", body=Exception()) - assert len(m._matches) == 1 - with pytest.raises(Exception): - requests.get("http://example.com") - assert len(m._matches) == 1 - - run() - assert_reset() - - -def test_allow_redirects_samehost(): - redirecting_url = "http://example.com" - final_url_path = "/1" - final_url = "{0}{1}".format(redirecting_url, final_url_path) - url_re = re.compile(r"^http://example.com(/)?(\d+)?$") - - def request_callback(request): - # endpoint of chained redirect - if request.url.endswith(final_url_path): - return 200, (), b"test" - - # otherwise redirect to an integer path - else: - if request.url.endswith("/0"): - n = 1 - else: - n = 0 - redirect_headers = {"location": "/{0!s}".format(n)} - return 301, redirect_headers, None - - def run(): - # setup redirect - with responses.mock: - responses.add_callback(responses.GET, url_re, request_callback) - resp_no_redirects = requests.get(redirecting_url, allow_redirects=False) - assert resp_no_redirects.status_code == 301 - assert len(responses.calls) == 1 # 1x300 - assert responses.calls[0][1].status_code == 301 - assert_reset() - - with responses.mock: - responses.add_callback(responses.GET, url_re, request_callback) - resp_yes_redirects = requests.get(redirecting_url, allow_redirects=True) - assert len(responses.calls) == 3 # 2x300 + 1x200 - assert len(resp_yes_redirects.history) == 2 - assert resp_yes_redirects.status_code == 200 - assert final_url == resp_yes_redirects.url - status_codes = [call[1].status_code for call in responses.calls] - assert status_codes == [301, 301, 200] - assert_reset() - - run() - assert_reset() - - -def test_handles_unicode_querystring(): - url = "http://example.com/test?type=2&ie=utf8&query=汉字" - - @responses.activate - def run(): - responses.add(responses.GET, url, body="test", match_querystring=True) - - resp = requests.get(url) - - assert_response(resp, "test") - - run() - assert_reset() - - -def test_handles_unicode_url(): - url = "http://www.संजाल.भारत/hi/वेबसाइट-डिजाइन" - - @responses.activate - def run(): - responses.add(responses.GET, url, body="test") - - resp = requests.get(url) - - assert_response(resp, "test") - - run() - assert_reset() - - -def test_headers(): - @responses.activate - def run(): - responses.add( - responses.GET, "http://example.com", body="", headers={"X-Test": "foo"} - ) - resp = requests.get("http://example.com") - assert resp.headers["X-Test"] == "foo" - - run() - assert_reset() - - -def test_legacy_adding_headers(): - @responses.activate - def run(): - responses.add( - responses.GET, - "http://example.com", - body="", - adding_headers={"X-Test": "foo"}, - ) - resp = requests.get("http://example.com") - assert resp.headers["X-Test"] == "foo" - - run() - assert_reset() - - -def test_multiple_responses(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com", body="test") - responses.add(responses.GET, "http://example.com", body="rest") - - resp = requests.get("http://example.com") - assert_response(resp, "test") - resp = requests.get("http://example.com") - assert_response(resp, "rest") - # After all responses are used, last response should be repeated - resp = requests.get("http://example.com") - assert_response(resp, "rest") - - run() - assert_reset() - - -def test_multiple_urls(): - @responses.activate - def run(): - responses.add(responses.GET, "http://example.com/one", body="one") - responses.add(responses.GET, "http://example.com/two", body="two") - - resp = requests.get("http://example.com/two") - assert_response(resp, "two") - resp = requests.get("http://example.com/one") - assert_response(resp, "one") - - run() - assert_reset() - - -def test_passthru(httpserver): - httpserver.serve_content("OK", headers={"Content-Type": "text/plain"}) - - @responses.activate - def run(): - responses.add_passthru(httpserver.url) - responses.add(responses.GET, "{}/one".format(httpserver.url), body="one") - responses.add(responses.GET, "http://example.com/two", body="two") - - resp = requests.get("http://example.com/two") - assert_response(resp, "two") - resp = requests.get("{}/one".format(httpserver.url)) - assert_response(resp, "one") - resp = requests.get(httpserver.url) - assert_response(resp, "OK") - - run() - assert_reset() - - -def test_method_named_param(): - @responses.activate - def run(): - responses.add(method=responses.GET, url="http://example.com", body="OK") - resp = requests.get("http://example.com") - assert_response(resp, "OK") - - run() - assert_reset() - - -def test_passthru_unicode(): - @responses.activate - def run(): - with responses.RequestsMock() as m: - url = "http://موقع.وزارة-الاتصالات.مصر/" - clean_url = "http://xn--4gbrim.xn----ymcbaaajlc6dj7bxne2c.xn--wgbh1c/" - m.add_passthru(url) - assert m.passthru_prefixes[0] == clean_url - - run() - assert_reset() - - -def test_custom_target(monkeypatch): - requests_mock = responses.RequestsMock(target="something.else") - std_mock_mock = responses.std_mock.MagicMock() - patch_mock = std_mock_mock.patch - monkeypatch.setattr(responses, "std_mock", std_mock_mock) - requests_mock.start() - assert len(patch_mock.call_args_list) == 1 - assert patch_mock.call_args[1]["target"] == "something.else" diff --git a/third_party/python/responses/tox.ini b/third_party/python/responses/tox.ini deleted file mode 100644 index 94d030cc37ad..000000000000 --- a/third_party/python/responses/tox.ini +++ /dev/null @@ -1,7 +0,0 @@ -[tox] -envlist = py27,py34,py35,py36,py37 - -[testenv] -extras = tests -commands = - pytest . --cov responses --cov-report term-missing diff --git a/third_party/python/sentry-sdk/MANIFEST.in b/third_party/python/sentry-sdk/MANIFEST.in deleted file mode 100644 index 86a2426325b6..000000000000 --- a/third_party/python/sentry-sdk/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include LICENSE -include sentry_sdk/py.typed diff --git a/third_party/python/sentry-sdk/README.md b/third_party/python/sentry-sdk/README.md deleted file mode 100644 index 0c845d601d72..000000000000 --- a/third_party/python/sentry-sdk/README.md +++ /dev/null @@ -1,42 +0,0 @@ -

    - - - -

    - -# sentry-python - Sentry SDK for Python - -[![Build Status](https://travis-ci.com/getsentry/sentry-python.svg?branch=master)](https://travis-ci.com/getsentry/sentry-python) -[![PyPi page link -- version](https://img.shields.io/pypi/v/sentry-sdk.svg)](https://pypi.python.org/pypi/sentry-sdk) -[![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/cWnMQeA) - -This is the next line of the Python SDK for [Sentry](http://sentry.io/), intended to replace the `raven` package on PyPI. - -```python -from sentry_sdk import init, capture_message - -init("https://mydsn@sentry.io/123") - -capture_message("Hello World") # Will create an event. - -raise ValueError() # Will also create an event. -``` - -To learn more about how to use the SDK: - -- [Getting started with the new SDK](https://docs.sentry.io/quickstart/?platform=python) -- [Configuration options](https://docs.sentry.io/error-reporting/configuration/?platform=python) -- [Setting context (tags, user, extra information)](https://docs.sentry.io/enriching-error-data/context/?platform=python) -- [Integrations](https://docs.sentry.io/platforms/python/) - -Are you coming from raven-python? - -- [Cheatsheet: Migrating to the new SDK from Raven](https://forum.sentry.io/t/switching-to-sentry-python/4733) - -To learn about internals: - -- [API Reference](https://getsentry.github.io/sentry-python/) - -# License - -Licensed under the BSD license, see `LICENSE` diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/PKG-INFO b/third_party/python/sentry-sdk/sentry_sdk.egg-info/PKG-INFO deleted file mode 100644 index 88d9a4087e50..000000000000 --- a/third_party/python/sentry-sdk/sentry_sdk.egg-info/PKG-INFO +++ /dev/null @@ -1,43 +0,0 @@ -Metadata-Version: 2.1 -Name: sentry-sdk -Version: 0.14.3 -Summary: Python client for Sentry (https://getsentry.com) -Home-page: https://github.com/getsentry/sentry-python -Author: Sentry Team and Contributors -Author-email: hello@getsentry.com -License: BSD -Description: - Sentry-Python - Sentry SDK for Python - ===================================== - - **Sentry-Python is an SDK for Sentry.** Check out `GitHub - `_ to find out more. - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Provides-Extra: flask -Provides-Extra: bottle -Provides-Extra: falcon -Provides-Extra: django -Provides-Extra: sanic -Provides-Extra: celery -Provides-Extra: beam -Provides-Extra: rq -Provides-Extra: aiohttp -Provides-Extra: tornado -Provides-Extra: sqlalchemy -Provides-Extra: pyspark diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/SOURCES.txt b/third_party/python/sentry-sdk/sentry_sdk.egg-info/SOURCES.txt deleted file mode 100644 index 662a5a069fee..000000000000 --- a/third_party/python/sentry-sdk/sentry_sdk.egg-info/SOURCES.txt +++ /dev/null @@ -1,64 +0,0 @@ -LICENSE -MANIFEST.in -README.md -setup.cfg -setup.py -sentry_sdk/__init__.py -sentry_sdk/_compat.py -sentry_sdk/_types.py -sentry_sdk/api.py -sentry_sdk/client.py -sentry_sdk/consts.py -sentry_sdk/debug.py -sentry_sdk/envelope.py -sentry_sdk/hub.py -sentry_sdk/py.typed -sentry_sdk/scope.py -sentry_sdk/serializer.py -sentry_sdk/sessions.py -sentry_sdk/tracing.py -sentry_sdk/transport.py -sentry_sdk/utils.py -sentry_sdk/worker.py -sentry_sdk.egg-info/PKG-INFO -sentry_sdk.egg-info/SOURCES.txt -sentry_sdk.egg-info/dependency_links.txt -sentry_sdk.egg-info/not-zip-safe -sentry_sdk.egg-info/requires.txt -sentry_sdk.egg-info/top_level.txt -sentry_sdk/integrations/__init__.py -sentry_sdk/integrations/_wsgi_common.py -sentry_sdk/integrations/aiohttp.py -sentry_sdk/integrations/argv.py -sentry_sdk/integrations/asgi.py -sentry_sdk/integrations/atexit.py -sentry_sdk/integrations/aws_lambda.py -sentry_sdk/integrations/beam.py -sentry_sdk/integrations/bottle.py -sentry_sdk/integrations/celery.py -sentry_sdk/integrations/dedupe.py -sentry_sdk/integrations/excepthook.py -sentry_sdk/integrations/falcon.py -sentry_sdk/integrations/flask.py -sentry_sdk/integrations/gnu_backtrace.py -sentry_sdk/integrations/logging.py -sentry_sdk/integrations/modules.py -sentry_sdk/integrations/pyramid.py -sentry_sdk/integrations/redis.py -sentry_sdk/integrations/rq.py -sentry_sdk/integrations/sanic.py -sentry_sdk/integrations/serverless.py -sentry_sdk/integrations/sqlalchemy.py -sentry_sdk/integrations/stdlib.py -sentry_sdk/integrations/threading.py -sentry_sdk/integrations/tornado.py -sentry_sdk/integrations/trytond.py -sentry_sdk/integrations/wsgi.py -sentry_sdk/integrations/django/__init__.py -sentry_sdk/integrations/django/asgi.py -sentry_sdk/integrations/django/middleware.py -sentry_sdk/integrations/django/templates.py -sentry_sdk/integrations/django/transactions.py -sentry_sdk/integrations/spark/__init__.py -sentry_sdk/integrations/spark/spark_driver.py -sentry_sdk/integrations/spark/spark_worker.py \ No newline at end of file diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/dependency_links.txt b/third_party/python/sentry-sdk/sentry_sdk.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/sentry-sdk/sentry_sdk.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/not-zip-safe b/third_party/python/sentry-sdk/sentry_sdk.egg-info/not-zip-safe deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/sentry-sdk/sentry_sdk.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/requires.txt b/third_party/python/sentry-sdk/sentry_sdk.egg-info/requires.txt deleted file mode 100644 index 5f325f6230fb..000000000000 --- a/third_party/python/sentry-sdk/sentry_sdk.egg-info/requires.txt +++ /dev/null @@ -1,39 +0,0 @@ -urllib3>=1.10.0 -certifi - -[aiohttp] -aiohttp>=3.5 - -[beam] -beam>=2.12 - -[bottle] -bottle>=0.12.13 - -[celery] -celery>=3 - -[django] -django>=1.8 - -[falcon] -falcon>=1.4 - -[flask] -flask>=0.11 -blinker>=1.1 - -[pyspark] -pyspark>=2.4.4 - -[rq] -0.6 - -[sanic] -sanic>=0.8 - -[sqlalchemy] -sqlalchemy>=1.2 - -[tornado] -tornado>=5 diff --git a/third_party/python/sentry-sdk/setup.cfg b/third_party/python/sentry-sdk/setup.cfg deleted file mode 100644 index adf5ed72aa40..000000000000 --- a/third_party/python/sentry-sdk/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[bdist_wheel] -universal = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/sentry-sdk/setup.py b/third_party/python/sentry-sdk/setup.py deleted file mode 100644 index 045532e7df25..000000000000 --- a/third_party/python/sentry-sdk/setup.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python - -""" -Sentry-Python - Sentry SDK for Python -===================================== - -**Sentry-Python is an SDK for Sentry.** Check out `GitHub -`_ to find out more. -""" - -from setuptools import setup, find_packages - -setup( - name="sentry-sdk", - version="0.14.3", - author="Sentry Team and Contributors", - author_email="hello@getsentry.com", - url="https://github.com/getsentry/sentry-python", - description="Python client for Sentry (https://getsentry.com)", - long_description=__doc__, - packages=find_packages(exclude=("tests", "tests.*")), - # PEP 561 - package_data={"sentry_sdk": ["py.typed"]}, - zip_safe=False, - license="BSD", - install_requires=["urllib3>=1.10.0", "certifi"], - extras_require={ - "flask": ["flask>=0.11", "blinker>=1.1"], - "bottle": ["bottle>=0.12.13"], - "falcon": ["falcon>=1.4"], - "django": ["django>=1.8"], - "sanic": ["sanic>=0.8"], - "celery": ["celery>=3"], - "beam": ["beam>=2.12"], - "rq": ["0.6"], - "aiohttp": ["aiohttp>=3.5"], - "tornado": ["tornado>=5"], - "sqlalchemy": ["sqlalchemy>=1.2"], - "pyspark": ["pyspark>=2.4.4"], - }, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Web Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Topic :: Software Development :: Libraries :: Python Modules", - ], -) diff --git a/third_party/python/sentry-sdk/LICENSE b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/LICENSE similarity index 100% rename from third_party/python/sentry-sdk/LICENSE rename to third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/LICENSE diff --git a/third_party/python/sentry-sdk/PKG-INFO b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/METADATA similarity index 58% rename from third_party/python/sentry-sdk/PKG-INFO rename to third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/METADATA index 88d9a4087e50..5fef4faa5b44 100644 --- a/third_party/python/sentry-sdk/PKG-INFO +++ b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/METADATA @@ -6,13 +6,6 @@ Home-page: https://github.com/getsentry/sentry-python Author: Sentry Team and Contributors Author-email: hello@getsentry.com License: BSD -Description: - Sentry-Python - Sentry SDK for Python - ===================================== - - **Sentry-Python is an SDK for Sentry.** Check out `GitHub - `_ to find out more. - Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment @@ -29,15 +22,39 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Topic :: Software Development :: Libraries :: Python Modules -Provides-Extra: flask -Provides-Extra: bottle -Provides-Extra: falcon -Provides-Extra: django -Provides-Extra: sanic -Provides-Extra: celery -Provides-Extra: beam -Provides-Extra: rq +Requires-Dist: urllib3 (>=1.10.0) +Requires-Dist: certifi Provides-Extra: aiohttp -Provides-Extra: tornado -Provides-Extra: sqlalchemy +Requires-Dist: aiohttp (>=3.5) ; extra == 'aiohttp' +Provides-Extra: beam +Requires-Dist: beam (>=2.12) ; extra == 'beam' +Provides-Extra: bottle +Requires-Dist: bottle (>=0.12.13) ; extra == 'bottle' +Provides-Extra: celery +Requires-Dist: celery (>=3) ; extra == 'celery' +Provides-Extra: django +Requires-Dist: django (>=1.8) ; extra == 'django' +Provides-Extra: falcon +Requires-Dist: falcon (>=1.4) ; extra == 'falcon' +Provides-Extra: flask +Requires-Dist: flask (>=0.11) ; extra == 'flask' +Requires-Dist: blinker (>=1.1) ; extra == 'flask' Provides-Extra: pyspark +Requires-Dist: pyspark (>=2.4.4) ; extra == 'pyspark' +Provides-Extra: rq +Requires-Dist: 0.6 ; extra == 'rq' +Provides-Extra: sanic +Requires-Dist: sanic (>=0.8) ; extra == 'sanic' +Provides-Extra: sqlalchemy +Requires-Dist: sqlalchemy (>=1.2) ; extra == 'sqlalchemy' +Provides-Extra: tornado +Requires-Dist: tornado (>=5) ; extra == 'tornado' + + +Sentry-Python - Sentry SDK for Python +===================================== + +**Sentry-Python is an SDK for Sentry.** Check out `GitHub +`_ to find out more. + + diff --git a/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/RECORD b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/RECORD new file mode 100644 index 000000000000..14cfd725cbbc --- /dev/null +++ b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/RECORD @@ -0,0 +1,58 @@ +sentry_sdk/__init__.py,sha256=k1HZ_Malhx3a5bIh4pAl4Tvt_hAopZhyR5lcRR0enX0,591 +sentry_sdk/_compat.py,sha256=f3Tadrt6580oSkwwriJrggZR6oeNsdN2OBCOGuSasj8,2422 +sentry_sdk/_types.py,sha256=1WMOPaU3zhM-W_ejMduB3yM-qNeb4fTKdmBY3L2QhXY,1080 +sentry_sdk/api.py,sha256=f6EJa-Zdr_Oehq5JgMqVcXeY0rU0scTiMMp2c3gSJN4,5528 +sentry_sdk/client.py,sha256=mD57zGxONY_DfFFksae5dJEEMnS11UnSgcfv9pE5gC4,13157 +sentry_sdk/consts.py,sha256=WS4SVRzlEoF0H3BKhxgAEPa8kT2mFPFdr6IqDznS6cQ,3487 +sentry_sdk/debug.py,sha256=ZT-7VoCIA5TYhh7X-ZSaSzYZ4_MuoNvzi12gKgIKzm0,1132 +sentry_sdk/envelope.py,sha256=cOSNXA2r0Q2lGMY-UpSP-jBh-cvSDDlMe12vy5DUn3w,8221 +sentry_sdk/hub.py,sha256=tbbZaSexKp44Sx6cxJ7uV8YwDkm2KAObZIIgu9UPfRQ,19459 +sentry_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sentry_sdk/scope.py,sha256=ZQshHgonA0lTgRzUsV0eSqqPdOMBD9OHEJZNs5Dsf-8,12509 +sentry_sdk/serializer.py,sha256=Nn9O5fZo7QquXae_pxoaOIbT3_iQP30GrWuUV0ykywI,10507 +sentry_sdk/sessions.py,sha256=5g-pUW3LqcEHL3gvnPk5lZvPQmP6B9Vu2KYYrxjbDls,7732 +sentry_sdk/tracing.py,sha256=55qCUgIesvTTAzl7dL9BFDDOcY25FgsUqm6bHvVMOP4,15210 +sentry_sdk/transport.py,sha256=qXPsbb4OAWLpAhSCImoILnKUulMVoHjgFWuiEJGXbbA,11002 +sentry_sdk/utils.py,sha256=TG89z9WzBqPu0039YnxgY6FcRRr8l5K0_R3X4hiInjc,22953 +sentry_sdk/worker.py,sha256=nlcd5mlawU3AOQLOYIgTtQVceX623p3YMqv2ot0czZw,4560 +sentry_sdk/integrations/__init__.py,sha256=pD6ksI4OXAH0NeXbqAc_vhvVJpyPR-ycGzqOLQSbiy4,6464 +sentry_sdk/integrations/_wsgi_common.py,sha256=J8jlafU5yhQu2xjKuK_3-Bt9HbqbHIP5ZyWebkfSJ_k,4763 +sentry_sdk/integrations/aiohttp.py,sha256=__SUTMu1k2eIT7M7lefyCXNxUMeSAoQYKTV0OtgB6YM,7076 +sentry_sdk/integrations/argv.py,sha256=X-RVfWNxuPObsOmuommDc4FcIhNSTKpGsD1cYbrqza4,945 +sentry_sdk/integrations/asgi.py,sha256=BvLrqtzyaM1UIXidSjkpZEWDGYlrplqOvXc52gX5Zhc,6821 +sentry_sdk/integrations/atexit.py,sha256=b75c2SBJPl_cS4ObiQT1SMKqeZG5Fqed61z2myHRKug,1837 +sentry_sdk/integrations/aws_lambda.py,sha256=NCop82UqSLetsvoIf0THuFPXSdWua-y4ZToG-ysqGSM,8890 +sentry_sdk/integrations/beam.py,sha256=3wSJv4SuIBsVFtoc2J1oW2JYZnq-biMXEL-7Qn85rOQ,5650 +sentry_sdk/integrations/bottle.py,sha256=KwvGziHwdxzv_FeT1UNRMAmtDEWiT_0ssT5QyzFQG2M,6188 +sentry_sdk/integrations/celery.py,sha256=86NG-gplsol8gR-8c5Cr43QT_CvLC_9sbD8efRuuHbg,8394 +sentry_sdk/integrations/dedupe.py,sha256=d3JaHlMJpeF9zqVmITSPcLPBEvr9aHRzIrlGyzqeNgs,1166 +sentry_sdk/integrations/excepthook.py,sha256=ho96OGOzBdTZDxNOV4VQXfHv_MD5hsZ_8ww-5GNrRDI,2182 +sentry_sdk/integrations/falcon.py,sha256=S15UIm84t1cHvzj_3gxEbgmkEy5sXex9p-L8Sc1UwSQ,6797 +sentry_sdk/integrations/flask.py,sha256=U5-23SYrEbiNB80TSX96lry_qzpa-Nyr675cWLSSfWQ,8168 +sentry_sdk/integrations/gnu_backtrace.py,sha256=VJU3zYY7GUybAgIOEGF_P7i4V2R_jOnlSgTCS7XNto0,2912 +sentry_sdk/integrations/logging.py,sha256=kqWZmR711fCc2k--eULHXbi0khJY9K4pcsYvSgu-Zs8,6922 +sentry_sdk/integrations/modules.py,sha256=tgl4abSudtR03NBOjXCWJ08dHY5KlxUveX3mPUNosYk,1393 +sentry_sdk/integrations/pyramid.py,sha256=4VPOY1AZAjGfrRiM2KAZHrevwC4Uy6gBQ2oH9sF5XyU,7006 +sentry_sdk/integrations/redis.py,sha256=HhXrJ8tOrsd-8pqXeYjtAepF31diRgl3bqJ4GnPiluI,1941 +sentry_sdk/integrations/rq.py,sha256=mT6iE4JcuwBL0cMeInMQMSaA0QzJ7JgN0dpDpiw4SCM,4714 +sentry_sdk/integrations/sanic.py,sha256=n_y49BpScw6XCMg1bRSJDrNnLcBIklAnFT9xibmGEQY,7646 +sentry_sdk/integrations/serverless.py,sha256=d97Z1cBXdRFdXxzYsLNtRebATfExIWZ1oxMT8_xTf4Q,1993 +sentry_sdk/integrations/sqlalchemy.py,sha256=jLVpxLSol0_4goqLVb9_z1awTpwdtmG_1IXbpqC1lkg,2525 +sentry_sdk/integrations/stdlib.py,sha256=bYoNEOP_xmKgR-n_SmBLNAHhwC41y8l96go5aQX3gss,7348 +sentry_sdk/integrations/threading.py,sha256=TN5cmoLfRIaayFFWoN9L0VdXunB23iTcUjUA6V9GSrE,2856 +sentry_sdk/integrations/tornado.py,sha256=4V32cl0cw0cpUjCyVUFKtW3kD0iN9VibW4IAHTJYhnM,6910 +sentry_sdk/integrations/trytond.py,sha256=cLpQ5CZrG1Wn5Cq3_Xosswu5Jt43KEV-ag_zrvcXwqo,1728 +sentry_sdk/integrations/wsgi.py,sha256=UPUJiEYM1eu1-zSNNZFSPLenkGYYS022lCLM36CQgCs,10232 +sentry_sdk/integrations/django/__init__.py,sha256=R0zTG2qyFyqal9Azb_DkMfcOW_gjF9PLWPz9vm0KKqM,15893 +sentry_sdk/integrations/django/asgi.py,sha256=-OPPl8WjFjXPgfdTmMuIZv1EqFSk0BRKLfkgmmPAwPA,1467 +sentry_sdk/integrations/django/middleware.py,sha256=bM-J_4ur2qilpHzAlrWtlUsakR-ZPH-wvKw931fnuX4,4419 +sentry_sdk/integrations/django/templates.py,sha256=Knq4W6NyfBbFGCLQqpB6mBCze2ZQJKmS4Up5Gvy47VU,3398 +sentry_sdk/integrations/django/transactions.py,sha256=1W-9xuryfy7ztqI_PLrSTAOWO0holUPyYuXYUh8ez2E,4094 +sentry_sdk/integrations/spark/__init__.py,sha256=oOewMErnZk2rzNvIlZO6URxQexu9bUJuSLM2m_zECy8,208 +sentry_sdk/integrations/spark/spark_driver.py,sha256=CMyEe6_Qf8E9OSz3bcCumsOgO8eJ4egKOrazOYPcvX4,8465 +sentry_sdk/integrations/spark/spark_worker.py,sha256=if_Pqkaxm-SKghaUETCLhL7Vrxk2HKG7A3mwocAHzas,3884 +sentry_sdk-0.14.3.dist-info/LICENSE,sha256=WUBNTIVOV5CX1Bv8zVAGr96dbXDmRs9VB0zb_q1ezxw,1330 +sentry_sdk-0.14.3.dist-info/METADATA,sha256=qTLzHA_baC0M0ImoObls68NW_BzxKhx63tzeKnBAW8E,2203 +sentry_sdk-0.14.3.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +sentry_sdk-0.14.3.dist-info/top_level.txt,sha256=XrQz30XE9FKXSY_yGLrd9bsv2Rk390GTDJOSujYaMxI,11 +sentry_sdk-0.14.3.dist-info/RECORD,, diff --git a/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/WHEEL b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/WHEEL new file mode 100644 index 000000000000..ef99c6cf3283 --- /dev/null +++ b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/sentry-sdk/sentry_sdk.egg-info/top_level.txt b/third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/top_level.txt similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk.egg-info/top_level.txt rename to third_party/python/sentry_sdk/sentry_sdk-0.14.3.dist-info/top_level.txt diff --git a/third_party/python/sentry-sdk/sentry_sdk/__init__.py b/third_party/python/sentry_sdk/sentry_sdk/__init__.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/__init__.py rename to third_party/python/sentry_sdk/sentry_sdk/__init__.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/_compat.py b/third_party/python/sentry_sdk/sentry_sdk/_compat.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/_compat.py rename to third_party/python/sentry_sdk/sentry_sdk/_compat.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/_types.py b/third_party/python/sentry_sdk/sentry_sdk/_types.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/_types.py rename to third_party/python/sentry_sdk/sentry_sdk/_types.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/api.py b/third_party/python/sentry_sdk/sentry_sdk/api.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/api.py rename to third_party/python/sentry_sdk/sentry_sdk/api.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/client.py b/third_party/python/sentry_sdk/sentry_sdk/client.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/client.py rename to third_party/python/sentry_sdk/sentry_sdk/client.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/consts.py b/third_party/python/sentry_sdk/sentry_sdk/consts.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/consts.py rename to third_party/python/sentry_sdk/sentry_sdk/consts.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/debug.py b/third_party/python/sentry_sdk/sentry_sdk/debug.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/debug.py rename to third_party/python/sentry_sdk/sentry_sdk/debug.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/envelope.py b/third_party/python/sentry_sdk/sentry_sdk/envelope.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/envelope.py rename to third_party/python/sentry_sdk/sentry_sdk/envelope.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/hub.py b/third_party/python/sentry_sdk/sentry_sdk/hub.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/hub.py rename to third_party/python/sentry_sdk/sentry_sdk/hub.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/__init__.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/__init__.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/__init__.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/__init__.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/_wsgi_common.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/_wsgi_common.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/_wsgi_common.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/_wsgi_common.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/aiohttp.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/aiohttp.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/aiohttp.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/aiohttp.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/argv.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/argv.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/argv.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/argv.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/asgi.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/asgi.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/asgi.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/asgi.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/atexit.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/atexit.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/atexit.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/atexit.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/aws_lambda.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/aws_lambda.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/aws_lambda.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/aws_lambda.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/beam.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/beam.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/beam.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/beam.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/bottle.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/bottle.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/bottle.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/bottle.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/celery.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/celery.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/celery.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/celery.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/dedupe.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/dedupe.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/dedupe.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/dedupe.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/django/__init__.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/django/__init__.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/django/__init__.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/django/__init__.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/django/asgi.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/django/asgi.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/django/asgi.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/django/asgi.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/django/middleware.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/django/middleware.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/django/middleware.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/django/middleware.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/django/templates.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/django/templates.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/django/templates.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/django/templates.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/django/transactions.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/django/transactions.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/django/transactions.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/django/transactions.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/excepthook.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/excepthook.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/excepthook.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/excepthook.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/falcon.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/falcon.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/falcon.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/falcon.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/flask.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/flask.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/flask.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/flask.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/gnu_backtrace.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/gnu_backtrace.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/gnu_backtrace.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/gnu_backtrace.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/logging.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/logging.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/logging.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/logging.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/modules.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/modules.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/modules.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/modules.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/pyramid.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/pyramid.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/pyramid.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/pyramid.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/redis.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/redis.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/redis.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/redis.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/rq.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/rq.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/rq.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/rq.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/sanic.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/sanic.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/sanic.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/sanic.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/serverless.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/serverless.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/serverless.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/serverless.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/spark/__init__.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/spark/__init__.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/spark/__init__.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/spark/__init__.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/spark/spark_driver.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/spark/spark_driver.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/spark/spark_driver.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/spark/spark_driver.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/spark/spark_worker.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/spark/spark_worker.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/spark/spark_worker.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/spark/spark_worker.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/sqlalchemy.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/sqlalchemy.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/sqlalchemy.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/sqlalchemy.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/stdlib.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/stdlib.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/stdlib.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/threading.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/threading.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/threading.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/threading.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/tornado.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/tornado.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/tornado.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/tornado.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/trytond.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/trytond.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/trytond.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/trytond.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/integrations/wsgi.py b/third_party/python/sentry_sdk/sentry_sdk/integrations/wsgi.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/integrations/wsgi.py rename to third_party/python/sentry_sdk/sentry_sdk/integrations/wsgi.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/py.typed b/third_party/python/sentry_sdk/sentry_sdk/py.typed similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/py.typed rename to third_party/python/sentry_sdk/sentry_sdk/py.typed diff --git a/third_party/python/sentry-sdk/sentry_sdk/scope.py b/third_party/python/sentry_sdk/sentry_sdk/scope.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/scope.py rename to third_party/python/sentry_sdk/sentry_sdk/scope.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/serializer.py b/third_party/python/sentry_sdk/sentry_sdk/serializer.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/serializer.py rename to third_party/python/sentry_sdk/sentry_sdk/serializer.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/sessions.py b/third_party/python/sentry_sdk/sentry_sdk/sessions.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/sessions.py rename to third_party/python/sentry_sdk/sentry_sdk/sessions.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/tracing.py b/third_party/python/sentry_sdk/sentry_sdk/tracing.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/tracing.py rename to third_party/python/sentry_sdk/sentry_sdk/tracing.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/transport.py b/third_party/python/sentry_sdk/sentry_sdk/transport.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/transport.py rename to third_party/python/sentry_sdk/sentry_sdk/transport.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/utils.py b/third_party/python/sentry_sdk/sentry_sdk/utils.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/utils.py rename to third_party/python/sentry_sdk/sentry_sdk/utils.py diff --git a/third_party/python/sentry-sdk/sentry_sdk/worker.py b/third_party/python/sentry_sdk/sentry_sdk/worker.py similarity index 100% rename from third_party/python/sentry-sdk/sentry_sdk/worker.py rename to third_party/python/sentry_sdk/sentry_sdk/worker.py diff --git a/third_party/python/six/CHANGES b/third_party/python/six/CHANGES deleted file mode 100644 index ffa702601b65..000000000000 --- a/third_party/python/six/CHANGES +++ /dev/null @@ -1,315 +0,0 @@ -Changelog for six -================= - -This file lists the changes in each six version. - -1.13.0 ------- - -- Issue #298, pull request #299: Add `six.moves.dbm_ndbm`. - -- Issue #155: Add `six.moves.collections_abc`, which aliases the `collections` - module on Python 2-3.2 and the `collections.abc` on Python 3.3 and greater. - -- Pull request #304: Re-add distutils fallback in `setup.py`. - -- Pull request #305: On Python 3.7, `with_metaclass` supports classes using PEP - 560 features. - -1.12.0 ------- - -- Issue #259, pull request #260: `six.add_metaclass` now preserves - `__qualname__` from the original class. - -- Pull request #204: Add `six.ensure_binary`, `six.ensure_text`, and - `six.ensure_str`. - -1.11.0 ------- - -- Pull request #178: `with_metaclass` now properly proxies `__prepare__` to the - underlying metaclass. - -- Pull request #191: Allow `with_metaclass` to work with metaclasses implemented - in C. - -- Pull request #203: Add parse_http_list and parse_keqv_list to moved - urllib.request. - -- Pull request #172 and issue #171: Add unquote_to_bytes to moved urllib.parse. - -- Pull request #167: Add `six.moves.getoutput`. - -- Pull request #80: Add `six.moves.urllib_parse.splitvalue`. - -- Pull request #75: Add `six.moves.email_mime_image`. - -- Pull request #72: Avoid creating reference cycles through tracebacks in - `reraise`. - -1.10.0 ------- - -- Issue #122: Improve the performance of `six.int2byte` on Python 3. - -- Pull request #55 and issue #99: Don't add the `winreg` module to `six.moves` - on non-Windows platforms. - -- Pull request #60 and issue #108: Add `six.moves.getcwd` and - `six.moves.getcwdu`. - -- Pull request #64: Add `create_unbound_method` to create unbound methods. - -1.9.0 ------ - -- Issue #106: Support the `flush` parameter to `six.print_`. - -- Pull request #48 and issue #15: Add the `python_2_unicode_compatible` - decorator. - -- Pull request #57 and issue #50: Add several compatibility methods for unittest - assertions that were renamed between Python 2 and 3. - -- Issue #105 and pull request #58: Ensure `six.wraps` respects the *updated* and - *assigned* arguments. - -- Issue #102: Add `raise_from` to abstract out Python 3's raise from syntax. - -- Issue #97: Optimize `six.iterbytes` on Python 2. - -- Issue #98: Fix `six.moves` race condition in multi-threaded code. - -- Pull request #51: Add `six.view(keys|values|itmes)`, which provide dictionary - views on Python 2.7+. - -- Issue #112: `six.moves.reload_module` now uses the importlib module on - Python 3.4+. - -1.8.0 ------ - -- Issue #90: Add `six.moves.shlex_quote`. - -- Issue #59: Add `six.moves.intern`. - -- Add `six.urllib.parse.uses_(fragment|netloc|params|query|relative)`. - -- Issue #88: Fix add_metaclass when the class has `__slots__` containing - `__weakref__` or `__dict__`. - -- Issue #89: Make six use absolute imports. - -- Issue #85: Always accept *updated* and *assigned* arguments for `wraps()`. - -- Issue #86: In `reraise()`, instantiate the exception if the second argument is - `None`. - -- Pull request #45: Add `six.moves.email_mime_nonmultipart`. - -- Issue #81: Add `six.urllib.request.splittag` mapping. - -- Issue #80: Add `six.urllib.request.splituser` mapping. - -1.7.3 ------ - -- Issue #77: Fix import six on Python 3.4 with a custom loader. - -- Issue #74: `six.moves.xmlrpc_server` should map to `SimpleXMLRPCServer` on Python - 2 as documented not `xmlrpclib`. - -1.7.2 ------ - -- Issue #72: Fix installing on Python 2. - -1.7.1 ------ - -- Issue #71: Make the six.moves meta path importer handle reloading of the six - module gracefully. - -1.7.0 ------ - -- Pull request #30: Implement six.moves with a PEP 302 meta path hook. - -- Pull request #32: Add six.wraps, which is like functools.wraps but always sets - the __wrapped__ attribute. - -- Pull request #35: Improve add_metaclass, so that it doesn't end up inserting - another class into the hierarchy. - -- Pull request #34: Add import mappings for dummy_thread. - -- Pull request #33: Add import mappings for UserDict and UserList. - -- Pull request #31: Select the implementations of dictionary iterator routines - at import time for a 20% speed boost. - -1.6.1 ------ - -- Raise an AttributeError for six.moves.X when X is a module not available in - the current interpreter. - -1.6.0 ------ - -- Raise an AttributeError for every attribute of unimportable modules. - -- Issue #56: Make the fake modules six.moves puts into sys.modules appear not to - have a __path__ unless they are loaded. - -- Pull request #28: Add support for SplitResult. - -- Issue #55: Add move mapping for xmlrpc.server. - -- Pull request #29: Add move for urllib.parse.splitquery. - -1.5.2 ------ - -- Issue #53: Make the fake modules six.moves puts into sys.modules appear not to - have a __name__ unless they are loaded. - -1.5.1 ------ - -- Issue #51: Hack around the Django autoreloader after recent six.moves changes. - -1.5.0 ------ - -- Removed support for Python 2.4. This is because py.test no longer supports - 2.4. - -- Fix various import problems including issues #19 and #41. six.moves modules - are now lazy wrappers over the underlying modules instead of the actual - modules themselves. - -- Issue #49: Add six.moves mapping for tkinter.ttk. - -- Pull request #24: Add __dir__ special method to six.moves modules. - -- Issue #47: Fix add_metaclass on classes with a string for the __slots__ - variable. - -- Issue #44: Fix interpretation of backslashes on Python 2 in the u() function. - -- Pull request #21: Add import mapping for urllib's proxy_bypass function. - -- Issue #43: Add import mapping for the Python 2 xmlrpclib module. - -- Issue #39: Add import mapping for the Python 2 thread module. - -- Issue #40: Add import mapping for the Python 2 gdbm module. - -- Issue #35: On Python versions less than 2.7, print_ now encodes unicode - strings when outputing to standard streams. (Python 2.7 handles this - automatically.) - -1.4.1 ------ - -- Issue #32: urllib module wrappings don't work when six is not a toplevel file. - -1.4.0 ------ - -- Issue #31: Add six.moves mapping for UserString. - -- Pull request #12: Add six.add_metaclass, a decorator for adding a metaclass to - a class. - -- Add six.moves.zip_longest and six.moves.filterfalse, which correspond - respectively to itertools.izip_longest and itertools.ifilterfalse on Python 2 - and itertools.zip_longest and itertools.filterfalse on Python 3. - -- Issue #25: Add the unichr function, which returns a string for a Unicode - codepoint. - -- Issue #26: Add byte2int function, which complements int2byte. - -- Add a PY2 constant with obvious semantics. - -- Add helpers for indexing and iterating over bytes: iterbytes and indexbytes. - -- Add create_bound_method() wrapper. - -- Issue #23: Allow multiple base classes to be passed to with_metaclass. - -- Issue #24: Add six.moves.range alias. This exactly the same as the current - xrange alias. - -- Pull request #5: Create six.moves.urllib, which contains abstractions for a - bunch of things which are in urllib in Python 3 and spread out across urllib, - urllib2, and urlparse in Python 2. - -1.3.0 ------ - -- Issue #21: Add methods to access the closure and globals of a function. - -- In six.iter(items/keys/values/lists), passed keyword arguments through to the - underlying method. - -- Add six.iterlists(). - -- Issue #20: Fix tests if tkinter is not available. - -- Issue #17: Define callable to be builtin callable when it is available again - in Python 3.2+. - -- Issue #16: Rename Python 2 exec_'s arguments, so casually calling exec_ with - keyword arguments will raise. - -- Issue #14: Put the six.moves package in sys.modules based on the name six is - imported under. - -- Fix Jython detection. - -- Pull request #4: Add email_mime_multipart, email_mime_text, and - email_mime_base to six.moves. - -1.2.0 ------ - -- Issue #13: Make iterkeys/itervalues/iteritems return iterators on Python 3 - instead of iterables. - -- Issue #11: Fix maxsize support on Jython. - -- Add six.next() as an alias for six.advance_iterator(). - -- Use the builtin next() function for advance_iterator() where is available - (2.6+), not just Python 3. - -- Add the Iterator class for writing portable iterators. - -1.1.0 ------ - -- Add the int2byte function. - -- Add compatibility mappings for iterators over the keys, values, and items of a - dictionary. - -- Fix six.MAXSIZE on platforms where sizeof(long) != sizeof(Py_ssize_t). - -- Issue #3: Add six.moves mappings for filter, map, and zip. - -1.0.0 ------ - -- Issue #2: u() on Python 2.x now resolves unicode escapes. - -- Expose an API for adding mappings to six.moves. - -1.0 beta 1 ----------- - -- Reworked six into one .py file. This breaks imports. Please tell me if you - are interested in an import compatibility layer. diff --git a/third_party/python/six/MANIFEST.in b/third_party/python/six/MANIFEST.in deleted file mode 100644 index b924e068eeee..000000000000 --- a/third_party/python/six/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include CHANGES -include LICENSE -include test_six.py - -recursive-include documentation * -prune documentation/_build diff --git a/third_party/python/six/PKG-INFO b/third_party/python/six/PKG-INFO deleted file mode 100644 index 33d8f432eaff..000000000000 --- a/third_party/python/six/PKG-INFO +++ /dev/null @@ -1,50 +0,0 @@ -Metadata-Version: 1.2 -Name: six -Version: 1.13.0 -Summary: Python 2 and 3 compatibility utilities -Home-page: https://github.com/benjaminp/six -Author: Benjamin Peterson -Author-email: benjamin@python.org -License: MIT -Description: .. image:: https://img.shields.io/pypi/v/six.svg - :target: https://pypi.org/project/six/ - :alt: six on PyPI - - .. image:: https://travis-ci.org/benjaminp/six.svg?branch=master - :target: https://travis-ci.org/benjaminp/six - :alt: six on TravisCI - - .. image:: https://readthedocs.org/projects/six/badge/?version=latest - :target: https://six.readthedocs.io/ - :alt: six's documentation on Read the Docs - - .. image:: https://img.shields.io/badge/license-MIT-green.svg - :target: https://github.com/benjaminp/six/blob/master/LICENSE - :alt: MIT License badge - - Six is a Python 2 and 3 compatibility library. It provides utility functions - for smoothing over the differences between the Python versions with the goal of - writing Python code that is compatible on both Python versions. See the - documentation for more information on what is provided. - - Six supports every Python version since 2.6. It is contained in only one Python - file, so it can be easily copied into your project. (The copyright and license - notice must be retained.) - - Online documentation is at https://six.readthedocs.io/. - - Bugs can be reported to https://github.com/benjaminp/six. The code can also - be found there. - - For questions about six or porting in general, email the python-porting mailing - list: https://mail.python.org/mailman/listinfo/python-porting - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Requires-Python: >=2.6, !=3.0.*, !=3.1.* diff --git a/third_party/python/six/documentation/Makefile b/third_party/python/six/documentation/Makefile deleted file mode 100644 index eebafcd6d60f..000000000000 --- a/third_party/python/six/documentation/Makefile +++ /dev/null @@ -1,130 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/six.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/six.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/six" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/six" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/third_party/python/six/documentation/conf.py b/third_party/python/six/documentation/conf.py deleted file mode 100644 index b3d1328adc2a..000000000000 --- a/third_party/python/six/documentation/conf.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -# -# six documentation build configuration file - -import os -import sys - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = "1.0" - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ["sphinx.ext.intersphinx"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -#source_encoding = "utf-8-sig" - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = u"six" -copyright = u"2010-2019, Benjamin Peterson" - -sys.path.append(os.path.abspath(os.path.join(".", ".."))) -from six import __version__ as six_version -sys.path.pop() - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = six_version[:-2] -# The full version, including alpha/beta/rc tags. -release = six_version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ["_build"] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = "default" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'sixdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ("index", "six.tex", u"six Documentation", - u"Benjamin Peterson", "manual"), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ("index", "six", u"six Documentation", - [u"Benjamin Peterson"], 1) -] - -# -- Intersphinx --------------------------------------------------------------- - -intersphinx_mapping = {"py2" : ("https://docs.python.org/2/", None), - "py3" : ("https://docs.python.org/3/", None)} diff --git a/third_party/python/six/documentation/index.rst b/third_party/python/six/documentation/index.rst deleted file mode 100644 index b7ec2754ecf8..000000000000 --- a/third_party/python/six/documentation/index.rst +++ /dev/null @@ -1,875 +0,0 @@ -Six: Python 2 and 3 Compatibility Library -========================================= - -.. module:: six - :synopsis: Python 2 and 3 compatibility - -.. moduleauthor:: Benjamin Peterson -.. sectionauthor:: Benjamin Peterson - - -Six provides simple utilities for wrapping over differences between Python 2 and -Python 3. It is intended to support codebases that work on both Python 2 and 3 -without modification. six consists of only one Python file, so it is painless -to copy into a project. - -Six can be downloaded on `PyPI `_. Its bug -tracker and code hosting is on `GitHub `_. - -The name, "six", comes from the fact that 2*3 equals 6. Why not addition? -Multiplication is more powerful, and, anyway, "five" has already been snatched -away by the (admittedly now moribund) Zope Five project. - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`search` - - -Package contents ----------------- - -.. data:: PY2 - - A boolean indicating if the code is running on Python 2. - -.. data:: PY3 - - A boolean indicating if the code is running on Python 3. - - -Constants ->>>>>>>>> - -Six provides constants that may differ between Python versions. Ones ending -``_types`` are mostly useful as the second argument to ``isinstance`` or -``issubclass``. - - -.. data:: class_types - - Possible class types. In Python 2, this encompasses old-style - :data:`py2:types.ClassType` and new-style ``type`` classes. In Python 3, - this is just ``type``. - - -.. data:: integer_types - - Possible integer types. In Python 2, this is :func:`py2:long` and - :func:`py2:int`, and in Python 3, just :func:`py3:int`. - - -.. data:: string_types - - Possible types for text data. This is :func:`py2:basestring` in Python 2 and - :func:`py3:str` in Python 3. - - -.. data:: text_type - - Type for representing (Unicode) textual data. This is :func:`py2:unicode` in - Python 2 and :func:`py3:str` in Python 3. - - -.. data:: binary_type - - Type for representing binary data. This is :func:`py2:str` in Python 2 and - :func:`py3:bytes` in Python 3. Python 2.6 and 2.7 include ``bytes`` as a - builtin alias of ``str``, so six’s version is only necessary for Python 2.5 - compatibility. - - -.. data:: MAXSIZE - - The maximum size of a container like :func:`py3:list` or :func:`py3:dict`. - This is equivalent to :data:`py3:sys.maxsize` in Python 2.6 and later - (including 3.x). Note, this is temptingly similar to, but not the same as - :data:`py2:sys.maxint` in Python 2. There is no direct equivalent to - :data:`py2:sys.maxint` in Python 3 because its integer type has no limits - aside from memory. - - -Here's example usage of the module:: - - import six - - def dispatch_types(value): - if isinstance(value, six.integer_types): - handle_integer(value) - elif isinstance(value, six.class_types): - handle_class(value) - elif isinstance(value, six.string_types): - handle_string(value) - - -Object model compatibility ->>>>>>>>>>>>>>>>>>>>>>>>>> - -Python 3 renamed the attributes of several interpreter data structures. The -following accessors are available. Note that the recommended way to inspect -functions and methods is the stdlib :mod:`py3:inspect` module. - - -.. function:: get_unbound_function(meth) - - Get the function out of unbound method *meth*. In Python 3, unbound methods - don't exist, so this function just returns *meth* unchanged. Example - usage:: - - from six import get_unbound_function - - class X(object): - def method(self): - pass - method_function = get_unbound_function(X.method) - - -.. function:: get_method_function(meth) - - Get the function out of method object *meth*. - - -.. function:: get_method_self(meth) - - Get the ``self`` of bound method *meth*. - - -.. function:: get_function_closure(func) - - Get the closure (list of cells) associated with *func*. This is equivalent - to ``func.__closure__`` on Python 2.6+ and ``func.func_closure`` on Python - 2.5. - - -.. function:: get_function_code(func) - - Get the code object associated with *func*. This is equivalent to - ``func.__code__`` on Python 2.6+ and ``func.func_code`` on Python 2.5. - - -.. function:: get_function_defaults(func) - - Get the defaults tuple associated with *func*. This is equivalent to - ``func.__defaults__`` on Python 2.6+ and ``func.func_defaults`` on Python - 2.5. - - -.. function:: get_function_globals(func) - - Get the globals of *func*. This is equivalent to ``func.__globals__`` on - Python 2.6+ and ``func.func_globals`` on Python 2.5. - - -.. function:: next(it) - advance_iterator(it) - - Get the next item of iterator *it*. :exc:`py3:StopIteration` is raised if - the iterator is exhausted. This is a replacement for calling ``it.next()`` - in Python 2 and ``next(it)`` in Python 3. Python 2.6 and above have a - builtin ``next`` function, so six's version is only necessary for Python 2.5 - compatibility. - - -.. function:: callable(obj) - - Check if *obj* can be called. Note ``callable`` has returned in Python 3.2, - so using six's version is only necessary when supporting Python 3.0 or 3.1. - - -.. function:: iterkeys(dictionary, **kwargs) - - Returns an iterator over *dictionary*\'s keys. This replaces - ``dictionary.iterkeys()`` on Python 2 and ``dictionary.keys()`` on - Python 3. *kwargs* are passed through to the underlying method. - - -.. function:: itervalues(dictionary, **kwargs) - - Returns an iterator over *dictionary*\'s values. This replaces - ``dictionary.itervalues()`` on Python 2 and ``dictionary.values()`` on - Python 3. *kwargs* are passed through to the underlying method. - - -.. function:: iteritems(dictionary, **kwargs) - - Returns an iterator over *dictionary*\'s items. This replaces - ``dictionary.iteritems()`` on Python 2 and ``dictionary.items()`` on - Python 3. *kwargs* are passed through to the underlying method. - - -.. function:: iterlists(dictionary, **kwargs) - - Calls ``dictionary.iterlists()`` on Python 2 and ``dictionary.lists()`` on - Python 3. No builtin Python mapping type has such a method; this method is - intended for use with multi-valued dictionaries like `Werkzeug's - `_. - *kwargs* are passed through to the underlying method. - - -.. function:: viewkeys(dictionary) - - Return a view over *dictionary*\'s keys. This replaces - :meth:`py2:dict.viewkeys` on Python 2.7 and :meth:`py3:dict.keys` on - Python 3. - - -.. function:: viewvalues(dictionary) - - Return a view over *dictionary*\'s values. This replaces - :meth:`py2:dict.viewvalues` on Python 2.7 and :meth:`py3:dict.values` on - Python 3. - - -.. function:: viewitems(dictionary) - - Return a view over *dictionary*\'s items. This replaces - :meth:`py2:dict.viewitems` on Python 2.7 and :meth:`py3:dict.items` on - Python 3. - - -.. function:: create_bound_method(func, obj) - - Return a method object wrapping *func* and bound to *obj*. On both Python 2 - and 3, this will return a :func:`py3:types.MethodType` object. The reason - this wrapper exists is that on Python 2, the ``MethodType`` constructor - requires the *obj*'s class to be passed. - - -.. function:: create_unbound_method(func, cls) - - Return an unbound method object wrapping *func*. In Python 2, this will - return a :func:`py2:types.MethodType` object. In Python 3, unbound methods - do not exist and this wrapper will simply return *func*. - - -.. class:: Iterator - - A class for making portable iterators. The intention is that it be subclassed - and subclasses provide a ``__next__`` method. In Python 2, :class:`Iterator` - has one method: ``next``. It simply delegates to ``__next__``. An alternate - way to do this would be to simply alias ``next`` to ``__next__``. However, - this interacts badly with subclasses that override - ``__next__``. :class:`Iterator` is empty on Python 3. (In fact, it is just - aliased to :class:`py3:object`.) - - -.. decorator:: wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES) - - This is exactly the :func:`py3:functools.wraps` decorator, but it sets the - ``__wrapped__`` attribute on what it decorates as :func:`py3:functools.wraps` - does on Python versions after 3.2. - - -Syntax compatibility ->>>>>>>>>>>>>>>>>>>> - -These functions smooth over operations which have different syntaxes between -Python 2 and 3. - - -.. function:: exec_(code, globals=None, locals=None) - - Execute *code* in the scope of *globals* and *locals*. *code* can be a - string or a code object. If *globals* or *locals* are not given, they will - default to the scope of the caller. If just *globals* is given, it will also - be used as *locals*. - - .. note:: - - Python 3's :func:`py3:exec` doesn't take keyword arguments, so calling - :func:`exec` with them should be avoided. - - -.. function:: print_(*args, *, file=sys.stdout, end="\\n", sep=" ", flush=False) - - Print *args* into *file*. Each argument will be separated with *sep* and - *end* will be written to the file after the last argument is printed. If - *flush* is true, ``file.flush()`` will be called after all data is written. - - .. note:: - - In Python 2, this function imitates Python 3's :func:`py3:print` by not - having softspace support. If you don't know what that is, you're probably - ok. :) - - -.. function:: raise_from(exc_value, exc_value_from) - - Raise an exception from a context. On Python 3, this is equivalent to - ``raise exc_value from exc_value_from``. On Python 2, which does not support - exception chaining, it is equivalent to ``raise exc_value``. - - -.. function:: reraise(exc_type, exc_value, exc_traceback=None) - - Reraise an exception, possibly with a different traceback. In the simple - case, ``reraise(*sys.exc_info())`` with an active exception (in an except - block) reraises the current exception with the last traceback. A different - traceback can be specified with the *exc_traceback* parameter. Note that - since the exception reraising is done within the :func:`reraise` function, - Python will attach the call frame of :func:`reraise` to whatever traceback is - raised. - - -.. function:: with_metaclass(metaclass, *bases) - - Create a new class with base classes *bases* and metaclass *metaclass*. This - is designed to be used in class declarations like this: :: - - from six import with_metaclass - - class Meta(type): - pass - - class Base(object): - pass - - class MyClass(with_metaclass(Meta, Base)): - pass - - Another way to set a metaclass on a class is with the :func:`add_metaclass` - decorator. - - -.. decorator:: add_metaclass(metaclass) - - Class decorator that replaces a normally-constructed class with a - metaclass-constructed one. Example usage: :: - - @add_metaclass(Meta) - class MyClass(object): - pass - - That code produces a class equivalent to :: - - class MyClass(object, metaclass=Meta): - pass - - on Python 3 or :: - - class MyClass(object): - __metaclass__ = Meta - - on Python 2. - - Note that class decorators require Python 2.6. However, the effect of the - decorator can be emulated on Python 2.5 like so:: - - class MyClass(object): - pass - MyClass = add_metaclass(Meta)(MyClass) - - -Binary and text data ->>>>>>>>>>>>>>>>>>>> - -Python 3 enforces the distinction between byte strings and text strings far more -rigorously than Python 2 does; binary data cannot be automatically coerced to -or from text data. six provides several functions to assist in classifying -string data in all Python versions. - - -.. function:: b(data) - - A "fake" bytes literal. *data* should always be a normal string literal. In - Python 2, :func:`b` returns an 8-bit string. In Python 3, *data* is encoded - with the latin-1 encoding to bytes. - - - .. note:: - - Since all Python versions 2.6 and after support the ``b`` prefix, - code without 2.5 support doesn't need :func:`b`. - - -.. function:: u(text) - - A "fake" unicode literal. *text* should always be a normal string literal. - In Python 2, :func:`u` returns unicode, and in Python 3, a string. Also, in - Python 2, the string is decoded with the ``unicode-escape`` codec, which - allows unicode escapes to be used in it. - - - .. note:: - - In Python 3.3, the ``u`` prefix has been reintroduced. Code that only - supports Python 3 versions of 3.3 and higher thus does not need - :func:`u`. - - .. note:: - - On Python 2, :func:`u` doesn't know what the encoding of the literal - is. Each byte is converted directly to the unicode codepoint of the same - value. Because of this, it's only safe to use :func:`u` with strings of - ASCII data. - - -.. function:: unichr(c) - - Return the (Unicode) string representing the codepoint *c*. This is - equivalent to :func:`py2:unichr` on Python 2 and :func:`py3:chr` on Python 3. - - -.. function:: int2byte(i) - - Converts *i* to a byte. *i* must be in ``range(0, 256)``. This is - equivalent to :func:`py2:chr` in Python 2 and ``bytes((i,))`` in Python 3. - - -.. function:: byte2int(bs) - - Converts the first byte of *bs* to an integer. This is equivalent to - ``ord(bs[0])`` on Python 2 and ``bs[0]`` on Python 3. - - -.. function:: indexbytes(buf, i) - - Return the byte at index *i* of *buf* as an integer. This is equivalent to - indexing a bytes object in Python 3. - - -.. function:: iterbytes(buf) - - Return an iterator over bytes in *buf* as integers. This is equivalent to - a bytes object iterator in Python 3. - - -.. function:: ensure_binary(s, encoding='utf-8', errors='strict') - - Coerce *s* to :data:`binary_type`. *encoding*, *errors* are the same as - :meth:`py3:str.encode` - - -.. function:: ensure_str(s, encoding='utf-8', errors='strict') - - Coerce *s* to ``str``. *encoding*, *errors* are the same as - :meth:`py3:str.encode` - - -.. function:: ensure_text(s, encoding='utf-8', errors='strict') - - Coerce *s* to :data:`text_type`. *encoding*, *errors* are the same as - :meth:`py3:str.encode` - - -.. data:: StringIO - - This is a fake file object for textual data. It's an alias for - :class:`py2:StringIO.StringIO` in Python 2 and :class:`py3:io.StringIO` in - Python 3. - - -.. data:: BytesIO - - This is a fake file object for binary data. In Python 2, it's an alias for - :class:`py2:StringIO.StringIO`, but in Python 3, it's an alias for - :class:`py3:io.BytesIO`. - - -.. decorator:: python_2_unicode_compatible - - A class decorator that takes a class defining a ``__str__`` method. On - Python 3, the decorator does nothing. On Python 2, it aliases the - ``__str__`` method to ``__unicode__`` and creates a new ``__str__`` method - that returns the result of ``__unicode__()`` encoded with UTF-8. - - -unittest assertions ->>>>>>>>>>>>>>>>>>> - -Six contains compatibility shims for unittest assertions that have been renamed. -The parameters are the same as their aliases, but you must pass the test method -as the first argument. For example:: - - import six - import unittest - - class TestAssertCountEqual(unittest.TestCase): - def test(self): - six.assertCountEqual(self, (1, 2), [2, 1]) - -Note these functions are only available on Python 2.7 or later. - -.. function:: assertCountEqual() - - Alias for :meth:`~py3:unittest.TestCase.assertCountEqual` on Python 3 and - :meth:`~py2:unittest.TestCase.assertItemsEqual` on Python 2. - - -.. function:: assertRaisesRegex() - - Alias for :meth:`~py3:unittest.TestCase.assertRaisesRegex` on Python 3 and - :meth:`~py2:unittest.TestCase.assertRaisesRegexp` on Python 2. - - -.. function:: assertRegex() - - Alias for :meth:`~py3:unittest.TestCase.assertRegex` on Python 3 and - :meth:`~py2:unittest.TestCase.assertRegexpMatches` on Python 2. - - -Renamed modules and attributes compatibility ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -.. module:: six.moves - :synopsis: Renamed modules and attributes compatibility - -Python 3 reorganized the standard library and moved several functions to -different modules. Six provides a consistent interface to them through the fake -:mod:`six.moves` module. For example, to load the module for parsing HTML on -Python 2 or 3, write:: - - from six.moves import html_parser - -Similarly, to get the function to reload modules, which was moved from the -builtin module to the ``importlib`` module, use:: - - from six.moves import reload_module - -For the most part, :mod:`six.moves` aliases are the names of the modules in -Python 3. When the new Python 3 name is a package, the components of the name -are separated by underscores. For example, ``html.parser`` becomes -``html_parser``. In some cases where several modules have been combined, the -Python 2 name is retained. This is so the appropriate modules can be found when -running on Python 2. For example, ``BaseHTTPServer`` which is in -``http.server`` in Python 3 is aliased as ``BaseHTTPServer``. - -Some modules which had two implementations have been merged in Python 3. For -example, ``cPickle`` no longer exists in Python 3; it was merged with -``pickle``. In these cases, fetching the fast version will load the fast one on -Python 2 and the merged module in Python 3. - -The :mod:`py2:urllib`, :mod:`py2:urllib2`, and :mod:`py2:urlparse` modules have -been combined in the :mod:`py3:urllib` package in Python 3. The -:mod:`six.moves.urllib` package is a version-independent location for this -functionality; its structure mimics the structure of the Python 3 -:mod:`py3:urllib` package. - -.. note:: - - In order to make imports of the form:: - - from six.moves.cPickle import loads - - work, six places special proxy objects in :data:`py3:sys.modules`. These - proxies lazily load the underlying module when an attribute is fetched. This - will fail if the underlying module is not available in the Python - interpreter. For example, ``sys.modules["six.moves.winreg"].LoadKey`` would - fail on any non-Windows platform. Unfortunately, some applications try to - load attributes on every module in :data:`py3:sys.modules`. six mitigates - this problem for some applications by pretending attributes on unimportable - modules do not exist. This hack does not work in every case, though. If you are - encountering problems with the lazy modules and don't use any from imports - directly from ``six.moves`` modules, you can workaround the issue by removing - the six proxy modules:: - - d = [name for name in sys.modules if name.startswith("six.moves.")] - for name in d: - del sys.modules[name] - -Supported renames: - -+------------------------------+-------------------------------------+---------------------------------------+ -| Name | Python 2 name | Python 3 name | -+==============================+=====================================+=======================================+ -| ``builtins`` | :mod:`py2:__builtin__` | :mod:`py3:builtins` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``configparser`` | :mod:`py2:ConfigParser` | :mod:`py3:configparser` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``copyreg`` | :mod:`py2:copy_reg` | :mod:`py3:copyreg` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``cPickle`` | :mod:`py2:cPickle` | :mod:`py3:pickle` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``cStringIO`` | :func:`py2:cStringIO.StringIO` | :class:`py3:io.StringIO` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``collections_abc`` | :mod:`py2:collections` | :mod:`py3:collections.abc` (3.3+) | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``dbm_gnu`` | :mod:`py2:gdbm` | :mod:`py3:dbm.gnu` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``dbm_ndbm`` | :mod:`py2:dbm` | :mod:`py3:dbm.ndbm` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``_dummy_thread`` | :mod:`py2:dummy_thread` | :mod:`py3:_dummy_thread` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``email_mime_base`` | :mod:`py2:email.MIMEBase` | :mod:`py3:email.mime.base` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``email_mime_image`` | :mod:`py2:email.MIMEImage` | :mod:`py3:email.mime.image` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``email_mime_multipart`` | :mod:`py2:email.MIMEMultipart` | :mod:`py3:email.mime.multipart` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``email_mime_nonmultipart`` | :mod:`py2:email.MIMENonMultipart` | :mod:`py3:email.mime.nonmultipart` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``email_mime_text`` | :mod:`py2:email.MIMEText` | :mod:`py3:email.mime.text` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``filter`` | :func:`py2:itertools.ifilter` | :func:`py3:filter` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``filterfalse`` | :func:`py2:itertools.ifilterfalse` | :func:`py3:itertools.filterfalse` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``getcwd`` | :func:`py2:os.getcwdu` | :func:`py3:os.getcwd` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``getcwdb`` | :func:`py2:os.getcwd` | :func:`py3:os.getcwdb` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``getoutput`` | :func:`py2:commands.getoutput` | :func:`py3:subprocess.getoutput` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``http_cookiejar`` | :mod:`py2:cookielib` | :mod:`py3:http.cookiejar` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``http_cookies`` | :mod:`py2:Cookie` | :mod:`py3:http.cookies` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``html_entities`` | :mod:`py2:htmlentitydefs` | :mod:`py3:html.entities` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``html_parser`` | :mod:`py2:HTMLParser` | :mod:`py3:html.parser` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``http_client`` | :mod:`py2:httplib` | :mod:`py3:http.client` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``BaseHTTPServer`` | :mod:`py2:BaseHTTPServer` | :mod:`py3:http.server` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``CGIHTTPServer`` | :mod:`py2:CGIHTTPServer` | :mod:`py3:http.server` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``SimpleHTTPServer`` | :mod:`py2:SimpleHTTPServer` | :mod:`py3:http.server` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``input`` | :func:`py2:raw_input` | :func:`py3:input` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``intern`` | :func:`py2:intern` | :func:`py3:sys.intern` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``map`` | :func:`py2:itertools.imap` | :func:`py3:map` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``queue`` | :mod:`py2:Queue` | :mod:`py3:queue` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``range`` | :func:`py2:xrange` | :func:`py3:range` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``reduce`` | :func:`py2:reduce` | :func:`py3:functools.reduce` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``reload_module`` | :func:`py2:reload` | :func:`py3:imp.reload`, | -| | | :func:`py3:importlib.reload` | -| | | on Python 3.4+ | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``reprlib`` | :mod:`py2:repr` | :mod:`py3:reprlib` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``shlex_quote`` | :mod:`py2:pipes.quote` | :mod:`py3:shlex.quote` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``socketserver`` | :mod:`py2:SocketServer` | :mod:`py3:socketserver` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``_thread`` | :mod:`py2:thread` | :mod:`py3:_thread` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter`` | :mod:`py2:Tkinter` | :mod:`py3:tkinter` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_dialog`` | :mod:`py2:Dialog` | :mod:`py3:tkinter.dialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_filedialog`` | :mod:`py2:FileDialog` | :mod:`py3:tkinter.FileDialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_scrolledtext`` | :mod:`py2:ScrolledText` | :mod:`py3:tkinter.scrolledtext` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_simpledialog`` | :mod:`py2:SimpleDialog` | :mod:`py3:tkinter.simpledialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_ttk`` | :mod:`py2:ttk` | :mod:`py3:tkinter.ttk` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_tix`` | :mod:`py2:Tix` | :mod:`py3:tkinter.tix` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_constants`` | :mod:`py2:Tkconstants` | :mod:`py3:tkinter.constants` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_dnd`` | :mod:`py2:Tkdnd` | :mod:`py3:tkinter.dnd` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_colorchooser`` | :mod:`py2:tkColorChooser` | :mod:`py3:tkinter.colorchooser` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_commondialog`` | :mod:`py2:tkCommonDialog` | :mod:`py3:tkinter.commondialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_tkfiledialog`` | :mod:`py2:tkFileDialog` | :mod:`py3:tkinter.filedialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_font`` | :mod:`py2:tkFont` | :mod:`py3:tkinter.font` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_messagebox`` | :mod:`py2:tkMessageBox` | :mod:`py3:tkinter.messagebox` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``tkinter_tksimpledialog`` | :mod:`py2:tkSimpleDialog` | :mod:`py3:tkinter.simpledialog` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib.parse`` | See :mod:`six.moves.urllib.parse` | :mod:`py3:urllib.parse` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib.error`` | See :mod:`six.moves.urllib.error` | :mod:`py3:urllib.error` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib.request`` | See :mod:`six.moves.urllib.request` | :mod:`py3:urllib.request` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib.response`` | See :mod:`six.moves.urllib.response`| :mod:`py3:urllib.response` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib.robotparser`` | :mod:`py2:robotparser` | :mod:`py3:urllib.robotparser` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``urllib_robotparser`` | :mod:`py2:robotparser` | :mod:`py3:urllib.robotparser` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``UserDict`` | :class:`py2:UserDict.UserDict` | :class:`py3:collections.UserDict` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``UserList`` | :class:`py2:UserList.UserList` | :class:`py3:collections.UserList` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``UserString`` | :class:`py2:UserString.UserString` | :class:`py3:collections.UserString` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``winreg`` | :mod:`py2:_winreg` | :mod:`py3:winreg` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``xmlrpc_client`` | :mod:`py2:xmlrpclib` | :mod:`py3:xmlrpc.client` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``xmlrpc_server`` | :mod:`py2:SimpleXMLRPCServer` | :mod:`py3:xmlrpc.server` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``xrange`` | :func:`py2:xrange` | :func:`py3:range` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``zip`` | :func:`py2:itertools.izip` | :func:`py3:zip` | -+------------------------------+-------------------------------------+---------------------------------------+ -| ``zip_longest`` | :func:`py2:itertools.izip_longest` | :func:`py3:itertools.zip_longest` | -+------------------------------+-------------------------------------+---------------------------------------+ - -urllib parse -<<<<<<<<<<<< - -.. module:: six.moves.urllib.parse - :synopsis: Stuff from :mod:`py2:urlparse` and :mod:`py2:urllib` in Python 2 and :mod:`py3:urllib.parse` in Python 3 - -Contains functions from Python 3's :mod:`py3:urllib.parse` and Python 2's: - -:mod:`py2:urlparse`: - -* :func:`py2:urlparse.ParseResult` -* :func:`py2:urlparse.SplitResult` -* :func:`py2:urlparse.urlparse` -* :func:`py2:urlparse.urlunparse` -* :func:`py2:urlparse.parse_qs` -* :func:`py2:urlparse.parse_qsl` -* :func:`py2:urlparse.urljoin` -* :func:`py2:urlparse.urldefrag` -* :func:`py2:urlparse.urlsplit` -* :func:`py2:urlparse.urlunsplit` -* :func:`py2:urlparse.splitquery` -* :func:`py2:urlparse.uses_fragment` -* :func:`py2:urlparse.uses_netloc` -* :func:`py2:urlparse.uses_params` -* :func:`py2:urlparse.uses_query` -* :func:`py2:urlparse.uses_relative` - -and :mod:`py2:urllib`: - -* :func:`py2:urllib.quote` -* :func:`py2:urllib.quote_plus` -* :func:`py2:urllib.splittag` -* :func:`py2:urllib.splituser` -* :func:`py2:urllib.splitvalue` -* :func:`py2:urllib.unquote` (also exposed as :func:`py3:urllib.parse.unquote_to_bytes`) -* :func:`py2:urllib.unquote_plus` -* :func:`py2:urllib.urlencode` - - -urllib error -<<<<<<<<<<<< - -.. module:: six.moves.urllib.error - :synopsis: Stuff from :mod:`py2:urllib` and :mod:`py2:urllib2` in Python 2 and :mod:`py3:urllib.error` in Python 3 - -Contains exceptions from Python 3's :mod:`py3:urllib.error` and Python 2's: - -:mod:`py2:urllib`: - -* :exc:`py2:urllib.ContentTooShortError` - -and :mod:`py2:urllib2`: - -* :exc:`py2:urllib2.URLError` -* :exc:`py2:urllib2.HTTPError` - - -urllib request -<<<<<<<<<<<<<< - -.. module:: six.moves.urllib.request - :synopsis: Stuff from :mod:`py2:urllib` and :mod:`py2:urllib2` in Python 2 and :mod:`py3:urllib.request` in Python 3 - -Contains items from Python 3's :mod:`py3:urllib.request` and Python 2's: - -:mod:`py2:urllib`: - -* :func:`py2:urllib.pathname2url` -* :func:`py2:urllib.url2pathname` -* :func:`py2:urllib.getproxies` -* :func:`py2:urllib.urlretrieve` -* :func:`py2:urllib.urlcleanup` -* :class:`py2:urllib.URLopener` -* :class:`py2:urllib.FancyURLopener` -* :func:`py2:urllib.proxy_bypass` - -and :mod:`py2:urllib2`: - -* :func:`py2:urllib2.urlopen` -* :func:`py2:urllib2.install_opener` -* :func:`py2:urllib2.build_opener` -* :func:`py2:urllib2.parse_http_list` -* :func:`py2:urllib2.parse_keqv_list` -* :class:`py2:urllib2.Request` -* :class:`py2:urllib2.OpenerDirector` -* :class:`py2:urllib2.HTTPDefaultErrorHandler` -* :class:`py2:urllib2.HTTPRedirectHandler` -* :class:`py2:urllib2.HTTPCookieProcessor` -* :class:`py2:urllib2.ProxyHandler` -* :class:`py2:urllib2.BaseHandler` -* :class:`py2:urllib2.HTTPPasswordMgr` -* :class:`py2:urllib2.HTTPPasswordMgrWithDefaultRealm` -* :class:`py2:urllib2.AbstractBasicAuthHandler` -* :class:`py2:urllib2.HTTPBasicAuthHandler` -* :class:`py2:urllib2.ProxyBasicAuthHandler` -* :class:`py2:urllib2.AbstractDigestAuthHandler` -* :class:`py2:urllib2.HTTPDigestAuthHandler` -* :class:`py2:urllib2.ProxyDigestAuthHandler` -* :class:`py2:urllib2.HTTPHandler` -* :class:`py2:urllib2.HTTPSHandler` -* :class:`py2:urllib2.FileHandler` -* :class:`py2:urllib2.FTPHandler` -* :class:`py2:urllib2.CacheFTPHandler` -* :class:`py2:urllib2.UnknownHandler` -* :class:`py2:urllib2.HTTPErrorProcessor` - - -urllib response -<<<<<<<<<<<<<<< - -.. module:: six.moves.urllib.response - :synopsis: Stuff from :mod:`py2:urllib` in Python 2 and :mod:`py3:urllib.response` in Python 3 - -Contains classes from Python 3's :mod:`py3:urllib.response` and Python 2's: - -:mod:`py2:urllib`: - -* :class:`py2:urllib.addbase` -* :class:`py2:urllib.addclosehook` -* :class:`py2:urllib.addinfo` -* :class:`py2:urllib.addinfourl` - - -Advanced - Customizing renames -<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - -.. currentmodule:: six - -It is possible to add additional names to the :mod:`six.moves` namespace. - - -.. function:: add_move(item) - - Add *item* to the :mod:`six.moves` mapping. *item* should be a - :class:`MovedAttribute` or :class:`MovedModule` instance. - - -.. function:: remove_move(name) - - Remove the :mod:`six.moves` mapping called *name*. *name* should be a - string. - - -Instances of the following classes can be passed to :func:`add_move`. Neither -have any public members. - - -.. class:: MovedModule(name, old_mod, new_mod) - - Create a mapping for :mod:`six.moves` called *name* that references different - modules in Python 2 and 3. *old_mod* is the name of the Python 2 module. - *new_mod* is the name of the Python 3 module. - - -.. class:: MovedAttribute(name, old_mod, new_mod, old_attr=None, new_attr=None) - - Create a mapping for :mod:`six.moves` called *name* that references different - attributes in Python 2 and 3. *old_mod* is the name of the Python 2 module. - *new_mod* is the name of the Python 3 module. If *new_attr* is not given, it - defaults to *old_attr*. If neither is given, they both default to *name*. diff --git a/third_party/python/six/setup.cfg b/third_party/python/six/setup.cfg deleted file mode 100644 index fb1f5367a487..000000000000 --- a/third_party/python/six/setup.cfg +++ /dev/null @@ -1,24 +0,0 @@ -[bdist_wheel] -universal = 1 - -[flake8] -max-line-length = 100 -ignore = F821 - -[metadata] -license_file = LICENSE - -[tool:pytest] -minversion = 2.2.0 -pep8ignore = - documentation/*.py ALL - test_six.py ALL -flakes-ignore = - documentation/*.py ALL - test_six.py ALL - six.py UndefinedName - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/six/setup.py b/third_party/python/six/setup.py deleted file mode 100644 index 97c685b5a50b..000000000000 --- a/third_party/python/six/setup.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2010-2019 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import with_statement - -# Six is a dependency of setuptools, so using setuptools creates a -# circular dependency when building a Python stack from source. We -# therefore allow falling back to distutils to install six. -try: - from setuptools import setup -except ImportError: - from distutils.core import setup - -import six - -six_classifiers = [ - "Development Status :: 5 - Production/Stable", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 3", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Topic :: Software Development :: Libraries", - "Topic :: Utilities", -] - -with open("README.rst", "r") as fp: - six_long_description = fp.read() - -setup(name="six", - version=six.__version__, - author="Benjamin Peterson", - author_email="benjamin@python.org", - url="https://github.com/benjaminp/six", - tests_require=["pytest"], - py_modules=["six"], - description="Python 2 and 3 compatibility utilities", - long_description=six_long_description, - license="MIT", - classifiers=six_classifiers, - python_requires=">=2.6, !=3.0.*, !=3.1.*", - ) diff --git a/third_party/python/six/LICENSE b/third_party/python/six/six-1.13.0.dist-info/LICENSE similarity index 100% rename from third_party/python/six/LICENSE rename to third_party/python/six/six-1.13.0.dist-info/LICENSE diff --git a/third_party/python/six/README.rst b/third_party/python/six/six-1.13.0.dist-info/METADATA similarity index 68% rename from third_party/python/six/README.rst rename to third_party/python/six/six-1.13.0.dist-info/METADATA index a99e6f5585a9..b0c8f51e1f36 100644 --- a/third_party/python/six/README.rst +++ b/third_party/python/six/six-1.13.0.dist-info/METADATA @@ -1,3 +1,21 @@ +Metadata-Version: 2.1 +Name: six +Version: 1.13.0 +Summary: Python 2 and 3 compatibility utilities +Home-page: https://github.com/benjaminp/six +Author: Benjamin Peterson +Author-email: benjamin@python.org +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=2.6, !=3.0.*, !=3.1.* + .. image:: https://img.shields.io/pypi/v/six.svg :target: https://pypi.org/project/six/ :alt: six on PyPI @@ -30,3 +48,5 @@ be found there. For questions about six or porting in general, email the python-porting mailing list: https://mail.python.org/mailman/listinfo/python-porting + + diff --git a/third_party/python/six/six-1.13.0.dist-info/RECORD b/third_party/python/six/six-1.13.0.dist-info/RECORD new file mode 100644 index 000000000000..a0e6c1fd4bd9 --- /dev/null +++ b/third_party/python/six/six-1.13.0.dist-info/RECORD @@ -0,0 +1,6 @@ +six.py,sha256=bsEzSFTZTx49wQttLORmSZTrpjGc8UbXt-HBa_LZX7Q,33045 +six-1.13.0.dist-info/LICENSE,sha256=t1KbjAcXGniow2wyg5BVKOSBKUXZd9El65JujMvyRbY,1066 +six-1.13.0.dist-info/METADATA,sha256=hxS4rSPRfO8ewbcLS30anoFi6LFgUQ3mk_xknZ8RV4w,1940 +six-1.13.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +six-1.13.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 +six-1.13.0.dist-info/RECORD,, diff --git a/third_party/python/six/six-1.13.0.dist-info/WHEEL b/third_party/python/six/six-1.13.0.dist-info/WHEEL new file mode 100644 index 000000000000..8b701e93c231 --- /dev/null +++ b/third_party/python/six/six-1.13.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/six/six-1.13.0.dist-info/top_level.txt b/third_party/python/six/six-1.13.0.dist-info/top_level.txt new file mode 100644 index 000000000000..ffe2fce49895 --- /dev/null +++ b/third_party/python/six/six-1.13.0.dist-info/top_level.txt @@ -0,0 +1 @@ +six diff --git a/third_party/python/six/test_six.py b/third_party/python/six/test_six.py deleted file mode 100644 index 0b7206741632..000000000000 --- a/third_party/python/six/test_six.py +++ /dev/null @@ -1,1060 +0,0 @@ -# Copyright (c) 2010-2019 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import operator -import sys -import types -import unittest -import abc - -import pytest - -import six - - -def test_add_doc(): - def f(): - """Icky doc""" - pass - six._add_doc(f, """New doc""") - assert f.__doc__ == "New doc" - - -def test_import_module(): - from logging import handlers - m = six._import_module("logging.handlers") - assert m is handlers - - -def test_integer_types(): - assert isinstance(1, six.integer_types) - assert isinstance(-1, six.integer_types) - assert isinstance(six.MAXSIZE + 23, six.integer_types) - assert not isinstance(.1, six.integer_types) - - -def test_string_types(): - assert isinstance("hi", six.string_types) - assert isinstance(six.u("hi"), six.string_types) - assert issubclass(six.text_type, six.string_types) - - -def test_class_types(): - class X: - pass - class Y(object): - pass - assert isinstance(X, six.class_types) - assert isinstance(Y, six.class_types) - assert not isinstance(X(), six.class_types) - - -def test_text_type(): - assert type(six.u("hi")) is six.text_type - - -def test_binary_type(): - assert type(six.b("hi")) is six.binary_type - - -def test_MAXSIZE(): - try: - # This shouldn't raise an overflow error. - six.MAXSIZE.__index__() - except AttributeError: - # Before Python 2.6. - pass - pytest.raises( - (ValueError, OverflowError), - operator.mul, [None], six.MAXSIZE + 1) - - -def test_lazy(): - if six.PY3: - html_name = "html.parser" - else: - html_name = "HTMLParser" - assert html_name not in sys.modules - mod = six.moves.html_parser - assert sys.modules[html_name] is mod - assert "htmlparser" not in six._MovedItems.__dict__ - - -try: - import _tkinter -except ImportError: - have_tkinter = False -else: - have_tkinter = True - -have_gdbm = True -try: - import gdbm -except ImportError: - try: - import dbm.gnu - except ImportError: - have_gdbm = False - -@pytest.mark.parametrize("item_name", - [item.name for item in six._moved_attributes]) -def test_move_items(item_name): - """Ensure that everything loads correctly.""" - try: - item = getattr(six.moves, item_name) - if isinstance(item, types.ModuleType): - __import__("six.moves." + item_name) - except AttributeError: - if item_name == "zip_longest" and sys.version_info < (2, 6): - pytest.skip("zip_longest only available on 2.6+") - except ImportError: - if item_name == "winreg" and not sys.platform.startswith("win"): - pytest.skip("Windows only module") - if item_name.startswith("tkinter"): - if not have_tkinter: - pytest.skip("requires tkinter") - if item_name == "tkinter_ttk" and sys.version_info[:2] <= (2, 6): - pytest.skip("ttk only available on 2.7+") - if item_name.startswith("dbm_gnu") and not have_gdbm: - pytest.skip("requires gdbm") - raise - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves) - - -@pytest.mark.parametrize("item_name", - [item.name for item in six._urllib_parse_moved_attributes]) -def test_move_items_urllib_parse(item_name): - """Ensure that everything loads correctly.""" - if item_name == "ParseResult" and sys.version_info < (2, 5): - pytest.skip("ParseResult is only found on 2.5+") - if item_name in ("parse_qs", "parse_qsl") and sys.version_info < (2, 6): - pytest.skip("parse_qs[l] is new in 2.6") - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves.urllib.parse) - getattr(six.moves.urllib.parse, item_name) - - -@pytest.mark.parametrize("item_name", - [item.name for item in six._urllib_error_moved_attributes]) -def test_move_items_urllib_error(item_name): - """Ensure that everything loads correctly.""" - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves.urllib.error) - getattr(six.moves.urllib.error, item_name) - - -@pytest.mark.parametrize("item_name", - [item.name for item in six._urllib_request_moved_attributes]) -def test_move_items_urllib_request(item_name): - """Ensure that everything loads correctly.""" - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves.urllib.request) - getattr(six.moves.urllib.request, item_name) - - -@pytest.mark.parametrize("item_name", - [item.name for item in six._urllib_response_moved_attributes]) -def test_move_items_urllib_response(item_name): - """Ensure that everything loads correctly.""" - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves.urllib.response) - getattr(six.moves.urllib.response, item_name) - - -@pytest.mark.parametrize("item_name", - [item.name for item in six._urllib_robotparser_moved_attributes]) -def test_move_items_urllib_robotparser(item_name): - """Ensure that everything loads correctly.""" - if sys.version_info[:2] >= (2, 6): - assert item_name in dir(six.moves.urllib.robotparser) - getattr(six.moves.urllib.robotparser, item_name) - - -def test_import_moves_error_1(): - from six.moves.urllib.parse import urljoin - from six import moves - # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin' - assert moves.urllib.parse.urljoin - - -def test_import_moves_error_2(): - from six import moves - assert moves.urllib.parse.urljoin - # In 1.4.1: ImportError: cannot import name urljoin - from six.moves.urllib.parse import urljoin - - -def test_import_moves_error_3(): - from six.moves.urllib.parse import urljoin - # In 1.4.1: ImportError: cannot import name urljoin - from six.moves.urllib_parse import urljoin - - -def test_from_imports(): - from six.moves.queue import Queue - assert isinstance(Queue, six.class_types) - from six.moves.configparser import ConfigParser - assert isinstance(ConfigParser, six.class_types) - - -def test_filter(): - from six.moves import filter - f = filter(lambda x: x % 2, range(10)) - assert six.advance_iterator(f) == 1 - - -def test_filter_false(): - from six.moves import filterfalse - f = filterfalse(lambda x: x % 3, range(10)) - assert six.advance_iterator(f) == 0 - assert six.advance_iterator(f) == 3 - assert six.advance_iterator(f) == 6 - -def test_map(): - from six.moves import map - assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1 - - -def test_getoutput(): - from six.moves import getoutput - output = getoutput('echo "foo"') - assert output == 'foo' - - -def test_zip(): - from six.moves import zip - assert six.advance_iterator(zip(range(2), range(2))) == (0, 0) - - -@pytest.mark.skipif("sys.version_info < (2, 6)") -def test_zip_longest(): - from six.moves import zip_longest - it = zip_longest(range(2), range(1)) - - assert six.advance_iterator(it) == (0, 0) - assert six.advance_iterator(it) == (1, None) - - -class TestCustomizedMoves: - - def teardown_method(self, meth): - try: - del six._MovedItems.spam - except AttributeError: - pass - try: - del six.moves.__dict__["spam"] - except KeyError: - pass - - - def test_moved_attribute(self): - attr = six.MovedAttribute("spam", "foo", "bar") - if six.PY3: - assert attr.mod == "bar" - else: - assert attr.mod == "foo" - assert attr.attr == "spam" - attr = six.MovedAttribute("spam", "foo", "bar", "lemma") - assert attr.attr == "lemma" - attr = six.MovedAttribute("spam", "foo", "bar", "lemma", "theorm") - if six.PY3: - assert attr.attr == "theorm" - else: - assert attr.attr == "lemma" - - - def test_moved_module(self): - attr = six.MovedModule("spam", "foo") - if six.PY3: - assert attr.mod == "spam" - else: - assert attr.mod == "foo" - attr = six.MovedModule("spam", "foo", "bar") - if six.PY3: - assert attr.mod == "bar" - else: - assert attr.mod == "foo" - - - def test_custom_move_module(self): - attr = six.MovedModule("spam", "six", "six") - six.add_move(attr) - six.remove_move("spam") - assert not hasattr(six.moves, "spam") - attr = six.MovedModule("spam", "six", "six") - six.add_move(attr) - from six.moves import spam - assert spam is six - six.remove_move("spam") - assert not hasattr(six.moves, "spam") - - - def test_custom_move_attribute(self): - attr = six.MovedAttribute("spam", "six", "six", "u", "u") - six.add_move(attr) - six.remove_move("spam") - assert not hasattr(six.moves, "spam") - attr = six.MovedAttribute("spam", "six", "six", "u", "u") - six.add_move(attr) - from six.moves import spam - assert spam is six.u - six.remove_move("spam") - assert not hasattr(six.moves, "spam") - - - def test_empty_remove(self): - pytest.raises(AttributeError, six.remove_move, "eggs") - - -def test_get_unbound_function(): - class X(object): - def m(self): - pass - assert six.get_unbound_function(X.m) is X.__dict__["m"] - - -def test_get_method_self(): - class X(object): - def m(self): - pass - x = X() - assert six.get_method_self(x.m) is x - pytest.raises(AttributeError, six.get_method_self, 42) - - -def test_get_method_function(): - class X(object): - def m(self): - pass - x = X() - assert six.get_method_function(x.m) is X.__dict__["m"] - pytest.raises(AttributeError, six.get_method_function, hasattr) - - -def test_get_function_closure(): - def f(): - x = 42 - def g(): - return x - return g - cell = six.get_function_closure(f())[0] - assert type(cell).__name__ == "cell" - - -def test_get_function_code(): - def f(): - pass - assert isinstance(six.get_function_code(f), types.CodeType) - if not hasattr(sys, "pypy_version_info"): - pytest.raises(AttributeError, six.get_function_code, hasattr) - - -def test_get_function_defaults(): - def f(x, y=3, b=4): - pass - assert six.get_function_defaults(f) == (3, 4) - - -def test_get_function_globals(): - def f(): - pass - assert six.get_function_globals(f) is globals() - - -def test_dictionary_iterators(monkeypatch): - def stock_method_name(iterwhat): - """Given a method suffix like "lists" or "values", return the name - of the dict method that delivers those on the version of Python - we're running in.""" - if six.PY3: - return iterwhat - return 'iter' + iterwhat - - class MyDict(dict): - if not six.PY3: - def lists(self, **kw): - return [1, 2, 3] - def iterlists(self, **kw): - return iter([1, 2, 3]) - f = MyDict.iterlists - del MyDict.iterlists - setattr(MyDict, stock_method_name('lists'), f) - - d = MyDict(zip(range(10), reversed(range(10)))) - for name in "keys", "values", "items", "lists": - meth = getattr(six, "iter" + name) - it = meth(d) - assert not isinstance(it, list) - assert list(it) == list(getattr(d, name)()) - pytest.raises(StopIteration, six.advance_iterator, it) - record = [] - def with_kw(*args, **kw): - record.append(kw["kw"]) - return old(*args) - old = getattr(MyDict, stock_method_name(name)) - monkeypatch.setattr(MyDict, stock_method_name(name), with_kw) - meth(d, kw=42) - assert record == [42] - monkeypatch.undo() - - -@pytest.mark.skipif("sys.version_info[:2] < (2, 7)", - reason="view methods on dictionaries only available on 2.7+") -def test_dictionary_views(): - def stock_method_name(viewwhat): - """Given a method suffix like "keys" or "values", return the name - of the dict method that delivers those on the version of Python - we're running in.""" - if six.PY3: - return viewwhat - return 'view' + viewwhat - - d = dict(zip(range(10), (range(11, 20)))) - for name in "keys", "values", "items": - meth = getattr(six, "view" + name) - view = meth(d) - assert set(view) == set(getattr(d, name)()) - - -def test_advance_iterator(): - assert six.next is six.advance_iterator - l = [1, 2] - it = iter(l) - assert six.next(it) == 1 - assert six.next(it) == 2 - pytest.raises(StopIteration, six.next, it) - pytest.raises(StopIteration, six.next, it) - - -def test_iterator(): - class myiter(six.Iterator): - def __next__(self): - return 13 - assert six.advance_iterator(myiter()) == 13 - class myitersub(myiter): - def __next__(self): - return 14 - assert six.advance_iterator(myitersub()) == 14 - - -def test_callable(): - class X: - def __call__(self): - pass - def method(self): - pass - assert six.callable(X) - assert six.callable(X()) - assert six.callable(test_callable) - assert six.callable(hasattr) - assert six.callable(X.method) - assert six.callable(X().method) - assert not six.callable(4) - assert not six.callable("string") - - -def test_create_bound_method(): - class X(object): - pass - def f(self): - return self - x = X() - b = six.create_bound_method(f, x) - assert isinstance(b, types.MethodType) - assert b() is x - - -def test_create_unbound_method(): - class X(object): - pass - - def f(self): - return self - u = six.create_unbound_method(f, X) - pytest.raises(TypeError, u) - if six.PY2: - assert isinstance(u, types.MethodType) - x = X() - assert f(x) is x - - -if six.PY3: - - def test_b(): - data = six.b("\xff") - assert isinstance(data, bytes) - assert len(data) == 1 - assert data == bytes([255]) - - - def test_u(): - s = six.u("hi \u0439 \U00000439 \\ \\\\ \n") - assert isinstance(s, str) - assert s == "hi \u0439 \U00000439 \\ \\\\ \n" - -else: - - def test_b(): - data = six.b("\xff") - assert isinstance(data, str) - assert len(data) == 1 - assert data == "\xff" - - - def test_u(): - s = six.u("hi \u0439 \U00000439 \\ \\\\ \n") - assert isinstance(s, unicode) - assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8") - - -def test_u_escapes(): - s = six.u("\u1234") - assert len(s) == 1 - - -def test_unichr(): - assert six.u("\u1234") == six.unichr(0x1234) - assert type(six.u("\u1234")) is type(six.unichr(0x1234)) - - -def test_int2byte(): - assert six.int2byte(3) == six.b("\x03") - pytest.raises(Exception, six.int2byte, 256) - - -def test_byte2int(): - assert six.byte2int(six.b("\x03")) == 3 - assert six.byte2int(six.b("\x03\x04")) == 3 - pytest.raises(IndexError, six.byte2int, six.b("")) - - -def test_bytesindex(): - assert six.indexbytes(six.b("hello"), 3) == ord("l") - - -def test_bytesiter(): - it = six.iterbytes(six.b("hi")) - assert six.next(it) == ord("h") - assert six.next(it) == ord("i") - pytest.raises(StopIteration, six.next, it) - - -def test_StringIO(): - fp = six.StringIO() - fp.write(six.u("hello")) - assert fp.getvalue() == six.u("hello") - - -def test_BytesIO(): - fp = six.BytesIO() - fp.write(six.b("hello")) - assert fp.getvalue() == six.b("hello") - - -def test_exec_(): - def f(): - l = [] - six.exec_("l.append(1)") - assert l == [1] - f() - ns = {} - six.exec_("x = 42", ns) - assert ns["x"] == 42 - glob = {} - loc = {} - six.exec_("global y; y = 42; x = 12", glob, loc) - assert glob["y"] == 42 - assert "x" not in glob - assert loc["x"] == 12 - assert "y" not in loc - - -def test_reraise(): - def get_next(tb): - if six.PY3: - return tb.tb_next.tb_next - else: - return tb.tb_next - e = Exception("blah") - try: - raise e - except Exception: - tp, val, tb = sys.exc_info() - try: - six.reraise(tp, val, tb) - except Exception: - tp2, value2, tb2 = sys.exc_info() - assert tp2 is Exception - assert value2 is e - assert tb is get_next(tb2) - try: - six.reraise(tp, val) - except Exception: - tp2, value2, tb2 = sys.exc_info() - assert tp2 is Exception - assert value2 is e - assert tb2 is not tb - try: - six.reraise(tp, val, tb2) - except Exception: - tp2, value2, tb3 = sys.exc_info() - assert tp2 is Exception - assert value2 is e - assert get_next(tb3) is tb2 - try: - six.reraise(tp, None, tb) - except Exception: - tp2, value2, tb2 = sys.exc_info() - assert tp2 is Exception - assert value2 is not val - assert isinstance(value2, Exception) - assert tb is get_next(tb2) - - -def test_raise_from(): - try: - try: - raise Exception("blah") - except Exception: - ctx = sys.exc_info()[1] - f = Exception("foo") - six.raise_from(f, None) - except Exception: - tp, val, tb = sys.exc_info() - if sys.version_info[:2] > (3, 0): - # We should have done a raise f from None equivalent. - assert val.__cause__ is None - assert val.__context__ is ctx - if sys.version_info[:2] >= (3, 3): - # And that should suppress the context on the exception. - assert val.__suppress_context__ - # For all versions the outer exception should have raised successfully. - assert str(val) == "foo" - - -def test_print_(): - save = sys.stdout - out = sys.stdout = six.moves.StringIO() - try: - six.print_("Hello,", "person!") - finally: - sys.stdout = save - assert out.getvalue() == "Hello, person!\n" - out = six.StringIO() - six.print_("Hello,", "person!", file=out) - assert out.getvalue() == "Hello, person!\n" - out = six.StringIO() - six.print_("Hello,", "person!", file=out, end="") - assert out.getvalue() == "Hello, person!" - out = six.StringIO() - six.print_("Hello,", "person!", file=out, sep="X") - assert out.getvalue() == "Hello,Xperson!\n" - out = six.StringIO() - six.print_(six.u("Hello,"), six.u("person!"), file=out) - result = out.getvalue() - assert isinstance(result, six.text_type) - assert result == six.u("Hello, person!\n") - six.print_("Hello", file=None) # This works. - out = six.StringIO() - six.print_(None, file=out) - assert out.getvalue() == "None\n" - class FlushableStringIO(six.StringIO): - def __init__(self): - six.StringIO.__init__(self) - self.flushed = False - def flush(self): - self.flushed = True - out = FlushableStringIO() - six.print_("Hello", file=out) - assert not out.flushed - six.print_("Hello", file=out, flush=True) - assert out.flushed - - -@pytest.mark.skipif("sys.version_info[:2] >= (2, 6)") -def test_print_encoding(monkeypatch): - # Fool the type checking in print_. - monkeypatch.setattr(six, "file", six.BytesIO, raising=False) - out = six.BytesIO() - out.encoding = "utf-8" - out.errors = None - six.print_(six.u("\u053c"), end="", file=out) - assert out.getvalue() == six.b("\xd4\xbc") - out = six.BytesIO() - out.encoding = "ascii" - out.errors = "strict" - pytest.raises(UnicodeEncodeError, six.print_, six.u("\u053c"), file=out) - out.errors = "backslashreplace" - six.print_(six.u("\u053c"), end="", file=out) - assert out.getvalue() == six.b("\\u053c") - - -def test_print_exceptions(): - pytest.raises(TypeError, six.print_, x=3) - pytest.raises(TypeError, six.print_, end=3) - pytest.raises(TypeError, six.print_, sep=42) - - -def test_with_metaclass(): - class Meta(type): - pass - class X(six.with_metaclass(Meta)): - pass - assert type(X) is Meta - assert issubclass(X, object) - class Base(object): - pass - class X(six.with_metaclass(Meta, Base)): - pass - assert type(X) is Meta - assert issubclass(X, Base) - class Base2(object): - pass - class X(six.with_metaclass(Meta, Base, Base2)): - pass - assert type(X) is Meta - assert issubclass(X, Base) - assert issubclass(X, Base2) - assert X.__mro__ == (X, Base, Base2, object) - class X(six.with_metaclass(Meta)): - pass - class MetaSub(Meta): - pass - class Y(six.with_metaclass(MetaSub, X)): - pass - assert type(Y) is MetaSub - assert Y.__mro__ == (Y, X, object) - - -@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") -def test_with_metaclass_typing(): - try: - import typing - except ImportError: - pytest.skip("typing module required") - class Meta(type): - pass - if sys.version_info[:2] < (3, 7): - # Generics with custom metaclasses were broken on older versions. - class Meta(Meta, typing.GenericMeta): - pass - T = typing.TypeVar('T') - class G(six.with_metaclass(Meta, typing.Generic[T])): - pass - class GA(six.with_metaclass(abc.ABCMeta, typing.Generic[T])): - pass - assert isinstance(G, Meta) - assert isinstance(GA, abc.ABCMeta) - assert G[int] is not G[G[int]] - assert GA[int] is not GA[GA[int]] - assert G.__bases__ == (typing.Generic,) - assert G.__orig_bases__ == (typing.Generic[T],) - - -@pytest.mark.skipif("sys.version_info[:2] < (3, 7)") -def test_with_metaclass_pep_560(): - class Meta(type): - pass - class A: - pass - class B: - pass - class Fake: - def __mro_entries__(self, bases): - return (A, B) - fake = Fake() - class G(six.with_metaclass(Meta, fake)): - pass - class GA(six.with_metaclass(abc.ABCMeta, fake)): - pass - assert isinstance(G, Meta) - assert isinstance(GA, abc.ABCMeta) - assert G.__bases__ == (A, B) - assert G.__orig_bases__ == (fake,) - - -@pytest.mark.skipif("sys.version_info[:2] < (3, 0)") -def test_with_metaclass_prepare(): - """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments.""" - - class MyDict(dict): - pass - - class Meta(type): - - @classmethod - def __prepare__(cls, name, bases): - namespace = MyDict(super().__prepare__(name, bases), cls=cls, bases=bases) - namespace['namespace'] = namespace - return namespace - - class Base(object): - pass - - bases = (Base,) - - class X(six.with_metaclass(Meta, *bases)): - pass - - assert getattr(X, 'cls', type) is Meta - assert getattr(X, 'bases', ()) == bases - assert isinstance(getattr(X, 'namespace', {}), MyDict) - - -def test_wraps(): - def f(g): - @six.wraps(g) - def w(): - return 42 - return w - def k(): - pass - original_k = k - k = f(f(k)) - assert hasattr(k, '__wrapped__') - k = k.__wrapped__ - assert hasattr(k, '__wrapped__') - k = k.__wrapped__ - assert k is original_k - assert not hasattr(k, '__wrapped__') - - def f(g, assign, update): - def w(): - return 42 - w.glue = {"foo" : "bar"} - return six.wraps(g, assign, update)(w) - k.glue = {"melon" : "egg"} - k.turnip = 43 - k = f(k, ["turnip"], ["glue"]) - assert k.__name__ == "w" - assert k.turnip == 43 - assert k.glue == {"melon" : "egg", "foo" : "bar"} - - -def test_add_metaclass(): - class Meta(type): - pass - class X: - "success" - X = six.add_metaclass(Meta)(X) - assert type(X) is Meta - assert issubclass(X, object) - assert X.__module__ == __name__ - assert X.__doc__ == "success" - class Base(object): - pass - class X(Base): - pass - X = six.add_metaclass(Meta)(X) - assert type(X) is Meta - assert issubclass(X, Base) - class Base2(object): - pass - class X(Base, Base2): - pass - X = six.add_metaclass(Meta)(X) - assert type(X) is Meta - assert issubclass(X, Base) - assert issubclass(X, Base2) - - # Test a second-generation subclass of a type. - class Meta1(type): - m1 = "m1" - class Meta2(Meta1): - m2 = "m2" - class Base: - b = "b" - Base = six.add_metaclass(Meta1)(Base) - class X(Base): - x = "x" - X = six.add_metaclass(Meta2)(X) - assert type(X) is Meta2 - assert issubclass(X, Base) - assert type(Base) is Meta1 - assert "__dict__" not in vars(X) - instance = X() - instance.attr = "test" - assert vars(instance) == {"attr": "test"} - assert instance.b == Base.b - assert instance.x == X.x - - # Test a class with slots. - class MySlots(object): - __slots__ = ["a", "b"] - MySlots = six.add_metaclass(Meta1)(MySlots) - - assert MySlots.__slots__ == ["a", "b"] - instance = MySlots() - instance.a = "foo" - pytest.raises(AttributeError, setattr, instance, "c", "baz") - - # Test a class with string for slots. - class MyStringSlots(object): - __slots__ = "ab" - MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots) - assert MyStringSlots.__slots__ == "ab" - instance = MyStringSlots() - instance.ab = "foo" - pytest.raises(AttributeError, setattr, instance, "a", "baz") - pytest.raises(AttributeError, setattr, instance, "b", "baz") - - class MySlotsWeakref(object): - __slots__ = "__weakref__", - MySlotsWeakref = six.add_metaclass(Meta)(MySlotsWeakref) - assert type(MySlotsWeakref) is Meta - - -@pytest.mark.skipif("sys.version_info[:2] < (3, 3)") -def test_add_metaclass_nested(): - # Regression test for https://github.com/benjaminp/six/issues/259 - class Meta(type): - pass - - class A: - class B: pass - - expected = 'test_add_metaclass_nested..A.B' - - assert A.B.__qualname__ == expected - - class A: - @six.add_metaclass(Meta) - class B: pass - - assert A.B.__qualname__ == expected - - -@pytest.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))") -def test_assertCountEqual(): - class TestAssertCountEqual(unittest.TestCase): - def test(self): - with self.assertRaises(AssertionError): - six.assertCountEqual(self, (1, 2), [3, 4, 5]) - - six.assertCountEqual(self, (1, 2), [2, 1]) - - TestAssertCountEqual('test').test() - - -@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") -def test_assertRegex(): - class TestAssertRegex(unittest.TestCase): - def test(self): - with self.assertRaises(AssertionError): - six.assertRegex(self, 'test', r'^a') - - six.assertRegex(self, 'test', r'^t') - - TestAssertRegex('test').test() - - -@pytest.mark.skipif("sys.version_info[:2] < (2, 7)") -def test_assertRaisesRegex(): - class TestAssertRaisesRegex(unittest.TestCase): - def test(self): - with six.assertRaisesRegex(self, AssertionError, '^Foo'): - raise AssertionError('Foo') - - with self.assertRaises(AssertionError): - with six.assertRaisesRegex(self, AssertionError, r'^Foo'): - raise AssertionError('Bar') - - TestAssertRaisesRegex('test').test() - - -def test_python_2_unicode_compatible(): - @six.python_2_unicode_compatible - class MyTest(object): - def __str__(self): - return six.u('hello') - - def __bytes__(self): - return six.b('hello') - - my_test = MyTest() - - if six.PY2: - assert str(my_test) == six.b("hello") - assert unicode(my_test) == six.u("hello") - elif six.PY3: - assert bytes(my_test) == six.b("hello") - assert str(my_test) == six.u("hello") - - assert getattr(six.moves.builtins, 'bytes', str)(my_test) == six.b("hello") - - -class EnsureTests: - - # grinning face emoji - UNICODE_EMOJI = six.u("\U0001F600") - BINARY_EMOJI = b"\xf0\x9f\x98\x80" - - def test_ensure_binary_raise_type_error(self): - with pytest.raises(TypeError): - six.ensure_str(8) - - def test_errors_and_encoding(self): - six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='ignore') - with pytest.raises(UnicodeEncodeError): - six.ensure_binary(self.UNICODE_EMOJI, encoding='latin-1', errors='strict') - - def test_ensure_binary_raise(self): - converted_unicode = six.ensure_binary(self.UNICODE_EMOJI, encoding='utf-8', errors='strict') - converted_binary = six.ensure_binary(self.BINARY_EMOJI, encoding="utf-8", errors='strict') - if six.PY2: - # PY2: unicode -> str - assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str) - # PY2: str -> str - assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str) - else: - # PY3: str -> bytes - assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, bytes) - # PY3: bytes -> bytes - assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, bytes) - - def test_ensure_str(self): - converted_unicode = six.ensure_str(self.UNICODE_EMOJI, encoding='utf-8', errors='strict') - converted_binary = six.ensure_str(self.BINARY_EMOJI, encoding="utf-8", errors='strict') - if six.PY2: - # PY2: unicode -> str - assert converted_unicode == self.BINARY_EMOJI and isinstance(converted_unicode, str) - # PY2: str -> str - assert converted_binary == self.BINARY_EMOJI and isinstance(converted_binary, str) - else: - # PY3: str -> str - assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str) - # PY3: bytes -> str - assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str) - - def test_ensure_text(self): - converted_unicode = six.ensure_text(self.UNICODE_EMOJI, encoding='utf-8', errors='strict') - converted_binary = six.ensure_text(self.BINARY_EMOJI, encoding="utf-8", errors='strict') - if six.PY2: - # PY2: unicode -> unicode - assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode) - # PY2: str -> unicode - assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, unicode) - else: - # PY3: str -> str - assert converted_unicode == self.UNICODE_EMOJI and isinstance(converted_unicode, str) - # PY3: bytes -> str - assert converted_binary == self.UNICODE_EMOJI and isinstance(converted_unicode, str) diff --git a/third_party/python/typing_extensions/MANIFEST.in b/third_party/python/typing_extensions/MANIFEST.in deleted file mode 100644 index feda4cf1e444..000000000000 --- a/third_party/python/typing_extensions/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include LICENSE README.rst -include src_py3/typing_extensions.py -include src_py3/test_typing_extensions.py -include src_py2/typing_extensions.py -include src_py2/test_typing_extensions.py diff --git a/third_party/python/typing_extensions/README.rst b/third_party/python/typing_extensions/README.rst deleted file mode 100644 index 5256bbc1f75f..000000000000 --- a/third_party/python/typing_extensions/README.rst +++ /dev/null @@ -1,90 +0,0 @@ -================= -Typing Extensions -================= - -.. image:: https://badges.gitter.im/python/typing.svg - :alt: Chat at https://gitter.im/python/typing - :target: https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge - -Overview -======== - -The ``typing`` module was added to the standard library in Python 3.5 on -a provisional basis and will no longer be provisional in Python 3.7. However, -this means users of Python 3.5 - 3.6 who are unable to upgrade will not be -able to take advantage of new types added to the ``typing`` module, such as -``typing.Text`` or ``typing.Coroutine``. - -The ``typing_extensions`` module contains both backports of these changes -as well as experimental types that will eventually be added to the ``typing`` -module, such as ``Protocol`` (see PEP 544 for details about protocols and -static duck typing) or ``TypedDict`` (see PEP 589). - -Users of other Python versions should continue to install and use -use the ``typing`` module from PyPi instead of using this one unless -specifically writing code that must be compatible with multiple Python -versions or requires experimental types. - -Included items -============== - -This module currently contains the following: - -All Python versions: --------------------- - -- ``ClassVar`` -- ``ContextManager`` -- ``Counter`` -- ``DefaultDict`` -- ``Deque`` -- ``final`` -- ``Final`` -- ``Literal`` -- ``NewType`` -- ``NoReturn`` -- ``overload`` (note that older versions of ``typing`` only let you use ``overload`` in stubs) -- ``Protocol`` (except on Python 3.5.0) -- ``runtime`` (except on Python 3.5.0) -- ``Text`` -- ``Type`` -- ``TypedDict`` -- ``TYPE_CHECKING`` - -Python 3.4+ only: ------------------ - -- ``ChainMap`` - -Python 3.5+ only: ------------------ - -- ``AsyncIterable`` -- ``AsyncIterator`` -- ``AsyncContextManager`` -- ``Awaitable`` -- ``Coroutine`` - -Python 3.6+ only: ------------------ - -- ``AsyncGenerator`` - -Other Notes and Limitations -=========================== - -There are a few types whose interface was modified between different -versions of typing. For example, ``typing.Sequence`` was modified to -subclass ``typing.Reversible`` as of Python 3.5.3. - -These changes are _not_ backported to prevent subtle compatibility -issues when mixing the differing implementations of modified classes. - -Running tests -============= - -To run tests, navigate into the appropriate source directory and run -``test_typing_extensions.py``. You will also need to install the latest -version of ``typing`` if you are using a version of Python that does not -include ``typing`` as a part of the standard library. - diff --git a/third_party/python/typing_extensions/setup.cfg b/third_party/python/typing_extensions/setup.cfg deleted file mode 100644 index 1d34bb2cf034..000000000000 --- a/third_party/python/typing_extensions/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[metadata] -license-file = LICENSE - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/typing_extensions/setup.py b/third_party/python/typing_extensions/setup.py deleted file mode 100644 index 023ab398395d..000000000000 --- a/third_party/python/typing_extensions/setup.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -import sys -from setuptools import setup - -if sys.version_info < (2, 7, 0) or (3, 0, 0) <= sys.version_info < (3, 4, 0): - sys.stderr.write('ERROR: You need Python 2.7 or 3.4+ ' - 'to install the typing package.\n') - exit(1) - -version = '3.7.4.3' -description = 'Backported and Experimental Type Hints for Python 3.5+' -long_description = '''\ -Typing Extensions -- Backported and Experimental Type Hints for Python - -The ``typing`` module was added to the standard library in Python 3.5 on -a provisional basis and will no longer be provisional in Python 3.7. However, -this means users of Python 3.5 - 3.6 who are unable to upgrade will not be -able to take advantage of new types added to the ``typing`` module, such as -``typing.Text`` or ``typing.Coroutine``. - -The ``typing_extensions`` module contains both backports of these changes -as well as experimental types that will eventually be added to the ``typing`` -module, such as ``Protocol`` or ``TypedDict``. - -Users of other Python versions should continue to install and use -the ``typing`` module from PyPi instead of using this one unless specifically -writing code that must be compatible with multiple Python versions or requires -experimental types. -''' - -classifiers = [ - 'Development Status :: 3 - Alpha', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Python Software Foundation License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Topic :: Software Development', -] - -if sys.version_info.major == 2: - package_dir = 'src_py2' -elif sys.version_info.major == 3: - package_dir = 'src_py3' -else: - raise AssertionError() - -setup(name='typing_extensions', - version=version, - description=description, - long_description=long_description, - author='Guido van Rossum, Jukka Lehtosalo, Lukasz Langa, Michael Lee', - author_email='levkivskyi@gmail.com', - url='https://github.com/python/typing/blob/master/typing_extensions/README.rst', - license='PSF', - keywords='typing function annotations type hints hinting checking ' - 'checker typehints typehinting typechecking backport', - package_dir={'': package_dir}, - py_modules=['typing_extensions'], - classifiers=classifiers, - install_requires=["typing >= 3.7.4; python_version < '3.5'"]) diff --git a/third_party/python/typing_extensions/src_py2/test_typing_extensions.py b/third_party/python/typing_extensions/src_py2/test_typing_extensions.py deleted file mode 100644 index 5c21a6df8966..000000000000 --- a/third_party/python/typing_extensions/src_py2/test_typing_extensions.py +++ /dev/null @@ -1,456 +0,0 @@ -import sys -import os -import contextlib -import collections -import subprocess -from unittest import TestCase, main - -from typing_extensions import Annotated, NoReturn, ClassVar, IntVar -from typing_extensions import ContextManager, Counter, Deque, DefaultDict -from typing_extensions import NewType, TypeAlias, overload -from typing import Dict, List -import typing -import typing_extensions - - -T = typing.TypeVar('T') -KT = typing.TypeVar('KT') -VT = typing.TypeVar('VT') - - -class BaseTestCase(TestCase): - - def assertIsSubclass(self, cls, class_or_tuple, msg=None): - if not issubclass(cls, class_or_tuple): - message = '%r is not a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): - if issubclass(cls, class_or_tuple): - message = '%r is a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - -class Employee(object): - pass - - -class NoReturnTests(BaseTestCase): - - def test_noreturn_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, NoReturn) - - def test_noreturn_subclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(Employee, NoReturn) - with self.assertRaises(TypeError): - issubclass(NoReturn, Employee) - - def test_repr(self): - if hasattr(typing, 'NoReturn'): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - else: - self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn') - - def test_not_generic(self): - with self.assertRaises(TypeError): - NoReturn[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(NoReturn): - pass - with self.assertRaises(TypeError): - class A(type(NoReturn)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - NoReturn() - with self.assertRaises(TypeError): - type(NoReturn)() - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - self.assertEqual(repr(ClassVar), 'typing.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), 'typing.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), 'typing.ClassVar[%s.Employee]' % __name__) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(ClassVar)): - pass - with self.assertRaises(TypeError): - class C(type(ClassVar[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - ClassVar() - with self.assertRaises(TypeError): - type(ClassVar)() - with self.assertRaises(TypeError): - type(ClassVar[typing.Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, ClassVar[int]) - with self.assertRaises(TypeError): - issubclass(int, ClassVar) - - -class IntVarTests(BaseTestCase): - def test_valid(self): - T_ints = IntVar("T_ints") # noqa - - def test_invalid(self): - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", bound=int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", covariant=True) # noqa - - -class CollectionsAbcTests(BaseTestCase): - - def test_isinstance_collections(self): - self.assertNotIsInstance(1, collections.Mapping) - self.assertNotIsInstance(1, collections.Iterable) - self.assertNotIsInstance(1, collections.Container) - self.assertNotIsInstance(1, collections.Sized) - with self.assertRaises(TypeError): - isinstance(collections.deque(), typing_extensions.Deque[int]) - with self.assertRaises(TypeError): - issubclass(collections.Counter, typing_extensions.Counter[str]) - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, ContextManager) - self.assertNotIsInstance(42, ContextManager) - - with self.assertRaises(TypeError): - isinstance(42, ContextManager[int]) - with self.assertRaises(TypeError): - isinstance(cm, ContextManager[int]) - with self.assertRaises(TypeError): - issubclass(type(cm), ContextManager[int]) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, Counter) - self.assertIs(type(Counter()), collections.Counter) - self.assertIs(type(Counter[T]()), collections.Counter) - self.assertIs(type(Counter[int]()), collections.Counter) - - class A(Counter[int]): pass - class B(Counter[T]): pass - - self.assertIsInstance(A(), collections.Counter) - self.assertIs(type(B[int]()), B) - self.assertEqual(B.__bases__, (typing_extensions.Counter,)) - - def test_deque(self): - self.assertIsSubclass(collections.deque, Deque) - self.assertIs(type(Deque()), collections.deque) - self.assertIs(type(Deque[T]()), collections.deque) - self.assertIs(type(Deque[int]()), collections.deque) - - class A(Deque[int]): pass - class B(Deque[T]): pass - - self.assertIsInstance(A(), collections.deque) - self.assertIs(type(B[int]()), B) - - def test_defaultdict_instantiation(self): - self.assertIsSubclass(collections.defaultdict, DefaultDict) - self.assertIs(type(DefaultDict()), collections.defaultdict) - self.assertIs(type(DefaultDict[KT, VT]()), collections.defaultdict) - self.assertIs(type(DefaultDict[str, int]()), collections.defaultdict) - - class A(DefaultDict[str, int]): pass - class B(DefaultDict[KT, VT]): pass - - self.assertIsInstance(A(), collections.defaultdict) - self.assertIs(type(B[str, int]()), B) - - -class NewTypeTests(BaseTestCase): - - def test_basic(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - self.assertIsInstance(UserId(5), int) - self.assertIsInstance(UserName('Joe'), type('Joe')) - self.assertEqual(UserId(5) + 1, 6) - - def test_errors(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - with self.assertRaises(TypeError): - issubclass(UserId, int) - with self.assertRaises(TypeError): - class D(UserName): - pass - - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - with self.assertRaises(RuntimeError): - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - -class AnnotatedTests(BaseTestCase): - - def test_repr(self): - self.assertEqual( - repr(Annotated[int, 4, 5]), - "typing_extensions.Annotated[int, 4, 5]" - ) - self.assertEqual( - repr(Annotated[List[int], 4, 5]), - "typing_extensions.Annotated[typing.List[int], 4, 5]" - ) - self.assertEqual(repr(Annotated), "typing_extensions.Annotated") - - def test_flatten(self): - A = Annotated[Annotated[int, 4], 5] - self.assertEqual(A, Annotated[int, 4, 5]) - self.assertEqual(A.__metadata__, (4, 5)) - - def test_specialize(self): - L = Annotated[List[T], "my decoration"] - LI = Annotated[List[int], "my decoration"] - self.assertEqual(L[int], Annotated[List[int], "my decoration"]) - self.assertEqual(L[int].__metadata__, ("my decoration",)) - with self.assertRaises(TypeError): - LI[int] - with self.assertRaises(TypeError): - L[int, float] - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_instantiate(self): - class C: - classvar = 4 - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - if not isinstance(other, C): - return NotImplemented - return other.x == self.x - - A = Annotated[C, "a decoration"] - a = A(5) - c = C(5) - self.assertEqual(a, c) - self.assertEqual(a.x, c.x) - self.assertEqual(a.classvar, c.classvar) - - def test_instantiate_generic(self): - MyCount = Annotated[typing_extensions.Counter[T], "my decoration"] - self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) - self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) - - def test_cannot_instantiate_forward(self): - A = Annotated["int", (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_instantiate_type_var(self): - A = Annotated[T, (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_getattr_typevar(self): - with self.assertRaises(AttributeError): - Annotated[T, (5, 7)].x - - def test_attr_passthrough(self): - class C: - classvar = 4 - - A = Annotated[C, "a decoration"] - self.assertEqual(A.classvar, 4) - A.x = 5 - self.assertEqual(C.x, 5) - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(Annotated): - pass - - def test_cannot_check_instance(self): - with self.assertRaises(TypeError): - isinstance(5, Annotated[int, "positive"]) - - def test_cannot_check_subclass(self): - with self.assertRaises(TypeError): - issubclass(int, Annotated[int, "positive"]) - - def test_subst(self): - dec = "a decoration" - dec2 = "another decoration" - - S = Annotated[T, dec2] - self.assertEqual(S[int], Annotated[int, dec2]) - - self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2]) - L = Annotated[List[T], dec] - - self.assertEqual(L[int], Annotated[List[int], dec]) - with self.assertRaises(TypeError): - L[int, int] - - self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2]) - - D = Annotated[Dict[KT, VT], dec] - self.assertEqual(D[str, int], Annotated[Dict[str, int], dec]) - with self.assertRaises(TypeError): - D[int] - - It = Annotated[int, dec] - with self.assertRaises(TypeError): - It[None] - - LI = L[int] - with self.assertRaises(TypeError): - LI[None] - - def test_annotated_in_other_types(self): - X = List[Annotated[T, 5]] - self.assertEqual(X[int], List[Annotated[int, 5]]) - - -class TypeAliasTests(BaseTestCase): - def test_canonical_usage(self): - Alias = Employee # type: TypeAlias - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - TypeAlias() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(42, TypeAlias) - - def test_no_issubclass(self): - with self.assertRaises(TypeError): - issubclass(Employee, TypeAlias) - - with self.assertRaises(TypeError): - issubclass(TypeAlias, Employee) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(TypeAlias): - pass - - with self.assertRaises(TypeError): - class C(type(TypeAlias)): - pass - - def test_repr(self): - if hasattr(typing, 'TypeAlias'): - self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') - self.assertEqual(repr(type(TypeAlias)), 'typing.TypeAlias') - else: - self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias') - self.assertEqual(repr(type(TypeAlias)), 'typing_extensions.TypeAlias') - - def test_cannot_subscript(self): - with self.assertRaises(TypeError): - TypeAlias[int] - - -class AllTests(BaseTestCase): - - def test_typing_extensions_includes_standard(self): - a = typing_extensions.__all__ - self.assertIn('ClassVar', a) - self.assertIn('Type', a) - self.assertIn('Counter', a) - self.assertIn('DefaultDict', a) - self.assertIn('Deque', a) - self.assertIn('NewType', a) - self.assertIn('overload', a) - self.assertIn('Text', a) - self.assertIn('TYPE_CHECKING', a) - - def test_typing_extensions_defers_when_possible(self): - exclude = {'overload', 'Text', 'TYPE_CHECKING', 'Final'} - for item in typing_extensions.__all__: - if item not in exclude and hasattr(typing, item): - self.assertIs( - getattr(typing_extensions, item), - getattr(typing, item)) - - def test_typing_extensions_compiles_with_opt(self): - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'typing_extensions.py') - try: - subprocess.check_output('{} -OO {}'.format(sys.executable, - file_path), - stderr=subprocess.STDOUT, - shell=True) - except subprocess.CalledProcessError: - self.fail('Module does not compile with optimize=2 (-OO flag).') - - -if __name__ == '__main__': - main() diff --git a/third_party/python/typing_extensions/src_py2/typing_extensions.py b/third_party/python/typing_extensions/src_py2/typing_extensions.py deleted file mode 100644 index 62d1e46c7217..000000000000 --- a/third_party/python/typing_extensions/src_py2/typing_extensions.py +++ /dev/null @@ -1,283 +0,0 @@ -import abc -import typing -from typing import ( # noqa - # These are imported for re-export. - ClassVar, Type, Generic, Callable, GenericMeta, TypingMeta, - Counter, DefaultDict, Deque, TypeVar, Tuple, Final, final, - NewType, overload, Text, TYPE_CHECKING, Literal, TypedDict, Protocol, - SupportsIndex, - runtime_checkable, - # We use internal typing helpers here, but this significantly reduces - # code duplication. (Also this is only until Protocol is in typing.) - _type_vars, _tp_cache, _type_check, -) - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'ClassVar', - 'Final', - 'Protocol', - 'Type', - 'TypedDict', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - - # Structural checks, a.k.a. protocols. - 'SupportsIndex', - - # One-off things. - 'final', - 'IntVar', - 'Literal', - 'NewType', - 'overload', - 'runtime_checkable', - 'Text', - 'TYPE_CHECKING', -] - - -if hasattr(typing, 'NoReturn'): - NoReturn = typing.NoReturn -else: - # TODO: Remove once typing.py has been updated - class _NoReturnMeta(typing.TypingMeta): - """Metaclass for NoReturn.""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(_NoReturnMeta, cls).__new__(cls, name, bases, namespace) - return self - - class _NoReturn(typing._FinalTypingBase): - """Special type indicating functions that never return. - Example:: - from typing import NoReturn - def stop() -> NoReturn: - raise Exception('no way') - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __metaclass__ = _NoReturnMeta - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - NoReturn = _NoReturn(_root=True) - - -T_co = typing.TypeVar('T_co', covariant=True) - -if hasattr(typing, 'ContextManager'): - ContextManager = typing.ContextManager -else: - # TODO: Remove once typing.py has been updated - class ContextManager(typing.Generic[T_co]): - __slots__ = () - - def __enter__(self): - return self - - @abc.abstractmethod - def __exit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is ContextManager: - # In Python 3.6+, it is possible to set a method to None to - # explicitly indicate that the class does not implement an ABC - # (https://bugs.python.org/issue25958), but we do not support - # that pattern here because this fallback class is only used - # in Python 3.5 and earlier. - if (any("__enter__" in B.__dict__ for B in C.__mro__) and - any("__exit__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented - - -def IntVar(name): - return TypeVar(name) - - -def _is_dunder(name): - """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') - - -class AnnotatedMeta(GenericMeta): - """Metaclass for Annotated""" - - def __new__(cls, name, bases, namespace, **kwargs): - if any(b is not object for b in bases): - raise TypeError("Cannot subclass %s" % Annotated) - return super(AnnotatedMeta, cls).__new__(cls, name, bases, namespace, **kwargs) - - @property - def __metadata__(self): - return self._subs_tree()[2] - - def _tree_repr(self, tree): - cls, origin, metadata = tree - if not isinstance(origin, tuple): - tp_repr = typing._type_repr(origin) - else: - tp_repr = origin[0]._tree_repr(origin) - metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs) - - def _subs_tree(self, tvars=None, args=None): - if self is Annotated: - return Annotated - res = super(AnnotatedMeta, self)._subs_tree(tvars=tvars, args=args) - # Flatten nested Annotated - if isinstance(res[1], tuple) and res[1][0] is Annotated: - sub_tp = res[1][1] - sub_annot = res[1][2] - return (Annotated, sub_tp, sub_annot + res[2]) - return res - - def _get_cons(self): - """Return the class used to create instance of this type.""" - if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a non-specialized " - "Annotated type.") - tree = self._subs_tree() - while isinstance(tree, tuple) and tree[0] is Annotated: - tree = tree[1] - if isinstance(tree, tuple): - return tree[0] - else: - return tree - - @_tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if self.__origin__ is not None: # specializing an instantiated type - return super(AnnotatedMeta, self).__getitem__(params) - elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated with at " - "least two arguments (a type and an annotation).") - else: - msg = "Annotated[t, ...]: t must be a type." - tp = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return self.__class__( - self.__name__, - self.__bases__, - dict(self.__dict__), - tvars=_type_vars((tp,)), - # Metadata is a tuple so it won't be touched by _replace_args et al. - args=(tp, metadata), - origin=self, - ) - - def __call__(self, *args, **kwargs): - cons = self._get_cons() - result = cons(*args, **kwargs) - try: - result.__orig_class__ = self - except AttributeError: - pass - return result - - def __getattr__(self, attr): - # For simplicity we just don't relay all dunder names - if self.__origin__ is not None and not _is_dunder(attr): - return getattr(self._get_cons(), attr) - raise AttributeError(attr) - - def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): - super(AnnotatedMeta, self).__setattr__(attr, value) - elif self.__origin__ is None: - raise AttributeError(attr) - else: - setattr(self._get_cons(), attr, value) - - -class Annotated(object): - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type, the remaining - arguments are kept as a tuple in the __metadata__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[int, Ann1, Ann2], Ann3] == Annotated[int, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - __metaclass__ = AnnotatedMeta - __slots__ = () - - -class _TypeAliasMeta(typing.TypingMeta): - """Metaclass for TypeAlias""" - - def __new__(cls, name, bases, namespace): - cls.assert_no_subclassing(bases) - self = super(_TypeAliasMeta, cls).__new__(cls, name, bases, namespace) - return self - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - -class _TypeAliasBase(typing._FinalTypingBase): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate = Callable[..., bool] # type: TypeAlias - - It's invalid when used anywhere except as in the example above. - """ - __metaclass__ = _TypeAliasMeta - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - -TypeAlias = _TypeAliasBase(_root=True) - -# This alias exists for backwards compatibility. -runtime = runtime_checkable diff --git a/third_party/python/typing_extensions/src_py3/test_typing_extensions.py b/third_party/python/typing_extensions/src_py3/test_typing_extensions.py deleted file mode 100644 index 02223038a679..000000000000 --- a/third_party/python/typing_extensions/src_py3/test_typing_extensions.py +++ /dev/null @@ -1,1940 +0,0 @@ -import sys -import os -import abc -import contextlib -import collections -import pickle -import subprocess -import types -from unittest import TestCase, main, skipUnless, skipIf -from typing import TypeVar, Optional -from typing import T, KT, VT # Not in __all__. -from typing import Tuple, List, Dict, Iterator -from typing import Generic -from typing import no_type_check -from typing_extensions import NoReturn, ClassVar, Final, IntVar, Literal, Type, NewType, TypedDict -from typing_extensions import TypeAlias -try: - from typing_extensions import Protocol, runtime, runtime_checkable -except ImportError: - pass -try: - from typing_extensions import Annotated -except ImportError: - pass -try: - from typing_extensions import get_type_hints -except ImportError: - from typing import get_type_hints - -import typing -import typing_extensions -import collections.abc as collections_abc - -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -OLD_GENERICS = False -try: - from typing import _type_vars, _next_in_mro, _type_check # noqa -except ImportError: - OLD_GENERICS = True - -# We assume Python versions *below* 3.5.0 will have the most -# up-to-date version of the typing module installed. Since -# the typing module isn't a part of the standard library in older -# versions of Python, those users are likely to have a reasonably -# modern version of `typing` installed from PyPi. -TYPING_LATEST = sys.version_info[:3] < (3, 5, 0) - -# Flags used to mark tests that only apply after a specific -# version of the typing module. -TYPING_3_5_1 = TYPING_LATEST or sys.version_info[:3] >= (3, 5, 1) -TYPING_3_5_3 = TYPING_LATEST or sys.version_info[:3] >= (3, 5, 3) -TYPING_3_6_1 = TYPING_LATEST or sys.version_info[:3] >= (3, 6, 1) - -# For typing versions where issubclass(...) and -# isinstance(...) checks are forbidden. -# -# See https://github.com/python/typing/issues/136 -# and https://github.com/python/typing/pull/283 -SUBCLASS_CHECK_FORBIDDEN = TYPING_3_5_3 - -# For typing versions where instantiating collection -# types are allowed. -# -# See https://github.com/python/typing/issues/367 -CAN_INSTANTIATE_COLLECTIONS = TYPING_3_6_1 - -# For Python versions supporting async/await and friends. -ASYNCIO = sys.version_info[:2] >= (3, 5) - -# For checks reliant on Python 3.6 syntax changes (e.g. classvar) -PY36 = sys.version_info[:2] >= (3, 6) - -# Protocols are hard to backport to the original version of typing 3.5.0 -HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0) - - -class BaseTestCase(TestCase): - def assertIsSubclass(self, cls, class_or_tuple, msg=None): - if not issubclass(cls, class_or_tuple): - message = '%r is not a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): - if issubclass(cls, class_or_tuple): - message = '%r is a subclass of %r' % (cls, class_or_tuple) - if msg is not None: - message += ' : %s' % msg - raise self.failureException(message) - - -class Employee: - pass - - -class NoReturnTests(BaseTestCase): - - def test_noreturn_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, NoReturn) - - def test_noreturn_subclass_type_error_1(self): - with self.assertRaises(TypeError): - issubclass(Employee, NoReturn) - - @skipUnless(SUBCLASS_CHECK_FORBIDDEN, "Behavior added in typing 3.5.3") - def test_noreturn_subclass_type_error_2(self): - with self.assertRaises(TypeError): - issubclass(NoReturn, Employee) - - def test_repr(self): - if hasattr(typing, 'NoReturn'): - self.assertEqual(repr(NoReturn), 'typing.NoReturn') - else: - self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn') - - def test_not_generic(self): - with self.assertRaises(TypeError): - NoReturn[int] - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class A(NoReturn): - pass - if SUBCLASS_CHECK_FORBIDDEN: - with self.assertRaises(TypeError): - class A(type(NoReturn)): - pass - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - NoReturn() - with self.assertRaises(TypeError): - type(NoReturn)() - - -class ClassVarTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - ClassVar[1] - with self.assertRaises(TypeError): - ClassVar[int, str] - with self.assertRaises(TypeError): - ClassVar[int][str] - - def test_repr(self): - if hasattr(typing, 'ClassVar'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(ClassVar), mod_name + '.ClassVar') - cv = ClassVar[int] - self.assertEqual(repr(cv), mod_name + '.ClassVar[int]') - cv = ClassVar[Employee] - self.assertEqual(repr(cv), mod_name + '.ClassVar[%s.Employee]' % __name__) - - @skipUnless(SUBCLASS_CHECK_FORBIDDEN, "Behavior added in typing 3.5.3") - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(ClassVar)): - pass - with self.assertRaises(TypeError): - class C(type(ClassVar[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - ClassVar() - with self.assertRaises(TypeError): - type(ClassVar)() - with self.assertRaises(TypeError): - type(ClassVar[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, ClassVar[int]) - with self.assertRaises(TypeError): - issubclass(int, ClassVar) - - -class FinalTests(BaseTestCase): - - def test_basics(self): - with self.assertRaises(TypeError): - Final[1] - with self.assertRaises(TypeError): - Final[int, str] - with self.assertRaises(TypeError): - Final[int][str] - - def test_repr(self): - if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Final), mod_name + '.Final') - cv = Final[int] - self.assertEqual(repr(cv), mod_name + '.Final[int]') - cv = Final[Employee] - self.assertEqual(repr(cv), mod_name + '.Final[%s.Employee]' % __name__) - - @skipUnless(SUBCLASS_CHECK_FORBIDDEN, "Behavior added in typing 3.5.3") - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(type(Final)): - pass - with self.assertRaises(TypeError): - class C(type(Final[int])): - pass - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Final() - with self.assertRaises(TypeError): - type(Final)() - with self.assertRaises(TypeError): - type(Final[Optional[int]])() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(1, Final[int]) - with self.assertRaises(TypeError): - issubclass(int, Final) - - -class IntVarTests(BaseTestCase): - def test_valid(self): - T_ints = IntVar("T_ints") # noqa - - def test_invalid(self): - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", bound=int) - with self.assertRaises(TypeError): - T_ints = IntVar("T_ints", covariant=True) # noqa - - -class LiteralTests(BaseTestCase): - def test_basics(self): - Literal[1] - Literal[1, 2, 3] - Literal["x", "y", "z"] - Literal[None] - - def test_illegal_parameters_do_not_raise_runtime_errors(self): - # Type checkers should reject these types, but we do not - # raise errors at runtime to maintain maximum flexibility - Literal[int] - Literal[Literal[1, 2], Literal[4, 5]] - Literal[3j + 2, ..., ()] - Literal[b"foo", u"bar"] - Literal[{"foo": 3, "bar": 4}] - Literal[T] - - def test_literals_inside_other_types(self): - List[Literal[1, 2, 3]] - List[Literal[("foo", "bar", "baz")]] - - def test_repr(self): - if hasattr(typing, 'Literal'): - mod_name = 'typing' - else: - mod_name = 'typing_extensions' - self.assertEqual(repr(Literal[1]), mod_name + ".Literal[1]") - self.assertEqual(repr(Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']") - self.assertEqual(repr(Literal[int]), mod_name + ".Literal[int]") - self.assertEqual(repr(Literal), mod_name + ".Literal") - self.assertEqual(repr(Literal[None]), mod_name + ".Literal[None]") - - def test_cannot_init(self): - with self.assertRaises(TypeError): - Literal() - with self.assertRaises(TypeError): - Literal[1]() - with self.assertRaises(TypeError): - type(Literal)() - with self.assertRaises(TypeError): - type(Literal[1])() - - def test_no_isinstance_or_issubclass(self): - with self.assertRaises(TypeError): - isinstance(1, Literal[1]) - with self.assertRaises(TypeError): - isinstance(int, Literal[1]) - with self.assertRaises(TypeError): - issubclass(1, Literal[1]) - with self.assertRaises(TypeError): - issubclass(int, Literal[1]) - - def test_no_subclassing(self): - with self.assertRaises(TypeError): - class Foo(Literal[1]): pass - with self.assertRaises(TypeError): - class Bar(Literal): pass - - def test_no_multiple_subscripts(self): - with self.assertRaises(TypeError): - Literal[1][1] - - -class OverloadTests(BaseTestCase): - - def test_overload_fails(self): - from typing_extensions import overload - - with self.assertRaises(RuntimeError): - - @overload - def blah(): - pass - - blah() - - def test_overload_succeeds(self): - from typing_extensions import overload - - @overload - def blah(): - pass - - def blah(): - pass - - blah() - - -ASYNCIO_TESTS = """ -from typing import Iterable -from typing_extensions import Awaitable, AsyncIterator - -T_a = TypeVar('T_a') - -class AwaitableWrapper(Awaitable[T_a]): - - def __init__(self, value): - self.value = value - - def __await__(self) -> typing.Iterator[T_a]: - yield - return self.value - -class AsyncIteratorWrapper(AsyncIterator[T_a]): - - def __init__(self, value: Iterable[T_a]): - self.value = value - - def __aiter__(self) -> AsyncIterator[T_a]: - return self - - async def __anext__(self) -> T_a: - data = await self.value - if data: - return data - else: - raise StopAsyncIteration - -class ACM: - async def __aenter__(self) -> int: - return 42 - async def __aexit__(self, etype, eval, tb): - return None -""" - -if ASYNCIO: - try: - exec(ASYNCIO_TESTS) - except ImportError: - ASYNCIO = False -else: - # fake names for the sake of static analysis - asyncio = None - AwaitableWrapper = AsyncIteratorWrapper = ACM = object - -PY36_TESTS = """ -from test import ann_module, ann_module2, ann_module3 -from typing_extensions import AsyncContextManager -from typing import NamedTuple - -class A: - y: float -class B(A): - x: ClassVar[Optional['B']] = None - y: int - b: int -class CSub(B): - z: ClassVar['CSub'] = B() -class G(Generic[T]): - lst: ClassVar[List[T]] = [] - -class Loop: - attr: Final['Loop'] - -class NoneAndForward: - parent: 'NoneAndForward' - meaning: None - -class XRepr(NamedTuple): - x: int - y: int = 1 - def __str__(self): - return f'{self.x} -> {self.y}' - def __add__(self, other): - return 0 - -@runtime -class HasCallProtocol(Protocol): - __call__: typing.Callable - - -async def g_with(am: AsyncContextManager[int]): - x: int - async with am as x: - return x - -try: - g_with(ACM()).send(None) -except StopIteration as e: - assert e.args[0] == 42 - -Label = TypedDict('Label', [('label', str)]) - -class Point2D(TypedDict): - x: int - y: int - -class Point2Dor3D(Point2D, total=False): - z: int - -class LabelPoint2D(Point2D, Label): ... - -class Options(TypedDict, total=False): - log_level: int - log_path: str - -class BaseAnimal(TypedDict): - name: str - -class Animal(BaseAnimal, total=False): - voice: str - tail: bool - -class Cat(Animal): - fur_color: str -""" - -if PY36: - exec(PY36_TESTS) -else: - # fake names for the sake of static analysis - ann_module = ann_module2 = ann_module3 = None - A = B = CSub = G = CoolEmployee = CoolEmployeeWithDefault = object - XMeth = XRepr = HasCallProtocol = NoneAndForward = Loop = object - Point2D = Point2Dor3D = LabelPoint2D = Options = object - BaseAnimal = Animal = Cat = object - -gth = get_type_hints - - -class GetTypeHintTests(BaseTestCase): - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_modules(self): - ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} - self.assertEqual(gth(ann_module), ann_module_type_hints) - self.assertEqual(gth(ann_module2), {}) - self.assertEqual(gth(ann_module3), {}) - - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_classes(self): - self.assertEqual(gth(ann_module.C, ann_module.__dict__), - {'y': Optional[ann_module.C]}) - self.assertIsInstance(gth(ann_module.j_class), dict) - self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) - self.assertEqual(gth(ann_module.D), - {'j': str, 'k': str, 'y': Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.Y), {'z': int}) - self.assertEqual(gth(ann_module.h_class), - {'y': Optional[ann_module.C]}) - self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) - self.assertEqual(gth(ann_module.foo), {'x': int}) - self.assertEqual(gth(NoneAndForward, globals()), - {'parent': NoneAndForward, 'meaning': type(None)}) - - @skipUnless(PY36, 'Python 3.6 required') - def test_respect_no_type_check(self): - @no_type_check - class NoTpCheck: - class Inn: - def __init__(self, x: 'not a type'): ... # noqa - self.assertTrue(NoTpCheck.__no_type_check__) - self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) - self.assertEqual(gth(ann_module2.NTC.meth), {}) - class ABase(Generic[T]): - def meth(x: int): ... - @no_type_check - class Der(ABase): ... - self.assertEqual(gth(ABase.meth), {'x': int}) - - @skipUnless(PY36, 'Python 3.6 required') - def test_get_type_hints_ClassVar(self): - self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__), - {'var': ClassVar[ann_module2.CV]}) - self.assertEqual(gth(B, globals()), - {'y': int, 'x': ClassVar[Optional[B]], 'b': int}) - self.assertEqual(gth(CSub, globals()), - {'z': ClassVar[CSub], 'y': int, 'b': int, - 'x': ClassVar[Optional[B]]}) - self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) - - @skipUnless(PY36, 'Python 3.6 required') - def test_final_forward_ref(self): - self.assertEqual(gth(Loop, globals())['attr'], Final[Loop]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final[int]) - self.assertNotEqual(gth(Loop, globals())['attr'], Final) - - -class CollectionsAbcTests(BaseTestCase): - - def test_isinstance_collections(self): - self.assertNotIsInstance(1, collections_abc.Mapping) - self.assertNotIsInstance(1, collections_abc.Iterable) - self.assertNotIsInstance(1, collections_abc.Container) - self.assertNotIsInstance(1, collections_abc.Sized) - if SUBCLASS_CHECK_FORBIDDEN: - with self.assertRaises(TypeError): - isinstance(collections.deque(), typing_extensions.Deque[int]) - with self.assertRaises(TypeError): - issubclass(collections.Counter, typing_extensions.Counter[str]) - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_awaitable(self): - ns = {} - exec( - "async def foo() -> typing_extensions.Awaitable[int]:\n" - " return await AwaitableWrapper(42)\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Awaitable) - self.assertNotIsInstance(foo, typing_extensions.Awaitable) - g.send(None) # Run foo() till completion, to avoid warning. - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_coroutine(self): - ns = {} - exec( - "async def foo():\n" - " return\n", - globals(), ns) - foo = ns['foo'] - g = foo() - self.assertIsInstance(g, typing_extensions.Coroutine) - with self.assertRaises(TypeError): - isinstance(g, typing_extensions.Coroutine[int]) - self.assertNotIsInstance(foo, typing_extensions.Coroutine) - try: - g.send(None) - except StopIteration: - pass - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_async_iterable(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertIsInstance(it, typing_extensions.AsyncIterable) - self.assertNotIsInstance(42, typing_extensions.AsyncIterable) - - @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') - def test_async_iterator(self): - base_it = range(10) # type: Iterator[int] - it = AsyncIteratorWrapper(base_it) - if TYPING_3_5_1: - self.assertIsInstance(it, typing_extensions.AsyncIterator) - self.assertNotIsInstance(42, typing_extensions.AsyncIterator) - - def test_deque(self): - self.assertIsSubclass(collections.deque, typing_extensions.Deque) - class MyDeque(typing_extensions.Deque[int]): ... - self.assertIsInstance(MyDeque(), collections.deque) - - def test_counter(self): - self.assertIsSubclass(collections.Counter, typing_extensions.Counter) - - @skipUnless(CAN_INSTANTIATE_COLLECTIONS, "Behavior added in typing 3.6.1") - def test_defaultdict_instantiation(self): - self.assertIs( - type(typing_extensions.DefaultDict()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[KT, VT]()), - collections.defaultdict) - self.assertIs( - type(typing_extensions.DefaultDict[str, int]()), - collections.defaultdict) - - def test_defaultdict_subclass(self): - - class MyDefDict(typing_extensions.DefaultDict[str, int]): - pass - - dd = MyDefDict() - self.assertIsInstance(dd, MyDefDict) - - self.assertIsSubclass(MyDefDict, collections.defaultdict) - if TYPING_3_5_3: - self.assertNotIsSubclass(collections.defaultdict, MyDefDict) - - def test_chainmap_instantiation(self): - self.assertIs(type(typing_extensions.ChainMap()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[KT, VT]()), collections.ChainMap) - self.assertIs(type(typing_extensions.ChainMap[str, int]()), collections.ChainMap) - class CM(typing_extensions.ChainMap[KT, VT]): ... - if TYPING_3_5_3: - self.assertIs(type(CM[int, str]()), CM) - - def test_chainmap_subclass(self): - - class MyChainMap(typing_extensions.ChainMap[str, int]): - pass - - cm = MyChainMap() - self.assertIsInstance(cm, MyChainMap) - - self.assertIsSubclass(MyChainMap, collections.ChainMap) - if TYPING_3_5_3: - self.assertNotIsSubclass(collections.ChainMap, MyChainMap) - - def test_deque_instantiation(self): - self.assertIs(type(typing_extensions.Deque()), collections.deque) - self.assertIs(type(typing_extensions.Deque[T]()), collections.deque) - self.assertIs(type(typing_extensions.Deque[int]()), collections.deque) - class D(typing_extensions.Deque[T]): ... - if TYPING_3_5_3: - self.assertIs(type(D[int]()), D) - - def test_counter_instantiation(self): - self.assertIs(type(typing_extensions.Counter()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[T]()), collections.Counter) - self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter) - class C(typing_extensions.Counter[T]): ... - if TYPING_3_5_3: - self.assertIs(type(C[int]()), C) - if not PEP_560: - self.assertEqual(C.__bases__, (typing_extensions.Counter,)) - else: - self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) - - def test_counter_subclass_instantiation(self): - - class MyCounter(typing_extensions.Counter[int]): - pass - - d = MyCounter() - self.assertIsInstance(d, MyCounter) - self.assertIsInstance(d, collections.Counter) - if TYPING_3_5_1: - self.assertIsInstance(d, typing_extensions.Counter) - - @skipUnless(PY36, 'Python 3.6 required') - def test_async_generator(self): - ns = {} - exec("async def f():\n" - " yield 42\n", globals(), ns) - g = ns['f']() - self.assertIsSubclass(type(g), typing_extensions.AsyncGenerator) - - @skipUnless(PY36, 'Python 3.6 required') - def test_no_async_generator_instantiation(self): - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[T, T]() - with self.assertRaises(TypeError): - typing_extensions.AsyncGenerator[int, int]() - - @skipUnless(PY36, 'Python 3.6 required') - def test_subclassing_async_generator(self): - class G(typing_extensions.AsyncGenerator[int, int]): - def asend(self, value): - pass - def athrow(self, typ, val=None, tb=None): - pass - - ns = {} - exec('async def g(): yield 0', globals(), ns) - g = ns['g'] - self.assertIsSubclass(G, typing_extensions.AsyncGenerator) - self.assertIsSubclass(G, typing_extensions.AsyncIterable) - self.assertIsSubclass(G, collections_abc.AsyncGenerator) - self.assertIsSubclass(G, collections_abc.AsyncIterable) - self.assertNotIsSubclass(type(g), G) - - instance = G() - self.assertIsInstance(instance, typing_extensions.AsyncGenerator) - self.assertIsInstance(instance, typing_extensions.AsyncIterable) - self.assertIsInstance(instance, collections_abc.AsyncGenerator) - self.assertIsInstance(instance, collections_abc.AsyncIterable) - self.assertNotIsInstance(type(g), G) - self.assertNotIsInstance(g, G) - - -class OtherABCTests(BaseTestCase): - - def test_contextmanager(self): - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertIsInstance(cm, typing_extensions.ContextManager) - self.assertNotIsInstance(42, typing_extensions.ContextManager) - - @skipUnless(ASYNCIO, 'Python 3.5 required') - def test_async_contextmanager(self): - class NotACM: - pass - self.assertIsInstance(ACM(), typing_extensions.AsyncContextManager) - self.assertNotIsInstance(NotACM(), typing_extensions.AsyncContextManager) - @contextlib.contextmanager - def manager(): - yield 42 - - cm = manager() - self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager) - if TYPING_3_5_3: - self.assertEqual(typing_extensions.AsyncContextManager[int].__args__, (int,)) - if TYPING_3_6_1: - with self.assertRaises(TypeError): - isinstance(42, typing_extensions.AsyncContextManager[int]) - with self.assertRaises(TypeError): - typing_extensions.AsyncContextManager[int, str] - - -class TypeTests(BaseTestCase): - - def test_type_basic(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - def new_user(user_class: Type[User]) -> User: - return user_class() - - new_user(BasicUser) - - def test_type_typevar(self): - - class User: pass - class BasicUser(User): pass - class ProUser(User): pass - - U = TypeVar('U', bound=User) - - def new_user(user_class: Type[U]) -> U: - return user_class() - - new_user(BasicUser) - - @skipUnless(sys.version_info[:3] != (3, 5, 2), - 'Python 3.5.2 has a somewhat buggy Type impl') - def test_type_optional(self): - A = Optional[Type[BaseException]] - - def foo(a: A) -> Optional[BaseException]: - if a is None: - return None - else: - return a() - - assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) - assert foo(None) is None - - -class NewTypeTests(BaseTestCase): - - def test_basic(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - self.assertIsInstance(UserId(5), int) - self.assertIsInstance(UserName('Joe'), str) - self.assertEqual(UserId(5) + 1, 6) - - def test_errors(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) - with self.assertRaises(TypeError): - issubclass(UserId, int) - with self.assertRaises(TypeError): - class D(UserName): - pass - - -PY36_PROTOCOL_TESTS = """ -class Coordinate(Protocol): - x: int - y: int - -@runtime -class Point(Coordinate, Protocol): - label: str - -class MyPoint: - x: int - y: int - label: str - -class XAxis(Protocol): - x: int - -class YAxis(Protocol): - y: int - -@runtime -class Position(XAxis, YAxis, Protocol): - pass - -@runtime -class Proto(Protocol): - attr: int - def meth(self, arg: str) -> int: - ... - -class Concrete(Proto): - pass - -class Other: - attr: int = 1 - def meth(self, arg: str) -> int: - if arg == 'this': - return 1 - return 0 - -class NT(NamedTuple): - x: int - y: int -""" - -if PY36: - exec(PY36_PROTOCOL_TESTS) -else: - # fake names for the sake of static analysis - Coordinate = Point = MyPoint = BadPoint = NT = object - XAxis = YAxis = Position = Proto = Concrete = Other = object - - -if HAVE_PROTOCOLS: - class ProtocolTests(BaseTestCase): - - def test_basic_protocol(self): - @runtime - class P(Protocol): - def meth(self): - pass - class C: pass - class D: - def meth(self): - pass - def f(): - pass - self.assertIsSubclass(D, P) - self.assertIsInstance(D(), P) - self.assertNotIsSubclass(C, P) - self.assertNotIsInstance(C(), P) - self.assertNotIsSubclass(types.FunctionType, P) - self.assertNotIsInstance(f, P) - - def test_everything_implements_empty_protocol(self): - @runtime - class Empty(Protocol): pass - class C: pass - def f(): - pass - for thing in (object, type, tuple, C, types.FunctionType): - self.assertIsSubclass(thing, Empty) - for thing in (object(), 1, (), typing, f): - self.assertIsInstance(thing, Empty) - - @skipUnless(PY36, 'Python 3.6 required') - def test_function_implements_protocol(self): - def f(): - pass - self.assertIsInstance(f, HasCallProtocol) - - def test_no_inheritance_from_nominal(self): - class C: pass - class BP(Protocol): pass - with self.assertRaises(TypeError): - class P(C, Protocol): - pass - with self.assertRaises(TypeError): - class P(Protocol, C): - pass - with self.assertRaises(TypeError): - class P(BP, C, Protocol): - pass - class D(BP, C): pass - class E(C, BP): pass - self.assertNotIsInstance(D(), E) - self.assertNotIsInstance(E(), D) - - def test_no_instantiation(self): - class P(Protocol): pass - with self.assertRaises(TypeError): - P() - class C(P): pass - self.assertIsInstance(C(), C) - T = TypeVar('T') - class PG(Protocol[T]): pass - with self.assertRaises(TypeError): - PG() - with self.assertRaises(TypeError): - PG[int]() - with self.assertRaises(TypeError): - PG[T]() - class CG(PG[T]): pass - self.assertIsInstance(CG[int](), CG) - - def test_cannot_instantiate_abstract(self): - @runtime - class P(Protocol): - @abc.abstractmethod - def ameth(self) -> int: - raise NotImplementedError - class B(P): - pass - class C(B): - def ameth(self) -> int: - return 26 - with self.assertRaises(TypeError): - B() - self.assertIsInstance(C(), P) - - def test_subprotocols_extending(self): - class P1(Protocol): - def meth1(self): - pass - @runtime - class P2(P1, Protocol): - def meth2(self): - pass - class C: - def meth1(self): - pass - def meth2(self): - pass - class C1: - def meth1(self): - pass - class C2: - def meth2(self): - pass - self.assertNotIsInstance(C1(), P2) - self.assertNotIsInstance(C2(), P2) - self.assertNotIsSubclass(C1, P2) - self.assertNotIsSubclass(C2, P2) - self.assertIsInstance(C(), P2) - self.assertIsSubclass(C, P2) - - def test_subprotocols_merging(self): - class P1(Protocol): - def meth1(self): - pass - class P2(Protocol): - def meth2(self): - pass - @runtime - class P(P1, P2, Protocol): - pass - class C: - def meth1(self): - pass - def meth2(self): - pass - class C1: - def meth1(self): - pass - class C2: - def meth2(self): - pass - self.assertNotIsInstance(C1(), P) - self.assertNotIsInstance(C2(), P) - self.assertNotIsSubclass(C1, P) - self.assertNotIsSubclass(C2, P) - self.assertIsInstance(C(), P) - self.assertIsSubclass(C, P) - - def test_protocols_issubclass(self): - T = TypeVar('T') - @runtime - class P(Protocol): - def x(self): ... - @runtime - class PG(Protocol[T]): - def x(self): ... - class BadP(Protocol): - def x(self): ... - class BadPG(Protocol[T]): - def x(self): ... - class C: - def x(self): ... - self.assertIsSubclass(C, P) - self.assertIsSubclass(C, PG) - self.assertIsSubclass(BadP, PG) - if not PEP_560: - self.assertIsSubclass(PG[int], PG) - self.assertIsSubclass(BadPG[int], P) - self.assertIsSubclass(BadPG[T], PG) - with self.assertRaises(TypeError): - issubclass(C, PG[T]) - with self.assertRaises(TypeError): - issubclass(C, PG[C]) - with self.assertRaises(TypeError): - issubclass(C, BadP) - with self.assertRaises(TypeError): - issubclass(C, BadPG) - with self.assertRaises(TypeError): - issubclass(P, PG[T]) - with self.assertRaises(TypeError): - issubclass(PG, PG[int]) - - def test_protocols_issubclass_non_callable(self): - class C: - x = 1 - @runtime - class PNonCall(Protocol): - x = 1 - with self.assertRaises(TypeError): - issubclass(C, PNonCall) - self.assertIsInstance(C(), PNonCall) - PNonCall.register(C) - with self.assertRaises(TypeError): - issubclass(C, PNonCall) - self.assertIsInstance(C(), PNonCall) - # check that non-protocol subclasses are not affected - class D(PNonCall): ... - self.assertNotIsSubclass(C, D) - self.assertNotIsInstance(C(), D) - D.register(C) - self.assertIsSubclass(C, D) - self.assertIsInstance(C(), D) - with self.assertRaises(TypeError): - issubclass(D, PNonCall) - - def test_protocols_isinstance(self): - T = TypeVar('T') - @runtime - class P(Protocol): - def meth(x): ... - @runtime - class PG(Protocol[T]): - def meth(x): ... - class BadP(Protocol): - def meth(x): ... - class BadPG(Protocol[T]): - def meth(x): ... - class C: - def meth(x): ... - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), PG) - with self.assertRaises(TypeError): - isinstance(C(), PG[T]) - with self.assertRaises(TypeError): - isinstance(C(), PG[C]) - with self.assertRaises(TypeError): - isinstance(C(), BadP) - with self.assertRaises(TypeError): - isinstance(C(), BadPG) - - @skipUnless(PY36, 'Python 3.6 required') - def test_protocols_isinstance_py36(self): - class APoint: - def __init__(self, x, y, label): - self.x = x - self.y = y - self.label = label - class BPoint: - label = 'B' - def __init__(self, x, y): - self.x = x - self.y = y - class C: - def __init__(self, attr): - self.attr = attr - def meth(self, arg): - return 0 - class Bad: pass - self.assertIsInstance(APoint(1, 2, 'A'), Point) - self.assertIsInstance(BPoint(1, 2), Point) - self.assertNotIsInstance(MyPoint(), Point) - self.assertIsInstance(BPoint(1, 2), Position) - self.assertIsInstance(Other(), Proto) - self.assertIsInstance(Concrete(), Proto) - self.assertIsInstance(C(42), Proto) - self.assertNotIsInstance(Bad(), Proto) - self.assertNotIsInstance(Bad(), Point) - self.assertNotIsInstance(Bad(), Position) - self.assertNotIsInstance(Bad(), Concrete) - self.assertNotIsInstance(Other(), Concrete) - self.assertIsInstance(NT(1, 2), Position) - - def test_protocols_isinstance_init(self): - T = TypeVar('T') - @runtime - class P(Protocol): - x = 1 - @runtime - class PG(Protocol[T]): - x = 1 - class C: - def __init__(self, x): - self.x = x - self.assertIsInstance(C(1), P) - self.assertIsInstance(C(1), PG) - - def test_protocols_support_register(self): - @runtime - class P(Protocol): - x = 1 - class PM(Protocol): - def meth(self): pass - class D(PM): pass - class C: pass - D.register(C) - P.register(C) - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), D) - - def test_none_on_non_callable_doesnt_block_implementation(self): - @runtime - class P(Protocol): - x = 1 - class A: - x = 1 - class B(A): - x = None - class C: - def __init__(self): - self.x = None - self.assertIsInstance(B(), P) - self.assertIsInstance(C(), P) - - def test_none_on_callable_blocks_implementation(self): - @runtime - class P(Protocol): - def x(self): ... - class A: - def x(self): ... - class B(A): - x = None - class C: - def __init__(self): - self.x = None - self.assertNotIsInstance(B(), P) - self.assertNotIsInstance(C(), P) - - def test_non_protocol_subclasses(self): - class P(Protocol): - x = 1 - @runtime - class PR(Protocol): - def meth(self): pass - class NonP(P): - x = 1 - class NonPR(PR): pass - class C: - x = 1 - class D: - def meth(self): pass - self.assertNotIsInstance(C(), NonP) - self.assertNotIsInstance(D(), NonPR) - self.assertNotIsSubclass(C, NonP) - self.assertNotIsSubclass(D, NonPR) - self.assertIsInstance(NonPR(), PR) - self.assertIsSubclass(NonPR, PR) - - def test_custom_subclasshook(self): - class P(Protocol): - x = 1 - class OKClass: pass - class BadClass: - x = 1 - class C(P): - @classmethod - def __subclasshook__(cls, other): - return other.__name__.startswith("OK") - self.assertIsInstance(OKClass(), C) - self.assertNotIsInstance(BadClass(), C) - self.assertIsSubclass(OKClass, C) - self.assertNotIsSubclass(BadClass, C) - - def test_issubclass_fails_correctly(self): - @runtime - class P(Protocol): - x = 1 - class C: pass - with self.assertRaises(TypeError): - issubclass(C(), P) - - @skipUnless(not OLD_GENERICS, "New style generics required") - def test_defining_generic_protocols(self): - T = TypeVar('T') - S = TypeVar('S') - @runtime - class PR(Protocol[T, S]): - def meth(self): pass - class P(PR[int, T], Protocol[T]): - y = 1 - self.assertIsSubclass(PR[int, T], PR) - self.assertIsSubclass(P[str], PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - P[int, str] - with self.assertRaises(TypeError): - PR[int, 1] - if TYPING_3_5_3: - with self.assertRaises(TypeError): - PR[int, ClassVar] - class C(PR[int, T]): pass - self.assertIsInstance(C[str](), C) - - def test_defining_generic_protocols_old_style(self): - T = TypeVar('T') - S = TypeVar('S') - @runtime - class PR(Protocol, Generic[T, S]): - def meth(self): pass - class P(PR[int, str], Protocol): - y = 1 - if not PEP_560: - self.assertIsSubclass(PR[int, str], PR) - else: - with self.assertRaises(TypeError): - self.assertIsSubclass(PR[int, str], PR) - self.assertIsSubclass(P, PR) - with self.assertRaises(TypeError): - PR[int] - with self.assertRaises(TypeError): - PR[int, 1] - class P1(Protocol, Generic[T]): - def bar(self, x: T) -> str: ... - class P2(Generic[T], Protocol): - def bar(self, x: T) -> str: ... - @runtime - class PSub(P1[str], Protocol): - x = 1 - class Test: - x = 1 - def bar(self, x: str) -> str: - return x - self.assertIsInstance(Test(), PSub) - if TYPING_3_5_3: - with self.assertRaises(TypeError): - PR[int, ClassVar] - - def test_init_called(self): - T = TypeVar('T') - class P(Protocol[T]): pass - class C(P[T]): - def __init__(self): - self.test = 'OK' - self.assertEqual(C[int]().test, 'OK') - - @skipUnless(not OLD_GENERICS, "New style generics required") - def test_protocols_bad_subscripts(self): - T = TypeVar('T') - S = TypeVar('S') - with self.assertRaises(TypeError): - class P(Protocol[T, T]): pass - with self.assertRaises(TypeError): - class P(Protocol[int]): pass - with self.assertRaises(TypeError): - class P(Protocol[T], Protocol[S]): pass - with self.assertRaises(TypeError): - class P(typing.Mapping[T, S], Protocol[T]): pass - - @skipUnless(TYPING_3_5_3, 'New style __repr__ and __eq__ only') - def test_generic_protocols_repr(self): - T = TypeVar('T') - S = TypeVar('S') - class P(Protocol[T, S]): pass - # After PEP 560 unsubscripted generics have a standard repr. - if not PEP_560: - self.assertTrue(repr(P).endswith('P')) - self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) - self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) - - @skipUnless(TYPING_3_5_3, 'New style __repr__ and __eq__ only') - def test_generic_protocols_eq(self): - T = TypeVar('T') - S = TypeVar('S') - class P(Protocol[T, S]): pass - self.assertEqual(P, P) - self.assertEqual(P[int, T], P[int, T]) - self.assertEqual(P[T, T][Tuple[T, S]][int, str], - P[Tuple[int, str], Tuple[int, str]]) - - @skipUnless(not OLD_GENERICS, "New style generics required") - def test_generic_protocols_special_from_generic(self): - T = TypeVar('T') - class P(Protocol[T]): pass - self.assertEqual(P.__parameters__, (T,)) - self.assertIs(P.__args__, None) - self.assertIs(P.__origin__, None) - self.assertEqual(P[int].__parameters__, ()) - self.assertEqual(P[int].__args__, (int,)) - self.assertIs(P[int].__origin__, P) - - def test_generic_protocols_special_from_protocol(self): - @runtime - class PR(Protocol): - x = 1 - class P(Protocol): - def meth(self): - pass - T = TypeVar('T') - class PG(Protocol[T]): - x = 1 - def meth(self): - pass - self.assertTrue(P._is_protocol) - self.assertTrue(PR._is_protocol) - self.assertTrue(PG._is_protocol) - if hasattr(typing, 'Protocol'): - self.assertFalse(P._is_runtime_protocol) - else: - with self.assertRaises(AttributeError): - self.assertFalse(P._is_runtime_protocol) - self.assertTrue(PR._is_runtime_protocol) - self.assertTrue(PG[int]._is_protocol) - self.assertEqual(typing_extensions._get_protocol_attrs(P), {'meth'}) - self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'}) - self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)), - frozenset({'x', 'meth'})) - if not PEP_560: - self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG[int])), - frozenset({'x', 'meth'})) - - def test_no_runtime_deco_on_nominal(self): - with self.assertRaises(TypeError): - @runtime - class C: pass - class Proto(Protocol): - x = 1 - with self.assertRaises(TypeError): - @runtime - class Concrete(Proto): - pass - - def test_none_treated_correctly(self): - @runtime - class P(Protocol): - x = None # type: int - class B(object): pass - self.assertNotIsInstance(B(), P) - class C: - x = 1 - class D: - x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) - class CI: - def __init__(self): - self.x = 1 - class DI: - def __init__(self): - self.x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) - - def test_protocols_in_unions(self): - class P(Protocol): - x = None # type: int - Alias = typing.Union[typing.Iterable, P] - Alias2 = typing.Union[P, typing.Iterable] - self.assertEqual(Alias, Alias2) - - def test_protocols_pickleable(self): - global P, CP # pickle wants to reference the class by name - T = TypeVar('T') - - @runtime - class P(Protocol[T]): - x = 1 - class CP(P[int]): - pass - - c = CP() - c.foo = 42 - c.bar = 'abc' - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(c, proto) - x = pickle.loads(z) - self.assertEqual(x.foo, 42) - self.assertEqual(x.bar, 'abc') - self.assertEqual(x.x, 1) - self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) - s = pickle.dumps(P) - D = pickle.loads(s) - class E: - x = 1 - self.assertIsInstance(E(), D) - - def test_collections_protocols_allowed(self): - @runtime_checkable - class Custom(collections.abc.Iterable, Protocol): - def close(self): pass - - class A: ... - class B: - def __iter__(self): - return [] - def close(self): - return 0 - - self.assertIsSubclass(B, Custom) - self.assertNotIsSubclass(A, Custom) - - -class TypedDictTests(BaseTestCase): - - def test_basics_iterable_syntax(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - if sys.version_info[0] >= 3: - import collections.abc - self.assertNotIsSubclass(Emp, collections.abc.Sequence) - jim = Emp(name='Jim', id=1) - self.assertIs(type(jim), dict) - self.assertEqual(jim['name'], 'Jim') - self.assertEqual(jim['id'], 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__module__, __name__) - self.assertEqual(Emp.__bases__, (dict,)) - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - self.assertEqual(Emp.__total__, True) - - def test_basics_keywords_syntax(self): - Emp = TypedDict('Emp', name=str, id=int) - self.assertIsSubclass(Emp, dict) - self.assertIsSubclass(Emp, typing.MutableMapping) - if sys.version_info[0] >= 3: - import collections.abc - self.assertNotIsSubclass(Emp, collections.abc.Sequence) - jim = Emp(name='Jim', id=1) - self.assertIs(type(jim), dict) - self.assertEqual(jim['name'], 'Jim') - self.assertEqual(jim['id'], 1) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__module__, __name__) - self.assertEqual(Emp.__bases__, (dict,)) - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - self.assertEqual(Emp.__total__, True) - - def test_typeddict_special_keyword_names(self): - TD = TypedDict("TD", cls=type, self=object, typename=str, _typename=int, - fields=list, _fields=dict) - self.assertEqual(TD.__name__, 'TD') - self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str, - '_typename': int, 'fields': list, '_fields': dict}) - a = TD(cls=str, self=42, typename='foo', _typename=53, - fields=[('bar', tuple)], _fields={'baz', set}) - self.assertEqual(a['cls'], str) - self.assertEqual(a['self'], 42) - self.assertEqual(a['typename'], 'foo') - self.assertEqual(a['_typename'], 53) - self.assertEqual(a['fields'], [('bar', tuple)]) - self.assertEqual(a['_fields'], {'baz', set}) - - @skipIf(hasattr(typing, 'TypedDict'), "Should be tested by upstream") - def test_typeddict_create_errors(self): - with self.assertRaises(TypeError): - TypedDict.__new__() - with self.assertRaises(TypeError): - TypedDict() - with self.assertRaises(TypeError): - TypedDict('Emp', [('name', str)], None) - - with self.assertWarns(DeprecationWarning): - Emp = TypedDict(_typename='Emp', name=str, id=int) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - - with self.assertWarns(DeprecationWarning): - Emp = TypedDict('Emp', _fields={'name': str, 'id': int}) - self.assertEqual(Emp.__name__, 'Emp') - self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) - - def test_typeddict_errors(self): - Emp = TypedDict('Emp', {'name': str, 'id': int}) - if sys.version_info[:2] >= (3, 9): - self.assertEqual(TypedDict.__module__, 'typing') - else: - self.assertEqual(TypedDict.__module__, 'typing_extensions') - jim = Emp(name='Jim', id=1) - with self.assertRaises(TypeError): - isinstance({}, Emp) - with self.assertRaises(TypeError): - isinstance(jim, Emp) - with self.assertRaises(TypeError): - issubclass(dict, Emp) - with self.assertRaises(TypeError): - TypedDict('Hi', x=1) - with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int), ('y', 1)]) - with self.assertRaises(TypeError): - TypedDict('Hi', [('x', int)], y=int) - - @skipUnless(PY36, 'Python 3.6 required') - def test_py36_class_syntax_usage(self): - self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D') - self.assertEqual(LabelPoint2D.__module__, __name__) - self.assertEqual(LabelPoint2D.__annotations__, {'x': int, 'y': int, 'label': str}) - self.assertEqual(LabelPoint2D.__bases__, (dict,)) - self.assertEqual(LabelPoint2D.__total__, True) - self.assertNotIsSubclass(LabelPoint2D, typing.Sequence) - not_origin = Point2D(x=0, y=1) - self.assertEqual(not_origin['x'], 0) - self.assertEqual(not_origin['y'], 1) - other = LabelPoint2D(x=0, y=1, label='hi') - self.assertEqual(other['label'], 'hi') - - def test_pickle(self): - global EmpD # pickle wants to reference the class by name - EmpD = TypedDict('EmpD', name=str, id=int) - jane = EmpD({'name': 'jane', 'id': 37}) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(jane, proto) - jane2 = pickle.loads(z) - self.assertEqual(jane2, jane) - self.assertEqual(jane2, {'name': 'jane', 'id': 37}) - ZZ = pickle.dumps(EmpD, proto) - EmpDnew = pickle.loads(ZZ) - self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane) - - def test_optional(self): - EmpD = TypedDict('EmpD', name=str, id=int) - - self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD]) - self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD]) - - def test_total(self): - D = TypedDict('D', {'x': int}, total=False) - self.assertEqual(D(), {}) - self.assertEqual(D(x=1), {'x': 1}) - self.assertEqual(D.__total__, False) - - if PY36: - self.assertEqual(Options(), {}) - self.assertEqual(Options(log_level=2), {'log_level': 2}) - self.assertEqual(Options.__total__, False) - - @skipUnless(PY36, 'Python 3.6 required') - def test_optional_keys(self): - assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) - assert Point2Dor3D.__optional_keys__ == frozenset(['z']) - - @skipUnless(PY36, 'Python 3.6 required') - def test_keys_inheritance(self): - assert BaseAnimal.__required_keys__ == frozenset(['name']) - assert BaseAnimal.__optional_keys__ == frozenset([]) - assert BaseAnimal.__annotations__ == {'name': str} - - assert Animal.__required_keys__ == frozenset(['name']) - assert Animal.__optional_keys__ == frozenset(['tail', 'voice']) - assert Animal.__annotations__ == { - 'name': str, - 'tail': bool, - 'voice': str, - } - - assert Cat.__required_keys__ == frozenset(['name', 'fur_color']) - assert Cat.__optional_keys__ == frozenset(['tail', 'voice']) - assert Cat.__annotations__ == { - 'fur_color': str, - 'name': str, - 'tail': bool, - 'voice': str, - } - - -@skipUnless(TYPING_3_5_3, "Python >= 3.5.3 required") -class AnnotatedTests(BaseTestCase): - - def test_repr(self): - if hasattr(typing, 'Annotated'): - mod_name = 'typing' - else: - mod_name = "typing_extensions" - self.assertEqual( - repr(Annotated[int, 4, 5]), - mod_name + ".Annotated[int, 4, 5]" - ) - self.assertEqual( - repr(Annotated[List[int], 4, 5]), - mod_name + ".Annotated[typing.List[int], 4, 5]" - ) - - def test_flatten(self): - A = Annotated[Annotated[int, 4], 5] - self.assertEqual(A, Annotated[int, 4, 5]) - self.assertEqual(A.__metadata__, (4, 5)) - if PEP_560: - self.assertEqual(A.__origin__, int) - - def test_specialize(self): - L = Annotated[List[T], "my decoration"] - LI = Annotated[List[int], "my decoration"] - self.assertEqual(L[int], Annotated[List[int], "my decoration"]) - self.assertEqual(L[int].__metadata__, ("my decoration",)) - if PEP_560: - self.assertEqual(L[int].__origin__, List[int]) - with self.assertRaises(TypeError): - LI[int] - with self.assertRaises(TypeError): - L[int, float] - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_instantiate(self): - class C: - classvar = 4 - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - if not isinstance(other, C): - return NotImplemented - return other.x == self.x - - A = Annotated[C, "a decoration"] - a = A(5) - c = C(5) - self.assertEqual(a, c) - self.assertEqual(a.x, c.x) - self.assertEqual(a.classvar, c.classvar) - - def test_instantiate_generic(self): - MyCount = Annotated[typing_extensions.Counter[T], "my decoration"] - self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) - self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) - - def test_cannot_instantiate_forward(self): - A = Annotated["int", (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_instantiate_type_var(self): - A = Annotated[T, (5, 6)] - with self.assertRaises(TypeError): - A(5) - - def test_cannot_getattr_typevar(self): - with self.assertRaises(AttributeError): - Annotated[T, (5, 7)].x - - def test_attr_passthrough(self): - class C: - classvar = 4 - - A = Annotated[C, "a decoration"] - self.assertEqual(A.classvar, 4) - A.x = 5 - self.assertEqual(C.x, 5) - - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - - def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): - class C(Annotated): - pass - - def test_cannot_check_instance(self): - with self.assertRaises(TypeError): - isinstance(5, Annotated[int, "positive"]) - - def test_cannot_check_subclass(self): - with self.assertRaises(TypeError): - issubclass(int, Annotated[int, "positive"]) - - @skipUnless(PEP_560, "pickle support was added with PEP 560") - def test_pickle(self): - samples = [typing.Any, typing.Union[int, str], - typing.Optional[str], Tuple[int, ...], - typing.Callable[[str], bytes]] - - for t in samples: - x = Annotated[t, "a"] - - for prot in range(pickle.HIGHEST_PROTOCOL + 1): - with self.subTest(protocol=prot, type=t): - pickled = pickle.dumps(x, prot) - restored = pickle.loads(pickled) - self.assertEqual(x, restored) - - global _Annotated_test_G - - class _Annotated_test_G(Generic[T]): - x = 1 - - G = Annotated[_Annotated_test_G[int], "A decoration"] - G.foo = 42 - G.bar = 'abc' - - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - z = pickle.dumps(G, proto) - x = pickle.loads(z) - self.assertEqual(x.foo, 42) - self.assertEqual(x.bar, 'abc') - self.assertEqual(x.x, 1) - - def test_subst(self): - dec = "a decoration" - dec2 = "another decoration" - - S = Annotated[T, dec2] - self.assertEqual(S[int], Annotated[int, dec2]) - - self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2]) - L = Annotated[List[T], dec] - - self.assertEqual(L[int], Annotated[List[int], dec]) - with self.assertRaises(TypeError): - L[int, int] - - self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2]) - - D = Annotated[Dict[KT, VT], dec] - self.assertEqual(D[str, int], Annotated[Dict[str, int], dec]) - with self.assertRaises(TypeError): - D[int] - - It = Annotated[int, dec] - with self.assertRaises(TypeError): - It[None] - - LI = L[int] - with self.assertRaises(TypeError): - LI[None] - - def test_annotated_in_other_types(self): - X = List[Annotated[T, 5]] - self.assertEqual(X[int], List[Annotated[int, 5]]) - - -@skipUnless(PEP_560, "Python 3.7 required") -class GetTypeHintsTests(BaseTestCase): - def test_get_type_hints(self): - def foobar(x: List['X']): ... - X = Annotated[int, (1, 10)] - self.assertEqual( - get_type_hints(foobar, globals(), locals()), - {'x': List[int]} - ) - self.assertEqual( - get_type_hints(foobar, globals(), locals(), include_extras=True), - {'x': List[Annotated[int, (1, 10)]]} - ) - BA = Tuple[Annotated[T, (1, 0)], ...] - def barfoo(x: BA): ... - self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) - self.assertIs( - get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'], - BA - ) - def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]], - y: typing.Union[int, Annotated[T, "mutable"]]): ... - self.assertEqual( - get_type_hints(barfoo2, globals(), locals()), - {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]} - ) - BA2 = typing.Callable[..., List[T]] - def barfoo3(x: BA2): ... - self.assertIs( - get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"], - BA2 - ) - - def test_get_type_hints_refs(self): - - Const = Annotated[T, "Const"] - - class MySet(Generic[T]): - - def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]": - ... - - def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]": - ... - - self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals()), - {'other': MySet[T], 'return': MySet[T]} - ) - - self.assertEqual( - get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True), - {'other': Const[MySet[T]], 'return': MySet[T]} - ) - - self.assertEqual( - get_type_hints(MySet.__ior__, globals(), locals()), - {'other': MySet[T], 'return': MySet[T]} - ) - - -class TypeAliasTests(BaseTestCase): - @skipUnless(PY36, 'Python 3.6 required') - def test_canonical_usage_with_variable_annotation(self): - ns = {} - exec('Alias: TypeAlias = Employee', globals(), ns) - - def test_canonical_usage_with_type_comment(self): - Alias = Employee # type: TypeAlias - - def test_cannot_instantiate(self): - with self.assertRaises(TypeError): - TypeAlias() - - def test_no_isinstance(self): - with self.assertRaises(TypeError): - isinstance(42, TypeAlias) - - def test_no_issubclass(self): - with self.assertRaises(TypeError): - issubclass(Employee, TypeAlias) - - if SUBCLASS_CHECK_FORBIDDEN: - with self.assertRaises(TypeError): - issubclass(TypeAlias, Employee) - - def test_cannot_subclass(self): - with self.assertRaises(TypeError): - class C(TypeAlias): - pass - - if SUBCLASS_CHECK_FORBIDDEN: - with self.assertRaises(TypeError): - class C(type(TypeAlias)): - pass - - def test_repr(self): - if hasattr(typing, 'TypeAlias'): - self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') - else: - self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias') - - def test_cannot_subscript(self): - with self.assertRaises(TypeError): - TypeAlias[int] - - -class AllTests(BaseTestCase): - - def test_typing_extensions_includes_standard(self): - a = typing_extensions.__all__ - self.assertIn('ClassVar', a) - self.assertIn('Type', a) - self.assertIn('ChainMap', a) - self.assertIn('ContextManager', a) - self.assertIn('Counter', a) - self.assertIn('DefaultDict', a) - self.assertIn('Deque', a) - self.assertIn('NewType', a) - self.assertIn('overload', a) - self.assertIn('Text', a) - self.assertIn('TYPE_CHECKING', a) - if TYPING_3_5_3: - self.assertIn('Annotated', a) - if PEP_560: - self.assertIn('get_type_hints', a) - - if ASYNCIO: - self.assertIn('Awaitable', a) - self.assertIn('AsyncIterator', a) - self.assertIn('AsyncIterable', a) - self.assertIn('Coroutine', a) - self.assertIn('AsyncContextManager', a) - - if PY36: - self.assertIn('AsyncGenerator', a) - - if TYPING_3_5_3: - self.assertIn('Protocol', a) - self.assertIn('runtime', a) - - def test_typing_extensions_defers_when_possible(self): - exclude = { - 'overload', - 'Text', - 'TypedDict', - 'TYPE_CHECKING', - 'Final', - 'get_type_hints' - } - if sys.version_info[:2] == (3, 8): - exclude |= {'get_args', 'get_origin'} - for item in typing_extensions.__all__: - if item not in exclude and hasattr(typing, item): - self.assertIs( - getattr(typing_extensions, item), - getattr(typing, item)) - - def test_typing_extensions_compiles_with_opt(self): - file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'typing_extensions.py') - try: - subprocess.check_output('{} -OO {}'.format(sys.executable, - file_path), - stderr=subprocess.STDOUT, - shell=True) - except subprocess.CalledProcessError: - self.fail('Module does not compile with optimize=2 (-OO flag).') - - -if __name__ == '__main__': - main() diff --git a/third_party/python/typing_extensions/LICENSE b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/LICENSE similarity index 100% rename from third_party/python/typing_extensions/LICENSE rename to third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/LICENSE diff --git a/third_party/python/typing_extensions/PKG-INFO b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/METADATA similarity index 50% rename from third_party/python/typing_extensions/PKG-INFO rename to third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/METADATA index 18e054c73e78..ee6d0e727ca0 100644 --- a/third_party/python/typing_extensions/PKG-INFO +++ b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/METADATA @@ -1,28 +1,11 @@ -Metadata-Version: 1.1 -Name: typing_extensions +Metadata-Version: 2.1 +Name: typing-extensions Version: 3.7.4.3 Summary: Backported and Experimental Type Hints for Python 3.5+ Home-page: https://github.com/python/typing/blob/master/typing_extensions/README.rst Author: Guido van Rossum, Jukka Lehtosalo, Lukasz Langa, Michael Lee Author-email: levkivskyi@gmail.com License: PSF -Description: Typing Extensions -- Backported and Experimental Type Hints for Python - - The ``typing`` module was added to the standard library in Python 3.5 on - a provisional basis and will no longer be provisional in Python 3.7. However, - this means users of Python 3.5 - 3.6 who are unable to upgrade will not be - able to take advantage of new types added to the ``typing`` module, such as - ``typing.Text`` or ``typing.Coroutine``. - - The ``typing_extensions`` module contains both backports of these changes - as well as experimental types that will eventually be added to the ``typing`` - module, such as ``Protocol`` or ``TypedDict``. - - Users of other Python versions should continue to install and use - the ``typing`` module from PyPi instead of using this one unless specifically - writing code that must be compatible with multiple Python versions or requires - experimental types. - Keywords: typing function annotations type hints hinting checking checker typehints typehinting typechecking backport Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha @@ -38,3 +21,23 @@ Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Topic :: Software Development +Requires-Dist: typing (>=3.7.4) ; python_version < "3.5" + +Typing Extensions -- Backported and Experimental Type Hints for Python + +The ``typing`` module was added to the standard library in Python 3.5 on +a provisional basis and will no longer be provisional in Python 3.7. However, +this means users of Python 3.5 - 3.6 who are unable to upgrade will not be +able to take advantage of new types added to the ``typing`` module, such as +``typing.Text`` or ``typing.Coroutine``. + +The ``typing_extensions`` module contains both backports of these changes +as well as experimental types that will eventually be added to the ``typing`` +module, such as ``Protocol`` or ``TypedDict``. + +Users of other Python versions should continue to install and use +the ``typing`` module from PyPi instead of using this one unless specifically +writing code that must be compatible with multiple Python versions or requires +experimental types. + + diff --git a/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/RECORD b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/RECORD new file mode 100644 index 000000000000..0ec829548e9a --- /dev/null +++ b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/RECORD @@ -0,0 +1,6 @@ +typing_extensions.py,sha256=MX7Db0Dze7Y5_V7HHFajAbf8IPuvw2ZS07o_sfpBOE8,83727 +typing_extensions-3.7.4.3.dist-info/LICENSE,sha256=_xfOlOECAk3raHc-scx0ynbaTmWPNzUx8Kwi1oprsa0,12755 +typing_extensions-3.7.4.3.dist-info/METADATA,sha256=ZHHy0ceuecxgjj7eY65f-I_dN1m3u2BgGVbnc9lgg78,2020 +typing_extensions-3.7.4.3.dist-info/WHEEL,sha256=p46_5Uhzqz6AzeSosiOnxK-zmFja1i22CrQCjmYe8ec,92 +typing_extensions-3.7.4.3.dist-info/top_level.txt,sha256=hkDmk3VmrfXPOD--jS4aKTCu6kFZo-kVT1cIFfq1eU8,18 +typing_extensions-3.7.4.3.dist-info/RECORD,, diff --git a/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/WHEEL b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/WHEEL new file mode 100644 index 000000000000..3b5c4038dd7b --- /dev/null +++ b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/top_level.txt b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/top_level.txt new file mode 100644 index 000000000000..5fd4f05f341a --- /dev/null +++ b/third_party/python/typing_extensions/typing_extensions-3.7.4.3.dist-info/top_level.txt @@ -0,0 +1 @@ +typing_extensions diff --git a/third_party/python/typing_extensions/src_py3/typing_extensions.py b/third_party/python/typing_extensions/typing_extensions.py similarity index 100% rename from third_party/python/typing_extensions/src_py3/typing_extensions.py rename to third_party/python/typing_extensions/typing_extensions.py diff --git a/third_party/python/urllib3/CONTRIBUTORS.txt b/third_party/python/urllib3/CONTRIBUTORS.txt deleted file mode 100644 index ef41e32b733a..000000000000 --- a/third_party/python/urllib3/CONTRIBUTORS.txt +++ /dev/null @@ -1,304 +0,0 @@ -# Contributions to the urllib3 project - -## Creator & Maintainer - -* Andrey Petrov - - -## Contributors - -In chronological order: - -* victor.vde - * HTTPS patch (which inspired HTTPSConnectionPool) - -* erikcederstrand - * NTLM-authenticated HTTPSConnectionPool - * Basic-authenticated HTTPSConnectionPool (merged into make_headers) - -* niphlod - * Client-verified SSL certificates for HTTPSConnectionPool - * Response gzip and deflate encoding support - * Better unicode support for filepost using StringIO buffers - -* btoconnor - * Non-multipart encoding for POST requests - -* p.dobrogost - * Code review, PEP8 compliance, benchmark fix - -* kennethreitz - * Bugfixes, suggestions, Requests integration - -* georgemarshall - * Bugfixes, Improvements and Test coverage - -* Thomas Kluyver - * Python 3 support - -* brandon-rhodes - * Design review, bugfixes, test coverage. - -* studer - * IPv6 url support and test coverage - -* Shivaram Lingamneni - * Support for explicitly closing pooled connections - -* hartator - * Corrected multipart behavior for params - -* Thomas Weißschuh - * Support for TLS SNI - * API unification of ssl_version/cert_reqs - * SSL fingerprint and alternative hostname verification - * Bugfixes in testsuite - -* Sune Kirkeby - * Optional SNI-support for Python 2 via PyOpenSSL. - -* Marc Schlaich - * Various bugfixes and test improvements. - -* Bryce Boe - * Correct six.moves conflict - * Fixed pickle support of some exceptions - -* Boris Figovsky - * Allowed to skip SSL hostname verification - -* Cory Benfield - * Stream method for Response objects. - * Return native strings in header values. - * Generate 'Host' header when using proxies. - -* Jason Robinson - * Add missing WrappedSocket.fileno method in PyOpenSSL - -* Audrius Butkevicius - * Fixed a race condition - -* Stanislav Vitkovskiy - * Added HTTPS (CONNECT) proxy support - -* Stephen Holsapple - * Added abstraction for granular control of request fields - -* Martin von Gagern - * Support for non-ASCII header parameters - -* Kevin Burke and Pavel Kirichenko - * Support for separate connect and request timeouts - -* Peter Waller - * HTTPResponse.tell() for determining amount received over the wire - -* Nipunn Koorapati - * Ignore default ports when comparing hosts for equality - -* Danilo @dbrgn - * Disabled TLS compression by default on Python 3.2+ - * Disabled TLS compression in pyopenssl contrib module - * Configurable cipher suites in pyopenssl contrib module - -* Roman Bogorodskiy - * Account retries on proxy errors - -* Nicolas Delaby - * Use the platform-specific CA certificate locations - -* Josh Schneier - * HTTPHeaderDict and associated tests and docs - * Bugfixes, docs, test coverage - -* Tahia Khan - * Added Timeout examples in docs - -* Arthur Grunseid - * source_address support and tests (with https://github.com/bui) - -* Ian Cordasco - * PEP8 Compliance and Linting - * Add ability to pass socket options to an HTTP Connection - -* Erik Tollerud - * Support for standard library io module. - -* Krishna Prasad - * Google App Engine documentation - -* Aaron Meurer - * Added Url.url, which unparses a Url - -* Evgeny Kapun - * Bugfixes - -* Benjamen Meyer - * Security Warning Documentation update for proper capture - -* Shivan Sornarajah - * Support for using ConnectionPool and PoolManager as context managers. - -* Alex Gaynor - * Updates to the default SSL configuration - -* Tomas Tomecek - * Implemented generator for getting chunks from chunked responses. - -* tlynn - * Respect the warning preferences at import. - -* David D. Riddle - * IPv6 bugfixes in testsuite - -* Thea Flowers - * App Engine environment tests. - * Documentation re-write. - -* John Krauss - * Clues to debugging problems with `cryptography` dependency in docs - -* Disassem - * Fix pool-default headers not applying for url-encoded requests like GET. - -* James Atherfold - * Bugfixes relating to cleanup of connections during errors. - -* Christian Pedersen - * IPv6 HTTPS proxy bugfix - -* Jordan Moldow - * Fix low-level exceptions leaking from ``HTTPResponse.stream()``. - * Bugfix for ``ConnectionPool.urlopen(release_conn=False)``. - * Creation of ``HTTPConnectionPool.ResponseCls``. - -* Predrag Gruevski - * Made cert digest comparison use a constant-time algorithm. - -* Adam Talsma - * Bugfix to ca_cert file paths. - -* Evan Meagher - * Bugfix related to `memoryview` usage in PyOpenSSL adapter - -* John Vandenberg - * Python 2.6 fixes; pyflakes and pep8 compliance - -* Andy Caldwell - * Bugfix related to reusing connections in indeterminate states. - -* Ville Skyttä - * Logging efficiency improvements, spelling fixes, Travis config. - -* Shige Takeda - * Started Recipes documentation and added a recipe about handling concatenated gzip data in HTTP response - -* Jess Shapiro - * Various character-encoding fixes/tweaks - * Disabling IPv6 DNS when IPv6 connections not supported - -* David Foster - * Ensure order of request and response headers are preserved. - -* Jeremy Cline - * Added connection pool keys by scheme - -* Aviv Palivoda - * History list to Retry object. - * HTTPResponse contains the last Retry object. - -* Nate Prewitt - * Ensure timeouts are not booleans and greater than zero. - * Fixed infinite loop in ``stream`` when amt=None. - * Added length_remaining to determine remaining data to be read. - * Added enforce_content_length to raise exception when incorrect content-length received. - -* Seth Michael Larson - * Created selectors backport that supports PEP 475. - -* Alexandre Dias - * Don't retry on timeout if method not in whitelist - -* Moinuddin Quadri - * Lazily load idna package - -* Tom White - * Made SOCKS handler differentiate socks5h from socks5 and socks4a from socks4. - -* Tim Burke - * Stop buffering entire deflate-encoded responses. - -* Tuukka Mustonen - * Add counter for status_forcelist retries. - -* Erik Rose - * Bugfix to pyopenssl vendoring - -* Wolfgang Richter - * Bugfix related to loading full certificate chains with PyOpenSSL backend. - -* Mike Miller - * Logging improvements to include the HTTP(S) port when opening a new connection - -* Ioannis Tziakos - * Fix ``util.selectors._fileobj_to_fd`` to accept ``long``. - * Update appveyor tox setup to use the 64bit python. - -* Akamai (through Jess Shapiro) - * Ongoing maintenance; 2017-2018 - -* Dominique Leuenberger - * Minor fixes in the test suite - -* Will Bond - * Add Python 2.6 support to ``contrib.securetransport`` - -* Aleksei Alekseev - * using auth info for socks proxy - -* Chris Wilcox - * Improve contribution guide - * Add ``HTTPResponse.geturl`` method to provide ``urllib2.urlopen().geturl()`` behavior - -* Bruce Merry - * Fix leaking exceptions when system calls are interrupted with zero timeout - -* Hugo van Kemenade - * Drop support for EOL Python 2.6 - -* Tim Bell - * Bugfix for responses with Content-Type: message/* logging warnings - -* Justin Bramley - * Add ability to handle multiple Content-Encodings - -* Katsuhiko YOSHIDA - * Remove Authorization header regardless of case when redirecting to cross-site - -* James Meickle - * Improve handling of Retry-After header - -* Chris Jerdonek - * Remove a spurious TypeError from the exception chain inside - HTTPConnectionPool._make_request(), also for BaseExceptions. - -* Jorge Lopez Silva - * Added support for forwarding requests through HTTPS proxies. - -* Benno Rice - * Allow cadata parameter to be passed to underlying ``SSLContext.load_verify_locations()``. - -* Keiichi Kobayashi - * Rename VerifiedHTTPSConnection to HTTPSConnection - -* Himanshu Garg - * DOC & LICENSE Update - -* Hod Bin Noon - * Test improvements - -* Chris Olufson - * Fix for connection not being released on HTTP redirect and response not preloaded - -* [Your name or handle] <[email or website]> - * [Brief summary of your changes] diff --git a/third_party/python/urllib3/MANIFEST.in b/third_party/python/urllib3/MANIFEST.in deleted file mode 100644 index 4edfedde2722..000000000000 --- a/third_party/python/urllib3/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst CHANGES.rst LICENSE.txt CONTRIBUTORS.txt dev-requirements.txt Makefile -recursive-include dummyserver * -recursive-include test * -recursive-include docs * -recursive-exclude docs/_build * diff --git a/third_party/python/urllib3/PKG-INFO b/third_party/python/urllib3/PKG-INFO deleted file mode 100644 index d95b8c2d2741..000000000000 --- a/third_party/python/urllib3/PKG-INFO +++ /dev/null @@ -1,1253 +0,0 @@ -Metadata-Version: 2.1 -Name: urllib3 -Version: 1.25.9 -Summary: HTTP library with thread-safe connection pooling, file post, and more. -Home-page: https://urllib3.readthedocs.io/ -Author: Andrey Petrov -Author-email: andrey.petrov@shazow.net -License: MIT -Project-URL: Documentation, https://urllib3.readthedocs.io/ -Project-URL: Code, https://github.com/urllib3/urllib3 -Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues -Description: urllib3 - ======= - - urllib3 is a powerful, *sanity-friendly* HTTP client for Python. Much of the - Python ecosystem already uses urllib3 and you should too. - urllib3 brings many critical features that are missing from the Python - standard libraries: - - - Thread safety. - - Connection pooling. - - Client-side SSL/TLS verification. - - File uploads with multipart encoding. - - Helpers for retrying requests and dealing with HTTP redirects. - - Support for gzip, deflate, and brotli encoding. - - Proxy support for HTTP and SOCKS. - - 100% test coverage. - - urllib3 is powerful and easy to use:: - - >>> import urllib3 - >>> http = urllib3.PoolManager() - >>> r = http.request('GET', 'http://httpbin.org/robots.txt') - >>> r.status - 200 - >>> r.data - 'User-agent: *\nDisallow: /deny\n' - - - Installing - ---------- - - urllib3 can be installed with `pip `_:: - - $ pip install urllib3 - - Alternatively, you can grab the latest source code from `GitHub `_:: - - $ git clone git://github.com/urllib3/urllib3.git - $ python setup.py install - - - Documentation - ------------- - - urllib3 has usage and reference documentation at `urllib3.readthedocs.io `_. - - - Contributing - ------------ - - urllib3 happily accepts contributions. Please see our - `contributing documentation `_ - for some tips on getting started. - - - Security Disclosures - -------------------- - - To report a security vulnerability, please use the - `Tidelift security contact `_. - Tidelift will coordinate the fix and disclosure with maintainers. - - Maintainers - ----------- - - - `@sethmlarson `_ (Seth M. Larson) - - `@pquentin `_ (Quentin Pradet) - - `@theacodes `_ (Thea Flowers) - - `@haikuginger `_ (Jess Shapiro) - - `@lukasa `_ (Cory Benfield) - - `@sigmavirus24 `_ (Ian Stapleton Cordasco) - - `@shazow `_ (Andrey Petrov) - - 👋 - - - Sponsorship - ----------- - - .. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png - :width: 75 - :alt: Tidelift - - .. list-table:: - :widths: 10 100 - - * - |tideliftlogo| - - Professional support for urllib3 is available as part of the `Tidelift - Subscription`_. Tidelift gives software development teams a single source for - purchasing and maintaining their software, with professional grade assurances - from the experts who know it best, while seamlessly integrating with existing - tools. - - .. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme - - If your company benefits from this library, please consider `sponsoring its - development `_. - - Sponsors include: - - - Abbott (2018-2019), sponsored `@sethmlarson `_'s work on urllib3. - - Google Cloud Platform (2018-2019), sponsored `@theacodes `_'s work on urllib3. - - Akamai (2017-2018), sponsored `@haikuginger `_'s work on urllib3 - - Hewlett Packard Enterprise (2016-2017), sponsored `@Lukasa’s `_ work on urllib3. - - - Changes - ======= - - 1.25.9 (2020-04-16) - ------------------- - - * Added ``InvalidProxyConfigurationWarning`` which is raised when - erroneously specifying an HTTPS proxy URL. urllib3 doesn't currently - support connecting to HTTPS proxies but will soon be able to - and we would like users to migrate properly without much breakage. - - See `this GitHub issue `_ - for more information on how to fix your proxy config. (Pull #1851) - - * Drain connection after ``PoolManager`` redirect (Pull #1817) - - * Ensure ``load_verify_locations`` raises ``SSLError`` for all backends (Pull #1812) - - * Rename ``VerifiedHTTPSConnection`` to ``HTTPSConnection`` (Pull #1805) - - * Allow the CA certificate data to be passed as a string (Pull #1804) - - * Raise ``ValueError`` if method contains control characters (Pull #1800) - - * Add ``__repr__`` to ``Timeout`` (Pull #1795) - - - 1.25.8 (2020-01-20) - ------------------- - - * Drop support for EOL Python 3.4 (Pull #1774) - - * Optimize _encode_invalid_chars (Pull #1787) - - - 1.25.7 (2019-11-11) - ------------------- - - * Preserve ``chunked`` parameter on retries (Pull #1715, Pull #1734) - - * Allow unset ``SERVER_SOFTWARE`` in App Engine (Pull #1704, Issue #1470) - - * Fix issue where URL fragment was sent within the request target. (Pull #1732) - - * Fix issue where an empty query section in a URL would fail to parse. (Pull #1732) - - * Remove TLS 1.3 support in SecureTransport due to Apple removing support (Pull #1703) - - - 1.25.6 (2019-09-24) - ------------------- - - * Fix issue where tilde (``~``) characters were incorrectly - percent-encoded in the path. (Pull #1692) - - - 1.25.5 (2019-09-19) - ------------------- - - * Add mitigation for BPO-37428 affecting Python <3.7.4 and OpenSSL 1.1.1+ which - caused certificate verification to be enabled when using ``cert_reqs=CERT_NONE``. - (Issue #1682) - - - 1.25.4 (2019-09-19) - ------------------- - - * Propagate Retry-After header settings to subsequent retries. (Pull #1607) - - * Fix edge case where Retry-After header was still respected even when - explicitly opted out of. (Pull #1607) - - * Remove dependency on ``rfc3986`` for URL parsing. - - * Fix issue where URLs containing invalid characters within ``Url.auth`` would - raise an exception instead of percent-encoding those characters. - - * Add support for ``HTTPResponse.auto_close = False`` which makes HTTP responses - work well with BufferedReaders and other ``io`` module features. (Pull #1652) - - * Percent-encode invalid characters in URL for ``HTTPConnectionPool.request()`` (Pull #1673) - - - 1.25.3 (2019-05-23) - ------------------- - - * Change ``HTTPSConnection`` to load system CA certificates - when ``ca_certs``, ``ca_cert_dir``, and ``ssl_context`` are - unspecified. (Pull #1608, Issue #1603) - - * Upgrade bundled rfc3986 to v1.3.2. (Pull #1609, Issue #1605) - - - 1.25.2 (2019-04-28) - ------------------- - - * Change ``is_ipaddress`` to not detect IPvFuture addresses. (Pull #1583) - - * Change ``parse_url`` to percent-encode invalid characters within the - path, query, and target components. (Pull #1586) - - - 1.25.1 (2019-04-24) - ------------------- - - * Add support for Google's ``Brotli`` package. (Pull #1572, Pull #1579) - - * Upgrade bundled rfc3986 to v1.3.1 (Pull #1578) - - - 1.25 (2019-04-22) - ----------------- - - * Require and validate certificates by default when using HTTPS (Pull #1507) - - * Upgraded ``urllib3.utils.parse_url()`` to be RFC 3986 compliant. (Pull #1487) - - * Added support for ``key_password`` for ``HTTPSConnectionPool`` to use - encrypted ``key_file`` without creating your own ``SSLContext`` object. (Pull #1489) - - * Add TLSv1.3 support to CPython, pyOpenSSL, and SecureTransport ``SSLContext`` - implementations. (Pull #1496) - - * Switched the default multipart header encoder from RFC 2231 to HTML 5 working draft. (Issue #303, PR #1492) - - * Fixed issue where OpenSSL would block if an encrypted client private key was - given and no password was given. Instead an ``SSLError`` is raised. (Pull #1489) - - * Added support for Brotli content encoding. It is enabled automatically if - ``brotlipy`` package is installed which can be requested with - ``urllib3[brotli]`` extra. (Pull #1532) - - * Drop ciphers using DSS key exchange from default TLS cipher suites. - Improve default ciphers when using SecureTransport. (Pull #1496) - - * Implemented a more efficient ``HTTPResponse.__iter__()`` method. (Issue #1483) - - 1.24.3 (2019-05-01) - ------------------- - - * Apply fix for CVE-2019-9740. (Pull #1591) - - 1.24.2 (2019-04-17) - ------------------- - - * Don't load system certificates by default when any other ``ca_certs``, ``ca_certs_dir`` or - ``ssl_context`` parameters are specified. - - * Remove Authorization header regardless of case when redirecting to cross-site. (Issue #1510) - - * Add support for IPv6 addresses in subjectAltName section of certificates. (Issue #1269) - - - 1.24.1 (2018-11-02) - ------------------- - - * Remove quadratic behavior within ``GzipDecoder.decompress()`` (Issue #1467) - - * Restored functionality of ``ciphers`` parameter for ``create_urllib3_context()``. (Issue #1462) - - - 1.24 (2018-10-16) - ----------------- - - * Allow key_server_hostname to be specified when initializing a PoolManager to allow custom SNI to be overridden. (Pull #1449) - - * Test against Python 3.7 on AppVeyor. (Pull #1453) - - * Early-out ipv6 checks when running on App Engine. (Pull #1450) - - * Change ambiguous description of backoff_factor (Pull #1436) - - * Add ability to handle multiple Content-Encodings (Issue #1441 and Pull #1442) - - * Skip DNS names that can't be idna-decoded when using pyOpenSSL (Issue #1405). - - * Add a server_hostname parameter to HTTPSConnection which allows for - overriding the SNI hostname sent in the handshake. (Pull #1397) - - * Drop support for EOL Python 2.6 (Pull #1429 and Pull #1430) - - * Fixed bug where responses with header Content-Type: message/* erroneously - raised HeaderParsingError, resulting in a warning being logged. (Pull #1439) - - * Move urllib3 to src/urllib3 (Pull #1409) - - - 1.23 (2018-06-04) - ----------------- - - * Allow providing a list of headers to strip from requests when redirecting - to a different host. Defaults to the ``Authorization`` header. Different - headers can be set via ``Retry.remove_headers_on_redirect``. (Issue #1316) - - * Fix ``util.selectors._fileobj_to_fd`` to accept ``long`` (Issue #1247). - - * Dropped Python 3.3 support. (Pull #1242) - - * Put the connection back in the pool when calling stream() or read_chunked() on - a chunked HEAD response. (Issue #1234) - - * Fixed pyOpenSSL-specific ssl client authentication issue when clients - attempted to auth via certificate + chain (Issue #1060) - - * Add the port to the connectionpool connect print (Pull #1251) - - * Don't use the ``uuid`` module to create multipart data boundaries. (Pull #1380) - - * ``read_chunked()`` on a closed response returns no chunks. (Issue #1088) - - * Add Python 2.6 support to ``contrib.securetransport`` (Pull #1359) - - * Added support for auth info in url for SOCKS proxy (Pull #1363) - - - 1.22 (2017-07-20) - ----------------- - - * Fixed missing brackets in ``HTTP CONNECT`` when connecting to IPv6 address via - IPv6 proxy. (Issue #1222) - - * Made the connection pool retry on ``SSLError``. The original ``SSLError`` - is available on ``MaxRetryError.reason``. (Issue #1112) - - * Drain and release connection before recursing on retry/redirect. Fixes - deadlocks with a blocking connectionpool. (Issue #1167) - - * Fixed compatibility for cookiejar. (Issue #1229) - - * pyopenssl: Use vendored version of ``six``. (Issue #1231) - - - 1.21.1 (2017-05-02) - ------------------- - - * Fixed SecureTransport issue that would cause long delays in response body - delivery. (Pull #1154) - - * Fixed regression in 1.21 that threw exceptions when users passed the - ``socket_options`` flag to the ``PoolManager``. (Issue #1165) - - * Fixed regression in 1.21 that threw exceptions when users passed the - ``assert_hostname`` or ``assert_fingerprint`` flag to the ``PoolManager``. - (Pull #1157) - - - 1.21 (2017-04-25) - ----------------- - - * Improved performance of certain selector system calls on Python 3.5 and - later. (Pull #1095) - - * Resolved issue where the PyOpenSSL backend would not wrap SysCallError - exceptions appropriately when sending data. (Pull #1125) - - * Selectors now detects a monkey-patched select module after import for modules - that patch the select module like eventlet, greenlet. (Pull #1128) - - * Reduced memory consumption when streaming zlib-compressed responses - (as opposed to raw deflate streams). (Pull #1129) - - * Connection pools now use the entire request context when constructing the - pool key. (Pull #1016) - - * ``PoolManager.connection_from_*`` methods now accept a new keyword argument, - ``pool_kwargs``, which are merged with the existing ``connection_pool_kw``. - (Pull #1016) - - * Add retry counter for ``status_forcelist``. (Issue #1147) - - * Added ``contrib`` module for using SecureTransport on macOS: - ``urllib3.contrib.securetransport``. (Pull #1122) - - * urllib3 now only normalizes the case of ``http://`` and ``https://`` schemes: - for schemes it does not recognise, it assumes they are case-sensitive and - leaves them unchanged. - (Issue #1080) - - - 1.20 (2017-01-19) - ----------------- - - * Added support for waiting for I/O using selectors other than select, - improving urllib3's behaviour with large numbers of concurrent connections. - (Pull #1001) - - * Updated the date for the system clock check. (Issue #1005) - - * ConnectionPools now correctly consider hostnames to be case-insensitive. - (Issue #1032) - - * Outdated versions of PyOpenSSL now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Pull #1063) - - * Outdated versions of cryptography now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Issue #1044) - - * Automatically attempt to rewind a file-like body object when a request is - retried or redirected. (Pull #1039) - - * Fix some bugs that occur when modules incautiously patch the queue module. - (Pull #1061) - - * Prevent retries from occurring on read timeouts for which the request method - was not in the method whitelist. (Issue #1059) - - * Changed the PyOpenSSL contrib module to lazily load idna to avoid - unnecessarily bloating the memory of programs that don't need it. (Pull - #1076) - - * Add support for IPv6 literals with zone identifiers. (Pull #1013) - - * Added support for socks5h:// and socks4a:// schemes when working with SOCKS - proxies, and controlled remote DNS appropriately. (Issue #1035) - - - 1.19.1 (2016-11-16) - ------------------- - - * Fixed AppEngine import that didn't function on Python 3.5. (Pull #1025) - - - 1.19 (2016-11-03) - ----------------- - - * urllib3 now respects Retry-After headers on 413, 429, and 503 responses when - using the default retry logic. (Pull #955) - - * Remove markers from setup.py to assist ancient setuptools versions. (Issue - #986) - - * Disallow superscripts and other integerish things in URL ports. (Issue #989) - - * Allow urllib3's HTTPResponse.stream() method to continue to work with - non-httplib underlying FPs. (Pull #990) - - * Empty filenames in multipart headers are now emitted as such, rather than - being suppressed. (Issue #1015) - - * Prefer user-supplied Host headers on chunked uploads. (Issue #1009) - - - 1.18.1 (2016-10-27) - ------------------- - - * CVE-2016-9015. Users who are using urllib3 version 1.17 or 1.18 along with - PyOpenSSL injection and OpenSSL 1.1.0 *must* upgrade to this version. This - release fixes a vulnerability whereby urllib3 in the above configuration - would silently fail to validate TLS certificates due to erroneously setting - invalid flags in OpenSSL's ``SSL_CTX_set_verify`` function. These erroneous - flags do not cause a problem in OpenSSL versions before 1.1.0, which - interprets the presence of any flag as requesting certificate validation. - - There is no PR for this patch, as it was prepared for simultaneous disclosure - and release. The master branch received the same fix in PR #1010. - - - 1.18 (2016-09-26) - ----------------- - - * Fixed incorrect message for IncompleteRead exception. (PR #973) - - * Accept ``iPAddress`` subject alternative name fields in TLS certificates. - (Issue #258) - - * Fixed consistency of ``HTTPResponse.closed`` between Python 2 and 3. - (Issue #977) - - * Fixed handling of wildcard certificates when using PyOpenSSL. (Issue #979) - - - 1.17 (2016-09-06) - ----------------- - - * Accept ``SSLContext`` objects for use in SSL/TLS negotiation. (Issue #835) - - * ConnectionPool debug log now includes scheme, host, and port. (Issue #897) - - * Substantially refactored documentation. (Issue #887) - - * Used URLFetch default timeout on AppEngine, rather than hardcoding our own. - (Issue #858) - - * Normalize the scheme and host in the URL parser (Issue #833) - - * ``HTTPResponse`` contains the last ``Retry`` object, which now also - contains retries history. (Issue #848) - - * Timeout can no longer be set as boolean, and must be greater than zero. - (PR #924) - - * Removed pyasn1 and ndg-httpsclient from dependencies used for PyOpenSSL. We - now use cryptography and idna, both of which are already dependencies of - PyOpenSSL. (PR #930) - - * Fixed infinite loop in ``stream`` when amt=None. (Issue #928) - - * Try to use the operating system's certificates when we are using an - ``SSLContext``. (PR #941) - - * Updated cipher suite list to allow ChaCha20+Poly1305. AES-GCM is preferred to - ChaCha20, but ChaCha20 is then preferred to everything else. (PR #947) - - * Updated cipher suite list to remove 3DES-based cipher suites. (PR #958) - - * Removed the cipher suite fallback to allow HIGH ciphers. (PR #958) - - * Implemented ``length_remaining`` to determine remaining content - to be read. (PR #949) - - * Implemented ``enforce_content_length`` to enable exceptions when - incomplete data chunks are received. (PR #949) - - * Dropped connection start, dropped connection reset, redirect, forced retry, - and new HTTPS connection log levels to DEBUG, from INFO. (PR #967) - - - 1.16 (2016-06-11) - ----------------- - - * Disable IPv6 DNS when IPv6 connections are not possible. (Issue #840) - - * Provide ``key_fn_by_scheme`` pool keying mechanism that can be - overridden. (Issue #830) - - * Normalize scheme and host to lowercase for pool keys, and include - ``source_address``. (Issue #830) - - * Cleaner exception chain in Python 3 for ``_make_request``. - (Issue #861) - - * Fixed installing ``urllib3[socks]`` extra. (Issue #864) - - * Fixed signature of ``ConnectionPool.close`` so it can actually safely be - called by subclasses. (Issue #873) - - * Retain ``release_conn`` state across retries. (Issues #651, #866) - - * Add customizable ``HTTPConnectionPool.ResponseCls``, which defaults to - ``HTTPResponse`` but can be replaced with a subclass. (Issue #879) - - - 1.15.1 (2016-04-11) - ------------------- - - * Fix packaging to include backports module. (Issue #841) - - - 1.15 (2016-04-06) - ----------------- - - * Added Retry(raise_on_status=False). (Issue #720) - - * Always use setuptools, no more distutils fallback. (Issue #785) - - * Dropped support for Python 3.2. (Issue #786) - - * Chunked transfer encoding when requesting with ``chunked=True``. - (Issue #790) - - * Fixed regression with IPv6 port parsing. (Issue #801) - - * Append SNIMissingWarning messages to allow users to specify it in - the PYTHONWARNINGS environment variable. (Issue #816) - - * Handle unicode headers in Py2. (Issue #818) - - * Log certificate when there is a hostname mismatch. (Issue #820) - - * Preserve order of request/response headers. (Issue #821) - - - 1.14 (2015-12-29) - ----------------- - - * contrib: SOCKS proxy support! (Issue #762) - - * Fixed AppEngine handling of transfer-encoding header and bug - in Timeout defaults checking. (Issue #763) - - - 1.13.1 (2015-12-18) - ------------------- - - * Fixed regression in IPv6 + SSL for match_hostname. (Issue #761) - - - 1.13 (2015-12-14) - ----------------- - - * Fixed ``pip install urllib3[secure]`` on modern pip. (Issue #706) - - * pyopenssl: Fixed SSL3_WRITE_PENDING error. (Issue #717) - - * pyopenssl: Support for TLSv1.1 and TLSv1.2. (Issue #696) - - * Close connections more defensively on exception. (Issue #734) - - * Adjusted ``read_chunked`` to handle gzipped, chunk-encoded bodies without - repeatedly flushing the decoder, to function better on Jython. (Issue #743) - - * Accept ``ca_cert_dir`` for SSL-related PoolManager configuration. (Issue #758) - - - 1.12 (2015-09-03) - ----------------- - - * Rely on ``six`` for importing ``httplib`` to work around - conflicts with other Python 3 shims. (Issue #688) - - * Add support for directories of certificate authorities, as supported by - OpenSSL. (Issue #701) - - * New exception: ``NewConnectionError``, raised when we fail to establish - a new connection, usually ``ECONNREFUSED`` socket error. - - - 1.11 (2015-07-21) - ----------------- - - * When ``ca_certs`` is given, ``cert_reqs`` defaults to - ``'CERT_REQUIRED'``. (Issue #650) - - * ``pip install urllib3[secure]`` will install Certifi and - PyOpenSSL as dependencies. (Issue #678) - - * Made ``HTTPHeaderDict`` usable as a ``headers`` input value - (Issues #632, #679) - - * Added `urllib3.contrib.appengine `_ - which has an ``AppEngineManager`` for using ``URLFetch`` in a - Google AppEngine environment. (Issue #664) - - * Dev: Added test suite for AppEngine. (Issue #631) - - * Fix performance regression when using PyOpenSSL. (Issue #626) - - * Passing incorrect scheme (e.g. ``foo://``) will raise - ``ValueError`` instead of ``AssertionError`` (backwards - compatible for now, but please migrate). (Issue #640) - - * Fix pools not getting replenished when an error occurs during a - request using ``release_conn=False``. (Issue #644) - - * Fix pool-default headers not applying for url-encoded requests - like GET. (Issue #657) - - * log.warning in Python 3 when headers are skipped due to parsing - errors. (Issue #642) - - * Close and discard connections if an error occurs during read. - (Issue #660) - - * Fix host parsing for IPv6 proxies. (Issue #668) - - * Separate warning type SubjectAltNameWarning, now issued once - per host. (Issue #671) - - * Fix ``httplib.IncompleteRead`` not getting converted to - ``ProtocolError`` when using ``HTTPResponse.stream()`` - (Issue #674) - - 1.10.4 (2015-05-03) - ------------------- - - * Migrate tests to Tornado 4. (Issue #594) - - * Append default warning configuration rather than overwrite. - (Issue #603) - - * Fix streaming decoding regression. (Issue #595) - - * Fix chunked requests losing state across keep-alive connections. - (Issue #599) - - * Fix hanging when chunked HEAD response has no body. (Issue #605) - - - 1.10.3 (2015-04-21) - ------------------- - - * Emit ``InsecurePlatformWarning`` when SSLContext object is missing. - (Issue #558) - - * Fix regression of duplicate header keys being discarded. - (Issue #563) - - * ``Response.stream()`` returns a generator for chunked responses. - (Issue #560) - - * Set upper-bound timeout when waiting for a socket in PyOpenSSL. - (Issue #585) - - * Work on platforms without `ssl` module for plain HTTP requests. - (Issue #587) - - * Stop relying on the stdlib's default cipher list. (Issue #588) - - - 1.10.2 (2015-02-25) - ------------------- - - * Fix file descriptor leakage on retries. (Issue #548) - - * Removed RC4 from default cipher list. (Issue #551) - - * Header performance improvements. (Issue #544) - - * Fix PoolManager not obeying redirect retry settings. (Issue #553) - - - 1.10.1 (2015-02-10) - ------------------- - - * Pools can be used as context managers. (Issue #545) - - * Don't re-use connections which experienced an SSLError. (Issue #529) - - * Don't fail when gzip decoding an empty stream. (Issue #535) - - * Add sha256 support for fingerprint verification. (Issue #540) - - * Fixed handling of header values containing commas. (Issue #533) - - - 1.10 (2014-12-14) - ----------------- - - * Disabled SSLv3. (Issue #473) - - * Add ``Url.url`` property to return the composed url string. (Issue #394) - - * Fixed PyOpenSSL + gevent ``WantWriteError``. (Issue #412) - - * ``MaxRetryError.reason`` will always be an exception, not string. - (Issue #481) - - * Fixed SSL-related timeouts not being detected as timeouts. (Issue #492) - - * Py3: Use ``ssl.create_default_context()`` when available. (Issue #473) - - * Emit ``InsecureRequestWarning`` for *every* insecure HTTPS request. - (Issue #496) - - * Emit ``SecurityWarning`` when certificate has no ``subjectAltName``. - (Issue #499) - - * Close and discard sockets which experienced SSL-related errors. - (Issue #501) - - * Handle ``body`` param in ``.request(...)``. (Issue #513) - - * Respect timeout with HTTPS proxy. (Issue #505) - - * PyOpenSSL: Handle ZeroReturnError exception. (Issue #520) - - - 1.9.1 (2014-09-13) - ------------------ - - * Apply socket arguments before binding. (Issue #427) - - * More careful checks if fp-like object is closed. (Issue #435) - - * Fixed packaging issues of some development-related files not - getting included. (Issue #440) - - * Allow performing *only* fingerprint verification. (Issue #444) - - * Emit ``SecurityWarning`` if system clock is waaay off. (Issue #445) - - * Fixed PyOpenSSL compatibility with PyPy. (Issue #450) - - * Fixed ``BrokenPipeError`` and ``ConnectionError`` handling in Py3. - (Issue #443) - - - - 1.9 (2014-07-04) - ---------------- - - * Shuffled around development-related files. If you're maintaining a distro - package of urllib3, you may need to tweak things. (Issue #415) - - * Unverified HTTPS requests will trigger a warning on the first request. See - our new `security documentation - `_ for details. - (Issue #426) - - * New retry logic and ``urllib3.util.retry.Retry`` configuration object. - (Issue #326) - - * All raised exceptions should now wrapped in a - ``urllib3.exceptions.HTTPException``-extending exception. (Issue #326) - - * All errors during a retry-enabled request should be wrapped in - ``urllib3.exceptions.MaxRetryError``, including timeout-related exceptions - which were previously exempt. Underlying error is accessible from the - ``.reason`` property. (Issue #326) - - * ``urllib3.exceptions.ConnectionError`` renamed to - ``urllib3.exceptions.ProtocolError``. (Issue #326) - - * Errors during response read (such as IncompleteRead) are now wrapped in - ``urllib3.exceptions.ProtocolError``. (Issue #418) - - * Requesting an empty host will raise ``urllib3.exceptions.LocationValueError``. - (Issue #417) - - * Catch read timeouts over SSL connections as - ``urllib3.exceptions.ReadTimeoutError``. (Issue #419) - - * Apply socket arguments before connecting. (Issue #427) - - - 1.8.3 (2014-06-23) - ------------------ - - * Fix TLS verification when using a proxy in Python 3.4.1. (Issue #385) - - * Add ``disable_cache`` option to ``urllib3.util.make_headers``. (Issue #393) - - * Wrap ``socket.timeout`` exception with - ``urllib3.exceptions.ReadTimeoutError``. (Issue #399) - - * Fixed proxy-related bug where connections were being reused incorrectly. - (Issues #366, #369) - - * Added ``socket_options`` keyword parameter which allows to define - ``setsockopt`` configuration of new sockets. (Issue #397) - - * Removed ``HTTPConnection.tcp_nodelay`` in favor of - ``HTTPConnection.default_socket_options``. (Issue #397) - - * Fixed ``TypeError`` bug in Python 2.6.4. (Issue #411) - - - 1.8.2 (2014-04-17) - ------------------ - - * Fix ``urllib3.util`` not being included in the package. - - - 1.8.1 (2014-04-17) - ------------------ - - * Fix AppEngine bug of HTTPS requests going out as HTTP. (Issue #356) - - * Don't install ``dummyserver`` into ``site-packages`` as it's only needed - for the test suite. (Issue #362) - - * Added support for specifying ``source_address``. (Issue #352) - - - 1.8 (2014-03-04) - ---------------- - - * Improved url parsing in ``urllib3.util.parse_url`` (properly parse '@' in - username, and blank ports like 'hostname:'). - - * New ``urllib3.connection`` module which contains all the HTTPConnection - objects. - - * Several ``urllib3.util.Timeout``-related fixes. Also changed constructor - signature to a more sensible order. [Backwards incompatible] - (Issues #252, #262, #263) - - * Use ``backports.ssl_match_hostname`` if it's installed. (Issue #274) - - * Added ``.tell()`` method to ``urllib3.response.HTTPResponse`` which - returns the number of bytes read so far. (Issue #277) - - * Support for platforms without threading. (Issue #289) - - * Expand default-port comparison in ``HTTPConnectionPool.is_same_host`` - to allow a pool with no specified port to be considered equal to to an - HTTP/HTTPS url with port 80/443 explicitly provided. (Issue #305) - - * Improved default SSL/TLS settings to avoid vulnerabilities. - (Issue #309) - - * Fixed ``urllib3.poolmanager.ProxyManager`` not retrying on connect errors. - (Issue #310) - - * Disable Nagle's Algorithm on the socket for non-proxies. A subset of requests - will send the entire HTTP request ~200 milliseconds faster; however, some of - the resulting TCP packets will be smaller. (Issue #254) - - * Increased maximum number of SubjectAltNames in ``urllib3.contrib.pyopenssl`` - from the default 64 to 1024 in a single certificate. (Issue #318) - - * Headers are now passed and stored as a custom - ``urllib3.collections_.HTTPHeaderDict`` object rather than a plain ``dict``. - (Issue #329, #333) - - * Headers no longer lose their case on Python 3. (Issue #236) - - * ``urllib3.contrib.pyopenssl`` now uses the operating system's default CA - certificates on inject. (Issue #332) - - * Requests with ``retries=False`` will immediately raise any exceptions without - wrapping them in ``MaxRetryError``. (Issue #348) - - * Fixed open socket leak with SSL-related failures. (Issue #344, #348) - - - 1.7.1 (2013-09-25) - ------------------ - - * Added granular timeout support with new ``urllib3.util.Timeout`` class. - (Issue #231) - - * Fixed Python 3.4 support. (Issue #238) - - - 1.7 (2013-08-14) - ---------------- - - * More exceptions are now pickle-able, with tests. (Issue #174) - - * Fixed redirecting with relative URLs in Location header. (Issue #178) - - * Support for relative urls in ``Location: ...`` header. (Issue #179) - - * ``urllib3.response.HTTPResponse`` now inherits from ``io.IOBase`` for bonus - file-like functionality. (Issue #187) - - * Passing ``assert_hostname=False`` when creating a HTTPSConnectionPool will - skip hostname verification for SSL connections. (Issue #194) - - * New method ``urllib3.response.HTTPResponse.stream(...)`` which acts as a - generator wrapped around ``.read(...)``. (Issue #198) - - * IPv6 url parsing enforces brackets around the hostname. (Issue #199) - - * Fixed thread race condition in - ``urllib3.poolmanager.PoolManager.connection_from_host(...)`` (Issue #204) - - * ``ProxyManager`` requests now include non-default port in ``Host: ...`` - header. (Issue #217) - - * Added HTTPS proxy support in ``ProxyManager``. (Issue #170 #139) - - * New ``RequestField`` object can be passed to the ``fields=...`` param which - can specify headers. (Issue #220) - - * Raise ``urllib3.exceptions.ProxyError`` when connecting to proxy fails. - (Issue #221) - - * Use international headers when posting file names. (Issue #119) - - * Improved IPv6 support. (Issue #203) - - - 1.6 (2013-04-25) - ---------------- - - * Contrib: Optional SNI support for Py2 using PyOpenSSL. (Issue #156) - - * ``ProxyManager`` automatically adds ``Host: ...`` header if not given. - - * Improved SSL-related code. ``cert_req`` now optionally takes a string like - "REQUIRED" or "NONE". Same with ``ssl_version`` takes strings like "SSLv23" - The string values reflect the suffix of the respective constant variable. - (Issue #130) - - * Vendored ``socksipy`` now based on Anorov's fork which handles unexpectedly - closed proxy connections and larger read buffers. (Issue #135) - - * Ensure the connection is closed if no data is received, fixes connection leak - on some platforms. (Issue #133) - - * Added SNI support for SSL/TLS connections on Py32+. (Issue #89) - - * Tests fixed to be compatible with Py26 again. (Issue #125) - - * Added ability to choose SSL version by passing an ``ssl.PROTOCOL_*`` constant - to the ``ssl_version`` parameter of ``HTTPSConnectionPool``. (Issue #109) - - * Allow an explicit content type to be specified when encoding file fields. - (Issue #126) - - * Exceptions are now pickleable, with tests. (Issue #101) - - * Fixed default headers not getting passed in some cases. (Issue #99) - - * Treat "content-encoding" header value as case-insensitive, per RFC 2616 - Section 3.5. (Issue #110) - - * "Connection Refused" SocketErrors will get retried rather than raised. - (Issue #92) - - * Updated vendored ``six``, no longer overrides the global ``six`` module - namespace. (Issue #113) - - * ``urllib3.exceptions.MaxRetryError`` contains a ``reason`` property holding - the exception that prompted the final retry. If ``reason is None`` then it - was due to a redirect. (Issue #92, #114) - - * Fixed ``PoolManager.urlopen()`` from not redirecting more than once. - (Issue #149) - - * Don't assume ``Content-Type: text/plain`` for multi-part encoding parameters - that are not files. (Issue #111) - - * Pass `strict` param down to ``httplib.HTTPConnection``. (Issue #122) - - * Added mechanism to verify SSL certificates by fingerprint (md5, sha1) or - against an arbitrary hostname (when connecting by IP or for misconfigured - servers). (Issue #140) - - * Streaming decompression support. (Issue #159) - - - 1.5 (2012-08-02) - ---------------- - - * Added ``urllib3.add_stderr_logger()`` for quickly enabling STDERR debug - logging in urllib3. - - * Native full URL parsing (including auth, path, query, fragment) available in - ``urllib3.util.parse_url(url)``. - - * Built-in redirect will switch method to 'GET' if status code is 303. - (Issue #11) - - * ``urllib3.PoolManager`` strips the scheme and host before sending the request - uri. (Issue #8) - - * New ``urllib3.exceptions.DecodeError`` exception for when automatic decoding, - based on the Content-Type header, fails. - - * Fixed bug with pool depletion and leaking connections (Issue #76). Added - explicit connection closing on pool eviction. Added - ``urllib3.PoolManager.clear()``. - - * 99% -> 100% unit test coverage. - - - 1.4 (2012-06-16) - ---------------- - - * Minor AppEngine-related fixes. - - * Switched from ``mimetools.choose_boundary`` to ``uuid.uuid4()``. - - * Improved url parsing. (Issue #73) - - * IPv6 url support. (Issue #72) - - - 1.3 (2012-03-25) - ---------------- - - * Removed pre-1.0 deprecated API. - - * Refactored helpers into a ``urllib3.util`` submodule. - - * Fixed multipart encoding to support list-of-tuples for keys with multiple - values. (Issue #48) - - * Fixed multiple Set-Cookie headers in response not getting merged properly in - Python 3. (Issue #53) - - * AppEngine support with Py27. (Issue #61) - - * Minor ``encode_multipart_formdata`` fixes related to Python 3 strings vs - bytes. - - - 1.2.2 (2012-02-06) - ------------------ - - * Fixed packaging bug of not shipping ``test-requirements.txt``. (Issue #47) - - - 1.2.1 (2012-02-05) - ------------------ - - * Fixed another bug related to when ``ssl`` module is not available. (Issue #41) - - * Location parsing errors now raise ``urllib3.exceptions.LocationParseError`` - which inherits from ``ValueError``. - - - 1.2 (2012-01-29) - ---------------- - - * Added Python 3 support (tested on 3.2.2) - - * Dropped Python 2.5 support (tested on 2.6.7, 2.7.2) - - * Use ``select.poll`` instead of ``select.select`` for platforms that support - it. - - * Use ``Queue.LifoQueue`` instead of ``Queue.Queue`` for more aggressive - connection reusing. Configurable by overriding ``ConnectionPool.QueueCls``. - - * Fixed ``ImportError`` during install when ``ssl`` module is not available. - (Issue #41) - - * Fixed ``PoolManager`` redirects between schemes (such as HTTP -> HTTPS) not - completing properly. (Issue #28, uncovered by Issue #10 in v1.1) - - * Ported ``dummyserver`` to use ``tornado`` instead of ``webob`` + - ``eventlet``. Removed extraneous unsupported dummyserver testing backends. - Added socket-level tests. - - * More tests. Achievement Unlocked: 99% Coverage. - - - 1.1 (2012-01-07) - ---------------- - - * Refactored ``dummyserver`` to its own root namespace module (used for - testing). - - * Added hostname verification for ``VerifiedHTTPSConnection`` by vendoring in - Py32's ``ssl_match_hostname``. (Issue #25) - - * Fixed cross-host HTTP redirects when using ``PoolManager``. (Issue #10) - - * Fixed ``decode_content`` being ignored when set through ``urlopen``. (Issue - #27) - - * Fixed timeout-related bugs. (Issues #17, #23) - - - 1.0.2 (2011-11-04) - ------------------ - - * Fixed typo in ``VerifiedHTTPSConnection`` which would only present as a bug if - you're using the object manually. (Thanks pyos) - - * Made RecentlyUsedContainer (and consequently PoolManager) more thread-safe by - wrapping the access log in a mutex. (Thanks @christer) - - * Made RecentlyUsedContainer more dict-like (corrected ``__delitem__`` and - ``__getitem__`` behaviour), with tests. Shouldn't affect core urllib3 code. - - - 1.0.1 (2011-10-10) - ------------------ - - * Fixed a bug where the same connection would get returned into the pool twice, - causing extraneous "HttpConnectionPool is full" log warnings. - - - 1.0 (2011-10-08) - ---------------- - - * Added ``PoolManager`` with LRU expiration of connections (tested and - documented). - * Added ``ProxyManager`` (needs tests, docs, and confirmation that it works - with HTTPS proxies). - * Added optional partial-read support for responses when - ``preload_content=False``. You can now make requests and just read the headers - without loading the content. - * Made response decoding optional (default on, same as before). - * Added optional explicit boundary string for ``encode_multipart_formdata``. - * Convenience request methods are now inherited from ``RequestMethods``. Old - helpers like ``get_url`` and ``post_url`` should be abandoned in favour of - the new ``request(method, url, ...)``. - * Refactored code to be even more decoupled, reusable, and extendable. - * License header added to ``.py`` files. - * Embiggened the documentation: Lots of Sphinx-friendly docstrings in the code - and docs in ``docs/`` and on https://urllib3.readthedocs.io/. - * Embettered all the things! - * Started writing this file. - - - 0.4.1 (2011-07-17) - ------------------ - - * Minor bug fixes, code cleanup. - - - 0.4 (2011-03-01) - ---------------- - - * Better unicode support. - * Added ``VerifiedHTTPSConnection``. - * Added ``NTLMConnectionPool`` in contrib. - * Minor improvements. - - - 0.3.1 (2010-07-13) - ------------------ - - * Added ``assert_host_name`` optional parameter. Now compatible with proxies. - - - 0.3 (2009-12-10) - ---------------- - - * Added HTTPS support. - * Minor bug fixes. - * Refactored, broken backwards compatibility with 0.2. - * API to be treated as stable from this version forward. - - - 0.2 (2008-11-17) - ---------------- - - * Added unit tests. - * Bug fixes. - - - 0.1 (2008-11-16) - ---------------- - - * First release. - -Keywords: urllib httplib threadsafe filepost http https ssl pooling -Platform: UNKNOWN -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: Software Development :: Libraries -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 -Provides-Extra: brotli -Provides-Extra: secure -Provides-Extra: socks diff --git a/third_party/python/urllib3/README.rst b/third_party/python/urllib3/README.rst deleted file mode 100644 index 07a5070ccb5c..000000000000 --- a/third_party/python/urllib3/README.rst +++ /dev/null @@ -1,104 +0,0 @@ -urllib3 -======= - -urllib3 is a powerful, *sanity-friendly* HTTP client for Python. Much of the -Python ecosystem already uses urllib3 and you should too. -urllib3 brings many critical features that are missing from the Python -standard libraries: - -- Thread safety. -- Connection pooling. -- Client-side SSL/TLS verification. -- File uploads with multipart encoding. -- Helpers for retrying requests and dealing with HTTP redirects. -- Support for gzip, deflate, and brotli encoding. -- Proxy support for HTTP and SOCKS. -- 100% test coverage. - -urllib3 is powerful and easy to use:: - - >>> import urllib3 - >>> http = urllib3.PoolManager() - >>> r = http.request('GET', 'http://httpbin.org/robots.txt') - >>> r.status - 200 - >>> r.data - 'User-agent: *\nDisallow: /deny\n' - - -Installing ----------- - -urllib3 can be installed with `pip `_:: - - $ pip install urllib3 - -Alternatively, you can grab the latest source code from `GitHub `_:: - - $ git clone git://github.com/urllib3/urllib3.git - $ python setup.py install - - -Documentation -------------- - -urllib3 has usage and reference documentation at `urllib3.readthedocs.io `_. - - -Contributing ------------- - -urllib3 happily accepts contributions. Please see our -`contributing documentation `_ -for some tips on getting started. - - -Security Disclosures --------------------- - -To report a security vulnerability, please use the -`Tidelift security contact `_. -Tidelift will coordinate the fix and disclosure with maintainers. - -Maintainers ------------ - -- `@sethmlarson `_ (Seth M. Larson) -- `@pquentin `_ (Quentin Pradet) -- `@theacodes `_ (Thea Flowers) -- `@haikuginger `_ (Jess Shapiro) -- `@lukasa `_ (Cory Benfield) -- `@sigmavirus24 `_ (Ian Stapleton Cordasco) -- `@shazow `_ (Andrey Petrov) - -👋 - - -Sponsorship ------------ - -.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png - :width: 75 - :alt: Tidelift - -.. list-table:: - :widths: 10 100 - - * - |tideliftlogo| - - Professional support for urllib3 is available as part of the `Tidelift - Subscription`_. Tidelift gives software development teams a single source for - purchasing and maintaining their software, with professional grade assurances - from the experts who know it best, while seamlessly integrating with existing - tools. - -.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme - -If your company benefits from this library, please consider `sponsoring its -development `_. - -Sponsors include: - -- Abbott (2018-2019), sponsored `@sethmlarson `_'s work on urllib3. -- Google Cloud Platform (2018-2019), sponsored `@theacodes `_'s work on urllib3. -- Akamai (2017-2018), sponsored `@haikuginger `_'s work on urllib3 -- Hewlett Packard Enterprise (2016-2017), sponsored `@Lukasa’s `_ work on urllib3. diff --git a/third_party/python/urllib3/dev-requirements.txt b/third_party/python/urllib3/dev-requirements.txt deleted file mode 100644 index e6b480eec374..000000000000 --- a/third_party/python/urllib3/dev-requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -mock==3.0.5 -coverage~=5.0 -tornado==5.1.1;python_version<="2.7" -tornado==6.0.3;python_version>="3.5" -PySocks==1.7.1 -# https://github.com/Anorov/PySocks/issues/131 -win-inet-pton==1.1.0 -pytest==4.6.9 -pytest-timeout==1.3.4 -flaky==3.6.1 -trustme==0.5.3 -cryptography==2.8 -gcp-devrel-py-tools==0.0.15 - -# https://github.com/GoogleCloudPlatform/python-repo-tools/issues/23 -pylint<2.0;python_version<="2.7" diff --git a/third_party/python/urllib3/dummyserver/__init__.py b/third_party/python/urllib3/dummyserver/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/urllib3/dummyserver/certs/README.rst b/third_party/python/urllib3/dummyserver/certs/README.rst deleted file mode 100644 index 7c712b6e15a2..000000000000 --- a/third_party/python/urllib3/dummyserver/certs/README.rst +++ /dev/null @@ -1,17 +0,0 @@ -Generating new certificates ---------------------------- - -Here's how you can regenerate the certificates:: - - import trustme - - ca = trustme.CA() - server_cert = ca.issue_cert(u"localhost") - - ca.cert_pem.write_to_path("cacert.pem") - ca.private_key_pem.write_to_path("cacert.key") - server_cert.cert_chain_pems[0].write_to_path("server.crt") - server_cert.private_key_pem.write_to_path("server.key") - -This will break a number of tests: you will need to update the -relevant fingerprints and hashes. diff --git a/third_party/python/urllib3/dummyserver/certs/cacert.key b/third_party/python/urllib3/dummyserver/certs/cacert.key deleted file mode 100644 index 58e1c201670c..000000000000 --- a/third_party/python/urllib3/dummyserver/certs/cacert.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAn330NEISY7w+GeZR2jh8Of1x2CtpenWRKuuD2u4FOaN0G1SN -pm6Owum6xzhv93jmj+tZrp9kYvC9HcvGrgzH9yP566pLLfY2SEEAJYNNeVdqegY5 -9W1wa6vEDN5UYruVEbymgPHoItiYhfndgEDbagPN5dhrdNvaRNI2c5zMmBDlzzhC -G7AZbXuthTp6OwTVye71f2lnNhKi6rzWtre/ji88fq8Qm406l29O1RTzmNttN5BZ -nPWU9v4GnCYKXdY6BN1Ub6z8C9hna/oRgBqa0Zbv7kEuAuqhsFQeuFCfBhQm7NdP -d/7Kh6LS+VIiCu3AOccZHOuFOjtHb/KyndmgCwIDAQABAoIBAGQg9wc308O5kmNA -LXMKszLU4nwMBRRUaua/JPB1LeKZs3LVCnjKP+YuRox76g87X8RKxOrUNnnHGXNz -UzBB5ehKNcS2DKy2Pi3uYOEsJZ9gOgCRmCF0q3dtRo+tpNy3V0bjYMTjGhGGWXsC -+wRhs15DNShvTkb3H3jFYFoEvo1YUKsvImBWJGwDbdDMfMZv4aeBWXlOrF+2fwt2 -TM3G1o8xzEEWBB4FLZBW+tq2zfUSa1KwqqyQ4ZIqXepjQcN6nNfuHADA+nxuruVV -LPUhz4ZmsBEnJ7CL9zWJkLUw/al9/6Q14tleRmiZTTztqAlFgZUpNhaKSzVdsIc/ -Xz3+OgECgYEAzgNu7eFJAOzq+ZVFRrrbA7tu+f318FTCaADJ1kFgAJyj6b9yOGan -LNL4TfXVjzgqtfQ4AIVqEHwXO7yS+YgTprvgzqRxqNRZ6ikuo2IPkIwXIAXZAlwd -JsWLPBXOlOFW6LHvhYxjY2xF+A9y4AbuZ3UDRUQ+tp226VfEaeY80+ECgYEAxjDV -cJqeBO06YRVGmcXfAYwRLJGT4hvIZeiSbxX/kJ0rx+cYLT/XZbAguJYQ5ZK2lkeA -YneXYDlSTxmBxHxiWwWe3mcmctdE4Jbw8oIZ8a49a4KE/F2ojC4gmisIt3/OqGOw -C4e/pDCE/QV64LWdazgUWHPGoVEmZx9/oMm/MWsCgYEAsLtlSJFB7ZdRpTcXLSxT -gwoilDf36mrsNAipHjMLRrsaKwbf197If72k4kyJHspSabHO8TOC4A10aPzHIWZJ -ZXo7y0prbyhs0mLt7Z/MNnbXx9L8bffT0lUZszwJ8tK1mf47utfK05opFDs8k0+e -6gYJ/jwjiMoYBmoSx76KZEECgYBagJxHAmQcbdQV1yhZOhFe3H5PMt8sBnHZj32m -+o2slQkUDQRuTVPoHKikgeqPWxLDxzzqOiBHEYXzlvs6JW6okAV/G+1jzcenI2Y9 -54k/YsirWnut3nsEIGBE5lfhq5xMKtGOQlwR9xITlLgK+wQ6nO41ghD3Q15dAvY+ -D0KepwKBgQChHvbyzw0t76J2gLxUSyuG7VsId651bpqTYUsbSDFlRo4g8UbBAkHd -fdv5BOon3ALJFreSK+a78es0kpiLwrS2SqG/y3mb9aUoLpCVB1haDmmP4Rn4AYXz -OCfUkusuSoXOR8CMjqkXYl5QjeJAUAt9GTsZnXIbOQKbaZwkeV0HEg== ------END RSA PRIVATE KEY----- diff --git a/third_party/python/urllib3/dummyserver/certs/cacert.pem b/third_party/python/urllib3/dummyserver/certs/cacert.pem deleted file mode 100644 index 710b8fbd98a5..000000000000 --- a/third_party/python/urllib3/dummyserver/certs/cacert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDfzCCAmegAwIBAgIUVGEi+7bkaGRIPoQrp9zFFAT5JYQwDQYJKoZIhvcNAQEL -BQAwQDEXMBUGA1UECgwOdHJ1c3RtZSB2MC41LjMxJTAjBgNVBAsMHFRlc3Rpbmcg -Q0EgIzdEUWJWOTBzV2xZSEstY0wwHhcNMDAwMTAxMDAwMDAwWhcNMzgwMTAxMDAw -MDAwWjBAMRcwFQYDVQQKDA50cnVzdG1lIHYwLjUuMzElMCMGA1UECwwcVGVzdGlu -ZyBDQSAjN0RRYlY5MHNXbFlISy1jTDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAJ999DRCEmO8PhnmUdo4fDn9cdgraXp1kSrrg9ruBTmjdBtUjaZujsLp -usc4b/d45o/rWa6fZGLwvR3Lxq4Mx/cj+euqSy32NkhBACWDTXlXanoGOfVtcGur -xAzeVGK7lRG8poDx6CLYmIX53YBA22oDzeXYa3Tb2kTSNnOczJgQ5c84QhuwGW17 -rYU6ejsE1cnu9X9pZzYSouq81ra3v44vPH6vEJuNOpdvTtUU85jbbTeQWZz1lPb+ -BpwmCl3WOgTdVG+s/AvYZ2v6EYAamtGW7+5BLgLqobBUHrhQnwYUJuzXT3f+yoei -0vlSIgrtwDnHGRzrhTo7R2/ysp3ZoAsCAwEAAaNxMG8wHQYDVR0OBBYEFHWf39Hn -rdChKjsOBoBGn1U+0VgxMBIGA1UdEwEB/wQIMAYBAf8CAQkwDgYDVR0PAQH/BAQD -AgEGMCoGA1UdJQEB/wQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMw -DQYJKoZIhvcNAQELBQADggEBAIAylnWX2WTB+mrVVpE2W8i0HollTMJIPJA9Jq3Q -/t2uPjXDEAVAcBmQju8qy2tHpamvzpQseVm3EF3UFNlGxwOGKsTzU4J45qOJITZk -eLRAcWNEt6cgqj8ml8PuMHU7oDnp7pP6VPe5KQH1a0FYQnDNEwg7MyX+GjnXeRwd -re6y9nMC+XKCYUAd1/nQcrZdnSsws1M5lzXir2vuyyN9EUkf2xMMKA2E1s0f+5he -3eNghAXtZw616ITBoMb7ckG6a0+YobbiQ0tKgB8D3MG2544Gx6xhCXf7pX4q4g// -1nTPeYFsBDyqEOEhcW1o9/MSSbjpUJC+QUmCb2Y1wYeum+w= ------END CERTIFICATE----- diff --git a/third_party/python/urllib3/dummyserver/certs/server.crt b/third_party/python/urllib3/dummyserver/certs/server.crt deleted file mode 100644 index 24026c367a25..000000000000 --- a/third_party/python/urllib3/dummyserver/certs/server.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDeTCCAmGgAwIBAgIUQeadxkH6YMoSecB2rNbFEr1u1kUwDQYJKoZIhvcNAQEL -BQAwQDEXMBUGA1UECgwOdHJ1c3RtZSB2MC41LjMxJTAjBgNVBAsMHFRlc3Rpbmcg -Q0EgIzdEUWJWOTBzV2xZSEstY0wwHhcNMDAwMTAxMDAwMDAwWhcNMzgwMTAxMDAw -MDAwWjBCMRcwFQYDVQQKDA50cnVzdG1lIHYwLjUuMzEnMCUGA1UECwweVGVzdGlu -ZyBjZXJ0ICMtSGRsMnMyTEYyeVp0NDFOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArRLZX+5dyCh4N7q90sH2Q4Ea6QLK8OfoUQPWtpzAtINDUAdfSXCC -/qYTtGeSCGjB4W0LfvRTI8afHoD/M+YpaCRnx7T1sy1taA2rnGrEVXEHalVP+RI4 -t4ZWtX56aez2M0Fs6o4MtzAuP6fKgSdWzIvOmtCxqn0Zf2KbfEHnQylsy2LgPa/x -Lg50fbZ195+h4EAB3d2/jqaeFGGhN+7zrrv4+L1eeW3bzOkvPEkTNepq3Gy/8r5e -0i2icEnM+eBfl8NYgQ1toJYvDIy5Qi2TRzaFxBVmqUOc8EFtHpL7E9YLbTTW15xd -oLVLdXI5igGxkwPYoeiiAJWxIsC/hL1RRQIDAQABo2kwZzAdBgNVHQ4EFgQUMU6+ -uwNmL8TxLwjrj7jzzlwDPiowDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBR1n9/R -563QoSo7DgaARp9VPtFYMTAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwDQYJKoZI -hvcNAQELBQADggEBAJ6w5neQKw+/efA/I3IHzt8GaSHQ/YehMHx8GxCViJUmLg6P -Vf74k856Knvh7IsVaqF1uRi6qQaFPik6CwtBCj7/ZftdseOCDljd+8EWyQ+ZWie7 -+tzMIdQWZxYSdR9Ov42VD++a6oWJtfJhWV5eyDit99FFK31/M1ZXoceiDS5AsIG6 -wfsxrFj1qV9pLNSIlfrnycYhYx7avVJTf+2mfZgTO9Tx+VPapkZrfCnP/2jpN39u -zblFFjP9Ir0QqBw7MXjVX+Y1HkQ2TQnEeSsp1HuFRIZYx72Cttnckv1Lxcx/HiQB -oebTDYiRfxOAEeIMgIhX88Jca8vNIRcXDeGK9mU= ------END CERTIFICATE----- diff --git a/third_party/python/urllib3/dummyserver/certs/server.key b/third_party/python/urllib3/dummyserver/certs/server.key deleted file mode 100644 index 592ee6bea213..000000000000 --- a/third_party/python/urllib3/dummyserver/certs/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEArRLZX+5dyCh4N7q90sH2Q4Ea6QLK8OfoUQPWtpzAtINDUAdf -SXCC/qYTtGeSCGjB4W0LfvRTI8afHoD/M+YpaCRnx7T1sy1taA2rnGrEVXEHalVP -+RI4t4ZWtX56aez2M0Fs6o4MtzAuP6fKgSdWzIvOmtCxqn0Zf2KbfEHnQylsy2Lg -Pa/xLg50fbZ195+h4EAB3d2/jqaeFGGhN+7zrrv4+L1eeW3bzOkvPEkTNepq3Gy/ -8r5e0i2icEnM+eBfl8NYgQ1toJYvDIy5Qi2TRzaFxBVmqUOc8EFtHpL7E9YLbTTW -15xdoLVLdXI5igGxkwPYoeiiAJWxIsC/hL1RRQIDAQABAoIBAQCZ/62f6G9WDHx7 -yhPhlmjTw+r37l45YYCbpbjFoFDvzeR1LzogFJbak1fxLD8KcHwjY23ZNvlLWg53 -i/yIZ4Hsgog9cM0283LoJVHPykiMZhhdCzAvxYDl/AjnUXUHD6w6CzsoseCql5pv -VZOgvCpFsxjRNGUB+HJZoJoNRG7MmHaY638pGHGMiVbskT9Ww3emtMLdTKy1rQcj -9XO/4mlaBGD79wYxy5Hlysbh2UYuQRv8XN5V46Uugk6sC/i2G7VC8KkqPQ2pM+rA -LaeWSuN9dfBwiKcHtJssMP95ilsXsjqh3NoVuFODDXHv3u+nBAxtg2TnLZFkDZXH -FvxPJu8BAoGBANwWWzvl/dnTtVDFbhF/61v3AVZV4vVpokXRJKny05CZPZWROTc4 -LXMVw9kxeecNdo0yR4jn1yyNUmKnQpTmpsR9Yo9NYH+Z1CLxswpc7ILfVRZBK6bK -cCG43lM5xZprG6FXhqkHN2u9z5Y8/PuaMzC8iVs402/gakgPKmn8OjdhAoGBAMlQ -mmrx24n9YY/dOn55XC5V/iN3Z6mIsHThnDIU515bwLwZVG7chOLSiWHAh4JzUH+v -bV3NnlE1jhf5ln0WAadCtIeVprJG6msNTQlbTMTTV5kVNdbfYX6sFQEI+hC1LCiV -yJtuNIa4P5W/PtoC3FWUlcAH8C91S/M4CeZZ0HhlAoGBAIxflgE2SBrO9S53PiTb -OfqGKMwwK3nrzhxJsODUiCwKEUV8Qsn9gr+MekXlUKMV6y9Tily/wnYgDRPvKoBe -PK/GaT6NU6cPLka7cj6B1jgCyfpPxs+y/qIDj4n1pxs+hXj6omDcwXRutCBW9eRk -DZJgLhuIuxL4R9F+GsdOoLMBAoGAKQn1cLe9OXQd32YJ9p5m3EtLc49z4murDSiw -3sTEJcgukinXvIHX1SV2PCczeLRpRJ5OfUDddVCllt2agAVscNx4UOuA//bU8t3T -RoUGMVmkEeDxCMyg42HRJlTeJWnJhryCGK1up8gHrk8+UNMkd43CuVLk88fFo99Y -pUzJ4sECgYEAvBDTo3k3sD18qV6p6tQwy+MVjvQb9V81GHP18tYcVKta3LkkqUFa -3qSyVxi7gl3JtynG7NJ7+GDx6zxW2xUR72NTcJwWvesLI+1orM288pyNDVw9MJ/j -AyVFnW5SEYEqdizTnQxL+rQB4CyeHfwZx2/1/Qr0ezLGUJv51lnk4mQ= ------END RSA PRIVATE KEY----- diff --git a/third_party/python/urllib3/dummyserver/handlers.py b/third_party/python/urllib3/dummyserver/handlers.py deleted file mode 100644 index 696dbab07621..000000000000 --- a/third_party/python/urllib3/dummyserver/handlers.py +++ /dev/null @@ -1,328 +0,0 @@ -from __future__ import print_function - -import collections -import contextlib -import gzip -import json -import logging -import sys -import time -import zlib - -from io import BytesIO -from tornado.web import RequestHandler -from tornado import httputil -from datetime import datetime -from datetime import timedelta - -from urllib3.packages.six.moves.http_client import responses -from urllib3.packages.six.moves.urllib.parse import urlsplit -from urllib3.packages.six import binary_type, ensure_str - -log = logging.getLogger(__name__) - - -class Response(object): - def __init__(self, body="", status="200 OK", headers=None): - self.body = body - self.status = status - self.headers = headers or [("Content-type", "text/plain")] - - def __call__(self, request_handler): - status, reason = self.status.split(" ", 1) - request_handler.set_status(int(status), reason) - for header, value in self.headers: - request_handler.add_header(header, value) - - # chunked - if isinstance(self.body, list): - for item in self.body: - if not isinstance(item, bytes): - item = item.encode("utf8") - request_handler.write(item) - request_handler.flush() - else: - body = self.body - if not isinstance(body, bytes): - body = body.encode("utf8") - - request_handler.write(body) - - -RETRY_TEST_NAMES = collections.defaultdict(int) - - -class TestingApp(RequestHandler): - """ - Simple app that performs various operations, useful for testing an HTTP - library. - - Given any path, it will attempt to load a corresponding local method if - it exists. Status code 200 indicates success, 400 indicates failure. Each - method has its own conditions for success/failure. - """ - - def get(self): - """ Handle GET requests """ - self._call_method() - - def post(self): - """ Handle POST requests """ - self._call_method() - - def put(self): - """ Handle PUT requests """ - self._call_method() - - def options(self): - """ Handle OPTIONS requests """ - self._call_method() - - def head(self): - """ Handle HEAD requests """ - self._call_method() - - def _call_method(self): - """ Call the correct method in this class based on the incoming URI """ - req = self.request - req.params = {} - for k, v in req.arguments.items(): - req.params[k] = next(iter(v)) - - path = req.path[:] - if not path.startswith("/"): - path = urlsplit(path).path - - target = path[1:].split("/", 1)[0] - method = getattr(self, target, self.index) - - resp = method(req) - - if dict(resp.headers).get("Connection") == "close": - # FIXME: Can we kill the connection somehow? - pass - - resp(self) - - def index(self, _request): - "Render simple message" - return Response("Dummy server!") - - def certificate(self, request): - """Return the requester's certificate.""" - cert = request.get_ssl_certificate() - subject = dict() - if cert is not None: - subject = dict((k, v) for (k, v) in [y for z in cert["subject"] for y in z]) - return Response(json.dumps(subject)) - - def source_address(self, request): - """Return the requester's IP address.""" - return Response(request.remote_ip) - - def set_up(self, request): - test_type = request.params.get("test_type") - test_id = request.params.get("test_id") - if test_id: - print("\nNew test %s: %s" % (test_type, test_id)) - else: - print("\nNew test %s" % test_type) - return Response("Dummy server is ready!") - - def specific_method(self, request): - "Confirm that the request matches the desired method type" - method = request.params.get("method") - if method and not isinstance(method, str): - method = method.decode("utf8") - - if request.method != method: - return Response( - "Wrong method: %s != %s" % (method, request.method), - status="400 Bad Request", - ) - return Response() - - def upload(self, request): - "Confirm that the uploaded file conforms to specification" - # FIXME: This is a huge broken mess - param = request.params.get("upload_param", b"myfile").decode("ascii") - filename = request.params.get("upload_filename", b"").decode("utf-8") - size = int(request.params.get("upload_size", "0")) - files_ = request.files.get(param) - - if len(files_) != 1: - return Response( - "Expected 1 file for '%s', not %d" % (param, len(files_)), - status="400 Bad Request", - ) - file_ = files_[0] - - data = file_["body"] - if int(size) != len(data): - return Response( - "Wrong size: %d != %d" % (size, len(data)), status="400 Bad Request" - ) - - got_filename = file_["filename"] - if isinstance(got_filename, binary_type): - got_filename = got_filename.decode("utf-8") - - # Tornado can leave the trailing \n in place on the filename. - if filename != got_filename: - return Response( - u"Wrong filename: %s != %s" % (filename, file_.filename), - status="400 Bad Request", - ) - - return Response() - - def redirect(self, request): - "Perform a redirect to ``target``" - target = request.params.get("target", "/") - status = request.params.get("status", "303 See Other") - if len(status) == 3: - status = "%s Redirect" % status.decode("latin-1") - - headers = [("Location", target)] - return Response(status=status, headers=headers) - - def not_found(self, request): - return Response("Not found", status="404 Not Found") - - def multi_redirect(self, request): - "Performs a redirect chain based on ``redirect_codes``" - codes = request.params.get("redirect_codes", b"200").decode("utf-8") - head, tail = codes.split(",", 1) if "," in codes else (codes, None) - status = "{0} {1}".format(head, responses[int(head)]) - if not tail: - return Response("Done redirecting", status=status) - - headers = [("Location", "/multi_redirect?redirect_codes=%s" % tail)] - return Response(status=status, headers=headers) - - def keepalive(self, request): - if request.params.get("close", b"0") == b"1": - headers = [("Connection", "close")] - return Response("Closing", headers=headers) - - headers = [("Connection", "keep-alive")] - return Response("Keeping alive", headers=headers) - - def echo_params(self, request): - params = sorted( - [(ensure_str(k), ensure_str(v)) for k, v in request.params.items()] - ) - return Response(repr(params)) - - def sleep(self, request): - "Sleep for a specified amount of ``seconds``" - # DO NOT USE THIS, IT'S DEPRECATED. - # FIXME: Delete this once appengine tests are fixed to not use this handler. - seconds = float(request.params.get("seconds", "1")) - time.sleep(seconds) - return Response() - - def echo(self, request): - "Echo back the params" - if request.method == "GET": - return Response(request.query) - - return Response(request.body) - - def echo_uri(self, request): - "Echo back the requested URI" - return Response(request.uri) - - def encodingrequest(self, request): - "Check for UA accepting gzip/deflate encoding" - data = b"hello, world!" - encoding = request.headers.get("Accept-Encoding", "") - headers = None - if encoding == "gzip": - headers = [("Content-Encoding", "gzip")] - file_ = BytesIO() - with contextlib.closing( - gzip.GzipFile("", mode="w", fileobj=file_) - ) as zipfile: - zipfile.write(data) - data = file_.getvalue() - elif encoding == "deflate": - headers = [("Content-Encoding", "deflate")] - data = zlib.compress(data) - elif encoding == "garbage-gzip": - headers = [("Content-Encoding", "gzip")] - data = "garbage" - elif encoding == "garbage-deflate": - headers = [("Content-Encoding", "deflate")] - data = "garbage" - return Response(data, headers=headers) - - def headers(self, request): - return Response(json.dumps(dict(request.headers))) - - def successful_retry(self, request): - """ Handler which will return an error and then success - - It's not currently very flexible as the number of retries is hard-coded. - """ - test_name = request.headers.get("test-name", None) - if not test_name: - return Response("test-name header not set", status="400 Bad Request") - - RETRY_TEST_NAMES[test_name] += 1 - - if RETRY_TEST_NAMES[test_name] >= 2: - return Response("Retry successful!") - else: - return Response("need to keep retrying!", status="418 I'm A Teapot") - - def chunked(self, request): - return Response(["123"] * 4) - - def chunked_gzip(self, request): - chunks = [] - compressor = zlib.compressobj(6, zlib.DEFLATED, 16 + zlib.MAX_WBITS) - - for uncompressed in [b"123"] * 4: - chunks.append(compressor.compress(uncompressed)) - - chunks.append(compressor.flush()) - - return Response(chunks, headers=[("Content-Encoding", "gzip")]) - - def nbytes(self, request): - length = int(request.params.get("length")) - data = b"1" * length - return Response(data, headers=[("Content-Type", "application/octet-stream")]) - - def status(self, request): - status = request.params.get("status", "200 OK") - - return Response(status=status) - - def retry_after(self, request): - if datetime.now() - self.application.last_req < timedelta(seconds=1): - status = request.params.get("status", b"429 Too Many Requests") - return Response( - status=status.decode("utf-8"), headers=[("Retry-After", "1")] - ) - - self.application.last_req = datetime.now() - - return Response(status="200 OK") - - def redirect_after(self, request): - "Perform a redirect to ``target``" - date = request.params.get("date") - if date: - retry_after = str( - httputil.format_timestamp(datetime.fromtimestamp(float(date))) - ) - else: - retry_after = "1" - target = request.params.get("target", "/") - headers = [("Location", target), ("Retry-After", retry_after)] - return Response(status="303 See Other", headers=headers) - - def shutdown(self, request): - sys.exit() diff --git a/third_party/python/urllib3/dummyserver/proxy.py b/third_party/python/urllib3/dummyserver/proxy.py deleted file mode 100755 index c4f0b824f77a..000000000000 --- a/third_party/python/urllib3/dummyserver/proxy.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -# Simple asynchronous HTTP proxy with tunnelling (CONNECT). -# -# GET/POST proxying based on -# http://groups.google.com/group/python-tornado/msg/7bea08e7a049cf26 -# -# Copyright (C) 2012 Senko Rasic -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import sys -import socket - -import tornado.gen -import tornado.httpserver -import tornado.ioloop -import tornado.iostream -import tornado.web -import tornado.httpclient - -__all__ = ["ProxyHandler", "run_proxy"] - - -class ProxyHandler(tornado.web.RequestHandler): - SUPPORTED_METHODS = ["GET", "POST", "CONNECT"] - - @tornado.gen.coroutine - def get(self): - def handle_response(response): - if response.error and not isinstance( - response.error, tornado.httpclient.HTTPError - ): - self.set_status(500) - self.write("Internal server error:\n" + str(response.error)) - self.finish() - else: - self.set_status(response.code) - for header in ( - "Date", - "Cache-Control", - "Server", - "Content-Type", - "Location", - ): - v = response.headers.get(header) - if v: - self.set_header(header, v) - if response.body: - self.write(response.body) - self.finish() - - req = tornado.httpclient.HTTPRequest( - url=self.request.uri, - method=self.request.method, - body=self.request.body, - headers=self.request.headers, - follow_redirects=False, - allow_nonstandard_methods=True, - ) - - client = tornado.httpclient.AsyncHTTPClient() - try: - response = yield client.fetch(req) - yield handle_response(response) - except tornado.httpclient.HTTPError as e: - if hasattr(e, "response") and e.response: - yield handle_response(e.response) - else: - self.set_status(500) - self.write("Internal server error:\n" + str(e)) - self.finish() - - @tornado.gen.coroutine - def post(self): - yield self.get() - - @tornado.gen.coroutine - def connect(self): - host, port = self.request.uri.split(":") - client = self.request.connection.stream - - @tornado.gen.coroutine - def start_forward(reader, writer): - while True: - try: - data = yield reader.read_bytes(4096, partial=True) - except tornado.iostream.StreamClosedError: - break - if not data: - break - writer.write(data) - writer.close() - - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - upstream = tornado.iostream.IOStream(s) - yield upstream.connect((host, int(port))) - - client.write(b"HTTP/1.0 200 Connection established\r\n\r\n") - fu1 = start_forward(client, upstream) - fu2 = start_forward(upstream, client) - yield [fu1, fu2] - - -def run_proxy(port, start_ioloop=True): - """ - Run proxy on the specified port. If start_ioloop is True (default), - the tornado IOLoop will be started immediately. - """ - app = tornado.web.Application([(r".*", ProxyHandler)]) - app.listen(port) - ioloop = tornado.ioloop.IOLoop.instance() - if start_ioloop: - ioloop.start() - - -if __name__ == "__main__": - port = 8888 - if len(sys.argv) > 1: - port = int(sys.argv[1]) - - print("Starting HTTP proxy on port %d" % port) - run_proxy(port) diff --git a/third_party/python/urllib3/dummyserver/server.py b/third_party/python/urllib3/dummyserver/server.py deleted file mode 100755 index 68f383534ef7..000000000000 --- a/third_party/python/urllib3/dummyserver/server.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python - -""" -Dummy server used for unit testing. -""" -from __future__ import print_function - -import logging -import os -import sys -import threading -import socket -import warnings -import ssl -from datetime import datetime - -from urllib3.exceptions import HTTPWarning - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization -import tornado.httpserver -import tornado.ioloop -import tornado.netutil -import tornado.web -import trustme - - -log = logging.getLogger(__name__) - -CERTS_PATH = os.path.join(os.path.dirname(__file__), "certs") -DEFAULT_CERTS = { - "certfile": os.path.join(CERTS_PATH, "server.crt"), - "keyfile": os.path.join(CERTS_PATH, "server.key"), - "cert_reqs": ssl.CERT_OPTIONAL, - "ca_certs": os.path.join(CERTS_PATH, "cacert.pem"), -} -DEFAULT_CA = os.path.join(CERTS_PATH, "cacert.pem") -DEFAULT_CA_KEY = os.path.join(CERTS_PATH, "cacert.key") - - -def _resolves_to_ipv6(host): - """ Returns True if the system resolves host to an IPv6 address by default. """ - resolves_to_ipv6 = False - try: - for res in socket.getaddrinfo(host, None, socket.AF_UNSPEC): - af, _, _, _, _ = res - if af == socket.AF_INET6: - resolves_to_ipv6 = True - except socket.gaierror: - pass - - return resolves_to_ipv6 - - -def _has_ipv6(host): - """ Returns True if the system can bind an IPv6 address. """ - sock = None - has_ipv6 = False - - if socket.has_ipv6: - # has_ipv6 returns true if cPython was compiled with IPv6 support. - # It does not tell us if the system has IPv6 support enabled. To - # determine that we must bind to an IPv6 address. - # https://github.com/urllib3/urllib3/pull/611 - # https://bugs.python.org/issue658327 - try: - sock = socket.socket(socket.AF_INET6) - sock.bind((host, 0)) - has_ipv6 = _resolves_to_ipv6("localhost") - except Exception: - pass - - if sock: - sock.close() - return has_ipv6 - - -# Some systems may have IPv6 support but DNS may not be configured -# properly. We can not count that localhost will resolve to ::1 on all -# systems. See https://github.com/urllib3/urllib3/pull/611 and -# https://bugs.python.org/issue18792 -HAS_IPV6_AND_DNS = _has_ipv6("localhost") -HAS_IPV6 = _has_ipv6("::1") - - -# Different types of servers we have: - - -class NoIPv6Warning(HTTPWarning): - "IPv6 is not available" - pass - - -class SocketServerThread(threading.Thread): - """ - :param socket_handler: Callable which receives a socket argument for one - request. - :param ready_event: Event which gets set when the socket handler is - ready to receive requests. - """ - - USE_IPV6 = HAS_IPV6_AND_DNS - - def __init__(self, socket_handler, host="localhost", port=8081, ready_event=None): - threading.Thread.__init__(self) - self.daemon = True - - self.socket_handler = socket_handler - self.host = host - self.ready_event = ready_event - - def _start_server(self): - if self.USE_IPV6: - sock = socket.socket(socket.AF_INET6) - else: - warnings.warn("No IPv6 support. Falling back to IPv4.", NoIPv6Warning) - sock = socket.socket(socket.AF_INET) - if sys.platform != "win32": - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((self.host, 0)) - self.port = sock.getsockname()[1] - - # Once listen() returns, the server socket is ready - sock.listen(1) - - if self.ready_event: - self.ready_event.set() - - self.socket_handler(sock) - sock.close() - - def run(self): - self.server = self._start_server() - - -def run_tornado_app(app, io_loop, certs, scheme, host): - assert io_loop == tornado.ioloop.IOLoop.current() - - # We can't use fromtimestamp(0) because of CPython issue 29097, so we'll - # just construct the datetime object directly. - app.last_req = datetime(1970, 1, 1) - - if scheme == "https": - http_server = tornado.httpserver.HTTPServer(app, ssl_options=certs) - else: - http_server = tornado.httpserver.HTTPServer(app) - - sockets = tornado.netutil.bind_sockets(None, address=host) - port = sockets[0].getsockname()[1] - http_server.add_sockets(sockets) - return http_server, port - - -def run_loop_in_thread(io_loop): - t = threading.Thread(target=io_loop.start) - t.start() - return t - - -def get_unreachable_address(): - # reserved as per rfc2606 - return ("something.invalid", 54321) - - -if __name__ == "__main__": - # For debugging dummyserver itself - python -m dummyserver.server - from .testcase import TestingApp - - host = "127.0.0.1" - - io_loop = tornado.ioloop.IOLoop.current() - app = tornado.web.Application([(r".*", TestingApp)]) - server, port = run_tornado_app(app, io_loop, None, "http", host) - server_thread = run_loop_in_thread(io_loop) - - print("Listening on http://{host}:{port}".format(host=host, port=port)) - - -def encrypt_key_pem(private_key_pem, password): - private_key = serialization.load_pem_private_key( - private_key_pem.bytes(), password=None, backend=default_backend() - ) - encrypted_key = private_key.private_bytes( - serialization.Encoding.PEM, - serialization.PrivateFormat.TraditionalOpenSSL, - serialization.BestAvailableEncryption(password), - ) - return trustme.Blob(encrypted_key) diff --git a/third_party/python/urllib3/dummyserver/testcase.py b/third_party/python/urllib3/dummyserver/testcase.py deleted file mode 100644 index 90c6b2240c85..000000000000 --- a/third_party/python/urllib3/dummyserver/testcase.py +++ /dev/null @@ -1,210 +0,0 @@ -import threading - -import pytest -from tornado import ioloop, web - -from dummyserver.server import ( - SocketServerThread, - run_tornado_app, - run_loop_in_thread, - DEFAULT_CERTS, - HAS_IPV6, -) -from dummyserver.handlers import TestingApp -from dummyserver.proxy import ProxyHandler - - -def consume_socket(sock, chunks=65536): - consumed = bytearray() - while True: - b = sock.recv(chunks) - consumed += b - if b.endswith(b"\r\n\r\n"): - break - return consumed - - -class SocketDummyServerTestCase(object): - """ - A simple socket-based server is created for this class that is good for - exactly one request. - """ - - scheme = "http" - host = "localhost" - - @classmethod - def _start_server(cls, socket_handler): - ready_event = threading.Event() - cls.server_thread = SocketServerThread( - socket_handler=socket_handler, ready_event=ready_event, host=cls.host - ) - cls.server_thread.start() - ready_event.wait(5) - if not ready_event.is_set(): - raise Exception("most likely failed to start server") - cls.port = cls.server_thread.port - - @classmethod - def start_response_handler(cls, response, num=1, block_send=None): - ready_event = threading.Event() - - def socket_handler(listener): - for _ in range(num): - ready_event.set() - - sock = listener.accept()[0] - consume_socket(sock) - if block_send: - block_send.wait() - block_send.clear() - sock.send(response) - sock.close() - - cls._start_server(socket_handler) - return ready_event - - @classmethod - def start_basic_handler(cls, **kw): - return cls.start_response_handler( - b"HTTP/1.1 200 OK\r\n" b"Content-Length: 0\r\n" b"\r\n", **kw - ) - - @classmethod - def teardown_class(cls): - if hasattr(cls, "server_thread"): - cls.server_thread.join(0.1) - - def assert_header_received( - self, received_headers, header_name, expected_value=None - ): - header_name = header_name.encode("ascii") - if expected_value is not None: - expected_value = expected_value.encode("ascii") - header_titles = [] - for header in received_headers: - key, value = header.split(b": ") - header_titles.append(key) - if key == header_name and expected_value is not None: - assert value == expected_value - assert header_name in header_titles - - -class IPV4SocketDummyServerTestCase(SocketDummyServerTestCase): - @classmethod - def _start_server(cls, socket_handler): - ready_event = threading.Event() - cls.server_thread = SocketServerThread( - socket_handler=socket_handler, ready_event=ready_event, host=cls.host - ) - cls.server_thread.USE_IPV6 = False - cls.server_thread.start() - ready_event.wait(5) - if not ready_event.is_set(): - raise Exception("most likely failed to start server") - cls.port = cls.server_thread.port - - -class HTTPDummyServerTestCase(object): - """ A simple HTTP server that runs when your test class runs - - Have your test class inherit from this one, and then a simple server - will start when your tests run, and automatically shut down when they - complete. For examples of what test requests you can send to the server, - see the TestingApp in dummyserver/handlers.py. - """ - - scheme = "http" - host = "localhost" - host_alt = "127.0.0.1" # Some tests need two hosts - certs = DEFAULT_CERTS - - @classmethod - def _start_server(cls): - cls.io_loop = ioloop.IOLoop.current() - app = web.Application([(r".*", TestingApp)]) - cls.server, cls.port = run_tornado_app( - app, cls.io_loop, cls.certs, cls.scheme, cls.host - ) - cls.server_thread = run_loop_in_thread(cls.io_loop) - - @classmethod - def _stop_server(cls): - cls.io_loop.add_callback(cls.server.stop) - cls.io_loop.add_callback(cls.io_loop.stop) - cls.server_thread.join() - - @classmethod - def setup_class(cls): - cls._start_server() - - @classmethod - def teardown_class(cls): - cls._stop_server() - - -class HTTPSDummyServerTestCase(HTTPDummyServerTestCase): - scheme = "https" - host = "localhost" - certs = DEFAULT_CERTS - - -class HTTPDummyProxyTestCase(object): - - http_host = "localhost" - http_host_alt = "127.0.0.1" - - https_host = "localhost" - https_host_alt = "127.0.0.1" - https_certs = DEFAULT_CERTS - - proxy_host = "localhost" - proxy_host_alt = "127.0.0.1" - - @classmethod - def setup_class(cls): - cls.io_loop = ioloop.IOLoop.current() - - app = web.Application([(r".*", TestingApp)]) - cls.http_server, cls.http_port = run_tornado_app( - app, cls.io_loop, None, "http", cls.http_host - ) - - app = web.Application([(r".*", TestingApp)]) - cls.https_server, cls.https_port = run_tornado_app( - app, cls.io_loop, cls.https_certs, "https", cls.http_host - ) - - app = web.Application([(r".*", ProxyHandler)]) - cls.proxy_server, cls.proxy_port = run_tornado_app( - app, cls.io_loop, None, "http", cls.proxy_host - ) - - cls.server_thread = run_loop_in_thread(cls.io_loop) - - @classmethod - def teardown_class(cls): - cls.io_loop.add_callback(cls.http_server.stop) - cls.io_loop.add_callback(cls.https_server.stop) - cls.io_loop.add_callback(cls.proxy_server.stop) - cls.io_loop.add_callback(cls.io_loop.stop) - cls.server_thread.join() - - -@pytest.mark.skipif(not HAS_IPV6, reason="IPv6 not available") -class IPv6HTTPDummyServerTestCase(HTTPDummyServerTestCase): - host = "::1" - - -@pytest.mark.skipif(not HAS_IPV6, reason="IPv6 not available") -class IPv6HTTPDummyProxyTestCase(HTTPDummyProxyTestCase): - - http_host = "localhost" - http_host_alt = "127.0.0.1" - - https_host = "localhost" - https_host_alt = "127.0.0.1" - https_certs = DEFAULT_CERTS - - proxy_host = "::1" - proxy_host_alt = "127.0.0.1" diff --git a/third_party/python/urllib3/setup.cfg b/third_party/python/urllib3/setup.cfg deleted file mode 100644 index 81b5727060f6..000000000000 --- a/third_party/python/urllib3/setup.cfg +++ /dev/null @@ -1,31 +0,0 @@ -[flake8] -ignore = E501, E203, W503, W504 -exclude = ./docs/conf.py,./src/urllib3/packages/* -max-line-length = 99 - -[bdist_wheel] -universal = 1 - -[metadata] -license_file = LICENSE.txt -provides-extra = - secure - socks - brotli -requires-dist = - pyOpenSSL>=0.14; extra == 'secure' - cryptography>=1.3.4; extra == 'secure' - idna>=2.0.0; extra == 'secure' - certifi; extra == 'secure' - ipaddress; python_version=="2.7" and extra == 'secure' - PySocks>=1.5.6,<2.0,!=1.5.7; extra == 'socks' - brotlipy>=0.6.0; extra == 'brotli' - -[tool:pytest] -xfail_strict = true -python_classes = Test *TestCase - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/urllib3/setup.py b/third_party/python/urllib3/setup.py deleted file mode 100755 index c0e1796fdc8b..000000000000 --- a/third_party/python/urllib3/setup.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - -from setuptools import setup - -import os -import re -import codecs - -base_path = os.path.dirname(__file__) - -# Get the version (borrowed from SQLAlchemy) -with open(os.path.join(base_path, "src", "urllib3", "__init__.py")) as fp: - VERSION = ( - re.compile(r""".*__version__ = ["'](.*?)['"]""", re.S).match(fp.read()).group(1) - ) - - -with codecs.open("README.rst", encoding="utf-8") as fp: - readme = fp.read() - -with codecs.open("CHANGES.rst", encoding="utf-8") as fp: - changes = fp.read() - -version = VERSION - -setup( - name="urllib3", - version=version, - description="HTTP library with thread-safe connection pooling, file post, and more.", - long_description=u"\n\n".join([readme, changes]), - classifiers=[ - "Environment :: Web Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Software Development :: Libraries", - ], - keywords="urllib httplib threadsafe filepost http https ssl pooling", - author="Andrey Petrov", - author_email="andrey.petrov@shazow.net", - url="https://urllib3.readthedocs.io/", - project_urls={ - "Documentation": "https://urllib3.readthedocs.io/", - "Code": "https://github.com/urllib3/urllib3", - "Issue tracker": "https://github.com/urllib3/urllib3/issues", - }, - license="MIT", - packages=[ - "urllib3", - "urllib3.packages", - "urllib3.packages.ssl_match_hostname", - "urllib3.packages.backports", - "urllib3.contrib", - "urllib3.contrib._securetransport", - "urllib3.util", - ], - package_dir={"": "src"}, - requires=[], - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4", - extras_require={ - "brotli": ["brotlipy>=0.6.0"], - "secure": [ - "pyOpenSSL>=0.14", - "cryptography>=1.3.4", - "idna>=2.0.0", - "certifi", - "ipaddress; python_version=='2.7'", - ], - "socks": ["PySocks>=1.5.6,<2.0,!=1.5.7"], - }, -) diff --git a/third_party/python/urllib3/src/urllib3.egg-info/PKG-INFO b/third_party/python/urllib3/src/urllib3.egg-info/PKG-INFO deleted file mode 100644 index d95b8c2d2741..000000000000 --- a/third_party/python/urllib3/src/urllib3.egg-info/PKG-INFO +++ /dev/null @@ -1,1253 +0,0 @@ -Metadata-Version: 2.1 -Name: urllib3 -Version: 1.25.9 -Summary: HTTP library with thread-safe connection pooling, file post, and more. -Home-page: https://urllib3.readthedocs.io/ -Author: Andrey Petrov -Author-email: andrey.petrov@shazow.net -License: MIT -Project-URL: Documentation, https://urllib3.readthedocs.io/ -Project-URL: Code, https://github.com/urllib3/urllib3 -Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues -Description: urllib3 - ======= - - urllib3 is a powerful, *sanity-friendly* HTTP client for Python. Much of the - Python ecosystem already uses urllib3 and you should too. - urllib3 brings many critical features that are missing from the Python - standard libraries: - - - Thread safety. - - Connection pooling. - - Client-side SSL/TLS verification. - - File uploads with multipart encoding. - - Helpers for retrying requests and dealing with HTTP redirects. - - Support for gzip, deflate, and brotli encoding. - - Proxy support for HTTP and SOCKS. - - 100% test coverage. - - urllib3 is powerful and easy to use:: - - >>> import urllib3 - >>> http = urllib3.PoolManager() - >>> r = http.request('GET', 'http://httpbin.org/robots.txt') - >>> r.status - 200 - >>> r.data - 'User-agent: *\nDisallow: /deny\n' - - - Installing - ---------- - - urllib3 can be installed with `pip `_:: - - $ pip install urllib3 - - Alternatively, you can grab the latest source code from `GitHub `_:: - - $ git clone git://github.com/urllib3/urllib3.git - $ python setup.py install - - - Documentation - ------------- - - urllib3 has usage and reference documentation at `urllib3.readthedocs.io `_. - - - Contributing - ------------ - - urllib3 happily accepts contributions. Please see our - `contributing documentation `_ - for some tips on getting started. - - - Security Disclosures - -------------------- - - To report a security vulnerability, please use the - `Tidelift security contact `_. - Tidelift will coordinate the fix and disclosure with maintainers. - - Maintainers - ----------- - - - `@sethmlarson `_ (Seth M. Larson) - - `@pquentin `_ (Quentin Pradet) - - `@theacodes `_ (Thea Flowers) - - `@haikuginger `_ (Jess Shapiro) - - `@lukasa `_ (Cory Benfield) - - `@sigmavirus24 `_ (Ian Stapleton Cordasco) - - `@shazow `_ (Andrey Petrov) - - 👋 - - - Sponsorship - ----------- - - .. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png - :width: 75 - :alt: Tidelift - - .. list-table:: - :widths: 10 100 - - * - |tideliftlogo| - - Professional support for urllib3 is available as part of the `Tidelift - Subscription`_. Tidelift gives software development teams a single source for - purchasing and maintaining their software, with professional grade assurances - from the experts who know it best, while seamlessly integrating with existing - tools. - - .. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme - - If your company benefits from this library, please consider `sponsoring its - development `_. - - Sponsors include: - - - Abbott (2018-2019), sponsored `@sethmlarson `_'s work on urllib3. - - Google Cloud Platform (2018-2019), sponsored `@theacodes `_'s work on urllib3. - - Akamai (2017-2018), sponsored `@haikuginger `_'s work on urllib3 - - Hewlett Packard Enterprise (2016-2017), sponsored `@Lukasa’s `_ work on urllib3. - - - Changes - ======= - - 1.25.9 (2020-04-16) - ------------------- - - * Added ``InvalidProxyConfigurationWarning`` which is raised when - erroneously specifying an HTTPS proxy URL. urllib3 doesn't currently - support connecting to HTTPS proxies but will soon be able to - and we would like users to migrate properly without much breakage. - - See `this GitHub issue `_ - for more information on how to fix your proxy config. (Pull #1851) - - * Drain connection after ``PoolManager`` redirect (Pull #1817) - - * Ensure ``load_verify_locations`` raises ``SSLError`` for all backends (Pull #1812) - - * Rename ``VerifiedHTTPSConnection`` to ``HTTPSConnection`` (Pull #1805) - - * Allow the CA certificate data to be passed as a string (Pull #1804) - - * Raise ``ValueError`` if method contains control characters (Pull #1800) - - * Add ``__repr__`` to ``Timeout`` (Pull #1795) - - - 1.25.8 (2020-01-20) - ------------------- - - * Drop support for EOL Python 3.4 (Pull #1774) - - * Optimize _encode_invalid_chars (Pull #1787) - - - 1.25.7 (2019-11-11) - ------------------- - - * Preserve ``chunked`` parameter on retries (Pull #1715, Pull #1734) - - * Allow unset ``SERVER_SOFTWARE`` in App Engine (Pull #1704, Issue #1470) - - * Fix issue where URL fragment was sent within the request target. (Pull #1732) - - * Fix issue where an empty query section in a URL would fail to parse. (Pull #1732) - - * Remove TLS 1.3 support in SecureTransport due to Apple removing support (Pull #1703) - - - 1.25.6 (2019-09-24) - ------------------- - - * Fix issue where tilde (``~``) characters were incorrectly - percent-encoded in the path. (Pull #1692) - - - 1.25.5 (2019-09-19) - ------------------- - - * Add mitigation for BPO-37428 affecting Python <3.7.4 and OpenSSL 1.1.1+ which - caused certificate verification to be enabled when using ``cert_reqs=CERT_NONE``. - (Issue #1682) - - - 1.25.4 (2019-09-19) - ------------------- - - * Propagate Retry-After header settings to subsequent retries. (Pull #1607) - - * Fix edge case where Retry-After header was still respected even when - explicitly opted out of. (Pull #1607) - - * Remove dependency on ``rfc3986`` for URL parsing. - - * Fix issue where URLs containing invalid characters within ``Url.auth`` would - raise an exception instead of percent-encoding those characters. - - * Add support for ``HTTPResponse.auto_close = False`` which makes HTTP responses - work well with BufferedReaders and other ``io`` module features. (Pull #1652) - - * Percent-encode invalid characters in URL for ``HTTPConnectionPool.request()`` (Pull #1673) - - - 1.25.3 (2019-05-23) - ------------------- - - * Change ``HTTPSConnection`` to load system CA certificates - when ``ca_certs``, ``ca_cert_dir``, and ``ssl_context`` are - unspecified. (Pull #1608, Issue #1603) - - * Upgrade bundled rfc3986 to v1.3.2. (Pull #1609, Issue #1605) - - - 1.25.2 (2019-04-28) - ------------------- - - * Change ``is_ipaddress`` to not detect IPvFuture addresses. (Pull #1583) - - * Change ``parse_url`` to percent-encode invalid characters within the - path, query, and target components. (Pull #1586) - - - 1.25.1 (2019-04-24) - ------------------- - - * Add support for Google's ``Brotli`` package. (Pull #1572, Pull #1579) - - * Upgrade bundled rfc3986 to v1.3.1 (Pull #1578) - - - 1.25 (2019-04-22) - ----------------- - - * Require and validate certificates by default when using HTTPS (Pull #1507) - - * Upgraded ``urllib3.utils.parse_url()`` to be RFC 3986 compliant. (Pull #1487) - - * Added support for ``key_password`` for ``HTTPSConnectionPool`` to use - encrypted ``key_file`` without creating your own ``SSLContext`` object. (Pull #1489) - - * Add TLSv1.3 support to CPython, pyOpenSSL, and SecureTransport ``SSLContext`` - implementations. (Pull #1496) - - * Switched the default multipart header encoder from RFC 2231 to HTML 5 working draft. (Issue #303, PR #1492) - - * Fixed issue where OpenSSL would block if an encrypted client private key was - given and no password was given. Instead an ``SSLError`` is raised. (Pull #1489) - - * Added support for Brotli content encoding. It is enabled automatically if - ``brotlipy`` package is installed which can be requested with - ``urllib3[brotli]`` extra. (Pull #1532) - - * Drop ciphers using DSS key exchange from default TLS cipher suites. - Improve default ciphers when using SecureTransport. (Pull #1496) - - * Implemented a more efficient ``HTTPResponse.__iter__()`` method. (Issue #1483) - - 1.24.3 (2019-05-01) - ------------------- - - * Apply fix for CVE-2019-9740. (Pull #1591) - - 1.24.2 (2019-04-17) - ------------------- - - * Don't load system certificates by default when any other ``ca_certs``, ``ca_certs_dir`` or - ``ssl_context`` parameters are specified. - - * Remove Authorization header regardless of case when redirecting to cross-site. (Issue #1510) - - * Add support for IPv6 addresses in subjectAltName section of certificates. (Issue #1269) - - - 1.24.1 (2018-11-02) - ------------------- - - * Remove quadratic behavior within ``GzipDecoder.decompress()`` (Issue #1467) - - * Restored functionality of ``ciphers`` parameter for ``create_urllib3_context()``. (Issue #1462) - - - 1.24 (2018-10-16) - ----------------- - - * Allow key_server_hostname to be specified when initializing a PoolManager to allow custom SNI to be overridden. (Pull #1449) - - * Test against Python 3.7 on AppVeyor. (Pull #1453) - - * Early-out ipv6 checks when running on App Engine. (Pull #1450) - - * Change ambiguous description of backoff_factor (Pull #1436) - - * Add ability to handle multiple Content-Encodings (Issue #1441 and Pull #1442) - - * Skip DNS names that can't be idna-decoded when using pyOpenSSL (Issue #1405). - - * Add a server_hostname parameter to HTTPSConnection which allows for - overriding the SNI hostname sent in the handshake. (Pull #1397) - - * Drop support for EOL Python 2.6 (Pull #1429 and Pull #1430) - - * Fixed bug where responses with header Content-Type: message/* erroneously - raised HeaderParsingError, resulting in a warning being logged. (Pull #1439) - - * Move urllib3 to src/urllib3 (Pull #1409) - - - 1.23 (2018-06-04) - ----------------- - - * Allow providing a list of headers to strip from requests when redirecting - to a different host. Defaults to the ``Authorization`` header. Different - headers can be set via ``Retry.remove_headers_on_redirect``. (Issue #1316) - - * Fix ``util.selectors._fileobj_to_fd`` to accept ``long`` (Issue #1247). - - * Dropped Python 3.3 support. (Pull #1242) - - * Put the connection back in the pool when calling stream() or read_chunked() on - a chunked HEAD response. (Issue #1234) - - * Fixed pyOpenSSL-specific ssl client authentication issue when clients - attempted to auth via certificate + chain (Issue #1060) - - * Add the port to the connectionpool connect print (Pull #1251) - - * Don't use the ``uuid`` module to create multipart data boundaries. (Pull #1380) - - * ``read_chunked()`` on a closed response returns no chunks. (Issue #1088) - - * Add Python 2.6 support to ``contrib.securetransport`` (Pull #1359) - - * Added support for auth info in url for SOCKS proxy (Pull #1363) - - - 1.22 (2017-07-20) - ----------------- - - * Fixed missing brackets in ``HTTP CONNECT`` when connecting to IPv6 address via - IPv6 proxy. (Issue #1222) - - * Made the connection pool retry on ``SSLError``. The original ``SSLError`` - is available on ``MaxRetryError.reason``. (Issue #1112) - - * Drain and release connection before recursing on retry/redirect. Fixes - deadlocks with a blocking connectionpool. (Issue #1167) - - * Fixed compatibility for cookiejar. (Issue #1229) - - * pyopenssl: Use vendored version of ``six``. (Issue #1231) - - - 1.21.1 (2017-05-02) - ------------------- - - * Fixed SecureTransport issue that would cause long delays in response body - delivery. (Pull #1154) - - * Fixed regression in 1.21 that threw exceptions when users passed the - ``socket_options`` flag to the ``PoolManager``. (Issue #1165) - - * Fixed regression in 1.21 that threw exceptions when users passed the - ``assert_hostname`` or ``assert_fingerprint`` flag to the ``PoolManager``. - (Pull #1157) - - - 1.21 (2017-04-25) - ----------------- - - * Improved performance of certain selector system calls on Python 3.5 and - later. (Pull #1095) - - * Resolved issue where the PyOpenSSL backend would not wrap SysCallError - exceptions appropriately when sending data. (Pull #1125) - - * Selectors now detects a monkey-patched select module after import for modules - that patch the select module like eventlet, greenlet. (Pull #1128) - - * Reduced memory consumption when streaming zlib-compressed responses - (as opposed to raw deflate streams). (Pull #1129) - - * Connection pools now use the entire request context when constructing the - pool key. (Pull #1016) - - * ``PoolManager.connection_from_*`` methods now accept a new keyword argument, - ``pool_kwargs``, which are merged with the existing ``connection_pool_kw``. - (Pull #1016) - - * Add retry counter for ``status_forcelist``. (Issue #1147) - - * Added ``contrib`` module for using SecureTransport on macOS: - ``urllib3.contrib.securetransport``. (Pull #1122) - - * urllib3 now only normalizes the case of ``http://`` and ``https://`` schemes: - for schemes it does not recognise, it assumes they are case-sensitive and - leaves them unchanged. - (Issue #1080) - - - 1.20 (2017-01-19) - ----------------- - - * Added support for waiting for I/O using selectors other than select, - improving urllib3's behaviour with large numbers of concurrent connections. - (Pull #1001) - - * Updated the date for the system clock check. (Issue #1005) - - * ConnectionPools now correctly consider hostnames to be case-insensitive. - (Issue #1032) - - * Outdated versions of PyOpenSSL now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Pull #1063) - - * Outdated versions of cryptography now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Issue #1044) - - * Automatically attempt to rewind a file-like body object when a request is - retried or redirected. (Pull #1039) - - * Fix some bugs that occur when modules incautiously patch the queue module. - (Pull #1061) - - * Prevent retries from occurring on read timeouts for which the request method - was not in the method whitelist. (Issue #1059) - - * Changed the PyOpenSSL contrib module to lazily load idna to avoid - unnecessarily bloating the memory of programs that don't need it. (Pull - #1076) - - * Add support for IPv6 literals with zone identifiers. (Pull #1013) - - * Added support for socks5h:// and socks4a:// schemes when working with SOCKS - proxies, and controlled remote DNS appropriately. (Issue #1035) - - - 1.19.1 (2016-11-16) - ------------------- - - * Fixed AppEngine import that didn't function on Python 3.5. (Pull #1025) - - - 1.19 (2016-11-03) - ----------------- - - * urllib3 now respects Retry-After headers on 413, 429, and 503 responses when - using the default retry logic. (Pull #955) - - * Remove markers from setup.py to assist ancient setuptools versions. (Issue - #986) - - * Disallow superscripts and other integerish things in URL ports. (Issue #989) - - * Allow urllib3's HTTPResponse.stream() method to continue to work with - non-httplib underlying FPs. (Pull #990) - - * Empty filenames in multipart headers are now emitted as such, rather than - being suppressed. (Issue #1015) - - * Prefer user-supplied Host headers on chunked uploads. (Issue #1009) - - - 1.18.1 (2016-10-27) - ------------------- - - * CVE-2016-9015. Users who are using urllib3 version 1.17 or 1.18 along with - PyOpenSSL injection and OpenSSL 1.1.0 *must* upgrade to this version. This - release fixes a vulnerability whereby urllib3 in the above configuration - would silently fail to validate TLS certificates due to erroneously setting - invalid flags in OpenSSL's ``SSL_CTX_set_verify`` function. These erroneous - flags do not cause a problem in OpenSSL versions before 1.1.0, which - interprets the presence of any flag as requesting certificate validation. - - There is no PR for this patch, as it was prepared for simultaneous disclosure - and release. The master branch received the same fix in PR #1010. - - - 1.18 (2016-09-26) - ----------------- - - * Fixed incorrect message for IncompleteRead exception. (PR #973) - - * Accept ``iPAddress`` subject alternative name fields in TLS certificates. - (Issue #258) - - * Fixed consistency of ``HTTPResponse.closed`` between Python 2 and 3. - (Issue #977) - - * Fixed handling of wildcard certificates when using PyOpenSSL. (Issue #979) - - - 1.17 (2016-09-06) - ----------------- - - * Accept ``SSLContext`` objects for use in SSL/TLS negotiation. (Issue #835) - - * ConnectionPool debug log now includes scheme, host, and port. (Issue #897) - - * Substantially refactored documentation. (Issue #887) - - * Used URLFetch default timeout on AppEngine, rather than hardcoding our own. - (Issue #858) - - * Normalize the scheme and host in the URL parser (Issue #833) - - * ``HTTPResponse`` contains the last ``Retry`` object, which now also - contains retries history. (Issue #848) - - * Timeout can no longer be set as boolean, and must be greater than zero. - (PR #924) - - * Removed pyasn1 and ndg-httpsclient from dependencies used for PyOpenSSL. We - now use cryptography and idna, both of which are already dependencies of - PyOpenSSL. (PR #930) - - * Fixed infinite loop in ``stream`` when amt=None. (Issue #928) - - * Try to use the operating system's certificates when we are using an - ``SSLContext``. (PR #941) - - * Updated cipher suite list to allow ChaCha20+Poly1305. AES-GCM is preferred to - ChaCha20, but ChaCha20 is then preferred to everything else. (PR #947) - - * Updated cipher suite list to remove 3DES-based cipher suites. (PR #958) - - * Removed the cipher suite fallback to allow HIGH ciphers. (PR #958) - - * Implemented ``length_remaining`` to determine remaining content - to be read. (PR #949) - - * Implemented ``enforce_content_length`` to enable exceptions when - incomplete data chunks are received. (PR #949) - - * Dropped connection start, dropped connection reset, redirect, forced retry, - and new HTTPS connection log levels to DEBUG, from INFO. (PR #967) - - - 1.16 (2016-06-11) - ----------------- - - * Disable IPv6 DNS when IPv6 connections are not possible. (Issue #840) - - * Provide ``key_fn_by_scheme`` pool keying mechanism that can be - overridden. (Issue #830) - - * Normalize scheme and host to lowercase for pool keys, and include - ``source_address``. (Issue #830) - - * Cleaner exception chain in Python 3 for ``_make_request``. - (Issue #861) - - * Fixed installing ``urllib3[socks]`` extra. (Issue #864) - - * Fixed signature of ``ConnectionPool.close`` so it can actually safely be - called by subclasses. (Issue #873) - - * Retain ``release_conn`` state across retries. (Issues #651, #866) - - * Add customizable ``HTTPConnectionPool.ResponseCls``, which defaults to - ``HTTPResponse`` but can be replaced with a subclass. (Issue #879) - - - 1.15.1 (2016-04-11) - ------------------- - - * Fix packaging to include backports module. (Issue #841) - - - 1.15 (2016-04-06) - ----------------- - - * Added Retry(raise_on_status=False). (Issue #720) - - * Always use setuptools, no more distutils fallback. (Issue #785) - - * Dropped support for Python 3.2. (Issue #786) - - * Chunked transfer encoding when requesting with ``chunked=True``. - (Issue #790) - - * Fixed regression with IPv6 port parsing. (Issue #801) - - * Append SNIMissingWarning messages to allow users to specify it in - the PYTHONWARNINGS environment variable. (Issue #816) - - * Handle unicode headers in Py2. (Issue #818) - - * Log certificate when there is a hostname mismatch. (Issue #820) - - * Preserve order of request/response headers. (Issue #821) - - - 1.14 (2015-12-29) - ----------------- - - * contrib: SOCKS proxy support! (Issue #762) - - * Fixed AppEngine handling of transfer-encoding header and bug - in Timeout defaults checking. (Issue #763) - - - 1.13.1 (2015-12-18) - ------------------- - - * Fixed regression in IPv6 + SSL for match_hostname. (Issue #761) - - - 1.13 (2015-12-14) - ----------------- - - * Fixed ``pip install urllib3[secure]`` on modern pip. (Issue #706) - - * pyopenssl: Fixed SSL3_WRITE_PENDING error. (Issue #717) - - * pyopenssl: Support for TLSv1.1 and TLSv1.2. (Issue #696) - - * Close connections more defensively on exception. (Issue #734) - - * Adjusted ``read_chunked`` to handle gzipped, chunk-encoded bodies without - repeatedly flushing the decoder, to function better on Jython. (Issue #743) - - * Accept ``ca_cert_dir`` for SSL-related PoolManager configuration. (Issue #758) - - - 1.12 (2015-09-03) - ----------------- - - * Rely on ``six`` for importing ``httplib`` to work around - conflicts with other Python 3 shims. (Issue #688) - - * Add support for directories of certificate authorities, as supported by - OpenSSL. (Issue #701) - - * New exception: ``NewConnectionError``, raised when we fail to establish - a new connection, usually ``ECONNREFUSED`` socket error. - - - 1.11 (2015-07-21) - ----------------- - - * When ``ca_certs`` is given, ``cert_reqs`` defaults to - ``'CERT_REQUIRED'``. (Issue #650) - - * ``pip install urllib3[secure]`` will install Certifi and - PyOpenSSL as dependencies. (Issue #678) - - * Made ``HTTPHeaderDict`` usable as a ``headers`` input value - (Issues #632, #679) - - * Added `urllib3.contrib.appengine `_ - which has an ``AppEngineManager`` for using ``URLFetch`` in a - Google AppEngine environment. (Issue #664) - - * Dev: Added test suite for AppEngine. (Issue #631) - - * Fix performance regression when using PyOpenSSL. (Issue #626) - - * Passing incorrect scheme (e.g. ``foo://``) will raise - ``ValueError`` instead of ``AssertionError`` (backwards - compatible for now, but please migrate). (Issue #640) - - * Fix pools not getting replenished when an error occurs during a - request using ``release_conn=False``. (Issue #644) - - * Fix pool-default headers not applying for url-encoded requests - like GET. (Issue #657) - - * log.warning in Python 3 when headers are skipped due to parsing - errors. (Issue #642) - - * Close and discard connections if an error occurs during read. - (Issue #660) - - * Fix host parsing for IPv6 proxies. (Issue #668) - - * Separate warning type SubjectAltNameWarning, now issued once - per host. (Issue #671) - - * Fix ``httplib.IncompleteRead`` not getting converted to - ``ProtocolError`` when using ``HTTPResponse.stream()`` - (Issue #674) - - 1.10.4 (2015-05-03) - ------------------- - - * Migrate tests to Tornado 4. (Issue #594) - - * Append default warning configuration rather than overwrite. - (Issue #603) - - * Fix streaming decoding regression. (Issue #595) - - * Fix chunked requests losing state across keep-alive connections. - (Issue #599) - - * Fix hanging when chunked HEAD response has no body. (Issue #605) - - - 1.10.3 (2015-04-21) - ------------------- - - * Emit ``InsecurePlatformWarning`` when SSLContext object is missing. - (Issue #558) - - * Fix regression of duplicate header keys being discarded. - (Issue #563) - - * ``Response.stream()`` returns a generator for chunked responses. - (Issue #560) - - * Set upper-bound timeout when waiting for a socket in PyOpenSSL. - (Issue #585) - - * Work on platforms without `ssl` module for plain HTTP requests. - (Issue #587) - - * Stop relying on the stdlib's default cipher list. (Issue #588) - - - 1.10.2 (2015-02-25) - ------------------- - - * Fix file descriptor leakage on retries. (Issue #548) - - * Removed RC4 from default cipher list. (Issue #551) - - * Header performance improvements. (Issue #544) - - * Fix PoolManager not obeying redirect retry settings. (Issue #553) - - - 1.10.1 (2015-02-10) - ------------------- - - * Pools can be used as context managers. (Issue #545) - - * Don't re-use connections which experienced an SSLError. (Issue #529) - - * Don't fail when gzip decoding an empty stream. (Issue #535) - - * Add sha256 support for fingerprint verification. (Issue #540) - - * Fixed handling of header values containing commas. (Issue #533) - - - 1.10 (2014-12-14) - ----------------- - - * Disabled SSLv3. (Issue #473) - - * Add ``Url.url`` property to return the composed url string. (Issue #394) - - * Fixed PyOpenSSL + gevent ``WantWriteError``. (Issue #412) - - * ``MaxRetryError.reason`` will always be an exception, not string. - (Issue #481) - - * Fixed SSL-related timeouts not being detected as timeouts. (Issue #492) - - * Py3: Use ``ssl.create_default_context()`` when available. (Issue #473) - - * Emit ``InsecureRequestWarning`` for *every* insecure HTTPS request. - (Issue #496) - - * Emit ``SecurityWarning`` when certificate has no ``subjectAltName``. - (Issue #499) - - * Close and discard sockets which experienced SSL-related errors. - (Issue #501) - - * Handle ``body`` param in ``.request(...)``. (Issue #513) - - * Respect timeout with HTTPS proxy. (Issue #505) - - * PyOpenSSL: Handle ZeroReturnError exception. (Issue #520) - - - 1.9.1 (2014-09-13) - ------------------ - - * Apply socket arguments before binding. (Issue #427) - - * More careful checks if fp-like object is closed. (Issue #435) - - * Fixed packaging issues of some development-related files not - getting included. (Issue #440) - - * Allow performing *only* fingerprint verification. (Issue #444) - - * Emit ``SecurityWarning`` if system clock is waaay off. (Issue #445) - - * Fixed PyOpenSSL compatibility with PyPy. (Issue #450) - - * Fixed ``BrokenPipeError`` and ``ConnectionError`` handling in Py3. - (Issue #443) - - - - 1.9 (2014-07-04) - ---------------- - - * Shuffled around development-related files. If you're maintaining a distro - package of urllib3, you may need to tweak things. (Issue #415) - - * Unverified HTTPS requests will trigger a warning on the first request. See - our new `security documentation - `_ for details. - (Issue #426) - - * New retry logic and ``urllib3.util.retry.Retry`` configuration object. - (Issue #326) - - * All raised exceptions should now wrapped in a - ``urllib3.exceptions.HTTPException``-extending exception. (Issue #326) - - * All errors during a retry-enabled request should be wrapped in - ``urllib3.exceptions.MaxRetryError``, including timeout-related exceptions - which were previously exempt. Underlying error is accessible from the - ``.reason`` property. (Issue #326) - - * ``urllib3.exceptions.ConnectionError`` renamed to - ``urllib3.exceptions.ProtocolError``. (Issue #326) - - * Errors during response read (such as IncompleteRead) are now wrapped in - ``urllib3.exceptions.ProtocolError``. (Issue #418) - - * Requesting an empty host will raise ``urllib3.exceptions.LocationValueError``. - (Issue #417) - - * Catch read timeouts over SSL connections as - ``urllib3.exceptions.ReadTimeoutError``. (Issue #419) - - * Apply socket arguments before connecting. (Issue #427) - - - 1.8.3 (2014-06-23) - ------------------ - - * Fix TLS verification when using a proxy in Python 3.4.1. (Issue #385) - - * Add ``disable_cache`` option to ``urllib3.util.make_headers``. (Issue #393) - - * Wrap ``socket.timeout`` exception with - ``urllib3.exceptions.ReadTimeoutError``. (Issue #399) - - * Fixed proxy-related bug where connections were being reused incorrectly. - (Issues #366, #369) - - * Added ``socket_options`` keyword parameter which allows to define - ``setsockopt`` configuration of new sockets. (Issue #397) - - * Removed ``HTTPConnection.tcp_nodelay`` in favor of - ``HTTPConnection.default_socket_options``. (Issue #397) - - * Fixed ``TypeError`` bug in Python 2.6.4. (Issue #411) - - - 1.8.2 (2014-04-17) - ------------------ - - * Fix ``urllib3.util`` not being included in the package. - - - 1.8.1 (2014-04-17) - ------------------ - - * Fix AppEngine bug of HTTPS requests going out as HTTP. (Issue #356) - - * Don't install ``dummyserver`` into ``site-packages`` as it's only needed - for the test suite. (Issue #362) - - * Added support for specifying ``source_address``. (Issue #352) - - - 1.8 (2014-03-04) - ---------------- - - * Improved url parsing in ``urllib3.util.parse_url`` (properly parse '@' in - username, and blank ports like 'hostname:'). - - * New ``urllib3.connection`` module which contains all the HTTPConnection - objects. - - * Several ``urllib3.util.Timeout``-related fixes. Also changed constructor - signature to a more sensible order. [Backwards incompatible] - (Issues #252, #262, #263) - - * Use ``backports.ssl_match_hostname`` if it's installed. (Issue #274) - - * Added ``.tell()`` method to ``urllib3.response.HTTPResponse`` which - returns the number of bytes read so far. (Issue #277) - - * Support for platforms without threading. (Issue #289) - - * Expand default-port comparison in ``HTTPConnectionPool.is_same_host`` - to allow a pool with no specified port to be considered equal to to an - HTTP/HTTPS url with port 80/443 explicitly provided. (Issue #305) - - * Improved default SSL/TLS settings to avoid vulnerabilities. - (Issue #309) - - * Fixed ``urllib3.poolmanager.ProxyManager`` not retrying on connect errors. - (Issue #310) - - * Disable Nagle's Algorithm on the socket for non-proxies. A subset of requests - will send the entire HTTP request ~200 milliseconds faster; however, some of - the resulting TCP packets will be smaller. (Issue #254) - - * Increased maximum number of SubjectAltNames in ``urllib3.contrib.pyopenssl`` - from the default 64 to 1024 in a single certificate. (Issue #318) - - * Headers are now passed and stored as a custom - ``urllib3.collections_.HTTPHeaderDict`` object rather than a plain ``dict``. - (Issue #329, #333) - - * Headers no longer lose their case on Python 3. (Issue #236) - - * ``urllib3.contrib.pyopenssl`` now uses the operating system's default CA - certificates on inject. (Issue #332) - - * Requests with ``retries=False`` will immediately raise any exceptions without - wrapping them in ``MaxRetryError``. (Issue #348) - - * Fixed open socket leak with SSL-related failures. (Issue #344, #348) - - - 1.7.1 (2013-09-25) - ------------------ - - * Added granular timeout support with new ``urllib3.util.Timeout`` class. - (Issue #231) - - * Fixed Python 3.4 support. (Issue #238) - - - 1.7 (2013-08-14) - ---------------- - - * More exceptions are now pickle-able, with tests. (Issue #174) - - * Fixed redirecting with relative URLs in Location header. (Issue #178) - - * Support for relative urls in ``Location: ...`` header. (Issue #179) - - * ``urllib3.response.HTTPResponse`` now inherits from ``io.IOBase`` for bonus - file-like functionality. (Issue #187) - - * Passing ``assert_hostname=False`` when creating a HTTPSConnectionPool will - skip hostname verification for SSL connections. (Issue #194) - - * New method ``urllib3.response.HTTPResponse.stream(...)`` which acts as a - generator wrapped around ``.read(...)``. (Issue #198) - - * IPv6 url parsing enforces brackets around the hostname. (Issue #199) - - * Fixed thread race condition in - ``urllib3.poolmanager.PoolManager.connection_from_host(...)`` (Issue #204) - - * ``ProxyManager`` requests now include non-default port in ``Host: ...`` - header. (Issue #217) - - * Added HTTPS proxy support in ``ProxyManager``. (Issue #170 #139) - - * New ``RequestField`` object can be passed to the ``fields=...`` param which - can specify headers. (Issue #220) - - * Raise ``urllib3.exceptions.ProxyError`` when connecting to proxy fails. - (Issue #221) - - * Use international headers when posting file names. (Issue #119) - - * Improved IPv6 support. (Issue #203) - - - 1.6 (2013-04-25) - ---------------- - - * Contrib: Optional SNI support for Py2 using PyOpenSSL. (Issue #156) - - * ``ProxyManager`` automatically adds ``Host: ...`` header if not given. - - * Improved SSL-related code. ``cert_req`` now optionally takes a string like - "REQUIRED" or "NONE". Same with ``ssl_version`` takes strings like "SSLv23" - The string values reflect the suffix of the respective constant variable. - (Issue #130) - - * Vendored ``socksipy`` now based on Anorov's fork which handles unexpectedly - closed proxy connections and larger read buffers. (Issue #135) - - * Ensure the connection is closed if no data is received, fixes connection leak - on some platforms. (Issue #133) - - * Added SNI support for SSL/TLS connections on Py32+. (Issue #89) - - * Tests fixed to be compatible with Py26 again. (Issue #125) - - * Added ability to choose SSL version by passing an ``ssl.PROTOCOL_*`` constant - to the ``ssl_version`` parameter of ``HTTPSConnectionPool``. (Issue #109) - - * Allow an explicit content type to be specified when encoding file fields. - (Issue #126) - - * Exceptions are now pickleable, with tests. (Issue #101) - - * Fixed default headers not getting passed in some cases. (Issue #99) - - * Treat "content-encoding" header value as case-insensitive, per RFC 2616 - Section 3.5. (Issue #110) - - * "Connection Refused" SocketErrors will get retried rather than raised. - (Issue #92) - - * Updated vendored ``six``, no longer overrides the global ``six`` module - namespace. (Issue #113) - - * ``urllib3.exceptions.MaxRetryError`` contains a ``reason`` property holding - the exception that prompted the final retry. If ``reason is None`` then it - was due to a redirect. (Issue #92, #114) - - * Fixed ``PoolManager.urlopen()`` from not redirecting more than once. - (Issue #149) - - * Don't assume ``Content-Type: text/plain`` for multi-part encoding parameters - that are not files. (Issue #111) - - * Pass `strict` param down to ``httplib.HTTPConnection``. (Issue #122) - - * Added mechanism to verify SSL certificates by fingerprint (md5, sha1) or - against an arbitrary hostname (when connecting by IP or for misconfigured - servers). (Issue #140) - - * Streaming decompression support. (Issue #159) - - - 1.5 (2012-08-02) - ---------------- - - * Added ``urllib3.add_stderr_logger()`` for quickly enabling STDERR debug - logging in urllib3. - - * Native full URL parsing (including auth, path, query, fragment) available in - ``urllib3.util.parse_url(url)``. - - * Built-in redirect will switch method to 'GET' if status code is 303. - (Issue #11) - - * ``urllib3.PoolManager`` strips the scheme and host before sending the request - uri. (Issue #8) - - * New ``urllib3.exceptions.DecodeError`` exception for when automatic decoding, - based on the Content-Type header, fails. - - * Fixed bug with pool depletion and leaking connections (Issue #76). Added - explicit connection closing on pool eviction. Added - ``urllib3.PoolManager.clear()``. - - * 99% -> 100% unit test coverage. - - - 1.4 (2012-06-16) - ---------------- - - * Minor AppEngine-related fixes. - - * Switched from ``mimetools.choose_boundary`` to ``uuid.uuid4()``. - - * Improved url parsing. (Issue #73) - - * IPv6 url support. (Issue #72) - - - 1.3 (2012-03-25) - ---------------- - - * Removed pre-1.0 deprecated API. - - * Refactored helpers into a ``urllib3.util`` submodule. - - * Fixed multipart encoding to support list-of-tuples for keys with multiple - values. (Issue #48) - - * Fixed multiple Set-Cookie headers in response not getting merged properly in - Python 3. (Issue #53) - - * AppEngine support with Py27. (Issue #61) - - * Minor ``encode_multipart_formdata`` fixes related to Python 3 strings vs - bytes. - - - 1.2.2 (2012-02-06) - ------------------ - - * Fixed packaging bug of not shipping ``test-requirements.txt``. (Issue #47) - - - 1.2.1 (2012-02-05) - ------------------ - - * Fixed another bug related to when ``ssl`` module is not available. (Issue #41) - - * Location parsing errors now raise ``urllib3.exceptions.LocationParseError`` - which inherits from ``ValueError``. - - - 1.2 (2012-01-29) - ---------------- - - * Added Python 3 support (tested on 3.2.2) - - * Dropped Python 2.5 support (tested on 2.6.7, 2.7.2) - - * Use ``select.poll`` instead of ``select.select`` for platforms that support - it. - - * Use ``Queue.LifoQueue`` instead of ``Queue.Queue`` for more aggressive - connection reusing. Configurable by overriding ``ConnectionPool.QueueCls``. - - * Fixed ``ImportError`` during install when ``ssl`` module is not available. - (Issue #41) - - * Fixed ``PoolManager`` redirects between schemes (such as HTTP -> HTTPS) not - completing properly. (Issue #28, uncovered by Issue #10 in v1.1) - - * Ported ``dummyserver`` to use ``tornado`` instead of ``webob`` + - ``eventlet``. Removed extraneous unsupported dummyserver testing backends. - Added socket-level tests. - - * More tests. Achievement Unlocked: 99% Coverage. - - - 1.1 (2012-01-07) - ---------------- - - * Refactored ``dummyserver`` to its own root namespace module (used for - testing). - - * Added hostname verification for ``VerifiedHTTPSConnection`` by vendoring in - Py32's ``ssl_match_hostname``. (Issue #25) - - * Fixed cross-host HTTP redirects when using ``PoolManager``. (Issue #10) - - * Fixed ``decode_content`` being ignored when set through ``urlopen``. (Issue - #27) - - * Fixed timeout-related bugs. (Issues #17, #23) - - - 1.0.2 (2011-11-04) - ------------------ - - * Fixed typo in ``VerifiedHTTPSConnection`` which would only present as a bug if - you're using the object manually. (Thanks pyos) - - * Made RecentlyUsedContainer (and consequently PoolManager) more thread-safe by - wrapping the access log in a mutex. (Thanks @christer) - - * Made RecentlyUsedContainer more dict-like (corrected ``__delitem__`` and - ``__getitem__`` behaviour), with tests. Shouldn't affect core urllib3 code. - - - 1.0.1 (2011-10-10) - ------------------ - - * Fixed a bug where the same connection would get returned into the pool twice, - causing extraneous "HttpConnectionPool is full" log warnings. - - - 1.0 (2011-10-08) - ---------------- - - * Added ``PoolManager`` with LRU expiration of connections (tested and - documented). - * Added ``ProxyManager`` (needs tests, docs, and confirmation that it works - with HTTPS proxies). - * Added optional partial-read support for responses when - ``preload_content=False``. You can now make requests and just read the headers - without loading the content. - * Made response decoding optional (default on, same as before). - * Added optional explicit boundary string for ``encode_multipart_formdata``. - * Convenience request methods are now inherited from ``RequestMethods``. Old - helpers like ``get_url`` and ``post_url`` should be abandoned in favour of - the new ``request(method, url, ...)``. - * Refactored code to be even more decoupled, reusable, and extendable. - * License header added to ``.py`` files. - * Embiggened the documentation: Lots of Sphinx-friendly docstrings in the code - and docs in ``docs/`` and on https://urllib3.readthedocs.io/. - * Embettered all the things! - * Started writing this file. - - - 0.4.1 (2011-07-17) - ------------------ - - * Minor bug fixes, code cleanup. - - - 0.4 (2011-03-01) - ---------------- - - * Better unicode support. - * Added ``VerifiedHTTPSConnection``. - * Added ``NTLMConnectionPool`` in contrib. - * Minor improvements. - - - 0.3.1 (2010-07-13) - ------------------ - - * Added ``assert_host_name`` optional parameter. Now compatible with proxies. - - - 0.3 (2009-12-10) - ---------------- - - * Added HTTPS support. - * Minor bug fixes. - * Refactored, broken backwards compatibility with 0.2. - * API to be treated as stable from this version forward. - - - 0.2 (2008-11-17) - ---------------- - - * Added unit tests. - * Bug fixes. - - - 0.1 (2008-11-16) - ---------------- - - * First release. - -Keywords: urllib httplib threadsafe filepost http https ssl pooling -Platform: UNKNOWN -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: Software Development :: Libraries -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 -Provides-Extra: brotli -Provides-Extra: secure -Provides-Extra: socks diff --git a/third_party/python/urllib3/src/urllib3.egg-info/SOURCES.txt b/third_party/python/urllib3/src/urllib3.egg-info/SOURCES.txt deleted file mode 100644 index 78a91adb8c18..000000000000 --- a/third_party/python/urllib3/src/urllib3.egg-info/SOURCES.txt +++ /dev/null @@ -1,115 +0,0 @@ -CHANGES.rst -CONTRIBUTORS.txt -LICENSE.txt -MANIFEST.in -README.rst -dev-requirements.txt -setup.cfg -setup.py -docs/Makefile -docs/advanced-usage.rst -docs/conf.py -docs/contributing.rst -docs/index.rst -docs/make.bat -docs/requirements.txt -docs/user-guide.rst -docs/_templates/fonts.html -docs/images/banner.svg -docs/images/demo-button.png -docs/images/learn-more-button.png -docs/images/logo.png -docs/images/logo.svg -docs/reference/index.rst -docs/reference/urllib3.contrib.rst -docs/reference/urllib3.util.rst -dummyserver/__init__.py -dummyserver/handlers.py -dummyserver/proxy.py -dummyserver/server.py -dummyserver/testcase.py -dummyserver/certs/README.rst -dummyserver/certs/cacert.key -dummyserver/certs/cacert.pem -dummyserver/certs/server.crt -dummyserver/certs/server.key -src/urllib3/__init__.py -src/urllib3/_collections.py -src/urllib3/connection.py -src/urllib3/connectionpool.py -src/urllib3/exceptions.py -src/urllib3/fields.py -src/urllib3/filepost.py -src/urllib3/poolmanager.py -src/urllib3/request.py -src/urllib3/response.py -src/urllib3.egg-info/PKG-INFO -src/urllib3.egg-info/SOURCES.txt -src/urllib3.egg-info/dependency_links.txt -src/urllib3.egg-info/requires.txt -src/urllib3.egg-info/top_level.txt -src/urllib3/contrib/__init__.py -src/urllib3/contrib/_appengine_environ.py -src/urllib3/contrib/appengine.py -src/urllib3/contrib/ntlmpool.py -src/urllib3/contrib/pyopenssl.py -src/urllib3/contrib/securetransport.py -src/urllib3/contrib/socks.py -src/urllib3/contrib/_securetransport/__init__.py -src/urllib3/contrib/_securetransport/bindings.py -src/urllib3/contrib/_securetransport/low_level.py -src/urllib3/packages/__init__.py -src/urllib3/packages/six.py -src/urllib3/packages/backports/__init__.py -src/urllib3/packages/backports/makefile.py -src/urllib3/packages/ssl_match_hostname/__init__.py -src/urllib3/packages/ssl_match_hostname/_implementation.py -src/urllib3/util/__init__.py -src/urllib3/util/connection.py -src/urllib3/util/queue.py -src/urllib3/util/request.py -src/urllib3/util/response.py -src/urllib3/util/retry.py -src/urllib3/util/ssl_.py -src/urllib3/util/timeout.py -src/urllib3/util/url.py -src/urllib3/util/wait.py -test/__init__.py -test/benchmark.py -test/conftest.py -test/port_helpers.py -test/socketpair_helper.py -test/test_collections.py -test/test_compatibility.py -test/test_connection.py -test/test_connectionpool.py -test/test_exceptions.py -test/test_fields.py -test/test_filepost.py -test/test_no_ssl.py -test/test_poolmanager.py -test/test_proxymanager.py -test/test_queue_monkeypatch.py -test/test_response.py -test/test_retry.py -test/test_ssl.py -test/test_util.py -test/test_wait.py -test/appengine/__init__.py -test/appengine/conftest.py -test/appengine/test_gae_manager.py -test/appengine/test_urlfetch.py -test/contrib/__init__.py -test/contrib/duplicate_san.pem -test/contrib/test_pyopenssl.py -test/contrib/test_pyopenssl_dependencies.py -test/contrib/test_securetransport.py -test/contrib/test_socks.py -test/with_dummyserver/__init__.py -test/with_dummyserver/test_chunked_transfer.py -test/with_dummyserver/test_connectionpool.py -test/with_dummyserver/test_https.py -test/with_dummyserver/test_no_ssl.py -test/with_dummyserver/test_poolmanager.py -test/with_dummyserver/test_proxy_poolmanager.py -test/with_dummyserver/test_socketlevel.py \ No newline at end of file diff --git a/third_party/python/urllib3/src/urllib3.egg-info/dependency_links.txt b/third_party/python/urllib3/src/urllib3.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891791f..000000000000 --- a/third_party/python/urllib3/src/urllib3.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/third_party/python/urllib3/src/urllib3.egg-info/requires.txt b/third_party/python/urllib3/src/urllib3.egg-info/requires.txt deleted file mode 100644 index ba01eaf2e6e9..000000000000 --- a/third_party/python/urllib3/src/urllib3.egg-info/requires.txt +++ /dev/null @@ -1,15 +0,0 @@ - -[brotli] -brotlipy>=0.6.0 - -[secure] -certifi -cryptography>=1.3.4 -idna>=2.0.0 -pyOpenSSL>=0.14 - -[secure:python_version == "2.7"] -ipaddress - -[socks] -PySocks!=1.5.7,<2.0,>=1.5.6 diff --git a/third_party/python/urllib3/src/urllib3/contrib/__init__.py b/third_party/python/urllib3/src/urllib3/contrib/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/urllib3/src/urllib3/contrib/_securetransport/__init__.py b/third_party/python/urllib3/src/urllib3/contrib/_securetransport/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/urllib3/src/urllib3/packages/backports/__init__.py b/third_party/python/urllib3/src/urllib3/packages/backports/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/urllib3/LICENSE.txt b/third_party/python/urllib3/urllib3-1.25.9.dist-info/LICENSE.txt similarity index 100% rename from third_party/python/urllib3/LICENSE.txt rename to third_party/python/urllib3/urllib3-1.25.9.dist-info/LICENSE.txt diff --git a/third_party/python/urllib3/CHANGES.rst b/third_party/python/urllib3/urllib3-1.25.9.dist-info/METADATA similarity index 86% rename from third_party/python/urllib3/CHANGES.rst rename to third_party/python/urllib3/urllib3-1.25.9.dist-info/METADATA index 389980f2b9f1..12fceb262a10 100644 --- a/third_party/python/urllib3/CHANGES.rst +++ b/third_party/python/urllib3/urllib3-1.25.9.dist-info/METADATA @@ -1,3 +1,151 @@ +Metadata-Version: 2.1 +Name: urllib3 +Version: 1.25.9 +Summary: HTTP library with thread-safe connection pooling, file post, and more. +Home-page: https://urllib3.readthedocs.io/ +Author: Andrey Petrov +Author-email: andrey.petrov@shazow.net +License: MIT +Project-URL: Documentation, https://urllib3.readthedocs.io/ +Project-URL: Code, https://github.com/urllib3/urllib3 +Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues +Keywords: urllib httplib threadsafe filepost http https ssl pooling +Platform: UNKNOWN +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: Software Development :: Libraries +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 +Provides-Extra: brotli +Requires-Dist: brotlipy (>=0.6.0) ; extra == 'brotli' +Provides-Extra: secure +Requires-Dist: certifi ; extra == 'secure' +Requires-Dist: cryptography (>=1.3.4) ; extra == 'secure' +Requires-Dist: idna (>=2.0.0) ; extra == 'secure' +Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'secure' +Requires-Dist: ipaddress ; (python_version == "2.7") and extra == 'secure' +Provides-Extra: socks +Requires-Dist: PySocks (!=1.5.7,<2.0,>=1.5.6) ; extra == 'socks' + +urllib3 +======= + +urllib3 is a powerful, *sanity-friendly* HTTP client for Python. Much of the +Python ecosystem already uses urllib3 and you should too. +urllib3 brings many critical features that are missing from the Python +standard libraries: + +- Thread safety. +- Connection pooling. +- Client-side SSL/TLS verification. +- File uploads with multipart encoding. +- Helpers for retrying requests and dealing with HTTP redirects. +- Support for gzip, deflate, and brotli encoding. +- Proxy support for HTTP and SOCKS. +- 100% test coverage. + +urllib3 is powerful and easy to use:: + + >>> import urllib3 + >>> http = urllib3.PoolManager() + >>> r = http.request('GET', 'http://httpbin.org/robots.txt') + >>> r.status + 200 + >>> r.data + 'User-agent: *\nDisallow: /deny\n' + + +Installing +---------- + +urllib3 can be installed with `pip `_:: + + $ pip install urllib3 + +Alternatively, you can grab the latest source code from `GitHub `_:: + + $ git clone git://github.com/urllib3/urllib3.git + $ python setup.py install + + +Documentation +------------- + +urllib3 has usage and reference documentation at `urllib3.readthedocs.io `_. + + +Contributing +------------ + +urllib3 happily accepts contributions. Please see our +`contributing documentation `_ +for some tips on getting started. + + +Security Disclosures +-------------------- + +To report a security vulnerability, please use the +`Tidelift security contact `_. +Tidelift will coordinate the fix and disclosure with maintainers. + +Maintainers +----------- + +- `@sethmlarson `_ (Seth M. Larson) +- `@pquentin `_ (Quentin Pradet) +- `@theacodes `_ (Thea Flowers) +- `@haikuginger `_ (Jess Shapiro) +- `@lukasa `_ (Cory Benfield) +- `@sigmavirus24 `_ (Ian Stapleton Cordasco) +- `@shazow `_ (Andrey Petrov) + +👋 + + +Sponsorship +----------- + +.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png + :width: 75 + :alt: Tidelift + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for urllib3 is available as part of the `Tidelift + Subscription`_. Tidelift gives software development teams a single source for + purchasing and maintaining their software, with professional grade assurances + from the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme + +If your company benefits from this library, please consider `sponsoring its +development `_. + +Sponsors include: + +- Abbott (2018-2019), sponsored `@sethmlarson `_'s work on urllib3. +- Google Cloud Platform (2018-2019), sponsored `@theacodes `_'s work on urllib3. +- Akamai (2017-2018), sponsored `@haikuginger `_'s work on urllib3 +- Hewlett Packard Enterprise (2016-2017), sponsored `@Lukasa’s `_ work on urllib3. + + Changes ======= @@ -1110,3 +1258,5 @@ Changes ---------------- * First release. + + diff --git a/third_party/python/urllib3/urllib3-1.25.9.dist-info/RECORD b/third_party/python/urllib3/urllib3-1.25.9.dist-info/RECORD new file mode 100644 index 000000000000..18bcf6d7f15e --- /dev/null +++ b/third_party/python/urllib3/urllib3-1.25.9.dist-info/RECORD @@ -0,0 +1,41 @@ +urllib3/__init__.py,sha256=rdFZCO1L7e8861ZTvo8AiSKwxCe9SnWQUQwJ599YV9c,2683 +urllib3/_collections.py,sha256=GouVsNzwg6jADZTmimMI6oqmwKSswnMo9dh5tGNVWO4,10792 +urllib3/connection.py,sha256=Fln8a_bkegdNMkFoSOwyI0PJvL1OqzVUO6ifihKOTpc,14461 +urllib3/connectionpool.py,sha256=egdaX-Db_LVXifDxv3JY0dHIpQqDv0wC0_9Eeh8FkPM,35725 +urllib3/exceptions.py,sha256=D2Jvab7M7m_n0rnmBmq481paoVT32VvVeB6VeQM0y-w,7172 +urllib3/fields.py,sha256=kroD76QK-GdHHW7f_AUN4XxDC3OQPI2FFrS9eSL4BCs,8553 +urllib3/filepost.py,sha256=vj0qbrpT1AFzvvW4SuC8M5kJiw7wftHcSr-7b8UpPpw,2440 +urllib3/poolmanager.py,sha256=iWEAIGrVNGoOmQyfiFwCqG-IyYy6GIQ-jJ9QCsX9li4,17861 +urllib3/request.py,sha256=hhoHvEEatyd9Tn5EbGjQ0emn-ENMCyY591yNWTneINA,6018 +urllib3/response.py,sha256=eo1Sfkn2x44FtjgP3qwwDsG9ak84spQAxEGy7Ovd4Pc,28221 +urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957 +urllib3/contrib/appengine.py,sha256=9RyUW5vKy4VPa2imtwBNWYKILrypr-K6UXEHUYsf0JY,11010 +urllib3/contrib/ntlmpool.py,sha256=a402AwGN_Ll3N-4ur_AS6UrU-ycUtlnYqoBF76lORg8,4160 +urllib3/contrib/pyopenssl.py,sha256=qQKqQXvlSvpCa2yEPxpdv18lS71SMESr9XzH9K9x3KI,16565 +urllib3/contrib/securetransport.py,sha256=vBDFjSnH2gWa-ztMKVaiwW46K1mlDZKqvo_VAonfdcY,32401 +urllib3/contrib/socks.py,sha256=nzDMgDIFJWVubKHqvIn2-SKCO91hhJInP92WgHChGzA,7036 +urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/contrib/_securetransport/bindings.py,sha256=mullWYFaghBdRWla6HYU-TBgFRTPLBEfxj3jplbeJmQ,16886 +urllib3/contrib/_securetransport/low_level.py,sha256=V7GnujxnWZh2N2sMsV5N4d9Imymokkm3zBwgt77_bSE,11956 +urllib3/packages/__init__.py,sha256=h4BLhD4tLaBx1adaDtKXfupsgqY0wWLXb_f1_yVlV6A,108 +urllib3/packages/six.py,sha256=adx4z-eM_D0Vvu0IIqVzFACQ_ux9l64y7DkSEfbxCDs,32536 +urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/packages/backports/makefile.py,sha256=005wrvH-_pWSnTFqQ2sdzzh4zVCtQUUQ4mR2Yyxwc0A,1418 +urllib3/packages/ssl_match_hostname/__init__.py,sha256=ywgKMtfHi1-DrXlzPfVAhzsLzzqcK7GT6eLgdode1Fg,688 +urllib3/packages/ssl_match_hostname/_implementation.py,sha256=6dZ-q074g7XhsJ27MFCgkct8iVNZB3sMZvKhf-KUVy0,5679 +urllib3/util/__init__.py,sha256=bWNaav_OT-1L7-sxm59cGb59rDORlbhb_4noduM5m0U,1038 +urllib3/util/connection.py,sha256=NsxUAKQ98GKywta--zg57CdVpeTCI6N-GElCq78Dl8U,4637 +urllib3/util/queue.py,sha256=myTX3JDHntglKQNBf3b6dasHH-uF-W59vzGSQiFdAfI,497 +urllib3/util/request.py,sha256=C-6-AWffxZG03AdRGoY59uqsn4CVItKU6gjxz7Hc3Mc,3815 +urllib3/util/response.py,sha256=_WbTQr8xRQuJuY2rTIZxVdJD6mnEOtQupjaK_bF_Vj8,2573 +urllib3/util/retry.py,sha256=3wbv7SdzYNOxPcBiFkPCubTbK1_6vWSepznOXirhUfA,15543 +urllib3/util/ssl_.py,sha256=R64MEN6Bh-YJq8b14kCb6hbV8L1p8oq4rcZiBow3tTQ,14511 +urllib3/util/timeout.py,sha256=3qawUo-TZq4q7tyeRToMIOdNGEOBjOOQVq7nHnLryP4,9947 +urllib3/util/url.py,sha256=jvkBGN64wo_Mx6Q6JYpFCGxamxbI2NdFoNQVTr7PUOM,13964 +urllib3/util/wait.py,sha256=k46KzqIYu3Vnzla5YW3EvtInNlU_QycFqQAghIOxoAg,5406 +urllib3-1.25.9.dist-info/LICENSE.txt,sha256=fA0TbuBYU4mt8tJWcbuZaHofdZKfRlt_Fu4_Ado3JV4,1115 +urllib3-1.25.9.dist-info/METADATA,sha256=QVc-HCXpe7Dm_RDmd-GpzKT-LvxBgwsPsLEiE5kUjEI,39852 +urllib3-1.25.9.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +urllib3-1.25.9.dist-info/top_level.txt,sha256=EMiXL2sKrTcmrMxIHTqdc3ET54pQI2Y072LexFEemvo,8 +urllib3-1.25.9.dist-info/RECORD,, diff --git a/third_party/python/urllib3/urllib3-1.25.9.dist-info/WHEEL b/third_party/python/urllib3/urllib3-1.25.9.dist-info/WHEEL new file mode 100644 index 000000000000..ef99c6cf3283 --- /dev/null +++ b/third_party/python/urllib3/urllib3-1.25.9.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/urllib3/src/urllib3.egg-info/top_level.txt b/third_party/python/urllib3/urllib3-1.25.9.dist-info/top_level.txt similarity index 100% rename from third_party/python/urllib3/src/urllib3.egg-info/top_level.txt rename to third_party/python/urllib3/urllib3-1.25.9.dist-info/top_level.txt diff --git a/third_party/python/urllib3/src/urllib3/__init__.py b/third_party/python/urllib3/urllib3/__init__.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/__init__.py rename to third_party/python/urllib3/urllib3/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/_collections.py b/third_party/python/urllib3/urllib3/_collections.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/_collections.py rename to third_party/python/urllib3/urllib3/_collections.py diff --git a/third_party/python/urllib3/src/urllib3/connection.py b/third_party/python/urllib3/urllib3/connection.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/connection.py rename to third_party/python/urllib3/urllib3/connection.py diff --git a/third_party/python/urllib3/src/urllib3/connectionpool.py b/third_party/python/urllib3/urllib3/connectionpool.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/connectionpool.py rename to third_party/python/urllib3/urllib3/connectionpool.py diff --git a/third_party/python/compare-locales/compare_locales/lint/__init__.py b/third_party/python/urllib3/urllib3/contrib/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/lint/__init__.py rename to third_party/python/urllib3/urllib3/contrib/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/_appengine_environ.py b/third_party/python/urllib3/urllib3/contrib/_appengine_environ.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/_appengine_environ.py rename to third_party/python/urllib3/urllib3/contrib/_appengine_environ.py diff --git a/third_party/python/compare-locales/compare_locales/tests/android/__init__.py b/third_party/python/urllib3/urllib3/contrib/_securetransport/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/tests/android/__init__.py rename to third_party/python/urllib3/urllib3/contrib/_securetransport/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/_securetransport/bindings.py b/third_party/python/urllib3/urllib3/contrib/_securetransport/bindings.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/_securetransport/bindings.py rename to third_party/python/urllib3/urllib3/contrib/_securetransport/bindings.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/_securetransport/low_level.py b/third_party/python/urllib3/urllib3/contrib/_securetransport/low_level.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/_securetransport/low_level.py rename to third_party/python/urllib3/urllib3/contrib/_securetransport/low_level.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/appengine.py b/third_party/python/urllib3/urllib3/contrib/appengine.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/appengine.py rename to third_party/python/urllib3/urllib3/contrib/appengine.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/ntlmpool.py b/third_party/python/urllib3/urllib3/contrib/ntlmpool.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/ntlmpool.py rename to third_party/python/urllib3/urllib3/contrib/ntlmpool.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/pyopenssl.py b/third_party/python/urllib3/urllib3/contrib/pyopenssl.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/pyopenssl.py rename to third_party/python/urllib3/urllib3/contrib/pyopenssl.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/securetransport.py b/third_party/python/urllib3/urllib3/contrib/securetransport.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/securetransport.py rename to third_party/python/urllib3/urllib3/contrib/securetransport.py diff --git a/third_party/python/urllib3/src/urllib3/contrib/socks.py b/third_party/python/urllib3/urllib3/contrib/socks.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/contrib/socks.py rename to third_party/python/urllib3/urllib3/contrib/socks.py diff --git a/third_party/python/urllib3/src/urllib3/exceptions.py b/third_party/python/urllib3/urllib3/exceptions.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/exceptions.py rename to third_party/python/urllib3/urllib3/exceptions.py diff --git a/third_party/python/urllib3/src/urllib3/fields.py b/third_party/python/urllib3/urllib3/fields.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/fields.py rename to third_party/python/urllib3/urllib3/fields.py diff --git a/third_party/python/urllib3/src/urllib3/filepost.py b/third_party/python/urllib3/urllib3/filepost.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/filepost.py rename to third_party/python/urllib3/urllib3/filepost.py diff --git a/third_party/python/urllib3/src/urllib3/packages/__init__.py b/third_party/python/urllib3/urllib3/packages/__init__.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/packages/__init__.py rename to third_party/python/urllib3/urllib3/packages/__init__.py diff --git a/third_party/python/compare-locales/compare_locales/tests/dtd/__init__.py b/third_party/python/urllib3/urllib3/packages/backports/__init__.py similarity index 100% rename from third_party/python/compare-locales/compare_locales/tests/dtd/__init__.py rename to third_party/python/urllib3/urllib3/packages/backports/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/packages/backports/makefile.py b/third_party/python/urllib3/urllib3/packages/backports/makefile.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/packages/backports/makefile.py rename to third_party/python/urllib3/urllib3/packages/backports/makefile.py diff --git a/third_party/python/urllib3/src/urllib3/packages/six.py b/third_party/python/urllib3/urllib3/packages/six.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/packages/six.py rename to third_party/python/urllib3/urllib3/packages/six.py diff --git a/third_party/python/urllib3/src/urllib3/packages/ssl_match_hostname/__init__.py b/third_party/python/urllib3/urllib3/packages/ssl_match_hostname/__init__.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/packages/ssl_match_hostname/__init__.py rename to third_party/python/urllib3/urllib3/packages/ssl_match_hostname/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/packages/ssl_match_hostname/_implementation.py b/third_party/python/urllib3/urllib3/packages/ssl_match_hostname/_implementation.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/packages/ssl_match_hostname/_implementation.py rename to third_party/python/urllib3/urllib3/packages/ssl_match_hostname/_implementation.py diff --git a/third_party/python/urllib3/src/urllib3/poolmanager.py b/third_party/python/urllib3/urllib3/poolmanager.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/poolmanager.py rename to third_party/python/urllib3/urllib3/poolmanager.py diff --git a/third_party/python/urllib3/src/urllib3/request.py b/third_party/python/urllib3/urllib3/request.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/request.py rename to third_party/python/urllib3/urllib3/request.py diff --git a/third_party/python/urllib3/src/urllib3/response.py b/third_party/python/urllib3/urllib3/response.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/response.py rename to third_party/python/urllib3/urllib3/response.py diff --git a/third_party/python/urllib3/src/urllib3/util/__init__.py b/third_party/python/urllib3/urllib3/util/__init__.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/__init__.py rename to third_party/python/urllib3/urllib3/util/__init__.py diff --git a/third_party/python/urllib3/src/urllib3/util/connection.py b/third_party/python/urllib3/urllib3/util/connection.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/connection.py rename to third_party/python/urllib3/urllib3/util/connection.py diff --git a/third_party/python/urllib3/src/urllib3/util/queue.py b/third_party/python/urllib3/urllib3/util/queue.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/queue.py rename to third_party/python/urllib3/urllib3/util/queue.py diff --git a/third_party/python/urllib3/src/urllib3/util/request.py b/third_party/python/urllib3/urllib3/util/request.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/request.py rename to third_party/python/urllib3/urllib3/util/request.py diff --git a/third_party/python/urllib3/src/urllib3/util/response.py b/third_party/python/urllib3/urllib3/util/response.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/response.py rename to third_party/python/urllib3/urllib3/util/response.py diff --git a/third_party/python/urllib3/src/urllib3/util/retry.py b/third_party/python/urllib3/urllib3/util/retry.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/retry.py rename to third_party/python/urllib3/urllib3/util/retry.py diff --git a/third_party/python/urllib3/src/urllib3/util/ssl_.py b/third_party/python/urllib3/urllib3/util/ssl_.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/ssl_.py rename to third_party/python/urllib3/urllib3/util/ssl_.py diff --git a/third_party/python/urllib3/src/urllib3/util/timeout.py b/third_party/python/urllib3/urllib3/util/timeout.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/timeout.py rename to third_party/python/urllib3/urllib3/util/timeout.py diff --git a/third_party/python/urllib3/src/urllib3/util/url.py b/third_party/python/urllib3/urllib3/util/url.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/url.py rename to third_party/python/urllib3/urllib3/util/url.py diff --git a/third_party/python/urllib3/src/urllib3/util/wait.py b/third_party/python/urllib3/urllib3/util/wait.py similarity index 100% rename from third_party/python/urllib3/src/urllib3/util/wait.py rename to third_party/python/urllib3/urllib3/util/wait.py diff --git a/third_party/python/voluptuous/CHANGELOG.md b/third_party/python/voluptuous/CHANGELOG.md deleted file mode 100644 index 90d644f34a4f..000000000000 --- a/third_party/python/voluptuous/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -# Changelog - -## [0.11.0] - -**Changes**: - -- [#293](https://github.com/alecthomas/voluptuous/pull/293): Support Python 3.6. -- [#294](https://github.com/alecthomas/voluptuous/pull/294): Drop support for Python 2.6, 3.1 and 3.2. -- [#318](https://github.com/alecthomas/voluptuous/pull/318): Allow to use nested schema and allow any validator to be compiled. -- [#324](https://github.com/alecthomas/voluptuous/pull/324): - Default values MUST now pass validation just as any regular value. This is a backward incompatible change if a schema uses default values that don't pass validation against the specified schema. -- [#328](https://github.com/alecthomas/voluptuous/pull/328): - Modify `__lt__` in Marker class to allow comparison with non Marker objects, such as str and int. - -**New**: - -- [#307](https://github.com/alecthomas/voluptuous/pull/307): Add description field to `Marker` instances. -- [#311](https://github.com/alecthomas/voluptuous/pull/311): Add `Schema.infer` method for basic schema inference. -- [#314](https://github.com/alecthomas/voluptuous/pull/314): Add `SomeOf` validator. - -**Fixes**: - -- [#279](https://github.com/alecthomas/voluptuous/pull/279): - Treat Python 2 old-style classes like types when validating. -- [#280](https://github.com/alecthomas/voluptuous/pull/280): Make - `IsDir()`, `IsFile()` and `PathExists()` consistent between different Python versions. -- [#290](https://github.com/alecthomas/voluptuous/pull/290): Use absolute imports to avoid import conflicts. -- [#291](https://github.com/alecthomas/voluptuous/pull/291): Fix `Coerce` validator to catch `decimal.InvalidOperation`. -- [#298](https://github.com/alecthomas/voluptuous/pull/298): Make `Schema([])` usage consistent with `Schema({})`. -- [#303](https://github.com/alecthomas/voluptuous/pull/303): Allow partial validation when using validate decorator. -- [#316](https://github.com/alecthomas/voluptuous/pull/316): Make `Schema.__eq__` deterministic. -- [#319](https://github.com/alecthomas/voluptuous/pull/319): Replace implementation of `Maybe(s)` with `Any(None, s)` to allow it to be compiled. - -## [0.10.5] - -- [#278](https://github.com/alecthomas/voluptuous/pull/278): Unicode -translation to python 2 issue fixed. - -## [0.10.2] - -**Changes**: - -- [#195](https://github.com/alecthomas/voluptuous/pull/195): - `Range` raises `RangeInvalid` when testing `math.nan`. -- [#215](https://github.com/alecthomas/voluptuous/pull/215): - `{}` and `[]` now always evaluate as is, instead of as any dict or any list. - To specify a free-form list, use `list` instead of `[]`. To specify a - free-form dict, use `dict` instead of `Schema({}, extra=ALLOW_EXTRA)`. -- [#224](https://github.com/alecthomas/voluptuous/pull/224): - Change the encoding of keys in error messages from Unicode to UTF-8. - -**New**: - -- [#185](https://github.com/alecthomas/voluptuous/pull/185): - Add argument validation decorator. -- [#199](https://github.com/alecthomas/voluptuous/pull/199): - Add `Unordered`. -- [#200](https://github.com/alecthomas/voluptuous/pull/200): - Add `Equal`. -- [#207](https://github.com/alecthomas/voluptuous/pull/207): - Add `Number`. -- [#210](https://github.com/alecthomas/voluptuous/pull/210): - Add `Schema` equality check. -- [#212](https://github.com/alecthomas/voluptuous/pull/212): - Add `coveralls`. -- [#227](https://github.com/alecthomas/voluptuous/pull/227): - Improve `Marker` management in `Schema`. -- [#232](https://github.com/alecthomas/voluptuous/pull/232): - Add `Maybe`. -- [#234](https://github.com/alecthomas/voluptuous/pull/234): - Add `Date`. -- [#236](https://github.com/alecthomas/voluptuous/pull/236), [#237](https://github.com/alecthomas/voluptuous/pull/237), and [#238](https://github.com/alecthomas/voluptuous/pull/238): - Add script for updating `gh-pages`. -- [#256](https://github.com/alecthomas/voluptuous/pull/256): - Add support for `OrderedDict` validation. -- [#258](https://github.com/alecthomas/voluptuous/pull/258): - Add `Contains`. - -**Fixes**: - -- [#197](https://github.com/alecthomas/voluptuous/pull/197): - `ExactSequence` checks sequences are the same length. -- [#201](https://github.com/alecthomas/voluptuous/pull/201): - Empty lists are evaluated as is. -- [#205](https://github.com/alecthomas/voluptuous/pull/205): - Filepath validators correctly handle `None`. -- [#206](https://github.com/alecthomas/voluptuous/pull/206): - Handle non-subscriptable types in `humanize_error`. -- [#231](https://github.com/alecthomas/voluptuous/pull/231): - Validate `namedtuple` as a `tuple`. -- [#235](https://github.com/alecthomas/voluptuous/pull/235): - Update docstring. -- [#249](https://github.com/alecthomas/voluptuous/pull/249): - Update documentation. -- [#262](https://github.com/alecthomas/voluptuous/pull/262): - Fix a performance issue of exponential complexity where all of the dict keys were matched against all keys in the schema. - This resulted in O(n*m) complexity where n is the number of keys in the dict being validated and m is the number of keys in the schema. - The fix ensures that each key in the dict is matched against the relevant schema keys only. It now works in O(n). -- [#266](https://github.com/alecthomas/voluptuous/pull/266): - Remove setuptools as a dependency. - -## 0.9.3 (2016-08-03) - -Changelog not kept for 0.9.3 and earlier releases. diff --git a/third_party/python/voluptuous/COPYING b/third_party/python/voluptuous/COPYING deleted file mode 100644 index a19b7057faab..000000000000 --- a/third_party/python/voluptuous/COPYING +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010, Alec Thomas -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - Neither the name of SwapOff.org nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/python/voluptuous/MANIFEST.in b/third_party/python/voluptuous/MANIFEST.in deleted file mode 100644 index dd15c3a1f682..000000000000 --- a/third_party/python/voluptuous/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include *.md -include COPYING -include voluptuous/tests/*.py -include voluptuous/tests/*.md diff --git a/third_party/python/voluptuous/PKG-INFO b/third_party/python/voluptuous/PKG-INFO deleted file mode 100644 index 999071c44eaf..000000000000 --- a/third_party/python/voluptuous/PKG-INFO +++ /dev/null @@ -1,744 +0,0 @@ -Metadata-Version: 2.1 -Name: voluptuous -Version: 0.11.5 -Summary: # Voluptuous is a Python data validation library -Home-page: https://github.com/alecthomas/voluptuous -Author: Alec Thomas -Author-email: alec@swapoff.org -License: BSD -Download-URL: https://pypi.python.org/pypi/voluptuous -Description: # Voluptuous is a Python data validation library - - [![Build Status](https://travis-ci.org/alecthomas/voluptuous.png)](https://travis-ci.org/alecthomas/voluptuous) - [![Coverage Status](https://coveralls.io/repos/github/alecthomas/voluptuous/badge.svg?branch=master)](https://coveralls.io/github/alecthomas/voluptuous?branch=master) [![Gitter chat](https://badges.gitter.im/alecthomas.png)](https://gitter.im/alecthomas/Lobby) - - Voluptuous, *despite* the name, is a Python data validation library. It - is primarily intended for validating data coming into Python as JSON, - YAML, etc. - - It has three goals: - - 1. Simplicity. - 2. Support for complex data structures. - 3. Provide useful error messages. - - ## Contact - - Voluptuous now has a mailing list! Send a mail to - [](mailto:voluptuous@librelist.com) to subscribe. Instructions - will follow. - - You can also contact me directly via [email](mailto:alec@swapoff.org) or - [Twitter](https://twitter.com/alecthomas). - - To file a bug, create a [new issue](https://github.com/alecthomas/voluptuous/issues/new) on GitHub with a short example of how to replicate the issue. - - ## Documentation - - The documentation is provided [here](http://alecthomas.github.io/voluptuous/). - - ## Changelog - - See [CHANGELOG.md](https://github.com/alecthomas/voluptuous/blob/master/CHANGELOG.md). - - ## Show me an example - - Twitter's [user search API](https://dev.twitter.com/rest/reference/get/users/search) accepts - query URLs like: - - ``` - $ curl 'https://api.twitter.com/1.1/users/search.json?q=python&per_page=20&page=1' - ``` - - To validate this we might use a schema like: - - ```pycon - >>> from voluptuous import Schema - >>> schema = Schema({ - ... 'q': str, - ... 'per_page': int, - ... 'page': int, - ... }) - - ``` - - This schema very succinctly and roughly describes the data required by - the API, and will work fine. But it has a few problems. Firstly, it - doesn't fully express the constraints of the API. According to the API, - `per_page` should be restricted to at most 20, defaulting to 5, for - example. To describe the semantics of the API more accurately, our - schema will need to be more thoroughly defined: - - ```pycon - >>> from voluptuous import Required, All, Length, Range - >>> schema = Schema({ - ... Required('q'): All(str, Length(min=1)), - ... Required('per_page', default=5): All(int, Range(min=1, max=20)), - ... 'page': All(int, Range(min=0)), - ... }) - - ``` - - This schema fully enforces the interface defined in Twitter's - documentation, and goes a little further for completeness. - - "q" is required: - - ```pycon - >>> from voluptuous import MultipleInvalid, Invalid - >>> try: - ... schema({}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "required key not provided @ data['q']" - True - - ``` - - ...must be a string: - - ```pycon - >>> try: - ... schema({'q': 123}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "expected str for dictionary value @ data['q']" - True - - ``` - - ...and must be at least one character in length: - - ```pycon - >>> try: - ... schema({'q': ''}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "length of value must be at least 1 for dictionary value @ data['q']" - True - >>> schema({'q': '#topic'}) == {'q': '#topic', 'per_page': 5} - True - - ``` - - "per\_page" is a positive integer no greater than 20: - - ```pycon - >>> try: - ... schema({'q': '#topic', 'per_page': 900}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "value must be at most 20 for dictionary value @ data['per_page']" - True - >>> try: - ... schema({'q': '#topic', 'per_page': -10}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "value must be at least 1 for dictionary value @ data['per_page']" - True - - ``` - - "page" is an integer \>= 0: - - ```pycon - >>> try: - ... schema({'q': '#topic', 'per_page': 'one'}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "expected int for dictionary value @ data['per_page']" - >>> schema({'q': '#topic', 'page': 1}) == {'q': '#topic', 'page': 1, 'per_page': 5} - True - - ``` - - ## Defining schemas - - Schemas are nested data structures consisting of dictionaries, lists, - scalars and *validators*. Each node in the input schema is pattern - matched against corresponding nodes in the input data. - - ### Literals - - Literals in the schema are matched using normal equality checks: - - ```pycon - >>> schema = Schema(1) - >>> schema(1) - 1 - >>> schema = Schema('a string') - >>> schema('a string') - 'a string' - - ``` - - ### Types - - Types in the schema are matched by checking if the corresponding value - is an instance of the type: - - ```pycon - >>> schema = Schema(int) - >>> schema(1) - 1 - >>> try: - ... schema('one') - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "expected int" - True - - ``` - - ### URL's - - URL's in the schema are matched by using `urlparse` library. - - ```pycon - >>> from voluptuous import Url - >>> schema = Schema(Url()) - >>> schema('http://w3.org') - 'http://w3.org' - >>> try: - ... schema('one') - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "expected a URL" - True - - ``` - - ### Lists - - Lists in the schema are treated as a set of valid values. Each element - in the schema list is compared to each value in the input data: - - ```pycon - >>> schema = Schema([1, 'a', 'string']) - >>> schema([1]) - [1] - >>> schema([1, 1, 1]) - [1, 1, 1] - >>> schema(['a', 1, 'string', 1, 'string']) - ['a', 1, 'string', 1, 'string'] - - ``` - - However, an empty list (`[]`) is treated as is. If you want to specify a list that can - contain anything, specify it as `list`: - - ```pycon - >>> schema = Schema([]) - >>> try: - ... schema([1]) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "not a valid value @ data[1]" - True - >>> schema([]) - [] - >>> schema = Schema(list) - >>> schema([]) - [] - >>> schema([1, 2]) - [1, 2] - - ``` - - ### Sets and frozensets - - Sets and frozensets are treated as a set of valid values. Each element - in the schema set is compared to each value in the input data: - - ```pycon - >>> schema = Schema({42}) - >>> schema({42}) == {42} - True - >>> try: - ... schema({43}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "invalid value in set" - True - >>> schema = Schema({int}) - >>> schema({1, 2, 3}) == {1, 2, 3} - True - >>> schema = Schema({int, str}) - >>> schema({1, 2, 'abc'}) == {1, 2, 'abc'} - True - >>> schema = Schema(frozenset([int])) - >>> try: - ... schema({3}) - ... raise AssertionError('Invalid not raised') - ... except Invalid as e: - ... exc = e - >>> str(exc) == 'expected a frozenset' - True - - ``` - - However, an empty set (`set()`) is treated as is. If you want to specify a set - that can contain anything, specify it as `set`: - - ```pycon - >>> schema = Schema(set()) - >>> try: - ... schema({1}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "invalid value in set" - True - >>> schema(set()) == set() - True - >>> schema = Schema(set) - >>> schema({1, 2}) == {1, 2} - True - - ``` - - ### Validation functions - - Validators are simple callables that raise an `Invalid` exception when - they encounter invalid data. The criteria for determining validity is - entirely up to the implementation; it may check that a value is a valid - username with `pwd.getpwnam()`, it may check that a value is of a - specific type, and so on. - - The simplest kind of validator is a Python function that raises - ValueError when its argument is invalid. Conveniently, many builtin - Python functions have this property. Here's an example of a date - validator: - - ```pycon - >>> from datetime import datetime - >>> def Date(fmt='%Y-%m-%d'): - ... return lambda v: datetime.strptime(v, fmt) - - ``` - - ```pycon - >>> schema = Schema(Date()) - >>> schema('2013-03-03') - datetime.datetime(2013, 3, 3, 0, 0) - >>> try: - ... schema('2013-03') - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "not a valid value" - True - - ``` - - In addition to simply determining if a value is valid, validators may - mutate the value into a valid form. An example of this is the - `Coerce(type)` function, which returns a function that coerces its - argument to the given type: - - ```python - def Coerce(type, msg=None): - """Coerce a value to a type. - - If the type constructor throws a ValueError, the value will be marked as - Invalid. - """ - def f(v): - try: - return type(v) - except ValueError: - raise Invalid(msg or ('expected %s' % type.__name__)) - return f - - ``` - - This example also shows a common idiom where an optional human-readable - message can be provided. This can vastly improve the usefulness of the - resulting error messages. - - ### Dictionaries - - Each key-value pair in a schema dictionary is validated against each - key-value pair in the corresponding data dictionary: - - ```pycon - >>> schema = Schema({1: 'one', 2: 'two'}) - >>> schema({1: 'one'}) - {1: 'one'} - - ``` - - #### Extra dictionary keys - - By default any additional keys in the data, not in the schema will - trigger exceptions: - - ```pycon - >>> schema = Schema({2: 3}) - >>> try: - ... schema({1: 2, 2: 3}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "extra keys not allowed @ data[1]" - True - - ``` - - This behaviour can be altered on a per-schema basis. To allow - additional keys use - `Schema(..., extra=ALLOW_EXTRA)`: - - ```pycon - >>> from voluptuous import ALLOW_EXTRA - >>> schema = Schema({2: 3}, extra=ALLOW_EXTRA) - >>> schema({1: 2, 2: 3}) - {1: 2, 2: 3} - - ``` - - To remove additional keys use - `Schema(..., extra=REMOVE_EXTRA)`: - - ```pycon - >>> from voluptuous import REMOVE_EXTRA - >>> schema = Schema({2: 3}, extra=REMOVE_EXTRA) - >>> schema({1: 2, 2: 3}) - {2: 3} - - ``` - - It can also be overridden per-dictionary by using the catch-all marker - token `extra` as a key: - - ```pycon - >>> from voluptuous import Extra - >>> schema = Schema({1: {Extra: object}}) - >>> schema({1: {'foo': 'bar'}}) - {1: {'foo': 'bar'}} - - ``` - - #### Required dictionary keys - - By default, keys in the schema are not required to be in the data: - - ```pycon - >>> schema = Schema({1: 2, 3: 4}) - >>> schema({3: 4}) - {3: 4} - - ``` - - Similarly to how extra\_ keys work, this behaviour can be overridden - per-schema: - - ```pycon - >>> schema = Schema({1: 2, 3: 4}, required=True) - >>> try: - ... schema({3: 4}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "required key not provided @ data[1]" - True - - ``` - - And per-key, with the marker token `Required(key)`: - - ```pycon - >>> schema = Schema({Required(1): 2, 3: 4}) - >>> try: - ... schema({3: 4}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "required key not provided @ data[1]" - True - >>> schema({1: 2}) - {1: 2} - - ``` - - #### Optional dictionary keys - - If a schema has `required=True`, keys may be individually marked as - optional using the marker token `Optional(key)`: - - ```pycon - >>> from voluptuous import Optional - >>> schema = Schema({1: 2, Optional(3): 4}, required=True) - >>> try: - ... schema({}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "required key not provided @ data[1]" - True - >>> schema({1: 2}) - {1: 2} - >>> try: - ... schema({1: 2, 4: 5}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "extra keys not allowed @ data[4]" - True - - ``` - - ```pycon - >>> schema({1: 2, 3: 4}) - {1: 2, 3: 4} - - ``` - - ### Recursive / nested schema - - You can use `voluptuous.Self` to define a nested schema: - - ```pycon - >>> from voluptuous import Schema, Self - >>> recursive = Schema({"more": Self, "value": int}) - >>> recursive({"more": {"value": 42}, "value": 41}) == {'more': {'value': 42}, 'value': 41} - True - - ``` - - ### Extending an existing Schema - - Often it comes handy to have a base `Schema` that is extended with more - requirements. In that case you can use `Schema.extend` to create a new - `Schema`: - - ```pycon - >>> from voluptuous import Schema - >>> person = Schema({'name': str}) - >>> person_with_age = person.extend({'age': int}) - >>> sorted(list(person_with_age.schema.keys())) - ['age', 'name'] - - ``` - - The original `Schema` remains unchanged. - - ### Objects - - Each key-value pair in a schema dictionary is validated against each - attribute-value pair in the corresponding object: - - ```pycon - >>> from voluptuous import Object - >>> class Structure(object): - ... def __init__(self, q=None): - ... self.q = q - ... def __repr__(self): - ... return ''.format(self) - ... - >>> schema = Schema(Object({'q': 'one'}, cls=Structure)) - >>> schema(Structure(q='one')) - - - ``` - - ### Allow None values - - To allow value to be None as well, use Any: - - ```pycon - >>> from voluptuous import Any - - >>> schema = Schema(Any(None, int)) - >>> schema(None) - >>> schema(5) - 5 - - ``` - - ## Error reporting - - Validators must throw an `Invalid` exception if invalid data is passed - to them. All other exceptions are treated as errors in the validator and - will not be caught. - - Each `Invalid` exception has an associated `path` attribute representing - the path in the data structure to our currently validating value, as well - as an `error_message` attribute that contains the message of the original - exception. This is especially useful when you want to catch `Invalid` - exceptions and give some feedback to the user, for instance in the context of - an HTTP API. - - - ```pycon - >>> def validate_email(email): - ... """Validate email.""" - ... if not "@" in email: - ... raise Invalid("This email is invalid.") - ... return email - >>> schema = Schema({"email": validate_email}) - >>> exc = None - >>> try: - ... schema({"email": "whatever"}) - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "This email is invalid. for dictionary value @ data['email']" - >>> exc.path - ['email'] - >>> exc.msg - 'This email is invalid.' - >>> exc.error_message - 'This email is invalid.' - - ``` - - The `path` attribute is used during error reporting, but also during matching - to determine whether an error should be reported to the user or if the next - match should be attempted. This is determined by comparing the depth of the - path where the check is, to the depth of the path where the error occurred. If - the error is more than one level deeper, it is reported. - - The upshot of this is that *matching is depth-first and fail-fast*. - - To illustrate this, here is an example schema: - - ```pycon - >>> schema = Schema([[2, 3], 6]) - - ``` - - Each value in the top-level list is matched depth-first in-order. Given - input data of `[[6]]`, the inner list will match the first element of - the schema, but the literal `6` will not match any of the elements of - that list. This error will be reported back to the user immediately. No - backtracking is attempted: - - ```pycon - >>> try: - ... schema([[6]]) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == "not a valid value @ data[0][0]" - True - - ``` - - If we pass the data `[6]`, the `6` is not a list type and so will not - recurse into the first element of the schema. Matching will continue on - to the second element in the schema, and succeed: - - ```pycon - >>> schema([6]) - [6] - - ``` - - ## Multi-field validation - - Validation rules that involve multiple fields can be implemented as - custom validators. It's recommended to use `All()` to do a two-pass - validation - the first pass checking the basic structure of the data, - and only after that, the second pass applying your cross-field - validator: - - ```python - def passwords_must_match(passwords): - if passwords['password'] != passwords['password_again']: - raise Invalid('passwords must match') - return passwords - - s=Schema(All( - # First "pass" for field types - {'password':str, 'password_again':str}, - # Follow up the first "pass" with your multi-field rules - passwords_must_match - )) - - # valid - s({'password':'123', 'password_again':'123'}) - - # raises MultipleInvalid: passwords must match - s({'password':'123', 'password_again':'and now for something completely different'}) - - ``` - - With this structure, your multi-field validator will run with - pre-validated data from the first "pass" and so will not have to do - its own type checking on its inputs. - - The flipside is that if the first "pass" of validation fails, your - cross-field validator will not run: - - ``` - # raises Invalid because password_again is not a string - # passwords_must_match() will not run because first-pass validation already failed - s({'password':'123', 'password_again': 1337}) - ``` - - ## Running tests. - - Voluptuous is using nosetests: - - $ nosetests - - - ## Why use Voluptuous over another validation library? - - **Validators are simple callables** - : No need to subclass anything, just use a function. - - **Errors are simple exceptions.** - : A validator can just `raise Invalid(msg)` and expect the user to get - useful messages. - - **Schemas are basic Python data structures.** - : Should your data be a dictionary of integer keys to strings? - `{int: str}` does what you expect. List of integers, floats or - strings? `[int, float, str]`. - - **Designed from the ground up for validating more than just forms.** - : Nested data structures are treated in the same way as any other - type. Need a list of dictionaries? `[{}]` - - **Consistency.** - : Types in the schema are checked as types. Values are compared as - values. Callables are called to validate. Simple. - - ## Other libraries and inspirations - - Voluptuous is heavily inspired by - [Validino](http://code.google.com/p/validino/), and to a lesser extent, - [jsonvalidator](http://code.google.com/p/jsonvalidator/) and - [json\_schema](http://blog.sendapatch.se/category/json_schema.html). - - [pytest-voluptuous](https://github.com/F-Secure/pytest-voluptuous) is a - [pytest](https://github.com/pytest-dev/pytest) plugin that helps in - using voluptuous validators in `assert`s. - - I greatly prefer the light-weight style promoted by these libraries to - the complexity of libraries like FormEncode. - -Platform: any -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Description-Content-Type: text/markdown diff --git a/third_party/python/voluptuous/setup.cfg b/third_party/python/voluptuous/setup.cfg deleted file mode 100644 index 1ccde4cee70e..000000000000 --- a/third_party/python/voluptuous/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[nosetests] -doctest-extension = md -with-doctest = 1 -where = . - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/voluptuous/setup.py b/third_party/python/voluptuous/setup.py deleted file mode 100644 index 6408f8ba962d..000000000000 --- a/third_party/python/voluptuous/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -from setuptools import setup - -import sys -import io -import os -import atexit -sys.path.insert(0, '.') -version = __import__('voluptuous').__version__ - - -with io.open('README.md', encoding='utf-8') as f: - long_description = f.read() - description = long_description.splitlines()[0].strip() - - -setup( - name='voluptuous', - url='https://github.com/alecthomas/voluptuous', - download_url='https://pypi.python.org/pypi/voluptuous', - version=version, - description=description, - long_description=long_description, - long_description_content_type='text/markdown', - license='BSD', - platforms=['any'], - packages=['voluptuous'], - author='Alec Thomas', - author_email='alec@swapoff.org', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - ] -) diff --git a/third_party/python/voluptuous/README.md b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/METADATA similarity index 95% rename from third_party/python/voluptuous/README.md rename to third_party/python/voluptuous/voluptuous-0.11.5.dist-info/METADATA index 46e2288f4bea..f23ce28ad57b 100644 --- a/third_party/python/voluptuous/README.md +++ b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/METADATA @@ -1,3 +1,24 @@ +Metadata-Version: 2.1 +Name: voluptuous +Version: 0.11.5 +Summary: # Voluptuous is a Python data validation library +Home-page: https://github.com/alecthomas/voluptuous +Author: Alec Thomas +Author-email: alec@swapoff.org +License: BSD +Download-URL: https://pypi.python.org/pypi/voluptuous +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown + # Voluptuous is a Python data validation library [![Build Status](https://travis-ci.org/alecthomas/voluptuous.png)](https://travis-ci.org/alecthomas/voluptuous) @@ -721,3 +742,5 @@ using voluptuous validators in `assert`s. I greatly prefer the light-weight style promoted by these libraries to the complexity of libraries like FormEncode. + + diff --git a/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/RECORD b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/RECORD new file mode 100644 index 000000000000..bf4ec2148c5d --- /dev/null +++ b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/RECORD @@ -0,0 +1,10 @@ +voluptuous/__init__.py,sha256=hppVuMXqmcq5q7ASwYKSsfaoZqOc56WZHdhGlO2e8BQ,203 +voluptuous/error.py,sha256=RDXTdcUBsrtBQtdXotSoLorINZJdDxFaL8aelzROb6I,4017 +voluptuous/humanize.py,sha256=hZlhdN4aVeGDIXdtSTeyEbmku65SDPRuut3mOfuRQP0,1606 +voluptuous/schema_builder.py,sha256=T4qOtzYCFaJFUEbyz9CfOcAnstdfoprAoF693KsVO3k,43368 +voluptuous/util.py,sha256=fRekWRV7CzJ2yRQO3csmB77PwTRBTZ2BPuy5E6kGELo,2990 +voluptuous/validators.py,sha256=abvmcKM_Ai2cMjQWauhXWAp6ShPlrJl5RUiCnTQBOfI,29543 +voluptuous-0.11.5.dist-info/METADATA,sha256=9qWbPg_TsTAMNJ53kZDs4AcbSSukljEy_u-eRqbzNVc,19196 +voluptuous-0.11.5.dist-info/RECORD,, +voluptuous-0.11.5.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110 +voluptuous-0.11.5.dist-info/top_level.txt,sha256=TTdVb7M-vndb67UqTmAxuVjpAUakrlAWJYqvo3w4Iqc,11 diff --git a/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/WHEEL b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/WHEEL new file mode 100644 index 000000000000..1316c41d0706 --- /dev/null +++ b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/top_level.txt b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/top_level.txt new file mode 100644 index 000000000000..55356d5da860 --- /dev/null +++ b/third_party/python/voluptuous/voluptuous-0.11.5.dist-info/top_level.txt @@ -0,0 +1 @@ +voluptuous diff --git a/third_party/python/voluptuous/voluptuous/tests/__init__.py b/third_party/python/voluptuous/voluptuous/tests/__init__.py deleted file mode 100644 index f29719c7262f..000000000000 --- a/third_party/python/voluptuous/voluptuous/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'tusharmakkar08' diff --git a/third_party/python/voluptuous/voluptuous/tests/tests.md b/third_party/python/voluptuous/voluptuous/tests/tests.md deleted file mode 100644 index 5ba97ab64b54..000000000000 --- a/third_party/python/voluptuous/voluptuous/tests/tests.md +++ /dev/null @@ -1,273 +0,0 @@ -Error reporting should be accurate: - - >>> from voluptuous import * - >>> schema = Schema(['one', {'two': 'three', 'four': ['five'], - ... 'six': {'seven': 'eight'}}]) - >>> schema(['one']) - ['one'] - >>> schema([{'two': 'three'}]) - [{'two': 'three'}] - -It should show the exact index and container type, in this case a list -value: - - >>> try: - ... schema(['one', 'two']) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) == 'expected a dictionary @ data[1]' - True - -It should also be accurate for nested values: - - >>> try: - ... schema([{'two': 'nine'}]) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "not a valid value for dictionary value @ data[0]['two']" - - >>> try: - ... schema([{'four': ['nine']}]) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "not a valid value @ data[0]['four'][0]" - - >>> try: - ... schema([{'six': {'seven': 'nine'}}]) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "not a valid value for dictionary value @ data[0]['six']['seven']" - -Errors should be reported depth-first: - - >>> validate = Schema({'one': {'two': 'three', 'four': 'five'}}) - >>> try: - ... validate({'one': {'four': 'six'}}) - ... except Invalid as e: - ... print(e) - ... print(e.path) - not a valid value for dictionary value @ data['one']['four'] - ['one', 'four'] - -Voluptuous supports validation when extra fields are present in the -data: - - >>> schema = Schema({'one': 1, Extra: object}) - >>> schema({'two': 'two', 'one': 1}) == {'two': 'two', 'one': 1} - True - >>> schema = Schema({'one': 1}) - >>> try: - ... schema({'two': 2}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "extra keys not allowed @ data['two']" - -dict, list, and tuple should be available as type validators: - - >>> Schema(dict)({'a': 1, 'b': 2}) == {'a': 1, 'b': 2} - True - >>> Schema(list)([1,2,3]) - [1, 2, 3] - >>> Schema(tuple)((1,2,3)) - (1, 2, 3) - -Validation should return instances of the right types when the types are -subclasses of dict or list: - - >>> class Dict(dict): - ... pass - >>> - >>> d = Schema(dict)(Dict(a=1, b=2)) - >>> d == {'a': 1, 'b': 2} - True - >>> type(d) is Dict - True - >>> class List(list): - ... pass - >>> - >>> l = Schema(list)(List([1,2,3])) - >>> l - [1, 2, 3] - >>> type(l) is List - True - -Multiple errors are reported: - - >>> schema = Schema({'one': 1, 'two': 2}) - >>> try: - ... schema({'one': 2, 'two': 3, 'three': 4}) - ... except MultipleInvalid as e: - ... errors = sorted(e.errors, key=lambda k: str(k)) - ... print([str(i) for i in errors]) # doctest: +NORMALIZE_WHITESPACE - ["extra keys not allowed @ data['three']", - "not a valid value for dictionary value @ data['one']", - "not a valid value for dictionary value @ data['two']"] - >>> schema = Schema([[1], [2], [3]]) - >>> try: - ... schema([1, 2, 3]) - ... except MultipleInvalid as e: - ... print([str(i) for i in e.errors]) # doctest: +NORMALIZE_WHITESPACE - ['expected a list @ data[0]', - 'expected a list @ data[1]', - 'expected a list @ data[2]'] - -Required fields in dictionary which are invalid should not have required : - - >>> from voluptuous import * - >>> schema = Schema({'one': {'two': 3}}, required=True) - >>> try: - ... schema({'one': {'two': 2}}) - ... except MultipleInvalid as e: - ... errors = e.errors - >>> 'required' in ' '.join([x.msg for x in errors]) - False - -Multiple errors for nested fields in dicts and objects: - -> \>\>\> from collections import namedtuple \>\>\> validate = Schema({ -> ... 'anobject': Object({ ... 'strfield': str, ... 'intfield': int ... -> }) ... }) \>\>\> try: ... SomeObj = namedtuple('SomeObj', ('strfield', -> 'intfield')) ... validate({'anobject': SomeObj(strfield=123, -> intfield='one')}) ... except MultipleInvalid as e: ... -> print(sorted(str(i) for i in e.errors)) \# doctest: -> +NORMALIZE\_WHITESPACE ["expected int for object value @ -> data['anobject']['intfield']", "expected str for object value @ -> data['anobject']['strfield']"] - -Custom classes validate as schemas: - - >>> class Thing(object): - ... pass - >>> schema = Schema(Thing) - >>> t = schema(Thing()) - >>> type(t) is Thing - True - -Classes with custom metaclasses should validate as schemas: - - >>> class MyMeta(type): - ... pass - >>> class Thing(object): - ... __metaclass__ = MyMeta - >>> schema = Schema(Thing) - >>> t = schema(Thing()) - >>> type(t) is Thing - True - -Schemas built with All() should give the same error as the original -validator (Issue \#26): - - >>> schema = Schema({ - ... Required('items'): All([{ - ... Required('foo'): str - ... }]) - ... }) - - >>> try: - ... schema({'items': [{}]}) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "required key not provided @ data['items'][0]['foo']" - -Validator should return same instance of the same type for object: - - >>> class Structure(object): - ... def __init__(self, q=None): - ... self.q = q - ... def __repr__(self): - ... return '{0.__name__}(q={1.q!r})'.format(type(self), self) - ... - >>> schema = Schema(Object({'q': 'one'}, cls=Structure)) - >>> type(schema(Structure(q='one'))) is Structure - True - -Object validator should treat cls argument as optional. In this case it -shouldn't check object type: - - >>> from collections import namedtuple - >>> NamedTuple = namedtuple('NamedTuple', ('q',)) - >>> schema = Schema(Object({'q': 'one'})) - >>> named = NamedTuple(q='one') - >>> schema(named) == named - True - >>> schema(named) - NamedTuple(q='one') - -If cls argument passed to object validator we should check object type: - - >>> schema = Schema(Object({'q': 'one'}, cls=Structure)) - >>> schema(NamedTuple(q='one')) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - MultipleInvalid: expected a - >>> schema = Schema(Object({'q': 'one'}, cls=NamedTuple)) - >>> schema(NamedTuple(q='one')) - NamedTuple(q='one') - -Ensure that objects with \_\_slots\_\_ supported properly: - - >>> class SlotsStructure(Structure): - ... __slots__ = ['q'] - ... - >>> schema = Schema(Object({'q': 'one'})) - >>> schema(SlotsStructure(q='one')) - SlotsStructure(q='one') - >>> class DictStructure(object): - ... __slots__ = ['q', '__dict__'] - ... def __init__(self, q=None, page=None): - ... self.q = q - ... self.page = page - ... def __repr__(self): - ... return '{0.__name__}(q={1.q!r}, page={1.page!r})'.format(type(self), self) - ... - >>> structure = DictStructure(q='one') - >>> structure.page = 1 - >>> try: - ... schema(structure) - ... raise AssertionError('MultipleInvalid not raised') - ... except MultipleInvalid as e: - ... exc = e - >>> str(exc) - "extra keys not allowed @ data['page']" - - >>> schema = Schema(Object({'q': 'one', Extra: object})) - >>> schema(structure) - DictStructure(q='one', page=1) - -Ensure that objects can be used with other validators: - - >>> schema = Schema({'meta': Object({'q': 'one'})}) - >>> schema({'meta': Structure(q='one')}) - {'meta': Structure(q='one')} - -Ensure that subclasses of Invalid of are raised as is. - - >>> class SpecialInvalid(Invalid): - ... pass - ... - >>> def custom_validator(value): - ... raise SpecialInvalid('boom') - ... - >>> schema = Schema({'thing': custom_validator}) - >>> try: - ... schema({'thing': 'not an int'}) - ... except MultipleInvalid as e: - ... exc = e - >>> exc.errors[0].__class__.__name__ - 'SpecialInvalid' - -Ensure that Optional('Classification') < 'Name' will return True instead of throwing an AttributeError - - >>> Optional('Classification') < 'Name' - True diff --git a/third_party/python/voluptuous/voluptuous/tests/tests.py b/third_party/python/voluptuous/voluptuous/tests/tests.py deleted file mode 100644 index fa44fbf770af..000000000000 --- a/third_party/python/voluptuous/voluptuous/tests/tests.py +++ /dev/null @@ -1,1265 +0,0 @@ -import copy -import collections -import os -import sys - -from nose.tools import assert_equal, assert_false, assert_raises, assert_true - -from voluptuous import ( - Schema, Required, Exclusive, Optional, Extra, Invalid, In, Remove, Literal, - Url, MultipleInvalid, LiteralInvalid, TypeInvalid, NotIn, Match, Email, - Replace, Range, Coerce, All, Any, Length, FqdnUrl, ALLOW_EXTRA, PREVENT_EXTRA, - validate, ExactSequence, Equal, Unordered, Number, Maybe, Datetime, Date, - Contains, Marker, IsDir, IsFile, PathExists, SomeOf, TooManyValid, Self, - raises) -from voluptuous.humanize import humanize_error -from voluptuous.util import u - - -def test_exact_sequence(): - schema = Schema(ExactSequence([int, int])) - try: - schema([1, 2, 3]) - except Invalid: - assert True - else: - assert False, "Did not raise Invalid" - assert_equal(schema([1, 2]), [1, 2]) - - -def test_required(): - """Verify that Required works.""" - schema = Schema({Required('q'): 1}) - # Can't use nose's raises (because we need to access the raised - # exception, nor assert_raises which fails with Python 2.6.9. - try: - schema({}) - except Invalid as e: - assert_equal(str(e), "required key not provided @ data['q']") - else: - assert False, "Did not raise Invalid" - - -def test_extra_with_required(): - """Verify that Required does not break Extra.""" - schema = Schema({Required('toaster'): str, Extra: object}) - r = schema({'toaster': 'blue', 'another_valid_key': 'another_valid_value'}) - assert_equal( - r, {'toaster': 'blue', 'another_valid_key': 'another_valid_value'}) - - -def test_iterate_candidates(): - """Verify that the order for iterating over mapping candidates is right.""" - schema = { - "toaster": str, - Extra: object, - } - # toaster should be first. - from voluptuous.schema_builder import _iterate_mapping_candidates - assert_equal(_iterate_mapping_candidates(schema)[0][0], 'toaster') - - -def test_in(): - """Verify that In works.""" - schema = Schema({"color": In(frozenset(["blue", "red", "yellow"]))}) - schema({"color": "blue"}) - - -def test_not_in(): - """Verify that NotIn works.""" - schema = Schema({"color": NotIn(frozenset(["blue", "red", "yellow"]))}) - schema({"color": "orange"}) - try: - schema({"color": "blue"}) - except Invalid as e: - assert_equal(str(e), "value is not allowed for dictionary value @ data['color']") - else: - assert False, "Did not raise NotInInvalid" - - -def test_contains(): - """Verify contains validation method.""" - schema = Schema({'color': Contains('red')}) - schema({'color': ['blue', 'red', 'yellow']}) - try: - schema({'color': ['blue', 'yellow']}) - except Invalid as e: - assert_equal(str(e), - "value is not allowed for dictionary value @ data['color']") - - -def test_remove(): - """Verify that Remove works.""" - # remove dict keys - schema = Schema({"weight": int, - Remove("color"): str, - Remove("amount"): int}) - out_ = schema({"weight": 10, "color": "red", "amount": 1}) - assert "color" not in out_ and "amount" not in out_ - - # remove keys by type - schema = Schema({"weight": float, - "amount": int, - # remvove str keys with int values - Remove(str): int, - # keep str keys with str values - str: str}) - out_ = schema({"weight": 73.4, - "condition": "new", - "amount": 5, - "left": 2}) - # amount should stay since it's defined - # other string keys with int values will be removed - assert "amount" in out_ and "left" not in out_ - # string keys with string values will stay - assert "condition" in out_ - - # remove value from list - schema = Schema([Remove(1), int]) - out_ = schema([1, 2, 3, 4, 1, 5, 6, 1, 1, 1]) - assert_equal(out_, [2, 3, 4, 5, 6]) - - # remove values from list by type - schema = Schema([1.0, Remove(float), int]) - out_ = schema([1, 2, 1.0, 2.0, 3.0, 4]) - assert_equal(out_, [1, 2, 1.0, 4]) - - -def test_extra_empty_errors(): - schema = Schema({'a': {Extra: object}}, required=True) - schema({'a': {}}) - - -def test_literal(): - """ test with Literal """ - - schema = Schema([Literal({"a": 1}), Literal({"b": 1})]) - schema([{"a": 1}]) - schema([{"b": 1}]) - schema([{"a": 1}, {"b": 1}]) - - try: - schema([{"c": 1}]) - except Invalid as e: - assert_equal(str(e), "{'c': 1} not match for {'b': 1} @ data[0]") - else: - assert False, "Did not raise Invalid" - - schema = Schema(Literal({"a": 1})) - try: - schema({"b": 1}) - except MultipleInvalid as e: - assert_equal(str(e), "{'b': 1} not match for {'a': 1}") - assert_equal(len(e.errors), 1) - assert_equal(type(e.errors[0]), LiteralInvalid) - else: - assert False, "Did not raise Invalid" - - -def test_class(): - class C1(object): - pass - - schema = Schema(C1) - schema(C1()) - - try: - schema(None) - except MultipleInvalid as e: - assert_equal(str(e), "expected C1") - assert_equal(len(e.errors), 1) - assert_equal(type(e.errors[0]), TypeInvalid) - else: - assert False, "Did not raise Invalid" - - # In Python 2, this will be an old-style class (classobj instance) - class C2: - pass - - schema = Schema(C2) - schema(C2()) - - try: - schema(None) - except MultipleInvalid as e: - assert_equal(str(e), "expected C2") - assert_equal(len(e.errors), 1) - assert_equal(type(e.errors[0]), TypeInvalid) - else: - assert False, "Did not raise Invalid" - - -def test_email_validation(): - """ test with valid email """ - schema = Schema({"email": Email()}) - out_ = schema({"email": "example@example.com"}) - - assert 'example@example.com"', out_.get("url") - - -def test_email_validation_with_none(): - """ test with invalid None Email""" - schema = Schema({"email": Email()}) - try: - schema({"email": None}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected an Email for dictionary value @ data['email']") - else: - assert False, "Did not raise Invalid for None url" - - -def test_email_validation_with_empty_string(): - """ test with empty string Email""" - schema = Schema({"email": Email()}) - try: - schema({"email": ''}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected an Email for dictionary value @ data['email']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_email_validation_without_host(): - """ test with empty host name in email """ - schema = Schema({"email": Email()}) - try: - schema({"email": 'a@.com'}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected an Email for dictionary value @ data['email']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_fqdn_url_validation(): - """ test with valid fully qualified domain name url """ - schema = Schema({"url": FqdnUrl()}) - out_ = schema({"url": "http://example.com/"}) - - assert 'http://example.com/', out_.get("url") - - -def test_fqdn_url_without_domain_name(): - """ test with invalid fully qualified domain name url """ - schema = Schema({"url": FqdnUrl()}) - try: - schema({"url": "http://localhost/"}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a Fully qualified domain name URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for None url" - - -def test_fqdnurl_validation_with_none(): - """ test with invalid None FQDN url""" - schema = Schema({"url": FqdnUrl()}) - try: - schema({"url": None}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a Fully qualified domain name URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for None url" - - -def test_fqdnurl_validation_with_empty_string(): - """ test with empty string FQDN URL """ - schema = Schema({"url": FqdnUrl()}) - try: - schema({"url": ''}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a Fully qualified domain name URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_fqdnurl_validation_without_host(): - """ test with empty host FQDN URL """ - schema = Schema({"url": FqdnUrl()}) - try: - schema({"url": 'http://'}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a Fully qualified domain name URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_url_validation(): - """ test with valid URL """ - schema = Schema({"url": Url()}) - out_ = schema({"url": "http://example.com/"}) - - assert 'http://example.com/', out_.get("url") - - -def test_url_validation_with_none(): - """ test with invalid None url""" - schema = Schema({"url": Url()}) - try: - schema({"url": None}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for None url" - - -def test_url_validation_with_empty_string(): - """ test with empty string URL """ - schema = Schema({"url": Url()}) - try: - schema({"url": ''}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_url_validation_without_host(): - """ test with empty host URL """ - schema = Schema({"url": Url()}) - try: - schema({"url": 'http://'}) - except MultipleInvalid as e: - assert_equal(str(e), - "expected a URL for dictionary value @ data['url']") - else: - assert False, "Did not raise Invalid for empty string url" - - -def test_copy_dict_undefined(): - """ test with a copied dictionary """ - fields = { - Required("foo"): int - } - copied_fields = copy.deepcopy(fields) - - schema = Schema(copied_fields) - - # This used to raise a `TypeError` because the instance of `Undefined` - # was a copy, so object comparison would not work correctly. - try: - schema({"foo": "bar"}) - except Exception as e: - assert isinstance(e, MultipleInvalid) - - -def test_sorting(): - """ Expect alphabetic sorting """ - foo = Required('foo') - bar = Required('bar') - items = [foo, bar] - expected = [bar, foo] - result = sorted(items) - assert result == expected - - -def test_schema_extend(): - """Verify that Schema.extend copies schema keys from both.""" - - base = Schema({'a': int}, required=True) - extension = {'b': str} - extended = base.extend(extension) - - assert base.schema == {'a': int} - assert extension == {'b': str} - assert extended.schema == {'a': int, 'b': str} - assert extended.required == base.required - assert extended.extra == base.extra - - -def test_schema_extend_overrides(): - """Verify that Schema.extend can override required/extra parameters.""" - - base = Schema({'a': int}, required=True) - extended = base.extend({'b': str}, required=False, extra=ALLOW_EXTRA) - - assert base.required is True - assert base.extra == PREVENT_EXTRA - assert extended.required is False - assert extended.extra == ALLOW_EXTRA - - -def test_schema_extend_key_swap(): - """Verify that Schema.extend can replace keys, even when different markers are used""" - - base = Schema({Optional('a'): int}) - extension = {Required('a'): int} - extended = base.extend(extension) - - assert_equal(len(base.schema), 1) - assert_true(isinstance(list(base.schema)[0], Optional)) - assert_equal(len(extended.schema), 1) - assert_true((list(extended.schema)[0], Required)) - - -def test_subschema_extension(): - """Verify that Schema.extend adds and replaces keys in a subschema""" - - base = Schema({'a': {'b': int, 'c': float}}) - extension = {'d': str, 'a': {'b': str, 'e': int}} - extended = base.extend(extension) - - assert_equal(base.schema, {'a': {'b': int, 'c': float}}) - assert_equal(extension, {'d': str, 'a': {'b': str, 'e': int}}) - assert_equal(extended.schema, {'a': {'b': str, 'c': float, 'e': int}, 'd': str}) - - -def test_equality(): - assert_equal(Schema('foo'), Schema('foo')) - - assert_equal(Schema(['foo', 'bar', 'baz']), - Schema(['foo', 'bar', 'baz'])) - - # Ensure two Schemas w/ two equivalent dicts initialized in a different - # order are considered equal. - dict_a = {} - dict_a['foo'] = 1 - dict_a['bar'] = 2 - dict_a['baz'] = 3 - - dict_b = {} - dict_b['baz'] = 3 - dict_b['bar'] = 2 - dict_b['foo'] = 1 - - assert_equal(Schema(dict_a), Schema(dict_b)) - - -def test_equality_negative(): - """Verify that Schema objects are not equal to string representations""" - assert_false(Schema('foo') == 'foo') - - assert_false(Schema(['foo', 'bar']) == "['foo', 'bar']") - assert_false(Schema(['foo', 'bar']) == Schema("['foo', 'bar']")) - - assert_false(Schema({'foo': 1, 'bar': 2}) == "{'foo': 1, 'bar': 2}") - assert_false(Schema({'foo': 1, 'bar': 2}) == Schema("{'foo': 1, 'bar': 2}")) - - -def test_inequality(): - assert_true(Schema('foo') != 'foo') - - assert_true(Schema(['foo', 'bar']) != "['foo', 'bar']") - assert_true(Schema(['foo', 'bar']) != Schema("['foo', 'bar']")) - - assert_true(Schema({'foo': 1, 'bar': 2}) != "{'foo': 1, 'bar': 2}") - assert_true(Schema({'foo': 1, 'bar': 2}) != Schema("{'foo': 1, 'bar': 2}")) - - -def test_inequality_negative(): - assert_false(Schema('foo') != Schema('foo')) - - assert_false(Schema(['foo', 'bar', 'baz']) != - Schema(['foo', 'bar', 'baz'])) - - # Ensure two Schemas w/ two equivalent dicts initialized in a different - # order are considered equal. - dict_a = {} - dict_a['foo'] = 1 - dict_a['bar'] = 2 - dict_a['baz'] = 3 - - dict_b = {} - dict_b['baz'] = 3 - dict_b['bar'] = 2 - dict_b['foo'] = 1 - - assert_false(Schema(dict_a) != Schema(dict_b)) - - -def test_repr(): - """Verify that __repr__ returns valid Python expressions""" - match = Match('a pattern', msg='message') - replace = Replace('you', 'I', msg='you and I') - range_ = Range(min=0, max=42, min_included=False, - max_included=False, msg='number not in range') - coerce_ = Coerce(int, msg="moo") - all_ = All('10', Coerce(int), msg='all msg') - maybe_int = Maybe(int) - - assert_equal(repr(match), "Match('a pattern', msg='message')") - assert_equal(repr(replace), "Replace('you', 'I', msg='you and I')") - assert_equal( - repr(range_), - "Range(min=0, max=42, min_included=False, max_included=False, msg='number not in range')" - ) - assert_equal(repr(coerce_), "Coerce(int, msg='moo')") - assert_equal(repr(all_), "All('10', Coerce(int, msg=None), msg='all msg')") - assert_equal(repr(maybe_int), "Any(None, %s, msg=None)" % str(int)) - - -def test_list_validation_messages(): - """ Make sure useful error messages are available """ - - def is_even(value): - if value % 2: - raise Invalid('%i is not even' % value) - return value - - schema = Schema(dict(even_numbers=[All(int, is_even)])) - - try: - schema(dict(even_numbers=[3])) - except Invalid as e: - assert_equal(len(e.errors), 1, e.errors) - assert_equal(str(e.errors[0]), "3 is not even @ data['even_numbers'][0]") - assert_equal(str(e), "3 is not even @ data['even_numbers'][0]") - else: - assert False, "Did not raise Invalid" - - -def test_nested_multiple_validation_errors(): - """ Make sure useful error messages are available """ - - def is_even(value): - if value % 2: - raise Invalid('%i is not even' % value) - return value - - schema = Schema(dict(even_numbers=All([All(int, is_even)], - Length(min=1)))) - - try: - schema(dict(even_numbers=[3])) - except Invalid as e: - assert_equal(len(e.errors), 1, e.errors) - assert_equal(str(e.errors[0]), "3 is not even @ data['even_numbers'][0]") - assert_equal(str(e), "3 is not even @ data['even_numbers'][0]") - else: - assert False, "Did not raise Invalid" - - -def test_humanize_error(): - data = { - 'a': 'not an int', - 'b': [123] - } - schema = Schema({ - 'a': int, - 'b': [str] - }) - try: - schema(data) - except MultipleInvalid as e: - assert_equal( - humanize_error(data, e), - "expected int for dictionary value @ data['a']. Got 'not an int'\n" - "expected str @ data['b'][0]. Got 123" - ) - else: - assert False, 'Did not raise MultipleInvalid' - - -def test_fix_157(): - s = Schema(All([Any('one', 'two', 'three')]), Length(min=1)) - assert_equal(['one'], s(['one'])) - assert_raises(MultipleInvalid, s, ['four']) - - -def test_range_exlcudes_nan(): - s = Schema(Range(min=0, max=10)) - assert_raises(MultipleInvalid, s, float('nan')) - - -def test_equal(): - s = Schema(Equal(1)) - s(1) - assert_raises(Invalid, s, 2) - s = Schema(Equal('foo')) - s('foo') - assert_raises(Invalid, s, 'bar') - s = Schema(Equal([1, 2])) - s([1, 2]) - assert_raises(Invalid, s, []) - assert_raises(Invalid, s, [1, 2, 3]) - # Evaluates exactly, not through validators - s = Schema(Equal(str)) - assert_raises(Invalid, s, 'foo') - - -def test_unordered(): - # Any order is OK - s = Schema(Unordered([2, 1])) - s([2, 1]) - s([1, 2]) - # Amount of errors is OK - assert_raises(Invalid, s, [2, 0]) - assert_raises(MultipleInvalid, s, [0, 0]) - # Different length is NOK - assert_raises(Invalid, s, [1]) - assert_raises(Invalid, s, [1, 2, 0]) - assert_raises(MultipleInvalid, s, [1, 2, 0, 0]) - # Other type than list or tuple is NOK - assert_raises(Invalid, s, 'foo') - assert_raises(Invalid, s, 10) - # Validators are evaluated through as schemas - s = Schema(Unordered([int, str])) - s([1, '2']) - s(['1', 2]) - s = Schema(Unordered([{'foo': int}, []])) - s([{'foo': 3}, []]) - # Most accurate validators must be positioned on left - s = Schema(Unordered([int, 3])) - assert_raises(Invalid, s, [3, 2]) - s = Schema(Unordered([3, int])) - s([3, 2]) - - -def test_maybe(): - s = Schema(Maybe(int)) - assert s(1) == 1 - assert s(None) is None - assert_raises(Invalid, s, 'foo') - - s = Schema(Maybe({str: Coerce(int)})) - assert s({'foo': '100'}) == {'foo': 100} - assert s(None) is None - assert_raises(Invalid, s, {'foo': 'bar'}) - - -def test_empty_list_as_exact(): - s = Schema([]) - assert_raises(Invalid, s, [1]) - s([]) - - -def test_schema_decorator_match_with_args(): - @validate(int) - def fn(arg): - return arg - - fn(1) - - -def test_schema_decorator_unmatch_with_args(): - @validate(int) - def fn(arg): - return arg - - assert_raises(Invalid, fn, 1.0) - - -def test_schema_decorator_match_with_kwargs(): - @validate(arg=int) - def fn(arg): - return arg - - fn(1) - - -def test_schema_decorator_unmatch_with_kwargs(): - @validate(arg=int) - def fn(arg): - return arg - - assert_raises(Invalid, fn, 1.0) - - -def test_schema_decorator_match_return_with_args(): - @validate(int, __return__=int) - def fn(arg): - return arg - - fn(1) - - -def test_schema_decorator_unmatch_return_with_args(): - @validate(int, __return__=int) - def fn(arg): - return "hello" - - assert_raises(Invalid, fn, 1) - - -def test_schema_decorator_match_return_with_kwargs(): - @validate(arg=int, __return__=int) - def fn(arg): - return arg - - fn(1) - - -def test_schema_decorator_unmatch_return_with_kwargs(): - @validate(arg=int, __return__=int) - def fn(arg): - return "hello" - - assert_raises(Invalid, fn, 1) - - -def test_schema_decorator_return_only_match(): - @validate(__return__=int) - def fn(arg): - return arg - - fn(1) - - -def test_schema_decorator_return_only_unmatch(): - @validate(__return__=int) - def fn(arg): - return "hello" - - assert_raises(Invalid, fn, 1) - - -def test_schema_decorator_partial_match_called_with_args(): - @validate(arg1=int) - def fn(arg1, arg2): - return arg1 - - fn(1, "foo") - - -def test_schema_decorator_partial_unmatch_called_with_args(): - @validate(arg1=int) - def fn(arg1, arg2): - return arg1 - - assert_raises(Invalid, fn, "bar", "foo") - - -def test_schema_decorator_partial_match_called_with_kwargs(): - @validate(arg2=int) - def fn(arg1, arg2): - return arg1 - - fn(arg1="foo", arg2=1) - - -def test_schema_decorator_partial_unmatch_called_with_kwargs(): - @validate(arg2=int) - def fn(arg1, arg2): - return arg1 - - assert_raises(Invalid, fn, arg1=1, arg2="foo") - - -def test_unicode_as_key(): - if sys.version_info >= (3,): - text_type = str - else: - text_type = unicode - schema = Schema({text_type: int}) - schema({u("foobar"): 1}) - - -def test_number_validation_with_string(): - """ test with Number with string""" - schema = Schema({"number": Number(precision=6, scale=2)}) - try: - schema({"number": 'teststr'}) - except MultipleInvalid as e: - assert_equal(str(e), - "Value must be a number enclosed with string for dictionary value @ data['number']") - else: - assert False, "Did not raise Invalid for String" - - -def test_number_validation_with_invalid_precision_invalid_scale(): - """ test with Number with invalid precision and scale""" - schema = Schema({"number": Number(precision=6, scale=2)}) - try: - schema({"number": '123456.712'}) - except MultipleInvalid as e: - assert_equal(str(e), - "Precision must be equal to 6, and Scale must be equal to 2 for dictionary value @ data['number']") - else: - assert False, "Did not raise Invalid for String" - - -def test_number_validation_with_valid_precision_scale_yield_decimal_true(): - """ test with Number with valid precision and scale""" - schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=True)}) - out_ = schema({"number": '1234.00'}) - assert_equal(float(out_.get("number")), 1234.00) - - -def test_number_when_precision_scale_none_yield_decimal_true(): - """ test with Number with no precision and scale""" - schema = Schema({"number": Number(yield_decimal=True)}) - out_ = schema({"number": '12345678901234'}) - assert_equal(out_.get("number"), 12345678901234) - - -def test_number_when_precision_none_n_valid_scale_case1_yield_decimal_true(): - """ test with Number with no precision and valid scale case 1""" - schema = Schema({"number": Number(scale=2, yield_decimal=True)}) - out_ = schema({"number": '123456789.34'}) - assert_equal(float(out_.get("number")), 123456789.34) - - -def test_number_when_precision_none_n_valid_scale_case2_yield_decimal_true(): - """ test with Number with no precision and valid scale case 2 with zero in decimal part""" - schema = Schema({"number": Number(scale=2, yield_decimal=True)}) - out_ = schema({"number": '123456789012.00'}) - assert_equal(float(out_.get("number")), 123456789012.00) - - -def test_number_when_precision_none_n_invalid_scale_yield_decimal_true(): - """ test with Number with no precision and invalid scale""" - schema = Schema({"number": Number(scale=2, yield_decimal=True)}) - try: - schema({"number": '12345678901.234'}) - except MultipleInvalid as e: - assert_equal(str(e), - "Scale must be equal to 2 for dictionary value @ data['number']") - else: - assert False, "Did not raise Invalid for String" - - -def test_number_when_valid_precision_n_scale_none_yield_decimal_true(): - """ test with Number with no precision and valid scale""" - schema = Schema({"number": Number(precision=14, yield_decimal=True)}) - out_ = schema({"number": '1234567.8901234'}) - assert_equal(float(out_.get("number")), 1234567.8901234) - - -def test_number_when_invalid_precision_n_scale_none_yield_decimal_true(): - """ test with Number with no precision and invalid scale""" - schema = Schema({"number": Number(precision=14, yield_decimal=True)}) - try: - schema({"number": '12345674.8901234'}) - except MultipleInvalid as e: - assert_equal(str(e), - "Precision must be equal to 14 for dictionary value @ data['number']") - else: - assert False, "Did not raise Invalid for String" - - -def test_number_validation_with_valid_precision_scale_yield_decimal_false(): - """ test with Number with valid precision, scale and no yield_decimal""" - schema = Schema({"number": Number(precision=6, scale=2, yield_decimal=False)}) - out_ = schema({"number": '1234.00'}) - assert_equal(out_.get("number"), '1234.00') - - -def test_named_tuples_validate_as_tuples(): - NT = collections.namedtuple('NT', ['a', 'b']) - nt = NT(1, 2) - t = (1, 2) - - Schema((int, int))(nt) - Schema((int, int))(t) - Schema(NT(int, int))(nt) - Schema(NT(int, int))(t) - - -def test_datetime(): - schema = Schema({"datetime": Datetime()}) - schema({"datetime": "2016-10-24T14:01:57.102152Z"}) - assert_raises(MultipleInvalid, schema, {"datetime": "2016-10-24T14:01:57"}) - - -def test_date(): - schema = Schema({"date": Date()}) - schema({"date": "2016-10-24"}) - assert_raises(MultipleInvalid, schema, {"date": "2016-10-24Z"}) - - -def test_date_custom_format(): - schema = Schema({"date": Date("%Y%m%d")}) - schema({"date": "20161024"}) - assert_raises(MultipleInvalid, schema, {"date": "2016-10-24"}) - - -def test_ordered_dict(): - if not hasattr(collections, 'OrderedDict'): - # collections.OrderedDict was added in Python2.7; only run if present - return - schema = Schema({Number(): Number()}) # x, y pairs (for interpolation or something) - data = collections.OrderedDict([(5.0, 3.7), (24.0, 8.7), (43.0, 1.5), - (62.0, 2.1), (71.5, 6.7), (90.5, 4.1), - (109.0, 3.9)]) - out = schema(data) - assert isinstance(out, collections.OrderedDict), 'Collection is no longer ordered' - assert data.keys() == out.keys(), 'Order is not consistent' - - -def test_marker_hashable(): - """Verify that you can get schema keys, even if markers were used""" - definition = { - Required('x'): int, Optional('y'): float, - Remove('j'): int, Remove(int): str, int: int - } - assert_equal(definition.get('x'), int) - assert_equal(definition.get('y'), float) - assert_true(Required('x') == Required('x')) - assert_true(Required('x') != Required('y')) - # Remove markers are not hashable - assert_equal(definition.get('j'), None) - - -def test_schema_infer(): - schema = Schema.infer({ - 'str': 'foo', - 'bool': True, - 'int': 42, - 'float': 3.14 - }) - assert_equal(schema, Schema({ - Required('str'): str, - Required('bool'): bool, - Required('int'): int, - Required('float'): float - })) - - -def test_schema_infer_dict(): - schema = Schema.infer({ - 'a': { - 'b': { - 'c': 'foo' - } - } - }) - - assert_equal(schema, Schema({ - Required('a'): { - Required('b'): { - Required('c'): str - } - } - })) - - -def test_schema_infer_list(): - schema = Schema.infer({ - 'list': ['foo', True, 42, 3.14] - }) - - assert_equal(schema, Schema({ - Required('list'): [str, bool, int, float] - })) - - -def test_schema_infer_scalar(): - assert_equal(Schema.infer('foo'), Schema(str)) - assert_equal(Schema.infer(True), Schema(bool)) - assert_equal(Schema.infer(42), Schema(int)) - assert_equal(Schema.infer(3.14), Schema(float)) - assert_equal(Schema.infer({}), Schema(dict)) - assert_equal(Schema.infer([]), Schema(list)) - - -def test_schema_infer_accepts_kwargs(): - schema = Schema.infer({ - 'str': 'foo', - 'bool': True - }, required=False, extra=True) - - # Subset of schema should be acceptable thanks to required=False. - schema({'bool': False}) - - # Keys that are in schema should still match required types. - try: - schema({'str': 42}) - except Invalid: - pass - else: - assert False, 'Did not raise Invalid for Number' - - # Extra fields should be acceptable thanks to extra=True. - schema({'str': 'bar', 'int': 42}) - - -def test_validation_performance(): - """ - This test comes to make sure the validation complexity of dictionaries is done in a linear time. - to achieve this a custom marker is used in the scheme that counts each time it is evaluated. - By doing so we can determine if the validation is done in linear complexity. - Prior to issue https://github.com/alecthomas/voluptuous/issues/259 this was exponential - """ - num_of_keys = 1000 - - schema_dict = {} - data = {} - data_extra_keys = {} - - counter = [0] - - class CounterMarker(Marker): - def __call__(self, *args, **kwargs): - counter[0] += 1 - return super(CounterMarker, self).__call__(*args, **kwargs) - - for i in range(num_of_keys): - schema_dict[CounterMarker(str(i))] = str - data[str(i)] = str(i) - data_extra_keys[str(i * 2)] = str(i) # half of the keys are present, and half aren't - - schema = Schema(schema_dict, extra=ALLOW_EXTRA) - - schema(data) - - assert counter[0] <= num_of_keys, "Validation complexity is not linear! %s > %s" % (counter[0], num_of_keys) - - counter[0] = 0 # reset counter - schema(data_extra_keys) - - assert counter[0] <= num_of_keys, "Validation complexity is not linear! %s > %s" % (counter[0], num_of_keys) - - -def test_IsDir(): - schema = Schema(IsDir()) - assert_raises(MultipleInvalid, schema, 3) - schema(os.path.dirname(os.path.abspath(__file__))) - - -def test_IsFile(): - schema = Schema(IsFile()) - assert_raises(MultipleInvalid, schema, 3) - schema(os.path.abspath(__file__)) - - -def test_PathExists(): - schema = Schema(PathExists()) - assert_raises(MultipleInvalid, schema, 3) - schema(os.path.abspath(__file__)) - - -def test_description(): - marker = Marker(Schema(str), description='Hello') - assert marker.description == 'Hello' - - optional = Optional('key', description='Hello') - assert optional.description == 'Hello' - - exclusive = Exclusive('alpha', 'angles', description='Hello') - assert exclusive.description == 'Hello' - - required = Required('key', description='Hello') - assert required.description == 'Hello' - - -def test_SomeOf_min_validation(): - validator = All(Length(min=8), SomeOf( - min_valid=3, - validators=[Match(r'.*[A-Z]', 'no uppercase letters'), - Match(r'.*[a-z]', 'no lowercase letters'), - Match(r'.*[0-9]', 'no numbers'), - Match(r'.*[$@$!%*#?&^:;/<,>|{}()\-\'._+=]', 'no symbols')])) - - validator('ffe532A1!') - with raises(MultipleInvalid, 'length of value must be at least 8'): - validator('a') - - with raises(MultipleInvalid, 'no uppercase letters, no lowercase letters'): - validator('wqs2!#s111') - - with raises(MultipleInvalid, 'no lowercase letters, no symbols'): - validator('3A34SDEF5') - - -def test_SomeOf_max_validation(): - validator = SomeOf( - max_valid=2, - validators=[Match(r'.*[A-Z]', 'no uppercase letters'), - Match(r'.*[a-z]', 'no lowercase letters'), - Match(r'.*[0-9]', 'no numbers')], - msg='max validation test failed') - - validator('Aa') - with raises(TooManyValid, 'max validation test failed'): - validator('Aa1') - - -def test_self_validation(): - schema = Schema({"number": int, - "follow": Self}) - try: - schema({"number": "abc"}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - try: - schema({"follow": {"number": '123456.712'}}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - schema({"follow": {"number": 123456}}) - schema({"follow": {"follow": {"number": 123456}}}) - - -def test_any_error_has_path(): - """https://github.com/alecthomas/voluptuous/issues/347""" - s = Schema({ - Optional('q'): int, - Required('q2'): Any(int, msg='toto') - }) - try: - s({'q': 'str', 'q2': 'tata'}) - except MultipleInvalid as exc: - assert ( - (exc.errors[0].path == ['q'] and exc.errors[1].path == ['q2']) or - (exc.errors[1].path == ['q'] and exc.errors[0].path == ['q2']) - ) - else: - assert False, "Did not raise AnyInvalid" - - -def test_all_error_has_path(): - """https://github.com/alecthomas/voluptuous/issues/347""" - s = Schema({ - Optional('q'): int, - Required('q2'): All([str, Length(min=10)], msg='toto'), - }) - try: - s({'q': 'str', 'q2': 12}) - except MultipleInvalid as exc: - assert ( - (exc.errors[0].path == ['q'] and exc.errors[1].path == ['q2']) or - (exc.errors[1].path == ['q'] and exc.errors[0].path == ['q2']) - ) - else: - assert False, "Did not raise AllInvalid" - - -def test_match_error_has_path(): - """https://github.com/alecthomas/voluptuous/issues/347""" - s = Schema({ - Required('q2'): Match("a"), - }) - try: - s({'q2': 12}) - except MultipleInvalid as exc: - assert exc.errors[0].path == ['q2'] - else: - assert False, "Did not raise MatchInvalid" - - -def test_self_any(): - schema = Schema({"number": int, - "follow": Any(Self, "stop")}) - try: - schema({"number": "abc"}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - try: - schema({"follow": {"number": '123456.712'}}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - schema({"follow": {"number": 123456}}) - schema({"follow": {"follow": {"number": 123456}}}) - schema({"follow": {"follow": {"number": 123456, "follow": "stop"}}}) - - -def test_self_all(): - schema = Schema({"number": int, - "follow": All(Self, - Schema({"extra_number": int}, - extra=ALLOW_EXTRA))}, - extra=ALLOW_EXTRA) - try: - schema({"number": "abc"}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - try: - schema({"follow": {"number": '123456.712'}}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - schema({"follow": {"number": 123456}}) - schema({"follow": {"follow": {"number": 123456}}}) - schema({"follow": {"number": 123456, "extra_number": 123}}) - try: - schema({"follow": {"number": 123456, "extra_number": "123"}}) - except MultipleInvalid: - pass - else: - assert False, "Did not raise Invalid" - - -def test_SomeOf_on_bounds_assertion(): - with raises(AssertionError, 'when using "SomeOf" you should specify at least one of min_valid and max_valid'): - SomeOf(validators=[]) - - -def test_comparing_voluptuous_object_to_str(): - assert_true(Optional('Classification') < 'Name') - - -def test_set_of_integers(): - schema = Schema({int}) - with raises(Invalid, 'expected a set'): - schema(42) - with raises(Invalid, 'expected a set'): - schema(frozenset([42])) - - schema(set()) - schema(set([42])) - schema(set([42, 43, 44])) - try: - schema(set(['abc'])) - except MultipleInvalid as e: - assert_equal(str(e), "invalid value in set") - else: - assert False, "Did not raise Invalid" - - -def test_frozenset_of_integers(): - schema = Schema(frozenset([int])) - with raises(Invalid, 'expected a frozenset'): - schema(42) - with raises(Invalid, 'expected a frozenset'): - schema(set([42])) - - schema(frozenset()) - schema(frozenset([42])) - schema(frozenset([42, 43, 44])) - try: - schema(frozenset(['abc'])) - except MultipleInvalid as e: - assert_equal(str(e), "invalid value in frozenset") - else: - assert False, "Did not raise Invalid" - - -def test_set_of_integers_and_strings(): - schema = Schema({int, str}) - with raises(Invalid, 'expected a set'): - schema(42) - - schema(set()) - schema(set([42])) - schema(set(['abc'])) - schema(set([42, 'abc'])) - try: - schema(set([None])) - except MultipleInvalid as e: - assert_equal(str(e), "invalid value in set") - else: - assert False, "Did not raise Invalid" - - -def test_frozenset_of_integers_and_strings(): - schema = Schema(frozenset([int, str])) - with raises(Invalid, 'expected a frozenset'): - schema(42) - - schema(frozenset()) - schema(frozenset([42])) - schema(frozenset(['abc'])) - schema(frozenset([42, 'abc'])) - try: - schema(frozenset([None])) - except MultipleInvalid as e: - assert_equal(str(e), "invalid value in frozenset") - else: - assert False, "Did not raise Invalid" diff --git a/third_party/python/yamllint/MANIFEST.in b/third_party/python/yamllint/MANIFEST.in deleted file mode 100644 index 792a6720cba6..000000000000 --- a/third_party/python/yamllint/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include LICENSE -include README.rst -include docs/* -include tests/*.py tests/rules/*.py tests/yaml-1.2-spec-examples/* diff --git a/third_party/python/yamllint/README.rst b/third_party/python/yamllint/README.rst deleted file mode 100644 index 89bc0e86f94c..000000000000 --- a/third_party/python/yamllint/README.rst +++ /dev/null @@ -1,144 +0,0 @@ -yamllint -======== - -A linter for YAML files. - -yamllint does not only check for syntax validity, but for weirdnesses like key -repetition and cosmetic problems such as lines length, trailing spaces, -indentation, etc. - -.. image:: - https://travis-ci.org/adrienverge/yamllint.svg?branch=master - :target: https://travis-ci.org/adrienverge/yamllint - :alt: CI tests status -.. image:: - https://coveralls.io/repos/github/adrienverge/yamllint/badge.svg?branch=master - :target: https://coveralls.io/github/adrienverge/yamllint?branch=master - :alt: Code coverage status -.. image:: https://readthedocs.org/projects/yamllint/badge/?version=latest - :target: https://yamllint.readthedocs.io/en/latest/?badge=latest - :alt: Documentation status - -Written in Python (compatible with Python 2 & 3). - -⚠ Python 2 upstream support stopped on January 1, 2020. yamllint will keep -best-effort support for Python 2.7 until January 1, 2021. Passed that date, -yamllint will drop all Python 2-related code. - -Documentation -------------- - -https://yamllint.readthedocs.io/ - -Overview --------- - -Screenshot -^^^^^^^^^^ - -.. image:: docs/screenshot.png - :alt: yamllint screenshot - -Installation -^^^^^^^^^^^^ - -Using pip, the Python package manager: - -.. code:: bash - - pip install --user yamllint - -yamllint is also packaged for all major operating systems, see installation -examples (``dnf``, ``apt-get``...) `in the documentation -`_. - -Usage -^^^^^ - -.. code:: bash - - # Lint one or more files - yamllint my_file.yml my_other_file.yaml ... - -.. code:: bash - - # Lint all YAML files in a directory - yamllint . - -.. code:: bash - - # Use a pre-defined lint configuration - yamllint -d relaxed file.yaml - - # Use a custom lint configuration - yamllint -c /path/to/myconfig file-to-lint.yaml - -.. code:: bash - - # Output a parsable format (for syntax checking in editors like Vim, emacs...) - yamllint -f parsable file.yaml - -`Read more in the complete documentation! `_ - -Features -^^^^^^^^ - -Here is a yamllint configuration file example: - -.. code:: yaml - - extends: default - - rules: - # 80 chars should be enough, but don't fail if a line is longer - line-length: - max: 80 - level: warning - - # don't bother me with this rule - indentation: disable - -Within a YAML file, special comments can be used to disable checks for a single -line: - -.. code:: yaml - - This line is waaaaaaaaaay too long # yamllint disable-line - -or for a whole block: - -.. code:: yaml - - # yamllint disable rule:colons - - Lorem : ipsum - dolor : sit amet, - consectetur : adipiscing elit - # yamllint enable - -Specific files can be ignored (totally or for some rules only) using a -``.gitignore``-style pattern: - -.. code:: yaml - - # For all rules - ignore: | - *.dont-lint-me.yaml - /bin/ - !/bin/*.lint-me-anyway.yaml - - rules: - key-duplicates: - ignore: | - generated - *.template.yaml - trailing-spaces: - ignore: | - *.ignore-trailing-spaces.yaml - /ascii-art/* - -`Read more in the complete documentation! `_ - -License -------- - -`GPL version 3 `_ diff --git a/third_party/python/yamllint/setup.cfg b/third_party/python/yamllint/setup.cfg deleted file mode 100644 index 90a4cb0ec47a..000000000000 --- a/third_party/python/yamllint/setup.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[bdist_wheel] -universal = 1 - -[flake8] -import-order-style = pep8 -application-import-names = yamllint - -[build_sphinx] -all-files = 1 -source-dir = docs -build-dir = docs/_build -warning-is-error = 1 - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/yamllint/setup.py b/third_party/python/yamllint/setup.py deleted file mode 100644 index ffa2ee226b41..000000000000 --- a/third_party/python/yamllint/setup.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016 Adrien Vergé -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from setuptools import find_packages, setup - -from yamllint import (__author__, __license__, - APP_NAME, APP_VERSION, APP_DESCRIPTION) - - -setup( - name=APP_NAME, - version=APP_VERSION, - author=__author__, - description=APP_DESCRIPTION.split('\n')[0], - long_description=APP_DESCRIPTION, - license=__license__, - keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'], - url='https://github.com/adrienverge/yamllint', - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Topic :: Software Development', - 'Topic :: Software Development :: Debuggers', - 'Topic :: Software Development :: Quality Assurance', - 'Topic :: Software Development :: Testing', - ], - - packages=find_packages(exclude=['tests', 'tests.*']), - entry_points={'console_scripts': ['yamllint=yamllint.cli:run']}, - package_data={'yamllint': ['conf/*.yaml']}, - install_requires=['pathspec >=0.5.3', 'pyyaml'], - test_suite='tests', -) diff --git a/third_party/python/yamllint/LICENSE b/third_party/python/yamllint/yamllint-1.23.0.dist-info/LICENSE similarity index 100% rename from third_party/python/yamllint/LICENSE rename to third_party/python/yamllint/yamllint-1.23.0.dist-info/LICENSE diff --git a/third_party/python/yamllint/PKG-INFO b/third_party/python/yamllint/yamllint-1.23.0.dist-info/METADATA similarity index 79% rename from third_party/python/yamllint/PKG-INFO rename to third_party/python/yamllint/yamllint-1.23.0.dist-info/METADATA index f3a33638b765..f97b581a3d2a 100644 --- a/third_party/python/yamllint/PKG-INFO +++ b/third_party/python/yamllint/yamllint-1.23.0.dist-info/METADATA @@ -1,15 +1,10 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: yamllint Version: 1.23.0 Summary: A linter for YAML files. Home-page: https://github.com/adrienverge/yamllint Author: Adrien Vergé License: GPLv3 -Description: A linter for YAML files. - - yamllint does not only check for syntax validity, but for weirdnesses like key - repetition and cosmetic problems such as lines length, trailing spaces, - indentation, etc. Keywords: yaml,lint,linter,syntax,checker Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable @@ -28,3 +23,12 @@ Classifier: Topic :: Software Development :: Debuggers Classifier: Topic :: Software Development :: Quality Assurance Classifier: Topic :: Software Development :: Testing Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: pathspec (>=0.5.3) +Requires-Dist: pyyaml + +A linter for YAML files. + +yamllint does not only check for syntax validity, but for weirdnesses like key +repetition and cosmetic problems such as lines length, trailing spaces, +indentation, etc. + diff --git a/third_party/python/yamllint/yamllint-1.23.0.dist-info/RECORD b/third_party/python/yamllint/yamllint-1.23.0.dist-info/RECORD new file mode 100644 index 000000000000..57b2adaa42ee --- /dev/null +++ b/third_party/python/yamllint/yamllint-1.23.0.dist-info/RECORD @@ -0,0 +1,37 @@ +yamllint/__init__.py,sha256=09UdMyFnq1ObJn5Q-OyN0bVxnqlNdeTOGCH0DBALZKM,1098 +yamllint/__main__.py,sha256=yUeYsN2w7fyIjcnleh2ow0u_hG6YO1BfnumvApBDWXQ,67 +yamllint/cli.py,sha256=PUphAVxTsXCKHMMvyUsuhwiELnDqVMRWX7xnWMZ5adw,7880 +yamllint/config.py,sha256=-Y4QnDKAcZD6DpRhvhSo89t9IGs_2ZAkJrP_c8ZPrVQ,7877 +yamllint/linter.py,sha256=yDkPv41mMmbdCBNyvblYs7Ds4P1F_jDAgy0LzeyyUMU,8773 +yamllint/parser.py,sha256=3MwMASIm3v6z5zKwlQFPJtt7rv4i4zD6_KgHABP3_oE,5191 +yamllint/conf/default.yaml,sha256=wsK6rYJ2A1sv-0ln3Ckvr8Tgbj4asvk42vD4OZQcEfc,587 +yamllint/conf/relaxed.yaml,sha256=Bz743etRSwggNRc8hMgxMmyr-5JazJrCPv3KNhjOu28,505 +yamllint/rules/__init__.py,sha256=b-32xKjsRiUqMaLAguHTBtxjV2zCEMwa-0hfC4dIcI0,1924 +yamllint/rules/braces.py,sha256=BLjn8qlo_3BCAGqi19qJUt2eVd-TKoNrqzV1R_d0Gfc,4542 +yamllint/rules/brackets.py,sha256=IwsOdigK2pPPDyA3gup8LhgHdaUIfeP8P4ApO0PuLU4,4583 +yamllint/rules/colons.py,sha256=DtN1lRBMq58r8M1aeAcU4TAhNx7qNCsa6isVpk_ukNM,2826 +yamllint/rules/commas.py,sha256=VBIO52n0DsFrdw_v0_F76tLSrQnwSbARsSAnfUKCCyo,3737 +yamllint/rules/comments.py,sha256=WfTYRnI8nZS0je1zlVzkhC-rtXR23krvUzS0cEQI_BI,3381 +yamllint/rules/comments_indentation.py,sha256=pCS5gSOZWc4wGHr7LlnwcReuSWax4WV0Ec_0G1RvoiI,3425 +yamllint/rules/common.py,sha256=_572eFYdjdTCMrzVGpuRDTi42OazsBYezcwlFMdsDPg,3226 +yamllint/rules/document_end.py,sha256=9rMdNmLDacI3sQopFYzRuGrc6Hj68GAkX5s8a5X1UWg,2686 +yamllint/rules/document_start.py,sha256=LJFunt4mqC_Cruq316hymg9uTKorfoOA2klHqdJiKH8,2437 +yamllint/rules/empty_lines.py,sha256=C5JoI-jtTDkApiBpcT_AeVt97xfR2jlyvkTfvFBpFqA,3259 +yamllint/rules/empty_values.py,sha256=iXuIjQkUyEQ_9kiXAbYjA32BsK8oxMUQgGo1xrPIVqg,2601 +yamllint/rules/hyphens.py,sha256=OfNUNWyGiABHnZwbqDtQTEBihmeJBmVEQgg2DVIllFo,1990 +yamllint/rules/indentation.py,sha256=82DOfCNnxBxFI0TX_6VF05HxUX0CEw6nRxcnhCprFfs,19067 +yamllint/rules/key_duplicates.py,sha256=dEYrBcG68MGG7iC6OBGsA9ZPbIX2rTYt-85Yf2Z2BJU,2890 +yamllint/rules/key_ordering.py,sha256=wbATImHwoojXPcrmG8RaGrvyPLmM7Dvvlz7U14uCrxs,3083 +yamllint/rules/line_length.py,sha256=FwI_8ShkiKzfjICo4RqG7WSAJKM87op5O-MDncPOvDI,4809 +yamllint/rules/new_line_at_end_of_file.py,sha256=X0T0jPojEkxTfDQiQrWVydXn_jPj0srd9hFOLm5t9wA,1357 +yamllint/rules/new_lines.py,sha256=bZCSz9PUVIn__PkgLx1R-iWUnXyfrQ5ZfXDh9qQ7WEM,1633 +yamllint/rules/octal_values.py,sha256=cCbDT4U0qCE0_wWoJUFgnvOxv1Ydv2bVDzTH-i0aK2Q,2792 +yamllint/rules/quoted_strings.py,sha256=bUIkpR-8i5Of18RrSvCi5lmffMiFchwNnkNkHQe3wqs,7468 +yamllint/rules/trailing_spaces.py,sha256=GH8RTvR-FXA0GbtRkFWymp_LzK2mJuROhcDoJcvQ4ns,1634 +yamllint/rules/truthy.py,sha256=K_or0_h7U2ymVe0_G_5IZ2GgMJhfcCklh4ojvABN4Tw,4011 +yamllint-1.23.0.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147 +yamllint-1.23.0.dist-info/METADATA,sha256=I6VrDjA7fBGgMpppaPTQnfiZwWnE9zVhN9GIoDJuBu8,1318 +yamllint-1.23.0.dist-info/WHEEL,sha256=HX-v9-noUkyUoxyZ1PMSuS7auUxDAR4VBdoYLqD0xws,110 +yamllint-1.23.0.dist-info/entry_points.txt,sha256=_aTkgNklEhR_lTZHrYseFHam-CSHZSqnhYtlYFb-72k,47 +yamllint-1.23.0.dist-info/top_level.txt,sha256=ivPsPeZUDHOuLbd603ZxKClOQ1bATyMYNx3GfHQmt4g,9 +yamllint-1.23.0.dist-info/RECORD,, diff --git a/third_party/python/yamllint/yamllint-1.23.0.dist-info/WHEEL b/third_party/python/yamllint/yamllint-1.23.0.dist-info/WHEEL new file mode 100644 index 000000000000..c8240f03e87f --- /dev/null +++ b/third_party/python/yamllint/yamllint-1.23.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/third_party/python/yamllint/yamllint-1.23.0.dist-info/entry_points.txt b/third_party/python/yamllint/yamllint-1.23.0.dist-info/entry_points.txt new file mode 100644 index 000000000000..a1b443ba38ef --- /dev/null +++ b/third_party/python/yamllint/yamllint-1.23.0.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +yamllint = yamllint.cli:run + diff --git a/third_party/python/yamllint/yamllint-1.23.0.dist-info/top_level.txt b/third_party/python/yamllint/yamllint-1.23.0.dist-info/top_level.txt new file mode 100644 index 000000000000..b2c729ca4de1 --- /dev/null +++ b/third_party/python/yamllint/yamllint-1.23.0.dist-info/top_level.txt @@ -0,0 +1 @@ +yamllint diff --git a/third_party/python/zipp/.coveragerc b/third_party/python/zipp/.coveragerc deleted file mode 100644 index 45823064a3c8..000000000000 --- a/third_party/python/zipp/.coveragerc +++ /dev/null @@ -1,5 +0,0 @@ -[run] -omit = .tox/* - -[report] -show_missing = True diff --git a/third_party/python/zipp/.editorconfig b/third_party/python/zipp/.editorconfig deleted file mode 100644 index 6385b5734383..000000000000 --- a/third_party/python/zipp/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_style = tab -indent_size = 4 -insert_final_newline = true -end_of_line = lf - -[*.py] -indent_style = space - -[*.{yml,yaml}] -indent_style = space -indent_size = 2 diff --git a/third_party/python/zipp/.flake8 b/third_party/python/zipp/.flake8 deleted file mode 100644 index 48b2e246f1b4..000000000000 --- a/third_party/python/zipp/.flake8 +++ /dev/null @@ -1,9 +0,0 @@ -[flake8] -max-line-length = 88 - -# jaraco/skeleton#34 -max-complexity = 10 - -extend-ignore = - # Black creates whitespace before colon - E203 diff --git a/third_party/python/zipp/.github/workflows/automerge.yml b/third_party/python/zipp/.github/workflows/automerge.yml deleted file mode 100644 index 4f70acfbcbb2..000000000000 --- a/third_party/python/zipp/.github/workflows/automerge.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: automerge -on: - pull_request: - types: - - labeled - - unlabeled - - synchronize - - opened - - edited - - ready_for_review - - reopened - - unlocked - pull_request_review: - types: - - submitted - check_suite: - types: - - completed - status: {} -jobs: - automerge: - runs-on: ubuntu-latest - steps: - - name: automerge - uses: "pascalgn/automerge-action@v0.12.0" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/third_party/python/zipp/.github/workflows/main.yml b/third_party/python/zipp/.github/workflows/main.yml deleted file mode 100644 index 6a8ff006f419..000000000000 --- a/third_party/python/zipp/.github/workflows/main.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: tests - -on: [push, pull_request] - -jobs: - test: - strategy: - matrix: - python: [3.6, 3.8, 3.9] - platform: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python }} - - name: Install tox - run: | - python -m pip install tox - - name: Run tests - run: tox - - release: - needs: test - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - name: Install tox - run: | - python -m pip install tox - - name: Release - run: tox -e release - env: - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/third_party/python/zipp/.pre-commit-config.yaml b/third_party/python/zipp/.pre-commit-config.yaml deleted file mode 100644 index c15ab0c9e6a0..000000000000 --- a/third_party/python/zipp/.pre-commit-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -repos: -- repo: https://github.com/psf/black - rev: 20.8b1 - hooks: - - id: black - -- repo: https://github.com/asottile/blacken-docs - rev: v1.9.1 - hooks: - - id: blacken-docs diff --git a/third_party/python/zipp/.readthedocs.yml b/third_party/python/zipp/.readthedocs.yml deleted file mode 100644 index cc698548db4f..000000000000 --- a/third_party/python/zipp/.readthedocs.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -python: - install: - - path: . - extra_requirements: - - docs diff --git a/third_party/python/zipp/CHANGES.rst b/third_party/python/zipp/CHANGES.rst deleted file mode 100644 index 0a864e6ba63b..000000000000 --- a/third_party/python/zipp/CHANGES.rst +++ /dev/null @@ -1,179 +0,0 @@ -v3.4.1 -====== - -Refresh packaging. - -v3.4.0 -====== - -#68 and bpo-42090: ``Path.joinpath`` now takes arbitrary -positional arguments and no longer accepts ``add`` as a -keyword argument. - -v3.3.2 -====== - -Updated project metadata including badges. - -v3.3.1 -====== - -bpo-42043: Add tests capturing subclassing requirements. - -v3.3.0 -====== - -#9: ``Path`` objects now expose a ``.filename`` attribute -and rely on that to resolve ``.name`` and ``.parent`` when -the ``Path`` object is at the root of the zipfile. - -v3.2.0 -====== - -#57 and bpo-40564: Mutate the passed ZipFile object -type instead of making a copy. Prevents issues when -both the local copy and the caller's copy attempt to -close the same file handle. - -#56 and bpo-41035: ``Path._next`` now honors -subclasses. - -#55: ``Path.is_file()`` now returns False for non-existent names. - -v3.1.0 -====== - -#47: ``.open`` now raises ``FileNotFoundError`` and -``IsADirectoryError`` when appropriate. - -v3.0.0 -====== - -#44: Merge with v1.2.0. - -v1.2.0 -====== - -#44: ``zipp.Path.open()`` now supports a compatible signature -as ``pathlib.Path.open()``, accepting text (default) or binary -modes and soliciting keyword parameters passed through to -``io.TextIOWrapper`` (encoding, newline, etc). The stream is -opened in text-mode by default now. ``open`` no -longer accepts ``pwd`` as a positional argument and does not -accept the ``force_zip64`` parameter at all. This change is -a backward-incompatible change for that single function. - -v2.2.1 -====== - -#43: Merge with v1.1.1. - -v1.1.1 -====== - -#43: Restored performance of implicit dir computation. - -v2.2.0 -====== - -#36: Rebuild package with minimum Python version declared both -in package metadata and in the python tag. - -v2.1.0 -====== - -#32: Merge with v1.1.0. - -v1.1.0 -====== - -#32: For read-only zip files, complexity of ``.exists`` and -``joinpath`` is now constant time instead of ``O(n)``, preventing -quadratic time in common use-cases and rendering large -zip files unusable for Path. Big thanks to Benjy Weinberger -for the bug report and contributed fix (#33). - -v2.0.1 -====== - -#30: Corrected version inference (from jaraco/skeleton#12). - -v2.0.0 -====== - -Require Python 3.6 or later. - -v1.0.0 -====== - -Re-release of 0.6 to correspond with release as found in -Python 3.8. - -v0.6.0 -====== - -#12: When adding implicit dirs, ensure that ancestral directories -are added and that duplicates are excluded. - -The library now relies on -`more_itertools `_. - -v0.5.2 -====== - -#7: Parent of a directory now actually returns the parent. - -v0.5.1 -====== - -Declared package as backport. - -v0.5.0 -====== - -Add ``.joinpath()`` method and ``.parent`` property. - -Now a backport release of the ``zipfile.Path`` class. - -v0.4.0 -====== - -#4: Add support for zip files with implied directories. - -v0.3.3 -====== - -#3: Fix issue where ``.name`` on a directory was empty. - -v0.3.2 -====== - -#2: Fix TypeError on Python 2.7 when classic division is used. - -v0.3.1 -====== - -#1: Fix TypeError on Python 3.5 when joining to a path-like object. - -v0.3.0 -====== - -Add support for constructing a ``zipp.Path`` from any path-like -object. - -``zipp.Path`` is now a new-style class on Python 2.7. - -v0.2.1 -====== - -Fix issue with ``__str__``. - -v0.2.0 -====== - -Drop reliance on future-fstrings. - -v0.1.0 -====== - -Initial release with basic functionality. diff --git a/third_party/python/zipp/PKG-INFO b/third_party/python/zipp/PKG-INFO deleted file mode 100644 index d8186000867c..000000000000 --- a/third_party/python/zipp/PKG-INFO +++ /dev/null @@ -1,40 +0,0 @@ -Metadata-Version: 2.1 -Name: zipp -Version: 3.4.1 -Summary: Backport of pathlib-compatible object wrapper for zip files -Home-page: https://github.com/jaraco/zipp -Author: Jason R. Coombs -Author-email: jaraco@jaraco.com -License: UNKNOWN -Description: .. image:: https://img.shields.io/pypi/v/zipp.svg - :target: `PyPI link`_ - - .. image:: https://img.shields.io/pypi/pyversions/zipp.svg - :target: `PyPI link`_ - - .. _PyPI link: https://pypi.org/project/zipp - - .. image:: https://github.com/jaraco/zipp/workflows/tests/badge.svg - :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22 - :alt: tests - - .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - - .. .. image:: https://readthedocs.org/projects/zipp/badge/?version=latest - .. :target: https://zipp.readthedocs.io/en/latest/?badge=latest - - - A pathlib-compatible Zipfile object wrapper. A backport of the - `Path object `_. - -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3 :: Only -Requires-Python: >=3.6 -Provides-Extra: testing -Provides-Extra: docs diff --git a/third_party/python/zipp/README.rst b/third_party/python/zipp/README.rst deleted file mode 100644 index 798ca3fec6c2..000000000000 --- a/third_party/python/zipp/README.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. image:: https://img.shields.io/pypi/v/zipp.svg - :target: `PyPI link`_ - -.. image:: https://img.shields.io/pypi/pyversions/zipp.svg - :target: `PyPI link`_ - -.. _PyPI link: https://pypi.org/project/zipp - -.. image:: https://github.com/jaraco/zipp/workflows/tests/badge.svg - :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - -.. .. image:: https://readthedocs.org/projects/zipp/badge/?version=latest -.. :target: https://zipp.readthedocs.io/en/latest/?badge=latest - - -A pathlib-compatible Zipfile object wrapper. A backport of the -`Path object `_. diff --git a/third_party/python/zipp/conftest.py b/third_party/python/zipp/conftest.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/third_party/python/zipp/mypy.ini b/third_party/python/zipp/mypy.ini deleted file mode 100644 index 976ba0294638..000000000000 --- a/third_party/python/zipp/mypy.ini +++ /dev/null @@ -1,2 +0,0 @@ -[mypy] -ignore_missing_imports = True diff --git a/third_party/python/zipp/pyproject.toml b/third_party/python/zipp/pyproject.toml deleted file mode 100644 index b6ebc0bef6ec..000000000000 --- a/third_party/python/zipp/pyproject.toml +++ /dev/null @@ -1,20 +0,0 @@ -[build-system] -requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4.1"] -build-backend = "setuptools.build_meta" - -[tool.black] -skip-string-normalization = true - -[tool.setuptools_scm] - -[pytest.enabler.black] -addopts = "--black" - -[pytest.enabler.mypy] -addopts = "--mypy" - -[pytest.enabler.flake8] -addopts = "--flake8" - -[pytest.enabler.cov] -addopts = "--cov" diff --git a/third_party/python/zipp/pytest.ini b/third_party/python/zipp/pytest.ini deleted file mode 100644 index 6bf69af1420a..000000000000 --- a/third_party/python/zipp/pytest.ini +++ /dev/null @@ -1,7 +0,0 @@ -[pytest] -norecursedirs=dist build .tox .eggs -addopts=--doctest-modules -doctest_optionflags=ALLOW_UNICODE ELLIPSIS -# workaround for warning pytest-dev/pytest#6178 -junit_family=xunit2 -filterwarnings= diff --git a/third_party/python/zipp/setup.cfg b/third_party/python/zipp/setup.cfg deleted file mode 100644 index a3ec5ccfe0cc..000000000000 --- a/third_party/python/zipp/setup.cfg +++ /dev/null @@ -1,54 +0,0 @@ -[metadata] -license_files = - LICENSE -name = zipp -author = Jason R. Coombs -author_email = jaraco@jaraco.com -description = Backport of pathlib-compatible object wrapper for zip files -long_description = file:README.rst -url = https://github.com/jaraco/zipp -classifiers = - Development Status :: 5 - Production/Stable - Intended Audience :: Developers - License :: OSI Approved :: MIT License - Programming Language :: Python :: 3 - Programming Language :: Python :: 3 :: Only - -[options] -packages = find_namespace: -py_modules = zipp -include_package_data = true -python_requires = >=3.6 -install_requires = -setup_requires = setuptools_scm[toml] >= 3.4.1 - -[options.packages.find] -exclude = - build* - dist* - docs* - tests* - -[options.extras_require] -testing = - pytest >= 4.6 - pytest-checkdocs >= 1.2.3 - pytest-flake8 - pytest-black >= 0.3.7; python_implementation != "PyPy" - pytest-cov - pytest-mypy; python_implementation != "PyPy" - pytest-enabler - - jaraco.itertools - func-timeout -docs = - sphinx - jaraco.packaging >= 8.2 - rst.linker >= 1.9 - -[options.entry_points] - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/zipp/setup.py b/third_party/python/zipp/setup.py deleted file mode 100644 index bac24a43d994..000000000000 --- a/third_party/python/zipp/setup.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -import setuptools - -if __name__ == "__main__": - setuptools.setup() diff --git a/third_party/python/zipp/skeleton.md b/third_party/python/zipp/skeleton.md deleted file mode 100644 index 0938f8920d6e..000000000000 --- a/third_party/python/zipp/skeleton.md +++ /dev/null @@ -1,166 +0,0 @@ -# Overview - -This project is merged with [skeleton](https://github.com/jaraco/skeleton). What is skeleton? It's the scaffolding of a Python project jaraco [introduced in his blog](https://blog.jaraco.com/a-project-skeleton-for-python-projects/). It seeks to provide a means to re-use techniques and inherit advances when managing projects for distribution. - -## An SCM-Managed Approach - -While maintaining dozens of projects in PyPI, jaraco derives best practices for project distribution and publishes them in the [skeleton repo](https://github.com/jaraco/skeleton), a Git repo capturing the evolution and culmination of these best practices. - -It's intended to be used by a new or existing project to adopt these practices and honed and proven techniques. Adopters are encouraged to use the project directly and maintain a small deviation from the technique, make their own fork for more substantial changes unique to their environment or preferences, or simply adopt the skeleton once and abandon it thereafter. - -The primary advantage to using an SCM for maintaining these techniques is that those tools help facilitate the merge between the template and its adopting projects. - -Another advantage to using an SCM-managed approach is that tools like GitHub recognize that a change in the skeleton is the _same change_ across all projects that merge with that skeleton. Without the ancestry, with a traditional copy/paste approach, a [commit like this](https://github.com/jaraco/skeleton/commit/12eed1326e1bc26ce256e7b3f8cd8d3a5beab2d5) would produce notifications in the upstream project issue for each and every application, but because it's centralized, GitHub provides just the one notification when the change is added to the skeleton. - -# Usage - -## new projects - -To use skeleton for a new project, simply pull the skeleton into a new project: - -``` -$ git init my-new-project -$ cd my-new-project -$ git pull gh://jaraco/skeleton -``` - -Now customize the project to suit your individual project needs. - -## existing projects - -If you have an existing project, you can still incorporate the skeleton by merging it into the codebase. - -``` -$ git merge skeleton --allow-unrelated-histories -``` - -The `--allow-unrelated-histories` is necessary because the history from the skeleton was previously unrelated to the existing codebase. Resolve any merge conflicts and commit to the master, and now the project is based on the shared skeleton. - -## Updating - -Whenever a change is needed or desired for the general technique for packaging, it can be made in the skeleton project and then merged into each of the derived projects as needed, recommended before each release. As a result, features and best practices for packaging are centrally maintained and readily trickle into a whole suite of packages. This technique lowers the amount of tedious work necessary to create or maintain a project, and coupled with other techniques like continuous integration and deployment, lowers the cost of creating and maintaining refined Python projects to just a few, familiar Git operations. - -For example, here's a session of the [path project](https://pypi.org/project/path) pulling non-conflicting changes from the skeleton: - - - -Thereafter, the target project can make whatever customizations it deems relevant to the scaffolding. The project may even at some point decide that the divergence is too great to merit renewed merging with the original skeleton. This approach applies maximal guidance while creating minimal constraints. - -## Periodic Collapse - -In late 2020, this project [introduced](https://github.com/jaraco/skeleton/issues/27) the idea of a periodic but infrequent (O(years)) collapse of commits to limit the number of commits a new consumer will need to accept to adopt the skeleton. - -The full history of commits is collapsed into a single commit and that commit becomes the new mainline head. - -When one of these collapse operations happens, any project that previously pulled from the skeleton will no longer have a related history with that new main branch. For those projects, the skeleton provides a "handoff" branch that reconciles the two branches. Any project that has previously merged with the skeleton but now gets an error "fatal: refusing to merge unrelated histories" should instead use the handoff branch once to incorporate the new main branch. - -``` -$ git pull https://github.com/jaraco/skeleton 2020-handoff -``` - -This handoff needs to be pulled just once and thereafter the project can pull from the main head. - -The archive and handoff branches from prior collapses are indicate here: - -| refresh | archive | handoff | -|---------|-----------------|--------------| -| 2020-12 | archive/2020-12 | 2020-handoff | - -# Features - -The features/techniques employed by the skeleton include: - -- PEP 517/518-based build relying on Setuptools as the build tool -- Setuptools declarative configuration using setup.cfg -- tox for running tests -- A README.rst as reStructuredText with some popular badges, but with Read the Docs and AppVeyor badges commented out -- A CHANGES.rst file intended for publishing release notes about the project -- Use of [Black](https://black.readthedocs.io/en/stable/) for code formatting (disabled on unsupported Python 3.5 and earlier) -- Integrated type checking through [mypy](https://github.com/python/mypy/). - -## Packaging Conventions - -A pyproject.toml is included to enable PEP 517 and PEP 518 compatibility and declares the requirements necessary to build the project on Setuptools (a minimum version compatible with setup.cfg declarative config). - -The setup.cfg file implements the following features: - -- Assumes universal wheel for release -- Advertises the project's LICENSE file (MIT by default) -- Reads the README.rst file into the long description -- Some common Trove classifiers -- Includes all packages discovered in the repo -- Data files in the package are also included (not just Python files) -- Declares the required Python versions -- Declares install requirements (empty by default) -- Declares setup requirements for legacy environments -- Supplies two 'extras': - - testing: requirements for running tests - - docs: requirements for building docs - - these extras split the declaration into "upstream" (requirements as declared by the skeleton) and "local" (those specific to the local project); these markers help avoid merge conflicts -- Placeholder for defining entry points - -Additionally, the setup.py file declares `use_scm_version` which relies on [setuptools_scm](https://pypi.org/project/setuptools_scm) to do two things: - -- derive the project version from SCM tags -- ensure that all files committed to the repo are automatically included in releases - -## Running Tests - -The skeleton assumes the developer has [tox](https://pypi.org/project/tox) installed. The developer is expected to run `tox` to run tests on the current Python version using [pytest](https://pypi.org/project/pytest). - -Other environments (invoked with `tox -e {name}`) supplied include: - - - a `docs` environment to build the documentation - - a `release` environment to publish the package to PyPI - -A pytest.ini is included to define common options around running tests. In particular: - -- rely on default test discovery in the current directory -- avoid recursing into common directories not containing tests -- run doctests on modules and invoke Flake8 tests -- in doctests, allow Unicode literals and regular literals to match, allowing for doctests to run on Python 2 and 3. Also enable ELLIPSES, a default that would be undone by supplying the prior option. -- filters out known warnings caused by libraries/functionality included by the skeleton - -Relies on a .flake8 file to correct some default behaviors: - -- disable mutually incompatible rules W503 and W504 -- support for Black format - -## Continuous Integration - -The project is pre-configured to run Continuous Integration tests. - -### Github Actions - -[Github Actions](https://docs.github.com/en/free-pro-team@latest/actions) are the preferred provider as they provide free, fast, multi-platform services with straightforward configuration. Configured in `.github/workflows`. - -Features include: -- test against multiple Python versions -- run on late (and updated) platform versions -- automated releases of tagged commits -- [automatic merging of PRs](https://github.com/marketplace/actions/merge-pull-requests) (requires [protecting branches with required status checks](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/enabling-required-status-checks), [not possible through API](https://github.community/t/set-all-status-checks-to-be-required-as-branch-protection-using-the-github-api/119493)) - - -### Continuous Deployments - -In addition to running tests, an additional publish stage is configured to automatically release tagged commits to PyPI using [API tokens](https://pypi.org/help/#apitoken). The release process expects an authorized token to be configured with each Github project (or org) `PYPI_TOKEN` [secret](https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets). Example: - -``` -pip-run -q jaraco.develop -- -m jaraco.develop.add-github-secrets -``` - -## Building Documentation - -Documentation is automatically built by [Read the Docs](https://readthedocs.org) when the project is registered with it, by way of the .readthedocs.yml file. To test the docs build manually, a tox env may be invoked as `tox -e docs`. Both techniques rely on the dependencies declared in `setup.cfg/options.extras_require.docs`. - -In addition to building the Sphinx docs scaffolded in `docs/`, the docs build a `history.html` file that first injects release dates and hyperlinks into the CHANGES.rst before incorporating it as history in the docs. - -## Cutting releases - -By default, tagged commits are released through the continuous integration deploy stage. - -Releases may also be cut manually by invoking the tox environment `release` with the PyPI token set as the TWINE_PASSWORD: - -``` -TWINE_PASSWORD={token} tox -e release -``` diff --git a/third_party/python/zipp/test_zipp.py b/third_party/python/zipp/test_zipp.py deleted file mode 100644 index 481255342ded..000000000000 --- a/third_party/python/zipp/test_zipp.py +++ /dev/null @@ -1,360 +0,0 @@ -import io -import zipfile -import contextlib -import pathlib -import unittest -import tempfile -import shutil -import string -import functools - -import jaraco.itertools -import func_timeout - -import zipp - -consume = tuple - - -def add_dirs(zf): - """ - Given a writable zip file zf, inject directory entries for - any directories implied by the presence of children. - """ - for name in zipp.CompleteDirs._implied_dirs(zf.namelist()): - zf.writestr(name, b"") - return zf - - -def build_alpharep_fixture(): - """ - Create a zip file with this structure: - - . - ├── a.txt - ├── b - │ ├── c.txt - │ ├── d - │ │ └── e.txt - │ └── f.txt - └── g - └── h - └── i.txt - - This fixture has the following key characteristics: - - - a file at the root (a) - - a file two levels deep (b/d/e) - - multiple files in a directory (b/c, b/f) - - a directory containing only a directory (g/h) - - "alpha" because it uses alphabet - "rep" because it's a representative example - """ - data = io.BytesIO() - zf = zipfile.ZipFile(data, "w") - zf.writestr("a.txt", b"content of a") - zf.writestr("b/c.txt", b"content of c") - zf.writestr("b/d/e.txt", b"content of e") - zf.writestr("b/f.txt", b"content of f") - zf.writestr("g/h/i.txt", b"content of i") - zf.filename = "alpharep.zip" - return zf - - -@contextlib.contextmanager -def temp_dir(): - tmpdir = tempfile.mkdtemp() - try: - yield pathlib.Path(tmpdir) - finally: - shutil.rmtree(tmpdir) - - -def pass_alpharep(meth): - """ - Given a method, wrap it in a for loop that invokes method - with each subtest. - """ - - @functools.wraps(meth) - def wrapper(self): - for alpharep in self.zipfile_alpharep(): - meth(self, alpharep=alpharep) - - return wrapper - - -class TestPath(unittest.TestCase): - def setUp(self): - self.fixtures = contextlib.ExitStack() - self.addCleanup(self.fixtures.close) - - def zipfile_alpharep(self): - with self.subTest(): - yield build_alpharep_fixture() - with self.subTest(): - yield add_dirs(build_alpharep_fixture()) - - def zipfile_ondisk(self, alpharep): - tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir())) - buffer = alpharep.fp - alpharep.close() - path = tmpdir / alpharep.filename - with path.open("wb") as strm: - strm.write(buffer.getvalue()) - return path - - @pass_alpharep - def test_iterdir_and_types(self, alpharep): - root = zipp.Path(alpharep) - assert root.is_dir() - a, b, g = root.iterdir() - assert a.is_file() - assert b.is_dir() - assert g.is_dir() - c, f, d = b.iterdir() - assert c.is_file() and f.is_file() - (e,) = d.iterdir() - assert e.is_file() - (h,) = g.iterdir() - (i,) = h.iterdir() - assert i.is_file() - - @pass_alpharep - def test_is_file_missing(self, alpharep): - root = zipp.Path(alpharep) - assert not root.joinpath('missing.txt').is_file() - - @pass_alpharep - def test_iterdir_on_file(self, alpharep): - root = zipp.Path(alpharep) - a, b, g = root.iterdir() - with self.assertRaises(ValueError): - a.iterdir() - - @pass_alpharep - def test_subdir_is_dir(self, alpharep): - root = zipp.Path(alpharep) - assert (root / 'b').is_dir() - assert (root / 'b/').is_dir() - assert (root / 'g').is_dir() - assert (root / 'g/').is_dir() - - @pass_alpharep - def test_open(self, alpharep): - root = zipp.Path(alpharep) - a, b, g = root.iterdir() - with a.open() as strm: - data = strm.read() - assert data == "content of a" - - def test_open_write(self): - """ - If the zipfile is open for write, it should be possible to - write bytes or text to it. - """ - zf = zipp.Path(zipfile.ZipFile(io.BytesIO(), mode='w')) - with zf.joinpath('file.bin').open('wb') as strm: - strm.write(b'binary contents') - with zf.joinpath('file.txt').open('w') as strm: - strm.write('text file') - - def test_open_extant_directory(self): - """ - Attempting to open a directory raises IsADirectoryError. - """ - zf = zipp.Path(add_dirs(build_alpharep_fixture())) - with self.assertRaises(IsADirectoryError): - zf.joinpath('b').open() - - @pass_alpharep - def test_open_binary_invalid_args(self, alpharep): - root = zipp.Path(alpharep) - with self.assertRaises(ValueError): - root.joinpath('a.txt').open('rb', encoding='utf-8') - with self.assertRaises(ValueError): - root.joinpath('a.txt').open('rb', 'utf-8') - - def test_open_missing_directory(self): - """ - Attempting to open a missing directory raises FileNotFoundError. - """ - zf = zipp.Path(add_dirs(build_alpharep_fixture())) - with self.assertRaises(FileNotFoundError): - zf.joinpath('z').open() - - @pass_alpharep - def test_read(self, alpharep): - root = zipp.Path(alpharep) - a, b, g = root.iterdir() - assert a.read_text() == "content of a" - assert a.read_bytes() == b"content of a" - - @pass_alpharep - def test_joinpath(self, alpharep): - root = zipp.Path(alpharep) - a = root.joinpath("a.txt") - assert a.is_file() - e = root.joinpath("b").joinpath("d").joinpath("e.txt") - assert e.read_text() == "content of e" - - @pass_alpharep - def test_joinpath_multiple(self, alpharep): - root = zipp.Path(alpharep) - e = root.joinpath("b", "d", "e.txt") - assert e.read_text() == "content of e" - - @pass_alpharep - def test_traverse_truediv(self, alpharep): - root = zipp.Path(alpharep) - a = root / "a.txt" - assert a.is_file() - e = root / "b" / "d" / "e.txt" - assert e.read_text() == "content of e" - - @pass_alpharep - def test_traverse_simplediv(self, alpharep): - """ - Disable the __future__.division when testing traversal. - """ - code = compile( - source="zipp.Path(alpharep) / 'a'", - filename="(test)", - mode="eval", - dont_inherit=True, - ) - eval(code) - - @pass_alpharep - def test_pathlike_construction(self, alpharep): - """ - zipp.Path should be constructable from a path-like object - """ - zipfile_ondisk = self.zipfile_ondisk(alpharep) - pathlike = pathlib.Path(str(zipfile_ondisk)) - zipp.Path(pathlike) - - @pass_alpharep - def test_traverse_pathlike(self, alpharep): - root = zipp.Path(alpharep) - root / pathlib.Path("a") - - @pass_alpharep - def test_parent(self, alpharep): - root = zipp.Path(alpharep) - assert (root / 'a').parent.at == '' - assert (root / 'a' / 'b').parent.at == 'a/' - - @pass_alpharep - def test_dir_parent(self, alpharep): - root = zipp.Path(alpharep) - assert (root / 'b').parent.at == '' - assert (root / 'b/').parent.at == '' - - @pass_alpharep - def test_missing_dir_parent(self, alpharep): - root = zipp.Path(alpharep) - assert (root / 'missing dir/').parent.at == '' - - @pass_alpharep - def test_mutability(self, alpharep): - """ - If the underlying zipfile is changed, the Path object should - reflect that change. - """ - root = zipp.Path(alpharep) - a, b, g = root.iterdir() - alpharep.writestr('foo.txt', 'foo') - alpharep.writestr('bar/baz.txt', 'baz') - assert any(child.name == 'foo.txt' for child in root.iterdir()) - assert (root / 'foo.txt').read_text() == 'foo' - (baz,) = (root / 'bar').iterdir() - assert baz.read_text() == 'baz' - - HUGE_ZIPFILE_NUM_ENTRIES = 2 ** 13 - - def huge_zipfile(self): - """Create a read-only zipfile with a huge number of entries entries.""" - strm = io.BytesIO() - zf = zipfile.ZipFile(strm, "w") - for entry in map(str, range(self.HUGE_ZIPFILE_NUM_ENTRIES)): - zf.writestr(entry, entry) - zf.mode = 'r' - return zf - - def test_joinpath_constant_time(self): - """ - Ensure joinpath on items in zipfile is linear time. - """ - root = zipp.Path(self.huge_zipfile()) - entries = jaraco.itertools.Counter(root.iterdir()) - for entry in entries: - entry.joinpath('suffix') - # Check the file iterated all items - assert entries.count == self.HUGE_ZIPFILE_NUM_ENTRIES - - @func_timeout.func_set_timeout(3) - def test_implied_dirs_performance(self): - data = ['/'.join(string.ascii_lowercase + str(n)) for n in range(10000)] - zipp.CompleteDirs._implied_dirs(data) - - @pass_alpharep - def test_read_does_not_close(self, alpharep): - alpharep = self.zipfile_ondisk(alpharep) - with zipfile.ZipFile(alpharep) as file: - for rep in range(2): - zipp.Path(file, 'a.txt').read_text() - - @pass_alpharep - def test_subclass(self, alpharep): - class Subclass(zipp.Path): - pass - - root = Subclass(alpharep) - assert isinstance(root / 'b', Subclass) - - @pass_alpharep - def test_filename(self, alpharep): - root = zipp.Path(alpharep) - assert root.filename == pathlib.Path('alpharep.zip') - - @pass_alpharep - def test_root_name(self, alpharep): - """ - The name of the root should be the name of the zipfile - """ - root = zipp.Path(alpharep) - assert root.name == 'alpharep.zip' == root.filename.name - - @pass_alpharep - def test_root_parent(self, alpharep): - root = zipp.Path(alpharep) - assert root.parent == pathlib.Path('.') - root.root.filename = 'foo/bar.zip' - assert root.parent == pathlib.Path('foo') - - @pass_alpharep - def test_root_unnamed(self, alpharep): - """ - It is an error to attempt to get the name - or parent of an unnamed zipfile. - """ - alpharep.filename = None - root = zipp.Path(alpharep) - with self.assertRaises(TypeError): - root.name - with self.assertRaises(TypeError): - root.parent - - # .name and .parent should still work on subs - sub = root / "b" - assert sub.name == "b" - assert sub.parent - - @pass_alpharep - def test_inheritance(self, alpharep): - cls = type('PathChild', (zipp.Path,), {}) - for alpharep in self.zipfile_alpharep(): - file = cls(alpharep).joinpath('some dir').parent - assert isinstance(file, cls) diff --git a/third_party/python/zipp/tox.ini b/third_party/python/zipp/tox.ini deleted file mode 100644 index a259a48388bf..000000000000 --- a/third_party/python/zipp/tox.ini +++ /dev/null @@ -1,42 +0,0 @@ -[tox] -envlist = python -minversion = 3.2 -# https://github.com/jaraco/skeleton/issues/6 -tox_pip_extensions_ext_venv_update = true -toxworkdir={env:TOX_WORK_DIR:.tox} - -[testenv] -deps = -commands = - pytest {posargs} -usedevelop = True -extras = testing -setenv = - # workaround pypa/pip#9143 - PIP_USE_DEPRECATED=legacy-resolver - -[testenv:docs] -extras = - docs - testing -changedir = docs -commands = - python -m sphinx . {toxinidir}/build/html - -[testenv:release] -skip_install = True -deps = - build - twine[keyring]>=1.13 - path - jaraco.develop>=7.1 -passenv = - TWINE_PASSWORD - GITHUB_TOKEN -setenv = - TWINE_USERNAME = {env:TWINE_USERNAME:__token__} -commands = - python -c "import path; path.Path('dist').rmtree_p()" - python -m build - python -m twine upload dist/* - python -m jaraco.develop.create-github-release diff --git a/third_party/python/zipp/LICENSE b/third_party/python/zipp/zipp-3.4.1.dist-info/LICENSE similarity index 100% rename from third_party/python/zipp/LICENSE rename to third_party/python/zipp/zipp-3.4.1.dist-info/LICENSE diff --git a/third_party/python/zipp/zipp-3.4.1.dist-info/METADATA b/third_party/python/zipp/zipp-3.4.1.dist-info/METADATA new file mode 100644 index 000000000000..b54d9c71bdc7 --- /dev/null +++ b/third_party/python/zipp/zipp-3.4.1.dist-info/METADATA @@ -0,0 +1,54 @@ +Metadata-Version: 2.1 +Name: zipp +Version: 3.4.1 +Summary: Backport of pathlib-compatible object wrapper for zip files +Home-page: https://github.com/jaraco/zipp +Author: Jason R. Coombs +Author-email: jaraco@jaraco.com +License: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Requires-Python: >=3.6 +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: jaraco.packaging (>=8.2) ; extra == 'docs' +Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Provides-Extra: testing +Requires-Dist: pytest (>=4.6) ; extra == 'testing' +Requires-Dist: pytest-checkdocs (>=1.2.3) ; extra == 'testing' +Requires-Dist: pytest-flake8 ; extra == 'testing' +Requires-Dist: pytest-cov ; extra == 'testing' +Requires-Dist: pytest-enabler ; extra == 'testing' +Requires-Dist: jaraco.itertools ; extra == 'testing' +Requires-Dist: func-timeout ; extra == 'testing' +Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy ; (platform_python_implementation != "PyPy") and extra == 'testing' + +.. image:: https://img.shields.io/pypi/v/zipp.svg + :target: `PyPI link`_ + +.. image:: https://img.shields.io/pypi/pyversions/zipp.svg + :target: `PyPI link`_ + +.. _PyPI link: https://pypi.org/project/zipp + +.. image:: https://github.com/jaraco/zipp/workflows/tests/badge.svg + :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. .. image:: https://readthedocs.org/projects/zipp/badge/?version=latest +.. :target: https://zipp.readthedocs.io/en/latest/?badge=latest + + +A pathlib-compatible Zipfile object wrapper. A backport of the +`Path object `_. + + diff --git a/third_party/python/zipp/zipp-3.4.1.dist-info/RECORD b/third_party/python/zipp/zipp-3.4.1.dist-info/RECORD new file mode 100644 index 000000000000..135f87095e6a --- /dev/null +++ b/third_party/python/zipp/zipp-3.4.1.dist-info/RECORD @@ -0,0 +1,6 @@ +zipp.py,sha256=wMSoYxAIPgYnqJAW0JcAl5sWaIcFc5xk3dNjf6ElGgU,8089 +zipp-3.4.1.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050 +zipp-3.4.1.dist-info/METADATA,sha256=ceLXh-zF008K5aguWA5dHZ20bzsRa1kwV3heimH0GXw,2087 +zipp-3.4.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +zipp-3.4.1.dist-info/top_level.txt,sha256=iAbdoSHfaGqBfVb2XuR9JqSQHCoOsOtG6y9C_LSpqFw,5 +zipp-3.4.1.dist-info/RECORD,, diff --git a/third_party/python/zipp/zipp-3.4.1.dist-info/WHEEL b/third_party/python/zipp/zipp-3.4.1.dist-info/WHEEL new file mode 100644 index 000000000000..385faab0525c --- /dev/null +++ b/third_party/python/zipp/zipp-3.4.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/third_party/python/zipp/zipp-3.4.1.dist-info/top_level.txt b/third_party/python/zipp/zipp-3.4.1.dist-info/top_level.txt new file mode 100644 index 000000000000..e82f676f82a3 --- /dev/null +++ b/third_party/python/zipp/zipp-3.4.1.dist-info/top_level.txt @@ -0,0 +1 @@ +zipp