├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── coverage_conditional_plugin ├── __init__.py ├── py.typed └── version.py ├── poetry.lock ├── pyproject.toml ├── setup.cfg ├── test_project ├── .coveragerc ├── __init__.py ├── compat.py ├── example.py ├── omit1.py ├── omit2.py └── pyproject.toml └── tests ├── test_implementation.py ├── test_integration.py ├── test_omits.py └── test_plugin.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # Check http://editorconfig.org for more information 2 | # This is the main config file for this project: 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 2 11 | trim_trailing_whitespace = true 12 | 13 | [*.py] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.pyi] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | [Makefile] 22 | indent_style = tab 23 | 24 | [*.md] 25 | trim_trailing_whitespace = false 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "02:00" 8 | open-pull-requests-limit: 10 9 | - package-ecosystem: github-actions 10 | directory: "/" 11 | schedule: 12 | interval: daily 13 | time: "02:00" 14 | open-pull-requests-limit: 10 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set up Python ${{ matrix.python-version }} 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: Install poetry 25 | run: | 26 | curl -sSL \ 27 | "https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py" | python 28 | 29 | # Adding `poetry` to `$PATH`: 30 | echo "$HOME/.poetry/bin" >> $GITHUB_PATH 31 | 32 | - name: Install dependencies 33 | run: | 34 | poetry config virtualenvs.in-project true 35 | poetry run pip install -U pip 36 | poetry install 37 | 38 | - name: Run checks 39 | run: make test 40 | 41 | - name: Upload coverage to Codecov 42 | uses: codecov/codecov-action@v3 43 | with: 44 | file: ./coverage.xml 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #### joe made this: http://goel.io/joe 2 | #### macos #### 3 | # General 4 | *.DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | #### linux #### 31 | *~ 32 | 33 | # temporary files which can be created if a process still has a handle open of a deleted file 34 | .fuse_hidden* 35 | 36 | # KDE directory preferences 37 | .directory 38 | 39 | # Linux trash folder which might appear on any partition or disk 40 | .Trash-* 41 | 42 | # .nfs files are created when an open file is removed but is still being accessed 43 | .nfs* 44 | #### windows #### 45 | # Windows thumbnail cache files 46 | Thumbs.db 47 | ehthumbs.db 48 | ehthumbs_vista.db 49 | 50 | # Dump file 51 | *.stackdump 52 | 53 | # Folder config file 54 | Desktop.ini 55 | 56 | # Recycle Bin used on file shares 57 | $RECYCLE.BIN/ 58 | 59 | # Windows Installer files 60 | *.cab 61 | *.msi 62 | *.msm 63 | *.msp 64 | 65 | # Windows shortcuts 66 | *.lnk 67 | #### python #### 68 | # Byte-compiled / optimized / DLL files 69 | __pycache__/ 70 | *.py[cod] 71 | *$py.class 72 | 73 | # C extensions 74 | *.so 75 | 76 | # Distribution / packaging 77 | .Python 78 | build/ 79 | develop-eggs/ 80 | dist/ 81 | downloads/ 82 | eggs/ 83 | .eggs/ 84 | lib/ 85 | lib64/ 86 | parts/ 87 | sdist/ 88 | var/ 89 | wheels/ 90 | *.egg-info/ 91 | .installed.cfg 92 | *.egg 93 | 94 | # PyInstaller 95 | # Usually these files are written by a python script from a template 96 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 97 | *.manifest 98 | *.spec 99 | 100 | # Installer logs 101 | pip-log.txt 102 | pip-delete-this-directory.txt 103 | 104 | # Unit test / coverage reports 105 | htmlcov/ 106 | .tox/ 107 | .coverage 108 | .coverage.* 109 | .cache 110 | nosetests.xml 111 | coverage.xml 112 | *.cover 113 | .hypothesis/ 114 | 115 | # Translations 116 | *.mo 117 | *.pot 118 | 119 | # Django stuff: 120 | *.log 121 | local_settings.py 122 | 123 | # Flask stuff: 124 | instance/ 125 | .webassets-cache 126 | 127 | # Scrapy stuff: 128 | .scrapy 129 | 130 | # Sphinx documentation 131 | docs/_build/ 132 | 133 | # PyBuilder 134 | target/ 135 | 136 | # Jupyter Notebook 137 | .ipynb_checkpoints 138 | 139 | # celery beat schedule file 140 | celerybeat-schedule 141 | 142 | # SageMath parsed files 143 | *.sage.py 144 | 145 | # Environments 146 | .env 147 | .venv 148 | env/ 149 | venv/ 150 | ENV/ 151 | 152 | # Spyder project settings 153 | .spyderproject 154 | .spyproject 155 | 156 | # Rope project settings 157 | .ropeproject 158 | 159 | # mkdocs documentation 160 | /site 161 | 162 | # mypy 163 | .mypy_cache/ 164 | 165 | #### jetbrains #### 166 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 167 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 168 | 169 | # User-specific stuff: 170 | .idea/**/workspace.xml 171 | .idea/**/tasks.xml 172 | .idea/dictionaries 173 | 174 | # Sensitive or high-churn files: 175 | .idea/**/dataSources/ 176 | .idea/**/dataSources.ids 177 | .idea/**/dataSources.xml 178 | .idea/**/dataSources.local.xml 179 | .idea/**/sqlDataSources.xml 180 | .idea/**/dynamic.xml 181 | .idea/**/uiDesigner.xml 182 | 183 | # Gradle: 184 | .idea/**/gradle.xml 185 | .idea/**/libraries 186 | 187 | # CMake 188 | cmake-build-debug/ 189 | 190 | # Mongo Explorer plugin: 191 | .idea/**/mongoSettings.xml 192 | 193 | ## File-based project format: 194 | *.iws 195 | 196 | ## Plugin-specific files: 197 | 198 | # IntelliJ 199 | /out/ 200 | 201 | # mpeltonen/sbt-idea plugin 202 | .idea_modules/ 203 | 204 | # JIRA plugin 205 | atlassian-ide-plugin.xml 206 | 207 | # Cursive Clojure plugin 208 | .idea/replstate.xml 209 | 210 | # Crashlytics plugin (for Android Studio and IntelliJ) 211 | com_crashlytics_export_strings.xml 212 | crashlytics.properties 213 | crashlytics-build.properties 214 | fabric.properties 215 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Version history 2 | 3 | We follow [Semantic Versions](https://semver.org/). 4 | 5 | 6 | ## Version 0.9.0 7 | 8 | ### Features 9 | 10 | - Adds `python@3.11` support 11 | - Now, only `coverage@7` is officially supported 12 | - We can now omit whole modules, 13 | using `[tool.coverage.coverage_conditional_plugin.omit]` feature 14 | in TOML configuration files 15 | 16 | 17 | ## Version 0.8.0 18 | 19 | ### Features 20 | 21 | - Bump `coverage` to `7.0` 22 | 23 | 24 | ## Version 0.7.0 25 | 26 | ### Features 27 | 28 | - Use `importlib` instead of `pkg_resources` to get package version 29 | 30 | 31 | ## Version 0.6.0 32 | 33 | ### Features 34 | 35 | - Drop `python3.6` support 36 | - Adds `tests/` and `test_project/` to `sdist` distributions 37 | 38 | ### Misc 39 | 40 | - Upgrades `poetry` to `1.2` 41 | 42 | 43 | ## Version 0.5.0 44 | 45 | ### Features 46 | 47 | - `python3.10` support 48 | - `coverage@6` support 49 | 50 | 51 | ## Version 0.4.0 52 | 53 | ### Features 54 | 55 | - `python3.9` support 56 | 57 | ### Bugfixes 58 | 59 | - Fixes that `packaging` restriction was too tight 60 | 61 | 62 | ## Version 0.3.1 63 | 64 | ### Bugfixes 65 | 66 | - Adds `packaging` to the deps 67 | 68 | 69 | ## Version 0.3.0 70 | 71 | ### Features 72 | 73 | - Now also works with configs specified in `pyproject.toml` 74 | 75 | 76 | ## Version 0.2.0 77 | 78 | ### Features 79 | 80 | - Adds `get_env_info` function, 81 | so one can import this plugin and use it programmatically 82 | to debug and explore 83 | 84 | ### Misc 85 | 86 | - Now using Github Actions 87 | - Updates lots of dev-deps 88 | 89 | 90 | ## Version 0.1.0 91 | 92 | - Initial release 93 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | 4 | ## Tutorials 5 | 6 | This might be helpful: 7 | 8 | - 9 | 10 | 11 | ## Dependencies 12 | 13 | We use [`poetry`](https://github.com/python-poetry/poetry) to manage the dependencies. 14 | 15 | To install them you would need to run `install` command: 16 | 17 | ```bash 18 | poetry install 19 | ``` 20 | 21 | To activate your `virtualenv` run `poetry shell`. 22 | 23 | 24 | ## One magic command 25 | 26 | Run `make test` to run everything we have! 27 | 28 | 29 | ## Tests 30 | 31 | We use `pytest` and `flake8` for quality control. 32 | We also use [`wemake_python_styleguide`](https://github.com/wemake-services/wemake-python-styleguide) to enforce the code quality. 33 | 34 | To run all tests: 35 | 36 | ```bash 37 | pytest 38 | ``` 39 | 40 | To run linting: 41 | 42 | ```bash 43 | flake8 . 44 | ``` 45 | 46 | These steps are mandatory during the CI. 47 | 48 | 49 | ## Type checks 50 | 51 | We use `mypy` to run type checks on our code. 52 | To use it: 53 | 54 | ```bash 55 | mypy coverage_conditional_plugin tests/**/*.py 56 | ``` 57 | 58 | This step is mandatory during the CI. 59 | 60 | 61 | ## Submitting your code 62 | 63 | We use [trunk based](https://trunkbaseddevelopment.com/) 64 | development (we also sometimes call it `wemake-git-flow`). 65 | 66 | What the point of this method? 67 | 68 | 1. We use protected `master` branch, 69 | so the only way to push your code is via pull request 70 | 2. We use issue branches: to implement a new feature or to fix a bug 71 | create a new branch named `issue-$TASKNUMBER` 72 | 3. Then create a pull request to `master` branch 73 | 4. We use `git tag`s to make releases, so we can track what has changed 74 | since the latest release 75 | 76 | So, this way we achieve an easy and scalable development process 77 | which frees us from merging hell and long-living branches. 78 | 79 | In this method, the latest version of the app is always in the `master` branch. 80 | 81 | ### Before submitting 82 | 83 | Before submitting your code please do the following steps: 84 | 85 | 1. Run `pytest` to make sure everything was working before 86 | 2. Add any changes you want 87 | 3. Add tests for the new changes 88 | 4. Edit documentation if you have changed something significant 89 | 5. Update `CHANGELOG.md` with a quick summary of your changes 90 | 6. Run `pytest` again to make sure it is still working 91 | 7. Run `mypy` to ensure that types are correct 92 | 8. Run `flake8` to ensure that style is correct 93 | 94 | 95 | ## Other help 96 | 97 | You can contribute by spreading a word about this library. 98 | It would also be a huge contribution to write 99 | a short article on how you are using this project. 100 | You can also share your best practices with us. 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | Copyright (c) 2019 wemake.services 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 | OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL:=/usr/bin/env bash 2 | 3 | .PHONY: lint 4 | lint: 5 | poetry run mypy coverage_conditional_plugin tests/*.py 6 | poetry run flake8 . 7 | 8 | .PHONY: unit 9 | unit: 10 | poetry run pytest 11 | 12 | .PHONY: package 13 | package: 14 | poetry check 15 | poetry run pip check 16 | poetry run safety check --full-report 17 | 18 | .PHONY: test 19 | test: lint unit package 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coverage-conditional-plugin 2 | 3 | [![wemake.services](https://img.shields.io/badge/%20-wemake.services-green.svg?label=%20&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC%2FxhBQAAAAFzUkdCAK7OHOkAAAAbUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP%2F%2F%2F5TvxDIAAAAIdFJOUwAjRA8xXANAL%2Bv0SAAAADNJREFUGNNjYCAIOJjRBdBFWMkVQeGzcHAwksJnAPPZGOGAASzPzAEHEGVsLExQwE7YswCb7AFZSF3bbAAAAABJRU5ErkJggg%3D%3D)](https://wemake.services) 4 | [![Build Status](https://github.com/wemake-services/coverage-conditional-plugin/workflows/test/badge.svg?branch=master&event=push)](https://github.com/wemake-services/coverage-conditional-plugin/actions?query=workflow%3Atest) 5 | [![codecov](https://codecov.io/gh/wemake-services/coverage-conditional-plugin/branch/master/graph/badge.svg)](https://codecov.io/gh/wemake-services/coverage-conditional-plugin) 6 | [![Python Version](https://img.shields.io/pypi/pyversions/coverage-conditional-plugin.svg)](https://pypi.org/project/coverage-conditional-plugin/) 7 | [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide) 8 | 9 | Conditional coverage based on any rules you define! 10 | 11 | Some projects have different parts that relies on different environments: 12 | 13 | - Python version, some code is only executed on specific versions and ignored on others 14 | - OS version, some code might be Windows, Mac, or Linux only 15 | - External packages, some code is only executed when some 3rd party package is installed 16 | 17 | Current best practice is to use `# pragma: no cover` for this places in our project. 18 | This project allows to use configurable pragmas 19 | that include code to the coverage if some condition evaluates to true, 20 | and fallback to ignoring this code when condition is false. 21 | 22 | Read [the announcing post](https://sobolevn.me/2020/02/conditional-coverage). 23 | 24 | 25 | ## Installation 26 | 27 | ```bash 28 | pip install coverage-conditional-plugin 29 | ``` 30 | 31 | Then you will need to add to your `setup.cfg` or `.coveragerc` file 32 | some extra configuration: 33 | 34 | ```ini 35 | [coverage:run] 36 | # Here we specify plugins for coverage to be used: 37 | plugins = 38 | coverage_conditional_plugin 39 | 40 | [coverage:coverage_conditional_plugin] 41 | # Here we specify files to conditionally omit: 42 | omit = 43 | "sys_platform == 'win32'": 44 | "my_project/omit*.py" 45 | "my_project/win.py" 46 | # Here we specify our pragma rules: 47 | rules = 48 | "sys_version_info >= (3, 8)": py-gte-38 49 | "is_installed('mypy')": has-mypy 50 | 51 | ``` 52 | 53 | Or to your `pyproject.toml`: 54 | 55 | ```toml 56 | [tool.coverage.run] 57 | # Here we specify plugins for coverage to be used: 58 | plugins = ["coverage_conditional_plugin"] 59 | 60 | [tool.coverage.coverage_conditional_plugin.omit] 61 | # Here we specify files to conditionally omit: 62 | "sys_platform == 'win32'" = "my_project/omit*.py" 63 | 64 | [tool.coverage.coverage_conditional_plugin.rules] 65 | # Here we specify our pragma rules: 66 | py-gte-38 = "sys_version_info >= (3, 8)" 67 | has-mypy = "is_installed('mypy')" 68 | ``` 69 | 70 | 71 | Adapt rules to suit your needs! 72 | 73 | 74 | ## Example 75 | 76 | Imagine that we have this code: 77 | 78 | ```python 79 | try: # pragma: has-django 80 | import django 81 | except ImportError: # pragma: has-no-django 82 | django = None 83 | 84 | def run_if_django_is_installed(): 85 | if django is not None: # pragma: has-django 86 | ... 87 | ``` 88 | 89 | And here's the configuration you might use: 90 | 91 | ```ini 92 | [coverage:coverage_conditional_plugin] 93 | rules = 94 | "is_installed('django')": has-django 95 | "not is_installed('django')": has-no-django 96 | 97 | ``` 98 | 99 | When running tests with and without `django` installed 100 | you will have `100%` coverage in both cases. 101 | 102 | But, different lines will be included. 103 | With `django` installed it will include 104 | both `try:` and `if django is not None:` conditions. 105 | 106 | When running without `django` installed, 107 | it will include `except ImportError:` line. 108 | 109 | 110 | ## Writing pragma rules 111 | 112 | Format for pragma rules is: 113 | 114 | ``` 115 | "pragma-condition": pragma-name 116 | ``` 117 | 118 | Code inside `"pragma-condition"` is evaluted with `eval`. 119 | Make sure that the input you pass there is trusted! 120 | `"pragma-condition"` must return `bool` value after evaluation. 121 | 122 | We support all environment markers specified in [PEP-496](https://www.python.org/dev/peps/pep-0496/). 123 | See [Strings](https://www.python.org/dev/peps/pep-0496/#strings) 124 | and [Version Numbers](https://www.python.org/dev/peps/pep-0496/#version-numbers) 125 | sections for available values. Also, we provide a bunch of additional markers: 126 | 127 | - `sys_version_info` is the same as [`sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info) 128 | - `os_environ` is the same as [`os.environ`](https://docs.python.org/3/library/os.html#os.environ) 129 | - `is_installed` is our custom function that tries to import the passed string, returns `bool` value 130 | - `package_version` is our custom function that tries to get package version from `pkg_resources` and returns its [parsed version](https://packaging.pypa.io/en/latest/version/#packaging.version.parse) 131 | 132 | Use `get_env_info` to get values for the current environment: 133 | 134 | ```python 135 | from coverage_conditional_plugin import get_env_info 136 | 137 | get_env_info() 138 | ``` 139 | 140 | 141 | ## Writing omits 142 | 143 | Omits allow entire files to be conditionally omitted from coverage measurement. 144 | 145 | The TOML format for omits is: 146 | 147 | ```toml 148 | [tool.coverage.coverage_conditional_plugin.omit] 149 | "pragma-condition" = ["project/prefix*.py", "project/filename.py"] 150 | # or 151 | "pragma-condition" = "project/filename.py" 152 | ``` 153 | 154 | **Note**: `ini` format is not supported for `omit` configuration option, 155 | because there's no easy way to parse `ini` complex configuration. 156 | PRs with the fix are welcome! 157 | 158 | File name patterns should follow coverage.py's `[run] omit` syntax. 159 | See [coverage.py](https://coverage.readthedocs.io/en/stable/source.html). 160 | 161 | 162 | ## License 163 | 164 | [MIT](https://github.com/wemake.services/coverage-conditional-plugin/blob/master/LICENSE) 165 | -------------------------------------------------------------------------------- /coverage_conditional_plugin/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import traceback 4 | from importlib import import_module 5 | from typing import Any, ClassVar, Dict, List, Tuple, Union 6 | 7 | from coverage import CoveragePlugin 8 | from coverage.config import CoverageConfig 9 | from packaging.markers import default_environment 10 | 11 | from coverage_conditional_plugin.version import package_version 12 | 13 | #: Used for `omit` specification. 14 | _OmitConfigSpec = Dict[str, Union[str, List[str]]] 15 | 16 | _INI_OMIT_ERROR = ( 17 | 'Improperly configured: `ini` does not ' + 18 | 'support `omit` specification, ' + 19 | 'current setting is: {0}' 20 | ) 21 | 22 | 23 | def get_env_info() -> Dict[str, object]: 24 | """Public helper to get the same env we pass to the plugin.""" 25 | env_info: Dict[str, object] = {} 26 | env_info.update(default_environment()) 27 | # Feel free to send PRs that extend this dict: 28 | env_info.update({ 29 | 'sys_version_info': sys.version_info, 30 | 'os_environ': os.environ, 31 | 'is_installed': _is_installed, 32 | 'package_version': package_version, 33 | # We need this, otherwise `_should_be_applied` can generate a warning: 34 | 'sys': sys, 35 | }) 36 | return env_info 37 | 38 | 39 | class _ConditionalCovPlugin(CoveragePlugin): 40 | _rules_opt_name: ClassVar[str] = 'coverage_conditional_plugin:rules' 41 | # We use `exlude_line` and not `exclude_also`, 42 | # because settings are already post-processed, which means that 43 | # `exlude_line` and `exclude_also` are already joined: 44 | _ignore_opt_name: ClassVar[str] = 'report:exclude_lines' 45 | _omit_opt_name_plugin: ClassVar[str] = 'coverage_conditional_plugin:omit' 46 | _omit_opt_name_coverage: ClassVar[str] = 'run:omit' 47 | 48 | def configure( # type: ignore[override] 49 | self, config: CoverageConfig, 50 | ) -> None: 51 | """ 52 | Main hook for adding extra configuration. 53 | 54 | Part of the ``coverage`` public API. 55 | Called right after ``coverage_init`` function. 56 | """ 57 | self._configure_omits(config) 58 | self._configure_rules(config) 59 | 60 | def _configure_omits(self, config: CoverageConfig) -> None: 61 | omits: Union[str, _OmitConfigSpec, None] = _get_option( 62 | config, 63 | self._omit_opt_name_plugin, 64 | ) 65 | if omits is None: 66 | return # No setting, ignoring 67 | elif not isinstance(omits, dict): 68 | raise RuntimeError(_INI_OMIT_ERROR.format(omits)) 69 | 70 | for code, patterns in omits.items(): 71 | if isinstance(patterns, str): 72 | patterns = [patterns] 73 | if _should_be_applied(code): 74 | self._omit_pattern(config, patterns) 75 | 76 | def _configure_rules(self, config: CoverageConfig) -> None: 77 | try: # ini format 78 | rules = filter( 79 | bool, 80 | _get_option(config, self._rules_opt_name).splitlines(), 81 | ) 82 | except AttributeError: # toml format 83 | rules = _get_option(config, self._rules_opt_name).items() 84 | 85 | for rule in rules: 86 | self._process_rule(config, rule) 87 | 88 | def _process_rule( 89 | self, config: CoverageConfig, rule: Union[str, Tuple[str, str]], 90 | ) -> None: 91 | if isinstance(rule, str): 92 | code, marker = [part.strip() for part in rule.rsplit(':', 1)] 93 | code = code[1:-1] # removes quotes 94 | elif isinstance(rule, tuple): 95 | marker = rule[0] 96 | code = rule[1] 97 | else: 98 | raise ValueError("Invalid type for 'rule'.") 99 | if _should_be_applied(code): 100 | self._ignore_marker(config, marker) 101 | 102 | def _ignore_marker( 103 | self, config: CoverageConfig, marker: str, 104 | ) -> None: 105 | """Adds a marker to the ignore list.""" 106 | exclude_lines = _get_option(config, self._ignore_opt_name) 107 | exclude_lines.append(marker) 108 | config.set_option(self._ignore_opt_name, exclude_lines) 109 | 110 | def _omit_pattern( 111 | self, config: CoverageConfig, patterns: List[str], 112 | ) -> None: 113 | """Adds a file name pattern to the omit list.""" 114 | omit_patterns = _get_option(config, self._omit_opt_name_coverage) 115 | omit_patterns.extend(patterns) 116 | config.set_option(self._omit_opt_name_coverage, omit_patterns) 117 | 118 | 119 | def _is_installed(package: str) -> bool: 120 | """Helper function to detect if some package is installed.""" 121 | try: 122 | import_module(package) 123 | except ImportError: 124 | return False 125 | return True 126 | 127 | 128 | def _should_be_applied(code: str) -> bool: 129 | """ 130 | Determines whether some specific marker should be applied or not. 131 | 132 | Uses ``exec`` on the code you pass with the marker. 133 | Be sure, that this code is safe. 134 | 135 | We also try to provide useful global functions 136 | to cover the most popular cases, like: 137 | 138 | - python version 139 | - OS name, platform, and version 140 | - helpers to work with installed packages 141 | 142 | Some examples: 143 | 144 | .. code:: ini 145 | 146 | [coverage:coverage_conditional_plugin] 147 | rules = 148 | "sys_version_info >= (3, 8)": py-gte-38 149 | "is_installed('mypy')": has-mypy 150 | 151 | So, code marked with `# pragma: py-gte-38` will be ignored 152 | for all version of Python prior to 3.8 release. 153 | And at the same time, 154 | this code will be included to the coverage on 3.8+ releases. 155 | 156 | """ 157 | env_info = get_env_info() 158 | try: 159 | return eval(code, env_info) # noqa: WPS421, S307 160 | except Exception: 161 | msg = 'Exception during conditional coverage evaluation:' 162 | print(msg, traceback.format_exc()) # noqa: WPS421 163 | return False 164 | 165 | 166 | def _get_option( # type: ignore[misc] 167 | config: CoverageConfig, option: str, 168 | ) -> Any: 169 | # Hack to silence all new typing issues. 170 | return config.get_option(option) 171 | 172 | 173 | def coverage_init(reg, options) -> None: 174 | """ 175 | Entrypoint, part of the ``coverage`` API. 176 | 177 | This is called when we specify: 178 | 179 | .. code:: ini 180 | 181 | [coverage:run] 182 | plugins = 183 | coverage_conditional_plugin 184 | 185 | See also: 186 | https://coverage.readthedocs.io/en/latest/plugins.html 187 | 188 | """ 189 | reg.add_configurer(_ConditionalCovPlugin()) 190 | -------------------------------------------------------------------------------- /coverage_conditional_plugin/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wemake-services/coverage-conditional-plugin/32c64be6fde4cc79ae3ab7c1a92d6effc0faad8d/coverage_conditional_plugin/py.typed -------------------------------------------------------------------------------- /coverage_conditional_plugin/version.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Tuple 2 | 3 | try: # pragma: no cover 4 | from importlib.metadata import version as metadata_version 5 | except ImportError: # pragma: no cover 6 | from importlib_metadata import version as metadata_version # type: ignore 7 | 8 | from packaging import version 9 | 10 | 11 | def package_version( 12 | package: str, 13 | ) -> Optional[Tuple[int, ...]]: 14 | """ 15 | Helper function that fetches distribution version. 16 | 17 | Can throw multiple exceptions. 18 | Be careful, use ``is_installed`` before using this one. 19 | 20 | Returns parsed varsion to be easily worked with. 21 | """ 22 | return version.parse(metadata_version(package)).release 23 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "astor" 5 | version = "0.8.1" 6 | description = "Read/rewrite/write Python ASTs" 7 | optional = false 8 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 9 | files = [ 10 | {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, 11 | {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, 12 | ] 13 | 14 | [[package]] 15 | name = "attrs" 16 | version = "23.1.0" 17 | description = "Classes Without Boilerplate" 18 | optional = false 19 | python-versions = ">=3.7" 20 | files = [ 21 | {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, 22 | {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, 23 | ] 24 | 25 | [package.dependencies] 26 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 27 | 28 | [package.extras] 29 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 30 | dev = ["attrs[docs,tests]", "pre-commit"] 31 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 32 | tests = ["attrs[tests-no-zope]", "zope-interface"] 33 | tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] 34 | 35 | [[package]] 36 | name = "autorepr" 37 | version = "0.3.0" 38 | description = "Makes civilized __repr__, __str__, and __unicode__ methods" 39 | optional = false 40 | python-versions = "*" 41 | files = [ 42 | {file = "autorepr-0.3.0-py2-none-any.whl", hash = "sha256:c34567e4073630feb52d9c788fc198085e9e9de4817e3b93b7c4c534fc689f11"}, 43 | {file = "autorepr-0.3.0-py2.py3-none-any.whl", hash = "sha256:1d9010d14fb325d3961e3aa73692685563f97d6ba4a2f0f735329fb37422599c"}, 44 | {file = "autorepr-0.3.0.tar.gz", hash = "sha256:ef770b84793d5433e6bb893054973b8c7ce6b487274f9c3f734f678cae11e85e"}, 45 | ] 46 | 47 | [[package]] 48 | name = "bandit" 49 | version = "1.7.5" 50 | description = "Security oriented static analyser for python code." 51 | optional = false 52 | python-versions = ">=3.7" 53 | files = [ 54 | {file = "bandit-1.7.5-py3-none-any.whl", hash = "sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549"}, 55 | {file = "bandit-1.7.5.tar.gz", hash = "sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e"}, 56 | ] 57 | 58 | [package.dependencies] 59 | colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} 60 | GitPython = ">=1.0.1" 61 | PyYAML = ">=5.3.1" 62 | rich = "*" 63 | stevedore = ">=1.20.0" 64 | 65 | [package.extras] 66 | test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "tomli (>=1.1.0)"] 67 | toml = ["tomli (>=1.1.0)"] 68 | yaml = ["PyYAML"] 69 | 70 | [[package]] 71 | name = "cattrs" 72 | version = "23.1.2" 73 | description = "Composable complex class support for attrs and dataclasses." 74 | optional = false 75 | python-versions = ">=3.7" 76 | files = [ 77 | {file = "cattrs-23.1.2-py3-none-any.whl", hash = "sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4"}, 78 | {file = "cattrs-23.1.2.tar.gz", hash = "sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657"}, 79 | ] 80 | 81 | [package.dependencies] 82 | attrs = ">=20" 83 | exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} 84 | typing_extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} 85 | 86 | [package.extras] 87 | bson = ["pymongo (>=4.2.0,<5.0.0)"] 88 | cbor2 = ["cbor2 (>=5.4.6,<6.0.0)"] 89 | msgpack = ["msgpack (>=1.0.2,<2.0.0)"] 90 | orjson = ["orjson (>=3.5.2,<4.0.0)"] 91 | pyyaml = ["PyYAML (>=6.0,<7.0)"] 92 | tomlkit = ["tomlkit (>=0.11.4,<0.12.0)"] 93 | ujson = ["ujson (>=5.4.0,<6.0.0)"] 94 | 95 | [[package]] 96 | name = "certifi" 97 | version = "2023.5.7" 98 | description = "Python package for providing Mozilla's CA Bundle." 99 | optional = false 100 | python-versions = ">=3.6" 101 | files = [ 102 | {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, 103 | {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, 104 | ] 105 | 106 | [[package]] 107 | name = "charset-normalizer" 108 | version = "3.1.0" 109 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 110 | optional = false 111 | python-versions = ">=3.7.0" 112 | files = [ 113 | {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, 114 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, 115 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, 116 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, 117 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, 118 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, 119 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, 120 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, 121 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, 122 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, 123 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, 124 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, 125 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, 126 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, 127 | {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, 128 | {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, 129 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, 130 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, 131 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, 132 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, 133 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, 134 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, 135 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, 136 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, 137 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, 138 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, 139 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, 140 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, 141 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, 142 | {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, 143 | {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, 144 | {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, 145 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, 146 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, 147 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, 148 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, 149 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, 150 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, 151 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, 152 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, 153 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, 154 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, 155 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, 156 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, 157 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, 158 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, 159 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, 160 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, 161 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, 162 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, 163 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, 164 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, 165 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, 166 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, 167 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, 168 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, 169 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, 170 | {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, 171 | {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, 172 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, 173 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, 174 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, 175 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, 176 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, 177 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, 178 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, 179 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, 180 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, 181 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, 182 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, 183 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, 184 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, 185 | {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, 186 | {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, 187 | {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, 188 | ] 189 | 190 | [[package]] 191 | name = "click" 192 | version = "8.1.3" 193 | description = "Composable command line interface toolkit" 194 | optional = false 195 | python-versions = ">=3.7" 196 | files = [ 197 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 198 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 199 | ] 200 | 201 | [package.dependencies] 202 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 203 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 204 | 205 | [[package]] 206 | name = "colorama" 207 | version = "0.4.6" 208 | description = "Cross-platform colored terminal text." 209 | optional = false 210 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 211 | files = [ 212 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 213 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 214 | ] 215 | 216 | [[package]] 217 | name = "configupdater" 218 | version = "3.1.1" 219 | description = "Parser like ConfigParser but for updating configuration files" 220 | optional = false 221 | python-versions = ">=3.6" 222 | files = [ 223 | {file = "ConfigUpdater-3.1.1-py2.py3-none-any.whl", hash = "sha256:805986dbeba317886c7a8d348b2e34986dc9e3128cd3761ecc35decbd372b286"}, 224 | {file = "ConfigUpdater-3.1.1.tar.gz", hash = "sha256:46f0c74d73efa723776764b43c9739f68052495dd3d734319c1d0eb58511f15b"}, 225 | ] 226 | 227 | [package.dependencies] 228 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 229 | 230 | [package.extras] 231 | testing = ["flake8", "pytest", "pytest-cov", "pytest-virtualenv", "pytest-xdist", "sphinx"] 232 | 233 | [[package]] 234 | name = "coverage" 235 | version = "7.2.7" 236 | description = "Code coverage measurement for Python" 237 | optional = false 238 | python-versions = ">=3.7" 239 | files = [ 240 | {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, 241 | {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, 242 | {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, 243 | {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, 244 | {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, 245 | {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, 246 | {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, 247 | {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, 248 | {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, 249 | {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, 250 | {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, 251 | {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, 252 | {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, 253 | {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, 254 | {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, 255 | {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, 256 | {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, 257 | {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, 258 | {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, 259 | {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, 260 | {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, 261 | {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, 262 | {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, 263 | {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, 264 | {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, 265 | {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, 266 | {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, 267 | {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, 268 | {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, 269 | {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, 270 | {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, 271 | {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, 272 | {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, 273 | {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, 274 | {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, 275 | {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, 276 | {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, 277 | {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, 278 | {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, 279 | {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, 280 | {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, 281 | {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, 282 | {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, 283 | {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, 284 | {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, 285 | {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, 286 | {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, 287 | {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, 288 | {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, 289 | {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, 290 | {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, 291 | {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, 292 | {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, 293 | {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, 294 | {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, 295 | {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, 296 | {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, 297 | {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, 298 | {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, 299 | {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, 300 | ] 301 | 302 | [package.dependencies] 303 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} 304 | 305 | [package.extras] 306 | toml = ["tomli"] 307 | 308 | [[package]] 309 | name = "darglint" 310 | version = "1.8.1" 311 | description = "A utility for ensuring Google-style docstrings stay up to date with the source code." 312 | optional = false 313 | python-versions = ">=3.6,<4.0" 314 | files = [ 315 | {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"}, 316 | {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"}, 317 | ] 318 | 319 | [[package]] 320 | name = "dictdiffer" 321 | version = "0.9.0" 322 | description = "Dictdiffer is a library that helps you to diff and patch dictionaries." 323 | optional = false 324 | python-versions = "*" 325 | files = [ 326 | {file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"}, 327 | {file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"}, 328 | ] 329 | 330 | [package.extras] 331 | all = ["Sphinx (>=3)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "tox (>=3.7.0)"] 332 | docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"] 333 | numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"] 334 | tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "tox (>=3.7.0)"] 335 | 336 | [[package]] 337 | name = "docutils" 338 | version = "0.20.1" 339 | description = "Docutils -- Python Documentation Utilities" 340 | optional = false 341 | python-versions = ">=3.7" 342 | files = [ 343 | {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, 344 | {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, 345 | ] 346 | 347 | [[package]] 348 | name = "dparse" 349 | version = "0.6.2" 350 | description = "A parser for Python dependency files" 351 | optional = false 352 | python-versions = ">=3.5" 353 | files = [ 354 | {file = "dparse-0.6.2-py3-none-any.whl", hash = "sha256:8097076f1dd26c377f30d4745e6ec18fef42f3bf493933b842ac5bafad8c345f"}, 355 | {file = "dparse-0.6.2.tar.gz", hash = "sha256:d45255bda21f998bc7ddf2afd5e62505ba6134756ba2d42a84c56b0826614dfe"}, 356 | ] 357 | 358 | [package.dependencies] 359 | packaging = "*" 360 | toml = "*" 361 | 362 | [package.extras] 363 | conda = ["pyyaml"] 364 | pipenv = ["pipenv"] 365 | 366 | [[package]] 367 | name = "dpath" 368 | version = "2.1.6" 369 | description = "Filesystem-like pathing and searching for dictionaries" 370 | optional = false 371 | python-versions = ">=3.7" 372 | files = [ 373 | {file = "dpath-2.1.6-py3-none-any.whl", hash = "sha256:31407395b177ab63ef72e2f6ae268c15e938f2990a8ecf6510f5686c02b6db73"}, 374 | {file = "dpath-2.1.6.tar.gz", hash = "sha256:f1e07c72e8605c6a9e80b64bc8f42714de08a789c7de417e49c3f87a19692e47"}, 375 | ] 376 | 377 | [[package]] 378 | name = "eradicate" 379 | version = "2.2.0" 380 | description = "Removes commented-out code." 381 | optional = false 382 | python-versions = "*" 383 | files = [ 384 | {file = "eradicate-2.2.0-py3-none-any.whl", hash = "sha256:751813c315a48ce7e3d0483410991015342d380a956e86e0265c61bfb875bcbc"}, 385 | {file = "eradicate-2.2.0.tar.gz", hash = "sha256:c329a05def6a4b558dab58bb1b694f5209706b7c99ba174d226dfdb69a5ba0da"}, 386 | ] 387 | 388 | [[package]] 389 | name = "exceptiongroup" 390 | version = "1.1.1" 391 | description = "Backport of PEP 654 (exception groups)" 392 | optional = false 393 | python-versions = ">=3.7" 394 | files = [ 395 | {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, 396 | {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, 397 | ] 398 | 399 | [package.extras] 400 | test = ["pytest (>=6)"] 401 | 402 | [[package]] 403 | name = "flake8" 404 | version = "4.0.1" 405 | description = "the modular source code checker: pep8 pyflakes and co" 406 | optional = false 407 | python-versions = ">=3.6" 408 | files = [ 409 | {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, 410 | {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, 411 | ] 412 | 413 | [package.dependencies] 414 | importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} 415 | mccabe = ">=0.6.0,<0.7.0" 416 | pycodestyle = ">=2.8.0,<2.9.0" 417 | pyflakes = ">=2.4.0,<2.5.0" 418 | 419 | [[package]] 420 | name = "flake8-bandit" 421 | version = "3.0.0" 422 | description = "Automated security testing with bandit and flake8." 423 | optional = false 424 | python-versions = ">=3.6" 425 | files = [ 426 | {file = "flake8_bandit-3.0.0-py2.py3-none-any.whl", hash = "sha256:61b617f4f7cdaa0e2b1e6bf7b68afb2b619a227bb3e3ae00dd36c213bd17900a"}, 427 | {file = "flake8_bandit-3.0.0.tar.gz", hash = "sha256:54d19427e6a8d50322a7b02e1841c0a7c22d856975f3459803320e0e18e2d6a1"}, 428 | ] 429 | 430 | [package.dependencies] 431 | bandit = ">=1.7.3" 432 | flake8 = "*" 433 | flake8-polyfill = "*" 434 | pycodestyle = "*" 435 | 436 | [[package]] 437 | name = "flake8-broken-line" 438 | version = "0.5.0" 439 | description = "Flake8 plugin to forbid backslashes for line breaks" 440 | optional = false 441 | python-versions = ">=3.6,<4.0" 442 | files = [ 443 | {file = "flake8-broken-line-0.5.0.tar.gz", hash = "sha256:7c98de9dd1385b71e888709c7f2aee3f0514107ecb5875bc95d0c03392191c97"}, 444 | {file = "flake8_broken_line-0.5.0-py3-none-any.whl", hash = "sha256:daafb19b67eead0410ce7ba155d51a15b9d020ebe7630d87de9c2b93cedb6703"}, 445 | ] 446 | 447 | [package.dependencies] 448 | flake8 = ">=3.5,<6" 449 | 450 | [[package]] 451 | name = "flake8-bugbear" 452 | version = "22.12.6" 453 | description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." 454 | optional = false 455 | python-versions = ">=3.7" 456 | files = [ 457 | {file = "flake8-bugbear-22.12.6.tar.gz", hash = "sha256:4cdb2c06e229971104443ae293e75e64c6107798229202fbe4f4091427a30ac0"}, 458 | {file = "flake8_bugbear-22.12.6-py3-none-any.whl", hash = "sha256:b69a510634f8a9c298dfda2b18a8036455e6b19ecac4fe582e4d7a0abfa50a30"}, 459 | ] 460 | 461 | [package.dependencies] 462 | attrs = ">=19.2.0" 463 | flake8 = ">=3.0.0" 464 | 465 | [package.extras] 466 | dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"] 467 | 468 | [[package]] 469 | name = "flake8-commas" 470 | version = "2.1.0" 471 | description = "Flake8 lint for trailing commas." 472 | optional = false 473 | python-versions = "*" 474 | files = [ 475 | {file = "flake8-commas-2.1.0.tar.gz", hash = "sha256:940441ab8ee544df564ae3b3f49f20462d75d5c7cac2463e0b27436e2050f263"}, 476 | {file = "flake8_commas-2.1.0-py2.py3-none-any.whl", hash = "sha256:ebb96c31e01d0ef1d0685a21f3f0e2f8153a0381430e748bf0bbbb5d5b453d54"}, 477 | ] 478 | 479 | [package.dependencies] 480 | flake8 = ">=2" 481 | 482 | [[package]] 483 | name = "flake8-comprehensions" 484 | version = "3.12.0" 485 | description = "A flake8 plugin to help you write better list/set/dict comprehensions." 486 | optional = false 487 | python-versions = ">=3.7" 488 | files = [ 489 | {file = "flake8_comprehensions-3.12.0-py3-none-any.whl", hash = "sha256:013234637ec7dfcb7cd2900578fb53c512f81db909cefe371c019232695c362d"}, 490 | {file = "flake8_comprehensions-3.12.0.tar.gz", hash = "sha256:419ef1a6e8de929203791a5e8ff5e3906caeba13eb3290eebdbf88a9078d502e"}, 491 | ] 492 | 493 | [package.dependencies] 494 | flake8 = ">=3.0,<3.2.0 || >3.2.0" 495 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 496 | 497 | [[package]] 498 | name = "flake8-debugger" 499 | version = "4.1.2" 500 | description = "ipdb/pdb statement checker plugin for flake8" 501 | optional = false 502 | python-versions = ">=3.7" 503 | files = [ 504 | {file = "flake8-debugger-4.1.2.tar.gz", hash = "sha256:52b002560941e36d9bf806fca2523dc7fb8560a295d5f1a6e15ac2ded7a73840"}, 505 | {file = "flake8_debugger-4.1.2-py3-none-any.whl", hash = "sha256:0a5e55aeddcc81da631ad9c8c366e7318998f83ff00985a49e6b3ecf61e571bf"}, 506 | ] 507 | 508 | [package.dependencies] 509 | flake8 = ">=3.0" 510 | pycodestyle = "*" 511 | 512 | [[package]] 513 | name = "flake8-docstrings" 514 | version = "1.7.0" 515 | description = "Extension for flake8 which uses pydocstyle to check docstrings" 516 | optional = false 517 | python-versions = ">=3.7" 518 | files = [ 519 | {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, 520 | {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, 521 | ] 522 | 523 | [package.dependencies] 524 | flake8 = ">=3" 525 | pydocstyle = ">=2.1" 526 | 527 | [[package]] 528 | name = "flake8-eradicate" 529 | version = "1.4.0" 530 | description = "Flake8 plugin to find commented out code" 531 | optional = false 532 | python-versions = ">=3.7,<4.0" 533 | files = [ 534 | {file = "flake8-eradicate-1.4.0.tar.gz", hash = "sha256:3088cfd6717d1c9c6c3ac45ef2e5f5b6c7267f7504d5a74b781500e95cb9c7e1"}, 535 | {file = "flake8_eradicate-1.4.0-py3-none-any.whl", hash = "sha256:e3bbd0871be358e908053c1ab728903c114f062ba596b4d40c852fd18f473d56"}, 536 | ] 537 | 538 | [package.dependencies] 539 | attrs = "*" 540 | eradicate = ">=2.0,<3.0" 541 | flake8 = ">=3.5,<6" 542 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 543 | 544 | [[package]] 545 | name = "flake8-isort" 546 | version = "4.2.0" 547 | description = "flake8 plugin that integrates isort ." 548 | optional = false 549 | python-versions = "*" 550 | files = [ 551 | {file = "flake8-isort-4.2.0.tar.gz", hash = "sha256:26571500cd54976bbc0cf1006ffbcd1a68dd102f816b7a1051b219616ba9fee0"}, 552 | {file = "flake8_isort-4.2.0-py3-none-any.whl", hash = "sha256:5b87630fb3719bf4c1833fd11e0d9534f43efdeba524863e15d8f14a7ef6adbf"}, 553 | ] 554 | 555 | [package.dependencies] 556 | flake8 = ">=3.2.1,<6" 557 | isort = ">=4.3.5,<6" 558 | 559 | [package.extras] 560 | test = ["pytest-cov"] 561 | 562 | [[package]] 563 | name = "flake8-plugin-utils" 564 | version = "1.3.2" 565 | description = "The package provides base classes and utils for flake8 plugin writing" 566 | optional = false 567 | python-versions = ">=3.6,<4.0" 568 | files = [ 569 | {file = "flake8-plugin-utils-1.3.2.tar.gz", hash = "sha256:20fa2a8ca2decac50116edb42e6af0a1253ef639ad79941249b840531889c65a"}, 570 | {file = "flake8_plugin_utils-1.3.2-py3-none-any.whl", hash = "sha256:1fe43e3e9acf3a7c0f6b88f5338cad37044d2f156c43cb6b080b5f9da8a76f06"}, 571 | ] 572 | 573 | [[package]] 574 | name = "flake8-polyfill" 575 | version = "1.0.2" 576 | description = "Polyfill package for Flake8 plugins" 577 | optional = false 578 | python-versions = "*" 579 | files = [ 580 | {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, 581 | {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, 582 | ] 583 | 584 | [package.dependencies] 585 | flake8 = "*" 586 | 587 | [[package]] 588 | name = "flake8-pytest-style" 589 | version = "1.6.0" 590 | description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests." 591 | optional = false 592 | python-versions = ">=3.6.2,<4.0.0" 593 | files = [ 594 | {file = "flake8-pytest-style-1.6.0.tar.gz", hash = "sha256:c1175713e9e11b78cd1a035ed0bca0d1e41d09c4af329a952750b61d4194ddac"}, 595 | {file = "flake8_pytest_style-1.6.0-py3-none-any.whl", hash = "sha256:5fedb371a950e9fe0e0e6bfc854be7d99151271208f34cd2cc517681ece27780"}, 596 | ] 597 | 598 | [package.dependencies] 599 | flake8-plugin-utils = ">=1.3.2,<2.0.0" 600 | 601 | [[package]] 602 | name = "flake8-quotes" 603 | version = "3.3.2" 604 | description = "Flake8 lint for quotes." 605 | optional = false 606 | python-versions = "*" 607 | files = [ 608 | {file = "flake8-quotes-3.3.2.tar.gz", hash = "sha256:6e26892b632dacba517bf27219c459a8396dcfac0f5e8204904c5a4ba9b480e1"}, 609 | ] 610 | 611 | [package.dependencies] 612 | flake8 = "*" 613 | 614 | [[package]] 615 | name = "flake8-rst-docstrings" 616 | version = "0.2.7" 617 | description = "Python docstring reStructuredText (RST) validator" 618 | optional = false 619 | python-versions = ">=3.7" 620 | files = [ 621 | {file = "flake8-rst-docstrings-0.2.7.tar.gz", hash = "sha256:2740067ab9237559dd45a3434d8c987792c7b259ca563621a3b95efe201f5382"}, 622 | {file = "flake8_rst_docstrings-0.2.7-py3-none-any.whl", hash = "sha256:5d56075dce360bcc9c6775bfe7cb431aa395de600ca7e8d40580a28d50b2a803"}, 623 | ] 624 | 625 | [package.dependencies] 626 | flake8 = ">=3.0.0" 627 | pygments = "*" 628 | restructuredtext-lint = "*" 629 | 630 | [[package]] 631 | name = "flake8-string-format" 632 | version = "0.3.0" 633 | description = "string format checker, plugin for flake8" 634 | optional = false 635 | python-versions = "*" 636 | files = [ 637 | {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"}, 638 | {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"}, 639 | ] 640 | 641 | [package.dependencies] 642 | flake8 = "*" 643 | 644 | [[package]] 645 | name = "flatten-dict" 646 | version = "0.4.2" 647 | description = "A flexible utility for flattening and unflattening dict-like objects in Python." 648 | optional = false 649 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 650 | files = [ 651 | {file = "flatten-dict-0.4.2.tar.gz", hash = "sha256:506a96b6e6f805b81ae46a0f9f31290beb5fa79ded9d80dbe1b7fa236ab43076"}, 652 | {file = "flatten_dict-0.4.2-py2.py3-none-any.whl", hash = "sha256:7e245b20c4c718981212210eec4284a330c9f713e632e98765560e05421e48ad"}, 653 | ] 654 | 655 | [package.dependencies] 656 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 657 | six = ">=1.12,<2.0" 658 | 659 | [[package]] 660 | name = "furl" 661 | version = "2.1.3" 662 | description = "URL manipulation made simple." 663 | optional = false 664 | python-versions = "*" 665 | files = [ 666 | {file = "furl-2.1.3-py2.py3-none-any.whl", hash = "sha256:9ab425062c4217f9802508e45feb4a83e54324273ac4b202f1850363309666c0"}, 667 | {file = "furl-2.1.3.tar.gz", hash = "sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e"}, 668 | ] 669 | 670 | [package.dependencies] 671 | orderedmultidict = ">=1.0.1" 672 | six = ">=1.8.0" 673 | 674 | [[package]] 675 | name = "gitdb" 676 | version = "4.0.10" 677 | description = "Git Object Database" 678 | optional = false 679 | python-versions = ">=3.7" 680 | files = [ 681 | {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, 682 | {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, 683 | ] 684 | 685 | [package.dependencies] 686 | smmap = ">=3.0.1,<6" 687 | 688 | [[package]] 689 | name = "gitpython" 690 | version = "3.1.31" 691 | description = "GitPython is a Python library used to interact with Git repositories" 692 | optional = false 693 | python-versions = ">=3.7" 694 | files = [ 695 | {file = "GitPython-3.1.31-py3-none-any.whl", hash = "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d"}, 696 | {file = "GitPython-3.1.31.tar.gz", hash = "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573"}, 697 | ] 698 | 699 | [package.dependencies] 700 | gitdb = ">=4.0.1,<5" 701 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} 702 | 703 | [[package]] 704 | name = "identify" 705 | version = "2.5.24" 706 | description = "File identification library for Python" 707 | optional = false 708 | python-versions = ">=3.7" 709 | files = [ 710 | {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, 711 | {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, 712 | ] 713 | 714 | [package.extras] 715 | license = ["ukkonen"] 716 | 717 | [[package]] 718 | name = "idna" 719 | version = "3.4" 720 | description = "Internationalized Domain Names in Applications (IDNA)" 721 | optional = false 722 | python-versions = ">=3.5" 723 | files = [ 724 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 725 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 726 | ] 727 | 728 | [[package]] 729 | name = "importlib-metadata" 730 | version = "4.2.0" 731 | description = "Read metadata from Python packages" 732 | optional = false 733 | python-versions = ">=3.6" 734 | files = [ 735 | {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, 736 | {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, 737 | ] 738 | 739 | [package.dependencies] 740 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 741 | zipp = ">=0.5" 742 | 743 | [package.extras] 744 | docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] 745 | testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] 746 | 747 | [[package]] 748 | name = "importlib-resources" 749 | version = "5.12.0" 750 | description = "Read resources from Python packages" 751 | optional = false 752 | python-versions = ">=3.7" 753 | files = [ 754 | {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, 755 | {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, 756 | ] 757 | 758 | [package.dependencies] 759 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} 760 | 761 | [package.extras] 762 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 763 | testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 764 | 765 | [[package]] 766 | name = "iniconfig" 767 | version = "2.0.0" 768 | description = "brain-dead simple config-ini parsing" 769 | optional = false 770 | python-versions = ">=3.7" 771 | files = [ 772 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 773 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 774 | ] 775 | 776 | [[package]] 777 | name = "isort" 778 | version = "5.11.5" 779 | description = "A Python utility / library to sort Python imports." 780 | optional = false 781 | python-versions = ">=3.7.0" 782 | files = [ 783 | {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, 784 | {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, 785 | ] 786 | 787 | [package.extras] 788 | colors = ["colorama (>=0.4.3,<0.5.0)"] 789 | pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] 790 | plugins = ["setuptools"] 791 | requirements-deprecated-finder = ["pip-api", "pipreqs"] 792 | 793 | [[package]] 794 | name = "jmespath" 795 | version = "1.0.1" 796 | description = "JSON Matching Expressions" 797 | optional = false 798 | python-versions = ">=3.7" 799 | files = [ 800 | {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, 801 | {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, 802 | ] 803 | 804 | [[package]] 805 | name = "loguru" 806 | version = "0.7.0" 807 | description = "Python logging made (stupidly) simple" 808 | optional = false 809 | python-versions = ">=3.5" 810 | files = [ 811 | {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, 812 | {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, 813 | ] 814 | 815 | [package.dependencies] 816 | colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} 817 | win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} 818 | 819 | [package.extras] 820 | dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] 821 | 822 | [[package]] 823 | name = "markdown-it-py" 824 | version = "2.2.0" 825 | description = "Python port of markdown-it. Markdown parsing, done right!" 826 | optional = false 827 | python-versions = ">=3.7" 828 | files = [ 829 | {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, 830 | {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, 831 | ] 832 | 833 | [package.dependencies] 834 | mdurl = ">=0.1,<1.0" 835 | typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} 836 | 837 | [package.extras] 838 | benchmarking = ["psutil", "pytest", "pytest-benchmark"] 839 | code-style = ["pre-commit (>=3.0,<4.0)"] 840 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] 841 | linkify = ["linkify-it-py (>=1,<3)"] 842 | plugins = ["mdit-py-plugins"] 843 | profiling = ["gprof2dot"] 844 | rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] 845 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] 846 | 847 | [[package]] 848 | name = "marshmallow" 849 | version = "3.19.0" 850 | description = "A lightweight library for converting complex datatypes to and from native Python datatypes." 851 | optional = false 852 | python-versions = ">=3.7" 853 | files = [ 854 | {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"}, 855 | {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"}, 856 | ] 857 | 858 | [package.dependencies] 859 | packaging = ">=17.0" 860 | 861 | [package.extras] 862 | dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] 863 | docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] 864 | lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"] 865 | tests = ["pytest", "pytz", "simplejson"] 866 | 867 | [[package]] 868 | name = "marshmallow-polyfield" 869 | version = "5.11" 870 | description = "An unofficial extension to Marshmallow to allow for polymorphic fields" 871 | optional = false 872 | python-versions = ">=3.5" 873 | files = [ 874 | {file = "marshmallow-polyfield-5.11.tar.gz", hash = "sha256:8075a9cc490da4af58b902b4a40a99882dd031adb7aaa96abd147a4fcd53415f"}, 875 | ] 876 | 877 | [package.dependencies] 878 | marshmallow = ">=3.0.0b10" 879 | 880 | [[package]] 881 | name = "mccabe" 882 | version = "0.6.1" 883 | description = "McCabe checker, plugin for flake8" 884 | optional = false 885 | python-versions = "*" 886 | files = [ 887 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 888 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 889 | ] 890 | 891 | [[package]] 892 | name = "mdurl" 893 | version = "0.1.2" 894 | description = "Markdown URL utilities" 895 | optional = false 896 | python-versions = ">=3.7" 897 | files = [ 898 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 899 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 900 | ] 901 | 902 | [[package]] 903 | name = "more-itertools" 904 | version = "9.1.0" 905 | description = "More routines for operating on iterables, beyond itertools" 906 | optional = false 907 | python-versions = ">=3.7" 908 | files = [ 909 | {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"}, 910 | {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, 911 | ] 912 | 913 | [[package]] 914 | name = "mypy" 915 | version = "1.3.0" 916 | description = "Optional static typing for Python" 917 | optional = false 918 | python-versions = ">=3.7" 919 | files = [ 920 | {file = "mypy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eb485cea53f4f5284e5baf92902cd0088b24984f4209e25981cc359d64448d"}, 921 | {file = "mypy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c99c3ecf223cf2952638da9cd82793d8f3c0c5fa8b6ae2b2d9ed1e1ff51ba85"}, 922 | {file = "mypy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:550a8b3a19bb6589679a7c3c31f64312e7ff482a816c96e0cecec9ad3a7564dd"}, 923 | {file = "mypy-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cbc07246253b9e3d7d74c9ff948cd0fd7a71afcc2b77c7f0a59c26e9395cb152"}, 924 | {file = "mypy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:a22435632710a4fcf8acf86cbd0d69f68ac389a3892cb23fbad176d1cddaf228"}, 925 | {file = "mypy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e33bb8b2613614a33dff70565f4c803f889ebd2f859466e42b46e1df76018dd"}, 926 | {file = "mypy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d23370d2a6b7a71dc65d1266f9a34e4cde9e8e21511322415db4b26f46f6b8c"}, 927 | {file = "mypy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:658fe7b674769a0770d4b26cb4d6f005e88a442fe82446f020be8e5f5efb2fae"}, 928 | {file = "mypy-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d29e324cdda61daaec2336c42512e59c7c375340bd202efa1fe0f7b8f8ca"}, 929 | {file = "mypy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:d0b6c62206e04061e27009481cb0ec966f7d6172b5b936f3ead3d74f29fe3dcf"}, 930 | {file = "mypy-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:76ec771e2342f1b558c36d49900dfe81d140361dd0d2df6cd71b3db1be155409"}, 931 | {file = "mypy-1.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc95f8386314272bbc817026f8ce8f4f0d2ef7ae44f947c4664efac9adec929"}, 932 | {file = "mypy-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:faff86aa10c1aa4a10e1a301de160f3d8fc8703b88c7e98de46b531ff1276a9a"}, 933 | {file = "mypy-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8c5979d0deb27e0f4479bee18ea0f83732a893e81b78e62e2dda3e7e518c92ee"}, 934 | {file = "mypy-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c5d2cc54175bab47011b09688b418db71403aefad07cbcd62d44010543fc143f"}, 935 | {file = "mypy-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87df44954c31d86df96c8bd6e80dfcd773473e877ac6176a8e29898bfb3501cb"}, 936 | {file = "mypy-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:473117e310febe632ddf10e745a355714e771ffe534f06db40702775056614c4"}, 937 | {file = "mypy-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:74bc9b6e0e79808bf8678d7678b2ae3736ea72d56eede3820bd3849823e7f305"}, 938 | {file = "mypy-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:44797d031a41516fcf5cbfa652265bb994e53e51994c1bd649ffcd0c3a7eccbf"}, 939 | {file = "mypy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ddae0f39ca146972ff6bb4399f3b2943884a774b8771ea0a8f50e971f5ea5ba8"}, 940 | {file = "mypy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c4c42c60a8103ead4c1c060ac3cdd3ff01e18fddce6f1016e08939647a0e703"}, 941 | {file = "mypy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e86c2c6852f62f8f2b24cb7a613ebe8e0c7dc1402c61d36a609174f63e0ff017"}, 942 | {file = "mypy-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f9dca1e257d4cc129517779226753dbefb4f2266c4eaad610fc15c6a7e14283e"}, 943 | {file = "mypy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:95d8d31a7713510685b05fbb18d6ac287a56c8f6554d88c19e73f724a445448a"}, 944 | {file = "mypy-1.3.0-py3-none-any.whl", hash = "sha256:a8763e72d5d9574d45ce5881962bc8e9046bf7b375b0abf031f3e6811732a897"}, 945 | {file = "mypy-1.3.0.tar.gz", hash = "sha256:e1f4d16e296f5135624b34e8fb741eb0eadedca90862405b1f1fde2040b9bd11"}, 946 | ] 947 | 948 | [package.dependencies] 949 | mypy-extensions = ">=1.0.0" 950 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 951 | typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} 952 | typing-extensions = ">=3.10" 953 | 954 | [package.extras] 955 | dmypy = ["psutil (>=4.0)"] 956 | install-types = ["pip"] 957 | python2 = ["typed-ast (>=1.4.0,<2)"] 958 | reports = ["lxml"] 959 | 960 | [[package]] 961 | name = "mypy-extensions" 962 | version = "1.0.0" 963 | description = "Type system extensions for programs checked with the mypy type checker." 964 | optional = false 965 | python-versions = ">=3.5" 966 | files = [ 967 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 968 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 969 | ] 970 | 971 | [[package]] 972 | name = "nitpick" 973 | version = "0.33.2" 974 | description = "Enforce the same settings across multiple language-independent projects" 975 | optional = false 976 | python-versions = ">=3.7,<4.0" 977 | files = [ 978 | {file = "nitpick-0.33.2-py3-none-any.whl", hash = "sha256:8b77d5968c36384c7a4cc957dc45c22bb8024e8cab83fb58fa7fbef45d3aae98"}, 979 | {file = "nitpick-0.33.2.tar.gz", hash = "sha256:e0f9f96128f390f95409a3d27fa922484e900ac8b974646b50ea4b8a3458cad7"}, 980 | ] 981 | 982 | [package.dependencies] 983 | attrs = ">=20.1.0" 984 | autorepr = "*" 985 | click = "*" 986 | ConfigUpdater = "*" 987 | dictdiffer = "*" 988 | dpath = "*" 989 | flake8 = ">=3.0.0" 990 | flatten-dict = "*" 991 | furl = "*" 992 | identify = "*" 993 | importlib-metadata = {version = "<5.0", markers = "python_version < \"3.8\""} 994 | importlib-resources = {version = "*", markers = "python_version >= \"3.7\" and python_version < \"3.9\""} 995 | jmespath = "*" 996 | loguru = "*" 997 | marshmallow = ">=3.0.0b10" 998 | marshmallow-polyfield = ">=5.10,<6.0" 999 | more-itertools = "*" 1000 | pluggy = "*" 1001 | python-slugify = "*" 1002 | requests = "*" 1003 | requests-cache = ">=1.0.0" 1004 | "ruamel.yaml" = "*" 1005 | sortedcontainers = "*" 1006 | StrEnum = "*" 1007 | toml = "*" 1008 | tomlkit = ">=0.8.0" 1009 | 1010 | [package.extras] 1011 | doc = ["sphinx", "sphinx-gitref", "sphinx_rtd_theme", "sphobjinv"] 1012 | lint = ["pylint"] 1013 | test = ["freezegun", "pytest", "pytest-cov", "pytest-datadir", "pytest-socket", "pytest-testmon", "pytest-watch", "responses", "testfixtures"] 1014 | 1015 | [[package]] 1016 | name = "orderedmultidict" 1017 | version = "1.0.1" 1018 | description = "Ordered Multivalue Dictionary" 1019 | optional = false 1020 | python-versions = "*" 1021 | files = [ 1022 | {file = "orderedmultidict-1.0.1-py2.py3-none-any.whl", hash = "sha256:43c839a17ee3cdd62234c47deca1a8508a3f2ca1d0678a3bf791c87cf84adbf3"}, 1023 | {file = "orderedmultidict-1.0.1.tar.gz", hash = "sha256:04070bbb5e87291cc9bfa51df413677faf2141c73c61d2a5f7b26bea3cd882ad"}, 1024 | ] 1025 | 1026 | [package.dependencies] 1027 | six = ">=1.8.0" 1028 | 1029 | [[package]] 1030 | name = "packaging" 1031 | version = "21.3" 1032 | description = "Core utilities for Python packages" 1033 | optional = false 1034 | python-versions = ">=3.6" 1035 | files = [ 1036 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 1037 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 1038 | ] 1039 | 1040 | [package.dependencies] 1041 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 1042 | 1043 | [[package]] 1044 | name = "pbr" 1045 | version = "5.11.1" 1046 | description = "Python Build Reasonableness" 1047 | optional = false 1048 | python-versions = ">=2.6" 1049 | files = [ 1050 | {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, 1051 | {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "pep8-naming" 1056 | version = "0.13.2" 1057 | description = "Check PEP-8 naming conventions, plugin for flake8" 1058 | optional = false 1059 | python-versions = ">=3.7" 1060 | files = [ 1061 | {file = "pep8-naming-0.13.2.tar.gz", hash = "sha256:93eef62f525fd12a6f8c98f4dcc17fa70baae2f37fa1f73bec00e3e44392fa48"}, 1062 | {file = "pep8_naming-0.13.2-py3-none-any.whl", hash = "sha256:59e29e55c478db69cffbe14ab24b5bd2cd615c0413edf790d47d3fb7ba9a4e23"}, 1063 | ] 1064 | 1065 | [package.dependencies] 1066 | flake8 = ">=3.9.1" 1067 | 1068 | [[package]] 1069 | name = "platformdirs" 1070 | version = "3.5.1" 1071 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 1072 | optional = false 1073 | python-versions = ">=3.7" 1074 | files = [ 1075 | {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, 1076 | {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, 1077 | ] 1078 | 1079 | [package.dependencies] 1080 | typing-extensions = {version = ">=4.5", markers = "python_version < \"3.8\""} 1081 | 1082 | [package.extras] 1083 | docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] 1084 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] 1085 | 1086 | [[package]] 1087 | name = "pluggy" 1088 | version = "1.0.0" 1089 | description = "plugin and hook calling mechanisms for python" 1090 | optional = false 1091 | python-versions = ">=3.6" 1092 | files = [ 1093 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 1094 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 1095 | ] 1096 | 1097 | [package.dependencies] 1098 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 1099 | 1100 | [package.extras] 1101 | dev = ["pre-commit", "tox"] 1102 | testing = ["pytest", "pytest-benchmark"] 1103 | 1104 | [[package]] 1105 | name = "pycodestyle" 1106 | version = "2.8.0" 1107 | description = "Python style guide checker" 1108 | optional = false 1109 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 1110 | files = [ 1111 | {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, 1112 | {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "pydocstyle" 1117 | version = "6.3.0" 1118 | description = "Python docstring style checker" 1119 | optional = false 1120 | python-versions = ">=3.6" 1121 | files = [ 1122 | {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, 1123 | {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, 1124 | ] 1125 | 1126 | [package.dependencies] 1127 | importlib-metadata = {version = ">=2.0.0,<5.0.0", markers = "python_version < \"3.8\""} 1128 | snowballstemmer = ">=2.2.0" 1129 | 1130 | [package.extras] 1131 | toml = ["tomli (>=1.2.3)"] 1132 | 1133 | [[package]] 1134 | name = "pyflakes" 1135 | version = "2.4.0" 1136 | description = "passive checker of Python programs" 1137 | optional = false 1138 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 1139 | files = [ 1140 | {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, 1141 | {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "pygments" 1146 | version = "2.15.1" 1147 | description = "Pygments is a syntax highlighting package written in Python." 1148 | optional = false 1149 | python-versions = ">=3.7" 1150 | files = [ 1151 | {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, 1152 | {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, 1153 | ] 1154 | 1155 | [package.extras] 1156 | plugins = ["importlib-metadata"] 1157 | 1158 | [[package]] 1159 | name = "pyparsing" 1160 | version = "3.0.9" 1161 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 1162 | optional = false 1163 | python-versions = ">=3.6.8" 1164 | files = [ 1165 | {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, 1166 | {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, 1167 | ] 1168 | 1169 | [package.extras] 1170 | diagrams = ["jinja2", "railroad-diagrams"] 1171 | 1172 | [[package]] 1173 | name = "pytest" 1174 | version = "7.3.1" 1175 | description = "pytest: simple powerful testing with Python" 1176 | optional = false 1177 | python-versions = ">=3.7" 1178 | files = [ 1179 | {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, 1180 | {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, 1181 | ] 1182 | 1183 | [package.dependencies] 1184 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 1185 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 1186 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 1187 | iniconfig = "*" 1188 | packaging = "*" 1189 | pluggy = ">=0.12,<2.0" 1190 | tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} 1191 | 1192 | [package.extras] 1193 | testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 1194 | 1195 | [[package]] 1196 | name = "pytest-cov" 1197 | version = "3.0.0" 1198 | description = "Pytest plugin for measuring coverage." 1199 | optional = false 1200 | python-versions = ">=3.6" 1201 | files = [ 1202 | {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, 1203 | {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, 1204 | ] 1205 | 1206 | [package.dependencies] 1207 | coverage = {version = ">=5.2.1", extras = ["toml"]} 1208 | pytest = ">=4.6" 1209 | 1210 | [package.extras] 1211 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] 1212 | 1213 | [[package]] 1214 | name = "pytest-randomly" 1215 | version = "3.12.0" 1216 | description = "Pytest plugin to randomly order tests and control random.seed." 1217 | optional = false 1218 | python-versions = ">=3.7" 1219 | files = [ 1220 | {file = "pytest-randomly-3.12.0.tar.gz", hash = "sha256:d60c2db71ac319aee0fc6c4110a7597d611a8b94a5590918bfa8583f00caccb2"}, 1221 | {file = "pytest_randomly-3.12.0-py3-none-any.whl", hash = "sha256:f4f2e803daf5d1ba036cc22bf4fe9dbbf99389ec56b00e5cba732fb5c1d07fdd"}, 1222 | ] 1223 | 1224 | [package.dependencies] 1225 | importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} 1226 | pytest = "*" 1227 | 1228 | [[package]] 1229 | name = "python-slugify" 1230 | version = "8.0.1" 1231 | description = "A Python slugify application that also handles Unicode" 1232 | optional = false 1233 | python-versions = ">=3.7" 1234 | files = [ 1235 | {file = "python-slugify-8.0.1.tar.gz", hash = "sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27"}, 1236 | {file = "python_slugify-8.0.1-py2.py3-none-any.whl", hash = "sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395"}, 1237 | ] 1238 | 1239 | [package.dependencies] 1240 | text-unidecode = ">=1.3" 1241 | 1242 | [package.extras] 1243 | unidecode = ["Unidecode (>=1.1.1)"] 1244 | 1245 | [[package]] 1246 | name = "pyyaml" 1247 | version = "6.0" 1248 | description = "YAML parser and emitter for Python" 1249 | optional = false 1250 | python-versions = ">=3.6" 1251 | files = [ 1252 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, 1253 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, 1254 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, 1255 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, 1256 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, 1257 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, 1258 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, 1259 | {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, 1260 | {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, 1261 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, 1262 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, 1263 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, 1264 | {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, 1265 | {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, 1266 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, 1267 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, 1268 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, 1269 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, 1270 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, 1271 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, 1272 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, 1273 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, 1274 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, 1275 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, 1276 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, 1277 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, 1278 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, 1279 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, 1280 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, 1281 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, 1282 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, 1283 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, 1284 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, 1285 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, 1286 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, 1287 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, 1288 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, 1289 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, 1290 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, 1291 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "requests" 1296 | version = "2.31.0" 1297 | description = "Python HTTP for Humans." 1298 | optional = false 1299 | python-versions = ">=3.7" 1300 | files = [ 1301 | {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, 1302 | {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, 1303 | ] 1304 | 1305 | [package.dependencies] 1306 | certifi = ">=2017.4.17" 1307 | charset-normalizer = ">=2,<4" 1308 | idna = ">=2.5,<4" 1309 | urllib3 = ">=1.21.1,<3" 1310 | 1311 | [package.extras] 1312 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 1313 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 1314 | 1315 | [[package]] 1316 | name = "requests-cache" 1317 | version = "1.0.1" 1318 | description = "A persistent cache for python requests" 1319 | optional = false 1320 | python-versions = ">=3.7,<4.0" 1321 | files = [ 1322 | {file = "requests_cache-1.0.1-py3-none-any.whl", hash = "sha256:55c5765c26fd98a38c633d6e3931a507b7708cdd07c0afb48773d0718ac15969"}, 1323 | {file = "requests_cache-1.0.1.tar.gz", hash = "sha256:d42e6c2f11de54e6a134c9a00c5ca2a3c8edde3c3f2bdfd942586fafa8990e14"}, 1324 | ] 1325 | 1326 | [package.dependencies] 1327 | attrs = ">=21.2" 1328 | cattrs = ">=22.2" 1329 | platformdirs = ">=2.5" 1330 | requests = ">=2.22" 1331 | url-normalize = ">=1.4" 1332 | urllib3 = ">=1.25.5" 1333 | 1334 | [package.extras] 1335 | all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=5.4)", "redis (>=3)", "ujson (>=5.4)"] 1336 | bson = ["bson (>=0.5)"] 1337 | docs = ["furo (>=2022.12.7,<2023.0.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.6)"] 1338 | dynamodb = ["boto3 (>=1.15)", "botocore (>=1.18)"] 1339 | json = ["ujson (>=5.4)"] 1340 | mongodb = ["pymongo (>=3)"] 1341 | redis = ["redis (>=3)"] 1342 | security = ["itsdangerous (>=2.0)"] 1343 | yaml = ["pyyaml (>=5.4)"] 1344 | 1345 | [[package]] 1346 | name = "restructuredtext-lint" 1347 | version = "1.4.0" 1348 | description = "reStructuredText linter" 1349 | optional = false 1350 | python-versions = "*" 1351 | files = [ 1352 | {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, 1353 | ] 1354 | 1355 | [package.dependencies] 1356 | docutils = ">=0.11,<1.0" 1357 | 1358 | [[package]] 1359 | name = "rich" 1360 | version = "13.4.1" 1361 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 1362 | optional = false 1363 | python-versions = ">=3.7.0" 1364 | files = [ 1365 | {file = "rich-13.4.1-py3-none-any.whl", hash = "sha256:d204aadb50b936bf6b1a695385429d192bc1fdaf3e8b907e8e26f4c4e4b5bf75"}, 1366 | {file = "rich-13.4.1.tar.gz", hash = "sha256:76f6b65ea7e5c5d924ba80e322231d7cb5b5981aa60bfc1e694f1bc097fe6fe1"}, 1367 | ] 1368 | 1369 | [package.dependencies] 1370 | markdown-it-py = ">=2.2.0,<3.0.0" 1371 | pygments = ">=2.13.0,<3.0.0" 1372 | typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} 1373 | 1374 | [package.extras] 1375 | jupyter = ["ipywidgets (>=7.5.1,<9)"] 1376 | 1377 | [[package]] 1378 | name = "ruamel-yaml" 1379 | version = "0.17.31" 1380 | description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" 1381 | optional = false 1382 | python-versions = ">=3" 1383 | files = [ 1384 | {file = "ruamel.yaml-0.17.31-py3-none-any.whl", hash = "sha256:3cf153f0047ced526e723097ac615d3009371779432e304dbd5596b6f3a4c777"}, 1385 | {file = "ruamel.yaml-0.17.31.tar.gz", hash = "sha256:098ed1eb6d338a684891a72380277c1e6fc4d4ae0e120de9a447275056dda335"}, 1386 | ] 1387 | 1388 | [package.dependencies] 1389 | "ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""} 1390 | 1391 | [package.extras] 1392 | docs = ["ryd"] 1393 | jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] 1394 | 1395 | [[package]] 1396 | name = "ruamel-yaml-clib" 1397 | version = "0.2.7" 1398 | description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" 1399 | optional = false 1400 | python-versions = ">=3.5" 1401 | files = [ 1402 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"}, 1403 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"}, 1404 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"}, 1405 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"}, 1406 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, 1407 | {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, 1408 | {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, 1409 | {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, 1410 | {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, 1411 | {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"}, 1412 | {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"}, 1413 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, 1414 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, 1415 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, 1416 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"}, 1417 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"}, 1418 | {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"}, 1419 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"}, 1420 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"}, 1421 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"}, 1422 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"}, 1423 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"}, 1424 | {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"}, 1425 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"}, 1426 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"}, 1427 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"}, 1428 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"}, 1429 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"}, 1430 | {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"}, 1431 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"}, 1432 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"}, 1433 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"}, 1434 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"}, 1435 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"}, 1436 | {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"}, 1437 | {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"}, 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "safety" 1442 | version = "2.3.5" 1443 | description = "Checks installed dependencies for known vulnerabilities and licenses." 1444 | optional = false 1445 | python-versions = "*" 1446 | files = [ 1447 | {file = "safety-2.3.5-py3-none-any.whl", hash = "sha256:2227fcac1b22b53c1615af78872b48348661691450aa25d6704a5504dbd1f7e2"}, 1448 | {file = "safety-2.3.5.tar.gz", hash = "sha256:a60c11f8952f412cbb165d70cb1f673a3b43a2ba9a93ce11f97e6a4de834aa3a"}, 1449 | ] 1450 | 1451 | [package.dependencies] 1452 | Click = ">=8.0.2" 1453 | dparse = ">=0.6.2" 1454 | packaging = ">=21.0,<22.0" 1455 | requests = "*" 1456 | "ruamel.yaml" = ">=0.17.21" 1457 | setuptools = ">=19.3" 1458 | 1459 | [package.extras] 1460 | github = ["jinja2 (>=3.1.0)", "pygithub (>=1.43.3)"] 1461 | gitlab = ["python-gitlab (>=1.3.0)"] 1462 | 1463 | [[package]] 1464 | name = "setuptools" 1465 | version = "67.8.0" 1466 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 1467 | optional = false 1468 | python-versions = ">=3.7" 1469 | files = [ 1470 | {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, 1471 | {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, 1472 | ] 1473 | 1474 | [package.extras] 1475 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] 1476 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] 1477 | testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] 1478 | 1479 | [[package]] 1480 | name = "six" 1481 | version = "1.16.0" 1482 | description = "Python 2 and 3 compatibility utilities" 1483 | optional = false 1484 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 1485 | files = [ 1486 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1487 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1488 | ] 1489 | 1490 | [[package]] 1491 | name = "smmap" 1492 | version = "5.0.0" 1493 | description = "A pure Python implementation of a sliding window memory map manager" 1494 | optional = false 1495 | python-versions = ">=3.6" 1496 | files = [ 1497 | {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, 1498 | {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "snowballstemmer" 1503 | version = "2.2.0" 1504 | description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." 1505 | optional = false 1506 | python-versions = "*" 1507 | files = [ 1508 | {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, 1509 | {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "sortedcontainers" 1514 | version = "2.4.0" 1515 | description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" 1516 | optional = false 1517 | python-versions = "*" 1518 | files = [ 1519 | {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, 1520 | {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, 1521 | ] 1522 | 1523 | [[package]] 1524 | name = "stevedore" 1525 | version = "3.5.2" 1526 | description = "Manage dynamic plugins for Python applications" 1527 | optional = false 1528 | python-versions = ">=3.6" 1529 | files = [ 1530 | {file = "stevedore-3.5.2-py3-none-any.whl", hash = "sha256:fa2630e3d0ad3e22d4914aff2501445815b9a4467a6edc49387c667a38faf5bf"}, 1531 | {file = "stevedore-3.5.2.tar.gz", hash = "sha256:cf99f41fc0d5a4f185ca4d3d42b03be9011b0a1ec1a4ea1a282be1b4b306dcc2"}, 1532 | ] 1533 | 1534 | [package.dependencies] 1535 | importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""} 1536 | pbr = ">=2.0.0,<2.1.0 || >2.1.0" 1537 | 1538 | [[package]] 1539 | name = "strenum" 1540 | version = "0.4.10" 1541 | description = "An Enum that inherits from str." 1542 | optional = false 1543 | python-versions = "*" 1544 | files = [ 1545 | {file = "StrEnum-0.4.10-py3-none-any.whl", hash = "sha256:aebf04bba8e5af435937c452d69a86798b6f8d5ca5f20ba18561dbfad571ccdd"}, 1546 | {file = "StrEnum-0.4.10.tar.gz", hash = "sha256:898cc0ebb5054ee07400341ac1d75fdfee489d76d6df3fbc1c2eaf95971e3916"}, 1547 | ] 1548 | 1549 | [package.extras] 1550 | docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] 1551 | release = ["twine"] 1552 | test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] 1553 | 1554 | [[package]] 1555 | name = "text-unidecode" 1556 | version = "1.3" 1557 | description = "The most basic Text::Unidecode port" 1558 | optional = false 1559 | python-versions = "*" 1560 | files = [ 1561 | {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, 1562 | {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "toml" 1567 | version = "0.10.2" 1568 | description = "Python Library for Tom's Obvious, Minimal Language" 1569 | optional = false 1570 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 1571 | files = [ 1572 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1573 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1574 | ] 1575 | 1576 | [[package]] 1577 | name = "tomli" 1578 | version = "2.0.1" 1579 | description = "A lil' TOML parser" 1580 | optional = false 1581 | python-versions = ">=3.7" 1582 | files = [ 1583 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1584 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "tomlkit" 1589 | version = "0.11.8" 1590 | description = "Style preserving TOML library" 1591 | optional = false 1592 | python-versions = ">=3.7" 1593 | files = [ 1594 | {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, 1595 | {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, 1596 | ] 1597 | 1598 | [[package]] 1599 | name = "typed-ast" 1600 | version = "1.5.4" 1601 | description = "a fork of Python 2 and 3 ast modules with type comment support" 1602 | optional = false 1603 | python-versions = ">=3.6" 1604 | files = [ 1605 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, 1606 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, 1607 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, 1608 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, 1609 | {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, 1610 | {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, 1611 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, 1612 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, 1613 | {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, 1614 | {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, 1615 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, 1616 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, 1617 | {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, 1618 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, 1619 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, 1620 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, 1621 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, 1622 | {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, 1623 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, 1624 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, 1625 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, 1626 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, 1627 | {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, 1628 | {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "types-docutils" 1633 | version = "0.20.0.1" 1634 | description = "Typing stubs for docutils" 1635 | optional = false 1636 | python-versions = "*" 1637 | files = [ 1638 | {file = "types-docutils-0.20.0.1.tar.gz", hash = "sha256:f682b5459a1e6e28208742adb0be8573d1ecbddd442f00d202b0278c1c4418a2"}, 1639 | {file = "types_docutils-0.20.0.1-py3-none-any.whl", hash = "sha256:6b17cbe57cb282158feb41d154cddaeabc16f1d6cff3c7308bd3056f42aa7cd2"}, 1640 | ] 1641 | 1642 | [[package]] 1643 | name = "types-setuptools" 1644 | version = "65.7.0.4" 1645 | description = "Typing stubs for setuptools" 1646 | optional = false 1647 | python-versions = "*" 1648 | files = [ 1649 | {file = "types-setuptools-65.7.0.4.tar.gz", hash = "sha256:147809433301fe7e0f4ef5c0782f9a0453788960575e1efb6da5fe8cb2493c9f"}, 1650 | {file = "types_setuptools-65.7.0.4-py3-none-any.whl", hash = "sha256:522067dfd8e1771f8d7e047e451de2740dc4e0c9f48a22302a6cc96e6c964a13"}, 1651 | ] 1652 | 1653 | [package.dependencies] 1654 | types-docutils = "*" 1655 | 1656 | [[package]] 1657 | name = "typing-extensions" 1658 | version = "4.6.3" 1659 | description = "Backported and Experimental Type Hints for Python 3.7+" 1660 | optional = false 1661 | python-versions = ">=3.7" 1662 | files = [ 1663 | {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, 1664 | {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, 1665 | ] 1666 | 1667 | [[package]] 1668 | name = "url-normalize" 1669 | version = "1.4.3" 1670 | description = "URL normalization for Python" 1671 | optional = false 1672 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 1673 | files = [ 1674 | {file = "url-normalize-1.4.3.tar.gz", hash = "sha256:d23d3a070ac52a67b83a1c59a0e68f8608d1cd538783b401bc9de2c0fac999b2"}, 1675 | {file = "url_normalize-1.4.3-py2.py3-none-any.whl", hash = "sha256:ec3c301f04e5bb676d333a7fa162fa977ad2ca04b7e652bfc9fac4e405728eed"}, 1676 | ] 1677 | 1678 | [package.dependencies] 1679 | six = "*" 1680 | 1681 | [[package]] 1682 | name = "urllib3" 1683 | version = "2.0.2" 1684 | description = "HTTP library with thread-safe connection pooling, file post, and more." 1685 | optional = false 1686 | python-versions = ">=3.7" 1687 | files = [ 1688 | {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, 1689 | {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, 1690 | ] 1691 | 1692 | [package.extras] 1693 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] 1694 | secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] 1695 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 1696 | zstd = ["zstandard (>=0.18.0)"] 1697 | 1698 | [[package]] 1699 | name = "wemake-python-styleguide" 1700 | version = "0.17.0" 1701 | description = "The strictest and most opinionated python linter ever" 1702 | optional = false 1703 | python-versions = ">=3.7,<4.0" 1704 | files = [ 1705 | {file = "wemake-python-styleguide-0.17.0.tar.gz", hash = "sha256:c8869fac392019c2bb3eae4287399245d10d2726b23f1b3c68d1564909c3a71a"}, 1706 | {file = "wemake_python_styleguide-0.17.0-py3-none-any.whl", hash = "sha256:d10b953bbe4fba83a34f4c224a0e1849ede89e486eacfc760690e6c87a28eaae"}, 1707 | ] 1708 | 1709 | [package.dependencies] 1710 | astor = ">=0.8,<0.9" 1711 | attrs = "*" 1712 | darglint = ">=1.2,<2.0" 1713 | flake8 = ">=3.7,<5" 1714 | flake8-bandit = ">=2.1,<4" 1715 | flake8-broken-line = ">=0.5,<0.6" 1716 | flake8-bugbear = ">=22.9,<23.0" 1717 | flake8-commas = ">=2.0,<3.0" 1718 | flake8-comprehensions = ">=3.1,<4.0" 1719 | flake8-debugger = ">=4.0,<5.0" 1720 | flake8-docstrings = ">=1.3,<2.0" 1721 | flake8-eradicate = ">=1.0,<2.0" 1722 | flake8-isort = ">=4.0,<5.0" 1723 | flake8-quotes = ">=3.0,<4.0" 1724 | flake8-rst-docstrings = ">=0.2,<0.3" 1725 | flake8-string-format = ">=0.3,<0.4" 1726 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 1727 | pep8-naming = ">=0.13,<0.14" 1728 | pygments = ">=2.4,<3.0" 1729 | typing_extensions = ">=4.0,<5.0" 1730 | 1731 | [[package]] 1732 | name = "win32-setctime" 1733 | version = "1.1.0" 1734 | description = "A small Python utility to set file creation time on Windows" 1735 | optional = false 1736 | python-versions = ">=3.5" 1737 | files = [ 1738 | {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, 1739 | {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, 1740 | ] 1741 | 1742 | [package.extras] 1743 | dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] 1744 | 1745 | [[package]] 1746 | name = "zipp" 1747 | version = "3.15.0" 1748 | description = "Backport of pathlib-compatible object wrapper for zip files" 1749 | optional = false 1750 | python-versions = ">=3.7" 1751 | files = [ 1752 | {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, 1753 | {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, 1754 | ] 1755 | 1756 | [package.extras] 1757 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 1758 | testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 1759 | 1760 | [metadata] 1761 | lock-version = "2.0" 1762 | python-versions = "^3.7" 1763 | content-hash = "0d47840c909debb1132d0c01adbbe26e5dfa6a22aa6b795525b49e5b80fbc60a" 1764 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "coverage-conditional-plugin" 3 | version = "0.9.0" 4 | description = "Conditional coverage based on any rules you define!" 5 | license = "MIT" 6 | 7 | authors = [ 8 | "sobolevn " 9 | ] 10 | 11 | # This is required for source distributions, like the one 12 | # used for Alpine linux. See #157 13 | include = [ 14 | {path = 'tests/*', format = 'sdist'}, 15 | {path = 'test_project/*', format = 'sdist'}, 16 | ] 17 | readme = "README.md" 18 | 19 | repository = "https://github.com/wemake-services/coverage-conditional-plugin" 20 | 21 | keywords = [ 22 | "coverage", 23 | "coverage.py", 24 | "pytest-cov", 25 | "testing", 26 | ] 27 | 28 | classifiers = [ 29 | "Development Status :: 4 - Beta", 30 | "Intended Audience :: Developers", 31 | "Operating System :: OS Independent", 32 | "Topic :: Software Development :: Libraries :: Python Modules", 33 | ] 34 | 35 | [tool.poetry.urls] 36 | "Funding" = "https://github.com/sponsors/wemake-services" 37 | 38 | [tool.poetry.dependencies] 39 | python = "^3.7" 40 | 41 | coverage = ">=7,<8" 42 | packaging = ">=20.4" 43 | importlib_metadata = { version = "*", python = "<3.10" } 44 | 45 | [tool.poetry.group.test.dependencies] 46 | mypy = "^1.3" 47 | types-setuptools = "^65.3" 48 | 49 | wemake-python-styleguide = "^0.17" 50 | flake8-pytest-style = "^1.5" 51 | nitpick = "^0.33" 52 | 53 | safety = "^2.3" 54 | 55 | pytest = "^7.3" 56 | pytest-cov = "^3.0" 57 | pytest-randomly = "^3.12" 58 | 59 | 60 | [build-system] 61 | requires = ["poetry_core>=1.6.0"] 62 | build-backend = "poetry.core.masonry.api" 63 | 64 | 65 | [tool.nitpick] 66 | style = "https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/styles/nitpick-style-wemake.toml" 67 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # All configuration for plugins and other utils is defined here. 2 | # Read more about `setup.cfg`: 3 | # https://docs.python.org/3/distutils/configfile.html 4 | 5 | [flake8] 6 | # Base flake8 configuration: 7 | # https://flake8.pycqa.org/en/latest/user/configuration.html 8 | format = wemake 9 | show-source = true 10 | statistics = false 11 | doctests = true 12 | 13 | # darglint configuration: 14 | # https://github.com/terrencepreilly/darglint 15 | strictness = long 16 | docstring-style = numpy 17 | 18 | # Plugins: 19 | max-complexity = 6 20 | max-line-length = 80 21 | 22 | # wemake-python-styleguide settings: 23 | i-control-code = false 24 | 25 | # Custom ignore options: 26 | ignore = D100, D104, D106, D401, W504, X100, RST303, RST304, DAR103, DAR203 27 | 28 | # Excluding some directories: 29 | extend-exclude = 30 | .venv 31 | 32 | # Ignoring some errors in some files: 33 | per-file-ignores = 34 | # we need nested import and block variable overlap for conditional 35 | # importlib_metadata import 36 | coverage_conditional_plugin/version.py: WPS433, WPS440 37 | # Disable `test_project` complexity checks: 38 | test_project/example.py: WPS202 39 | # Enable `assert` keyword and magic numbers for tests: 40 | tests/*.py: S101, WPS226, WPS432, WPS450 41 | 42 | 43 | [isort] 44 | # isort configuration: 45 | # https://github.com/timothycrosley/isort/wiki/isort-Settings 46 | profile = wemake 47 | 48 | 49 | [tool:pytest] 50 | # Directories that are not visited by pytest collector: 51 | norecursedirs = *.egg .eggs dist build docs .tox .git __pycache__ 52 | 53 | # PYTHONPATH configuration: 54 | # https://github.com/bigsassy/pytest-pythonpath 55 | pythonpath = ./test_project 56 | 57 | # Strict `@xfail` by default: 58 | xfail_strict = true 59 | 60 | # Extra options: 61 | addopts = 62 | --strict-markers 63 | --strict-config 64 | --tb=short 65 | --doctest-modules 66 | --cov=test_project 67 | --cov-fail-under=63 68 | --cov-report=term:skip-covered 69 | --cov-report=html 70 | --cov-report=xml 71 | --cov-config=test_project/.coveragerc 72 | 73 | 74 | [mypy] 75 | # mypy configurations: http://bit.ly/2zEl9WI 76 | allow_redefinition = false 77 | check_untyped_defs = true 78 | disallow_any_explicit = true 79 | disallow_any_generics = true 80 | disallow_untyped_calls = true 81 | ignore_errors = false 82 | ignore_missing_imports = true 83 | implicit_reexport = false 84 | local_partial_types = true 85 | strict_optional = true 86 | strict_equality = true 87 | no_implicit_optional = true 88 | warn_no_return = true 89 | warn_unused_ignores = true 90 | warn_redundant_casts = true 91 | warn_unused_configs = true 92 | warn_unreachable = true 93 | 94 | [mypy-coverage_conditional_plugin.version] 95 | # We allow unused `ignore` comments, because we cannot sync it between versions: 96 | warn_unused_ignores = false 97 | -------------------------------------------------------------------------------- /test_project/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = true 3 | plugins = 4 | coverage_conditional_plugin 5 | 6 | [report] 7 | exclude_also = 8 | raise NotImplementedError 9 | 10 | [coverage_conditional_plugin] 11 | # TODO: not supported, you can write parser similar to 12 | # https://github.com/PyCQA/flake8/blob/c8d75d9966c074770695cd44e2c2e9d8488761e7/src/flake8/utils.py#L61 13 | # But, I don't have time for it now. 14 | # omit = 15 | # "os_environ.get('OMIT_FILES')": 16 | # "test_project/omit*.py", 17 | # "test_project/compat.py" 18 | rules = 19 | "sys_version_info >= (3, 6)": py-gte-36 20 | "sys_version_info >= (3, 7)": py-gte-37 21 | "sys_version_info >= (3, 8)": py-gte-38 22 | "sys_version_info >= (3, 9)": py-gte-39 23 | "sys.version_info >= (3, 10)": py-gte-310 24 | "sys.version_info >= (3, 11)": py-gte-311 25 | -------------------------------------------------------------------------------- /test_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wemake-services/coverage-conditional-plugin/32c64be6fde4cc79ae3ab7c1a92d6effc0faad8d/test_project/__init__.py -------------------------------------------------------------------------------- /test_project/compat.py: -------------------------------------------------------------------------------- 1 | def uncovered() -> str: 2 | """Test function that is uncovered.""" 3 | return 'uncovered' 4 | -------------------------------------------------------------------------------- /test_project/example.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | 4 | def if_gte_python311() -> Tuple[int, int]: # pragma: py-gte-311 5 | """Test function for pragma ``py-gte-311``.""" 6 | return (3, 11) 7 | 8 | 9 | def if_gte_python310() -> Tuple[int, int]: # pragma: py-gte-310 10 | """Test function for pragma ``py-gte-310``.""" 11 | return (3, 10) 12 | 13 | 14 | def if_gte_python39() -> Tuple[int, int]: # pragma: py-gte-39 15 | """Test function for pragma ``py-gte-39``.""" 16 | return (3, 9) 17 | 18 | 19 | def if_gte_python38() -> Tuple[int, int]: # pragma: py-gte-38 20 | """Test function for pragma ``py-gte-38``.""" 21 | return (3, 8) 22 | 23 | 24 | def if_gte_python37() -> Tuple[int, int]: # pragma: py-gte-37 25 | """Test function for pragma ``py-gte-37``.""" 26 | return (3, 7) 27 | 28 | 29 | def if_gte_python36() -> Tuple[int, int]: # pragma: py-gte-36 30 | """Test function for pragma ``py-gte-36``.""" 31 | return (3, 6) 32 | 33 | 34 | def never() -> str: # pragma: no cover 35 | """Ensure that some code is never covered.""" 36 | return 'never' 37 | 38 | 39 | def always() -> str: 40 | """Test function that is always executed.""" 41 | return 'always' 42 | 43 | 44 | def uncovered(): 45 | """Test function that is uncovered.""" 46 | return 'uncovered' 47 | -------------------------------------------------------------------------------- /test_project/omit1.py: -------------------------------------------------------------------------------- 1 | def uncovered() -> str: 2 | """Test function that is uncovered.""" 3 | return 'uncovered' 4 | -------------------------------------------------------------------------------- /test_project/omit2.py: -------------------------------------------------------------------------------- 1 | def uncovered() -> str: 2 | """Test function that is uncovered.""" 3 | return 'uncovered' 4 | -------------------------------------------------------------------------------- /test_project/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.coverage.run] 2 | plugins = ["coverage_conditional_plugin"] 3 | omit = ["test_project/missing.py"] 4 | 5 | [tool.coverage.report] 6 | exclude_also = ['raise NotImplementedError'] 7 | 8 | [tool.coverage.coverage_conditional_plugin.omit] 9 | "os_environ.get('OMIT1')" = [ 10 | "test_project/omit*.py", 11 | "test_project/compat.py", 12 | ] 13 | "os_environ.get('OMIT2')" = "test_project/compat.py" 14 | 15 | [tool.coverage.coverage_conditional_plugin.rules] 16 | py-gte-36 = "sys_version_info >= (3, 6)" 17 | py-gte-37 = "sys_version_info >= (3, 7)" 18 | py-gte-38 = "sys_version_info >= (3, 8)" 19 | py-gte-39 = "sys_version_info >= (3, 9)" 20 | py-gte-310 = "sys_version_info >= (3, 10)" 21 | py-gte-311 = "sys_version_info >= (3, 11)" 22 | -------------------------------------------------------------------------------- /tests/test_implementation.py: -------------------------------------------------------------------------------- 1 | from coverage_conditional_plugin import _is_installed 2 | from coverage_conditional_plugin.version import package_version 3 | 4 | 5 | def test_is_installed(): 6 | """Ensures that ``_is_installed`` works correctly.""" 7 | assert _is_installed('coverage') is True # regular dependency 8 | assert _is_installed('pytest') is True # dev dependency 9 | assert _is_installed('missing') is False # missing dependency 10 | 11 | 12 | def test_package_version(): 13 | """Ensures that ``_package_version`` is correct.""" 14 | coverage_version = package_version('coverage') 15 | pytest_version = package_version('pytest') 16 | 17 | assert coverage_version is not None 18 | assert coverage_version < (1000, 0, 0) 19 | assert pytest_version is not None 20 | assert pytest_version > (5, 0) 21 | -------------------------------------------------------------------------------- /tests/test_integration.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | from pathlib import Path 4 | 5 | import pytest 6 | from coverage import Coverage 7 | 8 | from test_project.example import ( 9 | always, 10 | if_gte_python36, 11 | if_gte_python37, 12 | if_gte_python38, 13 | if_gte_python39, 14 | if_gte_python310, 15 | if_gte_python311, 16 | ) 17 | 18 | #: This is just our specific example. 19 | _EXCUDED_LINES = (sys.version_info[1] - 6) * 3 + 6 20 | # 3.11 = 21 21 | # 3.10 = 18 22 | # 3.9 = 15 23 | # 3.8 = 12 24 | # 3.7 = 9 25 | # 3.6 = 6 26 | 27 | #: This is just a result of the coverage run. 28 | #: It might change if you add new files / change something in `test_project/`. 29 | _COVERAGE_PERCENT = 63 30 | 31 | #: Lines that are not convered due to `omit` setting: 32 | _MISSING_LINES = 4 # 1 uncovered + 3 in omits 33 | 34 | 35 | def test_integration(cov, capsys): 36 | """Ensures that coverage is executed correctly.""" 37 | # We call all functions without any actual version checks. 38 | if_gte_python36() 39 | if_gte_python37() 40 | if_gte_python38() 41 | if_gte_python39() 42 | if_gte_python310() 43 | if_gte_python311() 44 | always() 45 | 46 | cov.json_report(outfile='-') 47 | captured = capsys.readouterr() 48 | coverage = json.loads(captured.out) 49 | 50 | assert len( 51 | coverage['files']['test_project/example.py']['excluded_lines'], 52 | ) == _EXCUDED_LINES 53 | assert int(coverage['totals']['percent_covered']) >= _COVERAGE_PERCENT 54 | assert coverage['totals']['missing_lines'] == _MISSING_LINES 55 | 56 | 57 | @pytest.mark.parametrize('configfile', ['.coveragerc', 'pyproject.toml']) 58 | def test_config_file_parsing(configfile): 59 | """Ensures that coverage is executed correctly.""" 60 | config_file_path = Path(__file__).parents[1] / 'test_project' / configfile 61 | 62 | cov = Coverage(config_file=str(config_file_path)) 63 | assert cov.config.config_file == str(config_file_path) 64 | assert cov.config.plugins == ['coverage_conditional_plugin'] 65 | 66 | cov.start() 67 | cov.stop() 68 | 69 | assert ( 70 | 'py-gte-3{minor_ver}'.format(minor_ver=sys.version_info[1]) 71 | in cov.config.exclude_list 72 | ) 73 | # Default exclude must not be lost: 74 | assert 'raise NotImplementedError' in cov.config.exclude_list 75 | -------------------------------------------------------------------------------- /tests/test_omits.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | from coverage import Coverage 5 | 6 | _OMIT_DEFAULT = 'test_project/missing.py' 7 | _OMIT_GLOB = 'test_project/omit*.py' 8 | _OMIT_FILE = 'test_project/compat.py' 9 | 10 | 11 | @pytest.mark.parametrize(('env_key', 'omits'), [ 12 | ('OMIT1', [_OMIT_DEFAULT, _OMIT_GLOB, _OMIT_FILE]), 13 | ('OMIT2', [_OMIT_DEFAULT, _OMIT_FILE]), 14 | ]) 15 | def test_omit1(monkeypatch, env_key, omits): 16 | """Ensures that coverage is executed correctly.""" 17 | monkeypatch.setenv(env_key, '1') 18 | config_file_path = ( 19 | Path(__file__).parents[1] / 'test_project' / 'pyproject.toml' 20 | ) 21 | 22 | cov = Coverage(config_file=str(config_file_path)) 23 | 24 | cov.start() 25 | cov.stop() 26 | 27 | assert cov.config.run_omit == omits 28 | -------------------------------------------------------------------------------- /tests/test_plugin.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from coverage_conditional_plugin import _should_be_applied 4 | 5 | 6 | @pytest.mark.parametrize('code', [ 7 | 'True or False', 8 | 'bool(1 + 2)', 9 | 10 | 'sys_version_info > (3,)', 11 | 'bool(os_name)', 12 | '"PATH" in os_environ', 13 | 'isinstance(platform_system, str)', 14 | 'len(platform_release) > 1', 15 | 'is_installed("pytest")', 16 | 'package_version("pytest") > (5,)', 17 | ]) 18 | def test_plugin_should_be_applied(code): 19 | """Ensures code is evaluated correctly.""" 20 | assert _should_be_applied(code) is True 21 | --------------------------------------------------------------------------------